bookworm-smart-assistant/scripts/patches/patch-x07-x08-x09-crlf-fix.js
Bookworm Admin b7a8e29d21 release: v6.7.0 - OTA E2E test release
- VERSION file as authoritative version source
- export.mjs reads VERSION with package.json fallback
- bw-ota.ps1 DryRun mode for safe testing
- auto-setup.ps1 bumped to v3.2.0 (Phase 8 OTA)
2026-04-27 17:59:44 +08:00

92 lines
3.6 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-x07-x08-x09-crlf-fix.js
* 统一修复 X07/X08/X09使用 CRLF 规范化后匹配
*/
'use strict';
const fs = require('fs');
const path = require('path');
const HOOKS_DIR = path.join(__dirname, '..', '..', 'hooks');
let total = 0;
function patchFile(filePath, label, patches) {
if (!fs.existsSync(filePath)) { console.log('SKIP ' + label + ': not found'); return; }
let src = fs.readFileSync(filePath, 'utf8');
const hadCRLF = src.includes('\r\n');
let norm = src.replace(/\r\n/g, '\n');
for (const p of patches) {
if (norm.includes(p.sentinel)) { console.log('SKIP ' + label + '/' + p.id + ': already patched'); continue; }
if (!norm.includes(p.old)) { console.error('FAIL ' + label + '/' + p.id + ': old pattern not found'); process.exit(1); }
norm = norm.replace(p.old, p.new);
console.log('OK ' + p.id + ' applied');
total++;
}
if (hadCRLF) norm = norm.replace(/\n/g, '\r\n');
const tmp = filePath + '.tmp.' + process.pid;
fs.writeFileSync(tmp, norm, 'utf8');
fs.renameSync(tmp, filePath);
}
// === X07: agent-isolation-gate.js seq 步长 ===
patchFile(path.join(HOOKS_DIR, 'agent-isolation-gate.js'), 'agent-isolation-gate', [{
id: 'X07',
sentinel: '[PATCH-X07-SEQ-STEP]',
old: ` const seqMatch = c.match(/\\bseq\\s+(\\d+)(?:\\s+(\\d+))?(?:\\s+(\\d+))?/);
if (seqMatch) {
const a = parseInt(seqMatch[1], 10);
const b = seqMatch[2] ? parseInt(seqMatch[2], 10) : null;
const z = seqMatch[3] ? parseInt(seqMatch[3], 10) : (b !== null ? b : a);
const n = b !== null && z !== null ? Math.max(0, z - a + 1) : a;
if (n >= 6) return { rule: 'B2', detail: 'seq ' + n };
}`,
new: ` const seqMatch = c.match(/\\bseq\\s+(\\d+)(?:\\s+(\\d+))?(?:\\s+(\\d+))?/); // [PATCH-X07-SEQ-STEP]
if (seqMatch) {
let n;
const g1 = parseInt(seqMatch[1], 10);
const g2 = seqMatch[2] ? parseInt(seqMatch[2], 10) : null;
const g3 = seqMatch[3] ? parseInt(seqMatch[3], 10) : null;
if (g3 !== null) {
const step = Math.max(1, g2);
n = Math.max(0, Math.floor((g3 - g1) / step) + 1);
} else if (g2 !== null) {
n = Math.max(0, g2 - g1 + 1);
} else {
n = g1;
}
if (n >= 6) return { rule: 'B2', detail: 'seq ' + n };
}`
}]);
// === X08: session-heartbeat.js 原子写 ===
patchFile(path.join(HOOKS_DIR, 'session-heartbeat.js'), 'session-heartbeat', [{
id: 'X08-hb',
sentinel: '[PATCH-X08-ATOMIC-WRITE]',
old: " fs.writeFileSync(STATE_FILE, JSON.stringify(allState), 'utf8');",
new: ` const _tmpHb = STATE_FILE + '.tmp.' + process.pid; // [PATCH-X08-ATOMIC-WRITE]
fs.writeFileSync(_tmpHb, JSON.stringify(allState), 'utf8');
fs.renameSync(_tmpHb, STATE_FILE);`
}]);
// === X08b: pre-compact-handoff.js heartbeat 原子写 ===
patchFile(path.join(HOOKS_DIR, 'pre-compact-handoff.js'), 'pre-compact-handoff', [{
id: 'X08-pch',
sentinel: '[PATCH-X08-ATOMIC-WRITE]',
old: " fs.writeFileSync(heartbeatPath, JSON.stringify(hbAll), 'utf8');",
new: ` const _tmpPch = heartbeatPath + '.tmp.' + process.pid; // [PATCH-X08-ATOMIC-WRITE]
fs.writeFileSync(_tmpPch, JSON.stringify(hbAll), 'utf8');
fs.renameSync(_tmpPch, heartbeatPath);`
}]);
// === X09: context-pressure-monitor.js CJK 范围 ===
patchFile(path.join(HOOKS_DIR, 'context-pressure-monitor.js'), 'context-pressure-monitor', [{
id: 'X09',
sentinel: '[PATCH-X09-CJK-KOREAN]',
old: " if (b >= 0xE3 && b <= 0xE9) cjk += 3;",
new: " if (b >= 0xE4 && b <= 0xED) cjk += 3; // [PATCH-X09-CJK-KOREAN]"
}]);
console.log('DONE: ' + total + ' patches applied');