bookworm-smart-assistant/hooks/prompt-dispatcher.js

94 lines
2.7 KiB
JavaScript
Raw Normal View History

#!/usr/bin/env node
/**
* UserPromptSubmit Hook: 统一提交派遣器 (v6.2 M3)
*
* 合并 2 UserPromptSubmit 钩子为单进程减少 ~50ms 串行开销:
* 1. security-startup-guard (同步, <5ms, fail-open)
* 2. route-interceptor-bundle (异步, 路由引擎, fail-open)
*
* 读取 stdin 一次:
* - security-startup-guard runGuard() 不需要 stdin 数据 (仅检查 lockfile + settings)
* - route-interceptor-bundle 作为子进程接收 stdin 数据 (保留其 timeout 逻辑)
*
* 退出码: 0 (始终放行, UserPromptSubmit 不阻断)
*/
'use strict';
const { spawn } = require('child_process');
const path = require('path');
const HOOKS_DIR = __dirname;
function main() {
let rawInput = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', (chunk) => {
rawInput += chunk;
if (rawInput.length > 256 * 1024) {
// 输入过大,直接退出
process.exit(0);
}
});
process.stdin.on('end', () => {
// --- 阶段 1: security-startup-guard (同步, fail-open) ---
try {
const guard = require('./security-startup-guard.js');
if (guard && guard.runGuard) {
guard.runGuard();
}
} catch {}
// --- 阶段 2: route-interceptor-bundle (子进程, 保留独立 timeout) ---
const bundlePath = path.join(HOOKS_DIR, 'route-interceptor-bundle.js');
const hookTimingMs = Date.now(); // [P3-6] 计时起点
try {
const child = spawn('node', [bundlePath], {
stdio: ['pipe', 'pipe', 'pipe'],
timeout: 3000,
});
let stdout = '';
let stderr = '';
child.stdout.on('data', (d) => { stdout += d; });
child.stderr.on('data', (d) => { stderr += d; });
child.on('close', () => {
// [P3-6] 记录路由耗时
try {
const elapsed = Date.now() - hookTimingMs;
const timingPath = path.join(HOOKS_DIR, '..', 'debug', 'hook-timing.jsonl');
const entry = JSON.stringify({ ts: new Date().toISOString(), hook: 'route-interceptor-bundle', elapsed }) + '\n';
require('fs').appendFileSync(timingPath, entry);
} catch {}
// 转发 route-interceptor-bundle 的 stdout (含 additionalContext)
if (stdout) {
process.stdout.write(stdout);
}
if (stderr) {
process.stderr.write(stderr);
}
process.exit(0);
});
child.on('error', () => {
process.exit(0); // fail-open
});
// 将 stdin 数据传递给子进程
child.stdin.write(rawInput);
child.stdin.end();
} catch {
process.exit(0); // fail-open
}
});
}
if (typeof module !== 'undefined') {
module.exports = { main };
}
if (require.main === module) {
main();
}