import crypto from "node:crypto";
import fss from "node:fs";
import path from "node:path";
import { resolveProjectConfig } from "../../knowledge/loader.js";
import { debug, userInfo, userError, internalWarn } from "../../engine/core/logger.js";
import { getArgValue, args } from "../args.js";
import { errorMessage, safeJsonParse } from "../../engine/core/helpers.js";
export async function cmdSyncTemplates() {
    debug("CLI", "执行 cmdSyncTemplates");
    const apply = args.includes("--apply");
    const confirm = args.includes("--confirm");
    const isJson = args.includes("--json");
    const { executeSync, validateSyncSafety, computeTemplateAssetVersions } = await import("../../engine/templates/template_sync.js");
    const { validateWorkflowTemplatePack, createWorkflowTemplatePackContract, createWorkflowTemplateEntry, createTemplateConsumptionEvidence, } = await import("../../engine/contracts/workflow_template_pack.js");
    const { buildTemplateManifestFromSource, loadProjectManifest, saveProjectManifest, writeFileSyncRecursive, hashFile, } = await import("../../engine/templates/template_manifest_io.js");
    const projectPath = process.cwd();
    const packageRoot = path.resolve(import.meta.dirname, "..", "..", "..");
    const sourceDir = args.find((a) => a.startsWith("--source="))?.slice("--source=".length) ?? path.join(packageRoot, "templates");
    if (apply) {
        const { classifyConfigContext, validateWriteBoundary } = await import("../../engine/config/config_write_boundary.js");
        const writeContext = classifyConfigContext(projectPath, { confirmed: confirm });
        const violations = validateWriteBoundary(writeContext, [
            path.join(projectPath, ".soloforge", "template-manifest.json"),
            path.join(projectPath, ".soloforge", "knowledge"),
        ]);
        if (violations.length > 0) {
            for (const v of violations)
                userError(`❌ 模板同步写入边界阻断: ${v.target_path} — ${v.reason_zh}`);
            process.exit(1);
        }
    }
    // 读取当前包版本
    let packageVersion = "0.0.0";
    try {
        const pkgJson = safeJsonParse(fss.readFileSync(path.join(packageRoot, "package.json"), "utf-8"));
        if (pkgJson)
            packageVersion = pkgJson.version;
    }
    catch { /* 回退 */ }
    // 构建源清单（真实模板文件）
    const sourceManifest = buildTemplateManifestFromSource(sourceDir, packageVersion);
    // 加载已安装清单
    const installedManifest = loadProjectManifest(projectPath) ?? [];
    // 计算哈希（Map key 用相对路径，与 computeTemplateAssetVersions 查找键一致）
    const sourceHashes = new Map();
    for (const e of sourceManifest) {
        const h = hashFile(path.join(packageRoot, e.source_path));
        if (h !== null)
            sourceHashes.set(e.source_path, h);
    }
    const baseManifest = installedManifest.length > 0 ? installedManifest : sourceManifest;
    const currentHashes = new Map();
    for (const e of baseManifest) {
        const h = hashFile(path.join(projectPath, e.target_path));
        if (h !== null)
            currentHashes.set(e.target_path, h);
    }
    // 计算差异（首次安装用 sourceManifest 作为基准，全部为 missing）
    const assets = computeTemplateAssetVersions(baseManifest, currentHashes, sourceHashes);
    // problem-53: 工作流模板包完整性校验 — 用真实 manifest 数据构建 pack
    const wfPackEntries = sourceManifest
        .filter(e => e.asset_kind === "workflow_template")
        .map(e => createWorkflowTemplateEntry("architecture_design", e.target_path));
    const wfConsumptionEvidences = assets
        .filter(a => wfPackEntries.some(w => w.template_path === a.target_path))
        .map(a => createTemplateConsumptionEvidence(a.target_path));
    if (wfPackEntries.length > 0) {
        const wfPack = createWorkflowTemplatePackContract({
            workflows: wfPackEntries,
            mechanism_consumption_map: sourceManifest
                .filter(e => e.asset_kind === "workflow_template")
                .map(e => ({ template_path: e.target_path, consumed_mechanism_id: `mc-${e.asset_id}`, consumption_type: "route_trigger", evidence_required: true })),
        });
        const wfResult = validateWorkflowTemplatePack(wfPack, wfConsumptionEvidences);
        if (!wfResult.valid && !isJson) {
            userInfo(`  ⚠ 工作流模板包校验: ${wfResult.violations.length} 个违规`);
            for (const v of wfResult.violations)
                userInfo(`    - ${v}`);
        }
        if (!wfResult.valid && apply) {
            // 校验失败阻断 apply
            internalWarn("CLI", `工作流模板包校验失败，apply 已阻断。违规: ${wfResult.violations.join("; ")}`);
            process.exit(1);
        }
    }
    const safeCheck = validateSyncSafety(assets);
    try {
        const { runKnowledgeGovernanceCheck } = await import("../../engine/knowledge/knowledge_governance_gate.js");
        const kgReport = runKnowledgeGovernanceCheck({
            project_language: "zh",
            contents: sourceManifest.slice(0, 12).map((e) => ({ id: e.asset_id, domain: "governance_contracts", content: e.target_path })),
        });
        if (kgReport.hard_fail_count > 0 && apply) {
            userError(`❌ 知识治理阻断模板同步: ${kgReport.hard_fail_count} hard_fail`);
            process.exit(1);
        }
    }
    catch (e) {
        if (!isJson)
            userInfo(`  ⚠ 知识治理同步检查异常: ${errorMessage(e)}`);
    }
    const syncResult = executeSync({ dry_run: !apply, apply, confirm, project_path: projectPath, source_path: sourceDir }, assets, sourceManifest);
    // apply 模式：真实文件复制
    if (apply && confirm && syncResult.success && syncResult.backup_path) {
        const backupDir = syncResult.backup_path;
        fss.mkdirSync(backupDir, { recursive: true });
        const assetMap = new Map(assets.map((a) => [a.asset_id, a]));
        const updatedManifest = [...sourceManifest];
        for (const assetId of [...syncResult.report.added, ...syncResult.report.updated]) {
            const asset = assetMap.get(assetId);
            if (!asset)
                continue;
            const srcAbs = path.join(packageRoot, asset.source_path);
            const tgtAbs = path.join(projectPath, asset.target_path);
            // 备份已有文件
            if (fss.existsSync(tgtAbs)) {
                const backupFile = path.join(backupDir, path.basename(tgtAbs));
                fss.copyFileSync(tgtAbs, backupFile);
            }
            // 复制源文件到目标
            writeFileSyncRecursive(tgtAbs, fss.readFileSync(srcAbs));
            // 更新清单中的 installed_hash
            const idx = updatedManifest.findIndex((e) => e.asset_id === assetId);
            if (idx >= 0) {
                updatedManifest[idx] = {
                    ...updatedManifest[idx],
                    installed_hash: asset.source_hash,
                    installed_at: new Date().toISOString(),
                };
            }
        }
        // 持久化清单
        saveProjectManifest(projectPath, updatedManifest);
        // [ENG-8] 模板同步后清除合同缓存，确保下次注入使用最新合同
        try {
            const { clearInjectionContractCache } = await import("../../engine/knowledge/knowledge_injection_boundary.js");
            clearInjectionContractCache();
        }
        catch { /* best effort — 模块可能未加载 */ }
    }
    if (isJson) {
        userInfo(JSON.stringify({
            command: "sync-templates",
            mode: apply ? "apply" : "dry_run",
            total_assets: assets.length,
            safe: safeCheck.safe,
            result: syncResult.success,
            dry_run: syncResult.dry_run,
            report: syncResult.report,
        }, null, 2));
    }
    else {
        userInfo(apply ? "模板同步: apply 模式" : "模板同步: dry-run 模式（不写入文件）");
        userInfo(`  资产总数: ${assets.length}`);
        userInfo(`  应用安全: ${safeCheck.safe ? "安全" : "需确认"}`);
        userInfo(`  结果: ${syncResult.success ? "成功" : "失败"}`);
        userInfo(`  新增: ${syncResult.report.added.length}`);
        userInfo(`  更新: ${syncResult.report.updated.length}`);
        userInfo(`  跳过(用户修改): ${syncResult.report.skipped_user_modified.length}`);
        userInfo(`  废弃: ${syncResult.report.deprecated.length}`);
        if (!apply)
            userInfo("  使用 --apply --confirm 应用同步；需确认表示 dry-run 发现现有用户资产，不会自动覆盖");
    }
    if (!syncResult.success)
        process.exit(1);
}
export async function cmdSyncAdapters() {
    debug("CLI", "执行 cmdSyncAdapters");
    const apply = args.includes("--apply");
    const confirm = args.includes("--confirm");
    const isJson = args.includes("--json");
    const { syncAdapterPrompts, REQUIRED_ADAPTER_SECTIONS, } = await import("../../engine/adapter_prompt_contract.js");
    const { writeFileSyncRecursive, sha256Hex, hashFile, } = await import("../../engine/templates/template_manifest_io.js");
    const projectPath = process.cwd();
    // 加载项目配置（回退到默认）
    let config;
    try {
        const resolved = await resolveProjectConfig(projectPath);
        config = resolved.config;
    }
    catch {
        config = {
            name: "default", tech_stack: { backend: { lang: "", framework: "", version: "" }, frontend: { lang: "", framework: "", version: "" } },
            product_profile: "general", repos: [], build_commands: { backend: { build: "", test: "", full: "" }, frontend: { build: "", test: "", full: "" } }, scope: { backend: [], frontend: [] },
        };
    }
    // 适配器生成器
    const { generateClaudeMd } = await import("../../adapters/claude_code/claude_md.js");
    const { generateCodexAgentsMd } = await import("../../adapters/codex/codex_rules.js");
    const { generateTraeRules } = await import("../../adapters/trae/trae_rules.js");
    const sections = [...REQUIRED_ADAPTER_SECTIONS];
    // 适配器 installed hash 记录文件
    const ADAPTER_HASH_FILE = ".soloforge/adapter_hashes.json";
    // 加载已安装的适配器 hash 记录
    let installedAdapterHashes = {};
    try {
        const hashContent = fss.readFileSync(path.join(projectPath, ADAPTER_HASH_FILE), "utf-8");
        installedAdapterHashes = safeJsonParse(hashContent) ?? {};
    }
    catch { /* 首次无记录 */ }
    const adapterContracts = [
        {
            adapter_id: "claude-code", host_type: "claude_code",
            prompt_path: "CLAUDE.md",
            generated_from_contract_version: "1",
            required_sections: sections,
            forbidden_claims: [],
            sync_required: true,
            next_allowed_tools: ["sf_classify", "sf_expand", "sf_verify", "sf_learn", "sf_deliver", "sf_review"],
        },
        {
            adapter_id: "codex", host_type: "codex",
            prompt_path: "AGENTS.md",
            generated_from_contract_version: "1",
            required_sections: sections,
            forbidden_claims: [],
            sync_required: true,
            next_allowed_tools: ["sf_classify", "sf_expand", "sf_verify", "sf_learn"],
        },
        {
            adapter_id: "trae", host_type: "trae",
            prompt_path: ".trae/rules/project_rules.md",
            generated_from_contract_version: "1",
            required_sections: sections,
            forbidden_claims: [],
            sync_required: true,
            next_allowed_tools: ["sf_classify", "sf_expand", "sf_verify", "sf_learn"],
        },
    ];
    // 验证所有适配器
    const validations = syncAdapterPrompts(adapterContracts, { dry_run: !apply, apply, confirm });
    // 适配器内容生成
    const generators = {
        "claude-code": () => generateClaudeMd(config),
        "codex": () => generateCodexAgentsMd(config),
        "trae": () => generateTraeRules(config),
    };
    // apply 模式：写入合规的适配器文件
    const writtenFiles = [];
    const skippedFiles = [];
    if (apply && confirm) {
        const updatedHashes = { ...installedAdapterHashes };
        for (const contract of adapterContracts) {
            const validation = validations.find((v) => v.adapter_id === contract.adapter_id);
            if (!validation?.compliant) {
                skippedFiles.push(`${contract.adapter_id}: 不合规，跳过`);
                continue;
            }
            const targetPath = path.join(projectPath, contract.prompt_path);
            const generator = generators[contract.adapter_id];
            if (!generator)
                continue;
            const content = generator();
            const generatedHash = sha256Hex(content);
            // 用户修改检测：文件存在且 hash 与已安装 hash 不一致
            if (fss.existsSync(targetPath)) {
                const diskHash = hashFile(targetPath);
                const installedHash = installedAdapterHashes[contract.adapter_id];
                if (diskHash && installedHash && diskHash !== installedHash) {
                    // 文件被用户修改，不得覆盖
                    skippedFiles.push(`${contract.adapter_id}: 用户已修改，跳过`);
                    continue;
                }
            }
            // 首次安装或内容有变化：写入
            writeFileSyncRecursive(targetPath, content);
            writtenFiles.push(contract.prompt_path);
            updatedHashes[contract.adapter_id] = generatedHash;
        }
        // 持久化 hash 记录
        writeFileSyncRecursive(path.join(projectPath, ADAPTER_HASH_FILE), JSON.stringify(updatedHashes, null, 2));
    }
    if (isJson) {
        userInfo(JSON.stringify({
            command: "sync-adapters",
            mode: apply ? "apply" : "dry_run",
            adapter_count: adapterContracts.length,
            validations,
            written: writtenFiles,
            skipped: skippedFiles,
        }, null, 2));
    }
    else {
        userInfo(apply ? "适配器同步: apply 模式" : "适配器同步: dry-run 模式（不写入文件）");
        userInfo(`  适配器数量: ${adapterContracts.length}`);
        for (const v of validations) {
            const icon = v.compliant ? "✓" : "✗";
            userInfo(`  ${icon} ${v.adapter_id}: ${v.compliant ? "合规" : "不合规"}`);
            for (const f of v.findings) {
                if (f.severity !== "info")
                    userInfo(`    ${f.severity === "critical" ? "✗" : "⚠"} ${f.message_zh}`);
            }
        }
        if (writtenFiles.length > 0) {
            userInfo(`  已写入: ${writtenFiles.join(", ")}`);
        }
        if (skippedFiles.length > 0) {
            userInfo(`  已跳过: ${skippedFiles.join("; ")}`);
        }
        if (!apply)
            userInfo("  使用 --apply --confirm 应用同步");
    }
}
export async function cmdMigrate() {
    debug("CLI", "执行 cmdMigrate");
    const apply = args.includes("--apply");
    const confirm = args.includes("--confirm");
    const isJson = args.includes("--json");
    const { createMigrationPlan, getCurrentCompatibility, validateMigrationSafety, generateVersionFile } = await import("../../engine/knowledge/release_compatibility.js");
    const { loadProjectVersion, saveProjectVersion } = await import("../../engine/templates/template_manifest_io.js");
    const projectPath = process.cwd();
    const compat = getCurrentCompatibility();
    const toVersion = compat.package_version;
    // 读取项目已安装版本，不存在视为首次
    const installed = loadProjectVersion(projectPath);
    const fromVersion = installed?.soloforge_package_version ?? "0.0.0";
    // 版本相同，无需迁移
    if (fromVersion === toVersion) {
        if (isJson) {
            userInfo(JSON.stringify({
                command: "migrate",
                mode: "noop",
                success: true,
                dry_run: !apply,
                safe: true,
                message: `已是最新版本 ${toVersion}`,
                from_version: fromVersion,
                to_version: toVersion,
            }, null, 2));
        }
        else {
            userInfo(`项目迁移: 已是最新版本 ${toVersion}`);
            userInfo(`  当前版本: ${fromVersion}`);
        }
        return;
    }
    // 先生成真实迁移计划
    const plan = createMigrationPlan({ dry_run: !apply, apply, confirm, project_path: projectPath, from_version: fromVersion, to_version: toVersion }, compat);
    // 基于真实 plan 做安全检查
    const safetyCheck = validateMigrationSafety(plan.plan, apply, !!confirm);
    // apply --confirm 模式且安全通过时：创建备份 + 写入 version.json
    if (apply && confirm && plan.success && safetyCheck.safe && plan.backup_path) {
        const backupDir = path.join(projectPath, plan.backup_path);
        fss.mkdirSync(backupDir, { recursive: true });
        // 备份已有 version.json
        const versionPath = path.join(projectPath, ".soloforge/version.json");
        if (fss.existsSync(versionPath)) {
            fss.copyFileSync(versionPath, path.join(backupDir, "version.json"));
        }
        // 写入新版本文件
        const versionContent = generateVersionFile(toVersion, compat.contract_registry_version);
        // 合并 created_at（首次用新时间，升级保留原时间）
        if (installed?.created_at) {
            versionContent.created_at = installed.created_at;
        }
        saveProjectVersion(projectPath, versionContent);
    }
    const success = plan.success && safetyCheck.safe;
    if (isJson) {
        userInfo(JSON.stringify({
            command: "migrate",
            mode: apply ? "apply" : "dry_run",
            success,
            dry_run: plan.dry_run,
            safe: safetyCheck.safe,
            from_version: fromVersion,
            to_version: toVersion,
            plan: plan.plan,
            backup_path: plan.backup_path,
        }, null, 2));
    }
    else {
        userInfo(apply ? "项目迁移: apply 模式" : "项目迁移: dry-run 模式（不写入文件）");
        userInfo(`  结果: ${success ? "成功" : "失败"}`);
        userInfo(`  从版本: ${fromVersion}`);
        userInfo(`  到版本: ${toVersion}`);
        userInfo(`  安全检查: ${safetyCheck.safe ? "✓" : "✗"}`);
        userInfo(`  需迁移: ${plan.plan.required_migrations.length}`);
        userInfo(`  自动应用: ${plan.plan.auto_applicable.length}`);
        userInfo(`  需人工: ${plan.plan.requires_human.length}`);
        if (!apply)
            userInfo("  使用 --apply --confirm 执行迁移");
    }
    if (!success)
        process.exit(1);
}
export async function cmdValidateReleaseGate() {
    const isJson = args.includes("--json");
    debug("CLI", "执行 cmdValidateReleaseGate");
    const { runReleaseReadinessGate } = await import("../../engine/release/release_readiness_gate.js");
    const result = await runReleaseReadinessGate(process.cwd());
    if (isJson) {
        userInfo(JSON.stringify({
            passed: result.passed,
            hard_fail_count: result.hard_fail_count,
            hard_fails: result.hard_fails,
            phases: result.phases,
        }, null, 2));
    }
    else {
        userInfo("══════════════════════════════════════════════════════════════");
        userInfo(`发布结论: ${result.passed ? "PASS" : "FAIL"}`);
        userInfo(`hard_fail 数量: ${result.hard_fail_count}`);
        userInfo("══════════════════════════════════════════════════════════════");
        userInfo();
        for (const p of result.phases) {
            userInfo(`  ${p.hard_fail_count === 0 ? "[PASS]" : "[FAIL]"} ${p.name} — ${p.hard_fail_count} hard_fail`);
        }
        if (result.hard_fails.length > 0) {
            userInfo();
            userInfo("━━━ hard_fail 明细 ━━━");
            for (let i = 0; i < result.hard_fails.length; i++) {
                const hf = result.hard_fails[i];
                userInfo(`[${i + 1}] ${hf.code}: ${hf.message}`);
                userInfo(`    涉及: ${hf.files.join(", ")}`);
                userInfo(`    下一步: ${hf.nextStep}`);
            }
        }
    }
    if (!result.passed) {
        // 让 stdout 刷盘后再退出，避免 process.exit() 截断大型 JSON 输出
        await new Promise((resolve) => process.stdout.write("", () => resolve()));
        process.exit(1);
    }
}
export async function cmdValidateFoundation() {
    debug("CLI", "执行 cmdValidateFoundation");
    const { validateMechanismLayerMaps, listMechanismLayerMaps } = await import("../../engine/contracts/dual_layer_mechanism_registry.js");
    const { auditTemplateMechanisms } = await import("../../engine/templates/template_mechanism_auditor.js");
    const { validateFoundationScenarios } = await import("../../engine/release/foundation_scenario_registry.js");
    const cwd = process.cwd();
    const maps = listMechanismLayerMaps();
    const mechFindings = validateMechanismLayerMaps(maps, cwd);
    const mechanismsPass = mechFindings.filter((f) => f.severity === "hard_fail").length === 0;
    const auditReport = auditTemplateMechanisms(cwd);
    const auditPass = auditReport.hard_fail_count === 0;
    const scenarioResults = await validateFoundationScenarios(mechanismsPass, auditPass, true);
    const allPass = scenarioResults.every((s) => s.status === "PASS");
    const isJson = process.argv.includes("--json");
    if (isJson) {
        userInfo(JSON.stringify({
            mechanisms_pass: mechanismsPass,
            audit_pass: auditPass,
            all_pass: allPass,
            scenarios: scenarioResults,
        }, null, 2));
    }
    else {
        for (const s of scenarioResults) {
            const icon = s.status === "PASS" ? "✓" : "✗";
            userInfo(`${icon} ${s.scenario_id}: ${s.scenario_name} — ${s.status}`);
            for (const r of s.rules) {
                const ri = r.status === "PASS" ? "  ✓" : "  ✗";
                userInfo(`${ri} ${r.rule}: ${r.evidence}`);
            }
        }
        userInfo(allPass ? "\n所有场景通过" : "\n部分场景失败");
    }
    process.exit(allPass ? 0 : 1);
}
/**
 * 新增问题/issue 演进门控 — problem-54 真实消费入口。
 * 用法: soloforge validate-new-issue --title="问题标题" --batch=2 [--json]
 */
export async function cmdValidateNewIssue() {
    debug("CLI", "执行 cmdValidateNewIssue");
    const title = getArgValue("--title") ?? "";
    const isJson = args.includes("--json");
    if (!title) {
        userError("❌ 错误: --title 必须提供");
        process.exit(1);
    }
    const { performEvolutionGate, createNewIssueRegressionGate, } = await import("../../engine/contracts/evolution_regression_gate.js");
    // 稳定 slug: 基于标题哈希而非 Date.now
    const titleSlug = title
        .toLowerCase()
        .replace(/[^a-z0-9一-鿿]+/g, "-")
        .replace(/^-|-$/g, "")
        .slice(0, 40);
    const hashSuffix = crypto.createHash("sha256").update(title).digest("hex").slice(0, 8);
    const candidateId = `issue-${titleSlug}-${hashSuffix}`;
    const gate = createNewIssueRegressionGate({
        issue_candidate_id: candidateId,
        candidate_title: title,
    });
    // 演进门控
    const result = performEvolutionGate(gate);
    const output = {
        title,
        candidate_id: candidateId,
        duplicate_detected: gate.duplicate_check.possible_duplicates.length > 0,
        duplicates: [...new Set(gate.duplicate_check.possible_duplicates)],
        gate_status: result.gate_status,
        can_proceed: result.allowed,
        reasons: result.reasons,
    };
    if (isJson) {
        userInfo(JSON.stringify(output, null, 2));
    }
    else {
        userInfo(`需求演进检查: ${output.gate_status}`);
        if (output.duplicate_detected) {
            userInfo(`  ⚠ 重复检测: 发现 ${output.duplicates.join(", ")}`);
        }
        if (result.reasons.length > 0) {
            userInfo(`  原因:`);
            for (const r of result.reasons)
                userInfo(`    - ${r}`);
        }
        if (output.can_proceed) {
            userInfo(`  ✓ 可继续: 需求新增已通过演进检查 (ID: ${candidateId})`);
        }
    }
    if (!result.allowed)
        process.exit(1);
}
//# sourceMappingURL=sync.js.map