"use strict";
/**
 * test_catalog_quality.ts — Story 5.6
 *
 * Regression gate against bad squad/skill check-ins.
 *
 * Scans `.catalog/squads/` and `.catalog/skills/` (excluding `test-*`) and asserts:
 *  - Every entry has the expected primary doc (SQUAD.md or SKILL.md).
 *  - Frontmatter parses and contains required fields (id, name, status).
 *  - Frontmatter `id` matches the directory name.
 *  - No squad is left in status=`draft` with `source: aiobuilder-auto-route` for
 *    more than CATALOG_DRAFT_TTL_DAYS days (default 7).
 *
 * Test-pollution entries (prefix `test-`) are ignored — `clean-test-pollution.js`
 * sweeps them in `pretest:all`. This test guards permanent check-ins.
 */
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 fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const CATALOG_ROOT = path.join(process.cwd(), '.catalog');
const SQUADS_DIR = path.join(CATALOG_ROOT, 'squads');
const SKILLS_DIR = path.join(CATALOG_ROOT, 'skills');
const DRAFT_TTL_DAYS = Number(process.env.OPENLIFE_DRAFT_TTL_DAYS || '7');
function parseFrontmatter(content) {
    const m = content.match(/^---\s*\n([\s\S]*?)\n---/);
    if (!m)
        return {};
    const out = {};
    for (const line of m[1].split('\n')) {
        const kv = line.match(/^([\w-]+):\s*(.*)$/);
        if (kv)
            out[kv[1]] = kv[2].trim();
    }
    return out;
}
function getDirMtimeMs(dir) {
    try {
        return fs.statSync(dir).mtimeMs;
    }
    catch {
        return Date.now();
    }
}
function scan(dir, docName, label) {
    const issues = [];
    if (!fs.existsSync(dir))
        return issues;
    for (const entry of fs.readdirSync(dir)) {
        if (entry.startsWith('test-'))
            continue;
        if (entry.startsWith('.'))
            continue;
        const entryDir = path.join(dir, entry);
        const stat = fs.statSync(entryDir);
        if (!stat.isDirectory())
            continue;
        const docPath = path.join(entryDir, docName);
        if (!fs.existsSync(docPath)) {
            // Imported-reference-only directories are tolerated: they hold raw upstream
            // material (e.g. fetched HTML, source-of-truth excerpts) and aren't meant
            // to be loaded as runtime skills. They must declare themselves with
            // IMPORTED_REFERENCE.md and no primary doc.
            const importedRef = path.join(entryDir, 'IMPORTED_REFERENCE.md');
            if (fs.existsSync(importedRef))
                continue;
            issues.push({ kind: 'missing_primary_doc', entry, detail: `${label} ${entry}/ has no ${docName}` });
            continue;
        }
        const fm = parseFrontmatter(fs.readFileSync(docPath, 'utf-8'));
        if (!fm.id)
            issues.push({ kind: 'missing_id', entry, detail: `${label} ${entry}/${docName} frontmatter missing 'id'` });
        if (!fm.name)
            issues.push({ kind: 'missing_name', entry, detail: `${label} ${entry}/${docName} frontmatter missing 'name'` });
        if (fm.id && fm.id !== entry) {
            issues.push({ kind: 'id_dir_mismatch', entry, detail: `${label} frontmatter id='${fm.id}' but directory is '${entry}'` });
        }
        // Stale draft gate — only enforced for auto-route auto-creations.
        if (fm.status === 'draft' && /aiobuilder-auto-route/.test(fm.source || '')) {
            const ageDays = (Date.now() - getDirMtimeMs(entryDir)) / (1000 * 60 * 60 * 24);
            if (ageDays > DRAFT_TTL_DAYS) {
                issues.push({
                    kind: 'stale_auto_route_draft',
                    entry,
                    detail: `${label} ${entry}/ is auto-route draft for ${ageDays.toFixed(1)}d (TTL ${DRAFT_TTL_DAYS}d). Promote with \`openlife aiobuilder canonize\` or delete.`,
                });
            }
        }
    }
    return issues;
}
function main() {
    const squadIssues = scan(SQUADS_DIR, 'SQUAD.md', 'squad');
    const skillIssues = scan(SKILLS_DIR, 'SKILL.md', 'skill');
    const all = [...squadIssues, ...skillIssues];
    const squadsScanned = fs.existsSync(SQUADS_DIR)
        ? fs.readdirSync(SQUADS_DIR).filter((e) => !e.startsWith('test-') && !e.startsWith('.')).length
        : 0;
    const skillsScanned = fs.existsSync(SKILLS_DIR)
        ? fs.readdirSync(SKILLS_DIR).filter((e) => !e.startsWith('test-') && !e.startsWith('.')).length
        : 0;
    console.log(`[catalog-quality] Scanned ${squadsScanned} squads, ${skillsScanned} skills.`);
    if (all.length > 0) {
        console.error(`[catalog-quality] ${all.length} issue(s) found:`);
        for (const i of all)
            console.error(`  - [${i.kind}] ${i.detail}`);
        throw new Error(`CATALOG_QUALITY_FAILED: ${all.length} issue(s) in .catalog/`);
    }
    console.log('[catalog-quality] PASS — no broken squad/skill check-ins.');
    console.log('TEST_CATALOG_QUALITY_OK');
}
try {
    main();
}
catch (err) {
    console.error('[catalog-quality] FAILED:', err instanceof Error ? err.message : err);
    process.exit(1);
}
