diff --git a/packages/opencode/test/tool/skill.test.ts b/packages/opencode/test/tool/skill.test.ts new file mode 100644 index 000000000000..d5057ba9e7f4 --- /dev/null +++ b/packages/opencode/test/tool/skill.test.ts @@ -0,0 +1,112 @@ +import { describe, expect, test } from "bun:test" +import path from "path" +import { pathToFileURL } from "url" +import type { PermissionNext } from "../../src/permission/next" +import type { Tool } from "../../src/tool/tool" +import { Instance } from "../../src/project/instance" +import { SkillTool } from "../../src/tool/skill" +import { tmpdir } from "../fixture/fixture" + +const baseCtx: Omit = { + sessionID: "test", + messageID: "", + callID: "", + agent: "build", + abort: AbortSignal.any([]), + messages: [], + metadata: () => {}, +} + +describe("tool.skill", () => { + test("description lists skill location URL", async () => { + await using tmp = await tmpdir({ + git: true, + init: async (dir) => { + const skillDir = path.join(dir, ".opencode", "skill", "tool-skill") + await Bun.write( + path.join(skillDir, "SKILL.md"), + `--- +name: tool-skill +description: Skill for tool tests. +--- + +# Tool 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 skillPath = path.join(tmp.path, ".opencode", "skill", "tool-skill", "SKILL.md") + expect(tool.description).toContain(`${pathToFileURL(skillPath).href}`) + }, + }) + } finally { + process.env.OPENCODE_TEST_HOME = home + } + }) + + test("execute returns skill content block with files", async () => { + await using tmp = await tmpdir({ + git: true, + init: async (dir) => { + const skillDir = path.join(dir, ".opencode", "skill", "tool-skill") + await Bun.write( + path.join(skillDir, "SKILL.md"), + `--- +name: tool-skill +description: Skill for tool tests. +--- + +# Tool Skill + +Use this skill. +`, + ) + await Bun.write(path.join(skillDir, "scripts", "demo.txt"), "demo") + }, + }) + + 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 requests: Array> = [] + const ctx: Tool.Context = { + ...baseCtx, + ask: async (req) => { + requests.push(req) + }, + } + + const result = await tool.execute({ name: "tool-skill" }, ctx) + const dir = path.join(tmp.path, ".opencode", "skill", "tool-skill") + const file = path.resolve(dir, "scripts", "demo.txt") + + expect(requests.length).toBe(1) + expect(requests[0].permission).toBe("skill") + expect(requests[0].patterns).toContain("tool-skill") + expect(requests[0].always).toContain("tool-skill") + + expect(result.metadata.dir).toBe(dir) + expect(result.output).toContain(``) + expect(result.output).toContain(`Base directory for this skill: ${pathToFileURL(dir).href}`) + expect(result.output).toContain(`${file}`) + }, + }) + } finally { + process.env.OPENCODE_TEST_HOME = home + } + }) +})