Files
ycode/docs/复刻待办清单-2026-10-17.md
T

327 lines
36 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.
# WorkBuddy 复刻 TODO(2026-10-17)
本清单记录用户最初提出的 20 项问题及后续追加项,作为后续逐项拆解、实现和验收的工作入口。原始编号保持不变,新增需求顺延编号。本清单的建立与追加仅记录需求,不代表已完成对应采集或实现。
## 执行约定
- 查看 WorkBuddy 的源码、CSS、资源、页面及交互行为一律使用 REA。
- 已有内容沿用 WorkBuddy 5.8.2 的有效 REA 证据;此前未覆盖的内容再采集,并注明实际版本、Evidence ID、观察范围及限制。
- 每项依次记录:证据整理 → 差异与方案 → 实现 → 功能验证 → 视觉/交互验收。实现或构建通过不等于完成 1:1 验收。
- 只有全部验收点通过才勾选完成;记录待拆解的模块保持未完成状态。
- 优先保留用户会话、草稿、空间、模型配置和已有产物。回退、归档、删除应分别建模,不混用同一操作。
- 消息时间沿用已确认规则:当天 `HH:mm`;本年非当天 `M月D日 HH:mm`;非本年 `YYYY年M月D日 HH:mm`。显示消息时间,不显示实时钟表时间。
## 对话与侧栏
### 01. 任务操作菜单
- [x] 将侧栏对话条目后的直接删除按钮替换为原版任务操作入口。
- [x] 通过 REA 对齐菜单的入口、位置、顺序、图标、文案、悬停、关闭、禁用和确认状态。
- [x] 接入:置顶、取消置顶、重命名、独立窗口中打开、打开文件夹、归档、删除任务。
- [ ] 验收:置顶顺序和重命名持久化;独立窗口打开正确任务;文件夹指向正确工作目录;归档与删除行为独立;涉及运行中任务时有明确处理。
状态:主体已实现;运行中任务的处理与逐像素截图比对未完成。
原版证据:WorkBuddy 5.8.3,REA Evidence `ev_f5e9d71a676c453daab40928acfb33aeabae68ba57ffda342380cead7f1a1fe2`(任务菜单打开态),归档 `.tmp/rea-css-evidence/ev_f5e9d71a….json`。观察范围:任务列表首条任务的菜单容器、9 个条目、2 条分隔线、逐项 SVG 图标、几何与 computed style;未覆盖:菜单在窗口边缘翻转、运行中任务状态、分享/保存到工作空间/批量操作三类条目的行为。
原版菜单为 9 项:置顶(已置顶时为“取消置顶”)、重命名、分享任务、在独立窗口中打开、保存到工作空间、打开文件夹、批量操作、归档、删除任务。其中分享任务、保存到工作空间、批量操作依赖云端或尚未实现的能力,按“不渲染无效入口”的原则暂不列出,YCode 当前渲染 6 项。
原版实测数值:容器 170×352、`left = 按钮 left − 17`、`top = 按钮 bottom + 4`、padding 8、圆角 16、最小宽度 160;条目 32 高 / 14px / 22px 行高 / 圆角 8 / 图标 16×16;分隔线 1px、margin 6px 0;危险色 `#b42c3f`、普通文字 `rgba(0,0,0,0.9)`;卡片内“更多”按钮 16×16 且默认 `display:none`,悬停时替换时间显示。
实现:`Sidebar.tsx`(行结构、置顶排序、行内重命名、菜单挂载)、`task-menu.tsx`(菜单容器与条目)、`task-menu.css`(原版规则与深浅色取值)、`task-menu-icons.tsx`(逐项 SVG 原样复刻)、`stores/chat.ts`(setPinned / setArchived / renameSession)、`main/sessions.ts`(pinnedAt / archivedAt 持久化与排序)、`main/ipc.ts`(pin / archive / openFolder / openWindow)、`main/index.ts`(任务独立窗口)、`shared/types.ts`+`shared/ipc.ts`+`preload/index.ts`(契约)。
验证:`scripts/verify-task-menu.cjs` 在真实隔离 Electron(真实 preload / IPC / 文件系统)中 33 项断言全部通过,覆盖菜单文案与顺序、两条分隔线、逐项几何与配色、锚点偏移、遮罩关闭、置顶与取消置顶持久化、行内重命名持久化、归档保留会话与消息、删除真正移除、打开文件夹指向真实 cwd、独立窗口创建且携带 `window=task&taskId=…`。报告与截图:`.tmp/task-menu-Moulvm/`。`npm run typecheck`、`npm run test:conversation`、`npm run build` 通过;`npm run test:sessions` 在干净 HEAD 上同样报 `yaml` 动态 require 失败,与本次改动无关。
遗留:未覆盖运行中任务的置顶/归档/删除副作用与提示;未做原版逐像素截图比对;置顶标识图标取自同批归档的成员图标,原版置顶行的独立截图证据未采集。
### 02. 表格“添加到对话”及引用结果
- [x] 对齐表格上方“添加到对话”按钮的字体、图标、背景、边距、出现条件及交互。
- [x] 对齐点击后输入区内引用表格的呈现,包括结构、预览、移除和与已有草稿的组合方式。
- [x] 对齐发送后用户消息中的表格引用显示。
- [x] 验收:引用正确表格内容,不丢失已有草稿;输入区、发送结果及历史重载三种状态一致。
状态:主体已实现并做了真实窗口回归;仍有两处原版证据缺口(见“遗留”)。
原版证据:
- 渲染器实现:WorkBuddy 5.8.3 渲染器(REA 回收 `.tmp/wb-src-DbE1_mgM.js`)中的 `TableMessageQuoteAction`、`createTableMessageQuoteSourceId`、`getTableMessageQuoteMessageId`、`MessageQuoteAddIcon`、`MessageQuoteTextIcon`、`ChipCloseIcon`、`QuoteReferenceCard`、`InputBannerRail`、`MessageQuotePhraseTag`、`convertUserFrame`/`ContextChipsRenderer`。
- 菜单几何:REA Evidence `ev_38cca1ac66606ab07fb495035e3509f5c4d8ec3e5e2b74d0fdcfcfadb120da3b`(`layout.json` 中 `.cr-message-quote-table-menu` 116×38、按钮 106×28、`top:8px right:8px`、padding 4、圆角 8、条目 14px/22px/500、padding 3px 8px、gap 4、圆角 6、图标 16×16 两条 path、`rgba(0,0,0,.08) 0 4px 16px` 阴影)。
- 样式:REA 回收样式表 `src-CyXHA0IC.css`(SHA-256 `a5e26b537bb50323aefbf25abddad52e288dd3868598be8d255d70886fe77cfe`)40 条引用相关规则,含 `._tag_1krka_19` 及其 message-quote/`:readOnly` 变体、`._iconContainer_1krka_38`、`._icon_1krka_38`、`._text_1krka_66`、`.cr-message-quote-phrase-*`、`.cr-input-quote-card*`、`.cr-input-banner-rail`、`.cr-context-chips`、`.cr-user-content`。
- 观察范围:桌面端浅色主题、单条助手消息中的 markdown 表格、输入区空白草稿。未覆盖:原版实际点击后输入区卡片与消息气泡标签的截图/几何(见遗留)。
实现:
- `shared/conversation.ts` 新增 `MessageQuote`(id、kind、sourceId、messageId、markdown、title?、preview);`ChatMessage.quotes`、`SendPayload.quotes`、`ComposerSendPayload.quotes` 贯通消息与 IPC。
- `workbuddy/conversation/MessageQuoteIcons.tsx`:`MessageQuoteAddIcon`、`MessageQuoteTextIcon`、`ChipCloseIcon` 按回收 path 原样复刻。
- `workbuddy/conversation/TableMessageQuoteAction.tsx`:原版 DOM 结构(`div.cr-message-quote-table-menu` + `data-message-quote-table-added` + `data-message-quote-source-id`、按钮 `aria-label="添加到对话"`),sourceId 用原版 `createTableMessageQuoteSourceId` 组合规则。
- `workbuddy/conversation/message-quote-source.css`:菜单/按钮、已加入描边、引用标签(含只读态)、引用卡片、短语标签与 tooltip 规则,均照搬回收声明。
- `workbuddy/conversation/MessageQuoteCard.tsx`、`MessageQuoteTag.tsx`:输入区卡片与消息只读标签。
- `MarkdownContent`/`ReactMarkdown`:`renderTableAction` 改为输出原版组件,新增 `sourceId`(`${messageId}-text-${index}`)与 `quotedSourceIds`。
- `ComposerControls`:输入框上方 rail 渲染引用卡片,支持移除与点击定位;发送载荷带 `quotes`;只有引用时也可发送。
- `ChatPane`:草稿新增 `quotes`;`quoteTable` 改为挂引用而不是把 markdown 追加进正文;点击卡片回到来源表格并临时置 `data-message-quote-anchor-active`;编辑/重发/重新生成沿用历史引用。
- `MessageBubble`:用户消息内新增只读引用标签(`.cr-context-chips`)。
- `main/ipc.ts`:引用快照写入 `userMessage.quotes`,引用 markdown 随消息一并进入模型提示;空文本但有引用时允许发送。
验证:`scripts/verify-quote-table.cjs` 在真实隔离 Electron(真实 preload/IPC/渲染进程与文件系统)中 48 项断言全部通过,覆盖菜单/按钮几何与配色、`:focus-within` 显隐、已加入描边(`#40d1b3`)、输入区卡片(圆角 10 / padding 8 / gap 8 / 强调条 3px / 16×16 移除按钮 / rail `0 16px 8px` 与 gap 6)、草稿不被覆盖、移除后按钮恢复、`chat:send` 真实 IPC 载荷(正文+引用 markdown+sourceId)、发送后只读标签(22 高 / 圆角 6 / padding 2px 6px / 13px/14px/500 / 只读底色 / `data-content-block-meta-type=message-quote`)、历史重载一致。报告与截图:`.tmp/quote-table-SI0PNC/`(另有 `.tmp/quote-table-yiKDIs/`)。`npm run typecheck`、`npm run test:conversation`、`npm run build` 通过。
遗留:
1. 未取到原版“点击后输入区卡片”和“发送后消息标签”的实际截图与几何:探针在打开的会话里没有找到可引用的表格(`hover .cr-table-block` 返回 "Selected node is absent"),因此这两态是按渲染器源码与回收样式表实现,视觉未与原版逐像素比对。
2. 原版 `--cr-brand-secondary`(以及 `--cr-bg-brand-subtle`、`--cr-border-brand-subtle`)在回收样式表中只有使用、没有定义;同版本 `contexts-BkjwYSZT.css` 给出的兜底值是 `#40d1b3`,YCode 暂按该兜底值定义并已在注释中标注,待取到原版运行时 token 后替换。
3. 输入区引用卡片中的“来源标题”在原版由宿主(`message.quote.add` 处理端)生成,尚未采集;YCode 当前不显示标题,只显示内容摘要,不臆造文案。
### 03. 编辑已发送消息
- [x] 拆解原版编辑入口、编辑容器、文本排版、按钮、焦点与键盘交互。
- [x] 对齐进入编辑、修改、取消、提交及失败状态。
- [x] 验收:编辑正确消息;取消恢复原内容;提交后的消息分支与产物处理符合已确认行为。
状态:主体已实现,并通过真实窗口回归与真实 IPC 回归;工具条淡入/提示出现时序未逐帧采集。
原版证据:
- 渲染器实现(REA 回收 `.tmp/wb-src-DbE1_mgM.js`):`UserMessageEditProvider`、`UserMessageEditor`/`UserMessageEditorContent`(校验规则 `empty`/`too-long`,上限 `1e4`;`message.edit.submit`;错误码映射 `userMessage.edit.error.retryLater`;`RenderNoHandlerError` → `sendFailed`;外部 mousedown 关闭规则与豁免选择器)、`ToolbarRenderer`(`cr-toolbar` = 时间 + 复制 + 恢复此版本 + 编辑;编辑中或已丢弃时不渲染)、`IconButton`、`RevertToBeforeIcon`、`LoadingSpinnerIcon`、`formatMessageTime`。
- 样式:REA 回收样式表 `src-CyXHA0IC.css`(SHA-256 `a5e26b537bb50323aefbf25abddad52e288dd3868598be8d255d70886fe77cfe`)中 21 条 `.cr-user-message-editor*` / `.cr-self-bubble--editing` 规则与 13 条 `.cr-toolbar*` 规则。
- 文案:REA Evidence `ev_717fa5e846e64d67ac19c8925d121bff632c0d3aefb3603b10858559cabb2dcb` 中 `userMessage.edit.*`、`userMessage.action.*`、`markdown.copy`/`markdown.copied` 的 zh-CN 与 en-US。
- 运行时几何与样式:`ev_245ea1740cde21869500348e47cf9663a1ea72943ccfe79c163a6838a153bfd3`(工具条 97.23×28、时间 33.23×20、复制/编辑按钮 24×24、图标 14×14;无产物会话不显示恢复按钮;编辑态气泡 535×110、编辑器 511×94、输入容器 50、页脚 44、提示 369×18、取消 62×32、发送 60×30)、`ev_5dd78e06e75b3a29b656d328c2efc2a820ea197e8204a39840207188a6496a0f`(编辑器保持打开)、`ev_ee345b160e5f520ed866c1059b7c72e77b34e49bf1ce407cd266ea886aa86405`(编辑态布局快照与计算样式:容器透明/无边框/无阴影/`min-height:50px`、宿主 `min-height:64px`、可编辑区 15px/1.75、提示 13/18 `rgba(0,0,0,.5)`、取消边框 `1px rgb(235,235,235)`、发送 `rgb(26,26,26)`/白字、InfoIcon path)、`ev_308764954de03fa28e4a980d609d33eabf794c44ce6733bfe1b83cec36ef562a`(取消关闭并恢复原气泡)。
- 观察范围:桌面浅色主题、单条用户消息;覆盖无产物写入会话(工具条无恢复入口)与含 `write_file` 记录会话(出现恢复入口)。未覆盖:工具条淡入与 tooltip 出现的逐帧时序、未发送/被丢弃消息的“恢复到此版本”状态。
实现:
- `workbuddy/conversation/UserMessageEditor.tsx`:就地编辑器,原版 DOM(`cr-user-message-editor` > `cr-input-container-wrapper`/`cr-input-container`/`cr-input-editor-host` + `[data-slate-editor]` 可编辑区、`__error`、`__footer`/`__hint`/`__hint-icon`/`__actions`/`__cancel`/`__send`);空内容与 10000 字符校验、Enter 提交(Shift+Enter 换行)、提交中禁用按钮并显示 spinner 与 `aria-busy`、失败文案按 `error.retryLater`/`sendFailed` 映射、外部 mousedown 仅在没有改动且未提交时取消。
- `workbuddy/conversation/MessageEditorIcons.tsx`:`RevertToBeforeIcon`、`EditorInfoIcon`、`EditorSpinnerIcon` 按回收源码与运行时 `svg_nodes` 原样复刻。
- `workbuddy/conversation/message-edit-source.css`:补齐 18 条缺失回收规则(含编辑容器 `min-height:50px` 与 `:focus-within` 去阴影以覆盖宿主适配规则);`.cr-self-bubble--editing` 与 `:has(.cr-user-message-editor)` 复用 `source-styles.css` 已有声明。
- `workbuddy/message-actions/UserMessageToolbar.tsx`:`div.cr-toolbar[data-message-id][role=toolbar]`,时间按三档格式显示;复制按钮 2000ms 内切换“已复制”且 tooltip 不因点击隐藏;恢复此版本仅在存在可回退产物时渲染并透传禁用态;编辑按钮受会话忙状态约束;图标按钮为 `button.cr-icon-button[data-action][aria-label]` + `svg.cr-icon-button__icon`。
- `workbuddy/message-actions/message-copy.ts`:抽出用户消息复制回退链,旧 `MessageActionToolbar` 复用同一实现。
- `components/MessageBubble.tsx` / `components/ChatPane.tsx`:新增 `editingMessageId` 与 `startEdit`/`cancelEdit`/`submitEdit`;编辑态用编辑器替换气泡内容并卸载工具条;提交走 `send(..., { fromMessageId, action:'edit' })`;移除底部输入框“编辑消息”横幅与用户消息的“重新发送”入口。
- `main/workspace-revert.ts` 新增 `rollbackEditedArtifacts`;`main/ipc.ts` 的 `chat:send` 在 `action==='edit'` 时先回退产物(无写入记录则跳过;记录不完整则拒绝提交),原生分支失败时撤销文件回退。
验证:`node scripts/verify-user-message-edit.cjs` 在真实隔离 Electron(真实 preload/IPC/渲染进程,`chat:send` 桩记录载荷)中 50 项断言全部通过,覆盖工具条几何/配色/时间格式/按钮集合与图标(copy/revert/edit、14×14、viewBox 16/14)、悬停显隐、进入编辑、编辑器几何与排版(容器 50/宿主 64/可编辑 15px·1.75/提示与按钮尺寸)、取消恢复原内容、有改动时外部 mousedown 不关闭、空内容校验阻断提交、提交中禁用 + spinner + `aria-busy`、`action:'edit'` + `fromMessageId` 真实 IPC 载荷、Enter 提交、无渲染器报错;报告与截图:`.tmp/edit-O1kT3A/`(早期 `.tmp/edit-2MoqPF/`、`.tmp/edit-624Sw3/`)。`npm run test:conversation-ipc` 新增 `testEditArtifactRollback`,覆盖真实主进程语义:产物回退到消息前版本、历史前缀保留并追加替换消息、原生分支失败时撤销文件回退且会话不变、无产物改动可直接编辑、含不可回滚工具时拒绝编辑且文件与会话不变。`npm run typecheck`、`npm run test:conversation`、`npm run test:recovered`、`npm run test:chat`、`npm run build` 均通过。
遗留:
1. 工具条淡入(`opacity .2s`,hover 后 `transition-delay:0s`)与 tooltip 出现时序未逐帧采集,当前按回收 CSS 声明实现,未做像素级时序比对。
2. 原版提交失败的错误码集合(`resend-settle-timeout`、`cancel-barrier`、`send-in-progress` 等)仅有映射表证据;YCode 目前只区分“上一轮未结束”和“其它失败”两类文案。
3. 原版 `userMessage.edit.resume`(恢复到此版本)依赖未发送/被丢弃消息状态,YCode 暂无对应状态,未渲染该按钮(DOM 结构与 CSS 规则已保留)。
4. 原版 `formatMessageTime` 含“昨天 HH:mm”分支,与此前用户确认的三档格式不同;当前沿用用户确认的三档规则,差异待确认。
### 04. 用户消息悬停时间
- [x] 为已发送用户消息补齐悬停显示时间。
- [x] 对齐出现位置、间距、字体、颜色和与操作图标的关系。
- [x] 复用三档时间格式;验证当天、同年异日、跨年、历史重载。
状态:随第 03 项的工具条一并实现并通过真实窗口回归;原版“昨天”分支差异待用户确认。
原版证据:
- 源码(REA 回收 `.tmp/wb-src-DbE1_mgM.js`):`ToolbarRenderer` 的 `span.cr-toolbar__time` 取 `formatMessageTime(props.createTime, locale, t('message.time.yesterday'))`;工具条整体由 `.cr-frame--right:hover` 控制显隐。
- 样式:回收表 `src-CyXHA0IC.css` 中 `.cr-toolbar__time{width:max-content;color:var(--cr-text-tertiary,#00000080);white-space:nowrap;font-size:14px;font-weight:400;line-height:20px}` 与 `.cr-toolbar{gap:8px;padding-top:4px;transition:opacity .2s ease-in-out .15s}`、`.cr-frame--right:hover .cr-toolbar{opacity:1;pointer-events:auto;transition-delay:0s}`。
- 运行时:`ev_245ea1740cde21869500348e47cf9663a1ea72943ccfe79c163a6838a153bfd3`(时间 33.23×20,位于复制按钮左侧,工具条 gap 8)、`ev_ee345b160e5f520ed866c1059b7c72e77b34e49bf1ce407cd266ea886aa86405`(时间计算样式 14px/20px `rgba(0,0,0,0.5)`)。
- 观察范围:桌面浅色主题、当天消息;同年/跨年分支来自源码 `formatMessageTime`,原版“昨天”分支未采用(以用户此前确认的三档格式为准)。
实现:`workbuddy/message-actions/UserMessageToolbar.tsx` 渲染 `span.cr-toolbar__time` 并复用共享 `formatMessageTime`(`components/AssistantMessageDetails.tsx`):当天 `HH:mm`、同年异日 `M月D日 HH:mm`、跨年 `YYYY年M月D日 HH:mm`;位置、间距、字体、颜色与“时间在图标左侧”的关系直接由回收的 `.cr-toolbar` / `.cr-toolbar__time` 规则提供。
验证:`node scripts/verify-user-message-edit.cjs` 57 项断言全 PASS,其中包含时间字号/行高/颜色、当天 `06:32`(HH:mm)、同年异日 `1月2日 09:05`、跨年 `2024年12月31日 09:05`、切换会话后只显示当前会话的时间、历史重载后三档时间保持一致;`npm run test:assistant-footer` 覆盖 `formatMessageTime` 的三档与无效输入。报告:`.tmp/edit-iAc4zi/`。
遗留:
1. 原版 `formatMessageTime` 含“昨天 HH:mm”分支,与已确认的三档规则不同;当前按用户确认的三档渲染,差异待确认。
2. 工具条淡入的延迟切换(默认 `.15s` 延迟、hover 时 `0s`)未逐帧采集。
### 05. 用户消息回退操作与图标
- [x] 移除已发送用户消息上的“重新发送”按钮。
- [x] 替换为“将对话及产物回退到此消息前”操作,图标、提示及交互通过 REA 对照。
- [x] 明确回退边界:该消息之前,而非该消息之后;对话记录与对应产物修改一起处理。
- [x] 验收:多轮对话、文件创建/修改、无产物、运行中禁用、取消确认、回退失败和重启后状态;不得只删除可见消息而保留应回退的文件修改。
状态:主体已实现,并通过真实窗口与真实 IPC 回归;弹窗逐像素几何、动画与失败 toast 尚未与原版比对。
原版证据:
- 桌面端接线(REA Evidence `ev_717fa5e846e64d67ac19c8925d121bff632c0d3aefb3603b10858559cabb2dcb`,脚本 SHA-256 `5f35b7489b107e21ef452c8ee88a95265756f6fc444841eef869228bbc44768b`,item 295):`ConversationTimelineImpl` 组装 `userMessage.actions = { showDefaultRevert: !isSessionActive && transport !== 'cloud', revertLabel: t('rewind.entry.tooltip'), revertEntersEdit: false, hasRevision: e => resolveRevertEntryVisible({ requestId: e.requestId, firstLoadedUserRequestId, hasMoreRequests }), onAction }`;`onAction('revert')` 先校验 `resolveRevertEntryVisible`,再 `M.confirm('rollback', requestId)`,仅当结果不是 `cancel` 才执行 `M.runRewind(requestId)`;`resolveRevertEntryVisible = requestId && (hasMoreRequests || !firstLoadedUserRequestId || requestId !== firstLoadedUserRequestId)`。
- 文案(REA Evidence `ev_e91787b1d4dea651582c6cf12827775b9068b0ee8b80c68ba08d4c1d87d94e90`,同一脚本):`rewind.entry.tooltip`=将对话及产物回退到此消息前、`rewind.dialog.plain.title/desc`、`rewind.dialog.artifacts.title`=将对话及以下产物版本回退到此消息前?、`rewind.dialog.artifacts.desc`=回退暂不支持部分类型文件、`rewind.dialog.noVersion.title/desc`、`rewind.item.restoreAt/restoreUnknown/willDelete/noEarlierVersion`、`rewind.action.cancel/rewind/skipRewind`、`rewind.error.rollbackFailed`=对话回退失败,请稍后重试。
- 工具条运行时几何:`ev_5820293fcc4fdf5acdfad597ae816ac49e0c1b7992e3a024cf75aa9968fe1c84`(3 个 24×24 按钮 x=1093/1125/1157;回退图标 14×14 `viewBox 0 0 14 14`、两条填充 path,与 `RevertToBeforeIcon` 一致)、`ev_245ea1740cde21869500348e47cf9663a1ea72943ccfe79c163a6838a153bfd3`(无产物写入会话只有 copy + edit,含 `write_file` 记录的会话出现第三个按钮)。
- 另一表面(云端/远程会话的 `useUserMessageActions`)使用 `userMessageActions.revertToThisVersion`(“回退到此版本”)并打开 checkpoint 弹窗;本地桌面任务会话(YCode 目标表面)使用上面的 rewind 文案与流程,本项按本地表面复刻。
- 观察范围:桌面端浅色主题、本地传输会话、含 `write_file` 记录的会话与只读会话。未覆盖:云端 checkpoint 弹窗、`rewind.dialog.artifacts` 逐产物 fallback 状态(`no-earlier-version`、`versionDeleted` 等)的真实数据形态、弹窗逐像素几何与动画。
实现:
- `workbuddy/conversation/rewind-labels.ts`:按 zh-CN 逐字回收 `rewind.*` 文案(含 `{time}` 占位替换),并记录两条 Evidence。
- `workbuddy/message-actions/UserMessageToolbar.tsx`:回退按钮的 aria-label/tooltip 由库默认 `userMessage.action.revert`(恢复此版本)改为桌面端 `revertLabel` 的 `rewind.entry.tooltip`。
- `components/ChatPane.tsx`:新增 `rewindEntryVisible`(`requestId` 存在、非首条用户消息、会话不在运行/发送中)与 `rewindPreview`(`artifacts`/`no-version`/`plain` 三变体);回退弹窗按变体渲染标题与说明,产物清单显示文件名、完整路径 tooltip 与状态(将被删除 / 回退至历史版本),按钮为“取消/回退”,提交中禁用并置 `aria-busy`;取消不触发任何 IPC。
- `workbuddy/message-actions/MessageActionToolbar.tsx`:删除用户消息的编辑/恢复/重新发送死分支,用户消息操作只由 `UserMessageToolbar` 承载,界面上不再可能出现“重新发送”。
- `main/ipc.ts`:`chat:revert` 允许无产物版本的“仅回退对话”(对应原版 no-version 变体,产物保持不变),并在消息不存在时明确报错;有产物时仍先回退文件、失败时撤销并保留会话。
- `styles/app.css`:`.rewind-artifacts` 产物清单样式(`max-height:200px`、13px/20px 行、名称省略与完整路径 tooltip、状态右对齐)。
验证:`node scripts/verify-user-message-edit.cjs` 在真实隔离 Electron(真实 preload/IPC/渲染进程)中 67 项断言全 PASS,覆盖按钮集合与标签(复制 / 将对话及产物回退到此消息前 / 编辑)、首条用户消息隐藏回退入口、其余消息显示、会话活动期间回退与编辑入口一并隐藏、弹窗 `artifacts` 变体标题/描述/按钮/产物行(`edited-artifact.txt` · 回退至历史版本)、取消不触发 IPC、确认以 `sessionId` + `messageId` 触发 `chat:revert` 并按回退结果替换消息前缀;报告与截图:`.tmp/edit-kYHO92/report.json`、`.tmp/edit-kYHO92/rewind-dialog.png`。`npm run test:conversation-ipc` 改写 read-only 用例为“无产物版本回退仅回退对话且历史持久化”,连同产物回退、外部修改冲突、原生分支失败撤销、运行中拒绝等主进程语义用例全部通过。`npm run typecheck`、`npm run test:conversation`、`npm run test:recovered`、`npm run test:chat`、`npm run test:assistant-footer`、`npm run build` 均通过。
遗留:
1. 回退弹窗沿用 YCode 现有 modal 样式,未采集原版弹窗(宿主 Modal:标题/正文/产物清单/底部按钮)的几何与动画;待后续按原版逐像素对齐。
2. 原版失败路径以 toast 呈现 `rewind.error.rollbackFailed`(对话回退失败,请稍后重试。);YCode 当前在弹窗内联展示原始错误文本。
3. 原版逐产物 fallback 状态(回退至 {time} 版本 / 历史版本已被删除,将保持当前版本 / 该产物无历史版本,回退后文件仍会保留在目录中)依赖服务端产物版本历史;YCode 只有工具写入前后快照,暂映射“将被删除 / 回退至历史版本”。
4. 原版编辑提交时会先弹 `rewind.edit.*` 询问是否回退产物历史版本(回退 / 不回退),YCode 编辑提交固定回退产物(`rollbackEditedArtifacts`);差异记入 TODO 03 追补。
5. 原版在 `hasMoreRequests`(分页历史未全部加载)时首条已加载消息也可显示回退入口;YCode 全量加载历史,按 `requestId !== 首条用户消息 requestId` 判定。
### 06. 对话区域滚动条
- [x] 对齐宽度、颜色、轨道、圆角、悬停显隐、与内容边缘的间距。
- [x] 检查滚动条占位、长内容、流式跟随底部及用户手动上滚的行为。
- [x] 验收:浅色、深色、短对话、长对话、流式输出与不同窗口尺寸。
状态:已对齐并通过真实窗口回归(像素级比对 + CSSOM + 计算值 + 行为);本轮无需改动实现代码,回收样式表已在位。
原版证据:
- 样式表 `src-CyXHA0IC.css`(SHA-256 `a5e26b537bb50323aefbf25abddad52e288dd3868598be8d255d70886fe77cfe`):`.cr-message-list{scrollbar-gutter:stable;scrollbar-width:thin;scrollbar-color:var(--cr-scrollbar-thumb) transparent;flex:1;min-height:0;overflow-y:auto}`;`::-webkit-scrollbar{width:6px;height:6px}`、`::-webkit-scrollbar-track{background:0 0}`、`::-webkit-scrollbar-thumb{background-color:var(--cr-scrollbar-thumb);border-radius:3px;transition:background-color .2s}`、`::-webkit-scrollbar-thumb:hover{background-color:var(--cr-scrollbar-thumb-hover)}`。
- token 链:`--cr-scrollbar-thumb: var(--cr-internal-scrollbar-thumb)`;浅色 `#0003` / `#00000052`,深色 `#fff3` / `#ffffff52`。
- 空闲隐藏由库选项 `hideScrollbarWhenIdle`(默认 `false`)驱动 `useScrollIdleVisibility`(3s 无滚动加 `cr-message-list--scrollbar-idle`,滚动时移除);WorkBuddy 应用包(脚本 SHA-256 `5f35b748…` 的 item 295)未传该选项,运行时截图也没有该 class,故原版不启用空闲隐藏,YCode 同样不实现。
- 运行时光栅证据:REA Evidence `ev_5820293fcc4fdf5acdfad597ae816ac49e0c1b7992e3a024cf75aa9968fe1c84` 的 `workbuddy.png`:滑块占据 x=1328..1333(6px),颜色 `rgb(204,204,204)`(即 `#0003` 叠白),轨道透明,槽位右侧留 2px 空白。
- 观察范围:浅色主题、1336×1240 视口、长会话。未覆盖:原版 hover 态与深色主题的运行时像素、原版槽位宽度的直接测量(只能由像素推断)、不同窗口尺寸下的原版像素。
实现:无代码改动——`ChatPane` 的滚动容器为 `.chat-scroll.cr-message-list`,回收样式表 `workbuddy/conversation/source-styles.css` 已包含上述全部规则;`flex:1/min-height:0/overflow-y:auto` 与自适应宿主一致。本项补齐可复跑的验收脚本。
验证:新增 `scripts/verify-conversation-scrollbar.cjs`(真实隔离 Electron + 真实 preload/IPC/渲染进程),24 项断言全 PASS:
- 样式契约:`scrollbar-width:thin`、`scrollbar-gutter:stable`、`overflow-y:auto`、实际槽位 10px;CSSOM 中 6px 宽度、透明轨道、`var(--cr-scrollbar-thumb)` + 3px 圆角 + `.2s` 过渡、hover 使用 `--cr-scrollbar-thumb-hover` 均按回收声明存在。
- 计算值:浅色 `rgba(0, 0, 0, 0.2) rgba(0, 0, 0, 0)`、深色 `rgba(255, 255, 255, 0.2) rgba(0, 0, 0, 0)`(与 `#0003`/`#fff3` 一致)。
- 像素:滑块 6 列 x=1328..1333、`204,204,204` 合成色、轨道列(1324..1327、1334..1335)保持纯白——与原版测量列完全一致。
- 行为:长会话加载即贴底;流式增量期间保持贴底;用户上滚后不再强制跟随(偏差 < -80px);回到底部后恢复跟随;1100×700 与 1600×1000 两种窗口尺寸下槽位与轨道契约不变;短对话不溢出且仍预留稳定槽位;空闲 3.4s 不出现空闲隐藏 class;无渲染器报错。
- 报告与截图:`.tmp/scrollbar-fpB0Vi/report.json`、`.tmp/scrollbar-fpB0Vi/scrollbar-early.png`。
遗留:
1. 原版 hover 态滑块颜色(`#00000052` / `#ffffff52`)与深色主题未采集运行时像素,当前以回收声明与计算值对齐。
2. 原版槽位宽度无法直接从 layout 证据测得(内容列受 `max-width` 约束),只能由像素推断;YCode 实测槽位 10px、可见滑块位置与原版一致。
3. 原版滚动条附近的其他 affordance(如“回到底部”控件)未纳入本项回归。
### 07. 侧栏最下一行
- [ ] 移除最下方不应存在的“收起菜单”入口。
- [ ] 对齐最下一行的布局、高度、内边距、字体、头像、当前图标与悬停状态。
- [ ] 验收:普通/窄侧栏、浅色/深色下均无残留入口或空白占位。
状态:待 REA 对照。
### 08. 新建任务发送后的立即切页与占位
- [ ] 盘点发送到创建会话、准备环境、接收首个事件之间的阻塞位置。
- [ ] 对照原版发送后的页面切换时机与等待状态。
- [ ] 发送后立即进入消息页面并显示用户消息;启动较慢时显示合适的助手占位/准备状态。
- [ ] 验收:慢启动、正常启动、发送失败、停止、切换任务;不等到模型输出后才切页,不重复创建会话或丢失草稿。
状态:待 REA 对照与发送状态链路排查。
### 09. 账户菜单与页面
- [ ] 通过 REA 对齐点击当前登录账户后的入口、弹层位置、布局、交互及页面风格。
- [ ] 内容按用户指定范围:头像与名称、套餐、余额、升级套餐、购买积分、设置、外观、记忆与进化、检查更新、退出登录。
- [ ] 逐项盘点现有数据和功能,区分可直接接入、待实现与依赖服务端;不以虚构余额、套餐或成功提示代替真实能力。
- [ ] 验收:已接功能实际生效,弹层关闭与导航返回正常,浅色/深色一致;内容不要求逐项照搬原版账户菜单。
状态:待 REA 拆解;菜单内容范围已确定。
## 设置
### 10. 通用
- [ ] 拆解原版通用设置页面的布局、控件和交互。
- [ ] 将 YCode 当前已经支持的内容接入对应控件,记录暂未支持的差异。
- [ ] 验收:控件反映真实配置;修改即时生效或明确提示生效时机,重启后持久化正确。
状态:待 REA 拆解与能力盘点。
### 11. 外观与浅色/深色主题
- [ ] 对齐原版外观页面及主题切换交互;当前只保留浅色、深色两种选择。
- [ ] 梳理原版主题切换会改变的 token、样式、资源和组件状态。
- [ ] 统一主窗口、设置窗口、独立任务窗口、弹层、输入区、对话、代码/表格/工具结果和右侧栏的主题响应。
- [ ] 验收:即时切换、跨窗口同步、重启持久化;所有已接页面无浅深混色和不可读内容。
状态:待 REA 对照与主题覆盖审计。
### 12. 快捷键页面与真实功能
- [ ] 拆解页面布局、分组、按键显示、编辑/恢复默认等实际存在的交互。
- [ ] 建立快捷键 → 命令 → 实际动作映射,按 REA 证据确认支持范围。
- [ ] 验收:展示按键与实际绑定一致;输入框、编辑器、弹层、独立窗口中的作用域和冲突处理正确;可修改项持久化。
状态:待 REA 拆解与命令绑定盘点。
### 13. 个性化页面与真实功能
- [ ] 拆解原版页面、字段、说明、保存/启停等交互。
- [ ] 将支持的个性化配置接入实际运行链路,确认在哪些新建/既有会话中生效。
- [ ] 验收:修改与持久化有效;界面显示与实际行为一致;未接能力明确记录,不用占位控件宣称完成。
状态:待 REA 拆解。
### 14. 记忆与进化
- [ ] 记录待拆解:入口、页面、数据、读写机制、会话生效方式及生命周期。
状态:待拆解,本轮不自动展开实施。
### 15. 智能体页面:团队管理
- [ ] 拆解原版智能体设置页面,本轮仅对接“智能体团队管理”。
- [ ] 根据 REA 证据梳理团队列表、详情及管理操作,将需要的真实存储/配置链路接入。
- [ ] 验收:仅展示已确定范围;管理操作实际生效、重启后可恢复;团队管理与真实子代理调度的完成度分别记录。
状态:待 REA 拆解;范围限定为团队管理。
### 16. 移除助理与设备连接
- [ ] 移除设置中的“助理”“设备连接”导航和页面入口。
- [ ] 清理默认选中、内部导航、深链接/旧配置回退中的无效目标。
- [ ] 验收:设置中不再出现这两项,旧导航目标不会导致空白页。
状态:待实施;范围仅为用户指定的设置入口,不据此删除其他模块功能。
### 17. 移除数据管理与应用管理
- [ ] 移除设置中的“数据管理”“应用管理”导航和页面入口。
- [ ] 清理相关无效导航与页面占位。
- [ ] 验收:入口完全移除且其余设置导航正常;不删除已有用户数据或已安装内容。
状态:待实施。
### 18. 安装中心
- [ ] 记录待拆解:入口、页面结构、安装来源、安装/更新/卸载流程及与其他能力中心的关系。
状态:待拆解,本轮不自动展开实施。
### 19. 关于与获取帮助
- [ ] 通过 REA 复刻“关于”“获取帮助”的布局、字体、图标、间距和交互外观。
- [ ] 不复制原版跳转链接;逐项标注 YCode 自有入口或尚未配置的跳转。
- [ ] 验收:本应用版本等信息真实;没有误跳 WorkBuddy 官方账户、帮助或其他服务地址。
状态:待 REA 对照;布局纳入范围,原版链接排除。
## 后续模块
### 20. 定时任务、资料库、更多中的项目
- [ ] 定时任务:待拆解入口、页面、任务配置、触发/执行记录及生命周期。
- [ ] 资料库:待拆解入口、资料组织、添加/读取/检索及会话引用方式。
- [ ] 更多 → 项目:待拆解入口、项目组织、工作区/任务关系及管理操作。
状态:三个模块均待拆解,本轮不自动展开实施。
## 追加需求
### 21. 对话框 Git 分支检测与会话上下文信息
- [ ] 通过 REA 拆解 WorkBuddy 对话框中 Git 分支和会话上下文信息的显示位置、图标、字体、间距、提示及交互。
- [ ] 根据当前任务绑定的工作目录检测 Git 仓库和实际分支;核对原版对非 Git 目录、未产生首次提交、detached HEAD、检测失败等状态的处理。
- [ ] 明确原版“上下文信息”的实际字段、数据来源、更新时机和展示方式,再接入 YCode 的真实会话数据;上下文用量等字段如存在,必须区分真实统计与估算。
- [ ] 验收:新建任务、已有会话、切换空间/任务、外部切换 Git 分支后的信息归属与刷新正确;无仓库时不显示虚构分支;浅色/深色及窄窗口布局与原版对齐。
状态:待 REA 拆解与现有能力盘点;本项仅加入 TODO,尚未实施。
## 推进顺序
1. 对话与侧栏:01 → 02 → 03 → 04 → 05 → 06 → 07 → 08 → 09 → 21。
2. 设置:先落实 16、17 的入口范围,再依次推进 10 → 11 → 12 → 13 → 15 → 19。
3. 14、18、20 保留为待拆解,后续单独展开。
## 每项交付记录模板
- 当前状态:待拆解 / 证据已齐 / 方案已明确 / 实现中 / 已实现未验收 / 已验收 / 有阻碍。
- 原版证据:版本、REA Evidence ID、观察范围、未覆盖状态。
- YCode 差异与方案:具体问题、涉及模块、数据与交互边界。
- 实现:修改文件、真实功能、占位或未接部分。
- 验证:功能回归、实际窗口交互、浅色/深色、相关截图/几何/像素结果及限制。
- 遗留:尚未解决的差异与下一步所需证据。