bookworm-smart-assistant/scripts/patches/patch-route-precision-10x-batch-b2.js
Bookworm Admin 34f304881f fix: strip session-continuity-mcp hooks from Portable template
export.mjs now removes hooks referencing npm packages not included
in the Portable distribution (session-continuity-mcp).
Eliminates MODULE_NOT_FOUND errors on Portable installations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 22:15:39 +08:00

179 lines
9.6 KiB
JavaScript

#!/usr/bin/env node
/**
* patch-route-precision-10x-batch-b2.js
* 路由精度10项改进 — Batch B2: route-interceptor-bundle.js
* Item 2: 图片继承链修复 — tryInherit() 处理 primary='none' 时保留 lastValidPrimary
* Item 9: 确认词强制继承 — 短确认词精确匹配时 force tryInherit()
*
* 注意: 文件含 CRLF 行尾,使用正则 \r?\n 匹配,输出保留原文件行尾格式
*/
'use strict';
const fs = require('fs');
const path = require('path');
const SENTINEL_2 = 'IMAGE_INHERIT_LAST_VALID_PRIMARY_v1_APPLIED';
const SENTINEL_9 = 'CONFIRM_WORDS_FORCE_INHERIT_v1_APPLIED';
const TARGET = path.join(__dirname, '..', '..', 'hooks', 'route-interceptor-bundle.js');
const BAK = TARGET + '.bak';
if (!fs.existsSync(TARGET)) {
console.error('[ERROR] route-interceptor-bundle.js not found:', TARGET);
process.exit(1);
}
let src = fs.readFileSync(TARGET, 'utf8');
// Detect line ending used by file (CRLF or LF)
const CRLF = src.includes('\r\n');
const NL = CRLF ? '\r\n' : '\n';
const alreadyItem2 = src.includes(SENTINEL_2);
const alreadyItem9 = src.includes(SENTINEL_9);
if (alreadyItem2 && alreadyItem9) {
console.log('[SKIP] Both Item 2 and Item 9 patches already applied.');
process.exit(0);
}
fs.writeFileSync(BAK, src, 'utf8');
console.log('[BAK] Backed up to', BAK);
// Helper: join lines using the file's native line ending
function L(...lines) {
return lines.join(NL);
}
// ─────────────────────────────────────────────────────────────
// Item 2: 图片继承链修复
// Replace the tryInherit function body using a regex that handles CRLF/LF
// ─────────────────────────────────────────────────────────────
if (!alreadyItem2) {
// Match the tryInherit function — use a regex with \r?\n throughout
// The function spans from "function tryInherit() {" to its closing "}"
// We match the exact known structure
const tryInheritRegex = /function tryInherit\(\) \{\r?\n\s+if \(!_cachedPrevState\) return null;\r?\n\s+const prevTs = _cachedPrevState\.ts \? new Date\(_cachedPrevState\.ts\)\.getTime\(\) : 0;\r?\n\s+const elapsed = Date\.now\(\) - prevTs;\r?\n\s+if \(\r?\n\s+elapsed > INHERIT_WINDOW_MS \|\|\r?\n\s+!_cachedPrevState\.routing\?\.primary \|\|\r?\n\s+_cachedPrevState\.routing\.primary === 'none'\r?\n\s+\) return null;\r?\n\s+const prevRouting = _cachedPrevState\.routing;\r?\n\s+return \{\r?\n\s+primary: prevRouting\.primary,\r?\n\s+candidates: \(prevRouting\.candidates \|\| \[\]\)\.map\(c => \(\{\r?\n\s+\.\.\.c,\r?\n\s+confidence: Math\.round\(c\.confidence \* 0\.7 \* 100\) \/ 100,\r?\n\s+\}\)\),\r?\n\s+confidence: Math\.round\(\(prevRouting\.confidence \|\| 0\) \* 0\.7 \* 100\) \/ 100,\r?\n\s+chain: prevRouting\.chain \|\| \[\],\r?\n\s+\/\/ 宪法 13\.1: 继承路由保留 mustInvoke 标记\r?\n\s+_inheritedMustInvoke: _cachedPrevState\.mustInvoke \|\| false,\r?\n\s+\};\r?\n\s+\}/;
// Build the replacement using the file's native line ending
const ind6 = ' '; // 6 spaces (inner function body)
const ind8 = ' '; // 8 spaces (inside function)
const replacement = L(
`// ${SENTINEL_2}`,
`${ind6}function tryInherit() {`,
`${ind8}if (!_cachedPrevState) return null;`,
`${ind8}const prevTs = _cachedPrevState.ts ? new Date(_cachedPrevState.ts).getTime() : 0;`,
`${ind8}const elapsed = Date.now() - prevTs;`,
`${ind8}if (elapsed > INHERIT_WINDOW_MS) return null;`,
``,
`${ind8}// Item 2: 图片继承链修复 — primary='none' 时回退到 lastValidPrimary`,
`${ind8}let prevRouting = _cachedPrevState.routing;`,
`${ind8}if (!prevRouting) return null;`,
`${ind8}let effectivePrimary = prevRouting.primary;`,
`${ind8}if (!effectivePrimary || effectivePrimary === 'none') {`,
`${ind8} const lvp = _cachedPrevState.lastValidPrimary || (prevRouting && prevRouting.lastValidPrimary);`,
`${ind8} if (!lvp || lvp === 'none') return null;`,
`${ind8} effectivePrimary = lvp;`,
`${ind8}}`,
`${ind8}return {`,
`${ind8} primary: effectivePrimary,`,
`${ind8} candidates: (prevRouting.candidates || []).map(c => ({`,
`${ind8} ...c,`,
`${ind8} confidence: Math.round(c.confidence * 0.7 * 100) / 100,`,
`${ind8} })),`,
`${ind8} confidence: Math.round((prevRouting.confidence || 0) * 0.7 * 100) / 100,`,
`${ind8} chain: prevRouting.chain || [],`,
`${ind8} // 宪法 13.1: 继承路由保留 mustInvoke 标记`,
`${ind8} _inheritedMustInvoke: _cachedPrevState.mustInvoke || false,`,
`${ind8}};`,
`${ind6}}`
);
if (!tryInheritRegex.test(src)) {
console.error('[ERROR Item2] tryInherit regex did not match. Skipping Item 2 tryInherit patch.');
} else {
src = src.replace(tryInheritRegex, replacement);
console.log('[DONE] Item 2a: tryInherit() patched with lastValidPrimary fallback');
}
// Inject lastValidPrimary maintenance before writeRouteState call
// Match: "// 写入 route-state\r?\n writeRouteState(traceId, prompt, intent, routing);"
const writeStateRegex = /\/\/ 写入 route-state\r?\n(\s+)writeRouteState\(traceId, prompt, intent, routing\);/;
const writeStateMatch = writeStateRegex.exec(src);
if (!writeStateMatch) {
console.error('[ERROR Item2] writeRouteState anchor not found. lastValidPrimary maintenance skipped.');
} else {
const ind = writeStateMatch[1]; // actual indentation of the writeRouteState call
const writeReplacement = L(
`// Item 2: 维护 lastValidPrimary — 供后续 tryInherit() 使用`,
`${ind}if (routing.primary && routing.primary !== 'none') {`,
`${ind} routing.lastValidPrimary = routing.primary;`,
`${ind}} else if (_cachedPrevState) {`,
`${ind} const _oldLvp = _cachedPrevState.lastValidPrimary ||`,
`${ind} (_cachedPrevState.routing && _cachedPrevState.routing.lastValidPrimary);`,
`${ind} if (_oldLvp && _oldLvp !== 'none') routing.lastValidPrimary = _oldLvp;`,
`${ind}}`,
``,
`${ind}// 写入 route-state`,
`${ind}writeRouteState(traceId, prompt, intent, routing);`
);
src = src.replace(writeStateRegex, writeReplacement);
console.log('[DONE] Item 2b: lastValidPrimary maintenance injected before writeRouteState');
}
}
// ─────────────────────────────────────────────────────────────
// Item 9: 确认词强制继承
// Insert confirm-word check before the isImageQuery branch
// ─────────────────────────────────────────────────────────────
if (!alreadyItem9) {
// Match "if (isImageQuery) {\r?\n // 斧四..."
const flowRegex = /if \(isImageQuery\) \{\r?\n(\s+)\/\/ 斧四: 图片查询/;
const flowMatch = flowRegex.exec(src);
if (!flowMatch) {
console.error('[ERROR Item9] isImageQuery flow anchor not found. Skipping Item 9 patch.');
} else {
const innerInd = flowMatch[1]; // indentation inside the if block
const outerInd = innerInd.slice(0, innerInd.length - 2); // one level out (2 spaces less)
const confirmBlock = L(
`// ${SENTINEL_9}`,
`${outerInd}// Item 9: 确认词强制继承 — 精确短确认词直接 tryInherit(),不走 TF-IDF`,
`${outerInd}const _CONFIRM_WORDS = ['执行', '开始', '继续', '确认', '好的', '行', '可以', 'go', 'yes', 'proceed', 'ok'];`,
`${outerInd}const _promptTrimmed = prompt.trim().toLowerCase();`,
`${outerInd}const _isConfirmWord = _CONFIRM_WORDS.some(w => _promptTrimmed === w) ||`,
`${outerInd} (_promptTrimmed.length <= 4 && _CONFIRM_WORDS.some(w => _promptTrimmed.includes(w)));`,
``,
`${outerInd}if (isImageQuery) {`,
`${innerInd}// 斧四: 图片查询`
);
src = src.replace(flowRegex, confirmBlock);
// Now insert the _isConfirmWord branch AFTER the isImageQuery block close
// Find "} else if (intent.complexity === 'simple') {" and prepend the confirm branch
const simpleRegex = /(\} else if \(intent\.complexity === 'simple'\) \{)/;
if (!simpleRegex.test(src)) {
console.error('[ERROR Item9] simple-complexity anchor not found. Confirm branch not injected.');
} else {
const confirmBranch = L(
`} else if (_isConfirmWord) {`,
`${innerInd}// Item 9: 确认词 → 强制继承,使用 lastValidPrimary 机制`,
`${innerInd}const _confirmInherit = tryInherit();`,
`${innerInd}if (_confirmInherit && _confirmInherit.primary && _confirmInherit.primary !== 'none') {`,
`${innerInd} routing = _confirmInherit;`,
`${innerInd} inherited = true;`,
`${innerInd}} else {`,
`${innerInd} routing = { primary: 'none', candidates: [], confidence: 0, chain: [] };`,
`${innerInd}}`,
`${outerInd}} else if (intent.complexity === 'simple') {`
);
src = src.replace(simpleRegex, confirmBranch);
console.log('[DONE] Item 9: confirm-words force-inherit injected into routing flow');
}
}
}
// ── 写入 ──────────────────────────────────────────────────────
fs.writeFileSync(TARGET, src, 'utf8');
console.log('\n[SUMMARY] route-interceptor-bundle.js patched.');
console.log(' Item 2 (image inherit chain):', alreadyItem2 ? 'SKIPPED (already applied)' : 'DONE');
console.log(' Item 9 (confirm words inherit):', alreadyItem9 ? 'SKIPPED (already applied)' : 'DONE');