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

34 KiB
Raw Blame History

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