// ---------------------------------------------------------------------------
// CLI command handlers
// ---------------------------------------------------------------------------
import { getFlag, getBoolFlag, getNumFlag, requireArg, requireFlag, parseCommaSeparated, output, die } from "./args.js";
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const VALID_SYMBOL_KINDS = new Set([
    "function", "method", "class", "interface", "type", "variable", "constant",
    "field", "enum", "namespace", "module", "section", "metadata",
    "test_suite", "test_case", "test_hook", "default_export", "unknown",
]);
const EXCLUDE_TESTS_QUERY_TYPES = new Set(["semantic", "hybrid"]);
// ---------------------------------------------------------------------------
// Index commands
// ---------------------------------------------------------------------------
async function handleIndex(args, flags) {
    const path = requireArg(args, 0, "path");
    const { indexFolder } = await import("../tools/index-tools.js");
    const result = await indexFolder(path, {
        incremental: getBoolFlag(flags, "incremental"),
        include_paths: parseCommaSeparated(flags, "include-paths"),
        watch: getBoolFlag(flags, "no-watch") === true ? false : undefined,
    });
    output(result, flags);
}
async function handleIndexRepo(args, flags) {
    const url = requireArg(args, 0, "url");
    const { indexRepo } = await import("../tools/index-tools.js");
    const result = await indexRepo(url, {
        branch: getFlag(flags, "branch"),
        include_paths: parseCommaSeparated(flags, "include-paths"),
    });
    output(result, flags);
}
async function handleRepos(_args, flags) {
    const { listAllRepos } = await import("../tools/index-tools.js");
    const result = await listAllRepos();
    output(result, flags);
}
async function handleInvalidate(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const { invalidateCache } = await import("../tools/index-tools.js");
    const result = await invalidateCache(repo);
    output({ invalidated: result, repo }, flags);
}
async function handleIndexConversations(args, flags) {
    const projectPath = args[0];
    const { indexConversations } = await import("../tools/conversation-tools.js");
    const result = await indexConversations(projectPath);
    if (!getBoolFlag(flags, "quiet")) {
        output(result, flags);
    }
}
// ---------------------------------------------------------------------------
// Search commands
// ---------------------------------------------------------------------------
async function handleSearch(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const query = requireArg(args, 1, "query");
    const { searchText } = await import("../tools/search-tools.js");
    const result = await searchText(repo, query, {
        file_pattern: getFlag(flags, "file-pattern"),
        regex: getBoolFlag(flags, "regex"),
        context_lines: getNumFlag(flags, "context-lines"),
        max_results: getNumFlag(flags, "max-results"),
        group_by_file: getBoolFlag(flags, "group-by-file"),
    });
    output(result, flags);
}
async function handleSymbols(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const query = requireArg(args, 1, "query");
    const { searchSymbols } = await import("../tools/search-tools.js");
    const kindRaw = getFlag(flags, "kind");
    if (kindRaw !== undefined && !VALID_SYMBOL_KINDS.has(kindRaw)) {
        die(`Invalid --kind: ${kindRaw}. Valid: ${Array.from(VALID_SYMBOL_KINDS).join(", ")}`);
    }
    const includeSource = getBoolFlag(flags, "include-source");
    const explicitTopK = getNumFlag(flags, "top-k");
    // When --include-source is set and no explicit --top-k, default to 5
    // instead of 50 to avoid returning 50 full function bodies
    const topK = explicitTopK ?? (includeSource ? 5 : undefined);
    const result = await searchSymbols(repo, query, {
        kind: kindRaw,
        file_pattern: getFlag(flags, "file-pattern"),
        include_source: includeSource,
        top_k: topK,
        source_chars: getNumFlag(flags, "source-chars"),
    });
    output(result, flags);
}
// ---------------------------------------------------------------------------
// Outline commands
// ---------------------------------------------------------------------------
async function handleTree(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const { getFileTree } = await import("../tools/outline-tools.js");
    const result = await getFileTree(repo, {
        path_prefix: getFlag(flags, "path") ?? args[1],
        name_pattern: getFlag(flags, "name-pattern"),
        depth: getNumFlag(flags, "depth"),
        compact: getBoolFlag(flags, "compact"),
        min_symbols: getNumFlag(flags, "min-symbols"),
    });
    output(result, flags);
}
async function handleOutline(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const file = requireArg(args, 1, "file");
    const { getFileOutline } = await import("../tools/outline-tools.js");
    const result = await getFileOutline(repo, file);
    output(result, flags);
}
async function handleRepoOutline(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const { getRepoOutline } = await import("../tools/outline-tools.js");
    const result = await getRepoOutline(repo);
    output(result, flags);
}
// ---------------------------------------------------------------------------
// Symbol commands
// ---------------------------------------------------------------------------
async function handleSymbol(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const id = requireArg(args, 1, "id");
    const { getSymbol } = await import("../tools/symbol-tools.js");
    const result = await getSymbol(repo, id);
    if (result === null) {
        die(`Symbol not found: ${id}`);
    }
    output(result.symbol, flags);
}
async function handleSymbolsBatch(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const ids = args.slice(1);
    if (ids.length === 0) {
        die("Missing required argument: <ids...>");
    }
    const { getSymbols } = await import("../tools/symbol-tools.js");
    const result = await getSymbols(repo, ids);
    output(result, flags);
}
async function handleFind(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const query = requireArg(args, 1, "query");
    const { findAndShow } = await import("../tools/symbol-tools.js");
    const result = await findAndShow(repo, query, getBoolFlag(flags, "include-refs"));
    if (result === null) {
        die(`No symbol found matching: ${query}`);
    }
    output(result, flags);
}
async function handleRefs(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const name = requireArg(args, 1, "name");
    const { findReferences } = await import("../tools/symbol-tools.js");
    const result = await findReferences(repo, name, getFlag(flags, "file-pattern"));
    if (getBoolFlag(flags, "json")) {
        output(result, flags);
    }
    else {
        // Compact tabular output: file:line:col | context
        for (const ref of result) {
            const loc = `${ref.file}:${ref.line}${ref.col ? `:${ref.col}` : ""}`;
            process.stdout.write(`${loc} | ${ref.context}\n`);
        }
        process.stderr.write(`\n${result.length} references found\n`);
    }
}
// ---------------------------------------------------------------------------
// Graph commands
// ---------------------------------------------------------------------------
function printTraceCompact(root) {
    function printNode(node, indent) {
        const prefix = indent === 0 ? "" : "  ".repeat(indent) + "|- ";
        const sym = node.symbol;
        const sig = sym.signature ? ` ${sym.signature}` : "";
        const loc = `${sym.file}:${sym.start_line}`;
        process.stdout.write(`${prefix}${sym.kind} | ${sym.name}${sig} | ${loc}\n`);
        for (const child of node.children) {
            printNode(child, indent + 1);
        }
    }
    printNode(root, 0);
    function countNodes(node) {
        return 1 + node.children.reduce((sum, c) => sum + countNodes(c), 0);
    }
    process.stderr.write(`\n${countNodes(root)} symbols in trace\n`);
}
async function handleTrace(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const name = requireArg(args, 1, "name");
    const { traceCallChain } = await import("../tools/graph-tools.js");
    const direction = (getFlag(flags, "direction") ?? "callers");
    if (direction !== "callers" && direction !== "callees") {
        die(`Invalid --direction: ${direction}. Must be "callers" or "callees".`);
    }
    const result = await traceCallChain(repo, name, direction, {
        depth: getNumFlag(flags, "depth"),
        include_source: getBoolFlag(flags, "include-source") ?? false,
        include_tests: getBoolFlag(flags, "include-tests") ?? false,
    });
    if (getBoolFlag(flags, "json")) {
        output(result, flags);
    }
    else {
        printTraceCompact(result);
    }
}
async function handleImpact(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const since = requireFlag(flags, "since");
    const { impactAnalysis } = await import("../tools/impact-tools.js");
    const result = await impactAnalysis(repo, since, {
        depth: getNumFlag(flags, "depth"),
        until: getFlag(flags, "until"),
        include_source: getBoolFlag(flags, "include-source"),
    });
    output(result, flags);
}
// ---------------------------------------------------------------------------
// Context commands
// ---------------------------------------------------------------------------
async function handleContext(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const query = requireArg(args, 1, "query");
    const { assembleContext } = await import("../tools/context-tools.js");
    const result = await assembleContext(repo, query, getNumFlag(flags, "token-budget"));
    output(result, flags);
}
async function handleKnowledgeMap(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const { getKnowledgeMap } = await import("../tools/context-tools.js");
    const result = await getKnowledgeMap(repo, getFlag(flags, "focus"), getNumFlag(flags, "depth"));
    output(result, flags);
}
// ---------------------------------------------------------------------------
// Diff commands
// ---------------------------------------------------------------------------
async function handleDiff(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const since = requireFlag(flags, "since");
    const { diffOutline } = await import("../tools/diff-tools.js");
    const result = await diffOutline(repo, since, getFlag(flags, "until"));
    output(result, flags);
}
async function handleChanged(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const since = requireFlag(flags, "since");
    const { changedSymbols } = await import("../tools/diff-tools.js");
    const result = await changedSymbols(repo, since, getFlag(flags, "until"));
    output(result, flags);
}
// ---------------------------------------------------------------------------
// Retrieval & utility commands
// ---------------------------------------------------------------------------
function parseRetrievalQueries(flags) {
    const queriesRaw = getFlag(flags, "queries");
    if (!queriesRaw) {
        die("Missing required flag: --queries <json>");
    }
    let parsed;
    try {
        parsed = JSON.parse(queriesRaw);
    }
    catch {
        die("Invalid JSON for --queries flag");
    }
    if (!Array.isArray(parsed)) {
        die("--queries must be a JSON array");
    }
    for (const item of parsed) {
        if (typeof item !== "object" || item === null || typeof item.type !== "string") {
            die("Each --queries entry must be an object with a \"type\" string field");
        }
    }
    const queries = parsed;
    // --exclude-tests (default: true) — inject into semantic/hybrid sub-queries
    const excludeTests = getBoolFlag(flags, "exclude-tests") !== false;
    for (const q of queries) {
        if (EXCLUDE_TESTS_QUERY_TYPES.has(q.type) && q["exclude_tests"] === undefined) {
            q["exclude_tests"] = excludeTests;
        }
    }
    return queries;
}
async function handleRetrieve(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const queries = parseRetrievalQueries(flags);
    const { codebaseRetrieval } = await import("../retrieval/codebase-retrieval.js");
    const result = await codebaseRetrieval(repo, queries, getNumFlag(flags, "token-budget"));
    output(result, flags);
}
async function handleStats(_args, flags) {
    const { getUsageStats, formatUsageReport } = await import("../storage/usage-stats.js");
    const stats = await getUsageStats();
    // If --json flag is set (or default), output raw stats; otherwise formatted report
    if (getBoolFlag(flags, "json") === false) {
        const report = formatUsageReport(stats);
        process.stdout.write(report + "\n");
    }
    else {
        output(stats, flags);
    }
}
async function handleGenerateClaudeMd(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const { generateClaudeMd } = await import("../tools/generate-tools.js");
    const result = await generateClaudeMd(repo, getFlag(flags, "output"));
    output(result, flags);
}
// ---------------------------------------------------------------------------
// Analysis commands
// ---------------------------------------------------------------------------
async function handleComplexity(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const { analyzeComplexity } = await import("../tools/complexity-tools.js");
    const result = await analyzeComplexity(repo, {
        file_pattern: getFlag(flags, "file-pattern"),
        top_n: getNumFlag(flags, "top-n"),
        min_complexity: getNumFlag(flags, "min-complexity"),
        include_tests: getBoolFlag(flags, "include-tests"),
    });
    output(result, flags);
}
async function handleDeadCode(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const { findDeadCode } = await import("../tools/symbol-tools.js");
    const result = await findDeadCode(repo, {
        file_pattern: getFlag(flags, "file-pattern"),
        include_tests: getBoolFlag(flags, "include-tests"),
    });
    output(result, flags);
}
async function handleHotspots(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const { analyzeHotspots } = await import("../tools/hotspot-tools.js");
    const result = await analyzeHotspots(repo, {
        since_days: getNumFlag(flags, "since-days"),
        top_n: getNumFlag(flags, "top-n"),
        file_pattern: getFlag(flags, "file-pattern"),
    });
    output(result, flags);
}
async function handleCommunities(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const { detectCommunities } = await import("../tools/community-tools.js");
    const result = await detectCommunities(repo, getFlag(flags, "focus"), getNumFlag(flags, "resolution"), getFlag(flags, "output-format"));
    output(result, flags);
}
async function handlePatterns(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const pattern = requireFlag(flags, "pattern");
    const { searchPatterns } = await import("../tools/pattern-tools.js");
    const result = await searchPatterns(repo, pattern, {
        file_pattern: getFlag(flags, "file-pattern"),
        include_tests: getBoolFlag(flags, "include-tests"),
        max_results: getNumFlag(flags, "max-results"),
    });
    output(result, flags);
}
async function handleSetup(args, flags) {
    const platform = args[0];
    const { formatSetupLines, SUPPORTED_PLATFORMS } = await import("./setup.js");
    if (!platform) {
        die(`Missing platform. Usage: codesift setup <${SUPPORTED_PLATFORMS.join("|")}|all>`);
        return;
    }
    const hooks = getBoolFlag(flags, "hooks") ?? true;
    const rules = getBoolFlag(flags, "rules") ?? true;
    const force = getBoolFlag(flags, "force") ?? false;
    // `--no-git-hooks` is a standalone boolean flag (parseArgs stores "no-git-hooks", not "git-hooks": false).
    const gitHooks = getBoolFlag(flags, "no-git-hooks")
        ? false
        : (getBoolFlag(flags, "git-hooks") ?? hooks);
    const options = { hooks, rules, force, gitHooks };
    /** Global post-commit backlog hook — wired here because `formatSetupLines` stays editor-setup only (see setup/setupAll for programmatic installs). */
    async function emitGlobalGitHooksIfRequested() {
        if (options.gitHooks === false)
            return;
        // Match setup(): git hooks accompany editor hooks by default; allow `--git-hooks` without `--hooks`.
        const wantGitHooks = options.hooks || getBoolFlag(flags, "git-hooks") === true;
        if (!wantGitHooks)
            return;
        const { installGitHooks } = await import("./git-hooks-installer.js");
        const result = await installGitHooks({ force });
        if (result.reason) {
            process.stdout.write(`⚠️ git hooks: ${result.reason}\n`);
            return;
        }
        process.stdout.write(`✓ git post-commit hook → ${result.hooksPath}\n`);
        if (result.hooksPathSkippedReason) {
            process.stdout.write(`  (${result.hooksPathSkippedReason})\n`);
        }
    }
    if (platform === "all") {
        for (const p of SUPPORTED_PLATFORMS) {
            const lines = await formatSetupLines(p, options);
            for (const line of lines)
                process.stdout.write(line + "\n");
        }
        await emitGlobalGitHooksIfRequested();
        return;
    }
    const lines = await formatSetupLines(platform, options);
    for (const line of lines)
        process.stdout.write(line + "\n");
    await emitGlobalGitHooksIfRequested();
}
async function handleFindClones(args, flags) {
    const repo = requireArg(args, 0, "repo");
    const { findClones } = await import("../tools/clone-tools.js");
    const result = await findClones(repo, {
        file_pattern: getFlag(flags, "file-pattern"),
        min_similarity: getNumFlag(flags, "threshold"),
        min_lines: getNumFlag(flags, "min-lines"),
        include_tests: getBoolFlag(flags, "include-tests"),
    });
    output(result, flags);
}
// ---------------------------------------------------------------------------
// Command dispatch map
// ---------------------------------------------------------------------------
export const COMMAND_MAP = {
    "index": handleIndex,
    "index-repo": handleIndexRepo,
    "repos": handleRepos,
    "invalidate": handleInvalidate,
    "index-conversations": handleIndexConversations,
    "search": handleSearch,
    "symbols": handleSymbols,
    "tree": handleTree,
    "outline": handleOutline,
    "repo-outline": handleRepoOutline,
    "symbol": handleSymbol,
    "symbols-batch": handleSymbolsBatch,
    "find": handleFind,
    "refs": handleRefs,
    "trace": handleTrace,
    "impact": handleImpact,
    "context": handleContext,
    "knowledge-map": handleKnowledgeMap,
    "diff": handleDiff,
    "changed": handleChanged,
    "retrieve": handleRetrieve,
    "stats": handleStats,
    "generate-claude-md": handleGenerateClaudeMd,
    "complexity": handleComplexity,
    "dead-code": handleDeadCode,
    "hotspots": handleHotspots,
    "communities": handleCommunities,
    "patterns": handlePatterns,
    "find-clones": handleFindClones,
    "setup": handleSetup,
    "wiki-generate": async (args, flags) => {
        const { handleWikiGenerate } = await import("./wiki-commands.js");
        await handleWikiGenerate(args, flags);
    },
    "wiki-lint": async (args, flags) => {
        const { handleWikiLint } = await import("./wiki-commands.js");
        await handleWikiLint(args, flags);
    },
    "journal-init": async (args, flags) => {
        const { handleJournalInit } = await import("./journal-commands.js");
        await handleJournalInit(args, flags);
    },
    "journal-append": async (args, flags) => {
        const { handleJournalAppend } = await import("./journal-commands.js");
        await handleJournalAppend(args, flags);
    },
    "journal-refresh-overview": async (args, flags) => {
        const { handleJournalRefreshOverview } = await import("./journal-commands.js");
        await handleJournalRefreshOverview(args, flags);
    },
    "journal-regenerate": async (args, flags) => {
        const { handleJournalRegenerate } = await import("./journal-commands.js");
        await handleJournalRegenerate(args, flags);
    },
    "journal-lint": async (args, flags) => {
        const { handleJournalLint } = await import("./journal-commands.js");
        await handleJournalLint(args, flags);
    },
    "journal-migrate": async (args, flags) => {
        const { handleJournalMigrate } = await import("./journal-commands.js");
        await handleJournalMigrate(args, flags);
    },
    "journal-stats": async (args, flags) => {
        const { handleJournalStats } = await import("./journal-commands.js");
        await handleJournalStats(args, flags);
    },
    "precheck-read": async () => {
        const { handlePrecheckRead } = await import("./hooks.js");
        await handlePrecheckRead();
    },
    "precheck-bash": async () => {
        const { handlePrecheckBash } = await import("./hooks.js");
        await handlePrecheckBash();
    },
    "precheck-glob": async () => {
        const { handlePrecheckGlob } = await import("./hooks.js");
        await handlePrecheckGlob();
    },
    "precheck-grep": async () => {
        const { handlePrecheckGrep } = await import("./hooks.js");
        await handlePrecheckGrep();
    },
    "precheck-agent": async () => {
        const { handlePrecheckAgent } = await import("./hooks.js");
        await handlePrecheckAgent();
    },
    "session-start": async () => {
        const { handleSessionStart } = await import("./hooks.js");
        await handleSessionStart();
    },
    "session-gate": async () => {
        const { handleSessionGate } = await import("./hooks.js");
        await handleSessionGate();
    },
    "sentinel-writer": async () => {
        const { handleSentinelWriter } = await import("./hooks.js");
        await handleSentinelWriter();
    },
    "postindex-file": async () => {
        const { handlePostindexFile } = await import("./hooks.js");
        await handlePostindexFile();
    },
    "precompact-snapshot": async () => {
        const { handlePrecompactSnapshot } = await import("./hooks.js");
        await handlePrecompactSnapshot();
    },
};
//# sourceMappingURL=commands.js.map