228 lines
12 KiB
Markdown
228 lines
12 KiB
Markdown
# WorkBuddy 对话区 / 右侧栏 UI 能否 1:1 复刻
|
||
|
||
**评估对象**:WorkBuddy 桌面版渲染进程 UI(`app.asar.unpacked/renderer`)+ 侧栏类扩展(`resources/extensions/*/ui`)
|
||
**评估方法**:REA MCP(`analyze_javascript_application` 实测)+ 资源清单/混淆度/CSS 类名/库指纹取证
|
||
**评估日期**:2026-10-14
|
||
**结论前置**:**UI 层是整个 WorkBuddy 里最接近可复刻的部分——视觉与结构可做到高度 1:1,交互行为需重写,数据流为 0(在云端)。**
|
||
|
||
---
|
||
|
||
## 0. 一句话结论
|
||
|
||
引擎层「不可 1:1」的核心障碍是**原生二进制 + 压缩 bundle**;而 UI 层**两个障碍都不存在**——
|
||
|
||
- 渲染进程代码**基本没有混淆**(920 个具名 React 组件、10,347 个可读函数名保留在 7.5MB 主 chunk 中,函数体逐行可读)
|
||
- CSS、设计 token、i18n、图标资源**全部明文可提取**
|
||
- UI 技术栈**几乎全是开源库**
|
||
|
||
**所以:对话区与右侧栏,可以做到「视觉 + 结构 + 交互行为」层面的 1:1 复刻;但「源码/二进制 1:1」仍然不行(版权),且排除云之后它是一套没有数据的空界面。**
|
||
|
||
---
|
||
|
||
## 1. 决定性证据:渲染进程代码未混淆
|
||
|
||
### 1.1 实测:函数体逐行可读
|
||
|
||
抽取 `contexts-BMeWSUHk.js`(7,549,089 B)中的真实代码:
|
||
|
||
```js
|
||
function ConversationInputArea({viewConversationId:e, renderRootId:t, scenarioId:n,
|
||
maxContentWidth:r, inputTopSlot:i, customFloatingSlot:a, cloudServiceQuotaBar:o,
|
||
fullscreenDropContainerRef:s, onPromptQueueInsetChange:c}){
|
||
let l = useConversationError(),
|
||
u = useConversationSessionSelector(selectConversationInputAreaSession, shallow$1),
|
||
{pending:d, planAdjustment:f} = useConversationInteraction(),
|
||
p = useConversationPromptQueue(),
|
||
m = useCreditInputBannerProvider(),
|
||
h = useConversationBackgroundTasks(),
|
||
g = useConversationApi(), ...
|
||
```
|
||
|
||
```js
|
||
function ConversationStreamingFooterImpl({options:e}){
|
||
let t = useConversationSessionSelector(selectConversationStreamingFooterSession, shallow$1),
|
||
n = useConversationI18n(),
|
||
...
|
||
let {reasoningOnly:s, credit:c, hasMessage:l} =
|
||
useConversationMessagesSelector(createStreamingFooterMessageSelector(e.messageId,o), shallow$1), ...
|
||
```
|
||
|
||
**解读**:只有空白被压掉(平均行长 9,764 字符)和**局部变量重命名为单字母**(`e/t/n/r`),而——
|
||
- **组件名、props 名、自定义 Hook 名、selector 名、状态机枚举值全部保留**
|
||
- 依赖注入关系(哪个组件用哪个 Hook)一目了然
|
||
|
||
对照:`main/server.js` 是真正压缩过的(平均行长 3,037、全单字母标识符)——**腾讯压了主进程,却没压渲染进程**。这是 UI 可复刻率远高于引擎的直接原因。
|
||
|
||
### 1.2 量化指标
|
||
|
||
| 文件 | 大小 | 行数 | 平均行长 | 保留的可读函数名 |
|
||
| --- | --- | --- | --- | --- |
|
||
| `contexts-BMeWSUHk.js` | 7.55 MB | 772 | 9,764 | **10,347** |
|
||
| `src-0FGg1seX.js` | 2.68 MB | 1,347 | 1,986 | 1,136 |
|
||
| `colleague-chat-page-DUBLIFUp.js` | 225 KB | 3 | 56,379 | 258 |
|
||
| `agent-chat-pane-CUPwHdfj.js` | 7.4 KB | — | — | **整文件可直读** |
|
||
|
||
全量普查:**920 个具名 React 组件**(`AccountPanel`、`ConversationPromptQueuePanel`、`DetailPanelSurfaceProvider`、`ClawSecondarySidebar`…)。
|
||
|
||
### 1.3 REA 实测运行记录
|
||
|
||
| 目标 | 结果 |
|
||
| --- | --- |
|
||
| `renderer`(限定 2 个 JS 源文件) | parsed=2、AST 节点=2,495、findings=67、**parse_failures=0**;data-flow 关系 1,561、closure 237 |
|
||
| coverage | `partial`(1,165 个文件未在本次选入范围) |
|
||
| 限制 | REA 自身声明:静态语法观察,不代表运行时;未执行 bundle bootstrap |
|
||
|
||
> 注意:CSS 文件**不能**作为 `analyze_javascript_application` 的 `source_paths`(实测被拒:`invalid_value`)——CSS 需用普通文本/样式工具处理,不归 REA。
|
||
|
||
---
|
||
|
||
## 2. 视觉层:CSS + 设计 token 可完整提取
|
||
|
||
### 2.1 CSS 明文且类名语义化
|
||
|
||
CSS 是压缩的(注释已被剥离,`/* */` 计数为 0),但**是 100% 有效 CSS,可直接提取**,且**类名一个都没被 hash**:
|
||
|
||
```css
|
||
.claw-agent-chat-pane{--claw-agent-chat-content-max-width:832px;
|
||
background:var(--wb-home-bg-secondary);flex-direction:column;width:100%;height:100%;...}
|
||
.colleague-chat-cb-chat [class*=input-area-container]{max-width:var(--cb-chat-max-content-width);...}
|
||
```
|
||
|
||
对话区相关类名(抽样):
|
||
|
||
```
|
||
.cb-chat-message--user .cb-chat-message--assistant .cb-chat-message-bubble
|
||
.cb-chat-tool-renderer .cb-chat-search-hit--current .cb-message-time-tip
|
||
.cb-input-banner--error .cb-message-queue-item .cb-message-queue-item-dragging
|
||
.cb-message-queue-item-drag-over-before .assistant-message-tool-container
|
||
.cb-chat-toast .cb-message-queue-item-single .cb-task-list-input
|
||
```
|
||
|
||
右侧栏相关类名(抽样):
|
||
|
||
```
|
||
.detail-sidebar .detail-sidebar--collapsed .detail-sidebar--file-version
|
||
.detail-sidebar-sash .claw-secondary-sidebar .claw-secondary-sidebar--pinned
|
||
.claw-secondary-sidebar--floating .claw-sidebar-drawer--floating .conversation-sidebar
|
||
.colleague-detail-panel .colleague-detail-sidebar-module .cb-sidebar-nav--compact
|
||
.cb-sidebar-category--file-tree .codicon-layout-sidebar-right-dock
|
||
```
|
||
|
||
**类名本身就是 DOM 结构说明书**(BEM 风格:块-元素-修饰符)。CSS 总量:`wb-` 前缀变量/类 1,425 个 + `cb-` 前缀组件类 437 个。
|
||
|
||
### 2.2 设计 token 完整(1,563 KB 的 `contexts-BkjwYSZT.css`)
|
||
|
||
```css
|
||
:root,body[data-vscode-theme-name=IDE\ Light]{
|
||
--wb-palette-brand-8:#00c29a; --wb-palette-brand-9:#009273;
|
||
--wb-palette-blue-7:#3370ff; --wb-palette-purple-6:#7c5cfc;
|
||
--wb-color-text-primary; --wb-color-border-secondary; --wb-radius-lg;
|
||
--wb-spacing-4; --wb-font-h1-size; --wb-alert-border-radius; ...
|
||
}
|
||
```
|
||
|
||
主题系统(light/dark/皮肤)**完全基于 CSS 变量**,且 `index.html` 内联脚本展示了主题注入协议(`windowTheme`/`colorScheme` → `root.dataset.theme`)。这意味着**换肤体系可以原样重建**。
|
||
|
||
顺带:`codicon-layout-sidebar-*` 证明图标用了 **VS Code codicon**(MIT 开源)。
|
||
|
||
---
|
||
|
||
## 3. 资源与国际化:全部本地明文
|
||
|
||
| 资源 | 状态 |
|
||
| --- | --- |
|
||
| i18n 语言包 | ✅ 全量本地:`zh-cn`(1.14MB)、`zh-tw`(1.07MB)、`en`(0.87MB),含全部 `chat.*` key(`chat.input.placeholder`、`chat.search.*`、`chat.input.sendShortcutTooltip`…) |
|
||
| 图标 | ✅ `icons-DmAL6CTu.js`(3.7MB)、大量 `.svg`(`file-pdf-color-link`、`wechat-color-link`…) |
|
||
| 插图/位图 | ✅ `claw-welcome-light.svg`(1.6MB)、`inspiration-fallback-{1,2,3}.png`、`empty-no-files.png`、`drop-files-icon-{light,dark}.png` |
|
||
| 字体 | ✅ 本地字体文件(`PingFang SC` 等走系统回退) |
|
||
|
||
> i18n key 用模板字符串存 Unicode 转义,可无损还原中文原文。**UI 文案零云依赖**。
|
||
|
||
---
|
||
|
||
## 4. UI 技术栈几乎全开源 → 直接复用,无需"复刻"
|
||
|
||
库指纹扫描(在 renderer bundle 中命中):
|
||
|
||
| 能力 | 采用的开源库 | 命中文件数 |
|
||
| --- | --- | --- |
|
||
| 框架 | **React 18** + rolldown 构建 | — |
|
||
| 无障碍/弹层原语 | Radix UI | 17 |
|
||
| 定位/浮层 | Floating UI | 54 |
|
||
| 状态管理 | Zustand | 39 |
|
||
| 图表 | **mermaid** | 101 |
|
||
| 公式 | **KaTeX** | 49 |
|
||
| 白板 | **Excalidraw** | 63 |
|
||
| PDF | **PDF.js** | 1 |
|
||
| 终端 | xterm | 9 |
|
||
| 代码编辑器 | **Monaco** | 15 |
|
||
| Markdown | marked / markdown-it | 17 / 1 |
|
||
| 代码高亮 | shiki / prism | 4 / 7 |
|
||
| 净化 | DOMPurify | 3 |
|
||
| 国际化 | i18next | 16 |
|
||
| 时间 | dayjs | 50 |
|
||
| 动画 | framer-motion | 3 |
|
||
|
||
**除 `cb-` 前缀的内部设计系统组件库外,UI 没有任何自研底层**。这意味着"复刻 UI"实际是"用同一批开源库重搭一遍"。
|
||
|
||
---
|
||
|
||
## 5. 侧栏的形态:壳 + 扩展
|
||
|
||
右侧栏不是单一组件,而是**主壳 + 独立扩展 UI**:
|
||
|
||
```
|
||
resources/extensions/
|
||
library/ ← 资料库 {assets/ ui/assets/ extension.json distribution.json}
|
||
global-search/ ← 全局搜索
|
||
im-channels/ ← 消息通道(23MB) 含 server/ + ui/
|
||
community/ ← 社区 (12MB)
|
||
cloud-assistant/ ← 云助手
|
||
workbuddy-baas-v2/ (15MB) edge-sync/ remote-desktop/
|
||
```
|
||
|
||
主壳侧栏由 `DetailPanelSurfaceProvider / DetailPanelSurfaceHost / DetailPanelSurfacePortal`、`ClawSecondarySidebar`、`ConversationArtifactPanelHost` 等组件驱动(均为可读组件名),扩展以独立 `ui/assets` 形式挂载。
|
||
|
||
---
|
||
|
||
## 6. 那么,到底能复刻到什么程度?
|
||
|
||
| 层面 | 可复刻度 | 说明 |
|
||
| --- | --- | --- |
|
||
| **视觉外观**(布局/配色/圆角/间距/阴影/动效) | **~95%** | CSS 明文 + token 完整 + 资源可复制;剩余差异来自字体渲染与平台差异 |
|
||
| **DOM 结构 / 组件树** | **~90%** | 类名语义化 + 920 个具名组件 + props 可读;可完整重建组件边界 |
|
||
| **交互行为**(输入、发送、流式渲染、折叠、拖拽排序、滚动、快捷键) | **~70%** | 状态机与 Hook 语义可读但要**重写**(局部变量被混淆、跨文件依赖多);跨进程/原生部分受限 |
|
||
| **数据/内容流**(模型列表、专家、会话历史、配额) | **0%** | 全在云端,属被排除的「云部分」 |
|
||
| **源码二进制 1:1** | **0%** | 复制 CSS/资源/代码仍构成侵权 |
|
||
|
||
### 具体受限点(诚实清单)
|
||
|
||
1. **函数内部逻辑被混淆**——`let l=..., u=...` 只能靠 Hook 名与调用顺序推断;行为需重写而非复制。
|
||
2. **跨进程交互**:窗口控件、原生菜单、文件对话框、拖到 Dock、剪贴板、截图 → 走主进程 + 原生模块(`@ban-dal/os-bridge`、`wwapi-electron` 等)。
|
||
3. **富文档预览**:office 预览经 `editor_sdk.exe`(199.5MB,见引擎报告)→ **不可复刻**;但 PDF.js / Excalidraw / 图片 预览路径是开源的,可复用。
|
||
4. **内部组件库**:`cb-` 前缀 437 个类对应的组件需自行重写。
|
||
5. **数据源**:排除云后,对话区与侧栏**没有内容可渲染**——必须自建模型网关与服务端(这是真正的护城河,也是上篇报告已指出的核心)。
|
||
|
||
---
|
||
|
||
## 7. 最终判断
|
||
|
||
> **对话区 / 右侧栏:UI 层可以做到 1:1 的「样子和手感」,做不到 1:1 的「源码」,且做出来是空壳。**
|
||
|
||
- 与引擎层的本质差别:**引擎层卡在原生二进制与压缩 bundle;UI 层这两者都不存在。** 渲染进程代码几乎未混淆、CSS/token/i18n/资源全明文、技术栈全开源。
|
||
- 工作量重心从"逆向还原"变成"用开源栈重搭 + 按可读组件名重组交互",这比复刻引擎现实得多。
|
||
- 但两个天花板不变:**版权**(不能复制产出物)与**云依赖**(没有数据源,界面无内容)。
|
||
- 结论落到可执行建议:**把 UI 分析产出当作「设计规范 + 组件清单 + 交互说明」来用**——这是安全且高价值的用法;要落地产品,用同一批开源库 + 自建后端重写。
|
||
|
||
---
|
||
|
||
### 附:本次取证命令与命中数据(可复核)
|
||
|
||
- `agent-chat-pane-CUPwHdfj.js` 与 `-F5lfde1Z.css` 全文可读(`AgentChatPane`、`computeAgentChatMaxContentWidth`、`shouldHideAssistantDuration`)
|
||
- `contexts-BMeWSUHk.js`:10,347 个具名函数;`ConversationInputArea`、`ConversationStreamingFooterImpl` 函数体可读
|
||
- CSS 类名抽样:`.cb-chat-message--user`、`.detail-sidebar--collapsed`、`.claw-secondary-sidebar--pinned`、`.codicon-layout-sidebar-right-dock`
|
||
- token 抽样:`--wb-palette-brand-8:#00c29a`、`--wb-color-text-primary`
|
||
- i18n:`zh-cn-Dfzn8myY.js` 含 `chat.input.placeholder`、`chat.search.placeholder`、`chat.input.sendShortcutTooltip`
|
||
- 库指纹:radix=17、floating-ui=54、zustand=39、mermaid=101、katex=49、excalidraw=63、pdfjs=1、monaco=15、marked=17、i18next=16、dayjs=50
|
||
- REA:`renderer` 目录分析 → 2 文件 / 2,495 AST 节点 / 67 findings / 0 parse failures / coverage=partial
|