// engine/validator/gates/code-gates.ts — typecheck and TODO/FIXME gates
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
/**
 * Gate: typecheck-gate
 * Reads a cached `.planu-typecheck-result` file if present.
 * Does NOT spawn tsc. Skipped if no cache file found.
 */
export async function runTypecheckGate(projectPath) {
    const cacheFile = join(projectPath, '.planu-typecheck-result');
    try {
        const raw = await readFile(cacheFile, 'utf-8');
        const parsed = JSON.parse(raw);
        if (typeof parsed.errors !== 'number') {
            return {
                gate: 'typecheck-gate',
                status: 'skipped',
                reason: 'typecheck requires manual run',
            };
        }
        if (parsed.errors === 0) {
            return { gate: 'typecheck-gate', status: 'passed' };
        }
        return {
            gate: 'typecheck-gate',
            status: 'failed',
            detail: `TypeScript reported ${String(parsed.errors)} error(s)`,
        };
    }
    catch {
        return {
            gate: 'typecheck-gate',
            status: 'skipped',
            reason: 'typecheck requires manual run',
        };
    }
}
const TODO_PATTERN = /\b(TODO|FIXME)\b/;
/**
 * Extract file paths from progress.md "## Changed Files" section.
 */
function extractChangedFiles(progressContent) {
    const match = /##\s+Changed Files\s*\n([\s\S]*?)(?=\n##|$)/i.exec(progressContent);
    if (!match?.[1]) {
        return [];
    }
    const lines = match[1].split('\n');
    return lines
        .map((l) => l.replace(/^[-*]\s+/, '').trim())
        .filter((l) => l.length > 0 && !l.startsWith('#'));
}
/**
 * Gate: todo-gate
 * Scans changed files (from progress.md) for TODO/FIXME markers.
 * Skipped if no changed files info is available.
 */
export async function runTodoGate(projectPath, progressContent) {
    if (!progressContent) {
        return { gate: 'todo-gate', status: 'skipped', reason: 'no changed files info available' };
    }
    const changedFiles = extractChangedFiles(progressContent);
    if (changedFiles.length === 0) {
        return { gate: 'todo-gate', status: 'skipped', reason: 'no changed files info available' };
    }
    const filesWithTodos = [];
    for (const file of changedFiles) {
        const absPath = file.startsWith('/') ? file : join(projectPath, file);
        try {
            const content = await readFile(absPath, 'utf-8');
            if (TODO_PATTERN.test(content)) {
                filesWithTodos.push(file);
            }
        }
        catch {
            // File not found or unreadable — skip silently
        }
    }
    if (filesWithTodos.length > 0) {
        return {
            gate: 'todo-gate',
            status: 'failed',
            detail: `TODO/FIXME found in: ${filesWithTodos.join(', ')}`,
        };
    }
    return { gate: 'todo-gate', status: 'passed' };
}
//# sourceMappingURL=code-gates.js.map