Files
ycode/.workbuddy/memory/2026-10-14.md
T

306 lines
34 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.
# 2026-10-14
## WorkBuddy AI「1:1 复刻」可行性评估(REA)
- 输入:`C:\Users\Administrator\code\ygent\docs\WorkBuddy-AI-实现分析报告.md`
- 产出:`C:\Users\Administrator\code\ygent\docs\WorkBuddy-AI-复刻可行性评估.md`
- 结论:**不能 1:1 复刻**,四重封死——法律(专有代码)+ 原生二进制(≈360MB,本机无 Ghidra/Hopper/IDA,无法反编译)+ 压缩 JS(0 个 sourceMappingURL,`.js.map` 无 sourcesContent,无 .ts 源)+ 云依赖(本地不推理,排除云后能力归零)。
- 关键实测数据(务必备查):
- 安装总体积 ≈935MB(Electron 运行时 279MB + app.asar 94MB + unpacked 562MB);asar 清单 14475 文件 / 680MB
- `node_modules/@tencent/tencent-docs-ai-engine/bin/win32-x64/editor_sdk.exe` = **199.5MB**,判定不可重建
- 自研沙盒:`tsbx.dll`(795KB)/`tsbx_sdk.dll`/`tsbxldr.dll`/`sandbox-center.exe`(9MB)/`betterleaks.exe`(22MB) —— 最关键且最不可还原
- 压缩 JS:`cli/dist/codebuddy-lite-wb.mjs` 9.48MB/2679 行、平均行长 3539;`main/server.js` 3.6MB;renderer/assets 116.7MB
- 可 1:1 的只有 ≈2.7MB:`cli/vendor/shim/*.cjs`(node-brokered-fs-shim 1162 行、safe-delete-bulk-guard 465 行)与 `cli/bin/*.cjs` 是未压缩完整源码
- 第三方 OSS ≈58MB 可直接 npm 复用(OpenAI Agents SDK、MCP SDK、OpenTelemetry、node-pty、koffi、lark SDK 等)
- REA 实测:`binary_session` 显示 ghidra=`not_configured`、hopper=`unsupported_host`、ida=`not_configured`、`recover_javascript_sources`(Wakaru)=provider_missing(仅 Linux)
- REA 分析 2 个源文件 → 11395 AST 节点 / 10 findings / 0 parse failures,但 coverage=partial,11,387 app unknowns + 128,327 semantic unknowns
- 技术注记:asar 解析时 header 长度字段含填充,需 `hdr[:hdr.rfind('}')+1]` 兜底;`analyze_javascript_application` 只接受目录或 `.asar`(不接受单个 `.mjs`),且官方 asar 需 `integrity_policy=record-and-continue`(unpacked 原生二进制被签名剥离导致校验不符)。
- 建议路径:不复刻,改走「参照公开架构 + 自研」——复用 OSS 底座(Electron / Anthropic sandbox-runtime / MCP SDK / OpenAI Agents SDK)+ 自建模型网关 + 自选沙盒方案。
## WorkBuddy 对话区 / 右侧栏 UI 复刻可行性(REA)
- 产出:`C:\Users\Administrator\code\ygent\docs\WorkBuddy-UI复刻可行性评估.md`
- 结论:**UI 层是整个项目最接近可复刻的部分**(视觉~95% / 结构~90% / 交互~70% / 数据 0%)。
- 决定性原因:**腾讯压了主进程(`main/server.js` avg 3037 字符/行、全单字母),却没压渲染进程** —— `contexts-BMeWSUHk.js`(7.55MB) 保留 **10,347 个可读函数名**、920 个具名 React 组件,函数体逐行可读(`ConversationInputArea`/`ConversationStreamingFooterImpl` 实测),仅局部变量重命名为单字母。
- 视觉层全明文:CSS 类名**无 hash**(`.cb-chat-message--user`、`.detail-sidebar--collapsed`、`.claw-secondary-sidebar--pinned`)、设计 token 完整(`--wb-palette-brand-8:#00c29a`,`wb-` 用 1425 个、`cb-` 用 437 个类)、i18n 三语全量本地(zh-cn/zh-tw/en,含全部 `chat.*` key)、图标/插图资源可复制、图标用 VS Code codicon(MIT)。
- UI 技术栈几乎全开源(可直接复用,无需复刻):React18 + Radix(17) + Floating UI(54) + Zustand(39) + mermaid(101) + KaTeX(49) + Excalidraw(63) + PDF.js + xterm + Monaco(15) + marked/markdown-it + DOMPurify + i18next(16) + dayjs(50) + framer-motion。
- 右侧栏形态 = 主壳组件(`DetailPanelSurfaceProvider/Host/Portal`、`ClawSecondarySidebar`)+ 独立扩展 `resources/extensions/{library,global-search,im-channels,community,cloud-assistant,...}/ui/assets`。
- 受限点:函数内部逻辑被混淆需重写;跨进程交互(窗口控件/原生菜单/文件对话框/剪贴板/截图)依赖主进程+原生模块;office 预览走不可复刻的 `editor_sdk.exe`(199.5MB);`cb-` 内部组件库需重写;排除云后无数据源=空壳。
- 两个不变天花板:**版权**(不能复制 CSS/资源/代码产出物)+ **云依赖**(无后端则界面无内容)。
- 复用要点:`analyze_javascript_application` 的 `source_paths` **不接受 .css**(实测 invalid_value),CSS 需用文本工具处理;renderer 目录可直接作为 input_path。
## YCode 工程落地(Electron 最小闭环)
- 位置:`C:\Users\Administrator\code\YCode`(clean-room,不复制 WorkBuddy 产物)
- 选型(用户确认):Electron 桌面应用 + 最小端到端闭环 + 自建 OpenAI 兼容网关(自有 API Key)
- 已落地:Electron 37.10.3 + React 19 + Vite 8 + TS 7 + Zustand 5 + electron-vite 5;主进程(config/ipc/sessions/gateway/agent+tools)、preload(CJS)、renderer(三栏 UI);typecheck/build 通过
- `npm run smoke` 全部通过(本地假上游驱动真实 gateway+loop:SSE 流式、分片工具调用组装、工具执行、上下文回填、越界拒绝、取消/缺 Key 报错)
- **关键坑(务必记住)**:
1. `electron` 在 devDependencies,`externalizeDepsPlugin` 不外置它 → 必须显式 `rollupOptions.external: ['electron']`,否则会把 electron 的 Node 入口内联进主进程
2. sandbox:true 要求 preload 为 **CJS** → preload 输出 `format:'cjs', entryFileNames:'index.cjs'`;主进程为 ESM(`index.mjs`),`__dirname` 由 electron-vite shim
3. TS 7 移除了 `baseUrl`,paths 必须写成 `./src/...`
4. **GPU 进程沙箱**:在受限进程树里 Chromium GPU 子进程以 0xC0000005 反复崩溃 → 用 `YCODE_DISABLE_GPU_SANDBOX=1`(仅关 GPU 沙箱,GPU 仍生效,实测 3 进程 0 崩溃) 或 `YCODE_DISABLE_GPU=1`(纯软渲染兜底)
5. 宿主环境带 `ELECTRON_RUN_AS_NODE=1`,从该环境启动 electron 会退化成普通 node → 需 `env -u ELECTRON_RUN_AS_NODE` 或换正常终端
6. 从 Agent shell 启动的 GUI 进程会在工具调用结束时被回收,无法跨调用保持
- 环境:node 22.22.2 / npm 10.9.7;用户机器 GPU = AMD Radeon RX 460,WorkBuddy 自身为 Electron 37.10.3
## YCode 视觉对齐(按 WorkBuddy 实测值重做)
- 起因:首版自拟的绿色主题+自创排版被用户指出「和 WorkBuddy 不相干」
- 依据(两项,勿凭记忆):① `ygent/docs/workbuddy-chat-layout.md` 真实 CDP 实测;② 安装包 `renderer/assets/tokens-Df-i-zsO.css` + `contexts-BkjwYSZT.css` 的 token 表
- 关键实测值(已落到 `src/renderer/src/styles/tokens.css`):
- **UI 主体是中性黑白灰**:文字 #000 / rgba(0,0,0,.7) / rgba(0,0,0,.5);背景 #fff / #f2f2f2;hover #ebebeb;active #e6e6e6;边框 #e6e6e6 / #ebebeb / #f2f2f2
- 品牌绿 #00c29a 只作状态点缀,**不用于主按钮/大面积色块**;成功 #0cbf5b、警告 #ff7800、危险 #f64041、信息 #3370ff
- 圆角 4/6/8,气泡 16(`16px 16px 0`),输入框 24
- 字号 caption 12 / body 14 / 气泡 13;Markdown 根 17.143px 行高 1.75,段落 .875em → 15/26.25;代码 12.857/22.5
- 布局:左栏 280px;内容列 max-width 832px 居中 + 左右 padding 40px(正文列 752px)
- 助手头部:24px 圆形标识 + 10px 间距,行高 24.5px,名称 14px/600,下间距 12px
- 用户气泡:#f2f2f2、padding 8px 12px、min-width 40px、max-height 310px
- 输入容器:圆角 24px、边框 #e6e6e6、白底+双层轻阴影;编辑区 min-height 64px / 横向 padding 16px;工具栏 56px、按钮 32px;发送按钮 32px 圆形(启用=黑/反色,禁用=rgba(0,0,0,.15))
- 落地原则:CSS 用自有类名(`.msg--assistant`/`.bubble`/`.composer__inner` 等),**只取实测数值,不复制对标产品的类名与样式表结构**
- 组件已同步:MessageBubble(助手头部+正文分离)、ChatPane(输入区拆「编辑区+56px 工具栏」)、ToolCard、Sidebar(280px + 列表容器)、RightSidebar
- **用户偏好:不要反复帮他启动应用**;他已自行 `npm run dev` 跑热更新,需要启动时由他自己来
## YCode 视觉对齐 第二轮(用户反馈「几乎完全不相干」后)
- 用户同时给了两张图:左=ygent(YCode),右=真实 WorkBuddy,差距很大
- 又捞到的**关键实测值**(来自安装包 CSS,勿再凭截图猜):
- **输入框填充是渐变**:`--wb-bg-input-slot-gradient: linear-gradient(180deg,#ebebeb 0%,#f5f5f5 100%)`(深色为 `#333→#292929`),外框 `border:1px solid #e6e6e6`、`border-radius:24px`,**无阴影**;focus 时 border 变 `rgba(0,0,0,.15)`
- 发送按钮:图标尺寸 32px,hover `opacity .8`,active `transform:scale(.93)`,禁用 `opacity:1`
- 侧栏导航(BEM `cb-sidebar-nav__*`):item `padding:8px 20px` flex 对齐;选中 `__item--selected` 用 list inactiveSelectionBackground(即灰底);icon `14×14` 且 `color-mix(text-primary 60%)` + `margin-right:8px`;title `13px/400/1.3`;section `margin-bottom:16px`;section-title `11px/600/uppercase/letter-spacing .5px/padding 8px 20px 4px`;header-title `13px/600/uppercase/opacity 30%`;content `flex:1;padding:8px 0 16px;overflow-y:auto`;footer `border-top:1px;padding:12px 20px`
- 真实 WorkBuddy 布局:左栏是「导航项+分组(任务/空间)+底部用户信息」,不是纯会话列表
- 本轮改动:tokens 新增 `--yc-input-slot-gradient`;app.css 重写侧栏(header/content/section/item/footer)+ 输入区渐变 + `.chat-head` 去掉下边框;Sidebar.tsx 改为「新建对话 + 任务分组 + 底部工作目录」;ChatPane 工具栏改为「+ / 模型名 / 发送圆钮」两段式
- **仍未对齐**:真实 WorkBuddy 侧栏顶部有多个导航项与图标集;输入区工具栏还有权限选择器、麦克风等。要做逐像素对齐必须开 CDP 实测真实 WorkBuddy(端口 9223,参考 ygent/docs/workbuddy-cdp.md)
## WorkBuddy CDP 采集准备(视觉对齐第三轮)
- **开关确认**:环境变量 `WORKBUDDY_REMOTE_DEBUGGING_PORT`(在 app.asar 的 `/main/index.js`:commandLine.appendSwitch('remote-debugging-port', r));`/main/server.js` 另有 `--remote-debugging-port=`。当前版本 37.10.3-42 仍有效
- **单实例锁**:起第二个实例(独立 `--user-data-dir`)**无效**,被锁挡掉、端口不开;WorkBuddy 会自行重设 userData
- **结论**:只能「完全退出 → 带环境变量重启」才开 CDP。Agent 跑在 WorkBuddy 内部,重启会中断会话,**必须由用户在外部终端执行**
- 已交付脚本(都在 YCode/scripts):
- `enable-wb-cdp.ps1` —— 一条命令走完:杀进程 → 带 env 启动 → 等端口(≤90s) → 调采集 → 打印产物目录
- `wb-capture.mjs <port> <outDir>` —— CDP 只读采集;44 个选择器(侧栏/对话区/输入区/右栏)+ 41 个精选计算属性 + 顶层布局树 + 截图;产出 `styles.json` + `page.png`
- npm script:`npm run wb:capture`(默认 9223 → `docs/workbuddy-capture`)
- 恢复:退出 WorkBuddy 后不带环境变量重启即关闭调试端口
- 产物按时间戳存 `docs/workbuddy-capture/<ts>/`
### 坑:.ps1 必须纯 ASCII
- 第一版 `enable-wb-cdp.ps1` 带中文,用户执行报 `字符串缺少终止符` —— Windows PowerShell 5.1 按 **ANSI(GBK)** 读 .ps1,中文被读成乱码(`宸茬瓑寰?`)并吃掉闭引号,解析直接失败(未执行,WorkBuddy 未被杀)
- 修法:脚本**全部改用英文输出**,实测 `non-ASCII bytes: 0` + `[Parser]::ParseFile` 通过
- 校验套路(以后写 ps1 都先跑):`[System.Management.Automation.Language.Parser]::ParseFile($p,[ref]$null,[ref]$errors)` 检查语法 + 统计 >127 字节数
- 采集产物改存 `$env:USERPROFILE\.ycode\captures\<ts>`(含真实对话,不进仓库);npm script 默认 `.tmp/wb-capture`
## CDP 实测成功 → 视觉对齐修正(2026-10-15 00:2x)
用户执行脚本后 WorkBuddy 以 CDP 启动,**采集成功**(视口 1334×901 / DPR 1 / zoom 1.0)。
链路:`scripts/wb-capture.mjs`(44 选择器 → styles.json + page.png)+ 新增 `scripts/wb-tree.mjs <port> <selector> [max] [outDir]` 导出子树结构与样式。
**实测数据已固化到 `docs/视觉对齐实测.md`**(以后先读它,别再靠截图猜)。
关键实测修正(我之前做错的地方):
1. **会话内输入框是白底**:`rgb(255,255,255)` + 1px `rgb(230,230,230)` + 圆角 24 + **双层阴影** `rgba(0,0,0,.03) 0 16px 32px -8px, rgba(0,0,0,.06) 0 2px 4px -4px`,`min-height:96`、`padding-top:12`、宽 **784**(不是 832)
- ⚠️ `--wb-bg-input-slot-gradient` 那个灰色渐变属于 **`.wb-home-composer__input-slot`(首页新建对话)**,**不是会话内**。我上一轮用它改错了,已改回
2. **主文字色 `rgba(0,0,0,.9)`**,不是 `#000`
3. **侧栏背景 `#f7f7f7`**(`rgb(247,247,247)`),不是我用的 `#f2f2f2`
4. **侧栏列表项是单行 31px**:`padding 5px 12px`、圆角 8、标题 14px/21 左 + 时间 11px/20 右(不是标题+副标题两行堆叠);导航按钮 255×32、图标 16×16、标签 14px
5. 分组标签 `.conversation-section-label` 30px 高、12px/600、色 `rgba(0,0,0,.5)`、文字形如「任务 (1)」
6. 品牌行高 64、标题 14px/700、版本徽标 10px
7. **右侧详情面板默认收起**(实测宽 1px)→ YCode 默认改为收起
8. 输入区工具栏 56 高 / padding 12 / `justify-content: space-between` / gap 8;发送按钮 32px 圆
9. 对话区 `.cr-message-list__content` 832 宽 + padding 0 40px → 正文列 752;`.cr-agent__header` 24.5 高 / margin-bottom 12 / gap 10;markdown 17.143px/30.0002;段落 15.0001/26.2502/margin-bottom 12;气泡 13/19、`#f2f2f2`、圆角 `16px 16px 0`、max-height 310
待补:右栏展开态(需用户在 WorkBuddy 里展开详情面板后再采一次)。
### 右栏展开态实测(2026-10-15 00:3x,视口 1638×901)
- 采到了:用户展开详情面板后重采,`scripts/wb-tree.mjs .detail-panel`
- 结构:`.detail-panel-container`(647×871, **border-left 1px #ebebeb**) > `.sidebar-next`(白底, **border-radius 12px 12px 0 0**) > `.detail-layout` > `.detail-layout__top`(64px) + `.detail-layout__content`
- 顶栏 `.sidebar-next-main-header`:646×64,`padding 0 16px`,**space-between**,`gap 4px`
- 页签:`.artifact-tab` 240×32(min 80/max 240),`padding 0 8px`,圆角 8,**当前项底色 #f2f2f2**,**14px/600**,行高 22;图标 16×16 色 `rgba(0,0,0,.7)`;关闭钮 14×14 色 #777 圆角 999
- 新增钮 32×32 圆角 8;右侧操作两个 32×32 圆角 6
- **宽度是可拖拽的**:CSS 里 `.detail-panel-container{width:100%}`,由外层布局决定 → 647px 只是本次实测值,不是 CSS 默认
- YCode 已对齐:右栏改为「顶栏 64 + 页签 + 操作按钮」,默认 647px(未实现拖拽调宽),并加了收起按钮
- **新增待补**:30px 高菜单栏 `.codebuddy-menubar`(文件/编辑/视图/帮助),YCode 还是 Electron 默认菜单栏
## 图标采集与接入(用户要求「图标先用 workbuddy 的,先 1:1 还原再改造」)
- 新增 `scripts/wb-icons.mjs`(CDP 导出指定节点 SVG outerHTML → icons.json)+ `scripts/gen-icons.mjs`(生成 icons.tsx)
- 生成 `src/renderer/src/components/icons.tsx`:15 个图标(新建任务/下拉箭头/筛选/收起/分组加号/加号/盾牌/小箭头/麦克风/停止/页签/关闭/右箭头/面板收起/右侧栏)
- **踩坑:SVG 属性必须转 JSX 驼峰**(`fill-rule`→`fillRule`、`stroke-width`→`strokeWidth`、`clip-path`→`clipPath` 等),已在 gen-icons.mjs 的 JSX_ATTRS 里统一处理,否则 React 告警
- `src/renderer/src/components/icons-extra.tsx`:自有矢量(IconSettings 滑杆、IconSendArrow、IconUser),可长期保留
- **合规标注**:icons.tsx 头部已写明「路径取自 WorkBuddy 运行时界面,仅作临时占位,正式发布前必须整体替换」;VS Code codicon 是 MIT 可长期用
- 验证:应用启动成功,`gpuRenderer` 实测 `ANGLE (AMD, AMD Radeon RX 460, D3D11)` —— **GPU 确实在跑**;截图存 `docs/screenshots/ycode-ui.png`
- 启动+截图的可行姿势:在同一个工具调用内完成——清 `ELECTRON_RUN_AS_NODE`、设 `YCODE_DISABLE_GPU_SANDBOX=1`、以独立进程启动 electron(带 `--user-data-dir` / `--remote-debugging-port=9335`),随后 `node scripts/shot.mjs 9335 <out.png>`
## 标题栏 + 自绘菜单栏(2026-10-15 00:4x)
- 实测(`.codebuddy-menubar`):**顶部条带高 30px**;左侧 x=0 宽 **92px** 为侧栏操作区;菜单区 `padding-left:4px`;菜单标题高 24、**`padding: 2px 8px`**、**圆角 4**、**12px/行高20**、色 **`#8b949e`**;菜单项 = **编辑(E)/窗口(W)/帮助(H)/关于(A)**;右侧窗口控制区宽 **138px**(≈46×3)
- 这是**自绘菜单**(VS Code 风格),故必须走无边框窗口
- 已实现:
- 主进程 `frame: false` + `Menu.setApplicationMenu(null)`;新增 IPC `window:minimize|toggleMaximize|close|state`、`edit:action`(走 webContents.undo/redo/cut/copy/paste/selectAll)、`app:info`、`app:openConfigDir`;窗口 maximize/focus 事件推给渲染进程
- 渲染 `components/TitleBar.tsx`:30px 条带、`-webkit-app-region: drag`(按钮/菜单 no-drag)、四个可展开的下拉菜单(条目都接真实行为)、右侧窗口控制(自绘 10×10 图标,关闭键 hover 变 `#e81123`)
- `components/AboutDialog.tsx`(版本/Electron/Chromium/Node/配置目录)+ Ctrl+, 打开设置
- CSS 新增 `.app-root`(列向 flex)+ `.app-shell{flex:1;min-height:0}` 以容纳顶部条带
- **重要坑:宿主环境带 `ELECTRON_RUN_AS_NODE=1`,且会间歇性被继承**,导致 electron 退化成 Node,报 `The requested module 'electron' does not provide an export named 'BrowserWindow'`
- 症状特征:报错里显示 `Node.js v22.21.1`,且 `import { ... } from "electron"` 报无命名导出
- 可靠解法:`Start-Process -UseNewEnvironment`(拿到干净环境块,不带该变量)+ 把 GPU 开关改为**命令行参数** `--disable-gpu-sandbox`(不再依赖 `YCODE_DISABLE_GPU_SANDBOX` 环境变量)
- `cmd /c set VAR= && ...` 被安全策略拦截,不要用
## 空态 + 间距阶对齐(2026-10-15 00:5x)
- 采集时机不巧:WorkBuddy 当时在会话中,页面**无空态元素**(`.claw-local-empty` 等命中 0)→ 本轮数据**取自安装包 CSS**,不是冒烟实测,已在文档里标注
- 实测值:
- 空态 `.colleague-chat-empty--profile`:容器 flex column 居中 / `gap:24` / `padding:0 16`;头像 **64px、边框 1px `#ebebeb`、圆角 18px**(radius lg+md+sm=8+6+4)、下距 16;标题 **24px/34/500**;说明 **max-width 324px、12px/18**
- 快捷提问胶囊:**`padding: 10px 16px`**、**`border-radius: 9999px`**、底色 gray-3 **`#f2f2f2`**、文字 `color-mix(text-primary 90%)`、14px、行高 21、`border: 0`
- 免责声明:`padding: 8px 0`、居中、色 `rgba(0,0,0,.3)`、12px/20、`pointer-events:none`;文案「内容由 AI 生成,请核实重要信息」
- **间距阶修正(重要)**:我原来的 `--yc-space-N` 整体**错位一档**。现按 `spacing-1=2 / 2=4 / 3=8 / 4=12 / 5=16 / 6=20 / 7=24 / 8=32 / 9=40 / 10=48 / 12=64` 对齐,**编号与对标一一对应**,以后翻译对方 CSS 无需换算
- 改动:`tokens.css`(间距阶 + 空态相关)、`app.css`(`.empty*` 重写 + `.composer__disclaimer`)、`ChatPane.tsx`(空态结构 + 免责声明);3 处 `--yc-space-6` 用法改 `--yc-space-7`
- 截图:`docs/screenshots/ycode-empty.png`
- **待复核**:用户切到 WorkBuddy 新建对话页后,可跑 `node scripts/wb-tree.mjs 9223 ".colleague-chat-empty" ` 做一次冒烟核对
## 参照文档已并入本项目 + 分级目标(2026-10-15 00:5x)
- **重要**:SOP 与对齐参照原本都在**另一个仓库** `C:\Users\Administrator\code\ygent\docs\`,YCode 里没有。已把 11 份拷到 **`YCode/docs/reference/`**,项目自此自包含:
`workbuddy-cdp.md`(SOP) / `workbuddy-chat-layout.md` / `workbuddy-composer-reference.md` / `ygent-ui-pixel-parity-feasibility-2026-10-14.md` / `ygent-font-parity.md` / `ygent-sidebar-parity.md` / `ygent-settings-parity.md` / `ygent-model-composer-parity.md` / `ygent-workbuddy-render-audit-2026-10-08.md` / `ygent-workbuddy-ai-gap-2026-10-14.md` / `ygent-chat-parity.md`
- **采用其分级目标**(写进 `docs/视觉对齐实测.md` §0):L1 几何(≤1px) 可达 / L2 静态像素 90%+ / **L3 动态交互一致才是真目标、未完成** / L4 全局 100% 不可能不做
- **沿用其"不做"约定**:不伪造消耗/模型/产物计数凑视觉;不复制平台商业入口;不硬补高度;不把静态像素通过说成动态交互通过;不把绝对 y 差当 margin 修
- 从该文档获得的立即修正:
1. **字体顺序**:实测 `"PingFang SC"` 打头(我原来 `-apple-system` 打头)→ 已改
2. **滚动条**:实测宽 **6px** / thumb **rgba(0,0,0,.2)**(我原来 8px / .15)→ 已改
- **交叉验证成功**:ygent 在 1200×762 下达成的对话区像素级锚点(正文列 w752、输入外框 784×134 + 1px #e6e6e6 + 圆角 24 + 双层阴影、发送按钮 32×32、头像 24×24 gap 10)与我本次在 1334×901 的实测**完全一致** → 说明这些宽度是 token 而非尺寸相关
- **图标许可**:该文档同样指出「逆向取值的 WB 图标照搬涉及资产许可,建议自绘」——与我写在 `icons.tsx` 头部的告警一致,后续替换时优先考虑自绘或 OFL/MIT 图标集
### 参照文档补齐(用户说"复制过来")
- 用户先问「那个 SOP 在当前目录下吗」→ 答:不在,在 `ygent/docs/`。随即要求复制
- 最终 **`YCode/docs/reference/` 共 24 份、288K**,涵盖:SOP、布局/输入区实测、像素级可行性、字体/侧栏/设置/模型对齐、40 项差异审计、能力差距、对话对标路线图、**L3 动态交互对标(37KB)**、流式活动、消息编辑、审批提问、富内容、附件、会话标题、壳层设置、调试、独立会话、参照导入、岗位团队方案
- 索引已写进 `docs/视觉对齐实测.md` §0,项目自此**不再依赖外部仓库**
- **下一步重点**:`reference/ygent-chat-interaction-parity.md` 是 L3 的规范(含必测序列、事件与渲染状态要求),做动态交互前必须先读它
## Token 体系镜像 + 六档字号 + 面板调宽(2026-10-15 凌晨自主推进)
用户指令:持续推进 1:1,拆解/对比 WorkBuddy 必须用 REA,需决策处先推荐并记录、最后统一汇报。
- **完整 token 表已提取并固化**(`docs/视觉对齐实测.md` §11):间距阶 1=2/2=4/3=8/4=12/5=16/6=20/7=24/8=32/9=40/10=48/12=64;字号阶 1..11 = 8,10,12,13,14,16,18,20,24,28,32;行高 4=16/4-2=18/5=20/5-2=22/6=24/7=28/8=32/10=40;控件尺寸 3=12..17=68 + control-sm/ms/md/lg/xl/2xl;圆角 none/xs2/sm4/md6/lg8/xl12/2xl16/3xl20/4xl24/full;体例语义字号(body 14/22/400、caption 12/18/400、code 13/20、h1 24/32、h2 20/28、h3 16/24、display 32/40);**chatflow 独立一套**(h1 21/37、h2 19/33、h3 17/30、h4 15/26、p1 15/26、p2 13/23、p3 11/19)
- **`--yc-*` 编号与 `--wb-*` 一一对应** → 翻译对方 CSS 是机械映射
- **app.css 裸 px 从 321 → 0**(53 处一次性实测值提为具名常量区);`npm run build` 通过
- **六档字号**(`src/renderer/src/fontSize.ts`):`--yc-font-offset-global` + `--yc-md-root`,`clamp(-1,·,2)`,Ctrl+-/+/0,localStorage;实测档位2 = 14px/22px 与基线一致,1→6 档 13/14/15/16/16/16(+2 封顶)
- **关键简化**:因样式已全 token 化,**不需要**像对标那样扫描样式表注入覆盖规则
- **面板调宽**:`.app-shell__resizer` 绝对定位 6px 命中区贴合网格边界(不占网格列),320–900px,默认 647,双击还原,localStorage 持久化
- **补测真实对话区顶栏 `.workbuddy-topbar`:高 64px / padding 0 16px / 两端对齐** → `.chat-head` 据此改写(原自拟 12px 作废)
- **REA 使用记录**:
- 成功:`open_binary app.asar`(asar/archive) + `inspect_artifact` → 12253 节点 / 14476 文件 / **45 处完整性矛盾**(首条 `cli/bin/native/win32-x64/job-object.node`,即 Job Object 原生模块)
- **边界(重要)**:REA 的 CDP 浏览器 provider **只枚举 HTTP(S) 目标**,WorkBuddy 是 `file://` → `list_browser_targets` 返回 `targets:[]`,故 `inspect_web_page`/`capture_web_screenshot`/`compare_web_captures` **无法观察 WorkBuddy**;仍须用自建 CDP 脚本。REA 二进制 provider 本机未配置且不接归档 → 无字符串检索
- 新增脚本:`scripts/verify-tokens.mjs`(运行时 token 校验)、`scripts/pngdiff.mjs`(无依赖 PNG 像素对比,zlib 手写解码)
- 回归对比:token 化前后变化像素 2.673%(已定位为 chat-head 位移 + 抗锯齿重绘)
- **汇报与决策记录:`docs/本轮汇报与决策记录.md`**(含 D1–D10 决策、被否决选项、阻塞项、下一步)
## 外围壳层配齐(2026-10-15 凌晨,用户新指令)
用户指令:**「先把外围配齐,登录账号先用 mock 写死数据,通知、发现应用、收起、搜索、分类、设置等等等,还差非常多」**
→ **推翻了我此前的 D7/D8「不摆空壳」决策**,改为全部实现 + mock 数据。
已实现(全部按实测尺寸):
- **品牌区**:标题 14/700 + 版本徽标 10px + **「发现应用」按钮 98×28 / 圆角 9999 / bg #f2f2f2 / 12px500**
- **导航项 6 个**:新建任务 / 助理(Beta 徽标) / 专家·技能·连接器 / 定时任务 / 资料库 / 更多(灵感副文案);**215×32、padding 5px 12px、圆角 8、图标 16、文字 14**
- **搜索**:放导航下方,**真实过滤任务列表**(不是装饰)
- **分类分组**:任务 (N) / 空间 (N),标签 **30 高 sticky、padding 5px 12px、圆角 8、12px/600、色 rgba(0,0,0,.5)**;折叠箭头与操作按钮默认 opacity 0
- **账号区(mock)**:footer **57 高、padding 8 12 8 8、border-top 1px #e6e6e6**;头像 **28×28 圆、bg #ebebeb**;用户名 12/600;铃铛 **32×32 圆角 6**;**未读角标 14×14、#f64041、9px/500**
- **通知面板**(mock 3 条)+ **设置分区**(账号/模型/外观/工作目录/关于,左侧分区导航)
- **侧栏收起**为 44px 窄轨(localStorage 持久化)
- 新增图标 8 个(导航 5 + 铃铛 + 小程序 + 发现应用),图标模块共 **23 个**
**重要实测发现**:**侧栏宽度不是常量** —— 两次采集分别 280px(@1334 窗口) 与 240px(@1276 窗口)。
**Mock 约定(重要)**:`src/renderer/src/mock.ts`,全部 `MOCK_` 前缀;**UI 上必须显式标注为示例数据**(通知面板底部、设置→账号页、账号按钮 title 三处已落实);未实现入口点击给 2 秒「尚未实现」提示,**不伪造可用状态**。
新增决策 D11(mock 标注方式)/ D12(搜索落点)/ D13(未实现入口反馈);D7 标注为「已被用户推翻」。
新增脚本:`scripts/wb-shell.mjs`(外围结构采集)、`scripts/click-shot.mjs`(点击后截图验收)。
样式拆分为 `styles/sidebar.css`(独立文件,避免 app.css 过长)。
## 标题栏左上操作区(2026-10-15 凌晨补充)
用户指出左上角不一致(我那里是空的 92px)。补采实测:
- `.conversation-list-topbar-actions` 内含**三个 24×24 按钮**,位置 **x=8 / 34 / 60**,`gap: 2px`,圆角 6
- 依次为 **收起侧边栏 / 搜索 / 筛选**(title 属性即这三个词)
- 已实现:新增图标 `IconCollapseSidebar` + `IconSearchTopbar`(`IconFilter` 此前已有),图标模块共 **25 个**
- 交互接线:收起侧边栏 → 侧栏折叠;搜索 → 展开侧栏并聚焦搜索框;筛选 → 走统一的「尚未实现」提示通道
- 新增全局事件约定:`ycode:focus-search`(聚焦侧栏搜索)、`ycode:not-implemented`(外围未实现入口的统一反馈)
- **验收**:三个按钮实测落在 x=8/34/60、24×24、gap 2,与对标完全一致
**CDP 可写能力**:CDP 不仅能读,也能**点击与导航**(`Runtime.evaluate` 里 `.click()`),
即可直接切换 WorkBuddy 的页面状态。但点击会**真实改变用户的应用状态**
(例如「新建任务」会真的建一个任务),与参考 SOP「只读采集」的约定不同,需用户明确同意后再做。
## 用户批准方案 B(CDP 驱动 WorkBuddy)+ OMP 接入(2026-10-15 凌晨)
### 决策
- **方案 B 已获批准**:我可用 CDP 直接点击/切页采集 WorkBuddy。已用此采到**首页/新建任务页**
- **底层循环接入 OMP**(本地 Agent 内核),**支持 responses 格式**,使用 `https://api.iiiii.run` + 用户给的 key(有限额,用户起床过期)
### OMP 事实(重要,勿再重查)
- 可执行文件:**`C:\Users\Administrator\AppData\Local\Ygent\omp.exe`**(随 Ygent 安装);`omp/18.6.3`
- 配置:默认 `~/.omp/agent/models.yml`;**命名 profile 在 `~/.omp/profiles/<name>/agent/`**,用 `OMP_PROFILE=<name>` 选择
- RPC:`omp --mode rpc`,**stdio 上的 newline-delimited JSONL**(非 JSON-RPC 2.0);启动先发 `ready` 帧;单帧上限 1MiB
- 其它 mode:`text`(默认)/ `json` / `rpc` / `rpc-ui`
- 常用 flag:`-p/--print`(非交互)、`--model`、`--cwd`、`--config`(叠加覆盖)、`--profile`、`--session-dir`、`--no-session`
- 协议文档:`ygent/docs/reference/omp/`(rpc.md 89KB / cli.md / models.md / env.md / approval.md)
- **`api:` 字段取值**含 `openai-completions` / **`openai-responses`** / `openai-codex-responses` / `azure-openai-responses`
### 已完成的配置(未动用户的 ygent 配置)
- 新建 **`~/.omp/profiles/ycode/agent/models.yml`**:provider `ycode`,baseUrl `https://api.iiiii.run/v1`,
**`api: openai-responses`**,模型 `gpt-6-luna` / `gpt-6-astra` / `gpt-6.1-sol`
- **验证通过**:`OMP_PROFILE=ycode omp.exe -p --model ycode/gpt-6-luna "回答两个字:收到"` → 返回「收到」
- 上游 `api.iiiii.run` 同时支持 `/v1/chat/completions` 与 `/v1/responses`(含流式 SSE `event: response.created`)
- **API Key 处理**:只写入 `~/.omp/profiles/ycode/...`(仓库外);**未落任何仓库文件**
### 首页空态实测(方案 B 产出,见 `docs/视觉对齐实测.md` §15)
- 真实首页 = 大标题「<产品名>, 我帮你」+ 分段控件 + **分类胶囊行** + 输入框 + 工作目录/权限行 + 建议列表 + 免责声明
- 分类胶囊:**高 32 / padding 0 12 / gap 4 / bg #f7f7f7 / 边框 1px #dedede / 圆角 100px / 14px**;列表宽 **680**,gap 8
- **首页编辑区 74px,会话内 64px** —— 两者不同
- 旧空态(头像+竖排胶囊)是**从 CSS 推断的,与真实不符**,已按实测重写
### 新增脚本
`wb-probe.mjs`(按文案定位,应对 CSS Module 哈希类名)、`wb-home.mjs`、`click-shot.mjs`
### 教训(重复踩了两次)
**不要把多行 JS 内联在 `node -e "..."` 里**(shell 引号会吃掉换行,报 SyntaxError)。一律写成 `.mjs` 脚本文件。
## 首页空态推翻重做(2026-10-15 上午,用户指出「几乎不一样」)
用户醒来后指出新建对话页还是不对。逐项精测后发现**第一轮实现整体结构错误**:
- 错:输入框底部停靠、10 个分类挤一行、无分段控件、无工作目录/权限行
- 对:**居中内容列(x=353 宽 800)、输入框在页面中部、建议列表在其下方**、
分类分两处(分段控件 3 个 + 胶囊行 7 个)、输入框下方有「工作目录+权限」行
精测值(`docs/视觉对齐实测.md` §15.5):
- 标题 h1 **30px/600/行高42**,rect [614,159,278,42]
- 分段控件 [643,219,220,32];分类行 [353,317,680,32];输入框外层 [353,365,800,184]
- 白框 144(圆角24/padding-top 12/白底/双层阴影);编辑区 74;工具栏 56;**纵向无 gap**
- 建议项 **高 38/圆角 9999/白底/边框 1px #e6e6e6/14px**,行距 **50**(38+12),左对齐
- 垂直间距:标题→分段 18 / 分段→分类 66 / 分类→输入 16 / 输入→建议 52
- 会话内输入框 **134**(12+64+56+2);首页白框 **144**(12+74+56+2)—— 都无 gap
**已重做**:ChatPane 拆 `composer`(`data-variant` 区分 64/74 编辑区高)+ `composerFooter`;
首页 `.home` 布局。构建通过,截图对比已接近。
**方法论教训(重要)**:**第一次只按「分类胶囊」这一个元素去对齐,没测整页垂直结构** →
局部对了、整体还是错的。以后对齐一个页面,**必须先量整页的垂直堆叠(各区块 y/h)**,
再量单元素。`scripts/wb-home-layout.mjs` + `wb-home-parts.mjs` 就是为此写的。
## OMP 内核接入完成(2026-10-15 上午,用户拍板方案 A)
**YCode 已从「自建网关+自写循环」转为 OMP 前端壳**,端到端验证通过。
- `src/main/omp.ts`:OmpKernel(spawn `omp.exe --mode rpc --profile ycode --cwd <ws> --no-session`、JSONL 解析、id 关联、ready 等待、退出清理)+ `detectOmpPath()`(YCODE_OMP_PATH → `%LOCALAPPDATA%\Ygent\omp.exe`)
- `src/main/agent/omp-turn.ts`:OMP 事件 → ChatEvent(text_delta→text、tool_execution_*→tool_call/result、agent_end yielded→done、prompt_result error→error、abort→cancelled)
- `src/main/ipc.ts`:**会话→内核进程池**(每会话一个 omp.exe,上下文由 OMP 进程内维护,磁盘持久化仍归 YCode);会话删除释放进程;OMP 不可用回退自建 loop
- **验证**:「只回复收到」→「收到」;「列出工作目录文件」→ 3 张工具卡 **glob/read/bash(OMP 原生工具)**,全 ok,回复「12 个文件」
- **关键坑**:`spawn ENOENT` 但 exe 存在 → 是 **cwd 不存在**(工作目录空字符串)。spawn 的 cwd 与 exe 无关,必须兜底(回退 homedir)
- 工具事件载荷文档未给全 → `readToolInfo()` 多形状兼容解析(toolCall/call/tool/data 逐层找)
- 会话内 134 = 12+64+56+2、首页白框 144 = 12+74+56+2,**纵向都无 gap**(之前多加了 4px 导致差几像素)
- 新增脚本:`e2e-send.mjs`(UI 层端到端发消息)、`probe-tools.mjs`(工具卡探测)
- **遗留**:abort 未端到端验证;key 过期需更换 `~/.omp/profiles/ycode/agent/models.yml`