"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports._testing = void 0;
exports.registerAuditCommand = registerAuditCommand;
const path = __importStar(require("path"));
const daemon_discovery_js_1 = require("../../lib/daemon-discovery.js");
const audit_pack_js_1 = require("../../lib/audit-pack.js");
const ui_js_1 = require("../ui.js");
const DEFAULT_TEMPLATE = 'review-only';
const VALID_FOCUS = new Set(['security', 'correctness', 'performance', 'maintainability', 'all']);
/**
 * Daemon HTTP timeout. Audit POSTs to /chats with the assembled
 * artifact — if the daemon stalls (libsql lock, OOM, etc.) the CLI
 * should fail fast with a clear message rather than hang. 30s matches
 * the project's "every external call has a timeout" rule.
 */
const DAEMON_FETCH_TIMEOUT_MS = 30_000;
async function runAudit(targetPath, opts) {
    console.log('');
    console.log(`  ${ui_js_1.sym.rocket} ${ui_js_1.c.bold('chorus audit')} ${ui_js_1.c.dim('— multi-LLM review of existing code')}`);
    console.log('');
    // 1. Daemon up?
    const info = (0, daemon_discovery_js_1.readDaemonInfo)();
    if (!info) {
        console.log(`  ${ui_js_1.c.red('✗')} daemon not running`);
        console.log(`     run ${ui_js_1.c.bold('chorus start')} first, then re-run audit`);
        process.exitCode = 1;
        return;
    }
    const healthy = await (0, daemon_discovery_js_1.isDaemonHealthy)(info.daemonPort, 1500);
    if (!healthy) {
        console.log(`  ${ui_js_1.c.red('✗')} daemon not responding on :${info.daemonPort}`);
        console.log(`     run ${ui_js_1.c.bold('chorus stop && chorus start')} to recycle`);
        process.exitCode = 1;
        return;
    }
    const baseUrl = opts.daemonUrl ?? `http://127.0.0.1:${info.daemonPort}`;
    // 2. Validate --focus before doing any filesystem work. A bad
    // --focus value should fail in milliseconds, not after a slow walk.
    const focus = opts.focus ?? 'all';
    if (!VALID_FOCUS.has(focus)) {
        console.log(`  ${ui_js_1.c.red('✗')} --focus must be one of: ${[...VALID_FOCUS].join(', ')}`);
        process.exitCode = 1;
        return;
    }
    // 3. Resolve + validate path.
    const rootAbs = path.resolve(process.cwd(), targetPath);
    let files;
    try {
        files = (0, audit_pack_js_1.walkAuditPath)(rootAbs);
    }
    catch (err) {
        if (err instanceof audit_pack_js_1.AuditPackError) {
            console.log(`  ${ui_js_1.c.red('✗')} ${err.message}`);
        }
        else if (err instanceof Error && 'code' in err && err.code === 'ENOENT') {
            console.log(`  ${ui_js_1.c.red('✗')} path not found: ${rootAbs}`);
        }
        else {
            console.log(`  ${ui_js_1.c.red('✗')} ${err instanceof Error ? err.message : String(err)}`);
        }
        process.exitCode = 1;
        return;
    }
    // 4. Assemble the artifact.
    const scope = opts.scope ?? path.basename(rootAbs);
    const focusPara = (0, audit_pack_js_1.focusParagraph)(focus);
    let pack;
    try {
        pack = (0, audit_pack_js_1.assembleAuditArtifact)(rootAbs, files, { scope, focusParagraph: focusPara });
    }
    catch (err) {
        if (err instanceof audit_pack_js_1.AuditPackError) {
            console.log(`  ${ui_js_1.c.red('✗')} ${err.message}`);
        }
        else {
            console.log(`  ${ui_js_1.c.red('✗')} ${err instanceof Error ? err.message : String(err)}`);
        }
        process.exitCode = 1;
        return;
    }
    console.log(`  ${ui_js_1.c.green('✓')} packed ${ui_js_1.c.bold(String(pack.filesIncluded.length))} file${pack.filesIncluded.length === 1 ? '' : 's'} ${ui_js_1.c.gray(`(${pack.totalBytes} bytes)`)}`);
    if (pack.filesSkipped.length > 0) {
        console.log(`  ${ui_js_1.c.gray('·')} skipped ${pack.filesSkipped.length} (extension / read failure)`);
    }
    // 5. Resolve template — must be review-only kind so audit framing
    // composes. Daemon will reject artifact on full-pipeline templates
    // anyway; this is a friendlier upfront message.
    const templateId = opts.template ?? DEFAULT_TEMPLATE;
    console.log(`  ${ui_js_1.c.gray('·')} template: ${ui_js_1.c.bold(templateId)}`);
    // 6. Build the audit-framed work brief.
    const work = (0, audit_pack_js_1.buildAuditWork)(scope, focusPara);
    // 7. Fire the chat. AbortSignal.timeout closes the connection if the
    // daemon hangs — failing fast beats blocking the terminal forever.
    let chatRes;
    try {
        chatRes = await fetch(`${baseUrl}/chats`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                work,
                templateId,
                artifact: pack.artifact,
            }),
            signal: AbortSignal.timeout(DAEMON_FETCH_TIMEOUT_MS),
        });
    }
    catch (err) {
        const msg = err instanceof Error ? err.message : String(err);
        const timedOut = err instanceof Error && (err.name === 'TimeoutError' || err.name === 'AbortError');
        if (timedOut) {
            console.log(`  ${ui_js_1.c.red('✗')} chat create timed out after ${DAEMON_FETCH_TIMEOUT_MS}ms (daemon hung?)`);
        }
        else {
            console.log(`  ${ui_js_1.c.red('✗')} chat create failed: ${msg}`);
        }
        process.exitCode = 1;
        return;
    }
    if (!chatRes.ok) {
        const text = await chatRes.text().catch(() => '');
        console.log(`  ${ui_js_1.c.red('✗')} chat create failed: ${chatRes.status} ${text.slice(0, 400)}`);
        if (chatRes.status === 400 && text.includes('review-only')) {
            console.log('');
            console.log(`     ${ui_js_1.c.gray('hint: --template must point at a review_only template')}`);
            console.log(`     ${ui_js_1.c.gray('the default ')}${ui_js_1.c.bold(DEFAULT_TEMPLATE)}${ui_js_1.c.gray(' is review_only; full-pipeline templates with a doer slot are not audit-compatible')}`);
        }
        process.exitCode = 1;
        return;
    }
    const chatEnv = (await chatRes.json());
    const chatId = chatEnv.data?.id;
    if (!chatId) {
        console.log(`  ${ui_js_1.c.red('✗')} chat create returned no id`);
        process.exitCode = 1;
        return;
    }
    const cockpitUrl = `http://127.0.0.1:${info.cockpitPort}`;
    console.log('');
    console.log(`  ${ui_js_1.c.green('✓')} audit fired ${ui_js_1.c.gray('(id: ' + chatId + ')')}`);
    console.log(`     watch live: ${ui_js_1.c.cyan(`${cockpitUrl}/runs/${chatId}`)}`);
    console.log('');
    console.log(`  ${ui_js_1.c.gray('reviewers run in the background — close this terminal and check the cockpit later')}`);
    console.log('');
}
function registerAuditCommand(program) {
    program
        .command('audit')
        .description('Multi-LLM review of existing production code. Reads <path>, packs source files, fires a review-only chat.')
        .argument('<path>', 'file or directory to audit')
        .option('--scope <name>', 'human label for the audit scope (defaults to path basename)')
        .option('--focus <area>', 'audit focus: security | correctness | performance | maintainability | all', 'all')
        .option('--template <id>', 'override the review-only template used for the fleet', DEFAULT_TEMPLATE)
        .action(async (targetPath, options) => {
        try {
            await runAudit(targetPath, options);
        }
        catch (err) {
            console.error('audit failed:', err instanceof Error ? err.message : err);
            process.exit(1);
        }
    });
}
exports._testing = {
    DEFAULT_TEMPLATE,
    VALID_FOCUS,
};
//# sourceMappingURL=audit.js.map