import assert from "node:assert/strict"; import { execFile } from "node:child_process"; import { access, mkdtemp, readFile, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { dirname, join, resolve } from "node:path"; import test from "node:test"; import { fileURLToPath } from "node:url"; import { promisify } from "node:util"; import { smokePackage } from "./smoke-package.mjs"; import { smokeMcp } from "./smoke-mcp.mjs"; const execFileAsync = promisify(execFile); const root = resolve(dirname(fileURLToPath(import.meta.url)), ".."); test("package structure and plan validation smoke", async () => { const result = await smokePackage(); assert.equal(result.status, "ok"); }); test("MCP exposes the image-set tools", async () => { const result = await smokeMcp(); assert.equal(result.status, "ok"); assert.deepEqual(result.tools.sort(), ["fmode_image_set_run", "fmode_image_set_validate"].sort()); const validator = result.toolDefinitions.find((tool) => tool.name === "fmode_image_set_validate"); assert.deepEqual(validator.annotations, { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }); }); test("skill can call its MCP tools and delegates unsupported images to the attachment bridge", async () => { const skill = await readFile(join(root, "skills", "fmode-image-set", "SKILL.md"), "utf8"); assert.doesNotMatch(skill, /^allowed-tools:/m); assert.match(skill, /\[Unsupported Image\]/); assert.match(skill, /`fmode_image_set_run` 的 `action=start`/); assert.match(skill, /不得先用 Glob 搜图/); }); test("workspace install places the complete package under the discoverable skill root", async () => { const workspace = await mkdtemp(join(tmpdir(), "fmode-image-set-workspace-")); try { await execFileAsync( process.execPath, [join(root, "bin", "fmode-image-set.js"), "workspace", "--skip-install"], { cwd: workspace }, ); const target = join(workspace, ".claude", "skills", "fmode-image-set"); for (const relativePath of [ ".claude-plugin/plugin.json", "bin/fmode-image-set.js", "docs/capability-map.md", "mcp/src/server.mjs", "memory-templates/image-set-profile.json", "scripts/smoke-package.mjs", "skills/fmode-image-set/SKILL.md", "skill-package-manifest.json", "SKILL.md", "references/image-set-planner.md", "agents/openai.yaml", ]) { await access(join(target, relativePath)); } const config = JSON.parse(await readFile(join(workspace, ".mcp.json"), "utf8")); assert.equal( resolve(config.mcpServers["fmode-image-set"].cwd), resolve(target), ); } finally { await rm(workspace, { recursive: true, force: true }); } });