"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.registerInGlobalRegistry = registerInGlobalRegistry;
exports.buildClaudeMd = buildClaudeMd;
exports.buildAgentsMd = buildAgentsMd;
exports.repairMcpConfigs = repairMcpConfigs;
exports.runInit = runInit;
exports.runRepair = runRepair;
exports.run = run;
const node_fs_1 = __importDefault(require("node:fs"));
const promises_1 = __importDefault(require("node:fs/promises"));
const node_path_1 = __importDefault(require("node:path"));
const node_os_1 = __importDefault(require("node:os"));
const suggest_1 = require("./suggest");
const prefix_utils_1 = require("../prefix-utils");
// ── Global project registry ───────────────────────────────────────────────────
// ~/.docuflow/projects.json  — written by `docuflow init` so the UI can always
// find all initialized projects regardless of where they live on disk.
const GLOBAL_REGISTRY = node_path_1.default.join(node_os_1.default.homedir(), ".docuflow", "projects.json");
async function registerInGlobalRegistry(projectPath) {
    try {
        const dir = node_path_1.default.dirname(GLOBAL_REGISTRY);
        await promises_1.default.mkdir(dir, { recursive: true });
        let registry = { version: 1, projects: [] };
        try {
            const raw = await promises_1.default.readFile(GLOBAL_REGISTRY, "utf8");
            const parsed = JSON.parse(raw);
            if (Array.isArray(parsed.projects))
                registry = parsed;
        }
        catch { /* file doesn't exist yet */ }
        if (!registry.projects.includes(projectPath)) {
            registry.projects.push(projectPath);
            await promises_1.default.writeFile(GLOBAL_REGISTRY, JSON.stringify(registry, null, 2) + "\n", "utf8");
        }
    }
    catch { /* non-fatal — registry is best-effort */ }
}
function getClaudeDesktopConfigPath() {
    const platform = process.platform;
    if (platform === "darwin") {
        return node_path_1.default.join(node_os_1.default.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
    }
    else if (platform === "win32") {
        return node_path_1.default.join(node_os_1.default.homedir(), "AppData", "Roaming", "Claude", "claude_desktop_config.json");
    }
    return node_path_1.default.join(node_os_1.default.homedir(), ".config", "Claude", "claude_desktop_config.json");
}
function getVSCodeMcpConfigPath() {
    const platform = process.platform;
    if (platform === "darwin") {
        return node_path_1.default.join(node_os_1.default.homedir(), "Library", "Application Support", "Code", "User", "mcp.json");
    }
    else if (platform === "win32") {
        return node_path_1.default.join(node_os_1.default.homedir(), "AppData", "Roaming", "Code", "User", "mcp.json");
    }
    return node_path_1.default.join(node_os_1.default.homedir(), ".config", "Code", "User", "mcp.json");
}
function getCopilotCliMcpConfigPath() {
    return node_path_1.default.join(node_os_1.default.homedir(), ".copilot", "mcp-config.json");
}
function getCodexConfigPath() {
    return node_path_1.default.join(node_os_1.default.homedir(), ".codex", "config.toml");
}
function resolveServerBin() {
    // Use the exports map key — avoids ERR_PACKAGE_PATH_NOT_EXPORTED
    try {
        return require.resolve("@doquflow/studio/mcp");
    }
    catch {
        // Fallback 1: studio is a @doquflow sibling inside node_modules
        // __dirname = .../@doquflow/cli/dist/commands  →  ../../../../@doquflow/studio
        const sibling = node_path_1.default.resolve(__dirname, "..", "..", "..", "..", "@doquflow", "studio", "dist", "mcp", "index.js");
        if (node_fs_1.default.existsSync(sibling))
            return sibling;
        // Fallback 2: monorepo dev — packages/cli/dist/commands → packages/studio
        return node_path_1.default.resolve(__dirname, "..", "..", "..", "studio", "dist", "mcp", "index.js");
    }
}
async function copyTemplateFile(templateName, destPath) {
    try {
        // Try package-installed location first
        const templatePath = require.resolve(`@doquflow/cli/templates/${templateName}`);
        const content = await promises_1.default.readFile(templatePath, "utf8");
        await promises_1.default.writeFile(destPath, content, "utf8");
    }
    catch {
        try {
            // Fallback: monorepo sibling path (dev environment)
            const templatePath = node_path_1.default.resolve(__dirname, "..", "..", "templates", templateName);
            const content = await promises_1.default.readFile(templatePath, "utf8");
            await promises_1.default.writeFile(destPath, content, "utf8");
        }
        catch (err) {
            // If template not found, create a minimal version
            console.warn(`  ⚠ Could not find template for ${templateName}, creating minimal version`);
            if (templateName === "schema.md") {
                await promises_1.default.writeFile(destPath, "# Docuflow Wiki Schema\n\n## Domain\n[Edit this file to customize your wiki]\n", "utf8");
            }
            else if (templateName === "index.md") {
                await promises_1.default.writeFile(destPath, "# Wiki Index\n\nAuto-maintained catalog of pages.\n", "utf8");
            }
            else if (templateName === "log.md") {
                await promises_1.default.writeFile(destPath, "# Operation Log\n\nRecord of wiki operations.\n", "utf8");
            }
        }
    }
}
function buildClaudeMd(projectDir) {
    return `<!-- BEGIN DOCUFLOW -->
# DocuFlow — AI Documentation Assistant

DocuFlow preserves decision context for AI agents. Intent in, value out.

## Core tools (use these first)

- **query_wiki({ project_path, question })** — Ask the wiki. Returns an answer with citations.
- **ingest_source({ project_path, source_filename })** — Fold a markdown source into the wiki.
- **wiki_search({ project_path, query })** — BM25 search across all pages.
- **read_module({ path })** — Read and extract facts from a single source file.

## CLI — Core Commands

\`\`\`
docuflow query "<question>"         # ask the wiki from the shell
docuflow ingest <source.md>         # add a source doc to the wiki
docuflow status                     # wiki health and counts
docuflow rewiki                     # re-ingest with current rules
docuflow init                       # initialise .docuflow/ in this project
\`\`\`

## Workflows

### Answer a question
\`\`\`
query_wiki({ project_path: ".", question: "How does authentication work?" })
\`\`\`

### Add new context
\`\`\`
# drop a markdown file in .docuflow/sources/
ingest_source({ project_path: ".", source_filename: "auth-design.md" })
\`\`\`

## Advanced tools

Use when the core tools don't cover the workflow. Each has more parameters and side effects.

- **list_modules** — Walk a directory tree and extract facts in bulk
- **list_wiki** — Inventory pages by category, with staleness flags
- **write_spec / read_specs** — Persistent agent-written specs
- **save_answer_as_page** — Promote a synthesised answer into the wiki
- **synthesize_answer** — Combine multiple pages into a markdown synthesis
- **update_index** — Rebuild \`.docuflow/index.md\`
- **lint_wiki** — Health checks: orphans, broken refs, stale content
- **get_schema_guidance** — Recommend what pages should exist
- **preview_generation** — Show what a tool will do before running
- **generate_dependency_graph** — Build the import/shared-table graph

## Storage Layout

\`\`\`
.docuflow/
├── specs/           Spec files written by write_spec
├── wiki/            LLM-generated wiki pages
│   ├── entities/    Named things (services, APIs, databases)
│   ├── concepts/    Design patterns, principles, integrations
│   ├── timelines/   Chronological pages
│   └── syntheses/   Cross-cutting synthesis pages
├── sources/         Raw input files for ingest_source
├── schema.md        Wiki configuration (edit to customise)
├── index.md         Auto-maintained catalog
└── log.md           Operation log
\`\`\`
<!-- END DOCUFLOW -->`;
}
async function writeClaudeMd(projectDir) {
    const claudeMdPath = node_path_1.default.join(projectDir, "CLAUDE.md");
    const newSection = buildClaudeMd(projectDir);
    if (node_fs_1.default.existsSync(claudeMdPath)) {
        const existing = await promises_1.default.readFile(claudeMdPath, "utf8");
        if (existing.includes("<!-- BEGIN DOCUFLOW -->") && existing.includes("<!-- END DOCUFLOW -->")) {
            // Marker-based replacement — idempotent re-runs preserve surrounding content
            const replaced = existing.replace(/<!-- BEGIN DOCUFLOW -->[\s\S]*?<!-- END DOCUFLOW -->/, newSection.trimEnd());
            await promises_1.default.writeFile(claudeMdPath, replaced, "utf8");
        }
        else if (existing.includes("DocuFlow")) {
            // Old format without markers — replace old DocuFlow section, add markers this time
            const withoutDocuflow = existing.replace(/\n?# DocuFlow[\s\S]*/, "").trimEnd();
            await promises_1.default.writeFile(claudeMdPath, withoutDocuflow + "\n\n" + newSection, "utf8");
        }
        else {
            // No DocuFlow section yet — append
            await promises_1.default.appendFile(claudeMdPath, "\n\n" + newSection, "utf8");
        }
    }
    else {
        await promises_1.default.writeFile(claudeMdPath, newSection, "utf8");
    }
}
function buildAgentsMd(projectDir) {
    return `# DocuFlow — AI Documentation Assistant

DocuFlow is an MCP server that provides structured access to this codebase and maintains a living wiki.
It is registered via \`.codex/config.toml\` and available as MCP tools in every Codex session.

## Available MCP Tools

### Codebase Scanner
- **read_module** — Analyse a single file: language, classes, functions, dependencies, DB tables, endpoints, config refs, raw content.
  - \`read_module({ path: "src/UserService.cs" })\`
- **list_modules** — Walk a directory, extract facts for every file. One call to understand the whole project.
  - \`list_modules({ path: "." })\`
- **write_spec** — Save a markdown spec to \`.docuflow/specs/<name>.md\`.
  - \`write_spec({ project_path: ".", filename: "UserService", content: "..." })\`
- **read_specs** — Read saved specs, optionally filtered by name.
  - \`read_specs({ project_path: "." })\`

### Wiki Pipeline
- **ingest_source** — Ingest a markdown file from \`.docuflow/sources/\` into the wiki (entities, concepts).
- **update_index** — Rebuild \`.docuflow/index.md\` from all wiki pages.
- **list_wiki** — List all wiki pages by category (entity/concept/timeline/synthesis).
- **wiki_search** — BM25 search across all wiki pages.
- **query_wiki** — Q&A: searches wiki, synthesises an answer, returns citations.
  - \`query_wiki({ project_path: ".", question: "How does auth work?" })\`
- **synthesize_answer** — Generate a markdown synthesis from a list of page IDs.
- **save_answer_as_page** — Persist a synthesis as a wiki page.

### Health & Guidance
- **lint_wiki** — Health check: orphan pages, broken refs, stale content. Returns a 0–100 health score.
- **get_schema_guidance** — Recommend what wiki pages should exist based on schema + current state.
- **preview_generation** — Preview what a tool will generate before running it.

## Common Workflows

Start here — understand the codebase:
\`\`\`
list_modules({ path: "." })
→ write_spec for important modules
\`\`\`

Answer a question:
\`\`\`
query_wiki({ project_path: ".", question: "..." })
\`\`\`

Maintain wiki health:
\`\`\`
lint_wiki({ project_path: "." })
\`\`\`

## Storage Layout

\`\`\`
.docuflow/
├── specs/        Code specs written by write_spec
├── wiki/         LLM-generated wiki pages
│   ├── entities/
│   ├── concepts/
│   ├── timelines/
│   └── syntheses/
├── sources/      Raw markdown docs to ingest
├── schema.md     Wiki configuration (edit to customise)
├── index.md      Auto-maintained catalog
└── log.md        Operation log
\`\`\`
`;
}
async function writeAgentsMd(projectDir) {
    const agentsMdPath = node_path_1.default.join(projectDir, "AGENTS.md");
    const newSection = buildAgentsMd(projectDir);
    if (node_fs_1.default.existsSync(agentsMdPath)) {
        const existing = await promises_1.default.readFile(agentsMdPath, "utf8");
        if (existing.includes("DocuFlow")) {
            // Replace existing DocuFlow section
            const withoutDocuflow = existing.replace(/\n?# DocuFlow[\s\S]*/, "").trimEnd();
            await promises_1.default.writeFile(agentsMdPath, withoutDocuflow + "\n\n" + newSection, "utf8");
        }
        else {
            // Append to existing AGENTS.md
            await promises_1.default.appendFile(agentsMdPath, "\n\n" + newSection, "utf8");
        }
    }
    else {
        await promises_1.default.writeFile(agentsMdPath, newSection, "utf8");
    }
}
/**
 * Detect and repair MCP server registrations in global and per-project configs.
 *
 * DEF-12: Beyond checking that the registered file exists, also detect:
 *   1. Cross-prefix mismatch — node binary prefix ≠ MCP entry path prefix
 *   2. Stale version     — registered code is older than the newest installed
 *
 * Covers: Claude Desktop global, VS Code global, Copilot CLI global,
 *         and .mcp.json in the current working directory (per-project).
 */
async function repairMcpConfigs() {
    // Find the best (newest, self-consistent) installation to target
    const allInstalls = (0, prefix_utils_1.findInstallsSync)();
    const bestInstall = allInstalls[0]; // sorted newest-first by findInstallsSync
    // Fall back to the running process if no external installs found
    const targetNodeBin = bestInstall?.nodeBin ?? process.execPath;
    const targetServerBin = bestInstall?.serverBin ?? resolveServerBin();
    const targetVersion = bestInstall?.version ?? "unknown";
    const repaired = [];
    const already_ok = [];
    const skipped = [];
    /**
     * Determine whether an existing entry needs repair.
     * Returns a reason string if repair is needed, undefined if it is clean.
     */
    function repairReason(entry) {
        const recorded = Array.isArray(entry.args) ? entry.args[0] : undefined;
        // 1. Missing / deleted file
        if (!recorded || !node_fs_1.default.existsSync(recorded)) {
            return `missing file (${recorded ?? "no args[0]"})`;
        }
        // 2. Cross-prefix mismatch: node binary prefix ≠ MCP entry path prefix
        const registeredNodeBin = entry.command;
        if (registeredNodeBin) {
            const nodeBinPrefix = node_path_1.default.dirname(node_path_1.default.dirname(registeredNodeBin));
            const mcpEntryPrefix = (0, prefix_utils_1.getMcpEntryPrefix)(recorded);
            if (mcpEntryPrefix &&
                node_path_1.default.resolve(nodeBinPrefix) !== node_path_1.default.resolve(mcpEntryPrefix)) {
                return `cross-prefix (node: ${nodeBinPrefix} ≠ entry: ${mcpEntryPrefix})`;
            }
        }
        // 3. Stale version: registered install is older than newest found
        const registeredVersion = (0, prefix_utils_1.getInstalledCliVersion)(recorded);
        if (registeredVersion && (0, prefix_utils_1.semverGt)(targetVersion, registeredVersion)) {
            return `stale version (${registeredVersion} → ${targetVersion})`;
        }
        return undefined; // clean
    }
    async function checkAndRepairJson(configPath, label, getEntry, writeEntry) {
        try {
            const raw = await promises_1.default.readFile(configPath, "utf8");
            const cfg = JSON.parse(raw);
            const entry = getEntry(cfg);
            if (!entry) {
                skipped.push(`${label} — no docuflow entry`);
                return;
            }
            const reason = repairReason(entry);
            if (!reason) {
                already_ok.push(label);
                return;
            }
            writeEntry(cfg);
            await promises_1.default.writeFile(configPath, JSON.stringify(cfg, null, 2) + "\n", "utf8");
            repaired.push(`${label} (${reason} → ${targetServerBin})`);
        }
        catch {
            skipped.push(`${label} — not found or unreadable`);
        }
    }
    // ── Global: Claude Desktop ──────────────────────────────────────────────────
    await checkAndRepairJson(getClaudeDesktopConfigPath(), "Claude Desktop", (cfg) => cfg.mcpServers?.docuflow, (cfg) => {
        if (!cfg.mcpServers)
            cfg.mcpServers = {};
        cfg.mcpServers.docuflow = {
            command: targetNodeBin,
            args: [targetServerBin],
        };
    });
    // ── Global: VS Code user MCP ───────────────────────────────────────────────
    await checkAndRepairJson(getVSCodeMcpConfigPath(), "VS Code", (cfg) => cfg.servers?.docuflow, (cfg) => {
        if (!cfg.servers)
            cfg.servers = {};
        cfg.servers.docuflow = {
            command: targetNodeBin,
            args: [targetServerBin],
            type: "stdio",
        };
    });
    // ── Global: Copilot CLI ────────────────────────────────────────────────────
    await checkAndRepairJson(getCopilotCliMcpConfigPath(), "Copilot CLI", (cfg) => cfg.mcpServers?.docuflow, (cfg) => {
        if (!cfg.mcpServers)
            cfg.mcpServers = {};
        cfg.mcpServers.docuflow = {
            type: "local",
            command: targetNodeBin,
            args: [targetServerBin],
            tools: ["*"],
        };
    });
    // ── Per-project: .mcp.json in current working directory ───────────────────
    const localMcpPath = node_path_1.default.join(process.cwd(), ".mcp.json");
    await checkAndRepairJson(localMcpPath, ".mcp.json (project)", (cfg) => {
        const servers = (cfg.mcpServers ?? cfg.servers);
        return servers?.docuflow;
    }, (cfg) => {
        // Preserve whichever key the file already uses (mcpServers vs servers)
        const key = cfg.mcpServers !== undefined ? "mcpServers" : "servers";
        if (!cfg[key])
            cfg[key] = {};
        cfg[key].docuflow = {
            type: "stdio",
            command: targetNodeBin,
            args: [targetServerBin],
        };
    });
    return { repaired, already_ok, skipped };
}
/**
 * Core init logic — creates the .docuflow/ structure, registers MCP configs,
 * writes CLAUDE.md/AGENTS.md, installs git hook, and registers in global registry.
 *
 * Accepts the target projectDir explicitly so it can be called from both the CLI
 * (which uses process.cwd()) and the API (/api/init which receives the path from
 * the request body).
 */
async function runInit(projectDir) {
    const details = [];
    const configPath = getClaudeDesktopConfigPath();
    const vscodeConfigPath = getVSCodeMcpConfigPath();
    const copilotCliConfigPath = getCopilotCliMcpConfigPath();
    const codexConfigPath = getCodexConfigPath();
    const serverBin = resolveServerBin();
    const nodeBin = process.execPath;
    // Register in Claude Desktop config
    try {
        let config = {};
        try {
            const raw = await promises_1.default.readFile(configPath, "utf8");
            config = JSON.parse(raw);
        }
        catch { /* File doesn't exist yet — that's fine */ }
        if (!config.mcpServers)
            config.mcpServers = {};
        config.mcpServers.docuflow = { command: nodeBin, args: [serverBin] };
        await promises_1.default.mkdir(node_path_1.default.dirname(configPath), { recursive: true });
        await promises_1.default.writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
        details.push("Claude Desktop MCP registered");
    }
    catch {
        details.push("Claude Desktop — skipped (not installed)");
    }
    // Register in VS Code (GitHub Copilot) user MCP config
    let vscodeRegistered = false;
    try {
        let vscodeConfig = {};
        try {
            const raw = await promises_1.default.readFile(vscodeConfigPath, "utf8");
            vscodeConfig = JSON.parse(raw);
        }
        catch { /* File may not exist */ }
        if (!vscodeConfig.servers)
            vscodeConfig.servers = {};
        vscodeConfig.servers.docuflow = { command: nodeBin, args: [serverBin], type: "stdio" };
        await promises_1.default.mkdir(node_path_1.default.dirname(vscodeConfigPath), { recursive: true });
        await promises_1.default.writeFile(vscodeConfigPath, JSON.stringify(vscodeConfig, null, 2) + "\n", "utf8");
        vscodeRegistered = true;
        details.push("VS Code Copilot MCP registered");
    }
    catch { /* VS Code not installed — skip */ }
    // Register in GitHub Copilot CLI MCP config (~/.copilot/mcp-config.json)
    let copilotCliRegistered = false;
    try {
        let copilotCliConfig = {};
        try {
            const raw = await promises_1.default.readFile(copilotCliConfigPath, "utf8");
            copilotCliConfig = JSON.parse(raw);
        }
        catch { /* File may not exist yet */ }
        if (!copilotCliConfig.mcpServers)
            copilotCliConfig.mcpServers = {};
        copilotCliConfig.mcpServers.docuflow = { type: "local", command: nodeBin, args: [serverBin], tools: ["*"] };
        await promises_1.default.mkdir(node_path_1.default.dirname(copilotCliConfigPath), { recursive: true });
        await promises_1.default.writeFile(copilotCliConfigPath, JSON.stringify(copilotCliConfig, null, 2) + "\n", "utf8");
        copilotCliRegistered = true;
        details.push("Copilot CLI MCP registered");
    }
    catch { /* Copilot CLI not installed — skip */ }
    // Register in OpenAI Codex CLI (~/.codex/config.toml in TOML format)
    let codexCliRegistered = false;
    try {
        await promises_1.default.mkdir(node_path_1.default.dirname(codexConfigPath), { recursive: true });
        let tomlContent = "";
        try {
            tomlContent = await promises_1.default.readFile(codexConfigPath, "utf8");
        }
        catch { /* new file */ }
        if (!tomlContent.includes("[mcp_servers.docuflow]")) {
            const entry = `\n[mcp_servers.docuflow]\ncommand = "${nodeBin}"\nargs = [${JSON.stringify(serverBin)}]\n`;
            await promises_1.default.writeFile(codexConfigPath, tomlContent + entry, "utf8");
        }
        codexCliRegistered = true;
        details.push("Codex CLI MCP registered");
    }
    catch { /* Codex CLI not installed — skip */ }
    // Suppress unused-variable warnings when variables are only used in console.log branches
    void vscodeRegistered;
    void copilotCliRegistered;
    void codexCliRegistered;
    // Create .docuflow/ directory structure
    const docuflowDir = node_path_1.default.join(projectDir, ".docuflow");
    const specsDir = node_path_1.default.join(docuflowDir, "specs");
    const wikiDir = node_path_1.default.join(docuflowDir, "wiki");
    const sourcesDir = node_path_1.default.join(docuflowDir, "sources");
    await promises_1.default.mkdir(specsDir, { recursive: true });
    await promises_1.default.mkdir(node_path_1.default.join(wikiDir, "entities"), { recursive: true });
    await promises_1.default.mkdir(node_path_1.default.join(wikiDir, "concepts"), { recursive: true });
    await promises_1.default.mkdir(node_path_1.default.join(wikiDir, "timelines"), { recursive: true });
    await promises_1.default.mkdir(node_path_1.default.join(wikiDir, "syntheses"), { recursive: true });
    await promises_1.default.mkdir(sourcesDir, { recursive: true });
    details.push("Created .docuflow/ directory structure");
    // Copy or create template files
    await copyTemplateFile("schema.md", node_path_1.default.join(docuflowDir, "schema.md"));
    await copyTemplateFile("index.md", node_path_1.default.join(docuflowDir, "index.md"));
    await copyTemplateFile("log.md", node_path_1.default.join(docuflowDir, "log.md"));
    details.push("Wrote schema.md, index.md, log.md");
    // Generate CLAUDE.md
    await writeClaudeMd(projectDir);
    details.push("Wrote CLAUDE.md");
    // Generate AGENTS.md
    await writeAgentsMd(projectDir);
    details.push("Wrote AGENTS.md");
    // Write .vscode/mcp.json for project-level workspace MCP config
    try {
        const vscodeDirPath = node_path_1.default.join(projectDir, ".vscode");
        const vscodeWorkspaceMcpPath = node_path_1.default.join(vscodeDirPath, "mcp.json");
        let workspaceMcpConfig = {};
        try {
            const raw = await promises_1.default.readFile(vscodeWorkspaceMcpPath, "utf8");
            workspaceMcpConfig = JSON.parse(raw);
        }
        catch { /* File doesn't exist yet */ }
        if (!workspaceMcpConfig.servers)
            workspaceMcpConfig.servers = {};
        workspaceMcpConfig.servers.docuflow = {
            command: "npx",
            args: ["-y", "-p", "@doquflow/server", "docuflow-server"],
            type: "stdio",
        };
        await promises_1.default.mkdir(vscodeDirPath, { recursive: true });
        await promises_1.default.writeFile(vscodeWorkspaceMcpPath, JSON.stringify(workspaceMcpConfig, null, 2) + "\n", "utf8");
        details.push("Wrote .vscode/mcp.json");
    }
    catch { /* non-fatal */ }
    // Add .docuflow/ to .gitignore if present and not already listed
    try {
        const gitignorePath = node_path_1.default.join(projectDir, ".gitignore");
        if (node_fs_1.default.existsSync(gitignorePath)) {
            const gitignore = await promises_1.default.readFile(gitignorePath, "utf8");
            if (!gitignore.includes(".docuflow/") && !gitignore.includes(".docuflow")) {
                await promises_1.default.appendFile(gitignorePath, "\n# Docuflow\n.docuflow/\n");
                details.push("Added .docuflow/ to .gitignore");
            }
        }
    }
    catch { /* non-fatal */ }
    // Install git post-commit hook
    await installGitHook(projectDir);
    details.push("Installed git post-commit hook");
    // Register in global project registry
    await registerInGlobalRegistry(projectDir);
    details.push("Registered in global project registry (~/.docuflow/projects.json)");
    return { ok: true, path: projectDir, details };
}
async function runRepair() {
    console.log("DocuFlow — repairing MCP config paths…");
    console.log("");
    const result = await repairMcpConfigs();
    for (const r of result.repaired)
        console.log(`  ✓ Repaired: ${r}`);
    for (const r of result.already_ok)
        console.log(`  ✓ OK:       ${r}`);
    for (const r of result.skipped)
        console.log(`  - Skipped:  ${r}`);
    if (result.repaired.length === 0 && result.already_ok.length === 0) {
        console.log("  (no docuflow MCP entries found in any config)");
    }
    console.log("");
    if (result.repaired.length > 0) {
        console.log("Restart Claude Desktop / reload VS Code to pick up the corrected paths.");
    }
}
async function run(opts = {}) {
    if (opts.repair) {
        return runRepair();
    }
    const result = await runInit(process.cwd());
    const docuflowDir = node_path_1.default.join(result.path, ".docuflow");
    console.log("✓ DocuFlow initialised successfully.");
    console.log("");
    console.log("📁 Structure created:");
    console.log(`  ${docuflowDir}/`);
    console.log(`  ├── specs/              (code specs written by the agent)`);
    console.log(`  ├── wiki/               (LLM-generated wiki pages)`);
    console.log(`  │   ├── entities/`);
    console.log(`  │   ├── concepts/`);
    console.log(`  │   ├── timelines/`);
    console.log(`  │   └── syntheses/`);
    console.log(`  ├── sources/            (raw markdown documents to ingest)`);
    console.log(`  ├── schema.md           (wiki configuration)`);
    console.log(`  ├── index.md            (auto-maintained catalog)`);
    console.log(`  └── log.md              (operation log)`);
    console.log("");
    console.log("📝 Steps completed:");
    for (const line of result.details) {
        console.log(`  ✓ ${line}`);
    }
    console.log("");
    console.log("📖 Next steps:");
    console.log("  1. Edit .docuflow/schema.md to customize your wiki domain");
    console.log("  2. Add markdown docs to .docuflow/sources/ then ingest them");
    console.log("  3. Restart Claude Desktop / reload VS Code / restart Copilot CLI");
    console.log("");
    console.log("⚡ Auto-sync options:");
    console.log("  docuflow watch           # background daemon (watches for file changes)");
    console.log("  docuflow watch --ai      # + Claude/Codex documents code changes automatically");
    console.log("  docuflow sync            # one-shot sync (good for CI/CD)");
    console.log("  docuflow sync --ai       # + AI generates docs from last git commit");
    console.log("");
    console.log("  A git post-commit hook was installed at .git/hooks/post-commit");
    console.log("  It runs \"docuflow sync --ai --quiet\" after every commit automatically.");
    console.log("");
    console.log("─────────────────────────────────────────────────────");
    await (0, suggest_1.run)();
}
/**
 * Install a git post-commit hook that runs `docuflow sync` automatically.
 * Idempotent — does not overwrite a hook that already has DocuFlow content.
 */
async function installGitHook(projectDir) {
    const gitDir = node_path_1.default.join(projectDir, ".git");
    if (!node_fs_1.default.existsSync(gitDir))
        return; // not a git repo
    const hooksDir = node_path_1.default.join(gitDir, "hooks");
    await promises_1.default.mkdir(hooksDir, { recursive: true });
    const hookPath = node_path_1.default.join(hooksDir, "post-commit");
    const hookMarker = "# docuflow-auto-sync";
    // Don't overwrite if already installed
    if (node_fs_1.default.existsSync(hookPath)) {
        const existing = await promises_1.default.readFile(hookPath, "utf8");
        if (existing.includes(hookMarker))
            return;
        // Append to existing hook
        const appendContent = [
            "",
            hookMarker,
            `# Auto-generated by docuflow init — runs wiki sync after every commit`,
            `# Requires Claude CLI, Codex CLI, or ANTHROPIC_API_KEY for AI-powered doc generation`,
            `# Remove the lines below to disable auto-sync`,
            `if command -v docuflow &> /dev/null; then`,
            `  docuflow sync --ai --quiet &`,
            `fi`,
        ].join("\n");
        await promises_1.default.appendFile(hookPath, appendContent + "\n");
        return;
    }
    // Create new hook file
    const hookContent = [
        `#!/bin/sh`,
        hookMarker,
        `# Auto-generated by docuflow init`,
        `# Syncs the DocuFlow wiki after every commit using Claude / Codex / Anthropic API`,
        `# AI bridge priority: Claude CLI > Codex CLI > ANTHROPIC_API_KEY`,
        `# Run in background (&) so it never delays your git workflow`,
        `if command -v docuflow &> /dev/null; then`,
        `  docuflow sync --ai --quiet &`,
        `fi`,
    ].join("\n");
    await promises_1.default.writeFile(hookPath, hookContent + "\n", "utf8");
    // Make executable
    node_fs_1.default.chmodSync(hookPath, 0o755);
}
