// `skill-load` MCP tool acceptance gate.
//
// Locks in the contract for `loadSkill` (the resolve+read helper backing
// the new `skill-load` MCP tool registered in index.ts). Tests build a
// temp PLATFORM_ROOT tree, seed SKILL.md files, and assert exact outcome
// shapes — no stdio transport, no SDK harness.
//
// Brand substitution is exercised in production via the same
// `substituteBrandPlaceholders` call as `plugin-read` (index.ts) and
// covered by brand-templating's own tests. Case 2 below asserts that
// `loadSkill` returns the raw bytes (placeholder intact) so the handler
// can substitute deterministically.
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { loadSkill } from "../skill-resolution.js";
let root;
beforeEach(() => {
    root = mkdtempSync(join(tmpdir(), "skill-load-"));
});
afterEach(() => {
    rmSync(root, { recursive: true, force: false });
});
function seedSkill(plugin, skill, body) {
    const dir = join(root, "plugins", plugin, "skills", skill);
    mkdirSync(dir, { recursive: true });
    writeFileSync(join(dir, "SKILL.md"), body);
}
describe("loadSkill", () => {
    it("unique → returns SKILL.md body verbatim with absolute path", async () => {
        seedSkill("admin", "plainly", "# Plainly\n\nStrip AI tells.\n");
        const outcome = await loadSkill(root, "plainly");
        expect(outcome.status).toBe("unique");
        if (outcome.status !== "unique")
            return;
        expect(outcome.pluginName).toBe("admin");
        expect(outcome.file).toBe("skills/plainly/SKILL.md");
        expect(outcome.body).toBe("# Plainly\n\nStrip AI tells.\n");
        expect(outcome.absolutePath.endsWith("plugins/admin/skills/plainly/SKILL.md")).toBe(true);
    });
    it("unique → returns raw bytes with brand placeholder intact (handler runs substitution)", async () => {
        seedSkill("admin", "branded", "# Welcome to <<product-name>>\n\nThe placeholder must reach the handler unmodified.\n");
        const outcome = await loadSkill(root, "branded");
        expect(outcome.status).toBe("unique");
        if (outcome.status !== "unique")
            return;
        expect(outcome.body).toContain("<<product-name>>");
    });
    it("ambiguous → returns ambiguous status with candidate list", async () => {
        seedSkill("admin", "shared-name", "# A\n");
        seedSkill("contacts", "shared-name", "# B\n");
        const outcome = await loadSkill(root, "shared-name");
        expect(outcome.status).toBe("ambiguous");
        if (outcome.status !== "ambiguous")
            return;
        expect(outcome.candidates).toHaveLength(2);
    });
    it("not-found → returns not-found status", async () => {
        seedSkill("admin", "plainly", "# Plainly\n");
        const outcome = await loadSkill(root, "absent-skill");
        expect(outcome.status).toBe("not-found");
    });
    it("kebab-case validator rejects path-shaped input like admin/skills/plainly", () => {
        // Mirrors the zod regex at the MCP tool registration in index.ts —
        // the validator runs before the handler so loadSkill is never called
        // with a path-shaped skillName.
        const KEBAB = /^[a-z0-9][a-z0-9-]*$/;
        expect(KEBAB.test("admin/skills/plainly")).toBe(false);
        expect(KEBAB.test("skills/plainly")).toBe(false);
        expect(KEBAB.test("admin/plainly")).toBe(false);
        expect(KEBAB.test("plainly")).toBe(true);
        expect(KEBAB.test("setup-tunnel")).toBe(true);
    });
    it("ambiguous candidates include every owning plugin (set comparison, no order dependency)", async () => {
        seedSkill("admin", "plainly", "# A\n");
        seedSkill("contacts", "plainly", "# B\n");
        seedSkill("memory", "plainly", "# C\n");
        const outcome = await loadSkill(root, "plainly");
        expect(outcome.status).toBe("ambiguous");
        if (outcome.status !== "ambiguous")
            return;
        const owners = outcome.candidates.map(c => c.pluginName).sort();
        expect(owners).toEqual(["admin", "contacts", "memory"]);
        expect(outcome.candidates.every(c => c.file === "skills/plainly/SKILL.md")).toBe(true);
    });
});
//# sourceMappingURL=skill-load.test.js.map