// 把一份录制打印成紧凑时间线:node scripts/show.ts recordings/level2-background.json import { readFileSync } from 'node:fs'; import type { RunRecording } from '../shared/types.ts'; const rec: RunRecording = JSON.parse(readFileSync(process.argv[2], 'utf8')); const s = (x: unknown, n = 100) => String(typeof x === 'string' ? x : JSON.stringify(x)).replace(/\s+/g, ' ').slice(0, n); const skip = new Set(['model.delta', 'tool.output', 'job.output', 'history.append', 'workspace.diff', 'run.start']); for (const e of rec.events) { if (skip.has(e.type)) continue; let d = ''; switch (e.type) { case 'model.start': d = `#${e.n} 历史 ${e.messageCount} 条`; break; case 'model.end': d = `#${e.n} ${s(e.message.content, 80)} ${(e.message.tool_calls ?? []).map((c) => `${c.function.name}${s(c.function.arguments, 50)}`).join(' | ')}`; break; case 'tool.start': d = `${e.name} ${s(e.args, 70)}`; break; case 'tool.end': d = s(e.result, 80); break; case 'job.start': d = `${e.jobId} ${e.command}`; break; case 'job.end': d = `${e.jobId} exit=${e.exitCode} ${e.durationMs}ms`; break; case 'inbox.push': d = `${e.item.id} ${e.item.kind} ${e.item.ref ?? ''}`; break; case 'inbox.deliver': d = e.ids.join(','); break; case 'question.ask': d = `${e.questionId} ${e.mode} ${e.question} [${e.options.join('/')}]`; break; case 'question.answer': d = `${e.questionId} ${e.answer}`; break; case 'model.error': d = e.error; break; case 'run.stop': d = e.reason; break; } console.log(`${(e.t / 1000).toFixed(1).padStart(6)} ${e.type.padEnd(15)} ${d}`); }