- 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)
70 lines
2.6 KiB
JavaScript
70 lines
2.6 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* patch-x08-heartbeat-atomic-write.js
|
|
* 修复 session-heartbeat.js 第80行 writeFileSync → tmp+rename 原子写
|
|
* 同步修复 pre-compact-handoff.js 第50行 heartbeat 写入
|
|
*
|
|
* 幂等: SENTINEL 标记
|
|
*/
|
|
'use strict';
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const SENTINEL = '[PATCH-X08-ATOMIC-WRITE]';
|
|
const HOOKS_DIR = path.join(__dirname, '..', '..', 'hooks');
|
|
|
|
let patchCount = 0;
|
|
|
|
// === 1. session-heartbeat.js ===
|
|
const HB_PATH = path.join(HOOKS_DIR, 'session-heartbeat.js');
|
|
if (fs.existsSync(HB_PATH)) {
|
|
let src = fs.readFileSync(HB_PATH, 'utf8');
|
|
if (src.includes(SENTINEL)) {
|
|
console.log('SKIP: session-heartbeat already patched');
|
|
} else {
|
|
const old = " fs.writeFileSync(STATE_FILE, JSON.stringify(allState), 'utf8');";
|
|
const replacement = [
|
|
" const _tmpHb = STATE_FILE + '.tmp.' + process.pid; // " + SENTINEL,
|
|
" fs.writeFileSync(_tmpHb, JSON.stringify(allState), 'utf8');",
|
|
" fs.renameSync(_tmpHb, STATE_FILE);"
|
|
].join('\n');
|
|
if (!src.includes(old)) {
|
|
console.error('FAIL: session-heartbeat old pattern not found');
|
|
process.exit(1);
|
|
}
|
|
src = src.replace(old, replacement);
|
|
const tmp = HB_PATH + '.tmp.' + process.pid;
|
|
fs.writeFileSync(tmp, src, 'utf8');
|
|
fs.renameSync(tmp, HB_PATH);
|
|
patchCount++;
|
|
console.log('OK: session-heartbeat atomic write patched');
|
|
}
|
|
}
|
|
|
|
// === 2. pre-compact-handoff.js heartbeat 写入 ===
|
|
const PCH_PATH = path.join(HOOKS_DIR, 'pre-compact-handoff.js');
|
|
if (fs.existsSync(PCH_PATH)) {
|
|
let src = fs.readFileSync(PCH_PATH, 'utf8');
|
|
// 查找 heartbeat 区域的非原子写 (不含 X13 的 handoff.json 那个)
|
|
const oldHb = " fs.writeFileSync(heartbeatPath, JSON.stringify(hbAll), 'utf8');";
|
|
if (src.includes(SENTINEL)) {
|
|
console.log('SKIP: pre-compact-handoff heartbeat already patched');
|
|
} else if (src.includes(oldHb)) {
|
|
const newHb = [
|
|
" const _tmpPch = heartbeatPath + '.tmp.' + process.pid; // " + SENTINEL,
|
|
" fs.writeFileSync(_tmpPch, JSON.stringify(hbAll), 'utf8');",
|
|
" fs.renameSync(_tmpPch, heartbeatPath);"
|
|
].join('\n');
|
|
src = src.replace(oldHb, newHb);
|
|
const tmp = PCH_PATH + '.tmp.' + process.pid;
|
|
fs.writeFileSync(tmp, src, 'utf8');
|
|
fs.renameSync(tmp, PCH_PATH);
|
|
patchCount++;
|
|
console.log('OK: pre-compact-handoff heartbeat atomic write patched');
|
|
} else {
|
|
console.log('SKIP: pre-compact-handoff heartbeat pattern not found (may already be patched)');
|
|
}
|
|
}
|
|
|
|
console.log('DONE: ' + patchCount + ' files patched');
|