// tools/reconcile-universal-rules.ts — SPEC-779: reconcile_universal_rules MCP tool
// Install missing catalog rules without touching user-modified ones.
import { join } from 'node:path';
import { atomicWriteFile } from '../engine/safety/atomic-write-file.js';
import { UNIVERSAL_RULES } from '../engine/universal-rules/catalog.js';
import { writeRuleForHost } from '../engine/universal-rules/host-writer.js';
import { hashContent, readManifest, isUserModified, upsertManifestEntry, } from '../engine/universal-rules/user-edit-detector.js';
import { detectHost } from '../engine/host-detection/detect-host.js';
function manifestPath(projectPath) {
    return join(projectPath, '.claude', 'rules', '.planu-rules-manifest.json');
}
function resolveHost() {
    const detected = detectHost();
    if (detected === 'codex') {
        return 'codex';
    }
    if (detected === 'gemini') {
        return 'gemini';
    }
    return 'claude-code';
}
export async function handleReconcileUniversalRules(input) {
    const projectPath = input.projectPath ?? process.cwd();
    const host = input.host ?? resolveHost();
    const mPath = manifestPath(projectPath);
    const manifest = (await readManifest(mPath)) ?? { rules: [] };
    const result = { added: [], skipped: [], failed: [] };
    for (const rule of UNIVERSAL_RULES) {
        if (!rule.defaultEnabled) {
            continue;
        }
        const isApplicable = rule.applicableHosts.includes('all') || rule.applicableHosts.includes(host);
        if (!isApplicable) {
            result.skipped.push({ id: rule.id, reason: 'not-applicable-for-host' });
            continue;
        }
        // Check if already installed and user-modified
        const alreadyInstalled = manifest.rules.some((r) => r.id === rule.id);
        if (alreadyInstalled) {
            const modified = await isUserModified(rule.id, mPath);
            if (modified) {
                result.skipped.push({ id: rule.id, reason: 'user-modified' });
                continue;
            }
            result.skipped.push({ id: rule.id, reason: 'already-installed' });
            continue;
        }
        // Not installed — install it
        try {
            const writtenPath = await writeRuleForHost(rule, projectPath, host);
            const content = rule.buildContent(host);
            const hash = hashContent(content);
            const entry = {
                id: rule.id,
                path: writtenPath,
                hostId: host,
                hashAtInstall: hash,
                installedAt: new Date().toISOString(),
            };
            const updated = upsertManifestEntry(manifest, entry);
            manifest.rules = updated.rules;
            result.added.push(rule.id);
        }
        catch (err) {
            const msg = err instanceof Error ? err.message : String(err);
            result.failed.push({ id: rule.id, error: msg });
        }
    }
    // Persist manifest
    try {
        await atomicWriteFile(mPath, JSON.stringify(manifest, null, 2), { _skipFreezeCheck: true });
    }
    catch {
        // Non-fatal
    }
    const lines = [
        '## Reconcile Universal Rules',
        '',
        `Added: ${result.added.length > 0 ? result.added.join(', ') : 'none'}`,
        `Skipped: ${result.skipped.length}`,
        `Failed: ${result.failed.length}`,
    ];
    if (result.skipped.length > 0) {
        lines.push('', '### Skipped');
        for (const s of result.skipped) {
            lines.push(`- \`${s.id}\`: ${s.reason}`);
        }
    }
    if (result.failed.length > 0) {
        lines.push('', '### Failed');
        for (const f of result.failed) {
            lines.push(`- \`${f.id}\`: ${f.error}`);
        }
    }
    return {
        content: [{ type: 'text', text: lines.join('\n') }],
        isError: result.failed.length > 0,
    };
}
//# sourceMappingURL=reconcile-universal-rules.js.map