import fs from "node:fs";
import path from "node:path";
import { checkJavaQuality } from "../audit/java_quality_guard.js";
import { orphanGate, buildMainPathIntegrationContracts, } from "../audit/main_path_integration_contract.js";
import { checkCorePrinciples } from "../audit/core_engineering_principles.js";
import { createCommandContract } from "../contracts/command_execution_contract.js";
import { debugLog } from "../core/logger.js";
import { checkAnalysisGate } from "../contracts/existing_system_analysis.js";
import { evaluateCodingReadiness } from "../contracts/coding_readiness_gate.js";
import { performDetailCheck } from "../contracts/detail_discipline.js";
import { performFirstPrinciplesCheck } from "../contracts/first_principles.js";
debugLog("verifier: 验证命令生成器模块已加载");
/** 终局宣言签名 */
const SOLOFORGE_AUDIT_PASS = "[SoloForge Audit: PASS - 已通过三重深度推演，确认无潜在隐患]";
const SOLOFORGE_AUDIT_FAIL = "[SoloForge Audit: FAIL - 三重推演发现未覆盖的边界场景]";
/**
 * 三重否定推演 — AI 必须假设自己的方案是错的，寻找能使其崩溃的极端边界。
 * 推演三重否定:
 * 1. 边界否定: 输入为空/极大/特殊字符时是否崩溃
 * 2. 状态否定: 并发/中断/部分失败后状态是否一致
 * 3. 链路否定: 上游依赖返回异常/超时/格式错误时是否安全
 *
 * @param params - 推演参数，包含变更文件、验收项和项目配置
 * @returns 三重否定推演结果，包含崩溃场景、修复建议和终局宣言
 */
/**
 * 知识消费钩子: 记录 verifier 的知识资产消费到统一 trace store。
 */
import { recordConsumptionTrace, getTracesByConsumer, CONSUMER_FIELD_CONTRACTS } from "../templates/consumption_trace_store.js";
import { listConsumableAssetsByConsumer } from "../templates/consumable_asset_registry.js";
/**
 * 内部函数: 在真实验证路径中记录 verifier 消费 trace。
 * 仅从 generateVerifyCommands 内部调用，不对外导出。
 * 记录真实验证决策消费的验证规则，不使用 registry 全量补数。
 */
function recordVerifierConsumptionInternal(route, changedFiles) {
    const verifierAssets = listConsumableAssetsByConsumer("verifier")
        .filter(a => a.consumption_mode === "required");
    if (verifierAssets.length === 0)
        return;
    for (const asset of verifierAssets) {
        recordConsumptionTrace({
            consumer: "verifier",
            asset_id: asset.id,
            fields_consumed: CONSUMER_FIELD_CONTRACTS.verifier,
            matched_reason: `verifier.generateVerifyCommands route=${route ?? "unknown"} files=${changedFiles.length}`,
            task_id_or_route: route ?? "verify",
            consumed_at: new Date().toISOString(),
        });
    }
}
export function getVerifierConsumptionTrace() {
    return getTracesByConsumer("verifier").map(t => ({
        task_id: t.task_id_or_route,
        consumed_hard_blocks: t.fields_consumed.filter(f => f === "hard_blocks"),
        consumed_required_evidence: t.fields_consumed.filter(f => f === "required_evidence"),
        consumed_at: t.consumed_at,
    }));
}
export function performTripleNegation(params) {
    const { changedFiles, acceptanceItems } = params;
    const crashScenarios = [];
    const mitigations = [];
    debugLog("verifier: 开始三重否定推演");
    // 推演 1: 边界否定 — 检查验收项是否覆盖空值和极端值
    const hasBoundaryCheck = acceptanceItems.some((a) => /null|undefined|空|边界|极端|空值/.test(a.description));
    if (!hasBoundaryCheck && changedFiles.length > 0) {
        crashScenarios.push("验收项未覆盖空值/边界值输入场景");
        mitigations.push("增加验收项: 核心入参为 null/undefined/空字符串时系统不崩溃");
    }
    // 推演 2: 状态否定 — 涉及数据库或状态变更时检查事务和幂等
    const hasStateFiles = changedFiles.some((f) => /service|repository|mapper|controller/i.test(f));
    const hasTransactionCheck = acceptanceItems.some((a) => /事务|幂等|并发|原子|一致性/.test(a.description));
    if (hasStateFiles && !hasTransactionCheck) {
        crashScenarios.push("涉及状态变更但验收项未覆盖事务/幂等/并发场景");
        mitigations.push("增加验收项: 操作中断后重试不会产生重复数据或状态不一致");
    }
    // 推演 3: 链路否定 — 涉及外部调用时检查异常处理
    const hasIntegrationFiles = changedFiles.some((f) => /api|client|feign|http|rpc|external|integrat/i.test(f));
    const hasErrorHandlingCheck = acceptanceItems.some((a) => /异常|超时|降级|fallback|错误处理/.test(a.description));
    if (hasIntegrationFiles && !hasErrorHandlingCheck) {
        crashScenarios.push("涉及外部调用但验收项未覆盖上游异常/超时场景");
        mitigations.push("增加验收项: 外部依赖超时或返回异常格式时系统安全降级");
    }
    const passed = crashScenarios.length === 0;
    if (!passed) {
        debugLog(`verifier: 三重否定推演发现 ${crashScenarios.length} 个未覆盖场景`);
    }
    else {
        debugLog("verifier: 三重否定推演通过");
    }
    return {
        crash_scenarios: crashScenarios,
        mitigation_suggestions: mitigations,
        audit_declaration: passed ? SOLOFORGE_AUDIT_PASS : SOLOFORGE_AUDIT_FAIL,
        passed,
    };
}
/**
 * 生成完整的验证命令集，包含构建、测试、自动验收和人工验收。
 * @param config - 项目配置，包含仓库定义和构建命令
 * @param changedFiles - 变更文件路径列表
 * @param acceptanceItems - 验收项列表（自动 + 人工）
 * @param route - 可选，当前路由类型
 * @param executionShape - 可选，当前执行形态
 * @returns 验证结果，包含命令列表、摘要、证据项和覆盖率矩阵
 */
export function generateVerifyCommands(config, changedFiles, acceptanceItems, route, executionShape) {
    debugLog(`verifier: 生成验证命令，变更文件 ${changedFiles.length} 个`);
    const projectPath = config._projectPath || process.cwd();
    // 确定受影响的仓库
    const affectedRepos = detectAffectedRepos(changedFiles, config);
    // 无变更文件时跳过构建/测试
    const hasChanges = changedFiles.length > 0;
    // 文档变更检测: 纯文档变更不生成构建/测试命令
    const docOnly = hasChanges && isDocumentationOnly(changedFiles);
    // 为每个受影响仓库收集构建命令
    const buildCommands = [];
    const testCommands = [];
    if (!hasChanges) {
        // 无变更文件: 不生成构建/测试命令
    }
    else if (docOnly) {
        // 文档变更: 生成合理验证命令
        const docBuild = resolveDocVerifyCommand(projectPath);
        if (docBuild)
            buildCommands.push(docBuild);
    }
    else if (affectedRepos.length > 0) {
        for (const repo of affectedRepos) {
            const buildCmd = resolveBuildCommand(config, repo, projectPath);
            if (buildCmd)
                buildCommands.push(buildCmd);
            const testCmd = resolveTestCommand(config, repo, projectPath);
            if (testCmd)
                testCommands.push(testCmd);
        }
    }
    else {
        // 无匹配 repo 且非纯文档: 从项目根目录启发式检测
        const rootBuild = resolveBuildCommandFromRoot(projectPath);
        if (rootBuild)
            buildCommands.push(rootBuild);
        const rootTest = resolveTestCommandFromRoot(projectPath);
        if (rootTest)
            testCommands.push(rootTest);
    }
    // 验收检查
    const automatedItems = acceptanceItems.filter((a) => a.type === "automated" && a.check_command);
    const acceptance = automatedItems.length > 0
        ? automatedItems.map((item) => ({
            id: item.id,
            description: item.description,
            check_command: item.check_command,
            cwd: projectPath,
        }))
        : undefined;
    // 人工验收项
    const manualItems = acceptanceItems
        .filter((a) => a.type === "manual")
        .map((a) => a.description);
    const autoTotal = automatedItems.length;
    const manualTotal = manualItems.length;
    const parts = [];
    if (buildCommands.length > 0)
        parts.push(`编译检查 (${buildCommands.length} 个仓库)`);
    if (testCommands.length > 0)
        parts.push(`测试 (${testCommands.length} 个仓库)`);
    if (autoTotal > 0)
        parts.push(`${autoTotal} 项自动验收`);
    if (manualTotal > 0)
        parts.push(`${manualTotal} 项需人工确认`);
    let summary;
    if (docOnly) {
        summary = buildCommands.length > 0
            ? `纯文档变更，执行格式检查: ${buildCommands.map((c) => c.command).join(" → ")}`
            : "纯文档变更，请人工确认文档内容正确性";
    }
    else if (parts.length > 0) {
        summary = `请依次执行: ${parts.join(" → ")}`;
    }
    else {
        summary = "⚠️ 无法确定构建命令，请手动验证编译和测试";
    }
    // 证据分级（能力 2）
    const evidence = buildEvidenceItems(buildCommands, testCommands, automatedItems);
    const coverage = buildCoverageMatrix(changedFiles, automatedItems);
    // Java 质量守卫: 对变更的 Java 文件执行质量检查
    const javaFiles = changedFiles.filter((f) => f.endsWith(".java"));
    const javaGuardEvidence = [];
    if (javaFiles.length > 0) {
        for (const jf of javaFiles) {
            const fullPath = path.join(projectPath, jf);
            if (fs.existsSync(fullPath)) {
                const content = fs.readFileSync(fullPath, "utf-8");
                const report = checkJavaQuality(jf, content);
                const sevLabel = report.hard_gate_failures > 0 ? "hard_gate" : "advisory";
                javaGuardEvidence.push({
                    id: `EV-JAVA-${jf.replace(/[^a-zA-Z0-9]/g, "_")}`,
                    level: sevLabel === "hard_gate" ? "E1" : "E2",
                    description: `Java 质量检查: ${jf} (${report.summary})`,
                    source: "static_analysis",
                    passed: report.can_proceed,
                });
            }
        }
    }
    // 机制 2: 三重否定推演
    const tripleNegation = performTripleNegation({
        changedFiles,
        acceptanceItems,
        projectConfig: config,
    });
    // 终局宣言注入 summary
    let finalSummary = summary;
    if (!tripleNegation.passed) {
        finalSummary += `\n\n${tripleNegation.audit_declaration}`;
        if (tripleNegation.crash_scenarios.length > 0) {
            finalSummary += `\n\n⚠ 三重否定推演发现以下未覆盖场景:`;
            for (const scenario of tripleNegation.crash_scenarios) {
                finalSummary += `\n- ${scenario}`;
            }
            finalSummary += `\n\n建议补充:`;
            for (const mit of tripleNegation.mitigation_suggestions) {
                finalSummary += `\n- ${mit}`;
            }
        }
    }
    else {
        finalSummary += `\n\n${tripleNegation.audit_declaration}`;
    }
    // ── 真实主链路集成扫描 ──
    const contracts = buildMainPathIntegrationContracts(projectPath, changedFiles, config);
    const integrationFindings = [];
    const checkedModules = [];
    for (const contract of contracts) {
        const findings = orphanGate(contract);
        if (findings.length > 0) {
            integrationFindings.push(...findings);
        }
        checkedModules.push(contract.module_path);
    }
    const integrationPassed = integrationFindings.every((f) => f.severity !== "hard_fail");
    if (!integrationPassed) {
        debugLog("verifier: 主链路集成检查失败");
        finalSummary += "\n\n⚠ 主链路集成检查失败: 存在孤岛模块或缺少集成/契约测试";
        for (const f of integrationFindings.filter((f) => f.severity === "hard_fail")) {
            finalSummary += `\n- ${f.module_path}: ${f.reason}`;
        }
        // 显示每个失败模块的证据
        for (const c of contracts) {
            if (!c.production_imports.length) {
                finalSummary += `\n  模块 ${c.module_path}: 无生产导入 (test=${c.integration_tests.length}, entry=${c.entry_traces.length}, obs=${c.observability_refs.length})`;
            }
        }
    }
    else if (integrationFindings.length > 0) {
        finalSummary += "\n\n⚠ 主链路集成检查: 存在需要关注的问题";
        for (const f of integrationFindings) {
            finalSummary += `\n- ${f.module_path}: ${f.reason}`;
        }
    }
    else if (checkedModules.length > 0) {
        finalSummary += `\n\n✓ 主链路集成检查通过: ${checkedModules.length} 个受检模块全部通过`;
    }
    // 核心工程执行原则检查
    const scopePaths = config.scope?.frontend?.length
        ? config.scope.frontend
        : config.scope?.backend?.length
            ? config.scope.backend
            : [];
    const corePrinciplesCtx = {
        route,
        execution_shape: executionShape,
        changed_files: changedFiles,
        declared_scope: scopePaths,
        // 调用 sf_verify 本身说明存在验证意图，算作有目标定义和验证计划
        has_goal_definition: true,
        has_verification_plan: true,
    };
    const corePrinciples = checkCorePrinciples(corePrinciplesCtx);
    // required 原则失败时，整体 summary 反映失败
    if (!corePrinciples.overall_passed) {
        const failedIds = corePrinciples.principles
            .filter((p) => p.status === "failed")
            .map((p) => p.principle_id);
        debugLog(`verifier: 核心工程执行原则检查失败: ${failedIds.join(", ")}`);
        finalSummary += `\n\n✗ 核心工程执行原则检查失败: ${failedIds.join(", ")}`;
        for (const pr of corePrinciples.principles) {
            if (pr.status === "failed") {
                for (const finding of pr.findings) {
                    finalSummary += `\n  - [${pr.principle_id}] ${finding}`;
                }
            }
        }
    }
    else if (corePrinciples.principles.some((p) => p.status === "passed")) {
        finalSummary += "\n\n✓ 核心工程执行原则检查通过";
    }
    // 10. 机制治理检查 — 条件性调用，使用真实参数
    const mechanismGovernanceEvidence = [];
    const governanceTimestamp = new Date().toISOString();
    const verifyId = `verify-${config.name}-${changedFiles.length}files`;
    // 问题四十九/六十二: 架构文件真实审查在 sf_verify adapter 层读取项目产物包执行。
    // 本命令生成器没有项目文档内容，不得自行拼造宽松 ArchitectureDesignContract。
    const hasArchChanges = changedFiles.some(f => /architecture|arch|design|架构|设计/.test(f) || f.includes("architecture_design"));
    if (hasArchChanges) {
        mechanismGovernanceEvidence.push({ id: `${verifyId}-arch-delegated`, level: "E1", description: "架构设计审查由 sf_verify 的 DesignArtifactPack 真实文件复验门执行；命令生成器不构造替代证据", source: "runtime", passed: true, timestamp: governanceTimestamp });
    }
    else {
        mechanismGovernanceEvidence.push({ id: `${verifyId}-arch-skip`, level: "E2", description: "架构设计审查: 跳过（无架构相关变更文件）", source: "runtime", passed: true, timestamp: governanceTimestamp });
    }
    // problem-50: checkAnalysisGate — 检查现有系统分析是否完成
    const projectType = config.tech_stack?.backend?.framework ? "existing_system" : "new_system";
    const analysisGate = checkAnalysisGate({ project_context_type: projectType, detection_evidence_refs: changedFiles.slice(0, 3), confidence: config.tech_stack?.backend?.framework ? "high" : "medium" }, changedFiles.length > 0, changedFiles.some(f => /spec|analysis|gap/i.test(f)));
    mechanismGovernanceEvidence.push({ id: `${verifyId}-analysis`, level: "E1", description: `分析前置门控(项目类型=${projectType}, 变更=${changedFiles.length}): ${analysisGate.allowed ? "通过" : "阻断"}`, source: "runtime", passed: analysisGate.allowed, timestamp: governanceTimestamp });
    // problem-51: evaluateCodingReadiness — 使用 route 和 changedFiles 构建真实编码准备上下文
    const hasTestAcceptance = acceptanceItems.some(a => /test|测试/.test(a.description));
    const codingReadiness = evaluateCodingReadiness({
        task_id: verifyId,
        project_context_type: projectType,
        task_type: route ?? "unknown",
        consumed_constraints: acceptanceItems.map(a => a.description),
        required_preconditions: changedFiles.length > 0 ? [`变更文件: ${changedFiles.length} 个`] : [],
        test_first_plan: {
            test_first_status: hasTestAcceptance ? "written" : "not_required",
            test_mode: hasTestAcceptance ? "verification_case_first" : "not_applicable_with_reason",
            task_type: route ?? "unknown",
            test_targets: acceptanceItems.filter(a => /test|测试/.test(a.description)).map(a => a.description),
            acceptance_cases: acceptanceItems.filter(a => a.type === "automated").map(a => a.description),
            must_not_break_cases: acceptanceItems.filter(a => a.type === "manual").map(a => a.description),
            expected_failures_before_implementation: [],
            test_files_to_create_or_update: [],
            verification_commands: buildCommands.map(c => c.command),
            manual_acceptance_steps: [],
            not_applicable_reason: hasTestAcceptance ? "" : "验证阶段无测试验收项",
        },
        implementation_scope: changedFiles,
        verification_plan_ref: "verifier.generateVerifyCommands",
        coding_readiness_status: changedFiles.length > 0 ? "ready_for_verification_first" : "manual_required",
    }, changedFiles.some(f => /gap|todo|hack/i.test(f)), !hasTestAcceptance, changedFiles.length === 0);
    mechanismGovernanceEvidence.push({ id: `${verifyId}-coding`, level: "E1", description: `编码准备门控(route=${route ?? "unknown"}, tests=${hasTestAcceptance}): ${codingReadiness.allowed ? "通过" : "阻断"}`, source: "runtime", passed: codingReadiness.allowed, timestamp: governanceTimestamp });
    // problem-26: performDetailCheck — 使用 acceptanceItems 提取真实维度
    const detailDimensions = [...new Set(acceptanceItems.map(a => a.type === "automated" ? "automated" : "manual"))];
    const detailResult = performDetailCheck({ contract_id: `${verifyId}-detail`, target_types: changedFiles.length > 0 ? ["implementation"] : [], required_dimensions: detailDimensions.length > 0 ? detailDimensions : ["implementation"] }, verifyId, "implementation", Object.fromEntries(acceptanceItems.map(a => [a.id, [a.description]])));
    mechanismGovernanceEvidence.push({ id: `${verifyId}-detail`, level: "E1", description: `细节纪律检查(${acceptanceItems.length} 验收项, ${detailDimensions.length} 维度): ${detailResult.detail_check_status}`, source: "runtime", passed: detailResult.detail_check_status === "passed", timestamp: governanceTimestamp });
    // problem-27: performFirstPrinciplesCheck — 使用 changedFiles 和 acceptanceItems 作为已知事实
    const fpResult = performFirstPrinciplesCheck({
        problem_id: `${verifyId}-fp`,
        user_goal: `验证 ${config.name} 的 ${changedFiles.length} 个变更文件`,
        fundamental_need: "变更不引入回归且保持系统一致性",
        known_facts: changedFiles.slice(0, 5).map(f => `变更文件: ${f}`),
        assumptions: acceptanceItems.filter(a => a.type === "manual").map(a => `假设: ${a.description}`),
        candidate_solutions: changedFiles.length > 0 ? [`验证 ${changedFiles.length} 个变更`] : [],
        simplest_viable_solution: changedFiles.length > 0 ? `运行构建和测试验证 ${changedFiles.length} 个变更` : "无变更，无需验证",
        falsification_questions: ["变更是否引入回归？", "测试是否覆盖变更路径？"],
        why_not_legacy_path: `当前验证路径: route=${route ?? "unknown"}, shape=${executionShape ?? "unknown"}`,
        chosen_solution: "执行验证命令集",
        first_principles_status: "passed",
        non_negotiable_constraints: acceptanceItems.filter(a => a.type === "automated").map(a => a.description).slice(0, 3),
    });
    mechanismGovernanceEvidence.push({ id: `${verifyId}-fp`, level: "E1", description: `第一性原理检查(${changedFiles.length} 变更, ${acceptanceItems.length} 验收): ${fpResult.passed ? "通过" : "未通过"}`, source: "runtime", passed: fpResult.passed, timestamp: governanceTimestamp });
    // problem-42: 验证阶段不涉及脑暴 — 记录 not_applicable
    mechanismGovernanceEvidence.push({ id: `${verifyId}-brainstorm-skip`, level: "E2", description: "脑暴会话验证: not_applicable（验证阶段不产生脑暴会话，脑暴由 sf_expand 消费）", source: "runtime", passed: true, timestamp: governanceTimestamp });
    // problem-16: 技术决策验证 — 验证阶段不产生新技术决策 — 记录 not_applicable
    mechanismGovernanceEvidence.push({ id: `${verifyId}-tech-skip`, level: "E2", description: "技术决策验证: not_applicable（验证阶段不产生技术决策，决策由 sf_expand 消费）", source: "runtime", passed: true, timestamp: governanceTimestamp });
    // problem-54: 演进回归门控 — 验证阶段不涉及 issue 演进 — 记录 not_applicable
    mechanismGovernanceEvidence.push({ id: `${verifyId}-evo-skip`, level: "E2", description: "演进回归门控: not_applicable（验证阶段不涉及 issue 演进，演进由问题管理流程消费）", source: "runtime", passed: true, timestamp: governanceTimestamp });
    // problem-53: 工作流模板包 — 验证阶段不验证模板包 — 记录 not_applicable
    mechanismGovernanceEvidence.push({ id: `${verifyId}-pack-skip`, level: "E2", description: "工作流模板包验证: not_applicable（验证阶段不验证模板包，模板包由 sync-templates 消费）", source: "runtime", passed: true, timestamp: governanceTimestamp });
    // 从构建和测试命令生成 command_contracts
    const command_contracts = [
        ...buildCommands.map((cmd) => createCommandContract({
            command: cmd.command,
            cwd: cmd.cwd ?? projectPath,
            source: "soloforge_generated",
            purpose: "build",
            mode: "plan_only",
        })),
        ...testCommands.map((cmd) => createCommandContract({
            command: cmd.command,
            cwd: cmd.cwd ?? projectPath,
            source: "soloforge_generated",
            purpose: "test",
            mode: "plan_only",
        })),
    ];
    debugLog(`verifier: 验证命令生成完成 — 构建 ${buildCommands.length} 个，测试 ${testCommands.length} 个，自动验收 ${autoTotal} 项`);
    // 真实验证路径 — 记录 verifier 消费 trace（使用真实 registry 资产 ID）
    recordVerifierConsumptionInternal(route, changedFiles);
    return {
        task_id: "", // 由调用方填充
        checks: {
            build: buildCommands,
            tests: testCommands,
            acceptance,
        },
        command_contracts,
        summary: finalSummary,
        manual_items: manualItems,
        evidence: [...evidence, ...javaGuardEvidence, ...mechanismGovernanceEvidence].length > 0 ? [...evidence, ...javaGuardEvidence, ...mechanismGovernanceEvidence] : undefined,
        coverage,
        triple_negation: tripleNegation,
        main_path_integration: checkedModules.length > 0 ? {
            passed: integrationPassed,
            findings: integrationFindings,
            checked_modules: checkedModules,
            summary: integrationPassed
                ? `${checkedModules.length} 个模块通过集成检查`
                : `${checkedModules.length} 个模块中存在孤岛或缺少集成/契约测试，主链路集成检查失败`,
        } : undefined,
        core_principles: corePrinciples,
    };
}
// ── 能力 2: 证据分级 ──
/**
 * 构建证据分级项: 构建和测试命令为 E2 级，验收项根据是否有 check_command 分别为 E2/E1 级。
 * @param buildCommands - 构建命令列表
 * @param testCommands - 测试命令列表
 * @param automatedItems - 自动验收项列表
 * @returns 证据项数组，每项包含唯一 ID、证据等级和来源
 */
function buildEvidenceItems(buildCommands, testCommands, automatedItems) {
    const items = [];
    let idx = 0;
    // 构建命令 → E2（脚本验证）
    for (const cmd of buildCommands) {
        items.push({
            id: `EV-${String(++idx).padStart(3, "0")}`,
            level: "E2",
            description: cmd.description,
            source: "command",
            command: cmd.command,
            passed: false,
        });
    }
    // 测试命令 → E2
    for (const cmd of testCommands) {
        items.push({
            id: `EV-${String(++idx).padStart(3, "0")}`,
            level: "E2",
            description: cmd.description,
            source: "command",
            command: cmd.command,
            passed: false,
        });
    }
    // 验收命令 → E2（有 check_command 的）/ E1（无 check_command）
    for (const item of automatedItems) {
        items.push({
            id: `EV-${String(++idx).padStart(3, "0")}`,
            level: item.check_command ? "E2" : "E1",
            description: item.description,
            source: item.check_command ? "command" : "static_analysis",
            command: item.check_command,
            passed: false,
        });
    }
    return items;
}
/**
 * 构建覆盖率矩阵: 从 API 文件、页面文件和业务流三个维度估算测试覆盖率。
 * @param changedFiles - 变更文件路径列表
 * @param automatedItems - 自动验收项列表
 * @returns 覆盖率矩阵，包含各维度的总数、已测试数和差距
 */
function buildCoverageMatrix(changedFiles, automatedItems) {
    // 估算覆盖率：基于变更文件类型和验收项数量
    const apiFiles = changedFiles.filter((f) => /controller|api|route|endpoint/i.test(f) || f.includes("Controller"));
    const pageFiles = changedFiles.filter((f) => /\.(tsx|jsx|vue)$/i.test(f) && !/\.test\./.test(f));
    const hasAcceptance = automatedItems.length > 0;
    return {
        api_coverage: {
            total: apiFiles.length,
            tested: hasAcceptance ? Math.min(apiFiles.length, Math.ceil(automatedItems.length / 3)) : 0,
            gaps: apiFiles.length > 0 && !hasAcceptance ? ["无验收项覆盖 API 变更"] : [],
        },
        page_coverage: {
            total: pageFiles.length,
            tested: hasAcceptance ? Math.min(pageFiles.length, Math.ceil(automatedItems.length / 3)) : 0,
            gaps: pageFiles.length > 0 && !hasAcceptance ? ["无验收项覆盖页面变更"] : [],
        },
        flow_coverage: {
            total: apiFiles.length + pageFiles.length > 0 ? 1 : 0,
            tested: 0,
            gaps: apiFiles.length + pageFiles.length > 0 ? ["需端到端业务流验证"] : [],
        },
    };
}
/**
 * 解析构建命令，按优先级: 显式配置 > 启发式检测（pom.xml / build.gradle / package.json）。
 * @param config - 项目配置
 * @param repoName - 仓库名称
 * @param projectPath - 项目根路径
 * @returns 构建命令对象，无法确定时返回 null
 */
function resolveBuildCommand(config, repoName, projectPath) {
    // 优先级 1: 显式配置
    const repoConfig = config.repos.find((r) => r.name === repoName);
    const buildCommands = config.build_commands[repoName];
    if (buildCommands?.build) {
        const cwd = repoConfig
            ? path.resolve(projectPath, repoConfig.path)
            : projectPath;
        return {
            command: buildCommands.build,
            cwd,
            timeout_hint: config.verify_timeout?.build ?? 120,
            description: `${repoName} 编译检查`,
        };
    }
    // 优先级 2: 启发式检测
    const repoPath = repoConfig
        ? path.resolve(projectPath, repoConfig.path)
        : projectPath;
    if (fs.existsSync(path.join(repoPath, "pom.xml"))) {
        return { command: "mvn compile -q", cwd: repoPath, timeout_hint: 120, description: "Maven 编译检查" };
    }
    if (fs.existsSync(path.join(repoPath, "build.gradle")) || fs.existsSync(path.join(repoPath, "build.gradle.kts"))) {
        return { command: "./gradlew compileJava", cwd: repoPath, timeout_hint: 120, description: "Gradle 编译检查" };
    }
    if (fs.existsSync(path.join(repoPath, "package.json"))) {
        return { command: "npm run build", cwd: repoPath, timeout_hint: 120, description: "npm 编译检查" };
    }
    // 优先级 3: 无法确定
    return null;
}
/**
 * 解析测试命令，逻辑与 resolveBuildCommand 相同但返回测试命令。
 * @param config - 项目配置
 * @param repoName - 仓库名称
 * @param projectPath - 项目根路径
 * @returns 测试命令对象，无法确定时返回 null
 */
function resolveTestCommand(config, repoName, projectPath) {
    const repoConfig = config.repos.find((r) => r.name === repoName);
    const buildCommands = config.build_commands[repoName];
    if (buildCommands?.test) {
        const cwd = repoConfig
            ? path.resolve(projectPath, repoConfig.path)
            : projectPath;
        return {
            command: buildCommands.test,
            cwd,
            timeout_hint: config.verify_timeout?.test ?? 180,
            description: `${repoName} 测试`,
        };
    }
    const repoPath = repoConfig
        ? path.resolve(projectPath, repoConfig.path)
        : projectPath;
    if (fs.existsSync(path.join(repoPath, "pom.xml"))) {
        return { command: "mvn test", cwd: repoPath, timeout_hint: 180, description: "Maven 测试" };
    }
    if (fs.existsSync(path.join(repoPath, "build.gradle")) || fs.existsSync(path.join(repoPath, "build.gradle.kts"))) {
        return { command: "./gradlew test", cwd: repoPath, timeout_hint: 180, description: "Gradle 测试" };
    }
    if (fs.existsSync(path.join(repoPath, "package.json"))) {
        return { command: "npm test", cwd: repoPath, timeout_hint: 180, description: "npm 测试" };
    }
    return null;
}
/**
 * 检测变更文件涉及的仓库，基于文件路径与仓库 scope 的前缀匹配。
 * 无匹配且非文档变更时，尝试从项目根目录启发式检测。
 * @param changedFiles - 变更文件路径列表
 * @param config - 项目配置，包含仓库定义
 * @returns 受影响的仓库名称数组（文档变更可能返回空数组）
 */
function detectAffectedRepos(changedFiles, config) {
    const repos = new Set();
    for (const file of changedFiles) {
        for (const repo of config.repos) {
            const normalizedFile = file.replace(/\\/g, "/");
            const normalizedRepoPath = repo.path.replace(/\\/g, "/").replace(/^\.\//, "");
            if (normalizedFile.startsWith(normalizedRepoPath + "/") || normalizedFile === normalizedRepoPath) {
                repos.add(repo.name);
            }
        }
    }
    // 不再盲切到第一个 repo — 留给 generateVerifyCommands 的文档检测和根目录启发式兜底
    return [...repos];
}
/** 真正的文档扩展名（配置文件不算文档） */
const DOC_EXTENSIONS = /\.(md|txt|rst|adoc)$/i;
/** 判断变更文件是否全部为文档类型（不含配置文件） */
function isDocumentationOnly(changedFiles) {
    if (changedFiles.length === 0)
        return false;
    return changedFiles.every((f) => DOC_EXTENSIONS.test(f));
}
/** 从项目根目录启发式检测构建命令（不依赖 repo 配置） */
function resolveBuildCommandFromRoot(projectPath) {
    if (fs.existsSync(path.join(projectPath, "package.json"))) {
        return { command: "npm run build", cwd: projectPath, timeout_hint: 120, description: "npm 编译检查" };
    }
    if (fs.existsSync(path.join(projectPath, "pom.xml"))) {
        return { command: "mvn compile -q", cwd: projectPath, timeout_hint: 120, description: "Maven 编译检查" };
    }
    return null;
}
/** 文档变更的验证命令：有 package.json 用 lint，否则用 git diff --check */
function resolveDocVerifyCommand(projectPath) {
    if (fs.existsSync(path.join(projectPath, "package.json"))) {
        return {
            command: "npm run lint --if-present",
            cwd: projectPath,
            timeout_hint: 60,
            description: "文档变更 lint 检查",
        };
    }
    return {
        command: "git diff --check",
        cwd: projectPath,
        timeout_hint: 30,
        description: "文档变更格式检查",
    };
}
/** 从项目根目录启发式检测测试命令 */
function resolveTestCommandFromRoot(projectPath) {
    if (fs.existsSync(path.join(projectPath, "package.json"))) {
        return { command: "npm test", cwd: projectPath, timeout_hint: 180, description: "npm 测试" };
    }
    if (fs.existsSync(path.join(projectPath, "pom.xml"))) {
        return { command: "mvn test", cwd: projectPath, timeout_hint: 180, description: "Maven 测试" };
    }
    return null;
}
//# sourceMappingURL=verifier.js.map