// plugin-skill resolution gate.
//
// Locks in the contract for `findSkillOwners` (the helper backing the
// new `skill-find` MCP tool) and the sibling-hint that `plugin-read`
// appends to its "not found" error when the agent guesses the wrong
// pluginName for a skill that DOES live somewhere else under
// `plugins/*/skills/<name>/SKILL.md`.
//
// Tests build a temp PLATFORM_ROOT tree, point the helpers at it, and
// assert exact result shapes — no stdio transport, no SDK harness.
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 { findSkillOwners, computePluginReadHint } from "../skill-resolution.js";
let root;
beforeEach(() => {
    root = mkdtempSync(join(tmpdir(), "skill-find-"));
});
afterEach(() => {
    rmSync(root, { recursive: true, force: false });
});
function seedSkill(plugin, skill) {
    const dir = join(root, "plugins", plugin, "skills", skill);
    mkdirSync(dir, { recursive: true });
    writeFileSync(join(dir, "SKILL.md"), `# ${skill}\n`);
}
describe("findSkillOwners", () => {
    it("returns a unique owner when exactly one plugin holds the skill", () => {
        seedSkill("cloudflare", "setup-tunnel");
        seedSkill("admin", "onboarding");
        const result = findSkillOwners(root, "setup-tunnel");
        expect(result).toEqual({
            status: "unique",
            candidates: [{ pluginName: "cloudflare", file: "skills/setup-tunnel/SKILL.md" }],
        });
    });
    it("returns every candidate when the skill name is shared across plugins", () => {
        seedSkill("admin", "shared-name");
        seedSkill("cloudflare", "shared-name");
        seedSkill("memory", "unrelated");
        const result = findSkillOwners(root, "shared-name");
        expect(result.status).toBe("ambiguous");
        expect(result.candidates).toHaveLength(2);
        const names = result.candidates.map(c => c.pluginName).sort();
        expect(names).toEqual(["admin", "cloudflare"]);
        expect(result.candidates.every(c => c.file === "skills/shared-name/SKILL.md")).toBe(true);
    });
    it("returns not-found when no plugin owns the skill", () => {
        seedSkill("admin", "onboarding");
        const result = findSkillOwners(root, "absent-skill");
        expect(result).toEqual({ status: "not-found", candidates: [] });
    });
});
describe("computePluginReadHint", () => {
    it("returns the owner and canonical SKILL.md path when one sibling owns the skill referenced via file", () => {
        seedSkill("cloudflare", "setup-tunnel");
        const hint = computePluginReadHint(root, "admin", "skills/setup-tunnel/SKILL.md");
        expect(hint).toEqual({ pluginName: "cloudflare", file: "skills/setup-tunnel/SKILL.md" });
    });
    it("returns null when no plugin owns the requested skill", () => {
        seedSkill("admin", "onboarding");
        const hint = computePluginReadHint(root, "admin", "skills/imaginary/SKILL.md");
        expect(hint).toBeNull();
    });
    // wrong-`pluginName` shape: the skill slug is buried inside
    // pluginName instead of the file path. The hint must still surface both
    // the corrected pluginName and the canonical SKILL.md file path.
    it("hints when skills/<slug> is buried in pluginName and file defaults to PLUGIN.md", () => {
        seedSkill("admin", "plainly");
        const hint = computePluginReadHint(root, "admin/skills/plainly", "PLUGIN.md");
        expect(hint).toEqual({ pluginName: "admin", file: "skills/plainly/SKILL.md" });
    });
    it("hints when skills/<slug> is buried in pluginName and file is the bare SKILL.md", () => {
        seedSkill("admin", "plainly");
        const hint = computePluginReadHint(root, "admin/skills/plainly", "SKILL.md");
        expect(hint).toEqual({ pluginName: "admin", file: "skills/plainly/SKILL.md" });
    });
    it("hints with the real owner when the pluginName prefix is wrong (contacts/skills/plainly → admin)", () => {
        seedSkill("admin", "plainly");
        const hint = computePluginReadHint(root, "contacts/skills/plainly", "PLUGIN.md");
        expect(hint).toEqual({ pluginName: "admin", file: "skills/plainly/SKILL.md" });
    });
    it("returns null when the skill name extracted from pluginName is ambiguous across plugins", () => {
        seedSkill("admin", "plainly");
        seedSkill("contacts", "plainly");
        const hint = computePluginReadHint(root, "admin/skills/plainly", "PLUGIN.md");
        expect(hint).toBeNull();
    });
});
//# sourceMappingURL=plugin-read-skill-resolution.test.js.map