import { describe, it, expect, beforeEach, afterEach } from "bun:test"; import { existsSync } from "node:fs"; import { mkdir, rm, readFile, readdir } from "node:fs/promises"; import { join } from "node:path"; import { injectOpenCode } from "../../src/adapters/opencode.ts"; const TMP_DIR = join(import.meta.dir, "__tmp_opencode_test__"); beforeEach(async () => { await mkdir(TMP_DIR, { recursive: true }); }); afterEach(async () => { await rm(TMP_DIR, { recursive: true, force: true }); }); describe("injectOpenCode", () => { it("生成 discuss、plan、build、archive 的 command 和 skill 文件", async () => { await injectOpenCode(TMP_DIR); const commands = await readdir(join(TMP_DIR, ".opencode", "commands")); const skills = await readdir(join(TMP_DIR, ".opencode", "skills")); for (const stage of ["discuss", "plan", "build", "archive"]) { expect(commands).toContain(`rune-${stage}.md`); expect(skills).toContain(`rune-${stage}`); expect( existsSync(join(TMP_DIR, ".opencode", "skills", `rune-${stage}`, "SKILL.md")), ).toBe(true); } }); it("生成 rune-status command 和 skill", async () => { await injectOpenCode(TMP_DIR); const commands = await readdir(join(TMP_DIR, ".opencode", "commands")); const skills = await readdir(join(TMP_DIR, ".opencode", "skills")); expect(commands).toContain("rune-status.md"); expect(skills).toContain("rune-status"); expect( existsSync(join(TMP_DIR, ".opencode", "skills", "rune-status", "SKILL.md")), ).toBe(true); }); it("command 文件包含 skill 调用指令", async () => { await injectOpenCode(TMP_DIR); const content = await readFile( join(TMP_DIR, ".opencode", "commands", "rune-discuss.md"), "utf-8", ); expect(content).toContain("rune-discuss"); }); it("skill 文件包含 bash 命令", async () => { await injectOpenCode(TMP_DIR); const content = await readFile( join(TMP_DIR, ".opencode", "skills", "rune-discuss", "SKILL.md"), "utf-8", ); expect(content).toContain("rune discuss"); expect(content).toContain("description"); expect(content).toContain("name: rune-discuss"); }); it("plan/build/archive skill 包含变更名称参数提示", async () => { await injectOpenCode(TMP_DIR); for (const stage of ["plan", "build", "archive"]) { const content = await readFile( join(TMP_DIR, ".opencode", "skills", `rune-${stage}`, "SKILL.md"), "utf-8", ); expect(content).toContain("变更名"); } }); it("重复注入时不覆盖已存在的文件", async () => { await injectOpenCode(TMP_DIR); const originalContent = await readFile( join(TMP_DIR, ".opencode", "commands", "rune-discuss.md"), "utf-8", ); await injectOpenCode(TMP_DIR); const content = await readFile( join(TMP_DIR, ".opencode", "commands", "rune-discuss.md"), "utf-8", ); expect(content).toBe(originalContent); }); });