import fss from "node:fs";
import path from "node:path";
import { resolveProjectConfig, getProjectKnowledgeDir } from "../../knowledge/loader.js";
import { debug, userInfo, userError, } from "../../engine/core/logger.js";
import { resolveCurrentProjectConfigReports, validateConfigPrecedence, } from "../../engine/config/config_precedence_contract.js";
import { loadConfigEvidenceEntries, } from "../config_commands.js";
import YAML from "yaml";
import { resolveProjectPath, args } from "../args.js";
import { errorMessage, safeJsonParse } from "../../engine/core/helpers.js";
function getConfigFieldValue(config, key) {
    const parts = key.split(".");
    let obj = config;
    for (const part of parts) {
        if (obj === null || typeof obj !== "object")
            return undefined;
        obj = obj[part];
    }
    return obj;
}
async function checkEvidenceWarnings(projectPath) {
    debug("CLI", "执行 checkEvidenceWarnings —", projectPath);
    const warnings = [];
    const configPath = path.join(projectPath, ".soloforge", "config.yaml");
    const evidencePath = path.join(projectPath, ".soloforge", "config.evidence.json");
    if (!fss.existsSync(configPath))
        return warnings;
    if (!fss.existsSync(evidencePath)) {
        warnings.push("config.yaml 存在但 config.evidence.json 缺失 — 来源追溯性丢失");
        return warnings;
    }
    // 检查 mtime 过期
    try {
        const configStat = fss.statSync(configPath);
        const evidenceStat = fss.statSync(evidencePath);
        if (configStat.mtimeMs > evidenceStat.mtimeMs) {
            warnings.push("config.evidence.json 已过期（config.yaml 在 evidence 生成后被修改）");
        }
    }
    catch {
        debug("status", "文件 mtime 过期检查失败，跳过");
    }
    // 旧版字段一致性检查（schema v1 evidence）
    try {
        const evidenceRaw = safeJsonParse(fss.readFileSync(evidencePath, "utf-8"));
        if (!evidenceRaw)
            throw new Error("无法解析 config evidence");
        const configContent = fss.readFileSync(configPath, "utf-8");
        const config = YAML.parse(configContent);
        for (const [key, field] of Object.entries(evidenceRaw.fields)) {
            const actualValue = getConfigFieldValue(config, key);
            if (actualValue !== undefined && JSON.stringify(field.value) !== JSON.stringify(actualValue)) {
                warnings.push(`evidence 字段 '${key}' 的值与 config.yaml 不匹配`);
            }
        }
    }
    catch {
        debug("status", "旧版字段一致性检查失败，跳过");
    }
    // 使用 schema v2 条目验证配置优先级
    try {
        const entries = loadConfigEvidenceEntries(projectPath);
        // 检查 C 类字段自动写入违规
        for (const e of entries) {
            if (e.source === "cli_flag" || e.source === "mcp_param") {
                if (e.lifetime === "project_persistent") {
                    warnings.push(`CLI/MCP 参数（${e.source}）已持久化到 config — 字段: ${e.field_path}`);
                }
            }
        }
        // 运行实时解析的配置优先级验证
        try {
            const { reports } = await resolveCurrentProjectConfigReports(projectPath);
            const findings = validateConfigPrecedence(reports, entries);
            for (const f of findings) {
                if (f.severity === "hard_fail") {
                    warnings.push(`[${f.rule}] ${f.message}`);
                }
            }
        }
        catch {
            debug("status", "配置优先级实时验证失败，跳过");
        }
    }
    catch {
        debug("status", "schema v2 条目验证失败，跳过");
    }
    return warnings;
}
function blueprintBackendCommands(framework) {
    switch (framework) {
        case "spring-boot": return { build: "./mvnw compile -q", test: "./mvnw test -q", full: "./mvnw verify -q" };
        case "gradle": return { build: "./gradlew compileJava", test: "./gradlew test", full: "./gradlew check" };
        case "stdlib": return { build: "go build ./...", test: "go test ./...", full: "go test -race ./..." };
        case "cargo": return { build: "cargo build", test: "cargo test", full: "cargo test --all" };
        default: return { build: "echo 'no backend build'", test: "echo 'no backend tests'", full: "echo 'no backend'" };
    }
}
function blueprintFrontendCommands(framework) {
    switch (framework) {
        case "react":
        case "vue":
            return { build: "npm run build", test: "npm test", full: "npm run build && npm test" };
        case "angular":
            return { build: "npx ng build", test: "npx ng test", full: "npx ng build && npx ng test" };
        default: return { build: "echo 'no frontend build'", test: "echo 'no frontend tests'", full: "echo 'no frontend'" };
    }
}
export async function cmdStatus() {
    debug("CLI", "执行 cmdStatus");
    const projectPath = resolveProjectPath();
    const { config, source } = await resolveProjectConfig(projectPath);
    userInfo(`SoloForge 状态: ${projectPath}`);
    userInfo(`  配置来源: ${source === "config_file" ? "config.yaml" : "自动推断"}`);
    userInfo(`  产品: ${config.product_profile}`);
    userInfo(`  后端: ${config.tech_stack.backend.framework || "未配置"}`);
    userInfo(`  前端: ${config.tech_stack.frontend.framework || "未配置"}`);
    // 逐字段配置优先级状态
    try {
        const { resolutions, entries } = await resolveCurrentProjectConfigReports(projectPath);
        if (resolutions.length > 0) {
            userInfo("");
            userInfo("  字段解析状态:");
            for (const r of resolutions) {
                const stale = r.stale_warning ? " ⚠️ stale" : "";
                const conflict = r.conflict_report ? " ⚠️ conflict" : "";
                userInfo(`    ${r.field_path}: ${JSON.stringify(r.resolved_value)} (${r.source}${stale}${conflict})`);
            }
        }
        const schemaPath = path.join(projectPath, ".soloforge", "config.evidence.json");
        if (fss.existsSync(schemaPath)) {
            try {
                const raw = safeJsonParse(fss.readFileSync(schemaPath, "utf-8"));
                userInfo(`  evidence: schema_version=${raw?.schema_version ?? 1}, ${entries.length} 条`);
            }
            catch (e) {
                userInfo("  evidence: 无法解析: " + String(e));
            }
        }
        else if (source === "config_file") {
            userInfo("  evidence: ⚠️ config.evidence.json 缺失");
        }
    }
    catch {
        debug("status", "字段解析状态获取失败，跳过");
    }
    // Evidence 警告
    const evidenceWarnings = await checkEvidenceWarnings(projectPath);
    for (const w of evidenceWarnings) {
        userInfo(`  ⚠️  evidence: ${w}`);
    }
    const knowledgeDir = getProjectKnowledgeDir(config);
    if (fss.existsSync(knowledgeDir)) {
        const { KnowledgeIndexManager } = await import("../../knowledge/index_manager.js");
        const index = new KnowledgeIndexManager(config, { watch: false });
        try {
            await index.build();
            const entries = index.getAllEntries();
            userInfo(`  知识: ${entries.global.length} 全局 + ${entries.project.length} 项目`);
        }
        finally {
            await index.close();
        }
    }
    else {
        userInfo("  知识: 未初始化");
    }
    // 导航摘要（消费同一规划模块，包含阻断项和下一步）
    try {
        const { planNextAction } = await import("../../engine/workflow/next_action_planner.js");
        const navigation = await planNextAction(projectPath);
        userInfo(`  阶段: ${navigation.project_stage}${navigation.task_stage ? ` / ${navigation.task_stage}` : ""}`);
        if (navigation.blocking_reasons.length > 0) {
            userInfo(`  导航阻断: ${navigation.blocking_reasons.join("; ")}`);
        }
        if (navigation.confirmation_decisions.auto_resolvable.length > 0) {
            userInfo(`  可自动处理: ${navigation.confirmation_decisions.auto_resolvable.map((item) => item.command_hint ?? item.title_zh).join(" / ")}`);
        }
        if (navigation.confirmation_decisions.must_confirm.length > 0) {
            userInfo(`  必须确认: ${navigation.confirmation_decisions.must_confirm.map((item) => item.title_zh).join(" / ")}`);
        }
        userInfo(`  下一步: ${navigation.work_package?.goal_zh ?? navigation.recommended_prompt_zh}`);
    }
    catch (e) {
        userInfo(`  ⚠ 导航摘要异常: ${errorMessage(e)}`);
    }
}
export async function interactiveConfig(projectPath) {
    debug("CLI", "执行 interactiveConfig");
    if (!process.stdin.isTTY)
        return undefined;
    const readline = await import("node:readline");
    const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
    const ask = (q) => new Promise((res) => rl.question(q, res));
    const name = await ask("项目名称: ") || "my-project";
    const product = await ask("产品类型 (saas/b2b-internal/b2c): ") || "default";
    const backendFramework = await ask("后端框架 (spring-boot): ") || "spring-boot";
    const frontendFramework = await ask("前端框架 (react): ") || "react";
    rl.close();
    const draft = {
        name,
        tech_stack: {
            backend: { lang: backendFramework === "go" ? "go" : "java", framework: backendFramework, version: "" },
            frontend: { lang: "typescript", framework: frontendFramework, version: "" },
        },
        product_profile: product,
        build_commands: {
            backend: blueprintBackendCommands(backendFramework),
            frontend: blueprintFrontendCommands(frontendFramework),
        },
        scope: { backend: [], frontend: [] },
        advisory_notes: [],
        confidence: "high",
    };
    const src = "confirmed";
    const evidence = {
        schema_version: 1,
        generated_at: new Date().toISOString(),
        mode: "interactive",
        project_root: projectPath,
        fields: {
            "name": { value: name, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
            "tech_stack.backend": { value: draft.tech_stack.backend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
            "tech_stack.frontend": { value: draft.tech_stack.frontend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
            "build_commands.backend": { value: draft.build_commands.backend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
            "build_commands.frontend": { value: draft.build_commands.frontend, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
            "product_profile": { value: product, confidence: "high", confidence_source: src, evidence: ["--interactive input"] },
            "scope.backend": { value: draft.scope.backend, confidence: "low", confidence_source: "default", evidence: ["黑名单模式：scope 为空，仅受内置安全黑名单约束"] },
            "scope.frontend": { value: draft.scope.frontend, confidence: "low", confidence_source: "default", evidence: ["黑名单模式：scope 为空，仅受内置安全黑名单约束"] },
        },
    };
    return { draft, evidence };
}
export function cmdVersion() {
    debug("CLI", "执行 cmdVersion");
    // dist/bin/commands/status.js → dist/package.json (local) 或 package.json (global npm)
    const pkgPath = path.resolve(import.meta.dirname, "..", "..", "package.json");
    try {
        const pkg = safeJsonParse(fss.readFileSync(pkgPath, "utf-8"));
        userInfo("SoloForge v" + (pkg?.version ?? "unknown"));
    }
    catch {
        // 回退: 从 dist 同级目录查找
        try {
            const altPath = path.resolve(import.meta.dirname, "..", "..", "..", "package.json");
            const altPkg = safeJsonParse(fss.readFileSync(altPath, "utf-8"));
            userInfo("SoloForge v" + (altPkg?.version ?? "unknown"));
        }
        catch (e) {
            debug("status", "版本读取失败 —", e);
            userInfo("SoloForge (version unknown)");
        }
    }
}
export async function cmdNext() {
    debug("CLI", "执行 cmdNext");
    const projectPath = resolveProjectPath();
    const isJson = args.includes("--json");
    const writeSnapshot = args.includes("--write-snapshot");
    const { planNextAction } = await import("../../engine/workflow/next_action_planner.js");
    const plan = await planNextAction(projectPath);
    if (isJson) {
        // JSON 模式: 纯 JSON 到 stdout，无日志污染
        const wp = plan.work_package;
        const output = {
            project_stage: plan.project_stage,
            task_stage: plan.task_stage,
            confidence: plan.confidence,
            stage_evidence: plan.stage_evidence,
            blocking_reasons: plan.blocking_reasons,
            confirmation_decisions: plan.confirmation_decisions,
            warnings: plan.warnings,
            recommended_commands: plan.recommended_commands,
            recommended_prompt: plan.recommended_prompt_zh,
            project_knowledge_context: plan.project_knowledge_context,
            disallowed_next_actions: plan.disallowed_actions.map((da) => ({
                rule_id: da.rule_id,
                blocked_actions: da.blocked_actions,
                reason_zh: da.reason_zh,
            })),
            work_package: wp ? {
                id: wp.id,
                goal: wp.goal_zh,
                input_files: wp.input_files,
                must_read: wp.must_read,
                forbidden_changes: wp.forbidden_changes,
                expected_outputs: wp.expected_outputs,
                acceptance_commands: wp.acceptance_commands,
                user_confirmation_points: wp.user_confirmation_points,
                rollback_or_fallback: wp.rollback_or_fallback,
            } : null,
        };
        process.stdout.write(JSON.stringify(output, null, 2) + "\n");
    }
    else {
        // 人类可读输出
        userInfo(`\n项目阶段: ${plan.project_stage}`);
        if (plan.task_stage) {
            userInfo(`任务阶段: ${plan.task_stage}`);
        }
        else {
            userInfo("任务阶段: 无活跃任务");
        }
        userInfo(`置信度: ${plan.confidence}`);
        if (plan.stage_evidence.length > 0) {
            userInfo(`\n判断依据:`);
            for (const ev of plan.stage_evidence) {
                userInfo(`  - ${ev}`);
            }
        }
        if (plan.warnings.length > 0) {
            userInfo(`\n提示:`);
            for (const warning of plan.warnings) {
                userInfo(`  - [${warning.code}] ${warning.message_zh}`);
            }
        }
        userInfo(`\n确认分级:`);
        userInfo(`  必须确认: ${plan.confirmation_decisions.must_confirm.length}`);
        for (const item of plan.confirmation_decisions.must_confirm) {
            userInfo(`    - ${item.title_zh}: ${item.reason_zh}`);
            if (item.command_hint)
                userInfo(`      命令: ${item.command_hint}`);
            userInfo(`      不确认影响: ${item.if_unconfirmed_zh}`);
        }
        userInfo(`  建议确认: ${plan.confirmation_decisions.should_confirm.length}`);
        for (const item of plan.confirmation_decisions.should_confirm) {
            userInfo(`    - ${item.title_zh}: ${item.reason_zh}`);
            if (item.command_hint)
                userInfo(`      命令: ${item.command_hint}`);
        }
        userInfo(`  可自动处理: ${plan.confirmation_decisions.auto_resolvable.length}`);
        for (const item of plan.confirmation_decisions.auto_resolvable) {
            userInfo(`    - ${item.title_zh}`);
            if (item.command_hint)
                userInfo(`      命令: ${item.command_hint}`);
        }
        userInfo(`  推荐处理: ${plan.confirmation_decisions.recommended_action}`);
        if (plan.project_knowledge_context && plan.project_knowledge_context.total > 0) {
            userInfo(`\n项目规则上下文:`);
            userInfo(`  项目知识: ${plan.project_knowledge_context.total} 条，hard_fail: ${plan.project_knowledge_context.hard_fail_count}`);
            if (plan.project_knowledge_context.selected.length > 0) {
                userInfo("  下一步会优先参考:");
                for (const item of plan.project_knowledge_context.selected) {
                    userInfo(`    - ${item.name} (${item.rel_path}, ${item.enforcement ?? item.consumption})`);
                    if (item.reason_zh)
                        userInfo(`      原因: ${item.reason_zh}`);
                    if (item.verification_command)
                        userInfo(`      复验: ${item.verification_command}`);
                }
            }
            if (plan.project_knowledge_context.blocked && plan.project_knowledge_context.blocked.length > 0) {
                userInfo("  必须先处理:");
                for (const item of plan.project_knowledge_context.blocked) {
                    userInfo(`    - ${item.name} (${item.rel_path})`);
                    userInfo(`      原因: ${item.reason_zh}`);
                    if (item.recovery)
                        userInfo(`      恢复: ${item.recovery}`);
                }
            }
        }
        // 陈旧任务
        if (plan.stale_task?.is_stale) {
            userInfo(`\n⚠️  检测到陈旧任务: ${plan.stale_task.reason_zh}`);
            userInfo(`  任务 ID: ${plan.stale_task.task_id}`);
            userInfo(`  建议操作: ${plan.stale_task.suggested_resolutions.join(" / ")}`);
            userInfo(`  ⚠️  不要绕过 SoloForge 状态直接操作`);
        }
        // 阻断项
        if (plan.blocking_reasons.length > 0) {
            userInfo(`\n阻断项:`);
            for (const r of plan.blocking_reasons) {
                userInfo(`  - ${r}`);
            }
        }
        // 工作包
        if (plan.work_package) {
            const wp = plan.work_package;
            userInfo(`\n下一步: ${wp.goal_zh}`);
            userInfo(`  描述: ${wp.description_zh}`);
            if (wp.tool_name) {
                userInfo(`  工具: ${wp.tool_name}`);
            }
            if (wp.must_read.length > 0) {
                userInfo(`  必读文件:`);
                for (const f of wp.must_read)
                    userInfo(`    - ${f}`);
            }
            if (wp.forbidden_changes.length > 0) {
                userInfo(`  禁止操作:`);
                for (const f of wp.forbidden_changes)
                    userInfo(`    - ${f}`);
            }
            if (wp.expected_outputs.length > 0) {
                userInfo(`  预期产出:`);
                for (const e of wp.expected_outputs)
                    userInfo(`    - ${e}`);
            }
            if (wp.acceptance_commands.length > 0) {
                userInfo(`  验收命令:`);
                for (const c of wp.acceptance_commands)
                    userInfo(`    - ${c}`);
            }
            if (wp.user_confirmation_points.length > 0) {
                userInfo(`  工作包确认点（是否阻塞以上方确认分级为准）:`);
                for (const u of wp.user_confirmation_points)
                    userInfo(`    - ${u}`);
            }
            if (wp.rollback_or_fallback.length > 0) {
                userInfo(`  失败回退:`);
                for (const r of wp.rollback_or_fallback)
                    userInfo(`    - ${r}`);
            }
        }
        // 推荐命令
        if (plan.recommended_commands.length > 0) {
            userInfo(`\n推荐命令:`);
            for (const c of plan.recommended_commands) {
                userInfo(`  ${c}`);
            }
        }
        // 禁止动作
        if (plan.disallowed_actions.length > 0) {
            userInfo(`\n禁止动作:`);
            for (const da of plan.disallowed_actions) {
                userInfo(`  [${da.rule_id}] ${da.blocked_actions.join(", ")}: ${da.reason_zh}`);
            }
        }
        // 推荐给 AI 的指令
        userInfo(`\n推荐指令: ${plan.recommended_prompt_zh}`);
    }
    // 写入快照（只在显式 --write-snapshot 时）
    if (writeSnapshot) {
        const snapshotPath = path.join(projectPath, ".soloforge", "navigation-snapshot.json");
        const snapshot = {
            plan_id: plan.plan_id,
            generated_at: plan.generated_at,
            project_stage: plan.project_stage,
            task_stage: plan.task_stage,
            current_task_id: plan.current_task_id,
            work_package: plan.work_package,
        };
        fss.mkdirSync(path.join(projectPath, ".soloforge"), { recursive: true });
        fss.writeFileSync(snapshotPath, JSON.stringify(snapshot, null, 2));
        if (!isJson) {
            userInfo(`\n导航快照已写入: ${snapshotPath}`);
        }
    }
}
export async function cmdStage() {
    debug("CLI", "执行 cmdStage");
    const projectPath = resolveProjectPath();
    const explain = args.includes("--explain");
    const isJson = args.includes("--json");
    const { detectProjectStage, explainProjectStage } = await import("../../engine/workflow/project_stage_detector.js");
    const { detectTaskStage, explainTaskStage } = await import("../../engine/pipeline/task_stage_detector.js");
    const projectStage = await detectProjectStage(projectPath);
    // 加载当前任务
    let taskStage = null;
    let taskId = null;
    try {
        const { TaskContextManager } = await import("../../engine/pipeline/task_context.js");
        const stateDir = path.join(projectPath, ".soloforge", "state");
        if (fss.existsSync(stateDir)) {
            const manager = new TaskContextManager(stateDir);
            const ctx = await manager.getCurrentTask();
            if (ctx) {
                taskStage = detectTaskStage(ctx);
                taskId = ctx.task_id;
            }
        }
    }
    catch {
        debug("status", "加载当前任务失败，跳过");
    }
    if (isJson) {
        const projExplanation = explainProjectStage(projectStage);
        process.stdout.write(JSON.stringify({
            project: projExplanation,
            task: taskStage ? explainTaskStage(taskStage) : null,
            task_id: taskId,
        }, null, 2) + "\n");
        return;
    }
    userInfo(`\n项目阶段: ${projectStage}`);
    if (explain) {
        const projExplanation = explainProjectStage(projectStage);
        userInfo(`  ${projExplanation.description_zh}`);
        userInfo(`  必要条件: ${projExplanation.required_evidence.join(", ") || "无"}`);
        userInfo(`  下一步可能: ${projExplanation.next_possible_stages.join(", ")}`);
    }
    if (taskStage) {
        userInfo(`\n任务阶段: ${taskStage} (${taskId ?? "unknown"})`);
        if (explain) {
            const taskExplanation = explainTaskStage(taskStage);
            userInfo(`  ${taskExplanation.description_zh}`);
            userInfo(`  必要条件: ${taskExplanation.required_evidence.join(", ")}`);
            userInfo(`  下一步可能: ${taskExplanation.next_possible_stages.join(", ")}`);
        }
    }
    else {
        userInfo("\n当前无活跃任务");
    }
}
export async function cmdCleanup() {
    debug("CLI", "执行 cmdCleanup");
    const dryRun = !args.includes("--apply");
    const staleOnly = args.includes("--stale");
    const projectPath = process.cwd();
    const stateDir = path.join(projectPath, ".soloforge", "state");
    let hasError = false;
    userInfo(`SoloForge 清理: ${projectPath}`);
    userInfo(`  模式: ${dryRun ? "dry-run（仅评估）" : "⚠️ 实际清理"}`);
    if (staleOnly) {
        try {
            const { detectStaleCurrentTask, archiveStaleCurrentPointer } = await import("../../engine/pipeline/stale_current_task_detector.js");
            const stale = await detectStaleCurrentTask(stateDir);
            userInfo("");
            userInfo("  陈旧 current-task 检测:");
            if (!stale.is_stale || !stale.task_id) {
                userInfo("    未发现陈旧指针");
                return;
            }
            userInfo(`    陈旧任务: ${stale.task_id}`);
            userInfo(`    原因: ${stale.reason_zh}`);
            if (dryRun) {
                userInfo("    处理: dry-run，仅提示；使用 --apply 归档指针");
                return;
            }
            const archived = await archiveStaleCurrentPointer(stateDir, stale.task_id);
            if (!archived) {
                userError("  ❌ 陈旧指针归档失败");
                process.exit(1);
            }
            userInfo("    处理: 已归档 current-task 指针，任务文件未删除");
            return;
        }
        catch (e) {
            userError(`  ❌ 陈旧 current-task 检测失败: ${errorMessage(e)}`);
            process.exit(1);
        }
    }
    // 收集所有 evidence 引用来源：task-*.json 中的 evidence 文件名 / evidence id
    const referencedEvidenceIds = new Set();
    // 扫描 task context 文件中的 evidence 引用
    if (fss.existsSync(stateDir)) {
        for (const f of fss.readdirSync(stateDir).filter((f) => f.startsWith("task-") && f.endsWith(".json"))) {
            try {
                const content = fss.readFileSync(path.join(stateDir, f), "utf-8");
                // eslint-disable-next-line @typescript-eslint/no-explicit-any -- MCP SDK 桥接/动态 JSON 解析，字段由运行时决定
                const ctx = safeJsonParse(content);
                // 从 verification_evidence 收集引用
                if (ctx.verification_evidence && typeof ctx.verification_evidence === "object") {
                    for (const [key, val] of Object.entries(ctx.verification_evidence)) {
                        if (typeof val === "string")
                            referencedEvidenceIds.add(val);
                        referencedEvidenceIds.add(key);
                    }
                }
                // 从 artifacts 的 evidence_refs 收集
                if (Array.isArray(ctx.output_artifacts)) {
                    for (const art of ctx.output_artifacts) {
                        if (art.evidence_refs && Array.isArray(art.evidence_refs)) {
                            for (const ref of art.evidence_refs)
                                referencedEvidenceIds.add(ref);
                        }
                        if (art.artifact_id)
                            referencedEvidenceIds.add(art.artifact_id);
                    }
                }
                // 从 delivery_report 收集
                if (ctx.delivery_report && typeof ctx.delivery_report === "object") {
                    const dr = ctx.delivery_report;
                    if (dr.evidence_refs && Array.isArray(dr.evidence_refs)) {
                        for (const ref of dr.evidence_refs)
                            referencedEvidenceIds.add(ref);
                    }
                }
                // 从 governance_report 收集
                if (ctx.governance_report && typeof ctx.governance_report === "string") {
                    referencedEvidenceIds.add(ctx.governance_report);
                }
            }
            catch (e) {
                debug("cleanup", "跳过不可解析文件 —", e);
            }
        }
    }
    // 1. TaskContext 清理（使用 retention_policy）
    if (fss.existsSync(stateDir)) {
        try {
            const { TaskContextManager } = await import("../../engine/pipeline/task_context.js");
            const mgr = new TaskContextManager(stateDir);
            const result = await mgr.cleanup(dryRun);
            userInfo("");
            userInfo("  TaskContext 清理:");
            userInfo(`    已清理: ${result.removed} 条`);
            userInfo(`    受保护（被引用不可删除）: ${result.protected} 条`);
            userInfo(`    禁止内容检出: ${result.forbidden_content_hits.length > 0 ? result.forbidden_content_hits.join("; ") : "无"}`);
            userInfo(`    dry_run: ${result.dry_run}`);
            if (result.forbidden_content_hits.length > 0) {
                userError(`  ❌ TaskContext 包含禁止内容，清理中止`);
                hasError = true;
            }
        }
        catch (e) {
            userError(`  ❌ TaskContext 清理失败: ${errorMessage(e)}`);
            process.exit(1);
        }
    }
    else {
        userInfo("  TaskContext: 状态目录不存在，跳过");
    }
    // 2. Evidence 文件清理（真实引用扫描）
    const evidenceDir = path.join(projectPath, ".soloforge");
    if (fss.existsSync(evidenceDir)) {
        try {
            const { evaluateCleanup, checkForbiddenContent } = await import("../../engine/retention_policy.js");
            const evidenceFiles = fss.readdirSync(evidenceDir)
                .filter((f) => f.endsWith(".json") && !f.startsWith("config."))
                .map((f) => {
                const fp = path.join(evidenceDir, f);
                const stat = fss.statSync(fp);
                const ageDays = Math.max(0, (Date.now() - stat.mtimeMs) / (24 * 60 * 60 * 1000));
                const content = fss.readFileSync(fp, "utf-8");
                const forbiddenHits = checkForbiddenContent("evidence", content);
                // 真实引用检查: evidence 文件名或内容中的 id 出现在引用集合中
                const isReferenced = referencedEvidenceIds.has(f) || referencedEvidenceIds.has(f.replace(/\.json$/, ""));
                return { name: f, age_days: ageDays, is_referenced: isReferenced, forbidden: forbiddenHits };
            });
            const records = evidenceFiles.map(e => ({ id: e.name, age_days: e.age_days, is_referenced: e.is_referenced }));
            const result = evaluateCleanup("evidence", records, dryRun);
            userInfo("");
            userInfo("  Evidence 清理:");
            userInfo(`    总文件: ${result.total_records}`);
            userInfo(`    可清理: ${result.eligible_for_cleanup}`);
            userInfo(`    受保护: ${result.protected_records}`);
            userInfo(`    dry_run: ${result.dry_run}`);
            if (result.cleanup_candidates.length > 0) {
                userInfo(`    清理候选: ${result.cleanup_candidates.join(", ")}`);
            }
            const forbiddenFiles = evidenceFiles.filter(e => e.forbidden.length > 0);
            if (forbiddenFiles.length > 0) {
                userInfo("    ❌ 禁止内容检出:");
                for (const f of forbiddenFiles) {
                    userInfo(`      ${f.name}: ${f.forbidden.join(", ")}`);
                }
                hasError = true;
            }
        }
        catch (e) {
            userError(`  ❌ Evidence 清理失败: ${errorMessage(e)}`);
            process.exit(1);
        }
    }
    // 3. 列出所有保留策略
    try {
        const { listRetentionPolicies } = await import("../../engine/retention_policy.js");
        const policies = listRetentionPolicies();
        userInfo("");
        userInfo("  保留策略:");
        for (const p of policies) {
            userInfo(`    ${p.policy_id}: ${p.record_type}, 最大 ${p.max_age_days} 天 / ${p.max_count} 条, dry_run_default=${p.dry_run_default}`);
        }
    }
    catch (e) {
        userError(`  ❌ 保留策略加载失败: ${errorMessage(e)}`);
        process.exit(1);
    }
    if (hasError)
        process.exit(1);
}
//# sourceMappingURL=status.js.map