# 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. 侧栏最下一行 - [x] 移除最下方不应存在的“收起菜单”入口。 - [x] 对齐最下一行的布局、高度、内边距、字体、头像、当前图标与悬停状态。 - [x] 验收:普通/窄侧栏、浅色/深色下均无残留入口或空白占位。 状态:已对齐并通过真实窗口回归(运行时几何 + 计算值 + hover 目标色);收起入口只在顶栏保留一处。 原版证据: - 运行时布局 REA Evidence `ev_721d830c97114930e046ec8931bd2f473a11ab23efcab9c727c4256889e29879`:`.conversation-list` 宽 284.28(含 border-right 1px);`.conversation-list-footer` `[0,845,283.28,57]`、padding 8/12/8/8、border-top 1px `rgb(230,230,230)`、display flex + align-items center + justify-content flex-start;`.user-menu-trigger-wrapper` `[8,854,263.28,40]`、gap 4;`.user-menu-trigger--workbuddy` `[8,854,191.28,40]`、min-height 40 / padding 6px 8px / radius 8;`.user-menu-trigger-left` gap 10;头像 28×28 圆形;姓名 12px/600/12px;`.msg-center-bell-btn` 与 `.user-menu-trigger-miniprogram` 各 32×32 / radius 6。 - 回收样式表 `contexts-BkjwYSZT.css`(`.conversation-list-footer{...}`、`.conversation-list-footer .user-menu{width:100%}`)与 `UserMenu-CpHz-0rF.css`(`.user-menu-trigger*`、`.user-menu-trigger--workbuddy:hover{background-color:var(--wb-bg-hover)}`、`.msg-center-bell-btn:hover{background-color:var(--wb-button-ghost-bg-hover);color:var(--wb-icon-primary)}`、`.msg-center-badge{...}`、`.user-menu-avatar-initial{background-color:#0056d4}`)。 - 同一证据中侧栏收起源位于顶栏 `.conversation-list-topbar-actions`(`[8,3,76,24]`,3 个 24×24,x=8/34/60);底部该行只有账号 / 通知 / 小程序三个入口。 - 观察范围:桌面端浅色主题、zoom=1、1336 宽窗口。未覆盖:深色主题运行时像素、原版真实头像图片。 实现: - `components/Sidebar.tsx`:底部账号区(`.sidebar__footer.conversation-list-footer`)只保留账号触发器、通知铃铛、小程序三个入口;删除底部“收起侧栏”按钮及随之无引用的 `IconCollapseRail`。 - `styles/sidebar.css`:逐条落地回收规则(footer padding/边框/flex、wrapper gap/宽度、触发器 min-height/padding/radius/`background-color .2s`、左组 gap 10、头像 28×28 圆形 + `#0056d4` 字面头像、姓名 12/600/12 省略号、铃铛与小程序 32×32/radius 6/`background-color, color .15s`、角标 14×14/radius 7/top 2/right 2/translate(40%,-30%));hover 直接使用回收 token `--wb-bg-hover`、`--wb-button-ghost-bg-hover`、`--wb-icon-primary`。 - `workbuddy/workbench/source-panel-layout.ts`:展开态侧栏宽度 280 → 284,使整列与 footer 边界对齐原版 284.28(实测 footer `[0,845,283,57]`、wrapper `[8,854,263,40]`、触发器 191×40)。 - 顶栏既有“收起侧边栏”入口(24×24)保持不变;折叠后由 `.sidebar__rail` 的“展开侧栏”恢复。 验证:新增 `scripts/verify-sidebar-footer.cjs`(真实隔离 Electron + 真实 preload/IPC/渲染进程)29 项断言全 PASS: - 布局:footer padding 8/12/8/8、flex 契约、border-top 1px `rgb(230,230,230)`、高 57;wrapper gap 4 且子元素恰为账号 / 通知 / 小程序;footer 内不存在任何“收起”入口。 - 组件:账号触发器 min-height 40 / padding 6px 8px / radius 8 / 过渡 `background-color .2s`、宽 191;左组 gap 10;头像 28×28 圆形 `rgb(0,86,212)`;姓名 12/600/12 + 省略号;铃铛 32×32 / radius 6 / `rgba(0,0,0,.7)` / `.15s`;小程序 32×32 / radius 6;角标几何与配色(`rgb(246,64,65)`、top/right/translate)。 - hover:先留档“过渡冻结在起始值”现象(`playState: running`、`currentTime: 0`,QA 窗口无合成帧),随后关闭过渡读取目标色——铃铛 hover 背景等于 `--wb-button-ghost-bg-hover` 计算值 `rgba(0,0,0,0.06)`、图标色等于 `--wb-icon-primary` `rgba(0,0,0,0.9)`;账号触发器 hover 背景等于 `--wb-bg-hover` 计算值 `color(srgb 0 0 0 / 0.05)`。 - 收起入口:顶栏 24×24 按钮仍可折叠侧栏,折叠轨道保留“展开侧栏”。 - 回归:侧栏宽度变更后 `node scripts/verify-conversation-scrollbar.cjs`、`node scripts/verify-user-message-edit.cjs` 仍全 PASS;`npm run typecheck`、`npm run build` 通过。 - 报告与截图:`.tmp/sidebar-footer-3edCU8/report.json`、`.tmp/sidebar-footer-3edCU8/sidebar-footer.png`。 遗留: 1. 侧栏宽度取整数 284,与原版运行时 284.28 存在 0.28px 分形残差(四舍五入后可见差异为 0)。 2. 原版头像为真实图片(`.user-menu-trigger-avatar-img:after` 还有依赖 `--wb-avatar-fallback-*` 的 1px 内描边);YCode 无账号体系,用 `#0056d4` 字面初始头像且未接内描边。 3. 深色主题底部行未采集运行时像素,仅按回收 token(white-6% / white-10%)对齐。 4. 通知角标数据与小程序跳转为 mock(属 TODO 09 与待拆解项),本项只对齐入口与样式。 ### 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 差异与方案:具体问题、涉及模块、数据与交互边界。 - 实现:修改文件、真实功能、占位或未接部分。 - 验证:功能回归、实际窗口交互、浅色/深色、相关截图/几何/像素结果及限制。 - 遗留:尚未解决的差异与下一步所需证据。