#!/usr/bin/env node
import { copyFile, mkdir, readdir, readFile, rm, writeFile, } from "node:fs/promises";
import { basename, dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { PACKAGE_NAME, PLUGIN_MODES, getPluginHooksConfig, getClaudePluginManifest, getClaudePluginMarketplaceManifest, getClaudeRepoMarketplaceManifest, getPluginManifest, } from "../lib/plugin-metadata.mjs";
import { normalizeTier, parseSkillFrontmatter, renderBundledSkillsReadme, } from "../lib/skill-tiers.mjs";
const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
const PLUGINS_DIR = join(REPO_ROOT, "plugins");
const PLUGIN_BUNDLE_DIR = join(PLUGINS_DIR, PACKAGE_NAME);
const CLAUDE_REPO_MARKETPLACE_PATH = join(REPO_ROOT, ".claude-plugin", "marketplace.json");
async function writeJson(filePath, data) {
    await mkdir(dirname(filePath), { recursive: true });
    await writeFile(filePath, `${JSON.stringify(data, null, 2)}\n`);
}
async function copyFileTo(sourcePath, targetPath) {
    await mkdir(dirname(targetPath), { recursive: true });
    await copyFile(sourcePath, targetPath);
}
async function copyDirectory(sourceDir, targetDir) {
    await mkdir(targetDir, { recursive: true });
    const entries = await readdir(sourceDir, { withFileTypes: true });
    for (const entry of entries) {
        const sourcePath = join(sourceDir, entry.name);
        const targetPath = join(targetDir, entry.name);
        if (entry.isDirectory()) {
            await copyDirectory(sourcePath, targetPath);
            continue;
        }
        if (entry.isFile()) {
            await copyFile(sourcePath, targetPath);
        }
    }
}
async function writeBundledSkills() {
    const sourceSkillsDir = join(REPO_ROOT, "skills");
    const targetSkillsDir = join(PLUGIN_BUNDLE_DIR, "skills");
    const companionSkills = (await readdir(sourceSkillsDir))
        .filter((file) => file.endsWith(".md") && file !== "README.md")
        .sort();
    await mkdir(targetSkillsDir, { recursive: true });
    await copyFileTo(join(REPO_ROOT, "SKILL.md"), join(targetSkillsDir, PACKAGE_NAME, "SKILL.md"));
    // Build the SkillMeta list as we copy each source skill into the bundle.
    // The core continuous-improvement skill is treated as tier "core" — it's
    // the 7 Laws spec itself, not a companion — so it leads the bundled README
    // in its own section, separate from the featured companion.
    const coreSkillContent = await readFile(join(REPO_ROOT, "SKILL.md"), "utf8");
    const coreFrontmatter = parseSkillFrontmatter(coreSkillContent);
    const skillsForReadme = [
        {
            name: PACKAGE_NAME,
            tier: "core",
            description: coreFrontmatter.description,
        },
    ];
    for (const file of companionSkills) {
        const skillName = basename(file, ".md");
        const skillDir = join(targetSkillsDir, skillName);
        await mkdir(skillDir, { recursive: true });
        await copyFile(join(sourceSkillsDir, file), join(skillDir, "SKILL.md"));
        const sourcePath = join(sourceSkillsDir, file);
        const content = await readFile(sourcePath, "utf8");
        const front = parseSkillFrontmatter(content);
        skillsForReadme.push({
            name: front.name ?? skillName,
            tier: normalizeTier(front.tier),
            description: front.description,
        });
    }
    await writeFile(join(targetSkillsDir, "README.md"), renderBundledSkillsReadme(skillsForReadme));
}
async function writePluginBundleReadme() {
    const readme = [
        "# Continuous Improvement Plugin Bundle (Claude Code)",
        "",
        "This directory is generated by `npm run build`.",
        "Do not edit files here manually; edit the source files in the repo root and rebuild.",
        "",
        "Included surfaces:",
        "- `.claude-plugin/plugin.json`",
        "- `.claude-plugin/marketplace.json`",
        "- `skills/`",
        "- `commands/`",
        "- `agents/` — `code-reviewer`, `security-auditor`, `test-engineer` personas (auto-discovered Claude Code subagents; pattern from addy/agent-skills)",
        "- `hooks/`",
        "- `bin/mcp-server.mjs`",
        "- `bin/observe.mjs`",
        "- `bin/backfill.mjs`",
        "- `lib/plugin-metadata.mjs`",
        "- `lib/observe-event.mjs`",
        "- `instinct-packs/`",
        "- `templates/planning-with-files/`",
        "",
        "## Required vs Optional companions",
        "",
        "The `proceed-with-the-recommendation` skill (bundled here) routes each",
        "recommendation it walks to a specialist skill. Some specialists ship in",
        "this bundle; the rest live in external plugins. Every external routing",
        "target has a concretely-worded inline fallback in the orchestrator skill,",
        "so the plugin works on a clean install with no other plugins present —",
        "the trade-off is fallback quality vs dedicated-skill quality.",
        "",
        "**Bundled with this plugin (no extra install needed):**",
        "",
        "- `continuous-improvement` — core 7 Laws skill",
        "- `proceed-with-the-recommendation` — the orchestrator itself",
        "- `ralph` — autonomous PRD-scale loop",
        "- `tdd-workflow` — RED/GREEN/REFACTOR + 80% coverage gate",
        "- `workspace-surface-audit` — environment + capability audit",
        "- Tier-1/Tier-2 enforcement skills (`gateguard`, `verification-loop`,",
        "  `safety-guard`, `token-budget-advisor`,",
        "  `strategic-compact`, `wild-risa-balance`)",
        "",
        "**Optional companions the orchestrator routes to (install separately if",
        "you want the dedicated skill instead of the inline fallback):**",
        "",
        "| Source plugin | Routing targets | Notes |",
        "|---|---|---|",
        "| `obra/superpowers` | `superpowers:brainstorming`, `:writing-plans`, `:systematic-debugging`, `:test-driven-development`, `:requesting-code-review`, `:verification-before-completion`, `:dispatching-parallel-agents`, `:finishing-a-development-branch`, `simplify`, `schedule`, `loop`, `update-config` | Largest external surface; covers planning, debugging, parallel dispatch, branch-finish |",
        "| Claude Code host (Anthropic built-in) | `security-review` | Ships with the host CLI itself, not a separate plugin install |",
        "| `code-review` plugin | `code-review` | Diff walk + severity tagging |",
        "| `documentation-lookup` agent / `context7` MCP | `documentation-lookup` | Library docs lookup with citations |",
        "| `frontend-design` plugin | `frontend-design:frontend-design` | Distinctive UI generation |",
        "| `commit-commands` plugin | `commit-commands:commit`, `:commit-push-pr` | Conventional-commit + push-PR helpers |",
        "",
        "Full per-target audit (license status, bundled flag, inline fallback,",
        "risk-if-absent) lives in `docs/audits/2026-05-06-routing-target-gap.md`.",
        "Per-target inline fallbacks are spelled out in the orchestrator skill at",
        "`skills/proceed-with-the-recommendation/SKILL.md` § \"Routing Table",
        "(with Inline Fallbacks)\".",
        "",
    ].join("\n");
    await writeFile(join(PLUGIN_BUNDLE_DIR, "README.md"), readme);
}
async function writePluginBundle() {
    await rm(PLUGIN_BUNDLE_DIR, { recursive: true, force: true });
    await mkdir(PLUGIN_BUNDLE_DIR, { recursive: true });
    await Promise.all([
        writeJson(join(PLUGIN_BUNDLE_DIR, ".claude-plugin", "plugin.json"), getClaudePluginManifest()),
        writeJson(join(PLUGIN_BUNDLE_DIR, ".claude-plugin", "marketplace.json"), getClaudePluginMarketplaceManifest()),
        copyDirectory(join(REPO_ROOT, "commands"), join(PLUGIN_BUNDLE_DIR, "commands")),
        copyDirectory(join(REPO_ROOT, "agents"), join(PLUGIN_BUNDLE_DIR, "agents")),
        copyDirectory(join(REPO_ROOT, "hooks"), join(PLUGIN_BUNDLE_DIR, "hooks")),
        copyDirectory(join(REPO_ROOT, "instinct-packs"), join(PLUGIN_BUNDLE_DIR, "instinct-packs")),
        copyDirectory(join(REPO_ROOT, "templates", "planning-with-files"), join(PLUGIN_BUNDLE_DIR, "templates", "planning-with-files")),
        copyFileTo(join(REPO_ROOT, "bin", "mcp-server.mjs"), join(PLUGIN_BUNDLE_DIR, "bin", "mcp-server.mjs")),
        copyFileTo(join(REPO_ROOT, "bin", "observe.mjs"), join(PLUGIN_BUNDLE_DIR, "bin", "observe.mjs")),
        copyFileTo(join(REPO_ROOT, "bin", "backfill.mjs"), join(PLUGIN_BUNDLE_DIR, "bin", "backfill.mjs")),
        copyFileTo(join(REPO_ROOT, "bin", "gateguard-clear.mjs"), join(PLUGIN_BUNDLE_DIR, "bin", "gateguard-clear.mjs")),
        copyFileTo(join(REPO_ROOT, "lib", "gateguard-state.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "gateguard-state.mjs")),
        copyFileTo(join(REPO_ROOT, "lib", "plugin-metadata.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "plugin-metadata.mjs")),
        copyFileTo(join(REPO_ROOT, "lib", "resolve-home-dir.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "resolve-home-dir.mjs")),
        copyFileTo(join(REPO_ROOT, "lib", "observe-event.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "observe-event.mjs")),
        copyFileTo(join(REPO_ROOT, "lib", "goal-state.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "goal-state.mjs")),
        copyFileTo(join(REPO_ROOT, "lib", "goal-drift-gate.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "goal-drift-gate.mjs")),
        copyFileTo(join(REPO_ROOT, "lib", "recall-index.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "recall-index.mjs")),
        copyFileTo(join(REPO_ROOT, "lib", "recall-briefing.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "recall-briefing.mjs")),
        copyFileTo(join(REPO_ROOT, "lib", "skill-distill.mjs"), join(PLUGIN_BUNDLE_DIR, "lib", "skill-distill.mjs")),
        copyFileTo(join(REPO_ROOT, "LICENSE"), join(PLUGIN_BUNDLE_DIR, "LICENSE")),
        writePluginBundleReadme(),
    ]);
    await writeJson(join(PLUGIN_BUNDLE_DIR, "hooks", "hooks.json"), getPluginHooksConfig());
    await writeBundledSkills();
    // PM plugins are no longer surfaced in the repo-level marketplace as the project
    // refocuses on the 7 Laws of AI Agent Discipline. Source plugin directories under
    // plugins/pm-* remain on disk pending follow-up removal. The discoverPm... helper
    // is preserved so downstream consumers (and the function-level test) still work.
    const pmEntries = [];
    await writeJson(CLAUDE_REPO_MARKETPLACE_PATH, getClaudeRepoMarketplaceManifest(pmEntries));
}
await mkdir(PLUGINS_DIR, { recursive: true });
for (const mode of PLUGIN_MODES) {
    const outputPath = join(PLUGINS_DIR, `${mode}.json`);
    await writeFile(outputPath, `${JSON.stringify(getPluginManifest(mode), null, 2)}\n`);
    console.log(`Generated ${outputPath}`);
}
await writePluginBundle();
console.log(`Generated ${join(PLUGIN_BUNDLE_DIR, ".claude-plugin", "plugin.json")}`);
console.log(`Generated ${CLAUDE_REPO_MARKETPLACE_PATH}`);
