Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions packages/opencode/test/command/hints.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { describe, test, expect } from "bun:test"
import { Command } from "../../src/command/index"

describe("Command.hints: template placeholder extraction", () => {
test("returns empty array for template with no placeholders", () => {
expect(Command.hints("Run the tests and report results")).toEqual([])
expect(Command.hints("")).toEqual([])
})

test("extracts numbered placeholders in sorted order", () => {
expect(Command.hints("Review $2 and compare with $1")).toEqual(["$1", "$2"])
})

test("deduplicates repeated placeholder occurrences", () => {
expect(Command.hints("Use $1 then use $1 again and $2")).toEqual(["$1", "$2"])
})

test("appends $ARGUMENTS when present", () => {
expect(Command.hints("Do something with $ARGUMENTS")).toEqual(["$ARGUMENTS"])
})
Comment on lines +18 to +20
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add a mixed-case assertion for numbered placeholders + $ARGUMENTS.

Line 18 currently verifies $ARGUMENTS alone, but it does not assert combined behavior in the same template (e.g., $1, $2, and $ARGUMENTS together), which is the higher-value ordering/append contract.

Suggested test addition
   test("appends $ARGUMENTS when present", () => {
     expect(Command.hints("Do something with $ARGUMENTS")).toEqual(["$ARGUMENTS"])
+    expect(Command.hints("Use $2 with $ARGUMENTS and $1")).toEqual(["$1", "$2", "$ARGUMENTS"])
   })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test("appends $ARGUMENTS when present", () => {
expect(Command.hints("Do something with $ARGUMENTS")).toEqual(["$ARGUMENTS"])
})
test("appends $ARGUMENTS when present", () => {
expect(Command.hints("Do something with $ARGUMENTS")).toEqual(["$ARGUMENTS"])
expect(Command.hints("Use $2 with $ARGUMENTS and $1")).toEqual(["$1", "$2", "$ARGUMENTS"])
})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/test/command/hints.test.ts` around lines 18 - 20, Add a
test to verify that Command.hints correctly extracts numbered placeholders along
with the $ARGUMENTS token in the same template: update the test suite in
hints.test.ts to include a case calling Command.hints with a string containing
mixed numbered placeholders and $ARGUMENTS (e.g., "$1 $2 $ARGUMENTS" or
mixed-case variants) and assert the returned array preserves the expected
ordering/append contract (contains "$1", "$2", and "$ARGUMENTS" in the correct
order). This ensures Command.hints handles combined placeholders and the special
$ARGUMENTS token together.


test("multi-digit placeholders sort lexicographically", () => {
// $10 sorts before $2 in lexicographic order — this is the actual behavior
// since the code uses [...new Set(numbered)].sort() which is string sort
const result = Command.hints("Map $1 to $2 and also $10")
expect(result).toEqual(["$1", "$10", "$2"])
})
})
55 changes: 55 additions & 0 deletions packages/opencode/test/skill/fmt.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { describe, test, expect } from "bun:test"
import { Skill } from "../../src/skill/skill"

function skill(overrides: Partial<Skill.Info> = {}): Skill.Info {
return {
name: overrides.name ?? "test-skill",
description: overrides.description ?? "A test skill",
location: overrides.location ?? "/home/user/skills/test-skill/SKILL.md",
content: overrides.content ?? "# Test\nDo the thing.",
}
}

describe("Skill.fmt: skill list formatting", () => {
test("returns 'No skills' message for empty list", () => {
expect(Skill.fmt([], { verbose: false })).toBe("No skills are currently available.")
expect(Skill.fmt([], { verbose: true })).toBe("No skills are currently available.")
})

test("verbose mode returns XML with skill tags", () => {
const skills = [
skill({ name: "analyze", description: "Analyze code", location: "/path/to/analyze/SKILL.md" }),
skill({ name: "deploy", description: "Deploy app", location: "/path/to/deploy/SKILL.md" }),
]
const output = Skill.fmt(skills, { verbose: true })
expect(output).toContain("<available_skills>")
expect(output).toContain("</available_skills>")
expect(output).toContain("<name>analyze</name>")
expect(output).toContain("<description>Analyze code</description>")
expect(output).toContain("<name>deploy</name>")
expect(output).toContain("<description>Deploy app</description>")
// File paths get converted to file:// URLs
expect(output).toContain("file:///path/to/analyze/SKILL.md")
})

test("non-verbose returns markdown with bullet points", () => {
const skills = [
skill({ name: "lint", description: "Lint the code" }),
skill({ name: "format", description: "Format files" }),
]
const output = Skill.fmt(skills, { verbose: false })
expect(output).toContain("## Available Skills")
expect(output).toContain("- **lint**: Lint the code")
expect(output).toContain("- **format**: Format files")
})

test("verbose mode preserves builtin: protocol without file:// conversion", () => {
const skills = [
skill({ name: "builtin-skill", description: "Built in", location: "builtin:my-skill/SKILL.md" }),
]
const output = Skill.fmt(skills, { verbose: true })
expect(output).toContain("<location>builtin:my-skill/SKILL.md</location>")
// Should NOT contain file:// for builtin: paths
expect(output).not.toContain("file://")
})
})
Loading