feat(transcript): 归档详情内回放执行/复审转录 (tsk_O9q0_u78_NPo)

- API:新增 GET /api/runs/:id/transcript,读 run.transcriptRef 指向的
  jsonl,逐行解析成脱敏后的结构化消息数组。校验 runId 合法且关联任务/
  项目存在;路径只允许在 transcriptDir 下(防目录穿越)。
- 脱敏:只透传 assistant 文本 / tool_use(名+摘要参数) / tool_result(截断)
  / 结论 / 模型回退;命中 secret/token/env 等敏感键名的值剔除为 [已脱敏]。
- 看板 archiveModal:执行历史从"文件路径"换成可展开的消息流,按 type
  分类渲染(文本/工具调用/工具结果/结论/回退),长内容折叠,复用 mdToHtml。
  executor 与 reviewer/security run 并列可回放。
- Store:新增 getRun(runId)。
- 测试:transcript 解析(样例 jsonl/脱敏/截断/坏行容错/路径穿越)+ 端点
  inject(合法/未知 runId/无转录/越界路径)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-13 10:42:57 +08:00
parent 872354cf7c
commit 0957a9049a
6 changed files with 512 additions and 6 deletions
+6
View File
@@ -639,6 +639,12 @@ export class Store {
return rows.map(rowToRun);
}
/** 单条 run(转录查看器校验 runId 合法性用);不存在 → undefined */
getRun(runId: string): Run | undefined {
const row = this.db.prepare(`SELECT * FROM runs WHERE id = ?`).get(runId) as RunRow | undefined;
return row ? rowToRun(row) : undefined;
}
// ---------- Events ----------
/** 单任务全量事件(升序):状态流转/审批/运行历史,供归档详情时间线 */
listTaskEvents(taskId: string): Event[] {