diff --git a/packages/opencode/src/tool/skill.ts b/packages/opencode/src/tool/skill.ts index 8fcfb592dee6..d7cc3406a421 100644 --- a/packages/opencode/src/tool/skill.ts +++ b/packages/opencode/src/tool/skill.ts @@ -62,7 +62,7 @@ export const SkillTool = Tool.define("skill", async (ctx) => { const skill = await Skill.get(params.name) if (!skill) { - const available = await Skill.all().then((x) => Object.keys(x).join(", ")) + const available = await Skill.all().then((x) => x.map((s) => s.name).join(", ")) throw new Error(`Skill "${params.name}" not found. Available skills: ${available || "none"}`) } diff --git a/packages/opencode/test/tool/skill.test.ts b/packages/opencode/test/tool/skill.test.ts index d5057ba9e7f4..e8e0f5d3beb3 100644 --- a/packages/opencode/test/tool/skill.test.ts +++ b/packages/opencode/test/tool/skill.test.ts @@ -18,6 +18,51 @@ const baseCtx: Omit = { } describe("tool.skill", () => { + test("error message lists skill names not array indices", async () => { + await using tmp = await tmpdir({ + git: true, + init: async (dir) => { + const skillDir = path.join(dir, ".opencode", "skill", "existing-skill") + await Bun.write( + path.join(skillDir, "SKILL.md"), + `--- +name: existing-skill +description: An existing skill. +--- + +# Existing Skill +`, + ) + }, + }) + + const home = process.env.OPENCODE_TEST_HOME + process.env.OPENCODE_TEST_HOME = tmp.path + + try { + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const tool = await SkillTool.init() + const ctx: Tool.Context = { + ...baseCtx, + ask: async () => {}, + } + + try { + await tool.execute({ name: "nonexistent-skill" }, ctx) + expect.unreachable("should have thrown") + } catch (err: any) { + expect(err.message).toContain("existing-skill") + expect(err.message).not.toContain("Available skills: 0") + } + }, + }) + } finally { + process.env.OPENCODE_TEST_HOME = home + } + }) + test("description lists skill location URL", async () => { await using tmp = await tmpdir({ git: true,