Files
2026-07-30 18:06:39 +08:00

3.1 KiB
Raw Permalink Blame History

修复侧栏标题刷新风暴

目标

修复会话或协作状态高频更新期间侧栏会话列表反复整段重建、视觉闪烁且点击目标失效的问题,同时保持标题、排序、运行状态、未读状态、等待状态、搜索与折叠行为实时正确。

已确认根因

  1. 服务端的多类会话事件会发送完整 session_list;MCP child-agent 每次增量还会更新父会话的 updated 并广播完整列表。
  2. 前端收到 session_list 或 session_message 后调用 renderSessionList()。
  3. renderSessionList() 无条件执行 sessionList.innerHTML = '',重建所有项目分组、会话项和监听器。
  4. 当重建发生在指针按下与抬起之间时,原点击节点已被替换,浏览器不会产生有效点击。

需求

  • 在侧栏渲染边界计算“结构视图签名”,只有影响列表结构、排序或交互状态的内容变化时才重建 DOM。
  • 单纯 updated 时间变化且会话顺序未变化时,不得替换现有项目分组或会话项节点。
  • 跳过结构重建时,原位刷新现有会话项的相对时间文本。
  • 会话顺序、标题、置顶、运行、未读、等待/回复计数、项目归属、当前会话、当前代理、搜索条件、项目折叠或旧会话展开状态变化时,仍必须重建。
  • 不改变 WebSocket 消息协议,不删除必要的未读/排序状态广播。
  • 同一父会话的连续 child-agent 增量应合并整份会话的加载、序列化与落盘;冲刷前必须基于最新父会话合并,不能覆盖同期父 turn 写入。
  • child-agent 引起的完整 session_list 广播应短周期合并,但局部 ccweb_mcp_child_agent_update 必须逐次实时发送。
  • returned、failed、interrupted、closed 最终态必须立即可靠冲刷,不能被尾随定时器覆盖或丢失。
  • 不引入新的前端依赖。

验收标准

  • 首次渲染正常建立侧栏 DOM。
  • 同一列表连续收到仅 updated 不同的快照时,.session-project-group 与 .session-item 节点身份保持不变。
  • 上述快速更新期间,现有点击监听器和点击目标保持有效。
  • 跳过结构重建时,.session-item-time 文本能原位更新。
  • 会话顺序、标题、状态、分组、搜索或折叠状态变化会触发一次正确重建。
  • 多次 running child 增量只触发一次父会话保存和一次完整列表广播,同时局部 child 更新逐次发送。
  • child 最终态立即落盘并取消残留尾随任务;最终工具结果刷新后可恢复。
  • 新增回归测试先失败、修复后通过;现有相关回归通过。

实现约束

  • 优先在 public/app.js 内复用现有状态和 timeAgo(),避免复制分组/排序逻辑。
  • 测试沿用 scripts/regression.js 的函数提取与最小 DOM stub 方式。
  • 关键注释使用简体中文,说明为什么 updated 不应触发结构重建。
  • 保留现有搜索、折叠、置顶和会话操作事件语义。

非目标

  • 本次不重构整个侧栏为框架组件。
  • 本次不修改 child-agent 工具卡协议。
  • 本次不通过粗暴长延迟隐藏问题。