Files
cc-web/.planning/subagent-card-metadata/findings.md
2026-07-18 10:14:38 +08:00

50 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 发现记录
- 前端 `collabAgentStateEntries` 已读取 `label/title/name` 和 `description/summary/message`。
- 当前渲染层仅把任务提示词和结果简介写入 DOM `title`,卡片正文没有显示简介。
- 真实 Codex App `spawnAgent` 记录通常提供 `prompt`,但 `agentsStates` 在启动时为空,完成时 `name` 常为线程 ID。
- 当前 `mergeCollabAgentTools` 只保留一个全局 `prompt`,需要把各次 spawn 的 prompt 写入对应代理状态。
- 工作树开始时干净;已有 `.planning/codex-app-worker-timeout` 和根目录规划文件,不能覆盖。
- Trellis 前端规范目前大多是模板,因此实施以现有 `public/app.js` / `public/style.css` 约定和回归测试为主要依据。
- 原 Trellis 当前任务是 `00-bootstrap-guidelines`,本任务结束后需要恢复。
- 样式集中在 `public/style.css` 的 `.collab-agent-*` 区块;需补齐 `min-width: 0` / `max-width: 100%` 收缩链,并为新增简介采用两行 clamp。
- 回归入口是 `scripts/regression.js` 的 Codex App 子代理端到端段;现有测试验证事件链但未覆盖标题/简介展示语义。
- mock 已提供两个子代理及不同 `name/role/summary`,可扩展为通用名称 + 不同 prompt,验证前端合并不串任务上下文。
- 计划复审通过;实现范围保持前端与回归测试,不改后端协议、不重启服务。
- 独立质量检查发现 UUID 正则仅覆盖 v1-v5,会漏掉 UUID v7;需要改为通用 UUID 形状判断。
- 静态源码契约不足以证明多 spawn 行为;需要提取并执行实际纯函数源码,覆盖独立 prompt 与 wait/close 保留。
- 后续状态会携带归一化空标题字段;合并时只有新状态含可读标题才允许覆盖旧标题。
- 归一化 `entry.label` 可能由 prompt 派生,必须携带 `hasReadableSourceTitle` 标记区分协议标题和派生标题。
- 当前真实会话持久化数据只剩一个 `receiverThreadIds: [] / agentsStates: {}` 的 `wait` 工具,说明不能只依赖同 ID 的历史工具快照。
- `closedCollabAgentIds` 只能标记已知 ID 的状态;需要额外缓存 `ccweb_mcp_child_agent_update.child` 的最后结构化状态,才能在空 wait/close 载荷中重建卡片。
- 当前工作树另有“放开图片数量限制”改动,涉及 `CHANGELOG.md`、`README*.md`、`public/app.js`、`server.js`、`scripts/regression.js`,本修复必须限制在不重叠代码区并避免格式化整文件。
- 独立复核确认实时缓存修复后,`renderMessages()` 会清空缓存;若历史只有空 close/wait,刷新仍退化为工具 ID。
- 服务端 `updatePersistedCcwebMcpChildTool` 只按 `child.spawnToolId` 查找工具;真实会话缺少该 spawn 工具时返回 null,未把 child 状态写入历史。
- 后端兜底应只选择最近的 `collab_agent_tool_call`,不得把 child 合并进普通工具。
- 2026-07-15 本机 PM2 `ccweb` 已实际重启并在线;其他机器仍显示旧样式属于发布物/部署路径问题,不是本机进程未重启。
- CentOS 7 单文件发布必须重新运行 `scripts/build-single-exe.js`;该流程会在打包前复制 `public/` 运行时资源,源码更新不会自动进入旧 tar.gz。
- 本机 `dist-exe/cc-web-bun-linux-x64-baseline.tar.gz` 已包含最新静态资源:tar 内 `app.js` / `style.css` 与源码 SHA-256 完全一致,并含 `collab-agent-item-description`、两行 clamp 和关闭状态缓存代码。
- 单文件运行时从二进制同目录的 `public/` 加载资源;只替换 `cc-web` 二进制、保留旧 `public/`,或设置 `CC_WEB_APP_DIR/CC_WEB_PUBLIC_DIR` 指向旧目录,都会继续显示旧样式。
- 旧历史会话本身若只保存 thread ID、没有 title/taskDescription,即使加载新前端也只能显示 `ID ...` 且没有简介;需要用新部署后新建的子代理验证,不能只看旧历史卡片。
- 2026-07-16 确认同一版本存在两套事件链路:完整 `spawnAgent` 会以 `collab_agent_tool_call` 进入 `mergeCollabAgentTools()`;原生 `subAgentActivity` 仅在服务端用于线程恢复,前端不会把它合并成富卡片。
- `mergeCollabAgentTools()` 明确过滤 `toolKind(tool) === 'collab_agent_tool_call'`;因此 `subAgentActivity + 空 wait` 会分别退化为原始折叠工具条和 `ID call_...` 卡片。
- 修复应在进入渲染前将 `agentThreadId`、`agentPath`、活动 `kind` 归一为结构化子代理状态,并避免原始活动事件重复渲染。
- 真实会话中的 `subAgentActivity` 输入与结果都只包含 `kind/agentThreadId/agentPath`,未携带 spawn prompt;因此历史数据能恢复线程 ID、状态与角色标题,但不能凭空恢复完整任务简介。
- 同一消息里随后出现的 `wait` 已被转换为 `collab_agent_tool_call`,但 `receiverThreadIds` 和 `agentsStates` 均为空,说明应将前置活动事件作为该 wait 的恢复来源。
- 扫描现有会话得到 41 条 `subAgentActivity`:活动类型只有 `started` 与 `interacted`,输入字段稳定为 `type/id/kind/agentThreadId/agentPath`,均无 prompt;`interacted` 应保持运行态。
- Phase 8 复审已通过;计划已明确字段映射、原始工具条与 `ID call_...` 去重、baseline 二进制 smoke test 和 tarball 核验。
- 前端所有历史、恢复流和实时流都通过 `toolKind()` 分流;让它把 raw `subAgentActivity` 识别为协作显示工具,可同时复用现有合并、富卡片渲染和普通工具过滤逻辑,避免在三个调用点分别硬编码。
- `normalizeCollabAgentData()` 是补齐活动字段的最小归一入口:从 `agentThreadId` 构建 receiver/state,从 `agentPath` basename 构建标题/角色,从活动 kind 映射状态,并按真实字段保留 prompt。
- 新事件还应在 `lib/codex-app-runtime.js` 的 `itemKind/itemInput/itemResult` 层输出 `collab_agent_tool_call` 结构;这样旧前端也能把新会话视为富卡片,同时保留 `input.type=subAgentActivity` 供服务端恢复线程路由。
- 首轮生产实现已让定向行为回归通过;人工审查仍需确认三项最小范围边界:空 wait 对整体头部状态的覆盖、agentPath 同时填充 role 导致标题/页脚重复、通用 tool_end 全量增加 name/input 的必要性。
- 独立质量检查确认首轮实现仍有高风险缺口:完成态空 wait 会覆盖整体头部为已返回但 child 仍运行;runtime completed 不带 prompt 时会直接替换 started input,刷新后简介丢失。
- 另有两个中风险边界:agentPath basename 回填 role 会导致标题/footer 重复;仅凭 name 匹配 `subAgentActivity` 会把无 agentThreadId 的同名普通工具误归类。
- 第二轮已改为子状态优先聚合整体状态、runtime 活动输入结构化合并、agentPath 仅提供标题、activity 匹配必须存在 threadId;新增边界回归均通过,等待原检查代理复核。
- 原检查代理复核时把 `item/completed` 误等同于 child completed;真实会话反证是 `input.kind=started` 的活动工具本身 `done=true`,因此 transport item 生命周期不能覆盖 activity kind 的 child 生命周期语义。
- 正确契约:completed 通知缺少新 kind 时继承 previous activity kind/status;只有活动 kind 明确为 completed/returned/failed/closed 时才改变 child 终态,同时仍保留 started prompt。
- 用户明确要求所有子代理统一成完整标题+简介卡片。上游 raw activity 无法追回真实 prompt,因此展示层需以 agentPath/task name 生成可读标题和明确标注的兜底简介,真实 prompt 仍保持最高优先级。
- 富卡片独立复核发现 `collabAgentStateEntries` 会重新推断并覆盖 `hasReadableSourceTitle:false`,导致 prompt 派生的 snake_case 标题被误翻译;该标记必须贯穿 merge、entry 与 render。
- 最终实现只美化协议/agentPath 来源的自动任务名;prompt 派生标题的 `hasReadableSourceTitle:false` 会贯穿 merge→entry→render,不被误翻译。
- 最终 HTTP `app.js` 与源码 SHA-256 均为 `0b3a14a543fa819837eb4d1bf007aa4929d52844af8624696d5f74afe8b7891e`,响应为 `Cache-Control: no-store, max-age=0`,刷新页面即可加载,无需为纯静态改动中断其他运行对话。
- 最终 baseline tar SHA-256 为 `c85202fa3ee989689aef3821b6860b1a356267180aa79858140849599f8504d4`,MCP initialize smoke test 成功。