84 lines
3.0 KiB
JavaScript
84 lines
3.0 KiB
JavaScript
|
|
#!/usr/bin/env node
|
||
|
|
/**
|
||
|
|
* P0-2 Patch: Hook Session-Once
|
||
|
|
* - session-start-mcp-probe.js: 追加 session-once early-exit + markRun
|
||
|
|
* - session-start-memory-audit.js: 追加 session-once early-exit + markRun
|
||
|
|
* 幂等: sentinel [P0-2] SESSION_ONCE_v1
|
||
|
|
*/
|
||
|
|
'use strict';
|
||
|
|
const fs = require('fs');
|
||
|
|
const path = require('path');
|
||
|
|
|
||
|
|
const HOOKS = path.resolve(__dirname, '..', '..', 'hooks');
|
||
|
|
const SENTINEL = '[P0-2] SESSION_ONCE_v1';
|
||
|
|
|
||
|
|
function patchFile(name, fn) {
|
||
|
|
const fp = path.join(HOOKS, name);
|
||
|
|
if (!fs.existsSync(fp)) { process.stderr.write('[SKIP] ' + name + ' not found\n'); return false; }
|
||
|
|
const src = fs.readFileSync(fp, 'utf8');
|
||
|
|
if (src.includes(SENTINEL)) { process.stderr.write('[SKIP] ' + name + ' already patched\n'); return false; }
|
||
|
|
fs.writeFileSync(fp + '.bak-p02.' + Date.now(), src);
|
||
|
|
const out = fn(src);
|
||
|
|
const tmp = fp + '.tmp.' + process.pid;
|
||
|
|
fs.writeFileSync(tmp, out, 'utf8');
|
||
|
|
fs.renameSync(tmp, fp);
|
||
|
|
process.stderr.write('[DONE] ' + name + '\n');
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- session-start-mcp-probe.js ---
|
||
|
|
function patchMcpProbe(src) {
|
||
|
|
// early-exit 插在 feature flag 检查之前 (main 函数第一行)
|
||
|
|
const marker = ' // Feature flag 检查';
|
||
|
|
if (!src.includes(marker)) throw new Error('marker not found in mcp-probe');
|
||
|
|
|
||
|
|
const earlyExit = [
|
||
|
|
' // ' + SENTINEL + ' — 会话级去重 (<1ms)',
|
||
|
|
' try { if (require(\'./lib/session-once.js\').hasRun(\'mcp-probe\')) return safeExit(); } catch {}',
|
||
|
|
'',
|
||
|
|
marker,
|
||
|
|
].join('\n');
|
||
|
|
let result = src.replace(marker, earlyExit);
|
||
|
|
|
||
|
|
// markRun 插在原子写成功之后
|
||
|
|
const writeMarker = " fs.renameSync(tmp, HEALTH_FILE);";
|
||
|
|
if (!result.includes(writeMarker)) throw new Error('write marker not found');
|
||
|
|
|
||
|
|
result = result.replace(
|
||
|
|
writeMarker,
|
||
|
|
writeMarker + '\n // ' + SENTINEL + '\n try { require(\'./lib/session-once.js\').markRun(\'mcp-probe\'); } catch {}'
|
||
|
|
);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- session-start-memory-audit.js ---
|
||
|
|
function patchMemoryAudit(src) {
|
||
|
|
// early-exit 插在 feature flag 之前
|
||
|
|
const marker = ' // Feature flag';
|
||
|
|
if (!src.includes(marker)) throw new Error('marker not found in memory-audit');
|
||
|
|
|
||
|
|
const earlyExit = [
|
||
|
|
' // ' + SENTINEL + ' — 会话级去重 (<1ms)',
|
||
|
|
' try { if (require(\'./lib/session-once.js\').hasRun(\'memory-audit\')) return safeExit(); } catch {}',
|
||
|
|
'',
|
||
|
|
marker,
|
||
|
|
].join('\n');
|
||
|
|
let result = src.replace(marker, earlyExit);
|
||
|
|
|
||
|
|
// markRun 插在 stamp 更新之后
|
||
|
|
const stampMarker = " fs.writeFileSync(STAMP_FILE, TODAY);";
|
||
|
|
if (!result.includes(stampMarker)) throw new Error('stamp marker not found');
|
||
|
|
|
||
|
|
result = result.replace(
|
||
|
|
stampMarker,
|
||
|
|
stampMarker + '\n // ' + SENTINEL + '\n try { require(\'./lib/session-once.js\').markRun(\'memory-audit\'); } catch {}'
|
||
|
|
);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- Execute ---
|
||
|
|
let count = 0;
|
||
|
|
if (patchFile('session-start-mcp-probe.js', patchMcpProbe)) count++;
|
||
|
|
if (patchFile('session-start-memory-audit.js', patchMemoryAudit)) count++;
|
||
|
|
process.stderr.write('\nP0-2 Session-Once: ' + count + '/2 files patched\n');
|