"use strict";
/**
 * test_aiobuilder_cli_parity.ts — Story 5.5
 *
 * Doc-vs-Code parity check for the AIOBuilder squad.
 *
 * Parses the canonical squad doc `.catalog/squads/01-meta-framework-ai-builder/SQUAD.md`
 * and extracts every promised `*aiobuilder;<verb>` sub-command. Then spawns
 * `node bin/openlife.js aiobuilder --help` and asserts each verb is wired
 * either as a direct sub-command or as a documented alias.
 *
 * Failure semantics: throws on missing wiring with a clear list, so a future
 * PR that adds a row to the doc without implementing the handler fails fast.
 */
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 });
const child_process_1 = require("child_process");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const CLI = path.join(process.cwd(), 'dist', 'index.js');
const SQUAD_DOC = path.join(process.cwd(), '.catalog', 'squads', '01-meta-framework-ai-builder', 'SQUAD.md');
// Aliases — old sub-command names that still satisfy a new verb in the doc.
// Maps doc verb → existing CLI sub-command that fulfills it.
const ALIAS_MAP = {
    'design': 'generate-ui',
    'build-agent': 'create-agent',
    'build-squad': 'create-squad',
    // `route` lives at the top level (`openlife route intent ...`), not under aiobuilder
    'route': '__top_level_route__',
};
function extractPromisedVerbs() {
    if (!fs.existsSync(SQUAD_DOC)) {
        throw new Error(`SQUAD doc missing: ${SQUAD_DOC}`);
    }
    const content = fs.readFileSync(SQUAD_DOC, 'utf-8');
    const verbs = new Set();
    const rowPattern = /\|\s*`\*aiobuilder;([\w-]+)`\s*\|/g;
    let m;
    while ((m = rowPattern.exec(content)) !== null) {
        verbs.add(m[1]);
    }
    return Array.from(verbs).sort();
}
function getAiobuilderHelp() {
    const r = (0, child_process_1.spawnSync)('node', [CLI, 'aiobuilder', '--help'], { encoding: 'utf-8', timeout: 20000 });
    return (r.stdout || '') + (r.stderr || '');
}
function getRootHelp() {
    const r = (0, child_process_1.spawnSync)('node', [CLI, '--help'], { encoding: 'utf-8', timeout: 20000 });
    return (r.stdout || '') + (r.stderr || '');
}
function extractCommandNames(helpText) {
    // Commander help lists each sub-command starting with the name at column 2.
    // Format: "  <name> [options] [args]    <desc>"
    const out = new Set();
    const lines = helpText.split('\n');
    let inCommands = false;
    for (const line of lines) {
        if (/^Commands:/.test(line)) {
            inCommands = true;
            continue;
        }
        if (!inCommands)
            continue;
        const m = line.match(/^\s{2}([a-z][\w-]*)/);
        if (m)
            out.add(m[1]);
    }
    return out;
}
function main() {
    const promised = extractPromisedVerbs();
    if (promised.length === 0) {
        throw new Error('PARSE_FAILED: no `*aiobuilder;<verb>` rows extracted from SQUAD.md');
    }
    console.log(`[parity] Doc promises ${promised.length} verbs:`, promised.join(', '));
    const aiobuilderHelp = getAiobuilderHelp();
    const rootHelp = getRootHelp();
    const aiobuilderCmds = extractCommandNames(aiobuilderHelp);
    const rootCmds = extractCommandNames(rootHelp);
    console.log(`[parity] CLI exposes ${aiobuilderCmds.size} aiobuilder sub-commands:`, Array.from(aiobuilderCmds).sort().join(', '));
    const missing = [];
    const matched = [];
    for (const verb of promised) {
        if (aiobuilderCmds.has(verb)) {
            matched.push({ verb, via: `aiobuilder ${verb}` });
            continue;
        }
        const alias = ALIAS_MAP[verb];
        if (alias === '__top_level_route__') {
            if (rootCmds.has('route')) {
                matched.push({ verb, via: 'route (top-level)' });
                continue;
            }
        }
        else if (alias && aiobuilderCmds.has(alias)) {
            matched.push({ verb, via: `aiobuilder ${alias} (alias)` });
            continue;
        }
        missing.push(verb);
    }
    if (missing.length > 0) {
        console.error('[parity] MISSING wiring for:', missing.join(', '));
        console.error('[parity] Matched verbs:');
        for (const m of matched)
            console.error(`  - ${m.verb} → ${m.via}`);
        throw new Error(`AIOBUILDER_PARITY_FAILED: ${missing.length} promised verb(s) have no CLI handler: ${missing.join(', ')}`);
    }
    console.log(`[parity] PASS: ${matched.length}/${promised.length} verbs wired:`);
    for (const m of matched)
        console.log(`  ✓ ${m.verb} → ${m.via}`);
    // Sanity: each wired sub-command responds to --help with non-empty output.
    let helpProbed = 0;
    for (const verb of promised) {
        const direct = aiobuilderCmds.has(verb);
        const alias = ALIAS_MAP[verb];
        if (!direct && alias === '__top_level_route__')
            continue; // top-level handled separately
        const cmdName = direct ? verb : alias;
        if (!cmdName)
            continue;
        const r = (0, child_process_1.spawnSync)('node', [CLI, 'aiobuilder', cmdName, '--help'], { encoding: 'utf-8', timeout: 15000 });
        if (r.status !== 0 || !(r.stdout || '').includes('Usage:')) {
            throw new Error(`HELP_PROBE_FAILED: \`openlife aiobuilder ${cmdName} --help\` returned exit ${r.status}\nstdout: ${r.stdout}\nstderr: ${r.stderr}`);
        }
        helpProbed += 1;
    }
    console.log(`[parity] Help-probe verified ${helpProbed} sub-commands respond cleanly to --help.`);
    console.log('TEST_AIOBUILDER_CLI_PARITY_OK');
}
try {
    main();
}
catch (err) {
    console.error('[parity] FAILED:', err instanceof Error ? err.message : err);
    process.exit(1);
}
