34 KiB
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.mjs9.48MB/2679 行、平均行长 3539;main/server.js3.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.jsavg 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 报错)- 关键坑(务必记住):
electron在 devDependencies,externalizeDepsPlugin不外置它 → 必须显式rollupOptions.external: ['electron'],否则会把 electron 的 Node 入口内联进主进程- sandbox:true 要求 preload 为 CJS → preload 输出
format:'cjs', entryFileNames:'index.cjs';主进程为 ESM(index.mjs),__dirname由 electron-vite shim - TS 7 移除了
baseUrl,paths 必须写成./src/... - GPU 进程沙箱:在受限进程树里 Chromium GPU 子进程以 0xC0000005 反复崩溃 → 用
YCODE_DISABLE_GPU_SANDBOX=1(仅关 GPU 沙箱,GPU 仍生效,实测 3 进程 0 崩溃) 或YCODE_DISABLE_GPU=1(纯软渲染兜底) - 宿主环境带
ELECTRON_RUN_AS_NODE=1,从该环境启动 electron 会退化成普通 node → 需env -u ELECTRON_RUN_AS_NODE或换正常终端 - 从 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,activetransform:scale(.93),禁用opacity:1 - 侧栏导航(BEM
cb-sidebar-nav__*):itempadding:8px 20pxflex 对齐;选中__item--selected用 list inactiveSelectionBackground(即灰底);icon14×14且color-mix(text-primary 60%)+margin-right:8px;title13px/400/1.3;sectionmargin-bottom:16px;section-title11px/600/uppercase/letter-spacing .5px/padding 8px 20px 4px;header-title13px/600/uppercase/opacity 30%;contentflex:1;padding:8px 0 16px;overflow-y:auto;footerborder-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(以后先读它,别再靠截图猜)。
关键实测修正(我之前做错的地方):
- 会话内输入框是白底:
rgb(255,255,255)+ 1pxrgb(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(首页新建对话),不是会话内。我上一轮用它改错了,已改回
- ⚠️
- 主文字色
rgba(0,0,0,.9),不是#000 - 侧栏背景
#f7f7f7(rgb(247,247,247)),不是我用的#f2f2f2 - 侧栏列表项是单行 31px:
padding 5px 12px、圆角 8、标题 14px/21 左 + 时间 11px/20 右(不是标题+副标题两行堆叠);导航按钮 255×32、图标 16×16、标签 14px - 分组标签
.conversation-section-label30px 高、12px/600、色rgba(0,0,0,.5)、文字形如「任务 (1)」 - 品牌行高 64、标题 14px/700、版本徽标 10px
- 右侧详情面板默认收起(实测宽 1px)→ YCode 默认改为收起
- 输入区工具栏 56 高 / padding 12 /
justify-content: space-between/ gap 8;发送按钮 32px 圆 - 对话区
.cr-message-list__content832 宽 + padding 0 40px → 正文列 752;.cr-agent__header24.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-tab240×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);新增 IPCwindow: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 修
- 从该文档获得的立即修正:
- 字体顺序:实测
"PingFang SC"打头(我原来-apple-system打头)→ 已改 - 滚动条:实测宽 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:providerycode,baseUrlhttps://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(含流式 SSEevent: 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(spawnomp.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