#!/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 + '] 请在回复末尾标注 ' + _traceId + ' 以便审计'; } 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();