bookworm-smart-assistant/scripts/patches/patch-p0-1-metrics-emit.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

84 lines
3.3 KiB
JavaScript

#!/usr/bin/env node
/**
* P0-1 Patch: 可观测性指标
* - prompt-dispatcher.js: 追加 metrics.emit('route', ...) 含路由延迟/置信度/技能
* - agent-claim-observer.js: 追加 model/duration_ms 字段 + metrics.emit('agent', ...)
* 幂等: sentinel [P0-1] METRICS_EMIT_v1
*/
'use strict';
const fs = require('fs');
const path = require('path');
const HOOKS = path.resolve(__dirname, '..', '..', 'hooks');
const SENTINEL = '[P0-1] METRICS_EMIT_v1';
function patchFile(name, fn) {
const fp = path.join(HOOKS, name);
if (!fs.existsSync(fp)) { console.log('[SKIP] ' + name + ' — not found'); return false; }
const src = fs.readFileSync(fp, 'utf8');
if (src.includes(SENTINEL)) { console.log('[SKIP] ' + name + ' — already patched'); return false; }
fs.writeFileSync(fp + '.bak-p01.' + Date.now(), src);
const out = fn(src);
const tmp = fp + '.tmp.' + process.pid;
fs.writeFileSync(tmp, out, 'utf8');
fs.renameSync(tmp, fp);
console.log('[DONE] ' + name);
return true;
}
// --- prompt-dispatcher.js ---
function patchDispatcher(src) {
const marker = "require('fs').appendFileSync(timingPath, entry);";
if (!src.includes(marker)) throw new Error('marker not found in prompt-dispatcher.js');
const lines = [
'',
' // ' + SENTINEL,
" try {",
" const metrics = require('./lib/metrics.js');",
" let ri = {};",
" try {",
" const parsed = JSON.parse(stdout || '{}');",
" const ctx = (parsed.hookSpecificOutput && parsed.hookSpecificOutput.additionalContext) || '';",
" const cm = ctx.match(/\\u7f6e\\u4fe1\\u5ea6\\s+(\\d+)%/);",
" const sm = ctx.match(/\\u4e3b\\u8def\\u7531:\\s+(\\S+)/);",
" ri = { confidence: cm ? +cm[1] : null, skill: sm ? sm[1] : null };",
" } catch {}",
" metrics.emit('route', Object.assign({ hook: 'prompt-dispatcher', elapsed_ms: elapsed }, ri));",
" } catch {}",
];
return src.replace(marker, marker + lines.join('\n'));
}
// --- agent-claim-observer.js ---
function patchObserver(src) {
// 1. 追加字段到 record 对象
const fieldMarker = ' text_length: text.length,';
if (!src.includes(fieldMarker)) throw new Error('field marker not found in agent-claim-observer.js');
const newFields = [
' text_length: text.length,',
' // ' + SENTINEL,
" model: (input.tool_input && input.tool_input.model) || '',",
" tool_name: (input.tool_input && input.tool_input.name) || 'Agent',",
" duration_ms: (input.tool_response && input.tool_response.duration_ms) || null,",
].join('\n');
let result = src.replace(fieldMarker, newFields);
// 2. 追加 metrics emit
const appendMarker = "fs.appendFileSync(LOG_FILE, JSON.stringify(record) + '\\n');";
if (!result.includes(appendMarker)) throw new Error('append marker not found');
result = result.replace(
appendMarker,
appendMarker + "\n // " + SENTINEL + " — 指标发射\n try { require('./lib/metrics.js').emit('agent', record); } catch {}"
);
return result;
}
// --- Execute ---
let count = 0;
if (patchFile('prompt-dispatcher.js', patchDispatcher)) count++;
if (patchFile('agent-claim-observer.js', patchObserver)) count++;
console.log('\nP0-1 Metrics: ' + count + '/2 files patched');