/** * V2 Bridge — V2 控制面的懒加载单例工厂。 * * 当环境变量 KCODE_GATE_RUNNER_V2=1 时,运行时入口(tool events、goal-loop) * 通过本模块获取 GateRunner、WritePipeline 等 V2 控制面实例。 * * 设计要点: * - 懒加载:首次调用时才动态 import 并初始化,避免未启用时的性能开销。 * - 单例:全局唯一实例,通过 Promise 防止并发初始化导致的重复创建。 * - 桥接模式:内部注册一个 meta-policy,将策略评估委托给 PolicyRegistry, * 使 GateRunner 不需要直接感知各个独立策略模块。 * * @see migration-switch.ts — GATE_RUNNER_V2_ENABLED 全局开关 * @see gate-runner.ts — GateRunner 门禁执行器 * @see write-pipeline.ts — WritePipeline 写入管道 */ import { GATE_RUNNER_V2_ENABLED } from "./migration-switch.ts"; import type { ActiveRun } from "../types.ts"; import type { GateContext, GateDecision, GateFinding } from "../gates/findings.ts"; import type { GateCheckpoint } from "../gates/taxonomy.ts"; import type { GateRunner } from "../gates/gate-runner.ts"; import type { WritePipeline } from "../tools/write-pipeline.ts"; // ── 懒加载单例 ───────────────────────────────────────────────────────────── // 使用 _instance + _promise 双变量模式: // - _instance 缓存已初始化的实例(快速路径) // - _promise 防止并发调用时重复初始化(慢速路径首次) let _gateRunner: GateRunner | undefined; let _gateRunnerPromise: Promise | undefined; /** * 获取或创建 GateRunner 单例。 * * 首次调用时动态导入 gate-runner.ts 和 policy-registry.ts, * 创建 GateRunner 并注册由 PolicyRegistry 桥接的 meta-policy。 * 后续调用直接返回缓存实例。 */ export async function getGateRunner(): Promise { if (_gateRunner) return _gateRunner; if (!_gateRunnerPromise) { _gateRunnerPromise = _initGateRunner(); } return _gateRunnerPromise; } async function _initGateRunner(): Promise { // 并行动态导入,减少初始化延迟 const [{ GateRunner: GR }, { createDefaultPolicyRegistry }] = await Promise.all([ import("../gates/gate-runner.ts"), import("../gates/policy-registry.ts"), ]); const runner = new GR(); // 创建包含全部 8 个 P0 策略的默认注册表 const registry = createDefaultPolicyRegistry(); // 桥接模式:注册一个 meta-policy,将所有策略评估委托给 PolicyRegistry。 // PolicyRegistry.evaluate() 内部已完成 checkpoint 过滤、severity 排序和去重, // 因此 GateRunner 收到的是预处理后的 findings。 runner.registerPolicy("v2-registry-bridge", (ctx: GateContext): GateFinding[] => { return registry.evaluate(ctx.checkpoint, ctx); }); _gateRunner = runner; return runner; } /** * 通过 V2 GateRunner 执行门禁检查。 * * 若 V2 未启用(GATE_RUNNER_V2_ENABLED=false),返回 null, * 调用方应回退到旧版门禁路径。 * * @param checkpoint - 门禁检查点(如 pre-tool、pre-write、pre-phase-transition) * @param cwd - 工作目录 * @param run - 当前活跃运行实例(可选,用于 ledger 关联) * @param opts - 可选上下文(工具名、文件路径、命令、负载) * @returns 门禁决策,V2 未启用时返回 null */ export async function runGateV2( checkpoint: GateCheckpoint, cwd: string, run: ActiveRun | undefined, opts?: { toolName?: string; path?: string; command?: string; payload?: unknown }, ): Promise { // V2 未启用时短路返回,调用方走旧路径 if (!GATE_RUNNER_V2_ENABLED) return null; const runner = await getGateRunner(); const ctx: GateContext = { cwd, checkpoint, run, toolName: opts?.toolName, path: opts?.path, command: opts?.command, payload: opts?.payload, }; return runner.runGate(ctx); } /** 检查 V2 控制面是否激活。 */ export function isV2Enabled(): boolean { return GATE_RUNNER_V2_ENABLED; } // ── 懒加载 WritePipeline ─────────────────────────────────────────────────── // 同样使用 _instance + _promise 双变量模式防止并发初始化 let _writePipeline: WritePipeline | undefined; let _writePipelinePromise: Promise | undefined; /** * 获取或创建 WritePipeline 单例。 * * WritePipeline 依赖 GateRunner 和 source-anchors 模块, * 首次调用时并行加载所有依赖并注入。 */ export async function getV2WritePipeline(): Promise { if (_writePipeline) return _writePipeline; if (!_writePipelinePromise) { _writePipelinePromise = _initWritePipeline(); } return _writePipelinePromise; } async function _initWritePipeline(): Promise { // 并行加载 GateRunner、WritePipeline 类和 source-anchors 验证函数 const [runner, { WritePipeline: WP }, { latestSourceAnchorForPath, validateSourceAnchorSnapshot }] = await Promise.all([ getGateRunner(), import("../tools/write-pipeline.ts"), import("../source-anchors.ts"), ]); // 注入 GateRunner 和锚点验证器,WritePipeline 通过依赖注入保持与具体实现的解耦 const wp = new WP(runner, { latestSourceAnchorForPath, validateSourceAnchorSnapshot }); _writePipeline = wp; return wp; }