// @crash-shield-ignore-file — config/cache reader for Planu-controlled JSON; writer is this codebase, shape guaranteed by build/seed.
// engine/conventions-ttl.ts — SPEC-665: TTL-based refresh for conventions.json
import { readFile, writeFile, mkdir, appendFile } from 'node:fs/promises';
import { join } from 'node:path';
const TTL_DAYS = 7;
const MS_PER_DAY = 86_400_000;
async function readConventionsFile(projectPath) {
    try {
        const raw = await readFile(join(projectPath, 'planu', 'conventions.json'), 'utf-8');
        return JSON.parse(raw);
    }
    catch {
        return null;
    }
}
function isStale(conventions, ttlDays) {
    if (!conventions.detectedAt) {
        return true;
    }
    const age = Date.now() - new Date(conventions.detectedAt).getTime();
    return age > ttlDays * MS_PER_DAY;
}
async function appendEvolutionLog(projectPath, entry) {
    const logPath = join(projectPath, 'planu', 'evolution-log.md');
    const line = `- ${new Date().toISOString().substring(0, 10)}: ${entry} (TTL refresh)\n`;
    await appendFile(logPath, line, 'utf-8');
}
function diffStack(before, after) {
    const changes = [];
    const keys = ['language', 'framework', 'testRunner', 'linter', 'formatter', 'bundler'];
    for (const k of keys) {
        if (before[k] !== after[k] && (before[k] ?? after[k]) !== null) {
            changes.push(`${k} ${before[k] ?? 'none'}→${after[k] ?? 'none'}`);
        }
    }
    return changes;
}
/**
 * SPEC-665: Check if conventions.json TTL is expired and trigger a background re-fetch.
 * Fire-and-forget — never blocks the caller. Silent failure on any error.
 */
export async function triggerConventionsTtlRefresh(projectPath) {
    try {
        const existing = await readConventionsFile(projectPath);
        if (!existing || !isStale(existing, TTL_DAYS)) {
            return;
        }
        const { scanProject } = await import('./project-scanner/index.js');
        const updated = await scanProject(projectPath);
        const changes = diffStack(existing.stack, updated.stack);
        const planuDir = join(projectPath, 'planu');
        await mkdir(planuDir, { recursive: true });
        await writeFile(join(planuDir, 'conventions.json'), JSON.stringify(updated, null, 2) + '\n', 'utf-8');
        if (changes.length > 0) {
            await mkdir(planuDir, { recursive: true });
            for (const change of changes) {
                await appendEvolutionLog(projectPath, `Updated ${change}`).catch(() => {
                    /* best-effort log */
                });
            }
        }
    }
    catch {
        /* best-effort — never blocks the caller */
    }
}
/** Exposed for tests — check if conventions.json is currently stale. */
export async function isConventionsStale(projectPath, ttlDays = TTL_DAYS) {
    const conventions = await readConventionsFile(projectPath);
    if (!conventions) {
        return true;
    }
    return isStale(conventions, ttlDays);
}
//# sourceMappingURL=conventions-ttl.js.map