#!/usr/bin/env node /** * Patch: route-interceptor-bundle.js 硬 require → fail-open * 原因: 旧版部署缺少 scripts/route-engine.js 等文件时, * 硬 require 导致整个 UserPromptSubmit hook 崩溃 (MODULE_NOT_FOUND) * 修复: 包裹 try-catch, 模块缺失时降级为 [BWR:skip] */ 'use strict'; const fs = require('fs'); const path = require('path'); const TARGET = path.join(__dirname, '..', '..', 'hooks', 'route-interceptor-bundle.js'); const SENTINEL = '_routingReady'; if (!fs.existsSync(TARGET)) { console.log('[patch] route-interceptor-bundle.js 不存在, 跳过'); process.exit(0); } let code = fs.readFileSync(TARGET, 'utf8'); if (code.includes(SENTINEL)) { console.log('[patch] 已包含 fail-open 保护, 跳过'); process.exit(0); } // 备份 const bak = TARGET + '.bak.' + Date.now(); fs.writeFileSync(bak, code); const OLD = `const { safeAppendJsonl } = require('./lib/safe-append.js'); const readStdin = require('./lib/read-stdin.js'); // === P3-1 BUNDLE: preload routing deps === // Phase 0 宪法合规拆分: 核心逻辑提取到独立模块 const { runRouteEngine, loadSkillsIndex, safeRequire: _engineRequire } = require('../scripts/route-engine.js'); const { buildBWRDirective, MUST_INVOKE_EXEMPT_INTENTS: _EXEMPT } = require('../scripts/bwr-builder.js'); const { writeRouteState: _writeRouteState } = require('../scripts/route-state.js');`; const NEW = `let safeAppendJsonl; try { ({ safeAppendJsonl } = require('./lib/safe-append.js')); } catch { safeAppendJsonl = () => {}; } let readStdin; try { readStdin = require('./lib/read-stdin.js'); } catch { readStdin = () => Promise.resolve(''); } // === P3-1 BUNDLE: preload routing deps (fail-open: 模块缺失时降级为空路由) === let runRouteEngine, loadSkillsIndex, _engineRequire; let buildBWRDirective, _EXEMPT; let _writeRouteState; let _routingReady = true; try { ({ runRouteEngine, loadSkillsIndex, safeRequire: _engineRequire } = require('../scripts/route-engine.js')); ({ buildBWRDirective, MUST_INVOKE_EXEMPT_INTENTS: _EXEMPT } = require('../scripts/bwr-builder.js')); ({ writeRouteState: _writeRouteState } = require('../scripts/route-state.js')); } catch (e) { _routingReady = false; runRouteEngine = () => ({ skill: null, confidence: 0, candidates: [] }); loadSkillsIndex = () => []; _engineRequire = () => null; buildBWRDirective = () => '[BWR:skip] routing modules unavailable'; _EXEMPT = []; _writeRouteState = () => {}; process.stderr.write('[route-interceptor] WARN: routing modules not found, degraded to skip mode: ' + (e.message || '') + '\\n'); }`; // 规范化换行符再匹配 const codeNorm = code.replace(/\r\n/g, '\n'); const oldNorm = OLD.replace(/\r\n/g, '\n'); if (!codeNorm.includes(oldNorm)) { console.error('[patch] 找不到目标代码块, 可能已被修改'); process.exit(1); } // 保留原文件换行风格 const eol = code.includes('\r\n') ? '\r\n' : '\n'; const newAdapted = NEW.replace(/\n/g, eol); code = code.replace(OLD.replace(/\n/g, eol), newAdapted); if (code === fs.readFileSync(TARGET, 'utf8')) { // fallback: 用规范化后的内容替换 code = codeNorm.replace(oldNorm, NEW); } fs.writeFileSync(TARGET, code); console.log('[patch] route-interceptor-bundle.js → fail-open 保护已注入'); console.log('[patch] 备份:', bak);