/**
 * 发布问题真实 MCP 工具测试装置。
 *
 * callTool() 每次实际调用已注册 handler 时，记录不可由场景手填的 ToolInvocationObservation。
 * collectTrace() 必须从 ToolInvocationObservation 生成 tool_entrypoint 和 diagnostic_codes。
 */
import fs from "node:fs";
import path from "node:path";
import os from "node:os";
import { debug } from "../core/logger.js";
import { errorMessage, safeJsonParse } from "../core/helpers.js";
const handlers = new Map();
function createFakeMcpServer() {
    handlers.clear();
    return {
        tool(name, _desc, _schema, handler) {
            handlers.set(name, handler);
        },
    };
}
/**
 * 创建真实 MCP 工具测试装置。
 *
 * 每个 scenario runner 调用此函数获得独立的临时项目 + 工具注册环境，
 * 通过 callTool("需求分析", ...) 调用与生产一致的注册工具。
 * 每次 callTool 自动记录 ToolInvocationObservation。
 */
export async function createToolHarness(options = {}) {
    const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "soloforge-b6-harness-"));
    const stateDir = path.join(tmpDir, ".soloforge", "state");
    fs.mkdirSync(stateDir, { recursive: true });
    // 可选复制知识库
    if (options.copyKnowledge) {
        const { copyKnowledgeToProject } = await import("../templates/template_init_sync.js");
        await copyKnowledgeToProject(process.cwd(), tmpDir);
    }
    // 清空 consumption traces
    const { clearConsumptionTraces } = await import("../templates/consumption_trace_store.js");
    clearConsumptionTraces();
    // 清空注入合同缓存
    const { clearInjectionContractCache } = await import("../knowledge/knowledge_injection_boundary.js");
    clearInjectionContractCache();
    const config = {
        name: "release-issue-test",
        tech_stack: {
            backend: options.techStack?.backend ?? { lang: "typescript", framework: "node", version: "20" },
            frontend: options.techStack?.frontend ?? { lang: "typescript", framework: "react", version: "18" },
        },
        product_profile: options.productProfile ?? "saas",
        repos: [],
        build_commands: {
            backend: { build: "npm run build", test: "npm test", full: "npm run ci" },
            frontend: { build: "npm run build", test: "npm test", full: "npm run ci" },
        },
        scope: { backend: ["src/"], frontend: ["src/"] },
        _projectPath: tmpDir,
    };
    const { TaskContextManager: TCM } = await import("../pipeline/task_context.js");
    const taskContext = new TCM(stateDir);
    const { KnowledgeIndexManager: KIM } = await import("../../knowledge/index_manager.js");
    const knowledgeIndex = new KIM(config, { watch: false });
    await knowledgeIndex.build();
    // 注册真实 MCP 工具
    const { registerTools } = await import("../../server/tools/index.js");
    const server = createFakeMcpServer();
    await registerTools(server, { config, knowledgeIndex, taskContext });
    // 不可手填的观察记录
    const observations = [];
    // callTool: 记录完整观察
    const callTool = async (name, args) => {
        const handler = handlers.get(name);
        if (!handler)
            throw new Error(`Tool ${name} not registered`);
        // 调用前状态
        let beforeStatus;
        const tid = typeof args?.task_id === "string" ? args.task_id : undefined;
        if (tid) {
            try {
                const ctx = await taskContext.load(tid);
                beforeStatus = ctx?.status;
            }
            catch { /* 任务可能不存在 */ }
        }
        const timestamp = new Date().toISOString();
        let isErr = false;
        let rawResult;
        try {
            rawResult = await handler(args);
            isErr = rawResult?.isError === true;
        }
        catch (e) {
            isErr = true;
            const _msg = errorMessage(e);
            rawResult = { content: [{ type: "text", text: JSON.stringify({ error: _msg }) }], isError: true };
        }
        // 解析响应
        const parsed = parseResultFn(rawResult);
        const diagCode = typeof parsed === "object" && parsed !== null && "diagnostic_code" in parsed
            ? parsed.diagnostic_code
            : undefined;
        const diagCodeOrError = diagCode ?? (typeof parsed === "object" && parsed !== null && "error" in parsed
            ? String(parsed.error)
            : undefined);
        // 调用后状态
        let afterStatus;
        if (tid) {
            try {
                const ctx = await taskContext.load(tid);
                afterStatus = ctx?.status;
            }
            catch { /* 忽略 */ }
        }
        observations.push({
            tool_name: name,
            request: args,
            parsed_response: parsed,
            is_error: isErr,
            task_id: tid,
            before_status: beforeStatus,
            after_status: afterStatus,
            diagnostic_code: diagCodeOrError,
            timestamp,
        });
        return rawResult;
    };
    const parseResultFn = (raw) => {
        const text = raw?.content?.[0]?.text;
        try {
            return safeJsonParse(text ?? "") ?? text ?? "";
        }
        catch {
            return text ?? "";
        }
    };
    const getObservations = () => observations;
    const getLastObservation = () => observations[observations.length - 1];
    // collectTrace: 从观察记录生成（非手写）
    const collectTrace = async () => {
        const toolNames = observations.map(o => o.tool_name);
        const diagCodes = observations
            .map(o => o.diagnostic_code)
            .filter((c) => typeof c === "string" && c.length > 0);
        const { getConsumptionTraces } = await import("../templates/consumption_trace_store.js");
        const traces = getConsumptionTraces();
        const gatesConsumed = [...new Set(traces.map((t) => t.consumer))];
        return {
            tool_entrypoint: toolNames.join(" → ") || "unknown",
            diagnostic_codes: [...new Set(diagCodes)],
            gates_consumed: gatesConsumed,
        };
    };
    // 显式设置计划提案门禁（场景必须明确调用）
    const setupPlanGate = async (taskId) => {
        await taskContext.setPlanProposalGate(taskId, {
            passed: true, plan_gate_status: "passed", required_level: "execution_plan",
            reason_zh: "release issue scenario 显式设置", violations: [], diagnostic_code: undefined,
            evidence_refs: ["release-issue-test"], blocked_actions: [],
        });
    };
    const cleanup = () => {
        knowledgeIndex.close().catch((e) => { debug("测试装置", "关闭知识索引失败", e); });
        fs.rmSync(tmpDir, { recursive: true, force: true });
    };
    return {
        tmpDir, stateDir, config, taskContext, knowledgeIndex,
        callTool, parseResult: parseResultFn, getObservations, getLastObservation, collectTrace, setupPlanGate, cleanup,
    };
}
//# sourceMappingURL=release_tool_harness.js.map