Files
ycode/docs/复刻待办清单-2026-10-17.md
T
xiaohan.yuan 0dc088f1f7 feat(settings): replicate the WorkBuddy personalization panel and wire identity, tone and prompts (TODO 13)
Recover the WorkBuddy 5.8.3 个性化 page from REA evidence (PersonalizationPanel-D16rRGjy.css + tokens): 45 module rules plus scoped light/dark tokens, the five-card 1160px layout (identity card 638x100 with inline editors, reply preference card 638x204, three 638x264 long-text cards with 598x160 previews) and the 640x520 editor modal.

Persist identity, tone, welcome tips, custom instructions, persona and long-term memory in config.json, expose personalization:get/update over IPC, and append the resulting personalization context to each turn's prompt for both the OMP and built-in kernels. Wire 欢迎语 to the streaming loading tips and keep 显示文件修改过程 visibly disabled because YCode has no incremental file-change renderer yet.

Verify with scripts/verify-personalization-settings.cjs: 29 assertions covering geometry, tone options, switches, inline identity editing with blur-discard, editor modal save/cancel, config persistence, reopen, dark surfaces and no renderer errors. Add a pure prompt-builder regression and keep every existing settings regression green.
2026-10-17 10:46:40 +08:00

579 lines
91 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. 侧栏最下一行
- [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. 新建任务发送后的立即切页与占位
- [x] 盘点发送到创建会话、准备环境、接收首个事件之间的阻塞位置。
- [x] 对照原版发送后的页面切换时机与等待状态。
- [x] 发送后立即进入消息页面并显示用户消息;启动较慢时显示合适的助手占位/准备状态。
- [x] 验收:慢启动、正常启动、发送失败、停止、切换任务;不等到模型输出后才切页,不重复创建会话或丢失草稿。
状态:已实现并通过真实窗口回归(发送即切页 + 乐观用户消息 + 启动占位 + 真实回合替换 + 失败/停止/切换任务)。
阻塞位置盘点(YCode 现状):
- 渲染进程 `stores/chat.ts` 的 `send()` 在无会话时依次 `await session.create` → `await chat.send`,旧实现只有两步都完成后才把用户消息与助手占位写入 `messages`,因此「点了发送什么也不动」直到回合就绪。
- 主进程 `chat:send` 在返回前要完成:附件/上下文准备、`createCapabilitySnapshot`、`getOmpKernel`(运行环境启动,本轮实测约 1.9–2.3 s)、`sessions.startTurn`;模型回合本身在后台推进,不属于返回前的阻塞。
原版证据:
- 启动阶段文案:REA `ev_717fa5e846e64d67ac19c8925d121bff632c0d3aefb3603b10858559cabb2dcb`(WorkBuddy 5.8.2,`contexts-BMeWSUHk.js`,SHA-256 `5f35b7489b107e21ef452c8ee88a95265756f6fc444841eef869228bbc44768b`):`chat.prepare.<stage>` 表与显示逻辑见 `docs/对话启动提示文案-2026-10-16.md`——阶段文案渲染在流式状态栏主文案位置,进入终态/失败/非 idle/MCP 进度后隐藏,其余回落「思考中」。本次占位使用 `acquiring_runtime` =「正在启动对话运行环境…」(用户确认沿用 5.8.2 已有内容,不重新采集)。
- REA 采集限制(已核到实现层):visual probe 的 `text` 动作要求 enabled text/search `INPUT`,`key` 动作对可编辑内容上的 Enter/Space 直接拒绝(`.tmp/rea-css-runtime/dist/browser/CdpElectronVisualProbe.js`;schema `.tmp/rea-css-runtime/dist/domain/javascript/ElectronVisualProbeSchema.js`)。WorkBuddy 新建任务编辑器是 `DIV[role=textbox]._editable_1cxd2_1`,因此无法用 REA 驱动发送并抓取「发送后」逐帧等待态;本项不通过其它通道查看/驱动原版。三次采集(`ev_a492a83d…`、`ev_150e8217…`、`ev_5b13ec7d…`)与限制说明见 `.tmp/todo08-wb-new-task/notes.md`。
- 观察范围:桌面端浅色主题、本机 5.8.3 运行时(文案表来自 5.8.2 已回收证据)。未覆盖:原版发送后逐帧顺序与各段时长。
实现:
- `stores/chat.ts`:无会话发送时先落地乐观的「用户消息 + 助手占位」(`local-user-*` / `local-assistant-*`,占位带 `prepareStage: acquiring_runtime` 与 `turnStartedAt`),随后才 `await session.create` / `chat.send`;`newSession(context, seedMessages)` 允许把乐观消息带进新会话;真实结果到达时先过滤 `local-*` 再追加真实用户消息与占位,避免重复;失败时移除乐观消息并写入 `error`。
- `components/ChatPane.tsx`:`submit()` 在发送前清空输入框,失败时把草稿恢复到当前所有者键(会话创建后草稿已迁移到会话 id);消息非空即离开首页布局(`isHome = currentId === null || messages.length === 0`)。
- `workbuddy/conversation/prepare-phases.ts`(新增)与 `StreamingFooter` 的 `prepareText`:按回收的 `chat.prepare` 表渲染「正在启动对话运行环境…」替换「思考中」,真实回合一到位即自动回落。
- `shared/types.ts`:`ChatMessage.prepareStage`(仅渲染进程启动占位使用,不持久化)。
验证:新增 `scripts/verify-new-task-switch.cjs`(真实隔离 Electron + 真实 preload/IPC/渲染进程 + 真实 OMP + 受控本地上游)30 项断言全 PASS:
- 计时(点击发送为 t0):对话页、用户消息、启动占位、「已处理」计时均在 **+26 ms** 出现;启动占位在 **+1.9 s** 让位给真实回合,真实回复在 **+2.6 s** 渲染(另一次跑分 +23.8 ms / +2.27 s / +2.97 s)——占位确实覆盖了运行环境启动窗口。
- 不重复:一次发送只创建 1 个会话;回合结束后 `.cr-self-bubble` 恰好 1 条(无乐观+真实重复);占位在真实回合出现前清除。
- 发送失败(清空模型注册表后发送):草稿恢复为原文、无残留乐观消息、错误「请先添加并选择自定义模型」显示、回到新建页、无启动占位。
- 停止与切换任务:回合运行中切到新任务再切回,消息与运行状态都在;点击停止后助手消息状态为 `cancelled`、取消指示可见、无残留占位、仍只有 1 条用户消息。
- 回归:`npm run typecheck`、`npm run build`、`npm run test:chat`、`npm run test:conversation`、`npm run test:conversation-ipc`、`node scripts/verify-user-message-edit.cjs` 全部通过。
- 报告:`.tmp/new-task-switch-641vdN/report.json`(另有 `.tmp/new-task-switch-TX5VSX/`)。
遗留:
1. 原版「发送后」逐帧等待态(先后顺序、每段时长)无 REA 运行时证据(探针限制见上),本项只对齐可证部分。
2. 发送失败时仍会留下一个空会话(`session.create` 已成功、回合未开始);原版在准备失败时是否保留会话未采集。
3. 启动阶段目前只使用 `acquiring_runtime` 一条;原版多阶段(expert → … → checking_launch_config)的发出方、顺序与时长未采集,不按字符串表臆造。
4. 发送窗口内没有「停止」入口(`停止` 只在回合运行后出现,沿用既有实现);原版在准备阶段是否可直接取消未采集。
### 09. 账户菜单与页面
- [x] 通过 REA 对齐点击当前登录账户后的入口、弹层位置、布局、交互及页面风格。
- [x] 内容按用户指定范围:头像与名称、套餐、余额、升级套餐、购买积分、设置、外观、记忆与进化、检查更新、退出登录。
- [x] 逐项盘点现有数据和功能,区分可直接接入、待实现与依赖服务端;不以虚构余额、套餐或成功提示代替真实能力。
- [x] 验收:已接功能实际生效,弹层关闭与导航返回正常,浅色/深色一致;内容不要求逐项照搬原版账户菜单。
状态:已按回收几何/样式实现并通过真实窗口回归(63 项断言);设置与外观接入真实设置窗口,账号/计费/更新类入口明确标注未接入。
原版证据:
- 打开态运行时布局 REA Evidence `ev_95a39af88081a641961779c55d5855e0e3d57889e5d2ccad2c3dc15e26e1c8bb`(WorkBuddy 5.8.3,视口 1336×1240,736 个节点):popover 根 `[8,607,320,577]`、`placement-top`、宽度 320、`max-width:calc(100vw - 24px)`(计算值 1312px)、`max-height:calc(100vh - 32px)`、`overflow:hidden auto`、padding 8、gap 8、圆角 16、背景 `rgb(247,247,247)`、`border-top-width` 计算值 1px(声明 `.5px`)、边框色 `rgb(222,222,222)`、阴影 `rgba(0,0,0,.04) 0 6px 24px 0, rgba(0,0,0,.04) 0 4px 6px 0`、字体 14/400/22、`role="menu"`;条目窄条 `.user-menu-item` 显式 `role="button"`(attributes 仅记录 class/id/role)。
- 同证据结构:`.user-menu-section` `[17,616,302,72]`(白卡 radius 8 / padding 8);`.user-menu-header` `[25,624,286,56]`(min-height 56 / padding 8 / gap 8)、头像框 `.user-menu-header-avatar` `[33,632,40,40]`、名称 `.user-menu-header-name-text` 16/500/24、`.user-menu-header-copy-uid` 20×20 默认 `opacity:0`;`.user-menu-billing-summary` `[17,696,302,102]` + 两个 `.user-menu-billing-cell` `[25|170,704,141,86]`(padding `4px 8px 8px`、title 12/400/20 `rgba(0,0,0,.5)`、value 14/500/22 + `tabular-nums`、`.user-menu-billing-cell-action` margin-top 8 / 高 24);`.user-menu-items` `[25,814,286,307]` gap 2、条目 `[25,*,286,32]`(padding `5px 8px`、radius 8、gap 8、`justify-content:space-between`、图标 16×16);`.user-menu-footer` `[25,1127,286,40]`(margin-top 6 + padding-top 8 + `:before` 1px `var(--wb-border-subtle)`);`::-webkit-scrollbar` 6px / thumb `var(--wb-scrollbar-thumb)` / radius 999。
- 同证据反证:736 个节点中没有全屏遮罩节点,也没有 overlay/mask/scrim/dismiss 类;因此原版不是靠全屏遮罩关闭,本实现不做 overlay(否则会吞掉外部点击的第一次交互)。
- 辅助证据:`ev_4162472c…`(5.8.2 账户菜单截图,`.tmp/rea-assessment-user-menu/frame-000.png`)、`ev_c9144986…`(5.8.3 打开→Escape 帧,`.tmp/rea-account-menu-20261017/`)、`ev_1e775995…`(只打开不关闭,`.tmp/rea-account-menu-open-20261017/`)。
- 回收样式表:`UserMenu-CpHz-0rF.css`(`.user-menu-popover`、`.user-menu-section`、`.user-menu-header*`、`.user-menu-billing-cell*`、`.user-menu-items`、`.user-menu-item*`、`.user-menu-separator`、`.user-menu-footer`、`.user-menu-avatar-initial{background-color:#0056d4}`)与 `tokens-Df-i-zsO.css` / `src-CBaV_A3S.css`(`--wb-bg-popover`:浅 `var(--wb-palette-white-100)` / 深 `#242424`,`.user-menu-popover` 内改写为 `var(--wb-bg-secondary)`;`--wb-popover-radius:var(--wb-radius-2xl)`=16px;`--wb-bg-card` 浅 `white-100` / 深 `#242424`;`--wb-border-subtle` 浅 `gray-3` / 深 `color-mix(in srgb, white 6%, transparent)`;`--wb-dropdown-item-bg-hover` 浅 `#f2f2f2` / 深 `#2e2e2e`;`--wb-scrollbar-thumb` 浅 `black-20` / 深 `white-20`、`--wb-scrollbar-thumb-hover` 浅 `black-30` / 深 `white-30`;`--wb-popover-shadow` 浅 `0 6px 24px 0 #0000000a, 0 4px 6px 0 #0000000a` / 深 `0 6px 24px -4px #0006, 0 4px 6px -8px #0003`)。
- 探针(可复跑):`scripts/rea/probe-account-menu-20261017.json`(打开 + 稳定帧)、`probe-account-menu-open-20261017.json`、`probe-account-menu-close-20261017.json`(Escape 关闭)。REA 的 layout 快照在 inspect 开始时抓取,早于探针动作,因此打开态证据需要「菜单已处于打开态再采集」。
- 观察范围:桌面端 5.8.3 浅色主题、zoom=1、1336 宽窗口,账户菜单打开态。未覆盖:原版深色主题运行时像素、原版条目 SVG 路径、账号/计费服务返回的真实数值、外部点击与 Escape 之外的关闭路径。
实现:
- `workbuddy/user-menu/AccountMenu.tsx`(新增):`createPortal` 到 `document.body`,根节点 `.ycode-account-menu` 类名按证据拼成 `wb-popover wb-popover--placement-top user-menu-popover user-menu-popover--local user-menu-popover--portal`;`useLayoutEffect` 按 `placement-top` 落位(左边缘对齐触发器、底边距触发器上沿 8px,并按视口夹紧,随 resize 重算);关闭沿用仓库既有 popover 约定(`document` 上的 `pointerdown` 外部判定 + 捕获阶段 Escape,Escape 后焦点回到触发器)。
- `workbuddy/user-menu/account-menu-source.css`(新增):逐条落地回收规则并把 8 个侧栏作用域缺失的 token 按回收取值补齐;所有规则收敛在 `.ycode-account-menu-scope` 下,避免与其它 `.wb-popover` 作用域互相污染。
- `workbuddy/user-menu/account-menu-icons.tsx`(新增):设置/外观/记忆与进化/检查更新/退出登录 5 个 16×16 线性图标,暂用 Lucide(MIT)占位并在文件头注明原版路径待回收。
- `components/Sidebar.tsx`:底部账号触发器改为打开账户菜单(`aria-haspopup="menu"`、`aria-expanded`,记录触发器几何供 popover 落位);收起侧栏时关闭菜单;菜单渲染在 footer 内(portal)。
- 内容与真实性:头部=mock 账号头像与名称(副标题标注「账号为 mock 数据,尚未接入登录」);计费摘要=套餐/余额两格,值显示「未接入」,升级套餐/购买积分按钮 `disabled` 并带「尚未接入账号与计费服务」提示;设置 → `openSettings('model')`、外观 → `openSettings('appearance')`(值跟随当前主题,显示浅色/深色);记忆与进化、检查更新、退出登录标注「待拆解」/「未接入」,点击只提示,不假装成功。
验证:新增 `scripts/verify-account-menu.cjs`(真实隔离 Electron + 真实 preload/IPC/渲染进程 + 真实设置窗口)63 项断言全 PASS:
- 几何/样式:popover 320 宽、左边缘与触发器对齐(实测 x=8)、底边距触发器上沿 8px(popover bottom 846 / 触发器 top 854)、padding 8 / gap 8 / radius 16、浅色背景 `rgb(247,247,247)`、边框计算值 1px `rgb(222,222,222)`、双层阴影、`overflow:hidden auto`、`max-width` 1312px、`max-height` 870px(视口 902)、`role=menu`;三张卡片 302 宽 / padding 8 / radius 8 / 白底。
- 头部与计费:min-height 56 / padding 8 / gap 8、头像框 40×40、初始头像圆形 `rgb(0,86,212)`、名称 16/500/24 且等于 mock 账号名;两个计费单元各 141×86、padding `4px 8px 8px`、title 12/400/20、value 14/500/22、动作行 margin-top 8 / 按钮高 24 / `disabled`、文案「升级套餐」「购买积分」;值恰为「未接入」,整份菜单文本不含任何数字(不虚构套餐/余额/积分)。
- 条目与 footer:4 个条目各 32 高 / `5px 8px` / radius 8 / gap 8 / space-between / 14/400/22 / 图标 16×16 / `role="button"`;设置显示 `Ctrl+,`、外观显示当前主题、未接入行显示「待拆解」「未接入」且 `aria-disabled="true"`;footer margin-top 6 + padding-top 8 + 1px 分隔线(`rgb(242,242,242)`)、退出登录行 32 高。
- 交互:触发器点击开/再点关、Escape 关闭并把焦点交还触发器(`aria-expanded` 同步为 false)、外部真实鼠标点击关闭且同一次点击不被吞(点通知铃铛 → 菜单关 + 通知面板开)、设置行复用并导航原生设置窗口到模型面板、外观点亮外观面板。
- 浅色/深色:通过设置窗口切深色后 popover 背景 `rgb(41,41,41)`、卡片 `rgb(36,36,36)`、边框 `rgb(61,61,61)`、阴影切换为深色 token,「外观」行值同步为「深色」;切回浅色后 `documentElement.dataset.theme` 与 `localStorage['ycode:theme']` 均为 light。
- 失败路径:未接入行点击后只显示提示、不新开窗口。
- 回归(单独串行执行,避免多进程 Electron 抢焦点):`npm run typecheck`、`npm run build`、`npm run test:chat`、`npm run test:conversation`、`npm run test:conversation-ipc`、`node scripts/verify-sidebar-footer.cjs`、`node scripts/verify-user-message-edit.cjs` 全部通过。
- 报告与截图:`.tmp/account-menu-Y1FW3I/report.json`、`account-menu-light.png`、`account-menu-dark.png`。
遗留:
1. 原版条目 SVG 路径未回收,5 个图标先用 Lucide(MIT)占位,待 REA 回收后替换。
2. 账号、套餐、余额、升级套餐、购买积分、检查更新、退出登录均依赖 YCode 不存在的账号/计费/更新服务,按「不渲染无效能力」原则保持未接入并显式标注;原版这些位置显示服务返回的真实数值。
3. 用户指定范围之外的原版组件未实现:Buddy 加油站 / 去邀约 / 成长计划 / 意见反馈、`.user-menu-header-copy-uid`(复制 UID,默认 `opacity:0`)、子菜单(`.user-menu-popover--portal .user-menu-submenu-wrapper`)。
4. 头部比原版高 4.19px(原版 56 只有名称行,本实现多一行「账号为 mock 数据」副标题),条目区比原版矮(原版 369 / 本实现 196,因未实现上述范围外条目),popover 总高因此为 408 而非 577。
5. 原版深色主题未做运行时像素采集,深色按回收 token 对齐(popover `#292929`、卡片 `#242424`)。
6. 原版外部点击与 Escape 之外的其他关闭路径(滚动、窗口失焦等)未采集。
## 设置
### 10. 通用
- [x] 拆解原版通用设置页面的布局、控件和交互。
- [x] 将 YCode 当前已经支持的内容接入对应控件,记录暂未支持的差异。
- [x] 验收:控件反映真实配置;修改即时生效或明确提示生效时机,重启后持久化正确。
状态:已实现并通过真实窗口回归;未接入项按「保持原版外观 + 明确标注」处理,逐项记录在下方。
原版证据:
- REA `ev_a2dbeb23e30b9770743e857279a2e43da38fcc48d10612f75ace2938c5b29114`(WorkBuddy 5.8.3 设置→通用面板,900×680,自顶向底滚动采样 0/400/795/0,帧 frame-000~003):16 行文案、控件类型与取值、分组标题(常规/权限/存储/通知/隐私)、滚动边界。
- REA `ev_2309de12a003fca2c863a223cbda5bccad36b3af73e29bc309fdaed94745cf9e`(同页 DOM 边界、computed style、svg_nodes):面板 `[232,40,638,1415]`(5.8.2 复核)、组 `[40/218] [274/514] [804/265] [1085/234] [1335/120]`、行高 `[44,68,52 | 56,68,68,76,68,68,56 | 56,68,56 | 66]`、卡片 `#fff / radius 12 / padding 12px 16px`、标题 14px/500/22px、描述 14px/400/22px `rgba(0,0,0,.5)`、开关 34×20、下拉 120×32、滑块 224×40、存储卡 638×235、路径输入 530×32、更改按钮 68×32、打开目录 76×22、通知按钮 130×32。
- REA `ev_377c8790468b3c67dad8577aabb327f98d3140659f0fffdbabfcff5a40cc9e94`:面板与控件样式来源(`contexts-BkjwYSZT.css` sha256 `50cbd673f7f35fc7f966bdddc6c9f5677fdfe944cb904888d214619fca259380`、`tokens-Df-i-zsO.css` sha256 `13f2bf82c96e5167a7d7098e36950c6c22c475b3337dbb8bb29ad2fe79cde696`、UI kit `src-Bh3YZ35H.css` sha256 `88dbdc1cd3f59d0e8b75824512a465a2be714bc7af481d790fe3a9484f85e01a`)。
- 观察范围:桌面端浅色主题(另加暗色抽查)、900×680 设置窗口、通用页默认态;未覆盖:各下拉展开态的选项列表(`general-settings-panel__link-open-select-popover` / `power-save-blocker-settings__popover` 均为 368 宽,规则已回收但本轮不接入)。
实现:
- `scripts/rea/recover-general-settings.mjs`:从上述 REA 回收样式表投影出面板规则(149 条)+ UI kit 控件规则 + 面板作用域 token,写入 `src/renderer/src/components/source-general-settings-recovered.css`;UI kit 规则用 `:where(.general-settings-panel)` 前缀并排在面板规则之前,以保持原版同权重、面板后加载的层叠(例如 `.wb-storage__open-folder{height:auto}` 必须压过 `.wb-button--medium{height:32px}`)。
- `src/renderer/src/components/GeneralSettingsPanel.tsx`(+ `source-general-settings.css`、`general-settings-icons.tsx`):按原版 DOM/类名/几何复刻 16 行;品牌替换遵循既有约定(「WorkBuddy 默认工作空间存储路径」→「YCode 默认工作空间存储路径」)。
- `src/main/general-settings.ts`、`src/main/config.ts`、`src/main/ipc.ts`、`src/main/index.ts`、`src/shared/{types,ipc}.ts`、`src/preload/index.ts`:新增 `window.ycode.general` API(get/update/openFolder/changeWorkspaceRoot/openSystemNotificationSettings)。
- 已接入(真实行为、重启持久化):
1. 运行时防止系统休眠 → `config.preventSleep`;任务运行期间主进程持有 `powerSaveBlocker`(`updateActiveRuns` 挂在 `chat:send` 运行生命周期上)。
2. 开机自动启动 → `config.autoLaunch` + 系统登录项(`app.setLoginItemSettings`),读取时以系统登录项真实状态为准。
3. 系统缓存目录 → 真实数据目录(`app.getPath('userData')`)、真实占用与磁盘容量(递归扫描 + `fs.statfs`)、「打开目录」调用系统文件管理器。
4. 默认工作空间存储路径 → `config.workspaceRoot`,只读填充态输入框 + 「更改」走系统目录选择器。
5. 桌面通知 → 「前往系统设置」打开系统通知设置页(Windows `ms-settings:notifications`)。
- 未接入(原版行为未实现,因此保留原版外观、控件类型与初始态,但标记 `aria-disabled` + `title="暂未接入"`,且不产生任何效果):语言、链接打开方式、字体大小、允许锁屏运行、网络代理、自动安装可信技能、技能自动更新、套件自动更新、通知提示音、定时任务产物通知、体验优化计划(含「了解更多」内联链接)。共 11 项。
验证:`scripts/verify-general-settings.cjs` 在真实隔离 Electron(真实 preload/IPC/渲染进程/文件系统 + 原生设置窗口,视口 900×680)中 43 项断言全部通过:导航「通用」可用且为当前页;面板列宽 638、顶层级顺序 group/group/storage/group/group;4 个分组标题;14 行标题与行高逐一匹配;分组标签 638×22 且左内边距 8px;卡片 `12px 16px`/radius 12/白底;标题 14/500/22、描述 14/400/22 三级色;开关 34×20;5 个下拉 120×32;滑块 224×40 且标签 小/默认/大;通知按钮 130×32 且带尾部图标;存储卡标题/说明/76×22 打开目录/530×32 输入框/68×32 更改/填充态样式;用量文案与真实数据目录;进度条 606×4 三段合计 604;分隔线 606×1;11 个占位项全部 `aria-disabled` + 「暂未接入」且点击无效(下拉不弹层、开关不切换);防休眠与开机自启动开关可切换、写入 `config.json` 并可还原;工作空间路径改写真实持久化(含 `workspace.get()` 与 `config.json`);重开设置窗口后偏好与路径仍正确渲染;暗色主题下面板卡片与标题重新着色;无渲染器报错。报告 `.tmp/general-settings-2elYNv/report.json`。
回归:`npm run typecheck`、`npm run build`、`npm run test:chat`、`npm run test:conversation`、`npm run test:conversation-ipc`、`node scripts/verify-settings-nav.cjs`、`node scripts/verify-composer-context-info.cjs`、`node scripts/verify-account-menu.cjs` 全部通过。`test:conversation-ipc` 的 electron mock 因新增 `powerSaveBlocker` 依赖而先失败,已在 `scripts/conversation-ipc-regression.ts` 补齐 mock(`powerSaveBlocker`、`app.isPackaged/isReady/getAppPath/getLoginItemSettings/setLoginItemSettings`、`shell.openExternal`)。
遗留:
1. 系统级写入的自动化隔离:验收时以 `YCODE_DISABLE_SYSTEM_INTEGRATION=1` 跳过登录项与系统设置页的真实写入,因此「写入注册表登录项」「打开 ms-settings:notifications」两条系统副作用只在人工路径覆盖,未纳入自动化断言。
2. 「更改」按钮会弹出系统目录选择器,无法自动点击;脚本改为断言按钮可用 + 通过 IPC 验证路径持久化,并在重开窗口后断言面板渲染新路径。
3. 数据目录路径较长时,缓存目录说明行会像原版一样换行(原版 `.wb-storage__path-text` 无 nowrap);脚本按实际行高换算期望的面板/卡片高度(QA 沙箱路径下为 1415+22=1437)。
4. 若后续要把语言/链接打开方式/网络代理/通知提示音等下拉接入,需要先按 REA 采集各下拉的展开态选项列表(当前仅有弹层容器 368 宽的样式规则)。
### 11. 外观与浅色/深色主题
- [x] 对齐原版外观页面及主题切换交互;当前只保留浅色、深色两种选择。
- [x] 梳理原版主题切换会改变的 token、样式、资源和组件状态。
- [x] 统一设置窗口与主窗口已接表面的主题响应(采样验收);独立任务窗口、弹层、代码/表格/工具结果等表面尚未逐一采样(见遗留)。
- [x] 验收:即时切换、跨窗口同步、重启持久化;采样表面无浅深混色和不可读内容。
状态:已实现并通过真实窗口回归(21 项断言)。
原版证据:
- REA `ev_dee8f184f6d8de34338f454e3a2588c26e2621dbc29c07c65337c475a243a6a0`(WorkBuddy 5.8.3,设置窗口 target `6D5A7FEE…`,900×680):外观页最终浅色态(含 PNG 帧)。
- REA `ev_24ab58532d4ece0d79f35c8c7d4cb14f5611a7405cdf747c4698e6184bea7d99`:深色态版式 + 模块样式表 `appearance-DMmhwsxq.css`(sha256 `af58cb3134d3e6c474424f6d718daa8f5be0c6e29d40aa5f9f80c14b3ffbbbd2`,外观页懒加载资源)。
- REA `ev_ff4f073ea843a5f444244393b3e190ccb1803bfec2b32afbfb4edfed9cc7bbc7` / `ev_fa67fddbb3dc00dde1609ef8e72d448e586066b74949f97634e1dbd0921599dc`:切换后的稳定深色/浅色等待探针。
- 预览图资产(REA `media_selectors` 导出,原版 `IMG.appearance-preview__image`,alt「效果预览」):浅色 `ev_c0b1dacb5fa65c88f32c2f600f0a7a6731b05e58f88b74677924a53899b17ff7`(1260×840,sha256 `0b1f24f382c53fa6d3b364bf89d0bbe62b4c6c403dc5a6263c9c5b7fcec7f925`)、深色 `ev_43c82492b3154ca67bcccc0bfb54694d1e4d06e0baf72560e49355747b1ad3f7`(sha256 `ca133c7200b03a49170658e9661f4b64d8ecdf30f8c6395b7f07dc25eff653b6`);图片本身含原版 V5.0.2 样例角标,属原版静态资源内容。
- 原版几何:`.appearance-panel` [232,40,638,640]、`.appearance-preview` [236,40,634,317]、预览图 [308.906,86.281,488.172,270.719](radius 8px 8px 0 0)、徽标「永久有效」[806,48,56,20]、标题「全部主题」[236,381,56,20]、网格 [236,413,634,218.391](gap 12px 8px、padding 4px 4px 0)、卡片 118.797×79.188、名称 118.797×18;原版共 9 张卡(浅色/深色/有风/经典QQ/和平精英激战金秋/同行/涟漪/伙伴/敬请期待),面板内无字号/主题色/动效控件。
- token 结论:主题切换是纯颜色层——浅色域可解析变量 1870 个,其中 562 个在深色域取值不同,尺寸/字体/间距类差异 0(本轮复核 tokens 表 sha256 `13f2bf82c96e5167a7d7098e36950c6c22c475b3337dbb8bb29ad2fe79cde696`)。
- 观察范围:桌面端 900×680 设置窗口的外观页 + 主窗口 1336×1240 抽查;未覆盖:复合主题切换的单次连续采集(REA 返回 `target_changed`,改以稳定深/浅两态等待探针取证)、系统跟随模式、原版其余 7 张主题卡的行为。
实现:
- `scripts/rea/recover-appearance-panel.mjs`:从 `ev_24ab5853…` 的模块样式表投影 44 条 `.appearance-*` 规则,把原版深色选择器(`.dark`/`[data-cb-theme=dark]`)改写成 YCode 的 `[data-theme=dark]`,并按引用闭包复制作用域 token,生成 `src/renderer/src/components/source-appearance-panel-recovered.css`;`source-appearance-panel.css` 只做 import 与本地适配(标题行盒 20px)。
- `src/renderer/src/components/AppearanceSettingsPanel.tsx`:预览图 + 「永久有效」徽标 + 「全部主题」+ 浅色/深色两张卡(`aria-pressed`、`appearance-card--selected` 选中态);`appearance-assets/provenance.json` 记录两张预览图的证据与 sha256。
- `src/renderer/src/components/SettingsDialog.tsx`:外观页接入 `AppearanceSettingsPanel`(替换旧的 `.segmented` 占位控件)。
- `scripts/rea/recover-settings-shell.mjs`:为 `.settings-window-root,.settings-modal` 追加作用域 token(67 light/37 dark)并重生成 `settings-shell-source.css`,修复深色下设置窗口仍白底、近白文字的真实缺陷。
验证:`scripts/verify-appearance-settings.cjs`(真实隔离 Electron + 原生设置窗口,视口 900×680)21 项断言全部通过:导航/面板/预览卡/徽标/标题/网格/卡片/名称与被回收原版几何逐一比对;浅色选中环 solid 2px;点击「深色」即时切换(`data-theme`、`localStorage['ycode:theme']`、预览图 src、选中环变白)且主窗口跨窗同步;深/浅两态对设置壳 4 个表面 + 主窗口 5 个表面采样,背景明度与文字对比度全部达标(读性 ≥4.5);深色下重开设置窗口仍持久化,浅色可还原;预览卡渐变随主题重绘;无渲染器报错。报告 `.tmp/appearance-settings-vxGNgk/report.json`。
回归:`npm run typecheck`、`npm run build`、`npm run test:chat`、`npm run test:conversation`、`npm run test:conversation-ipc`、`node scripts/verify-settings-nav.cjs`、`node scripts/verify-general-settings.cjs`、`node scripts/verify-desktop-appearance.cjs`、`node scripts/verify-account-menu.cjs` 全部通过(三个旧脚本对新外观组件的选择器断言已同步更新)。
遗留:
1. YCode 只保留「浅色/深色」两张主题卡;原版另外 7 张(有风、经典 QQ、和平精英激战金秋、同行、涟漪、伙伴、敬请期待)未接入,不臆造其资源。
2. 预览图直接使用原版静态截图资源(含 V5.0.2 角标),不是 YCode 的渲染实拍。
3. 主题切换的过渡动画未连续采集(复合探针 REA 返回 `target_changed`),只验证了稳定深浅两态。
4. 主题覆盖采样未包含:独立任务窗口、弹层、代码/表格/工具结果等表面;后续如需可沿用同样的采样方法补齐。
5. 原版 tokens 表中不存在的变量(`--wb-color-fill-hover/active/secondary`、`--wb-color-bg-primary`、`--wb-radius-2`、`--cb-*` 等)未臆造取值,规则保留 fallback。
### 12. 快捷键页面与真实功能
- [x] 拆解页面布局、分组、按键显示、编辑/恢复默认等实际存在的交互。
- [x] 建立快捷键 → 命令 → 实际动作映射:24 行中 14 行已真实绑定,其余在 tooltip 明确标注未接入。
- [x] 验收:展示按键与实际绑定一致;搜索、录制态/取消、深色主题与 5 个新全局键位通过真实窗口回归。可修改项持久化未接入(见遗留)。
状态:已实现并通过真实窗口回归(32 项断言)。原版 24 行全部按 1:1 呈现,其中 14 行在 YCode 真实生效。
原版证据:
- REA `ev_5f3148eb51ea4a6e5b6f2ffea5f6e3dfb94e4009ecf2d16173fa676ce7c51b4b`(WorkBuddy 5.8.3,设置窗口 `6D5A7FEE…`,900×680):快捷键页浅色顶部布局、578 个 DOM 节点、计算样式与模块样式表 `keyboard-shortcuts-DOrivHwf.css`(sha256 `d2c570c8d65db87c1cb9df06b59e6aa191b772330857376b85fd923aed580ae8`,8,430 字节)。
- REA `ev_7266946b025216056fc67f7c6d3c991894e985b6a8486a3153c3508e21771f73`:四段滚动采样(顶/中/底/回顶),覆盖全部 24 行。
- REA `ev_b3e014e5cff4971d7c5e75fefbbfefb0088db9ce655ef7ff33114cd3c4caead9`:搜索「语音」→ 单行、禁用「全部恢复默认」、点击绑定进入「按下快捷键 / ESC 取消」、Esc 取消后保留 `Ctrl+K`。
- REA `ev_f4fd417445481ef93c34a7e85be45e63327daa2acbccaf169706d7e19bacc531`(深色同页布局)与 `ev_528724699462fa08e2e4119bb8504c0180483c86cd844461cc969422b915650b`(最终浅色顶部稳定态)。
- 页面结构:无分组标题的平面表格,列名 命令 / 按键绑定 / 操作。面板 `[232,40,638,620]`;toolbar `[232,40,638,32]`、搜索 `[232,40,516,32]`、恢复默认 `[760,40,110,32]`;列表 `[232,88,638,572]`、表头 39px、滚动区 `[232,127,638,533]`;行宽 623,前 16 行 41px、17–23 行 45px、末行 44px;键帽高 22px。
- 24 行命令与键位:打开全局搜索 `Ctrl+K`、打开设置 `Ctrl+,`、语音录制开关 `长按 Alt`、对话内搜索 `Ctrl+F`、全局搜索 `Ctrl+K`、发送消息 `Enter`、输入时换行 `Shift+Enter`、新建对话 `Ctrl+N`、停止生成 `Esc`、上一个任务 `Ctrl+[`、下一个任务 `Ctrl+]`、定位当前任务 `Ctrl+Shift+E`、切换左侧栏 `Ctrl+B`、切换右侧栏 `Ctrl+Shift+B`、进入/退出全屏 `F11`、唤起/隐藏主窗口 `Shift+Alt+W`、放大内容字号 `Ctrl+"+"`、缩小内容字号 `Ctrl+"-"`、重置内容字号 `Ctrl+0`、唤起选择器 `@`、唤起斜杠命令 `/`、按住后点击始终外部打开 `Ctrl`、新建标签页 `Ctrl+T`、关闭标签页 `Ctrl+W`。
- 深浅差异:几何不变;列表/行背景 `#fff → rgb(31,31,31)`,正文 `rgb(0,0,0) → rgb(242,243,245)`,键帽由 `#f2f2f2` 变为 8% 白色填充;只读行键帽不透明度 0.5。
- 观察范围:桌面端 900×680 设置窗口浅色 + 深色抽查;未覆盖:单条删除按钮的实际点击结果、空搜索结果的原文案、复合主题切换的单次连续采集(深色/浅色点击各遇到一次 `target_changed`,已用独立稳定采样确认)。
实现:
- `scripts/rea/recover-shortcuts-panel.mjs`:从 `ev_5f3148…` 投影 49 条 `.keyboard-shortcuts-panel*` / `.shortcut-item*` 模块规则(含 `recording-cursor-blink` 关键帧),深色选择器改写为 `[data-theme=dark]`,按引用闭包复制 53 个浅色/53 个深色作用域 token,生成 `source-shortcuts-panel-recovered.css`(12,540 字节,sha256 `414aa003…`,两次运行一致)。
- `src/renderer/src/components/shortcuts-catalog.ts`:24 行命令/键位/可编辑性,以及 `supported` 真实绑定标记(14 行为 true)。
- `src/renderer/src/components/ShortcutsSettingsPanel.tsx`:工具栏(搜索 + 禁用「全部恢复默认」)、三列表头、24 行表格、前 16 行删除按钮(禁用)、后 8 行 `shortcut-item--not-editable` + 「—」、点击绑定进入「按下快捷键 / ESC 取消」、捕获按键时提示「自定义键位尚未接入,已保留默认绑定」、真实搜索过滤与空结果态。
- `src/renderer/src/components/source-shortcuts-panel.css`:import 回收样式 + 本地适配原版 UI kit 的输入/按钮基件(浅色取值来自 REA computed style:搜索框 32 高/radius 8/`#e6e6e6` 边、恢复默认按钮 110×32、删除按钮 24×24),深色下文色按 REA 实测 `rgb(242,243,245)`。
- `SettingsDialog.tsx`:`keyboardShortcuts` 加入 supportedTabs 并渲染面板。
- `App.tsx`:新增全局键位——`Ctrl+K` 展开侧栏并聚焦搜索、`Ctrl+B` / `Ctrl+Shift+B` 切换左/右侧栏、`Ctrl+N` 新建对话、生成中 `Esc` 停止;`Sidebar.tsx` 监听 `ycode:new-task` 复用「新建任务」路径,并补上搜索框挂载后的聚焦(修复 rAF 早于条件渲染导致焦点丢失)。
验证:`scripts/verify-shortcuts-settings.cjs`(真实隔离 Electron + 原生设置窗口,900×680)32 项断言全部通过:导航启用/选中;面板、工具栏、搜索、恢复默认、列表、表头、滚动区几何;三列表头文案;24 行文案/键位顺序;41/45/44 行高与 22px 键帽;前 16 行删除按钮与可编辑、后 8 行不可编辑且「—」;`长按 Alt` 拆分;14 个 supported id 精确匹配;未接入行 tooltip 含「尚未接入」;搜索「语音」筛为 1 行、无匹配显示空态、清空恢复 24 行;录音态文案与光标、Esc 取消保留 `Ctrl+K`、按键捕获提示未接入;深色几何不变且行底 `rgb(31,31,31)`、正文 `rgb(242,243,245)`、键帽 8% 白;恢复浅色正确。主窗口真实按键:`Ctrl+B` 折叠/展开并写入 `localStorage`、`Ctrl+K` 聚焦 `.sidebar__search-input`、`Ctrl+Shift+B` 开/关右栏、`Ctrl+N` 触发新建任务通路。报告 `.tmp/shortcuts-settings-neCeel/report.json`。
回归:`npm run typecheck`、`npm run build`、`npm run test:chat`、`npm run test:conversation`、`npm run test:conversation-ipc`、`node scripts/verify-settings-nav.cjs`、`node scripts/verify-appearance-settings.cjs`、`node scripts/verify-general-settings.cjs`、`node scripts/verify-desktop-appearance.cjs`、`node scripts/verify-account-menu.cjs` 全部通过。
遗留:
1. 自定义键位编辑/单条删除/整表恢复默认未接入:YCode 尚无键位配置存储与命令注册表,页面保持原版控件形态但按钮禁用,捕获按键后明确提示「自定义键位尚未接入」,不伪造成功,也未宣称可持久化。
2. 未真实接入的 10 行(语音录制、对话内搜索、上一个/下一个任务、定位当前任务、全屏、唤起/隐藏主窗口、`@` 选择器、`/` 斜杠命令、`Ctrl` 外部打开)只还原原版展示,tooltip 标注「YCode 尚未接入」。
3. `Ctrl+T` / `Ctrl+W` 为工作台焦点内作用域绑定,`Ctrl+K` 落到侧栏任务搜索,与原版「全局搜索」的服务端检索范围不同(云端服务本轮不处理)。
4. 深色下 toolbar 输入框/按钮来自本地适配(原版把 UI kit 放在独立样式表,未随该页模块导出),已按 tokens 深色取值还原。
5. 空搜索结果文案「未找到匹配的快捷键」是 YCode 本地文案,原版空态未采集。
### 13. 个性化页面与真实功能
- [x] 拆解原版页面、字段、说明、保存/启停等交互。
- [x] 将支持的个性化配置接入实际运行链路(身份/风格/指令/人设/长期记忆随每轮请求发送,欢迎语控制加载提示)。
- [x] 验收:修改与持久化有效;界面显示与实际行为一致;「显示文件修改过程」明确标注未接入,不用占位控件宣称完成。
状态:已实现并通过真实窗口回归(29 项断言)。
原版证据:
- REA `ev_af920edf33af5e811d58f05dad15210b29cd891f28e0fa74f6b18d63212241b1`(WorkBuddy 5.8.3,设置窗口 `6D5A7FEE…`,900×680):浅色顶部 DOM/layout/computed style + 模块样式表 `PersonalizationPanel-D16rRGjy.css`(sha256 `318664f96253adace047d7b1d2d213fbf6139461c10d80ae12135998b7b98f3d`,6,218 字节)。
- REA `ev_88af0774005c02e9c75284ade2be45de4943ee5aaf73fe5b13ac8a38b85be786`:深色同页布局与计算样式。
- REA `ev_d6e0a2483a3bde901f4cf8299ff03eb0b475cb934921058cf38dd671585ab457`:回复风格下拉展开/关闭、欢迎语与显示文件修改过程开关的切换与恢复。
- REA `ev_3086b2b2…` / `ev_e1762bd8…` / `ev_9ee64574…` / `ev_bc120498…` / `ev_7b372850…`:身份字段编辑态、失焦丢弃草稿、非空确认保存、空值无法保存。
- REA `ev_523e07353a9fd7a003136f8e07c72d5ba87a05f893dd4b4c4adb2d7ed5a7430f`(指令编辑弹窗 DOM/几何)、`ev_624240fb…`(人设弹窗)、`ev_64e60ac3…`(长期记忆弹窗)。
- REA `ev_4f4f76054a930a186199ee28a5f0169f7de48a05a295b8e9eb630c796f07be4a`:最终浅色顶部稳定态。
- 页面结构:五张卡片、内容高 1160px。身份卡 `[232,40,638,100]`(两行 `[244,48/98,614,34]`,胶囊 172×34,占位「暂无内容,点击编辑添加」);回复偏好卡 `[232,156,638,204]`(回复风格下拉 120×32、欢迎语开关 34×20 默认开、显示文件修改过程默认关);指令/人设/长期记忆三张长卡 `[232,376/656/936,638,264]`,预览 598×160,编辑按钮 68×32;编辑弹窗 `[130,80,640,520]`,footer 保存/取消 68×32。
- 回复风格 8 个选项(标签+说明):默认/不设定特定风格。、专业严谨/清晰、准确、值得信赖。、亲和友善/温暖、平易近人、鼓励支持。、直言不讳/简明扼要、不废话、直击要点。、天马行空/富有想象力、善用比喻类比。、高效务实/最少文字、最大信息量。、毒舌吐槽/犀利吐槽、但绝不伤人。、启发引导/用提问引导思考、授人以渔。
- 深色差异:卡片 `#fff → rgb(31,31,31)`,标题 `rgb(0,0,0) → rgb(242,243,245)`,描述黑 50% → 白 50%,开关 on `rgb(0,194,154) → rgb(34,203,168)`、off `rgb(230,230,230) → rgb(60,60,60)`,长预览 `#fff → rgb(38,38,38)`。
- 观察范围:桌面端 900×680 浅色 + 深色抽查;未覆盖:富文本编辑器内的真实输入(REA text action 不支持 `.sc-editor-content`)、单条身份值清除(原版空值确认被拒)、主题切换时 `target_changed` 后的连续动画。
实现:
- `scripts/rea/recover-personalization-panel.mjs` → `source-personalization-panel-recovered.css`:45 条模块规则 + 两组主题 token(47 条规则、9,802 字节、sha256 `530b89d5…`),连续重跑一致。
- `src/shared/personalization.ts`:8 个风格选项、原版默认人设文本、默认值归一化与 `buildPersonalizationPrompt`(纯函数,可离线回归)。
- `src/main/personalization.ts` + `src/main/config.ts`:`config.json.personalization` 持久化(身份、风格、开关、指令、人设、长期记忆)。
- `src/main/ipc.ts` / `src/shared/ipc.ts` / `src/preload/index.ts`:`personalization:get/update`;每轮 `promptText` 末尾附加个性化上下文,OMP 与自建循环共用同一段文本。
- `PersonalizationSettingsPanel.tsx` + `source-personalization-panel.css`:按原版卡片/行/胶囊/下拉/开关/长预览/弹窗结构复刻;身份行支持 inline 编辑、失焦丢弃草稿、空值确认禁用;长文本用弹窗 + 保存/取消;欢迎语真实控制流式加载提示(`personalization-prefs.ts` + `StreamingFooter`);「显示文件修改过程」保留原版 off 形态,但禁用并标注「暂未接入」。
- `SettingsDialog.tsx`:`personalization` 加入 supportedTabs 并渲染面板。
验证:`scripts/verify-personalization-settings.cjs`(真实隔离 Electron + 原生设置窗口,900×680)29 项断言全部通过:导航启用/选中;面板/身份卡/两行/胶囊/回复偏好卡/三行/下拉/开关/三张长卡/预览/编辑按钮几何;5 组文案与占位;回复风格弹层 240 宽、8 个标签+说明、选择「专业严谨」持久化;欢迎语关→localStorage `0`→开;未接入开关保持禁用;身份 inline 编辑 172×34、确认保存、失焦丢弃草稿;指令弹窗 640×520 + 保存/取消 68×32 + 占位文案,保存后预览与配置一致;人设弹窗带默认文本且取消不改值;`config.json.personalization` 字段正确;重开设置窗口恢复全部值;深色卡片 `rgb(31,31,31)` 与正文 `rgb(242,243,245)`;恢复浅色;无渲染器报错。报告 `.tmp/personalization-settings-V0Vev8/report.json`。
回归:`npm run typecheck`、`npm run build`、`npm run test:chat`、`npm run test:conversation`、`npm run test:conversation-ipc`、`npm run test:personalization`、`node scripts/verify-settings-nav.cjs`、`node scripts/verify-shortcuts-settings.cjs`、`node scripts/verify-appearance-settings.cjs`、`node scripts/verify-general-settings.cjs`、`node scripts/verify-desktop-appearance.cjs`、`node scripts/verify-account-menu.cjs` 全部通过。
遗留:
1. 「显示文件修改过程」尚未接入 YCode 的逐步文件变更渲染,保持原版 off 形态并禁用+「暂未接入」提示。
2. 编辑弹窗用 textarea 承载纯文本;原版是富文本编辑器(`.sc-editor-content`),富文本格式、粘贴与快捷键未复刻。
3. 原版默认人设文本已按 REA 抄录并显示在面板中,但默认值不会注入请求上下文(用户修改后才注入),避免与 YCode 自身身份设定重复冲突。
4. 个性化上下文附加在每轮 `promptText` 末尾(与用户消息同一条 prompt 发送),不是独立的 system 消息;OMP 与自建循环行为一致。
5. **采集副作用**:REA 采集时把 WorkBuddy「对你的称呼」保存成了 `CodexTmp`;原版界面不接受空值确认(空字符串与单空格均被拒绝),无法通过可见操作恢复为空。该项需要在 WorkBuddy 内另行处理。
### 14. 记忆与进化
- [ ] 记录待拆解:入口、页面、数据、读写机制、会话生效方式及生命周期。
状态:待拆解,本轮不自动展开实施。
### 15. 智能体页面:团队管理
- [ ] 拆解原版智能体设置页面,本轮仅对接“智能体团队管理”。
- [ ] 根据 REA 证据梳理团队列表、详情及管理操作,将需要的真实存储/配置链路接入。
- [ ] 验收:仅展示已确定范围;管理操作实际生效、重启后可恢复;团队管理与真实子代理调度的完成度分别记录。
状态:待 REA 拆解;范围限定为团队管理。
### 16. 移除助理与设备连接
- [x] 移除设置中的“助理”“设备连接”导航和页面入口。
- [x] 清理默认选中、内部导航、深链接/旧配置回退中的无效目标。
- [x] 验收:设置中不再出现这两项,旧导航目标不会导致空白页。
状态:已实现并通过真实窗口回归。
原版证据:WorkBuddy 5.8.3,REA Evidence `ev_2309de12a003fca2c863a223cbda5bccad36b3af73e29bc309fdaed94745cf9e`(归档 `.tmp/rea-assessment-settings-window/layout.json`,视口 900×680):设置导航 16 项 / 4 组、条目 `190×32`、x=12、y 从 111 起;`.settings-modal__nav` 200 宽而条目 190 宽,10px 差值为内容溢出时 thin 滚动条占用的槽位。观察范围:设置窗口导航栏;未覆盖:被移除项的原版内部页面(本轮不迁移其内容)。
实现:`src/renderer/src/components/SettingsDialog.tsx` 新增 `REMOVED_SETTINGS_TABS = ['claw','deviceConnections','dataManagement','buddyApps']`、导出 `VISIBLE_SETTINGS_TABS = SOURCE_WINDOWS_SETTINGS_TABS.filter(...)`(12 项)、`normalizeSection()`;`?section=` 启动、已打开窗口的 `onSettingsNavigate` 深链接统一走 normalize(`models`→`model`,已移除项→`model` 回退),`SourceSettingsNavigation` 新增 `visibleTabs` 属性按可见列表渲染。未删除任何用户数据、已安装内容或配置。
验证:`scripts/verify-settings-nav.cjs` 在真实隔离 Electron(真实 preload/IPC/renderer + 原生设置窗口)中 19 项断言全部通过:12 项顺序与移除项不在 DOM/标签/搜索元数据、条目几何 x=12 / 32 高 / 宽度等于导航内容宽、3 个组标题 + 1 条 about 分隔线、未接入项 `aria-disabled` + 「暂未接入」提示且点击提示「该设置尚未接入」、`appearance`/`models` 仍可打开、`openSettings('claw')`(旧窗口导航)与 `openSettings('dataManagement')`(新窗口 `?section=` 启动)都回退到模型面板、无渲染器报错;报告 `.tmp/settings-nav-5YlLX6/report.json`。回归:`npm run typecheck`、`npm run build`、`npm run test:chat`、`npm run test:conversation`、`npm run test:conversation-ipc`、`node scripts/verify-composer-context-info.cjs` 全部通过。
遗留:移除 4 项后本窗口导航不再溢出,条目宽 200(原版 16 项溢出时为 190);未补 `scrollbar-gutter`,因为 REA 回收的原版 CSS 没有该规则,保持源码级一致,条目增多再次溢出时会自动回到 190。
### 17. 移除数据管理与应用管理
- [x] 移除设置中的“数据管理”“应用管理”导航和页面入口。
- [x] 清理相关无效导航与页面占位。
- [x] 验收:入口完全移除且其余设置导航正常;不删除已有用户数据或已安装内容。
状态:已实现并通过真实窗口回归(与 16 同一次改动,代码见上)。
原版证据、实现、验证:同 16。`dataManagement`、`buddyApps` 与 `claw`、`deviceConnections` 一并进入 `REMOVED_SETTINGS_TABS`,走同一份 normalize 回退与 `visibleTabs` 渲染;验收脚本同时断言这两项(以及 `claw`、`deviceConnections`)不在 DOM、标签和搜索元数据中,且 `openSettings('dataManagement')` 深链接落到模型面板而不是空白页。未触碰本地会话数据、安装中心与任何已有用户内容。
遗留:无新增;数据管理/应用管理的原版页面内容不再复刻(用户指定仅移除入口)。
### 18. 安装中心
- [ ] 记录待拆解:入口、页面结构、安装来源、安装/更新/卸载流程及与其他能力中心的关系。
状态:待拆解,本轮不自动展开实施。
### 19. 关于与获取帮助
- [ ] 通过 REA 复刻“关于”“获取帮助”的布局、字体、图标、间距和交互外观。
- [ ] 不复制原版跳转链接;逐项标注 YCode 自有入口或尚未配置的跳转。
- [ ] 验收:本应用版本等信息真实;没有误跳 WorkBuddy 官方账户、帮助或其他服务地址。
状态:待 REA 对照;布局纳入范围,原版链接排除。
## 后续模块
### 20. 定时任务、资料库、更多中的项目
- [ ] 定时任务:待拆解入口、页面、任务配置、触发/执行记录及生命周期。
- [ ] 资料库:待拆解入口、资料组织、添加/读取/检索及会话引用方式。
- [ ] 更多 → 项目:待拆解入口、项目组织、工作区/任务关系及管理操作。
状态:三个模块均待拆解,本轮不自动展开实施。
## 追加需求
### 21. 对话框 Git 分支检测与会话上下文信息
- [x] 通过 REA 拆解 WorkBuddy 对话框中 Git 分支和会话上下文信息的显示位置、图标、字体、间距、提示及交互。
- [x] 根据当前任务绑定的工作目录检测 Git 仓库和实际分支;核对原版对非 Git 目录、未产生首次提交、detached HEAD、检测失败等状态的处理。
- [x] 明确原版“上下文信息”的实际字段、数据来源、更新时机和展示方式,再接入 YCode 的真实会话数据;上下文用量等字段如存在,必须区分真实统计与估算。
- [x] 验收:新建任务、已有会话、切换空间/任务、外部切换 Git 分支后的信息归属与刷新正确;无仓库时不显示虚构分支;浅色/深色及窄窗口布局与原版对齐。
状态:已按回收几何/样式/图标/文案实现,并通过真实隔离 App 端到端回归(47 项断言 + 6 项 Git 检测断言);分支为真实 git 结果,用量为上游真实 token(不估算)。
原版证据:
- 运行时几何/结构 REA Evidence `ev_2569313a7a0aa901c5a3b8dc1d7fd190109b9006c915830109b62195f312376a`(WorkBuddy 5.8.3 会话输入区,视口 1336×902,`.tmp/rea-debug-ready-20261017/layout.json`):
左组 `[.cr-add-menu 431,32]` → `[._branchLabel_jdvlk_244 471,82×32]` → `[.cr-permission-setting 561,107×32]` → `[.cr-status-chips 676]`;
右组 `[.cr-context-usage 903,32×32]` → `[.cr-model-selector 939,174×32]` → `[.cr-voice-trigger 1117]` → `[.cr-send-button 1157]`;两组 gap 分别为 8 / 4。
分支标签:radius 999、padding `5px 8px`、gap 8、max-width 188、字体 14/400/22、transition `background .15s`;图标按钮 16×16(`._branchLabelIconButton_jdvlk_279`),默认 SVG `viewBox 0 0 16 16` 分支字形、悬停 copy 字形(`lucide lucide-copy wb-icon`、`viewBox 0 0 24 24`、`stroke-width 1.5`、rect 14×14 + path),两个字形用 opacity 互换(1/0 → 0/1),`:hover`/`:focus-within` 背景 `var(--wb-bg-secondary)`;
用量环:32×32 / radius 16 / transition `background-color .2s`、hover `var(--cr-context-usage-hover-bg,#0000000d)`、`role="button"`、`cursor:pointer`;内含 16×16 SVG,track `circle r=7 stroke-width 2 stroke rgba(128,128,128,.2)`、progress `circle r=7 stroke-width 2 stroke-linecap round transform rotate(-90 8 8)` + `transition:stroke-dashoffset .3s`;截图像素采样确认该实例用的就是这两个回退色(`rgb(230,230,230)` / `rgb(158,162,176)`)。
浮层:`.cr-context-usage-popover` 280 宽 / padding 16 / radius 16 / font 12、标题行(`__title` 12/400/20 + `__close` 16×16)、百分比 20/700/28、`已使用` 12/20、进度条 8 高 radius 3、五类图例(每行 22 高、8×8 圆点、名称 13/22、值 12/20)、`__window-control` 分隔区;另有 `.__requesting-tip`(`bottom:calc(100% + 8px); right:0`)。
- 回收样式表:`contexts-BkjwYSZT.css`(`._branchLabel_*`、`._branchLabelCompact_jdvlk_274`)、`src-CyXHA0IC.css`(`.cr-context-usage*`);文案取自已回收 i18n 表 `chatInput.contextUsage.*`(title 上下文用量 / used 已使用 / tooltip `{percentage}% · {used} / {total} 上下文已使用` / requesting / needMessage / unavailable / 五个分类名)。
- 探针(可复跑):`scripts/rea/probe-todo21-discovery.json`(当前窗口基线)、`probe-todo21-home.json`、`probe-todo21-conversation.json`;本轮采集 `ev_f11473e2…`(首页基线,首页输入区只有工作空间/权限两个入口,没有分支标签与用量环)、`ev_c0dbb550…`、`ev_9796071b…`。
- 数据来源(原版):REA 只能拿到 DOM/样式/文案,浮层的定位与用量数值生成在 JS 内,本轮未取到;因此数值字段按已回收文案与类名结构对齐,YCode 侧只用自己能证明的真实值。
- 观察范围:桌面端 5.8.3、浅色运行时 + 深色按 `.cr-theme` token;未覆盖:原版 detached HEAD/无首次提交/非仓库时的标签表现、悬浮提示的实际锚定与延迟、用量环颜色的分段规则、`__window-control` 的内容。
实现:
- `src/main/git.ts`(新增):`readGitBranch(cwd)` 真实执行 `git -C <cwd> rev-parse --is-inside-work-tree` → `symbolic-ref --short -q HEAD` → 失败再 `rev-parse --short HEAD`;`windowsHide`、5s 超时、git 缺失/超时降级为 `unavailable:true`,全部异常都返回合法形状而不是抛出。
- `src/main/ipc.ts`:新增 `git:branch(sessionId)`,用会话 `cwd`(无则回退工作空间根目录)调用上面的检测。
- `src/renderer/src/workbuddy/composer/context-info/`(新增):`ComposerContextInfo.tsx`(`ComposerBranchLabel` / `ContextUsageRing`)、`icons.tsx`(分支字形 + lucide copy,路径逐字取自证据)、`source.css`(回收规则收敛在 `.cr-input-toolbar` 内)。
- `src/renderer/src/workbuddy/composer/ComposerControls.tsx`:新增 `branchLabelSlot`(左组「+」之后)与 `contextUsageSlot`(右组最前)两个槽位,与证据里的顺序一致。
- `src/renderer/src/components/ChatPane.tsx`:传入两个槽位;用量环的分母用所选模型真实的 `maxInputTokens`。
- 用量真实性:`ChatEvent` 新增 `usage`;OMP 通路在 `message_end` 读取助手消息上的真实 usage(`contextTokens ?? input + cacheRead + cacheWrite`,字段语义取自内核自身),网关通路在 Responses `response.completed.response.usage` 透传;渲染进程只保存最近一次真实值(`stores/chat.ts` 的 `sessionUsage`),拿不到就显示原版「正在会话中 / 暂无用量明细 / 暂时无法获取」文案。
- 原版浮层按五类拆分提示词构成,YCode 的提示词由内核拼装、拿不到该拆分,因此分类值显示「—」,不编造比例。
验证:
- `node scripts/verify-git-branch.cjs`(真实临时仓库 + esbuild 打包被测模块)6 项全 PASS:master 分支、`feature/x`、detached HEAD 短 SHA、空目录、包含不存在路径的非仓库目录、`git init` 无提交。
- `node scripts/verify-composer-context-info.cjs`(真实隔离 App + 真实 OMP 内核 + 受控本地 OpenAI 兼容上游 + 真实 Git 仓库)47 项全 PASS:
分支标签:文案等于真实分支名、32 高 / `5px 8px` / radius 999 / gap 8 / max-width 188 / 14-400-22 省略号、图标按钮 16×16、默认字形与 copy 字形几何与 class 逐项一致、默认可见 copy 隐藏、与「+」和权限入口各相距 8px;悬停后字形 opacity 互换且背景等于同作用域 `--wb-bg-secondary` 解析值;点击图标把真实分支名写入系统剪贴板。
用量环:32×32 / radius 16 / `role=button`、为右组第一个元素、与模型选择器相距 4px、内部 16×16 SVG 与 track/progress 圆的 r/描边/线帽/rotate/过渡逐项一致;无用量时 dashoffset 等于整周长。
浮层与提示:未拿到用量时显示「暂时无法获取用量明细,请稍后重试」且不显示百分比;真实回合(上游 `prompt_tokens 12800`、窗口 64000)后 dashoffset = 周长 ×0.8、悬浮提示 `20% · 12800 / 64000 上下文已使用`(底色/文字/圆角/内边距/字号与 `--wb-tooltip-*` 解析值一致)、浮层显示 `20%` 与 `12800 / 64000`、进度条填充 20%、五类图例名与 8×8 圆点齐全且值为「—」;关闭按钮可关闭浮层。
主题:通过原生设置窗口切深色后 `.chat-pane[data-cr-theme]` 变为 dark,浮层底色 `rgb(36,38,41)`、进度条 `rgba(255,255,255,.1)`、分支标签文字 `rgb(255,255,255)`;再切回浅色恢复 `rgb(255,255,255)`/`rgb(0,0,0)`。
- 回归(顺序执行,避免多进程 Electron 抢焦点):`npm run typecheck`、`npm run build`、`npm run test:chat`、`npm run test:conversation`、`npm run test:conversation-ipc`、`node scripts/verify-sidebar-footer.cjs`、`node scripts/verify-account-menu.cjs`、`node scripts/verify-new-task-switch.cjs` 全部通过。
- 报告:`.tmp/composer-context-lEIWRF/report.json`。
遗留:
1. 原版浮层/提示由 JS 定位(floating-ui),本轮只回收了 `.__requesting-tip{bottom:calc(100% + 8px);right:0}` 这一处锚定规则;YCode 按同向(上方 8px、右对齐到用量环)内联渲染,未逐像素比对原版浮层相对位置。
2. 原版五类上下文占比无法复刻(提示词由内核拼装,YCode 拿不到分类统计),分类值固定显示「—」;原版 `__window-control`(上下文窗口相关控件)内容未采集,未实现。
3. `._branchLabelCompact_jdvlk_274`(32 宽的紧凑形态)只回收了规则,未观察到运行时触发条件,尚未启用。
4. 原版对 detached HEAD、无首次提交、非 Git 目录、检测失败的标签表现未采集;YCode 在这些情况下不渲染标签(无提交但有分支时按 git 真实结果仍显示分支名)。
5. 用量环进度颜色:原版通过未回收的变量注入,本轮截图像素证明该实例用的是回退色 `#9ca3af`;是否随用量分段变色未验证。
6. 刷新时机未采集:YCode 在切换会话、窗口重新聚焦以及每 20s 轮询时重新读取分支;用量只在收到真实 `usage` 时更新。
7. 备用(非 OMP)内核走自建网关时用量来自 Responses `response.completed.usage`;Chat Completions 上游路径仍未解析 `usage`。
8. 用量环只在会话输入区渲染(本轮首页基线的 REA 证据里首页输入区确实没有该入口),首页/新建任务时不显示。
## 推进顺序
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 差异与方案:具体问题、涉及模块、数据与交互边界。
- 实现:修改文件、真实功能、占位或未接部分。
- 验证:功能回归、实际窗口交互、浅色/深色、相关截图/几何/像素结果及限制。
- 遗留:尚未解决的差异与下一步所需证据。