bookworm-smart-assistant/scripts/patches/v6.6-rc2-02-inject-traceid.js

103 lines
3.8 KiB
JavaScript
Raw Permalink Normal View History

#!/usr/bin/env node
/**
* Patch v6.6-rc2-02 · 扩展 subagent-route-injector 注入 traceId + state 占位
* AGENT_TRACE_INJECTOR_P0 · 代号 v6.6-rc2-20260422-1859
*
* hooks/subagent-route-injector.js "[重读纪律]" 行之后插入:
* 1. 生成 traceId = bwr-{yyyymmddhhMMss}-{rand6}
* 2. state/agent-traces/{traceId}.json 占位 (pre_snapshot/claims null)
* 3. additionalContext 追加 [trace:{id}] 约定 Agent 在回复末尾 echo
*
* 幂等: sentinel AGENT_TRACE_INJECTOR_P0
* 回滚: pwsh scripts/rollback-v6.6-rc2.ps1 -Scope all (自动从 .bak 恢复)
* 重签: node hooks/integrity-check.js --generate (必须)
*/
'use strict';
const fs = require('fs');
const path = require('path');
const CLAUDE_ROOT = path.resolve(__dirname, '..', '..');
const INJECTOR_PATH = path.join(CLAUDE_ROOT, 'hooks', 'subagent-route-injector.js');
const SENTINEL = 'AGENT_TRACE_INJECTOR_P0';
const BAK_TAG = 'v6.6-rc2-02-inject-traceid';
// 锚点 (原文件第 84 行附近, 足够唯一可做字符串替换)
const ANCHOR = 'ctx += String.fromCharCode(10)+"[重读纪律] 你是 fresh 实例。不要假设之前的 Agent 做了什么,从当前代码状态独立判断。";';
// 注入段 (用 String.raw 保持 \n 等字面量, 避免模板串转义)
const INJECTION = String.raw`
// --- v6.6-rc2-02 AGENT_TRACE_INJECTOR_P0 ---
try {
const _crypto = require('crypto');
const _tsC = new Date().toISOString().replace(/[-:T.Z]/g, '').slice(0, 14);
const _rand6 = _crypto.randomBytes(3).toString('hex');
const _traceId = 'bwr-' + _tsC + '-' + _rand6;
const _traceFile = path.join(CLAUDE_ROOT, 'state', 'agent-traces', _traceId + '.json');
try {
fs.mkdirSync(path.dirname(_traceFile), { recursive: true });
const _placeholder = {
traceId: _traceId,
session_id: input.session_id || '',
agent_type: (input.tool_input && input.tool_input.subagent_type) || '',
started_at: new Date().toISOString(),
status: 'started',
pre_snapshot: null,
claims: null,
};
const _tmp = _traceFile + '.tmp.' + process.pid;
fs.writeFileSync(_tmp, JSON.stringify(_placeholder, null, 2));
fs.renameSync(_tmp, _traceFile);
} catch {}
ctx += String.fromCharCode(10) + '[trace: ' + _traceId + '] 请在回复末尾标注 <trace>' + _traceId + '</trace> 以便审计';
} catch {}
// --- end AGENT_TRACE_INJECTOR_P0 ---`;
function tsStamp() {
return new Date().toISOString().replace(/[:.]/g, '-');
}
function atomicWrite(target, content) {
const tmp = target + '.tmp.' + process.pid;
fs.writeFileSync(tmp, content);
fs.renameSync(tmp, target);
}
function patchInjector() {
if (!fs.existsSync(INJECTOR_PATH)) {
console.error('[patch-02] 目标不存在: ' + INJECTOR_PATH);
return false;
}
const raw = fs.readFileSync(INJECTOR_PATH, 'utf8');
if (raw.includes(SENTINEL)) {
console.log('[patch-02] 已含 sentinel, 跳过');
return false;
}
if (!raw.includes(ANCHOR)) {
console.error('[patch-02] 未找到锚点字符串, 停止 (文件可能已被修改)');
return false;
}
// 备份
fs.copyFileSync(INJECTOR_PATH, INJECTOR_PATH + '.bak.' + BAK_TAG + '.' + tsStamp());
// 在锚点后追加注入段
const patched = raw.replace(ANCHOR, ANCHOR + INJECTION);
atomicWrite(INJECTOR_PATH, patched);
console.log('[patch-02] subagent-route-injector.js 已注入 traceId 生成段');
return true;
}
function main() {
console.log('[patch-02] v6.6-rc2-02 注入 traceId + state 占位');
const wrote = patchInjector();
if (!wrote) {
console.log('[patch-02] 补丁已生效或失败, 无变更');
} else {
console.log('[patch-02] 完成');
console.log('[patch-02] 后续必跑: node hooks/integrity-check.js --generate (重签 HMAC)');
}
process.exit(0);
}
main();