bookworm-smart-assistant/scripts/patches/patch-review-chaptered-seal.js

114 lines
4.0 KiB
JavaScript
Raw Normal View History

#!/usr/bin/env node
/**
* review-report-checker 章节封印升级补丁 (2026-04-25)
*
* 目标: hooks/review-report-checker.js required[] 提示词升级为方案 E
* - 裁决行改为 "裁决 │ PASS / BLOCKED (宪章 §2.1 · 章节封印)"
* - 各维度提示追加模板引用 (模板 M/L/XL)
* - header 追加 "采用章节封印模板" 文案
*
* 不改变: SOURCE_EXTENSIONS / 行数阈值 / 敏感路径判定 / logCompliance 契约
*
* 幂等: sentinel "chaptered-seal:v1" 注入文件顶部, 已打过则跳过
* 原子: tmp + rename
* 备份: scripts/patches/bak/review-report-checker.js.cs.<ts>.bak
*/
'use strict';
const fs = require('fs');
const path = require('path');
const TARGET = path.join(__dirname, '..', '..', 'hooks', 'review-report-checker.js');
const SENTINEL = '/* patch-review-chaptered-seal:v1 */';
const REPLACEMENTS = [
{
from: "const required = ['审查: PASS / BLOCKED (宪法 2.1)'];",
to: "const required = ['裁决 │ PASS / BLOCKED (宪章 §2.1 · 章节封印)'];",
label: 'verdict-line',
},
{
from: "required.push('=== AI CODE REVIEW REPORT === (规范/安全/质量/架构 4 维度)');",
to: "required.push('章节封印 (模板 M): 规范/安全/质量/架构 4 维度 + BOOKWORM REVIEW SEAL 框');",
label: 'standard-tier',
},
{
from: "required.push('=== RED TEAM SELF-REVIEW === (5 问对抗自审, 宪法 11.3)');",
to: "required.push('章节封印 (模板 L): SAFETY SEAL + 红队 5 问分节 (§11.3)');",
label: 'red-team-tier',
},
{
from: "required.push('=== SEMANTIC DIFF === (逐行原始→修改→原因→副作用, 宪法 12.1)');",
to: "required.push('章节封印 (模板 XL): SEMANTIC DIFF 追加节 + 善读者锚定句 (§12.1)');",
label: 'semantic-diff-tier',
},
{
from: "const header = '[review-required] ' + path.basename(filePath)\n + ' 修改 ' + lineCount + ' 行'\n + (sensitive ? ' (安全敏感)' : '')\n + ' — 回复末尾必须附:';",
to: "const header = '[review-required] ' + path.basename(filePath)\n + ' 修改 ' + lineCount + ' 行'\n + (sensitive ? ' (安全敏感)' : '')\n + ' — 回复末尾必须以【章节封印】格式附:';",
label: 'header-nudge',
},
];
function atomicWrite(file, content) {
const tmp = file + '.tmp.' + process.pid + '.' + Date.now();
fs.writeFileSync(tmp, content);
fs.renameSync(tmp, file);
}
function main() {
if (!fs.existsSync(TARGET)) {
console.error('[patch-cs] 目标不存在:', TARGET);
process.exit(1);
}
const before = fs.readFileSync(TARGET, 'utf8');
if (before.includes(SENTINEL)) {
console.log('[patch-cs] 已打过补丁, 跳过');
process.exit(0);
}
let after = before;
const applied = [];
const missing = [];
for (const rep of REPLACEMENTS) {
if (after.includes(rep.from)) {
after = after.replace(rep.from, rep.to);
applied.push(rep.label);
} else if (after.includes(rep.to)) {
applied.push(rep.label + ' [already-correct]');
} else {
missing.push(rep.label);
}
}
if (applied.length === 0) {
console.error('[patch-cs] 所有锚点均未命中, 可能文件已大幅修改');
console.error(' missing=' + missing.join(','));
process.exit(1);
}
// 注入 sentinel (紧跟 'use strict')
if (after.startsWith("'use strict';")) {
after = after.replace("'use strict';", "'use strict';\n" + SENTINEL);
} else {
after = SENTINEL + '\n' + after;
}
// 备份
const bakDir = path.join(__dirname, 'bak');
if (!fs.existsSync(bakDir)) fs.mkdirSync(bakDir, { recursive: true });
const bakFile = path.join(bakDir, 'review-report-checker.js.cs.' + Date.now() + '.bak');
fs.writeFileSync(bakFile, before);
atomicWrite(TARGET, after);
console.log('[patch-cs] ✓ applied=[' + applied.join(', ') + '] bak=' + path.basename(bakFile));
if (missing.length > 0) {
console.warn('[patch-cs] ⚠ missing=' + missing.join(','));
}
console.log('[patch-cs] 下次 Edit/Write 即生效章节封印提示');
}
main();