/**
 * `olam flywheel check-persona-skeleton` — D12 skeleton conformance checker.
 *
 * Port of `shared/engineering/scripts/check-persona-skeleton.py`. Validates
 * persona-file conformance:
 *   1. Frontmatter has `name`, `description`, `allowed-tools`.
 *   2-5. Body has `## Role`, `## Cognitive patterns`, `## Scoring rubric`,
 *      `## Output format`.
 *   6. `## Cognitive patterns` has ≥5 named patterns (### headings or bullets).
 *   7. Token count (chars/4 approx) ≤ K10 cap (6000).
 *
 * Note on merged-result measurement: the Python predecessor imports
 * apply-overlays.py's `merge_markdown` to measure overlay+upstream merged
 * results. This TypeScript port currently measures STANDALONE only — overlay
 * files needing merged-result measurement emit a warning + are checked
 * against their standalone content. The merge-aware measurement lands when
 * Phase A step 9 (apply-overlays port) ships; see follow-up task A7-merge.
 *
 * CLI:
 *   olam flywheel check-persona-skeleton <file> [<file> ...]
 *   Exit 0 = all PASS; Exit 1 = any FAIL.
 *
 * Plan reference: docs/plans/olam-flywheel-cli-namespace/phase-a-tasks.md § A7
 */
import { existsSync, readFileSync, statSync } from 'node:fs';
import { homedir } from 'node:os';
import { basename, join } from 'node:path';
import { parse as parseYAML } from 'yaml';
const CHARS_PER_TOKEN = 4;
const K10_TOKEN_CAP = 6000;
const AGENTS_DIR = join(homedir(), '.claude', 'agents');
const REQUIRED_FRONTMATTER_KEYS = ['name', 'description', 'allowed-tools'];
const REQUIRED_SECTIONS = [
    '## Role',
    '## Cognitive patterns',
    '## Scoring rubric',
    '## Output format',
];
function parseFile(text) {
    const cleaned = text.replace(/^﻿/, '');
    if (!cleaned.startsWith('---'))
        return { fm: {}, body: cleaned };
    const closeIdx = cleaned.indexOf('\n---', 3);
    if (closeIdx === -1)
        return { fm: {}, body: cleaned };
    const fmRaw = cleaned.slice(4, closeIdx);
    const body = cleaned.slice(closeIdx + 4).replace(/^\n/, '');
    try {
        const fm = parseYAML(fmRaw) ?? {};
        return { fm, body };
    }
    catch {
        return { fm: {}, body };
    }
}
function countH2(body, heading) {
    const escaped = heading.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    const pattern = new RegExp(`^${escaped}\\s*$`, 'gm');
    return (body.match(pattern) ?? []).length;
}
function sectionBody(body, heading) {
    const escaped = heading.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    const pattern = new RegExp(`^${escaped}\\s*\\n([\\s\\S]*?)(?=^## |$(?![\\r\\n]))`, 'm');
    const match = body.match(pattern);
    return match?.[1] ?? '';
}
function countNamedPatterns(sectionText) {
    const h3Count = (sectionText.match(/^###\s+\S/gm) ?? []).length;
    if (h3Count >= 5)
        return h3Count;
    const bulletCount = (sectionText.match(/^\s*[-*]\s+\S/gm) ?? []).length;
    return Math.max(h3Count, bulletCount);
}
export function checkFile(filepath) {
    if (!existsSync(filepath) || !statSync(filepath).isFile()) {
        return { passed: false, failures: [`file not found: ${filepath}`], tokens: 0, mergedSkipped: false };
    }
    const text = readFileSync(filepath, 'utf8');
    const { fm, body } = parseFile(text);
    const failures = [];
    // 1. Frontmatter required keys.
    for (const key of REQUIRED_FRONTMATTER_KEYS) {
        const val = fm[key];
        if (val === undefined || val === null || val === '') {
            failures.push(`frontmatter missing \`${key}:\``);
        }
    }
    // Determine whether to attempt merged measurement.
    const isNewAgent = fm['overlay-intent'] === 'new-agent';
    const agentName = typeof fm.name === 'string' ? fm.name : '';
    let mergedSkipped = false;
    if (!isNewAgent && agentName !== '') {
        const upstreamPath = join(AGENTS_DIR, `${agentName}.md`);
        if (existsSync(upstreamPath)) {
            // Merged-result measurement requires A9 apply-overlays port.
            // For now: warn + fall back to standalone measurement.
            mergedSkipped = true;
        }
    }
    // 2-5. Required sections.
    for (const heading of REQUIRED_SECTIONS) {
        if (countH2(body, heading) === 0) {
            failures.push(`missing section: '${heading}'`);
        }
    }
    // 6. ≥5 named patterns.
    const cogBody = sectionBody(body, '## Cognitive patterns');
    if (cogBody !== '') {
        const patternCount = countNamedPatterns(cogBody);
        if (patternCount < 5) {
            failures.push(`'## Cognitive patterns' has ${patternCount} named pattern(s); need >= 5`);
        }
    }
    // 7. Token cap.
    const tokens = Math.floor(text.length / CHARS_PER_TOKEN);
    if (tokens > K10_TOKEN_CAP) {
        failures.push(`K10 cap exceeded: ${tokens} > ${K10_TOKEN_CAP} tokens`);
    }
    return { passed: failures.length === 0, failures, tokens, mergedSkipped };
}
export function registerFlywheelCheckPersonaSkeleton(parent) {
    parent
        .command('check-persona-skeleton')
        .description('Validate D12 skeleton conformance of persona files (frontmatter + required sections + cognitive patterns + K10 cap)')
        .argument('<file...>', 'one or more persona files to check')
        .action((files) => {
        let passCount = 0;
        let failCount = 0;
        for (const filepath of files) {
            const result = checkFile(filepath);
            const label = basename(filepath);
            if (result.passed) {
                process.stdout.write(`PASS: ${label} -- D12 skeleton valid; tokens=${result.tokens}/${K10_TOKEN_CAP}`);
                if (result.mergedSkipped) {
                    process.stdout.write(' (merged measurement deferred to A9 apply-overlays port)');
                }
                process.stdout.write('\n');
                passCount += 1;
            }
            else {
                for (const detail of result.failures) {
                    process.stdout.write(`FAIL: ${label} -- ${detail}\n`);
                }
                failCount += 1;
            }
        }
        process.stdout.write(`\nResults: ${passCount} passed, ${failCount} failed\n`);
        process.exit(failCount > 0 ? 1 : 0);
    });
}
//# sourceMappingURL=check-persona-skeleton.js.map