bookworm-smart-assistant/scripts/patches/patch-route-precision-10x-batch-a.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
7.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* patch-route-precision-10x-batch-a.js
* 路由精度10项改进 — Batch A: disambiguation-rules.json 变更
* Item 3: R27 移除 bookworm|自检 关键词
* Item 4: 新增 R90 sre-expert boost
* Item 5: 新增 R91 impact-analyst boost
* Item 7: 新增 R92 Google Sheets 数据分析再路由
* Item 8: R58 补充 evolution-tracker boost
* Item 10: 新增 R93 MCP browser consolidation
*
* 安全性: .bak 备份 + sentinel 幂等检查 + UTF-8 无 BOM 写入
*/
'use strict';
const fs = require('fs');
const path = require('path');
// SENTINEL: 防止重复运行
const SENTINEL = 'PATCH_ROUTE_PRECISION_10X_BATCH_A_APPLIED';
const SCRIPTS_DIR = path.join(__dirname, '..');
const RULES_FILE = path.join(SCRIPTS_DIR, 'disambiguation-rules.json');
const BAK_FILE = RULES_FILE + '.bak';
// ── 读取原文件 ─────────────────────────────────────────
if (!fs.existsSync(RULES_FILE)) {
console.error('[ERROR] disambiguation-rules.json not found:', RULES_FILE);
process.exit(1);
}
const raw = fs.readFileSync(RULES_FILE, 'utf8');
const data = JSON.parse(raw);
// ── 幂等检查 ───────────────────────────────────────────
if (data._meta && data._meta[SENTINEL]) {
console.log('[SKIP] Patch already applied (sentinel found). Nothing to do.');
process.exit(0);
}
// 另一种幂等检查: 如果 R90 已存在,也跳过
if (data.rules && data.rules.some(r => r.id === 'R90')) {
console.log('[SKIP] R90 already exists. Patch appears already applied.');
process.exit(0);
}
// ── 备份 ───────────────────────────────────────────────
fs.writeFileSync(BAK_FILE, raw, 'utf8');
console.log('[BAK] Backed up to', BAK_FILE);
// ── Item 3: R27 — 移除 bookworm 和 自检 关键词 ─────────
let r27Modified = false;
for (const rule of data.rules) {
if (rule.id === 'R27') {
const before = rule.trigger;
// 移除整个 pipe-delimited token: bookworm 和 自检
// 策略: 将 trigger 按 | 分割,过滤掉目标词,再重新 join
// 这样避免跨词的正则副作用(如 系统自检|系统健康 → 系统系统健康)
const tokens = rule.trigger.split('|');
const filtered = tokens.filter(tok => tok !== 'bookworm' && tok !== '自检');
let t = filtered.join('|');
// 清理多余的 | 分隔符(防御性)
t = t.replace(/\|{2,}/g, '|').replace(/^\||\|$/g, '');
rule.trigger = t;
r27Modified = (before !== t);
console.log('[ITEM3] R27 trigger before:', before);
console.log('[ITEM3] R27 trigger after :', t);
console.log('[ITEM3]', r27Modified ? 'MODIFIED' : 'NO_CHANGE (keywords not found)');
break;
}
}
// ── Item 8: R58 — 补充 evolution-tracker boost ─────────
let r58Modified = false;
for (const rule of data.rules) {
if (rule.id === 'R58') {
if (!rule.boost) {
rule.boost = 'evolution-tracker';
r58Modified = true;
console.log('[ITEM8] R58 added boost: evolution-tracker');
} else {
console.log('[ITEM8] R58 already has boost:', rule.boost, '— no change');
}
break;
}
}
// ── Items 4/5/7/10: 追加新规则 R90R93 ─────────────────
const newRules = [
{
id: 'R90',
note: 'SRE 专属场景 → sre-expert从 devops-expert 分离',
trigger: 'sli|slo|sla.*(?:监控|告警)|on.?call|postmortem|error.*budget|toil|事故响应|incident.*response|runbook|alert.*rule',
boost: 'sre-expert',
penalty: ['devops-expert'],
weight: 0.35,
note2: 'SRE专属场景从devops-expert中分离',
},
{
id: 'R91',
note: '变更影响分析 → impact-analyst与架构咨询消歧',
trigger: '变更影响|影响分析|影响范围|爆炸半径|依赖分析|改.*(?:会|有).*影响|change.*impact|blast.*radius|downstream.*impact|调用链.*分析|谁在.*(?:用|调用)',
boost: 'impact-analyst',
penalty: ['architect-expert', 'developer-expert'],
weight: 0.35,
note2: '变更影响分析与架构咨询消歧',
},
{
id: 'R92',
note: 'Google Sheets 数据分析 → data-analyst-expert (MCP: google-drive)',
trigger: '(?:google\\s*sheets?|谷歌表格).*(?:分析|统计|可视化|透视|图表|数据清洗|pivot)',
boost: 'data-analyst-expert',
penalty: ['developer-expert'],
weight: 0.30,
preferred_mcp: 'google-drive',
note2: 'Google Sheets数据分析场景从developer-expert分流',
},
{
id: 'R93',
note: '浏览器MCP统一路由 → browser-automation-expert (playwright为主)',
trigger: '(?:browser.?mcp|computer.?control|桌面控制).*(?:测试|自动化|操作)',
boost: 'browser-automation-expert',
penalty: [],
weight: 0.25,
preferred_mcp: 'playwright',
note2: '浏览器MCP统一路由: playwright为主, chrome-devtools为辅, browser-mcp/computer-control-mcp为备选',
},
];
for (const r of newRules) {
data.rules.push(r);
console.log(`[ITEM${r.id === 'R90' ? '4' : r.id === 'R91' ? '5' : r.id === 'R92' ? '7' : '10'}] Added rule ${r.id}`);
}
// ── 更新元数据 ──────────────────────────────────────────
const totalRules = data.rules.length;
data._meta.ruleCount = totalRules;
data._meta[SENTINEL] = true;
data._meta.patchedAt_batchA = new Date().toISOString();
// 更新 changelog
if (!data._meta.changelog) data._meta.changelog = [];
data._meta.changelog.push(
'R27: 移除 bookworm|自检 关键词 (已由 R81-R89 覆盖)',
'R58: 补充 boost: evolution-tracker',
'R90: 新增 — SRE 专属场景 sre-expert (postmortem/on-call/runbook等)',
'R91: 新增 — 变更影响分析 impact-analyst (爆炸半径/依赖分析等)',
'R92: 新增 — Google Sheets 数据分析 data-analyst-expert (preferred_mcp: google-drive)',
'R93: 新增 — 浏览器MCP统一路由 browser-automation-expert (preferred_mcp: playwright)',
);
// 更新 description 中的规则数量引用 (89条 → 实际数)
if (data._meta.description) {
data._meta.description = data._meta.description.replace(/\d+ 条/g, `${totalRules}`);
}
// ── 写入 (UTF-8 无 BOM) ────────────────────────────────
const output = JSON.stringify(data, null, 2) + '\n';
fs.writeFileSync(RULES_FILE, output, 'utf8');
console.log('\n[DONE] disambiguation-rules.json updated.');
console.log(` Total rules: ${totalRules}`);
console.log(` R27 modified: ${r27Modified}`);
console.log(` R58 modified: ${r58Modified}`);
console.log(` New rules added: R90, R91, R92, R93`);
// ── JSON 验证 ──────────────────────────────────────────
try {
const verify = JSON.parse(fs.readFileSync(RULES_FILE, 'utf8'));
console.log(`[VERIFY] JSON valid. rules.length=${verify.rules.length}, ruleCount=${verify._meta.ruleCount}`);
} catch (e) {
console.error('[VERIFY ERROR] JSON parse failed:', e.message);
// 回滚
fs.copyFileSync(BAK_FILE, RULES_FILE);
console.error('[ROLLBACK] Restored from .bak');
process.exit(1);
}