cc-haha/docs/desktop/02-architecture.md
程序员阿江(Relakkes) 386a41e606 feat(desktop): enable Electron migration path
Introduce the Electron desktop shell alongside the existing React renderer and local Bun server boundary. The migration keeps the DesktopHost contract explicit across Tauri, Electron, and browser runtimes while adding Electron main/preload services for dialogs, shell, notifications, updates, tray/window lifecycle, terminal, preview WebContentsView, app mode, and release/package validation.

The commit also carries the latest local main desktop command updates, including agent slash entries and hidden-by-default markdown thinking details, so the packaged Electron build matches the current main UX surface.

Constraint: React renderer, local Bun server, REST/WebSocket, and sidecar boundaries must remain reusable during the migration
Constraint: macOS dev packages are ad-hoc signed and cannot prove Developer ID notarization or Gatekeeper release launch
Rejected: Browser-only smoke validation | it cannot exercise native dialogs, keychain prompts, notification behavior, or packaged app startup
Confidence: medium
Scope-risk: broad
Directive: Do not remove Tauri host support until signed Electron release artifacts pass native OS smoke on macOS, Windows, and Linux
Tested: bun run check:desktop
Tested: cd desktop && bun run check:electron
Tested: CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron📦dir
Tested: bun run test:package-smoke --platform macos --package-kind dir --artifacts-dir desktop/build-artifacts/electron
Tested: Computer Use read packaged Electron app window at desktop/build-artifacts/electron/mac-arm64/Claude Code Haha.app
Not-tested: Developer ID signed/notarized Gatekeeper launch
Not-tested: Real OS notification click-to-session action
Not-tested: Windows and Linux packaged app smoke on real hosts
2026-06-01 22:43:16 +08:00

16 KiB
Raw Blame History

架构设计

从 Electron host 到 CLI 子进程,桌面端的三层通信架构。


技术栈

前端

技术 版本 职责
React 18 UI 框架
Zustand 5 状态管理
Vite 6 构建工具
Tailwind CSS 4 样式
Shiki 4 代码高亮
Mermaid 11 图表渲染
marked + DOMPurify - Markdown 渲染
react-diff-viewer 4 Diff 展示
Lucide React - 图标

桌面层

技术 版本 职责
Electron - 跨平台桌面 host管理 Chromium renderer、窗口、IPC 和系统能力
electron-builder - macOS/Windows/Linux 打包与 release artifact 生成
electron-updater - 自动更新检查、下载与安装
node-pty - Electron main 中的终端 PTY runtime
Tauri 2 2 迁移期 legacy host 与 sidecar 资源目录React 层通过 desktopHost adapter 隔离

服务端

技术 职责
Bun 运行时 + 构建工具
Bun.serve HTTP/WebSocket 服务器

字体

  • Inter — 正文
  • Manrope — 标题
  • JetBrains Mono — 代码
  • Material Symbols Outlined — 图标

三层架构

┌─────────────────────────────────────┐
│         Electron Host (main/preload) │
│  ┌─────────────────────────────┐    │
│  │   Chromium Renderer         │    │  ← React 用户界面
│  └───────────┬─────────────────┘    │
│              │ HTTP + WebSocket      │
│  ┌───────────▼─────────────────┐    │
│  │   Server Sidecar (Bun)      │    │  ← API 服务 + 会话管理
│  │   Port: 动态分配             │    │
│  └───────────┬─────────────────┘    │
│              │ 子进程 spawn          │
│  ┌───────────▼─────────────────┐    │
│  │   CLI 子进程                 │    │  ← AI 对话 + 工具执行
│  └─────────────────────────────┘    │
│                                     │
│  ┌─────────────────────────────┐    │
│  │   Adapter Sidecar (可选)    │    │  ← Telegram/飞书接入
│  └─────────────────────────────┘    │
└─────────────────────────────────────┘

第一层Electron Host

职责窗口管理、Sidecar 进程编排、原生 API 桥接

核心文件位于 desktop/electron/,通过 preload 暴露 window.desktopHostrenderer 只调用 typed host contract不直接调用 Electron IPC。

能力 说明
runtime.getServerUrl 前端获取 Server Sidecar 的 HTTP 地址
dialogs.open/save 系统文件/目录选择与保存对话框
shell.open/openPath 外链与本地路径打开main 侧做 scheme/path allowlist
updates.check/download/install electron-updater 检查、下载、安装与 relaunch
terminal.* node-pty 会话创建、写入、resize、kill 和事件转发
preview.* WebContentsView 预览面板与 preview-agent message bridge
appMode.* 默认/便携模式和 CLAUDE_CONFIG_DIR 启动语义

状态管理

模块 说明
serverRuntime.ts server/adapters sidecar 生命周期、动态端口、日志和 env 注入
sidecarManager.ts sidecar 二进制定位、参数构造、子进程管理
windows.ts 窗口状态持久化、显示/聚焦、close-to-hide 生命周期
updater.ts 更新元数据归一化、下载进度和安装前状态校验

启动流程

  1. 应用启动时解析便携模式,必要时设置 CLAUDE_CONFIG_DIR
  2. 创建 BrowserWindow 并注入 preload hostdev 模式只允许 localhost rendererpackaged 模式加载 app.asar/dist/index.html
  3. renderer 调用 runtime.getServerUrl()Electron host 启动 claude-sidecar server --app-root ... --host 0.0.0.0 --port {dynamic}
  4. server 健康检查通过后React 继续加载设置、会话和 WebSocket。
  5. 修改 IM adapter 配置后renderer 调用 adapters.restartSidecar()host 重启 claude-sidecar adapters 并注入 ADAPTER_SERVER_URL

退出处理:窗口默认 close-to-hide明确退出、更新安装或 app mode restart 前会停止 server/adapters sidecar。

平台差异

  • macOSoverlay titlebar + 自定义菜单(关于、设置 Cmd+,、编辑、窗口)
  • Windowsset_decorations(false) 隐藏原生标题栏,前端自定义渲染 TitleBar + WindowControls

第二层Server Sidecar

职责HTTP REST API + WebSocket 网关 + 会话管理 + 协议代理

核心文件 src/server/(项目根目录),分层结构:

src/server/
├── index.ts              # 入口
├── server.ts             # HTTP 服务器
├── router.ts             # 路由注册
├── sessionManager.ts     # 会话管理器
├── api/                  # REST 路由层 (14 个模块)
├── services/             # 业务服务层 (14 个模块)
├── ws/                   # WebSocket 处理
├── proxy/                # API 代理Anthropic/OpenAI 协议转换)
├── middleware/            # auth、cors、errorHandler
└── config/               # Provider 预设

第三层CLI 子进程

职责AI 对话核心、工具执行、Agent 编排

Server 为每个 Session spawn 一个 CLI 子进程,通过 stdin/stdout JSON 通信。

Sidecar 构建

使用 Bun 编译为独立二进制(desktop/scripts/build-sidecars.ts

三种模式共用一个入口 desktop/sidecars/claude-sidecar.ts

  • server — 启动 HTTP/WS 服务
  • cli — 启动 CLI 子进程
  • adapters — 启动 IM 适配器(解析 --feishu/--telegram 参数,检查凭据后按需加载)

编译产物仍放置在 desktop/src-tauri/binaries/作为迁移期稳定资源目录Electron Builder 通过 filesasarUnpack 把它们打入 app.asar.unpacked


WebSocket 通信协议

连接地址

ws://127.0.0.1:{port}/ws/{sessionId}

前端通过 WebSocketManagerper-session 连接管理支持自动重连、消息队列缓冲、ping 心跳保活。

客户端 → 服务端

type 说明
user_message 用户消息(含 content, attachments
permission_response 权限审批requestId, allowed, rule
set_permission_mode 切换权限模式
stop_generation 停止生成
ping 心跳

服务端 → 客户端

type 说明
connected 连接成功
status 状态变更thinking/generating
content_start / content_delta 流式文本
thinking Extended Thinking
tool_use_complete 工具调用就绪
tool_result 工具执行结果
permission_request 权限请求
message_complete 消息完成(含 Token 统计)
error 错误通知
session_title_updated 标题更新
team_update / team_created / team_deleted 团队事件
task_update 任务变更
pong 心跳响应

连接管理

  • 心跳30s 间隔 ping/pong
  • 重连:指数退避 min(1000ms × 2^n, 30000ms),最多 10 次
  • 缓冲:未连接时消息暂存队列,恢复后自动发送

HTTP API

会话

方法 端点 说明
GET /api/sessions 列表(支持 project/limit/offset 筛选)
POST /api/sessions 创建
GET /api/sessions/:id/messages 历史消息
PATCH /api/sessions/:id 重命名
DELETE /api/sessions/:id 删除
GET /api/sessions/:id/git-info Git 信息
GET /api/sessions/:id/slash-commands 可用斜杠命令
GET /api/sessions/recent-projects 最近项目

模型与提供商

方法 端点 说明
GET/PUT /api/models/current 当前模型
GET /api/models 可用模型列表
GET/PUT /api/effort Effort 级别
GET/POST/PUT/DELETE /api/providers 提供商 CRUD
POST /api/providers/:id/activate 激活
POST /api/providers/:id/test 测试连接
GET /api/providers/presets 预设列表

定时任务

方法 端点 说明
GET/POST/PUT/DELETE /api/scheduled-tasks 任务 CRUD
POST /api/scheduled-tasks/:id/run 手动运行
GET /api/scheduled-tasks/runs 运行记录

其他

方法 端点 说明
GET /api/teams Agent 团队
GET /api/teams/:name/members/:agentId/transcript 成员转录
GET /api/agents Agent 定义
GET /api/skills 技能列表
GET/PUT /api/adapters 适配器配置
GET/PUT /api/settings/user 用户设置
GET/PUT /api/permissions/mode 权限模式
GET /api/tasks/lists CLI 任务清单
GET /health 健康检查

状态管理

使用 Zustand按领域拆分为 12 个 Store

Store 核心状态
chatStore per-session 消息、流式状态、权限请求、Token 统计
sessionStore 会话列表、activeSessionId、项目筛选
tabStore 标签页顺序localStorage 持久化)
settingsStore 权限模式、当前模型、effort、语言
providerStore Provider 列表、activeId
uiStore 主题、侧边栏、activeView、Toast、设置标签页
taskStore 定时任务、运行记录
teamStore 团队列表、成员转录轮询
agentStore Agent 定义列表
skillStore 技能元数据、详情
adapterStore 适配器配置、配对码
cliTaskStore per-session CLI 任务追踪

数据流

用户操作 → Component → Store → API/WebSocket → Server → Store → Component 重渲染

持久化

数据 存储
标签页状态 localStorage
语言偏好 localStorage
会话数据 Server JSONL (~/.claude/sessions/)
设置 Server API
适配器配置 ~/.claude/adapters.json

协议代理层

Server 内置代理层(src/server/proxy/),统一不同 AI 提供商的 API 格式。

支持格式

格式 典型提供商
anthropic Anthropic、OpenRouter、MiniMax
openai_chat OpenAI、DeepSeek、Ollama
openai_responses OpenAI Responses API

模型映射

每个 Provider 配置 4 个模型槽位:mainhaikusonnetopus,前端按槽位名调用,代理层自动映射为实际模型名。


适配器架构

适配器系统让 Telegram/飞书等 IM 平台接入 Claude Code。

IM 平台 → Adapter 进程 → HTTP + WebSocket → Server → CLI

共享模块 adapters/common/

模块 职责
config.ts 配置加载env > JSON > 默认值)
ws-bridge.ts WebSocket 桥接(心跳、重连、消息路由)
pairing.ts 用户配对6 位安全码、速率限制)
session-store.ts Chat → Session 映射持久化
message-buffer.ts 流式缓冲500ms / 200 字符阈值)
message-dedup.ts 消息去重
chat-queue.ts 同一 Chat 消息串行队列
http-client.ts HTTP 客户端

分片限制

  • Telegram: 4000 字符/消息
  • 飞书: 30000 字符/消息

项目目录结构

desktop/
├── src/                              # React 前端
│   ├── api/                         #   API 客户端 (15 个模块)
│   ├── components/
│   │   ├── layout/                  #   AppShell, Sidebar, TabBar, TitleBar,
│   │   │                            #   WindowControls, StatusBar, ContentRouter,
│   │   │                            #   ProjectFilter
│   │   ├── chat/                    #   ChatInput, MessageList, AssistantMessage,
│   │   │                            #   ToolCallBlock, ToolCallGroup, ThinkingBlock,
│   │   │                            #   PermissionDialog, CodeViewer, DiffViewer,
│   │   │                            #   ImageGalleryModal, StreamingIndicator ...
│   │   ├── shared/                  #   Button, Modal, Toast, Spinner,
│   │   │                            #   UpdateChecker, DirectoryPicker ...
│   │   ├── controls/                #   ModelSelector, PermissionModeSelector
│   │   ├── markdown/                #   MarkdownRenderer, MermaidRenderer
│   │   ├── skills/                  #   SkillList, SkillDetail
│   │   ├── tasks/                   #   TaskList, TaskRow, NewTaskModal,
│   │   │                            #   DayOfWeekPicker, PromptEditor ...
│   │   └── teams/                   #   TeamStatusBar
│   ├── pages/                       #   ActiveSession, EmptySession, Settings,
│   │                                #   AdapterSettings, AgentTeams, ScheduledTasks,
│   │                                #   ComputerUseSettings, ToolInspection ...
│   ├── stores/                      #   12 个 Zustand store
│   ├── types/                       #   TypeScript 类型 (9 个模块)
│   ├── hooks/                       #   useKeyboardShortcuts
│   ├── i18n/                        #   中/英 国际化
│   ├── config/                      #   providerPresets, spinnerVerbs
│   └── lib/                         #   desktopRuntime, cronDescribe, parseRunOutput
├── src-tauri/
│   ├── binaries/                    #   Electron/Tauri 共用 sidecar 二进制
│   ├── resources/preview-agent.js   #   预览页面注入脚本
│   ├── src/main.rs                  #   迁移期 Tauri legacy 入口
│   ├── src/lib.rs                   #   迁移期 Tauri legacy host
│   ├── Cargo.toml
│   └── tauri.conf.json
├── electron/
│   ├── main.ts                      #   Electron main 入口
│   ├── preload.ts                   #   renderer host bridge
│   ├── preview-preload.ts           #   preview WebContentsView bridge
│   ├── ipc/                         #   channel registry + payload validators
│   └── services/                    #   dialogs, shell, updater, terminal, preview ...
├── sidecars/
│   └── claude-sidecar.ts            #   统一入口 (server/cli/adapters)
└── scripts/
    ├── build-sidecars.ts
    ├── build-macos-arm64.sh
    └── build-windows-x64.ps1

src/server/                           # 服务端(项目根目录)
├── api/                             #   REST 路由 (14 个模块)
├── services/                        #   业务服务 (14 个模块)
├── ws/                              #   WebSocket 处理
├── proxy/                           #   协议代理转换
├── middleware/                      #   auth, cors, errorHandler
└── config/                          #   Provider 预设

adapters/                             # IM 适配器
├── common/                          #   共享模块 (8 个)
├── telegram/                        #   Telegram Bot
└── feishu/                          #   飞书 Bot