3ac4cf8d2e
Continues HWLAB #775 round 2 by adding live runner-trace streaming on top of the round-1 inactivity-timeout + 23-row Code Agent status + rich trace panel foundation. Cloud-api v0.2 removed the pre-React `/v1/agent/chat/trace/<id>/stream` SSE endpoint (404 today), so this round uses the existing `/v1/agent/chat/trace/<id>` JSON endpoint as a polling source. ## 修复对照(迁移前 → 迁移后) | 类别 | 迁移前 (`893f46bc`) | 迁移后 (round 2) | 状态 | |---|---|---|---| | **Trace 事件实时滚动** | `app-device-pod.ts:708-756` `subscribeRunnerTrace` EventSource on `/v1/agent/chat/trace/<id>/stream`,`TRACE_STREAM_FALLBACK_MS` 后降级到 `pollRunnerTrace` (3s 间隔) | `state/runner-trace.ts:pollRunnerTrace` 直接走 `/v1/agent/chat/trace/<id>` 1.5s 间隔(EventSource 端点 404),每次新 eventCount / status / updatedAt 触发 `onSnapshot(snapshot)` | ✅ 对齐(polling 模式) | | **Trace 事件合并** | `app-trace.ts:80-110` `appendTraceEvents` 把新 events 追加到 message.runnerTrace.events | `state/runner-trace.ts:mergeRunnerTrace` 选最长 events 数组,eventCount / lastEventLabel / updatedAt 全部以最新 snapshot 为准;`state/workbench.ts:reducer.message:trace` 派发并替换 | ✅ 对齐 | | **Trace 终态** | `app-device-pod.ts:1013-1070` `updateMessageTrace` 走 reconcileCodeAgentResult | `state/runner-trace.ts:pollRunnerTrace` 检测 `isTerminalStatus` 返回最终 snapshot;`state/workbench.ts:submitMessage` 拿到 `mergeTraceResults(terminal, traceTerminal)` 作为 `messageFromAgentResponse` 入参 | ✅ 对齐 | | **Trace 全量回放** | `app-conv.ts:1133-1170` `replayFullTrace(messageId)` 调 `/v1/agent/chat/trace/<id>` | `state/runner-trace.ts:replayFullTrace(traceId, totalTimeoutMs)` 同样路径;`message:trace` reducer 自动接收新 snapshot | ✅ 对齐(client 暴露) | | **TRACE_POLL_INTERVAL_MS** | `TRACE_POLL_INTERVAL_MS = 1500`(推断,从 `setTimeout(tick, ...)`) | `state/runner-trace.ts:TRACE_POLL_INTERVAL_MS = 1500` | ✅ 对齐 | ## 新文件 / 改动 - 新增 `web/hwlab-cloud-web/src/state/runner-trace.ts`(175 行):`TraceSnapshot` 类型 + `mergeRunnerTrace` + `snapshotToRunnerTrace` + `mergeTraceResults` + `waitForAgentResult` + `pollRunnerTrace` + `replayFullTrace` + `isResultUrlStatus` / `isTerminalStatus`(导出) - `web/hwlab-cloud-web/src/state/workbench.ts`:删除内置的 `waitForAgentResult` / `pollRunnerTrace` / `mergeTrace` / `snapshotToRunnerTrace` / `mergeTraceResults` / `isResultUrlStatus` / `isTerminalStatus` / `TraceSnapshot`,全部 import 自 `./runner-trace`;新增 reducer `message:trace` 处理 partial trace 推送;`submitMessage` 并行启动 `pollRunnerTrace` 与 `waitForAgentResult`,最终用 `mergeTraceResults` 合并 ## 验收 - `cd web/hwlab-cloud-web && bun run check` 通过(Vite build + 2/2 dist freshness test pass) - `bun run scripts/tsc-check.ts` 通过(strict React TSX, 0 explicit any) - `bun test` 2 pass / 0 fail - `bun run build` 9 dist files verified fresh;`app.js` 213154 → 216030 bytes - `workbench.ts` 371 行(< 400 前端 guard);`runner-trace.ts` 175 行 - dist `app.js` 含 `/v1/agent/chat/trace`、`eventsCompacted`、`agentRun` 关键字 Refs: pikasTech/HWLAB#775 (round 2 of 7) Co-authored-by: HWLAB <ci@hwlab.local>