// engine/elicitation/decision-cache.ts — SPEC-651: Decision cache backed by conventions.json
//
// Reads and writes persisted business/policy decisions under `conventions.json#decisions`.
// All functions are best-effort: errors are logged and swallowed (mirrors other convention writes).
// `getCachedDecision` never throws — corrupted or missing files are treated as a cache miss.
import { readFile, writeFile, mkdir } from 'node:fs/promises';
import { join } from 'node:path';
/** Namespace prefix for decision cache keys. */
export const DECISION_CACHE_KEY_PREFIX = 'planu.decision.';
const CONVENTIONS_RELATIVE = join('planu', 'conventions.json');
async function readConventions(projectPath) {
    try {
        const raw = await readFile(join(projectPath, CONVENTIONS_RELATIVE), 'utf-8');
        if (!raw.trim()) {
            return null;
        }
        const parsed = JSON.parse(raw);
        if (!parsed || typeof parsed !== 'object') {
            return null;
        }
        return parsed;
    }
    catch {
        return null;
    }
}
/**
 * Returns the cached decision string for the given key, or null on miss /
 * parse error / missing file.  Never throws.
 *
 * Keys are stored in `conventions.json#decisions` as plain strings.
 * The full storage key is `${DECISION_CACHE_KEY_PREFIX}${decisionKey}`.
 */
export async function getCachedDecision(projectPath, decisionKey) {
    const conventions = await readConventions(projectPath);
    if (!conventions) {
        return null;
    }
    const decisions = conventions.decisions;
    if (!decisions || typeof decisions !== 'object') {
        return null;
    }
    const storageKey = `${DECISION_CACHE_KEY_PREFIX}${decisionKey}`;
    const value = decisions[storageKey];
    return typeof value === 'string' ? value : null;
}
/**
 * Best-effort write to `conventions.json#decisions[decisionKey]`.
 * Reads the existing file, patches the `decisions` map, and writes atomically.
 * Logs and swallows all errors — never rejects.
 *
 * When the file is missing or corrupted, a minimal valid structure is created.
 */
export async function setCachedDecision(projectPath, decisionKey, value) {
    try {
        const planuDir = join(projectPath, 'planu');
        const filePath = join(planuDir, 'conventions.json');
        // Read existing or start fresh (create minimal valid structure on miss/corruption)
        const conventions = (await readConventions(projectPath)) ??
            {
                detectedAt: new Date().toISOString(),
                stack: {
                    language: 'unknown',
                    framework: null,
                    testRunner: null,
                    linter: null,
                    formatter: null,
                    bundler: null,
                },
                conventions: {
                    fileNaming: 'unknown',
                    functionNaming: 'unknown',
                    testLocation: 'unknown',
                    importStyle: 'unknown',
                    errorHandling: 'unknown',
                },
                baseline: {
                    testCount: 0,
                    lintWarnings: null,
                    coveragePercent: null,
                },
                decisions: {},
            };
        // Patch decisions map
        conventions.decisions ??= {};
        const storageKey = `${DECISION_CACHE_KEY_PREFIX}${decisionKey}`;
        conventions.decisions[storageKey] = value;
        // Write back
        await mkdir(planuDir, { recursive: true });
        await writeFile(filePath, JSON.stringify(conventions, null, 2) + '\n', 'utf-8');
    }
    catch (err) {
        // Best-effort — log and swallow
        console.error(`[decision-cache] Failed to persist decision '${decisionKey}':`, err instanceof Error ? err.message : String(err));
    }
}
//# sourceMappingURL=decision-cache.js.map