docs(desktop): add comprehensive desktop app documentation with illustrations

添加桌面端完整文档体系,包含快速上手、架构设计、功能详解三篇渐进式文档,
涵盖 Tauri 三层架构、WebSocket 通信协议、适配器桥接、状态管理等核心内容,
配 8 张深色主题技术配图。
This commit is contained in:
程序员阿江(Relakkes) 2026-04-10 09:39:08 +08:00
parent 98a24f99b4
commit 7ce39d099c
12 changed files with 2092 additions and 0 deletions

View File

@ -0,0 +1,383 @@
# Claude Code 桌面端 — 快速上手
> 告别纯黑终端,用图形界面释放 Claude Code 的全部潜能。
<p align="center">
<a href="#一界面布局">界面布局</a> · <a href="#二对话操作">对话操作</a> · <a href="#三多标签系统">多标签系统</a> · <a href="#四权限控制">权限控制</a> · <a href="#五项目管理">项目管理</a> · <a href="#六模型与提供商">模型与提供商</a> · <a href="#七im-适配器接入">IM 适配器</a> · <a href="#八定时任务">定时任务</a>
</p>
![桌面端界面总览](./images/01-desktop-overview.png)
---
## 一、界面布局
桌面端采用**三栏 + 标签页**的经典 IDE 布局,从左到右分为:
| 区域 | 位置 | 功能 |
|------|------|------|
| **侧边栏** | 左侧 | 会话列表、项目筛选、搜索、导航入口 |
| **标签栏** | 顶部 | 多标签切换、拖拽排序、右键菜单 |
| **内容区** | 中央 | 对话界面 / 设置页 / 任务页 |
| **状态栏** | 底部 | 当前项目名、模型名称 |
### 侧边栏
侧边栏是你与 Claude Code 交互的导航中心:
- **品牌区域**显示「Claude Code Haha」标识点击 GitHub 图标跳转仓库
- **操作按钮**
- `+` 新建会话
- 时钟图标 → 定时任务管理
- 齿轮图标 → 设置页面
- **项目筛选器**:按工作目录过滤会话列表
- **搜索框**:实时搜索会话标题(不区分大小写)
- **会话列表**:按时间自动分组 —— 今天 / 昨天 / 最近 7 天 / 最近 30 天 / 更早
**右键菜单**:在会话项上右键可以 **重命名****删除** 会话。
### 状态栏
底部状态栏显示当前会话的项目路径和正在使用的 AI 模型名称,一目了然。
---
## 二、对话操作
### 新建会话
1. 点击侧边栏 `+` 按钮,或使用快捷键 `Cmd/Ctrl + N`
2. 在空白会话页选择**工作目录**(关联本地项目文件夹)
3. 输入第一条消息开始对话
### 发送消息
在底部输入框编写消息:
- **Enter** → 发送消息
- **Shift + Enter** → 换行(多行输入)
- 输入框会自动调整高度(最高 200px
### 附件上传
桌面端支持多种附件方式:
| 方式 | 操作 |
|------|------|
| **粘贴图片** | 在输入框中 `Cmd/Ctrl + V` 粘贴剪贴板图片 |
| **拖拽上传** | 将文件拖入输入区域 |
| **文件选择** | 点击 `+` 按钮 → 「添加文件」 |
附件会在输入框上方以缩略图画廊展示,支持预览和移除。
### 斜杠命令
输入 `/` 触发命令自动补全菜单:
```
/commit — 提交代码
/review-pr — 审查 PR
/memory — 管理记忆
/debug — 调试模式
...
```
- **上下箭头** 导航选项
- **Enter / Tab** 确认选择
- **Esc** 关闭菜单
- 命令列表由服务端动态提供,支持搜索过滤
### @ 文件引用
输入 `@` 触发文件搜索菜单,快速将文件引入对话上下文:
- 支持路径和文件名自动补全
- 上下箭头导航、Enter 选择
### 消息类型
对话中会展示多种消息类型:
| 类型 | 说明 | 展示形式 |
|------|------|----------|
| **用户消息** | 你发送的文本和附件 | 用户头像 + 消息气泡 |
| **助手消息** | AI 回复内容 | 带边框气泡 + Markdown 渲染 |
| **思考块** | AI 的推理过程Extended Thinking | 可展开/折叠,显示思考预览 |
| **工具调用** | Bash、Edit、Read 等工具操作 | 工具图标 + 可展开详情 |
| **工具结果** | 工具执行的输出 | 代码块展示,带成功/错误状态 |
| **权限请求** | 需要用户审批的操作 | 交互式对话框,含允许/拒绝按钮 |
| **AskUser** | AI 向你提问 | 特殊输入框 |
### 流式输出
AI 回复时实时流式展示,支持:
- 打字效果的闪烁光标 `▍`
- 流式代码高亮(使用 Shiki 引擎VS Code 级别语法着色)
- 随时可点击 **停止** 按钮(或 `Cmd/Ctrl + .`)中断生成
### 消息操作
悬浮在消息上时,右下角出现操作栏:
- **复制** — 复制消息文本内容
---
## 三、多标签系统
桌面端支持同时打开多个对话标签,像浏览器一样管理会话。
### 标签操作
| 操作 | 方式 |
|------|------|
| **新建标签** | `Cmd/Ctrl + N` 或点击 `+` |
| **切换标签** | 点击目标标签 |
| **关闭标签** | 悬浮标签 → 点击 `×` |
| **拖拽排序** | 按住标签拖动到目标位置 |
| **左右滚动** | 标签过多时出现滚动箭头 |
### 标签状态指示
- **绿色脉冲点** → 会话正在运行
- **红色点** → 会话出错
- **无标记** → 会话空闲
### 右键菜单
右键标签打开上下文菜单:
- 关闭当前标签
- 关闭其他标签
- 关闭左侧标签
- 关闭右侧标签
- 关闭全部标签
### 关闭保护
当关闭一个**正在运行的会话标签**时,会弹出确认对话框:
- **继续运行** — 保留标签
- **停止并关闭** — 终止会话后关闭
- **取消** — 放弃操作
标签状态自动保存到 `localStorage`,下次启动时恢复。
---
## 四、权限控制
Claude Code 在执行文件修改、Shell 命令等操作前,会请求你的权限。
### 权限请求对话框
当 AI 需要执行敏感操作时,会弹出权限请求卡片,显示:
- 工具类型(如 Bash、Edit、Write
- 操作预览命令内容、Diff 变更等)
- 详细输入参数(可展开查看)
你可以选择:
| 按钮 | 效果 |
|------|------|
| **允许** | 仅本次允许执行 |
| **一直允许** | 本次会话内自动允许同类操作 |
| **拒绝** | 拒绝本次执行 |
### 四种权限模式
在设置中可切换全局权限模式:
| 模式 | 说明 | 适用场景 |
|------|------|----------|
| **询问权限** (default) | 每个操作都需确认 | 安全第一 |
| **自动接受** (acceptEdits) | 自动允许编辑操作 | 信任文件修改 |
| **计划模式** (plan) | 只展示计划不执行 | 审查方案 |
| **绕过权限** (bypassPermissions) | 全部自动执行 | 完全信任(需二次确认) |
> 切换到「绕过权限」时需要确认警告对话框,防止误操作。
---
## 五、项目管理
每个会话都绑定一个**工作目录**,即你的本地项目文件夹。
### 工作目录
- 新建会话时通过 **DirectoryPicker** 选择工作目录
- 系统自动检测目录是否存在,不存在时显示警告
- 支持 Git 仓库识别,状态栏和会话信息中展示:
- 仓库名称
- 当前分支
- 项目路径
### 项目筛选
侧边栏中的 **ProjectFilter** 组件可按项目过滤会话:
1. 点击项目筛选下拉框
2. 选择目标项目
3. 会话列表仅显示该项目的会话
### 最近项目
通过 API 获取最近使用的项目列表,包含:
- 项目路径和名称
- 是否为 Git 仓库
- 分支名
- 会话数量
- 最后修改时间
---
## 六、模型与提供商
### 模型选择
点击状态栏的模型名称,或在设置中打开模型选择器:
- 显示所有可用模型(带图标区分 Opus/Sonnet/Haiku
- 单选切换当前模型
- 支持 **Effort 级别** 调节Low / Medium / High / Max
### 自定义 Provider
在设置 → **Providers** 标签页管理 AI 提供商:
#### 预设提供商
系统内置多种预设,快速配置:
- **Anthropic** — 官方 API
- **OpenAI** — GPT 系列
- **OpenRouter** — 多模型聚合
- **Ollama** — 本地模型
- 其他 Anthropic 兼容服务
#### 配置项
| 字段 | 说明 |
|------|------|
| API Key | 提供商密钥 |
| Base URL | API 基础地址 |
| API 格式 | anthropic / openai_chat / openai_responses |
| 模型映射 | main / haiku / sonnet / opus 对应的实际模型名 |
#### 连接测试
配置完成后可点击 **测试连接**,系统会发送测试请求验证配置是否正确(两步验证:连接性 + 模型可用性)。
---
## 七、IM 适配器接入
桌面端不仅提供本地 GUI还支持通过 **Telegram 和飞书** 远程对话。
### 配置步骤
1. 打开设置 → **Adapters** 标签页
2. 填入平台凭证:
- **Telegram**Bot Token
- **飞书**App ID + App Secret
3. 配置默认工作目录和允许的用户
4. 启动适配器进程
### 用户配对
为了安全IM 用户需要通过**配对码**授权:
1. 在桌面端设置中点击「生成配对码」
2. 获取一个 **6 位安全字符码**60 分钟有效、一次性使用)
3. 在 Telegram/飞书中向 Bot 发送该配对码
4. 配对成功后即可开始对话
安全特性:
- 排除易混淆字符0/O/1/I/L
- 同一用户 5 分钟内最多失败 5 次
- 密钥在 API 返回时自动脱敏(仅显示后 4 位)
### IM 内操作
配对成功后,可在 IM 中:
| 命令 | 效果 |
|------|------|
| 直接发文本 | 与 Claude Code 对话 |
| `/new [项目名]``新会话` | 开始新会话(支持模糊匹配项目) |
| `/projects``项目列表` | 查看最近项目 |
| `/stop``停止` | 停止当前生成 |
权限请求在 IM 中以**按钮卡片**形式展示Telegram Inline Keyboard / 飞书 Interactive Card点击即可审批。
---
## 八、定时任务
桌面端支持创建 **Cron 定时任务**,让 Claude Code 按计划自动执行。
### 进入任务管理
点击侧边栏的**时钟图标**进入定时任务页面。
页面顶部显示统计卡片:总任务数 / 活跃数 / 禁用数。
### 创建任务
点击「新建任务」,填写:
| 字段 | 说明 |
|------|------|
| 任务名称 | 描述性名称 |
| 提示词 | Claude Code 执行的 Prompt |
| Cron 表达式 | 执行时间计划 |
| 周日期 | 可视化选择执行的星期几 |
| 模型 | 使用的 AI 模型 |
| 权限模式 | 任务执行时的权限策略 |
### 任务管理
每个任务行显示:
- 名称和描述
- Cron 表达式(人性化展示)
- 启用/禁用开关
- 运行历史(可展开查看)
- 手动运行按钮
- 删除按钮
> 注意:定时任务在桌面应用运行时才会执行。
---
## 九、键盘快捷键速查
| 快捷键 | 功能 |
|--------|------|
| `Cmd/Ctrl + N` | 新建会话 |
| `Cmd/Ctrl + K` | 聚焦侧边栏搜索 |
| `Cmd/Ctrl + .` | 停止当前生成 |
| `Escape` | 关闭模态框 |
| `Enter` | 发送消息 |
| `Shift + Enter` | 输入框换行 |
| `/` | 触发斜杠命令菜单 |
| `@` | 触发文件搜索菜单 |
---
## 十、主题与国际化
### 主题切换
在设置中切换 **浅色 / 深色** 主题。
桌面端采用暖色调设计系统:
- 浅色模式:奶油色背景(#FAF9F5
- 深色模式:深色背景
- 品牌色:褐红色(#8F482F
### 国际化
支持 **中文****英文** 两种语言,在设置 → 通用 中切换。

View File

@ -0,0 +1,835 @@
# Claude Code 桌面端 — 架构设计
> 从 Tauri 窗口到 CLI 子进程,深入理解桌面端的三层通信架构。
<p align="center">
<a href="#一技术栈全景">技术栈</a> · <a href="#二三层架构">三层架构</a> · <a href="#三websocket-通信协议">WebSocket 协议</a> · <a href="#四http-api-端点">HTTP API</a> · <a href="#五状态管理">状态管理</a> · <a href="#六会话生命周期">会话生命周期</a> · <a href="#七代理层协议转换">协议转换</a> · <a href="#八适配器桥接架构">适配器架构</a>
</p>
![技术栈全景](./images/02-tech-stack.png)
---
## 一、技术栈全景
Claude Code 桌面端的技术选型强调**轻量、高性能、跨平台**
### 前端层
| 技术 | 版本 | 职责 |
|------|------|------|
| **React** | 18.3.1 | UI 框架,函数式组件 + Hooks |
| **Zustand** | 5.0.3 | 轻量级状态管理,零样板代码 |
| **Vite** | 6.0.7 | 构建工具HMR 热更新 |
| **Tailwind CSS** | 4.0 | 原子化样式框架 |
| **Shiki** | 4.0.2 | VS Code 级别代码语法高亮 |
| **react-diff-viewer** | 4.2.0 | Diff 变更展示 |
| **marked** | 15.0.7 | Markdown 解析渲染 |
### 桌面层
| 技术 | 版本 | 职责 |
|------|------|------|
| **Tauri** | 2.x | 跨平台桌面框架Rust |
| **tauri-plugin-shell** | 2.x | Sidecar 进程管理 |
| **tauri-plugin-dialog** | 2.x | 原生文件选择对话框 |
| **tauri-plugin-process** | 2.x | 进程生命周期管理 |
### 服务端层
| 技术 | 职责 |
|------|------|
| **Bun** | JavaScript/TypeScript 运行时 + 构建工具 |
| **Bun.serve** | HTTP/WebSocket 服务器 |
| **Zod** | 请求参数校验 |
### 字体系统
桌面端自托管所有字体,无需 CDN 依赖:
- **Inter** (400-600) — 正文
- **Manrope** (400-800) — 标题
- **JetBrains Mono** — 代码
- **Material Symbols Outlined** — 图标
---
## 二、三层架构
![三层架构图](./images/03-three-layer-arch.png)
桌面端采用**三层架构**设计,各层职责明确:
```
┌─────────────────────────────────┐
│ Tauri 主进程 (Rust) │
│ ┌───────────────────────────┐ │
│ │ WebView (React App) │ │ ← 用户看到的界面
│ │ Port 1420 (开发) / 内置 │ │
│ └───────────┬───────────────┘ │
│ │ HTTP + WebSocket │
│ ┌───────────▼───────────────┐ │
│ │ Sidecar: claude-server │ │ ← Bun 编译的服务端二进制
│ │ Port: 动态分配 │ │
│ └───────────┬───────────────┘ │
│ │ 子进程 spawn │
│ ┌───────────▼───────────────┐ │
│ │ CLI 子进程 (claude-cli) │ │ ← 实际执行 AI 对话和工具调用
│ │ stdin/stdout 通信 │ │
│ └───────────────────────────┘ │
└─────────────────────────────────┘
```
### 第一层Tauri 主进程
**职责**:窗口管理、进程编排、原生 API 桥接
关键文件:`desktop/src-tauri/src/lib.rs`
```rust
// 核心功能
fn reserve_local_port() -> u16 // 获取空闲端口
fn wait_for_server(port) -> bool // 等待服务就绪(超时 10 秒)
fn start_server_sidecar(port) // 启动 Server 后台进程
fn stop_server_sidecar() // 停止 Server 后台进程
// Tauri 命令(暴露给前端调用)
#[tauri::command]
fn get_server_url() -> String // 返回 http://127.0.0.1:{port}
```
启动流程:
1. Tauri 主进程启动
2. 调用 `reserve_local_port()` 获取空闲端口
3. 启动 `claude-server` sidecar 进程,传入端口号
4. 调用 `wait_for_server()` 轮询等待服务就绪
5. WebView 加载 React 应用
6. 前端调用 `get_server_url` 获取服务地址
### 第二层Server Sidecar
**职责**HTTP API + WebSocket 网关 + 会话管理 + 代理转换
关键文件:`src/server/index.ts`
```typescript
// 服务器启动
Bun.serve({
port: config.port,
fetch(req, server) {
// HTTP 路由 + WebSocket 升级
if (url.pathname.startsWith('/ws/')) {
server.upgrade(req, { data: { sessionId } })
return
}
return router.handle(req)
},
websocket: {
open(ws) { /* 连接建立 */ },
message(ws, msg) { /* 消息处理 */ },
close(ws) { /* 连接关闭 */ }
}
})
```
Server 提供两类服务:
- **HTTP REST API** — 会话管理、配置读写、模型操作
- **WebSocket** — 实时消息通道(对话流、权限请求、状态推送)
### 第三层CLI 子进程
**职责**AI 对话核心逻辑、工具执行、Agent 编排
Server 为每个 Session 创建一个 CLI 子进程:
```typescript
// 创建 CLI 子进程
const child = spawn('claude-cli', ['--session', sessionId], {
cwd: workDir,
env: { ...process.env, ANTHROPIC_AUTH_TOKEN: token }
})
// 通过 stdin/stdout 通信
child.stdin.write(JSON.stringify({ type: 'user_message', content }))
child.stdout.on('data', (chunk) => {
// 解析 stream_event转发给 WebSocket 客户端
})
```
### Sidecar 构建
使用 Bun 将 TypeScript 编译为独立可执行文件:
```typescript
// desktop/scripts/build-sidecars.ts
// 支持 8 种目标平台:
const targets = [
'bun-darwin-arm64', // M1/M2 Mac
'bun-darwin-x64', // Intel Mac
'bun-windows-x64', // Windows x64
'bun-windows-arm64', // Windows ARM
'bun-linux-x64', // Linux x64
'bun-linux-arm64', // Linux ARM
'bun-linux-x64-musl', // Alpine Linux
'bun-linux-arm64-musl', // Alpine ARM
]
```
编译产物放置在 `desktop/src-tauri/binaries/`Tauri 打包时自动包含。
---
## 三、WebSocket 通信协议
![WebSocket 通信协议](./images/04-websocket-protocol.png)
WebSocket 是桌面端与服务端实时通信的核心通道。
### 连接建立
```
ws://127.0.0.1:{port}/ws/{sessionId}
```
前端通过 `wsManager`(单例)管理所有 WebSocket 连接:
```typescript
// desktop/src/api/websocket.ts
class WebSocketManager {
private connections = new Map<string, WebSocket>()
connect(sessionId: string): void {
const ws = new WebSocket(`${baseUrl}/ws/${sessionId}`)
// 自动重连(指数退避)
// 消息队列(连接未就绪时缓冲)
// 心跳 ping30 秒间隔)
}
}
```
### 客户端 → 服务端消息
| type | 字段 | 说明 |
|------|------|------|
| `user_message` | `content`, `attachments?` | 用户发送消息 |
| `permission_response` | `requestId`, `allowed`, `rule?` | 权限审批响应 |
| `set_permission_mode` | `mode` | 切换权限模式 |
| `stop_generation` | — | 停止当前生成 |
| `ping` | — | 心跳保活 |
### 服务端 → 客户端消息
| type | 关键字段 | 说明 |
|------|----------|------|
| `connected` | `sessionId` | 连接成功确认 |
| `status` | `state`, `verb?`, `elapsed?` | 状态变更thinking/generating |
| `content_start` | `blockType` | 内容块开始text/tool_use |
| `content_delta` | `text?`, `toolInput?` | 增量内容(流式文本) |
| `thinking` | `text` | Extended Thinking 内容 |
| `tool_use_complete` | `toolName`, `input` | 工具调用准备就绪 |
| `tool_result` | `output`, `isError` | 工具执行结果 |
| `permission_request` | `toolName`, `input`, `requestId` | 权限请求 |
| `message_complete` | `usage: TokenUsage` | 消息完成(含 Token 统计) |
| `error` | `message`, `code` | 错误通知 |
| `session_title_updated` | `title` | 会话标题更新 |
| `team_update` | `team` | 团队状态变更 |
| `team_created` / `team_deleted` | `teamName` | 团队创建/删除 |
| `task_update` | `task` | 任务状态变更 |
| `pong` | — | 心跳响应 |
### 完整消息流示例
一条用户消息从发送到收到完整回复的流程:
```
用户输入 "写一个排序函数"
ChatInput → chatStore.sendMessage()
wsManager.send({ type: 'user_message', content: '...' })
Server 收到 → 转发到 CLI 子进程
CLI 开始处理,流式返回事件:
← { type: 'status', state: 'thinking' }
→ UI 显示"思考中..."动画
← { type: 'thinking', text: '让我分析...' }
→ ThinkingBlock 展示推理过程
← { type: 'content_start', blockType: 'text' }
→ 准备接收文本内容
← { type: 'content_delta', text: 'def sort(' }
← { type: 'content_delta', text: 'arr):\n' }
← { type: 'content_delta', text: ' return sorted(arr)' }
→ AssistantMessage 流式渲染,闪烁光标
← { type: 'content_start', blockType: 'tool_use' }
→ 准备接收工具调用
← { type: 'tool_use_complete', toolName: 'Write', input: {...} }
→ ToolCallBlock 展示文件写入操作
← { type: 'permission_request', toolName: 'Write', requestId: '...' }
→ PermissionDialog 弹出,等待用户审批
用户点击"允许"
→ { type: 'permission_response', requestId: '...', allowed: true }
← { type: 'tool_result', output: '文件已写入' }
→ ToolResultBlock 展示结果
← { type: 'message_complete', usage: { input: 1200, output: 350 } }
→ 更新 Token 统计,清除流式状态
```
### 连接管理
**心跳保活**:每 30 秒发送 `ping`,服务端回复 `pong`
**自动重连**:指数退避策略
```
重连间隔 = min(1000ms × 2^(attempt-1), 30000ms)
最大重连次数 = 10
```
**消息缓冲**WebSocket 未就绪时,消息暂存队列,连接恢复后自动发送。
---
## 四、HTTP API 端点
Server 提供完整的 RESTful API供前端和适配器调用。
### 会话管理
| 方法 | 端点 | 说明 |
|------|------|------|
| `GET` | `/api/sessions` | 获取会话列表 |
| `POST` | `/api/sessions` | 创建新会话 |
| `GET` | `/api/sessions/:id` | 获取会话详情 |
| `PATCH` | `/api/sessions/:id` | 重命名会话 |
| `DELETE` | `/api/sessions/:id` | 删除会话 |
| `GET` | `/api/sessions/:id/messages` | 获取历史消息 |
| `GET` | `/api/sessions/:id/git-info` | 获取 Git 信息 |
| `GET` | `/api/sessions/:id/slash-commands` | 获取可用斜杠命令 |
| `GET` | `/api/sessions/recent-projects` | 最近项目列表 |
### 模型与提供商
| 方法 | 端点 | 说明 |
|------|------|------|
| `GET` | `/api/models` | 可用模型列表 |
| `GET` | `/api/models/current` | 当前使用的模型 |
| `POST` | `/api/models/:id/set-current` | 切换模型 |
| `GET/POST` | `/api/models/effort` | 获取/设置 Effort 级别 |
| `GET` | `/api/providers` | 提供商列表 |
| `POST` | `/api/providers` | 创建提供商 |
| `PUT` | `/api/providers/:id` | 更新提供商配置 |
| `DELETE` | `/api/providers/:id` | 删除提供商 |
| `POST` | `/api/providers/:id/activate` | 激活提供商 |
| `POST` | `/api/providers/:id/test` | 测试连接 |
| `GET` | `/api/providers/presets` | 获取预设列表 |
### 定时任务
| 方法 | 端点 | 说明 |
|------|------|------|
| `GET` | `/api/scheduled-tasks` | 任务列表 |
| `POST` | `/api/scheduled-tasks` | 创建任务 |
| `PUT` | `/api/scheduled-tasks/:id` | 更新任务 |
| `DELETE` | `/api/scheduled-tasks/:id` | 删除任务 |
| `POST` | `/api/scheduled-tasks/:id/run` | 手动运行 |
| `GET` | `/api/scheduled-tasks/runs` | 所有运行记录 |
| `GET` | `/api/scheduled-tasks/:id/runs` | 单任务运行记录 |
### Agent 团队
| 方法 | 端点 | 说明 |
|------|------|------|
| `GET` | `/api/teams` | 团队列表 |
| `GET` | `/api/teams/:name` | 团队详情 |
| `GET` | `/api/teams/:name/members/:agentId/transcript` | 成员转录 |
| `DELETE` | `/api/teams/:name` | 删除团队 |
### 其他
| 方法 | 端点 | 说明 |
|------|------|------|
| `GET` | `/health` | 健康检查 |
| `GET/POST` | `/api/settings/permission-mode` | 权限模式 |
| `GET` | `/api/agents` | Agent 定义列表 |
| `GET` | `/api/skills` | 技能列表 |
| `GET` | `/api/skills/detail` | 技能详情 |
| `GET/PUT` | `/api/adapters` | 适配器配置 |
---
## 五、状态管理
![会话生命周期](./images/05-session-lifecycle.png)
桌面端使用 **Zustand** 进行状态管理,按领域拆分为多个独立 Store。
### Store 架构
```
stores/
├── chatStore.ts # 聊天状态(消息、流式、权限) 20KB
├── sessionStore.ts # 会话列表、创建、删除
├── tabStore.ts # 标签页管理、顺序、持久化 5KB
├── settingsStore.ts # 全局设置(模型、权限、语言)
├── providerStore.ts # LLM 提供商配置
├── uiStore.ts # UI 状态主题、Toast、模态框
├── taskStore.ts # 定时任务管理
├── teamStore.ts # Agent 团队状态
├── agentStore.ts # Agent 定义管理
├── skillStore.ts # 技能库
├── adapterStore.ts # 适配器配置
└── cliTaskStore.ts # CLI 任务状态
```
### chatStore 核心设计
`chatStore` 是最复杂的 Store为**每个 Session 维护独立状态**
```typescript
type PerSessionState = {
messages: UIMessage[] // 消息列表
chatState: 'idle' | 'thinking' | ... // 对话状态
connectionState: ConnectionState // WebSocket 连接状态
streamingText: string // 流式文本缓冲
streamingToolInput: string // 工具输入流
activeToolUseId: string | null // 当前工具调用 ID
activeToolName: string | null // 当前工具名称
activeThinkingId: string | null // 当前思考块 ID
pendingPermission: PermissionRequest | null // 待决权限
tokenUsage: TokenUsage // Token 使用统计
elapsedSeconds: number // 经过时间
statusVerb: string // 随机状态动词
slashCommands: SlashCommand[] // 可用命令列表
}
```
关键方法:
| 方法 | 职责 |
|------|------|
| `connectToSession(id)` | 建立 WebSocket 连接 |
| `disconnectSession(id)` | 断开连接 |
| `sendMessage(id, content, attachments)` | 发送用户消息 |
| `respondToPermission(id, requestId, allowed, rule)` | 权限审批 |
| `stopGeneration(id)` | 停止生成 |
| `loadHistory(id)` | 加载历史消息 |
| `handleServerMessage(id, msg)` | 处理服务端消息 |
### 数据流向
```
用户操作
Component (调用 Store 方法)
Store (更新状态 + 调用 API/WebSocket)
API 层 (HTTP 请求 / WebSocket 发送)
Server 响应
Store (更新状态)
Component (自动重渲染)
```
### 持久化策略
| 数据 | 存储位置 | 说明 |
|------|----------|------|
| 打开的标签页 | `localStorage` | 页面刷新/重启后恢复 |
| 会话数据 | Server JSONL 文件 | `~/.claude/sessions/` |
| 设置 | Server API | 通过 HTTP 读写 |
| 适配器配置 | `~/.claude/adapters.json` | JSON 文件 |
| 会话映射 | `~/.claude/adapter-sessions.json` | 适配器 Chat→Session 映射 |
---
## 六、会话生命周期
一个会话从创建到恢复的完整流程:
### 创建
```
用户点击 + 新建会话
sessionStore.createSession({ workDir })
POST /api/sessions { workDir: '/path/to/project' }
Server 创建 Session 记录 → 返回 { sessionId }
tabStore.openTab(sessionId)
chatStore.connectToSession(sessionId)
WebSocket 连接 → 收到 { type: 'connected' }
```
### 交互
```
用户发送消息
wsManager.send({ type: 'user_message', content })
Server 转发到 CLI 子进程
CLI 处理 → 流式返回 stream_event
Server 转换为 ServerMessage → 推送到 WebSocket
chatStore.handleServerMessage() → UI 更新
```
### 断开
```
用户关闭标签页 / 切换到其他标签
chatStore.disconnectSession(sessionId)
WebSocket 关闭
CLI 子进程可能继续运行(后台任务)
```
### 恢复
```
应用启动 / 切回标签页
tabStore.restoreTabs() // 从 localStorage 读取
验证会话是否仍存在 (GET /api/sessions)
chatStore.connectToSession(sessionId)
chatStore.loadHistory(sessionId) // GET /api/sessions/:id/messages
WebSocket 重连 → 恢复实时通信
```
### 会话持久化
Server 使用 **JSONLJSON Lines** 格式持久化会话数据:
```
~/.claude/sessions/
├── {sessionId}/
│ ├── messages.jsonl ← 流式追加,每行一条消息/事件
│ ├── metadata.json ← 会话元数据workDir、标题、模型等
│ └── ...
```
JSONL 格式的优势:
- **流式追加**:新消息直接 append无需重写整个文件
- **崩溃恢复**:即使中途崩溃,已写入的行不会丢失
- **大会话支持**:按行读取,无需一次性加载整个 JSON
---
## 七、代理层协议转换
Server 内置了多协议代理层Proxy让不同 AI 提供商的 API 统一接入。
### 支持的 API 格式
| 格式 | 说明 | 典型提供商 |
|------|------|-----------|
| `anthropic` | Anthropic Messages API | Anthropic 官方、MiniMax |
| `openai_chat` | OpenAI Chat Completions | OpenAI、DeepSeek |
| `openai_responses` | OpenAI Responses API | OpenAI 新接口 |
### 协议转换流程
```
前端发送消息
Server 接收
判断当前 Provider 的 API 格式
┌─────────────────────────────────┐
│ anthropic │ openai_chat/resp │
│ 直接透传 │ 转换消息格式 │
│ │ system → 系统消息 │
│ │ tool_use → 函数调用 │
│ │ tool_result → 函数结果│
└──────┬──────┴──────┬────────────┘
│ │
↓ ↓
Anthropic API OpenAI API
│ │
↓ ↓
直接返回 反向转换响应格式
│ │
└──────┬──────┘
统一的 ServerMessage 格式
WebSocket 推送给前端
```
### 模型映射
每个 Provider 可配置四个模型槽位:
| 槽位 | 用途 |
|------|------|
| `main` | 主对话模型 |
| `haiku` | 快速/轻量任务 |
| `sonnet` | 中等复杂度 |
| `opus` | 最高能力 |
例如 OpenRouter 配置:
```json
{
"apiFormat": "anthropic",
"baseUrl": "https://openrouter.ai/api/v1",
"modelMapping": {
"main": "anthropic/claude-sonnet-4-20250514",
"haiku": "anthropic/claude-haiku-4-5-20251001",
"opus": "anthropic/claude-opus-4-20250514"
}
}
```
---
## 八、适配器桥接架构
![适配器桥接架构](./images/07-adapter-bridge.png)
适配器系统让**任何 IM 平台**都可以接入 Claude Code无需修改核心代码。
### 整体架构
```
┌──────────────┐ ┌──────────────┐
│ Telegram │ │ 飞书 │ ← IM 平台
│ grammy │ │ Lark SDK │
└──────┬───────┘ └──────┬───────┘
│ │
▼ ▼
┌──────────────────────────────────┐
│ Adapter 进程 │ ← 平台适配层
│ ┌─────────────────────────────┐ │
│ │ common/ 共享模块 │ │
│ │ config │ ws-bridge │ │
│ │ pairing │ message-buffer │ │
│ │ dedup │ chat-queue │ │
│ │ session │ http-client │ │
│ └─────────────────────────────┘ │
└──────────────┬───────────────────┘
│ HTTP + WebSocket
┌──────────────────────────────────┐
│ Desktop Server │ ← 服务端
│ POST /api/sessions │
│ WS /ws/{sessionId} │
└──────────────┬───────────────────┘
┌──────────────────────────────────┐
│ CLI 子进程 │ ← AI 对话引擎
└──────────────────────────────────┘
```
### 四层架构
| 层级 | 职责 | 关键文件 |
|------|------|----------|
| **配置层** | 桌面端 UI 填写凭证 | `desktop/src/pages/AdapterSettings.tsx` |
| **存储层** | 配置读写和脱敏 | `src/server/services/adapterService.ts` |
| **适配层** | IM SDK 对接、消息路由 | `adapters/telegram/index.ts`, `adapters/feishu/index.ts` |
| **会话层** | WebSocket 桥接到 Server | `adapters/common/ws-bridge.ts` |
### 共享模块
所有适配器共用 `adapters/common/` 模块:
| 模块 | 职责 |
|------|------|
| `config.ts` | 配置加载(环境变量 > 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 客户端(创建会话、获取项目列表) |
### 接入新 IM 平台
得益于模块化设计,接入新平台只需三步:
**1. 创建适配器文件**
```typescript
// adapters/discord/index.ts
import { WsBridge } from '../common/ws-bridge.js'
import { MessageBuffer } from '../common/message-buffer.js'
import { loadConfig } from '../common/config.js'
import { isPaired, tryPair } from '../common/pairing.js'
```
**2. 实现消息接收**
```typescript
bot.on('message', async (msg) => {
// 去重 → 授权检查 → 会话管理 → WebSocket 桥接
if (!dedup.tryRecord(msg.id)) return
if (!isPaired('discord', msg.author.id, config)) {
tryPair(msg.content, { userId: msg.author.id, ... }, 'discord')
return
}
bridge.sendUserMessage(chatId, msg.content)
})
```
**3. 处理服务端事件**
```typescript
bridge.onServerMessage(chatId, async (msg) => {
switch (msg.type) {
case 'content_delta': /* 流式文本 */ break
case 'permission_request': /* 权限按钮 */ break
case 'message_complete': /* 完成 */ break
}
})
```
### 消息缓冲机制
为防止 IM 平台的消息频率限制,适配器使用 `MessageBuffer` 批量刷新:
```
content_delta: "def " ─┐
content_delta: "sort(" │→ 缓冲累积
content_delta: "arr):" │
↓ 500ms 或 200 字符
IM 平台: "def sort(arr): ▍" (编辑消息)
content_delta: "\n ..." ─┐
content_delta: "return" │→ 继续缓冲
IM 平台: "def sort(arr):\n return ▍"
message_complete ↓
IM 平台: 最终完整文本(分片发送)
```
分片限制:
- Telegram: 4000 字符/消息
- 飞书: 30000 字符/消息
---
## 九、项目目录结构
```
desktop/
├── src/ # React 前端
│ ├── App.tsx # 根组件
│ ├── main.tsx # 入口
│ ├── components/
│ │ ├── layout/ # 布局AppShell, Sidebar, TabBar
│ │ ├── chat/ # 聊天MessageList, ChatInput, ToolCallBlock
│ │ ├── shared/ # 通用Button, Modal, Toast, Spinner
│ │ ├── controls/ # 控件ModelSelector, PermissionModeSelector
│ │ ├── markdown/ # MarkdownRenderer
│ │ ├── skills/ # 技能浏览
│ │ ├── tasks/ # 任务管理
│ │ └── teams/ # 团队视图
│ ├── pages/ # 页面ActiveSession, Settings, ScheduledTasks
│ ├── stores/ # Zustand 状态
│ ├── api/ # HTTP + WebSocket 客户端
│ ├── types/ # TypeScript 类型定义
│ ├── hooks/ # 自定义 Hooks
│ ├── i18n/ # 国际化
│ ├── theme/ # 全局样式
│ ├── config/ # 提供商预设
│ └── lib/ # 工具库
├── src-tauri/ # Tauri Rust 后端
│ ├── src/lib.rs # 核心端口管理、Sidecar 启动
│ ├── Cargo.toml # Rust 依赖
│ └── tauri.conf.json # Tauri 配置
├── sidecars/ # Sidecar 启动器
│ ├── server-launcher.ts # Server 进程启动
│ └── cli-launcher.ts # CLI 进程启动
├── scripts/
│ └── build-sidecars.ts # 跨平台编译脚本
├── vite.config.ts # Vite 构建配置
├── package.json # 依赖和脚本
└── tsconfig.json # TypeScript 配置
src/server/ # 服务端(独立于 desktop/
├── index.ts # 入口Bun.serve
├── router.ts # HTTP 路由
├── ws/ # WebSocket 处理
├── api/ # REST API 路由
├── services/ # 业务服务
├── proxy/ # 代理层(协议转换)
├── middleware/ # 中间件
├── config/ # 服务端配置
└── types/ # 类型定义
adapters/ # 外部 IM 适配器
├── common/ # 共享模块9 个文件)
├── telegram/index.ts # Telegram Bot
├── feishu/index.ts # 飞书 Bot
└── package.json # 独立依赖
```
---
## 十、快速参考
### 关键端口
| 端口 | 用途 |
|------|------|
| 1420 | Vite 开发服务器 |
| 动态分配 | Server Sidecar`reserve_local_port` |
### 关键文件路径
| 文件 | 说明 |
|------|------|
| `~/.claude/adapters.json` | 适配器配置 |
| `~/.claude/adapter-sessions.json` | 适配器会话映射 |
| `~/.claude/sessions/` | 会话持久化数据 |
### 开发命令
```bash
# 前端开发
cd desktop && pnpm dev
# 编译 Sidecar
cd desktop && bun run build:sidecars
# Tauri 开发模式(前端 + 桌面框架)
cd desktop && pnpm tauri dev
# 构建发布包
cd desktop && pnpm tauri build
# 运行测试
cd desktop && pnpm test
```

755
docs/desktop/03-features.md Normal file
View File

@ -0,0 +1,755 @@
# Claude Code 桌面端 — 功能详解
> 深入每一个功能模块,从聊天引擎到定时任务,全面解析桌面端的能力矩阵。
<p align="center">
<a href="#一聊天引擎">聊天引擎</a> · <a href="#二工具调用系统">工具调用</a> · <a href="#三代码展示系统">代码展示</a> · <a href="#四agent-teams-团队协作">Agent Teams</a> · <a href="#五提供商管理">提供商管理</a> · <a href="#六技能与-agent-定义">技能与 Agent</a> · <a href="#七定时任务系统">定时任务</a> · <a href="#八im-适配器">IM 适配器</a> · <a href="#九设计系统">设计系统</a>
</p>
![功能全景图](./images/06-features-grid.png)
---
## 一、聊天引擎
聊天引擎是桌面端的核心,负责消息的发送、接收、渲染和交互。
### 消息列表MessageList
**文件位置**`desktop/src/components/chat/MessageList.tsx`
消息列表是对话的主展示区域:
- **自动滚动**:新消息到达时 smooth 滚动到底部
- **消息分组**Tool calls 和对应的 results 按组展示
- **混合渲染**支持文本、代码、Diff、工具调用等多种内容类型
### 消息类型详解
#### 用户消息UserMessage
```
┌──────────────────────────────┐
│ 👤 写一个快速排序算法 │
│ 📎 screenshot.png (附件) │
│ [复制] │
└──────────────────────────────┘
```
- 用户头像 + 消息文本
- 附件画廊展示(图片缩略图、文件图标)
- 悬浮显示消息操作栏
#### 助手消息AssistantMessage
```
┌──────────────────────────────────┐
│ ┌──────────────────────────────┐ │
│ │ 好的,我来实现快速排序: │ │
│ │ │ │
│ │ ```python │ │
│ │ def quicksort(arr): │ │
│ │ if len(arr) <= 1: │ │
│ │ return arr │ │
│ │ ``` │ │
│ │ [复制] ▍ │ │
│ └──────────────────────────────┘ │
└──────────────────────────────────┘
```
- 带边框的气泡容器
- 完整 Markdown 渲染(标题、列表、表格、引用、链接)
- 代码块使用 Shiki 语法高亮
- 流式输出时显示闪烁光标 `▍`
#### 思考块ThinkingBlock
```
┌──────────────────────────────────┐
│ 💭 思考过程 [展开 ▼] │
│ │
│ ┌──────────────────────────────┐ │
│ │ 让我分析一下用户的需求... │ │
│ │ 快速排序的时间复杂度是... │ │
│ │ 我应该用 Lomuto 分区方案... │ │
│ └──────────────────────────────┘ │
└──────────────────────────────────┘
```
- 默认折叠,显示第一行预览
- 点击展开查看完整推理过程
- 流式更新时显示动画光标
- 自动滚动到最新思考内容
#### 权限请求PermissionDialog
```
┌──────────────────────────────────┐
│ ⚠️ 权限请求 │
│ │
│ 工具: Write │
│ 文件: /src/sort.py │
│ │
│ ┌──────────────────────────────┐ │
│ │ + def quicksort(arr): │ │
│ │ + if len(arr) <= 1: │ │
│ │ + return arr │ │
│ └──────────────────────────────┘ │
│ │
│ [允许] [一直允许] [拒绝] │
└──────────────────────────────────┘
```
- 显示工具类型和操作目标
- 预览操作内容Diff、命令等
- 可展开查看完整输入参数
- 三个操作按钮:允许 / 一直允许 / 拒绝
#### AskUser 提问
当 AI 使用 `AskUserQuestion` 工具向你提问时,会显示一个专用输入框,你的回答会直接发送给 AI。
#### 内联任务摘要InlineTaskSummary
当 AI 创建后台任务时,对话中会内联显示任务的进度和结果摘要。
### 输入系统ChatInput
**文件位置**`desktop/src/components/chat/ChatInput.tsx`
输入框是一个功能丰富的组合组件:
```
┌──────────────────────────────────┐
│ 📎 screenshot.png × │ ← 附件画廊
├──────────────────────────────────┤
│ 🏷️ myproject (main) │ ← 项目上下文芯片
├──────────────────────────────────┤
│ │
│ 输入消息... │ ← 可扩展文本框
│ │
├──────────────┬───────────────────┤
│ [+] │ [发送] │ ← 工具栏
└──────────────┴───────────────────┘
```
**核心功能**
1. **自适应高度**:文本框随内容自动扩展,最高 200px
2. **附件画廊**:显示待发送的文件/图片
3. **项目上下文芯片**:展示当前 Git 仓库和分支
4. **Plus 菜单**:添加文件 / 插入斜杠命令
5. **斜杠命令菜单**`/` 触发,支持搜索和键盘导航
6. **文件搜索菜单**`@` 触发,路径自动补全
7. **快捷键**Enter 发送、Shift+Enter 换行、Esc 关闭菜单
---
## 二、工具调用系统
当 AI 执行工具操作时,桌面端会以结构化的方式展示工具调用和结果。
### 工具调用块ToolCallBlock
**文件位置**`desktop/src/components/chat/ToolCallBlock.tsx`
每种工具有专门的展示方式:
#### Bash 工具
```
┌──────────────────────────────────┐
│ 🖥️ Bash │
│ │
│ $ npm install express │ ← 终端风格
│ │
│ 说明: Install express package │
│ [展开] │
└──────────────────────────────────┘
```
使用 `TerminalChrome` 组件模拟终端界面:
- 深色背景
- 绿色提示符 `$`
- 显示命令内容和说明
#### Edit / Write 工具
```
┌──────────────────────────────────┐
│ ✏️ Edit src/app.ts │
│ │
│ ┌──────────────────────────────┐ │
│ │ - const port = 3000 │ │ ← Diff 视图
│ │ + const port = 8080 │ │
│ └──────────────────────────────┘ │
│ │
│ +1 -1 行 │
└──────────────────────────────────┘
```
- 使用 `DiffViewer` 展示文件变更
- 显示行数统计(+N / -N
- 自动识别文件语言
- 词级别 Diff 高亮
#### Read 工具
展示被读取的文件内容,使用 `CodeViewer` 语法高亮。
#### Glob / Grep 工具
展示搜索模式和匹配结果。
#### WebSearch / WebFetch 工具
展示搜索关键词或目标 URL。
#### 其他工具
以 JSON 格式展示工具的输入参数,可展开查看详情。
### 工具结果块ToolResultBlock
工具执行后的输出展示:
- **成功** → 绿色状态指示 + 输出内容
- **错误** → 红色状态指示 + 错误信息
- 输出以代码块展示,支持语法高亮
- 超长输出自动截断,显示行数摘要
---
## 三、代码展示系统
桌面端在代码展示方面追求**VS Code 级别的体验**。
### CodeViewer
**文件位置**`desktop/src/components/chat/CodeViewer.tsx`
- **引擎**Shiki与 VS Code 相同的语法高亮引擎)
- **主题**:自定义温暖色调主题,与应用设计系统匹配
- **行号**:左侧行号显示
- **折叠**:超过 20 行时自动折叠,点击展开
- **复制**:右上角一键复制按钮
### DiffViewer
**文件位置**`desktop/src/components/chat/DiffViewer.tsx`
- **引擎**react-diff-viewer-continued
- **模式**单列split view 更紧凑)
- **高亮**:词级别变更高亮
- **统计**:顶部显示 +N/-N 行数变化
- **语言识别**:根据文件扩展名自动识别语言
### MarkdownRenderer
**文件位置**`desktop/src/components/markdown/MarkdownRenderer.tsx`
- 基于 `marked` 解析 Markdown
- 代码块自动使用 Shiki 高亮
- 支持表格、列表、引用、链接
- 内联代码和粗体/斜体
---
## 四、Agent Teams 团队协作
![聊天消息流](./images/08-chat-message-flow.png)
桌面端可视化展示 Agent Teams 的协作状态。
### 团队视图AgentTeams
**文件位置**`desktop/src/pages/AgentTeams.tsx`
当 AI 创建 Agent Team 时,桌面端显示团队管理界面:
- **团队列表**:所有活跃团队
- **成员状态**:每个 Agent 的实时状态
| 状态 | 指示 |
|------|------|
| running | 绿色脉冲动画 |
| idle | 灰色 |
| completed | 完成标记 |
| error | 红色错误标记 |
- **成员标签**:彩色标签显示 Agent 角色和名称
- **实时更新**:通过 WebSocket 推送 `team_update` 事件
### 转录视图AgentTranscript
点击团队成员可查看该 Agent 的完整对话转录:
- 与主聊天相同的消息渲染
- 支持查看工具调用和结果
- 「返回团队」导航按钮
### TeamStatusBar
**文件位置**`desktop/src/components/teams/TeamStatusBar.tsx`
在活跃会话底部展示团队状态条:
- 团队名称
- 成员数量和状态分布
- 快速导航到团队视图
---
## 五、提供商管理
桌面端提供了完整的 AI 提供商管理界面。
### 提供商列表
**文件位置**`desktop/src/pages/Settings.tsx`Providers 标签页)
展示所有已配置的提供商:
```
┌──────────────────────────────────┐
│ ✅ Anthropic (Official) [活跃] │ ← 官方提供商
├──────────────────────────────────┤
│ 🔵 OpenRouter [编辑]│ ← 自定义提供商
│ Base: openrouter.ai/api/v1 │
│ Format: anthropic │
├──────────────────────────────────┤
│ ⚪ Ollama (Local) [编辑]│ ← 本地模型
│ Base: localhost:11434 │
│ Format: openai_chat │
├──────────────────────────────────┤
│ [+ 添加提供商] │
└──────────────────────────────────┘
```
### 提供商配置
每个提供商可配置:
| 字段 | 说明 |
|------|------|
| 名称 | 提供商显示名称 |
| API Key | 密钥(密码输入,自动脱敏) |
| Base URL | API 基础地址 |
| API 格式 | `anthropic` / `openai_chat` / `openai_responses` |
| 模型映射 | main / haiku / sonnet / opus 槽位对应的模型名 |
### 预设系统
**文件位置**`desktop/src/config/providerPresets.ts`
点击「添加提供商」时,可从预设快速创建:
- Anthropic
- OpenAI
- OpenRouter
- Ollama
- Azure OpenAI
- Google AI
- 自定义...
预设自动填充 Base URL 和 API 格式,只需填入 API Key。
### 连接测试
配置完成后点击「测试」,系统执行两步验证:
1. **连接性测试** — 发送简单请求验证网络可达
2. **模型可用性测试** — 验证配置的模型是否可用
结果以 Toast 通知展示(成功 / 失败 + 错误信息)。
---
## 六、技能与 Agent 定义
### 技能浏览SkillList / SkillDetail
**文件位置**`desktop/src/components/skills/`
技能库浏览界面:
- **列表视图**按来源分类bundled / user / project / plugin
- **搜索过滤**:按名称和描述搜索
- **详情视图**
- 技能元数据(描述、版本、来源)
- 源代码目录树
- 代码文件内容(带语法高亮)
- Frontmatter 属性展示
### Agent 定义管理
**文件位置**`desktop/src/pages/Settings.tsx`Agents 标签页)
管理 Agent 类型定义:
| 字段 | 说明 |
|------|------|
| agentType | Agent 类型标识符 |
| description | 描述(何时使用) |
| model | 默认模型sonnet/haiku/opus |
| tools | 可用工具列表 |
| systemPrompt | 自定义系统提示词 |
| color | 标识颜色 |
**来源分类**
| 来源 | 说明 |
|------|------|
| built-in | 系统内置(不可修改) |
| plugin | 插件提供 |
| userSettings | 用户级自定义 |
| projectSettings | 项目级自定义 |
| localSettings | 本地自定义 |
---
## 七、定时任务系统
### 任务管理页面
**文件位置**`desktop/src/pages/ScheduledTasks.tsx`
#### 统计卡片
页面顶部三个统计卡片:
```
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 总计 5 │ │ 活跃 3 │ │ 禁用 2 │
└──────────┘ └──────────┘ └──────────┘
```
#### 任务列表
每个任务行展示:
```
┌──────────────────────────────────────────────┐
│ 📋 每日代码审查 [启用 ✓] │
│ 每天 09:00 执行 │
│ cron: 0 9 * * * │
│ │
│ [运行历史 ▼] [手动运行] [删除] │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ 2026-04-10 09:00 ✅ 成功 (12s) │ │
│ │ 2026-04-09 09:00 ✅ 成功 (8s) │ │
│ │ 2026-04-08 09:00 ❌ 失败: timeout │ │
│ └──────────────────────────────────────┘ │
└──────────────────────────────────────────────┘
```
### 创建任务
**文件位置**`desktop/src/pages/NewTaskModal.tsx`
模态框表单:
| 字段 | 组件 | 说明 |
|------|------|------|
| 任务名称 | Input | 描述性名称 |
| 提示词 | PromptEditor | 多行文本编辑器 |
| Cron 表达式 | Input + 解释文本 | 支持标准 Cron 语法 |
| 星期几 | DayOfWeekPicker | 可视化多选星期 |
| 模型 | ModelSelector | 使用的 AI 模型 |
| 权限模式 | PermissionModeSelector | 执行时的权限策略 |
#### DayOfWeekPicker
```
┌───┬───┬───┬───┬───┬───┬───┐
│ 日│ 一│ 二│ 三│ 四│ 五│ 六│
│ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ │
└───┴───┴───┴───┴───┴───┴───┘
```
可视化选择任务执行的星期几,自动更新 Cron 表达式。
### Cron 表达式
使用 `cronDescribe` 工具将 Cron 表达式转换为人类可读描述:
```
0 9 * * 1-5 → "周一到周五每天 09:00"
*/30 * * * * → "每 30 分钟"
0 0 1 * * → "每月 1 号 00:00"
```
---
## 八、IM 适配器
### 适配器设置页面
**文件位置**`desktop/src/pages/AdapterSettings.tsx`
#### 配对管理
```
┌──────────────────────────────────┐
│ 🔐 用户配对 │
│ │
│ 当前配对码: A3K7NP │
│ 过期时间: 58 分钟后 │
│ │
│ [生成新配对码] │
│ │
│ 已配对用户: │
│ ┌──────────────────────────────┐ │
│ │ Telegram │ @john 2026-04-01 │ │
│ │ 飞书 │ 张三 2026-04-05 │ │
│ └──────────────────────────────┘ │
└──────────────────────────────────┘
```
#### Telegram 配置
| 字段 | 类型 | 说明 |
|------|------|------|
| Bot Token | 密码输入 | Telegram Bot API Token |
| 允许的用户 ID | 逗号分隔 | 静态白名单 |
#### 飞书配置
| 字段 | 类型 | 说明 |
|------|------|------|
| App ID | 文本 | 飞书应用 ID |
| App Secret | 密码 | 飞书应用密钥 |
| 加密密钥 | 密码 | 事件加密密钥 |
| 验证 Token | 密码 | 事件验证 Token |
| 允许的用户 | 逗号分隔 | open_id 白名单 |
| 流式卡片 | 开关 | 是否启用流式消息卡片 |
### 飞书适配器特性
**文件位置**`adapters/feishu/index.ts`
- **连接方式**WebSocket 长连接(无需公网地址)
- **消息格式**:飞书 JSON 富文本 → Markdown 文本
- **权限审批**Interactive Card卡片按钮
- **消息更新**Patch API 编辑已发消息(流式效果)
- **分片发送**:超过 30000 字时自动分片
### Telegram 适配器特性
**文件位置**`adapters/telegram/index.ts`
- **连接方式**Polling 模式Bot 主动轮询)
- **消息格式**:纯文本 + Markdown
- **权限审批**Inline Keyboard内联按钮
- **消息更新**`editMessageText` 编辑已发消息
- **分片发送**:超过 4000 字时自动分片
### 权限请求在 IM 中的展示
**Telegram**
```
⚠️ 权限请求
工具: Bash
命令: npm install express
说明: Install express package
[✅ 允许] [❌ 拒绝] ← Inline Keyboard
```
**飞书**
```
┌──────────────────────────┐
│ ⚠️ 权限请求 │
│ │
│ 工具: Bash │
│ 命令: npm install express│
│ │
│ [✅ 允许] [❌ 拒绝] │ ← Interactive Card
└──────────────────────────┘
```
---
## 九、设计系统
### 颜色体系
桌面端采用**暖色调**设计语言:
**文件位置**`desktop/src/theme/globals.css`
#### 主色
| 变量 | 色值 | 用途 |
|------|------|------|
| `--color-primary` | #8F482F | 品牌色、CTA 按钮 |
| `--color-primary-container` | #AD5F45 | 品牌色容器 |
| `--color-on-primary` | #FFFFFF | 品牌色上的文字 |
#### 表面色
| 变量 | 色值 | 用途 |
|------|------|------|
| `--color-surface` | #FAF9F5 | 主背景(浅米色) |
| `--color-surface-container` | #EFEEEA | 卡片背景 |
| `--color-surface-container-low` | #F4F4F0 | 次级容器 |
| `--color-surface-container-high` | #E9E8E4 | 高层级容器 |
#### 语义色
| 变量 | 色值 | 用途 |
|------|------|------|
| `--color-secondary` | #2D628F | 信息、链接 |
| `--color-tertiary` | #4F6237 | 成功、确认 |
| `--color-error` | #BA1A1A | 错误、警告 |
#### 文本色
| 变量 | 色值 | 用途 |
|------|------|------|
| `--color-on-surface` | #1B1C1A | 主文本 |
| `--color-on-surface-variant` | #54433E | 次级文本 |
| `--color-outline` | #87736D | 边框 |
| `--color-outline-variant` | #DAC1BA | 弱边框 |
### 字体系统
| 字体 | 用途 | 字重 |
|------|------|------|
| **Inter** | 正文 | 400-600 |
| **Manrope** | 标题 | 400-800 |
| **JetBrains Mono** | 代码 | 400 |
### 图标系统
使用 **Material Symbols Outlined** 图标集,自托管字体:
- 齿轮 → 设置
- 时钟 → 定时任务
- + → 新建
- × → 关闭
- 文件夹 → 项目
- 搜索 → 搜索
### 动画
| 名称 | 效果 | 用途 |
|------|------|------|
| `animate-pulse-dot` | 脉冲闪烁 | 运行中会话指示 |
| `animate-shimmer` | 闪烁光标 | 流式输出光标 |
| slide-in / fade-in | 滑入淡入 | Toast 通知 |
### 通知系统Toast
**文件位置**`desktop/src/components/shared/Toast.tsx`
右下角固定位置的通知组件:
```
┌──────────────────────────┐
│ ✅ 提供商连接测试成功 ×│
│ 所有模型可用 │
└──────────────────────────┘
```
四种类型:
| 类型 | 左边框色 | 场景 |
|------|----------|------|
| success | 绿色 | 操作成功 |
| error | 红色 | 操作失败 |
| warning | 黄色 | 警告提示 |
| info | 蓝色 | 信息通知 |
- 自动消失(可配置时长)
- 点击 × 手动关闭
- 从右侧滑入动画
---
## 十、国际化
**文件位置**`desktop/src/i18n/`
### 支持语言
- **en** — English
- **zh** — 简体中文
### 使用方式
```typescript
// 在 React 组件中
const t = useTranslation()
return <button>{t('common.save')}</button>
// 支持参数插值
t('chat.tokenCount', { count: 1200 })
```
### 翻译 Key 体系
| 命名空间 | 示例 | 说明 |
|----------|------|------|
| `common.*` | save, cancel, delete | 通用词汇 |
| `sidebar.*` | newSession, search | 侧边栏 |
| `chat.*` | sendMessage, thinking | 聊天 |
| `settings.*` | providers, permissions | 设置 |
| `status.*` | connected, error | 状态 |
| `titlebar.*` | appName | 标题栏 |
### 切换语言
在设置 → 通用 中切换语言,设置保存到 `localStorage`,即时生效。
---
## 十一、快速参考
### 组件清单
| 组件 | 路径 | 职责 |
|------|------|------|
| AppShell | `components/layout/AppShell.tsx` | 应用根容器、初始化 |
| Sidebar | `components/layout/Sidebar.tsx` | 侧边栏导航 |
| TabBar | `components/layout/TabBar.tsx` | 标签页管理 |
| ContentRouter | `components/layout/ContentRouter.tsx` | 页面路由 |
| StatusBar | `components/layout/StatusBar.tsx` | 状态栏 |
| ChatInput | `components/chat/ChatInput.tsx` | 消息输入 |
| MessageList | `components/chat/MessageList.tsx` | 消息列表 |
| ToolCallBlock | `components/chat/ToolCallBlock.tsx` | 工具调用展示 |
| CodeViewer | `components/chat/CodeViewer.tsx` | 代码高亮 |
| DiffViewer | `components/chat/DiffViewer.tsx` | Diff 展示 |
| PermissionDialog | `components/chat/PermissionDialog.tsx` | 权限审批 |
| ModelSelector | `components/controls/ModelSelector.tsx` | 模型选择 |
| Toast | `components/shared/Toast.tsx` | 通知系统 |
### Store 清单
| Store | 路径 | 核心状态 |
|-------|------|----------|
| chatStore | `stores/chatStore.ts` | messages, chatState, streamingText |
| sessionStore | `stores/sessionStore.ts` | sessions, activeSessionId |
| tabStore | `stores/tabStore.ts` | tabs, activeTabId, tabOrder |
| settingsStore | `stores/settingsStore.ts` | model, permissionMode, language |
| providerStore | `stores/providerStore.ts` | providers, activeProvider |
| uiStore | `stores/uiStore.ts` | theme, toasts, modals |
| taskStore | `stores/taskStore.ts` | tasks, runs |
| teamStore | `stores/teamStore.ts` | teams, members |
### API 客户端清单
| 模块 | 路径 | 职责 |
|------|------|------|
| client | `api/client.ts` | HTTP 基础客户端 |
| websocket | `api/websocket.ts` | WebSocket 管理器 |
| sessions | `api/sessions.ts` | 会话 CRUD |
| providers | `api/providers.ts` | 提供商管理 |
| models | `api/models.ts` | 模型操作 |
| tasks | `api/tasks.ts` | 定时任务 |
| teams | `api/teams.ts` | Agent 团队 |
| agents | `api/agents.ts` | Agent 定义 |
| skills | `api/skills.ts` | 技能查询 |
| adapters | `api/adapters.ts` | 适配器配置 |
| search | `api/search.ts` | 搜索 |
| filesystem | `api/filesystem.ts` | 文件系统 |

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 769 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

119
docs/desktop/index.md Normal file
View File

@ -0,0 +1,119 @@
# Claude Code 桌面端文档
> 图形化的 AI Code Editor支持多会话、多标签、外部 UI 接入的完整桌面体验。
---
## 文档目录
### [01-quick-start.md](./01-quick-start.md) — 快速上手
面向用户的桌面端使用指南,涵盖:
- **启动与界面**:首次运行、界面布局、主题切换
- **对话操作**:新建会话、发送消息、附件上传、斜杠命令
- **多标签系统**:标签切换、拖拽排序、关闭策略
- **权限控制**:四种权限模式、工具审批流程
- **项目管理**工作目录关联、项目筛选、Git 信息展示
- **模型与提供商**:模型切换、自定义 Provider、连接测试
- **IM 适配器**Telegram / 飞书接入、用户配对
- **定时任务**Cron 任务创建、运行历史查看
**适合人群**:所有桌面端用户
---
### [02-architecture.md](./02-architecture.md) — 架构设计
面向开发者的技术架构解析,涵盖:
- **技术栈总览**Tauri 2 + React 18 + Zustand + Vite + Tailwind CSS 4
- **三层架构**Tauri Shell → Express Server → CLI 子进程
- **通信协议**WebSocket 消息格式、HTTP API 端点、流式输出机制
- **状态管理**Zustand Store 设计、数据流向、持久化策略
- **会话生命周期**:创建 → 连接 → 交互 → 断开 → 恢复
- **代理层**多协议转换Anthropic / OpenAI、Provider 管理
- **适配器桥接**:外部 IM 平台的 WebSocket 接入架构
**适合人群**:贡献者、架构师、想接入自定义 UI 的开发者
---
### [03-features.md](./03-features.md) — 功能详解
深入解析桌面端每个功能模块,涵盖:
- **聊天引擎**消息类型、流式渲染、代码高亮、Diff 展示、思考块
- **工具调用系统**权限请求卡片、Tool 输入/输出展示、Bash 终端模拟
- **Agent Teams**:团队视图、成员状态、转录查看
- **技能与 Agent 定义**技能浏览、Agent 配置、自定义扩展
- **定时任务**Cron 编辑器、Day-of-Week 选择、运行日志
- **国际化**:中英文切换、翻译 Key 体系
- **键盘快捷键**:全局快捷键、输入框快捷操作
**适合人群**:想充分利用桌面端功能的高级用户和开发者
---
## 配图说明
所有配图采用深色背景(#1a1a2e+ Anthropic 品牌橙铜色(#D97757)风格,与项目文档视觉语言一致。
| 图片 | 说明 | 所属文档 |
|------|------|----------|
| `01-desktop-overview.png` | 桌面端界面总览 — 布局与核心区域 | 快速上手 |
| `02-tech-stack.png` | 技术栈全景 — 框架与工具链 | 架构设计 |
| `03-three-layer-arch.png` | 三层架构图 — Tauri / Server / CLI | 架构设计 |
| `04-websocket-protocol.png` | WebSocket 通信协议 — 消息类型与流向 | 架构设计 |
| `05-session-lifecycle.png` | 会话生命周期 — 创建到恢复的完整流程 | 架构设计 |
| `06-features-grid.png` | 功能全景图 — 核心功能模块一览 | 功能详解 |
| `07-adapter-bridge.png` | 适配器桥接 — 外部 IM 平台接入架构 | 功能详解 |
| `08-chat-message-flow.png` | 聊天消息流 — 从输入到渲染的数据流 | 功能详解 |
---
## 快速开始
### 用户
1. 阅读 [快速上手](./01-quick-start.md)
2. 了解界面布局和基本操作
3. 配置 AI 模型提供商
4. 开始你的第一次对话
### 开发者
1. 阅读 [架构设计](./02-architecture.md)
2. 查看源码位置:
- `desktop/src/` — React 前端代码
- `desktop/src-tauri/` — Tauri Rust 后端
- `desktop/sidecars/` — Sidecar 启动器
- `src/server/` — Express API 服务端
- `adapters/` — 外部 IM 适配器
3. 理解三层架构和 WebSocket 通信协议
---
## 核心概念速查
| 概念 | 说明 |
|------|------|
| **Tauri** | 轻量级跨平台桌面框架,用 Rust 管理窗口和 Sidecar 进程 |
| **Sidecar** | 随 Tauri 主进程启动的后台服务,运行 Express API 服务器 |
| **Session** | 一次对话会话,绑定工作目录,通过 WebSocket 通信 |
| **Tab** | 标签页,一个 Tab 对应一个 Session 或特殊页面(设置、任务) |
| **Provider** | AI 模型提供商,支持 Anthropic、OpenAI 兼容等多种接口 |
| **Adapter** | 外部 IM 适配器,让 Telegram / 飞书等平台接入 Claude Code |
| **Pairing** | 配对机制6 位安全码授权外部 IM 用户访问 |
| **Store** | Zustand 状态容器,管理聊天、会话、设置等状态 |
| **Slash Command** | 斜杠命令,`/commit``/review-pr` 等快捷操作 |
---
## 相关资源
- [Claude Code Haha 主页](/)
- [多 Agent 系统文档](/agent/)
- [记忆系统文档](/memory/)
- [Skills 系统文档](/skills/)
- [GitHub Issues](https://github.com/NanmiCoder/cc-haha/issues)