mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
Add complete server-side implementation for the Claude Code Desktop App UI: - REST API: sessions, conversations, settings, models, scheduled tasks, search, agents, and status endpoints (9 modules, 30+ endpoints) - WebSocket: real-time chat streaming with state transitions, ping/pong, permission request forwarding, and stop generation support - Services: sessionService (JSONL read/write, CLI-compatible), settingsService (atomic writes), cronService, searchService (ripgrep), agentService (YAML management) - Middleware: CORS (localhost-only), auth, unified error handling - Tests: 180 tests (unit + E2E + business flow), all passing - Docs: PRD, UI design spec, server architecture design Non-invasive: all new code under src/server/, no changes to existing CLI code. CLI/UI data interop: reads/writes the same JSONL/JSON files as the CLI. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
9.7 KiB
9.7 KiB
Claude Code Desktop App — 服务端架构设计
一、设计原则
- 非侵入性: 不修改现有 CLI 源代码,在
src/server/下新建服务层 - 数据一致性: 读写与 CLI 完全相同的文件(JSONL 会话、JSON 设置、Cron 任务)
- CLI/UI 互通: UI 的操作落盘到 CLI 的文件系统,CLI 的会话在 UI 可见
- 渐进式: 先实现核心 API,再扩展高级功能
二、技术栈
| 层 | 技术 | 理由 |
|---|---|---|
| HTTP Server | Bun.serve() | 原项目已用 Bun,零额外依赖 |
| WebSocket | Bun 原生 WebSocket | 已有 ws 依赖,Bun 原生更高效 |
| 验证 | Zod v4 | 已在依赖中 |
| 测试 | bun:test | Bun 内置,无需额外依赖 |
| API 风格 | REST + WebSocket | REST 用于 CRUD,WS 用于流式传输 |
三、目录结构
src/server/
├── index.ts # 服务器入口
├── router.ts # 路由注册
├── middleware/
│ ├── auth.ts # API Key 鉴权
│ ├── cors.ts # CORS 处理
│ └── errorHandler.ts # 统一错误处理
├── api/
│ ├── sessions.ts # 会话管理 API
│ ├── conversations.ts # 对话/消息 API
│ ├── settings.ts # 设置 API
│ ├── models.ts # 模型选择 API
│ ├── scheduled-tasks.ts # 定时任务 API
│ ├── search.ts # 搜索 API
│ ├── agents.ts # Agent 管理 API
│ ├── mcp.ts # MCP 服务器管理 API
│ └── status.ts # 状态与诊断 API
├── ws/
│ ├── handler.ts # WebSocket 连接管理
│ ├── chatStream.ts # 对话流式传输
│ └── events.ts # 事件类型定义
├── services/
│ ├── sessionService.ts # 会话服务(封装 sessionStorage)
│ ├── conversationService.ts # 对话服务(封装 query engine)
│ ├── settingsService.ts # 设置服务(封装 settings)
│ ├── cronService.ts # 定时任务服务(封装 cronTasks)
│ ├── searchService.ts # 搜索服务(封装 ripgrep)
│ ├── agentService.ts # Agent 服务
│ └── mcpService.ts # MCP 服务
└── __tests__/
├── sessions.test.ts
├── conversations.test.ts
├── settings.test.ts
├── scheduled-tasks.test.ts
├── search.test.ts
└── e2e/
└── full-flow.test.ts
四、API 设计
4.1 会话管理 (Sessions)
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /api/sessions |
获取会话列表(支持分页、项目过滤) |
| GET | /api/sessions/:id |
获取会话详情(标题、消息数、时间) |
| POST | /api/sessions |
创建新会话 |
| DELETE | /api/sessions/:id |
删除会话 |
| PATCH | /api/sessions/:id |
更新会话(重命名) |
| GET | /api/sessions/:id/messages |
获取会话消息历史 |
数据来源: ~/.claude/projects/{proj}/{sid}.jsonl (JSONL 格式)
实现要点:
- 调用
loadMessageLogs()获取会话列表 - 调用
loadTranscriptFile()解析 JSONL 消息 - 使用
getProjectDir()定位项目目录 - 会话 ID 为 UUID v4
4.2 对话 (Conversations)
| 方法 | 路径 | 描述 |
|---|---|---|
| POST | /api/sessions/:id/chat |
发送消息(返回任务 ID) |
| GET | /api/sessions/:id/chat/status |
获取对话状态 |
| POST | /api/sessions/:id/chat/stop |
停止生成 |
WebSocket: ws://host:port/ws/chat/:sessionId
- 发送消息 → 流式接收 AI 回复
- 实时推送工具调用进度
- 权限请求转发给前端
WebSocket 消息格式:
// 客户端 → 服务器
type ClientMessage =
| { type: 'user_message'; content: string; attachments?: Attachment[] }
| { type: 'permission_response'; requestId: string; allowed: boolean }
| { type: 'stop_generation' }
// 服务器 → 客户端
type ServerMessage =
| { type: 'content_start'; blockType: 'text' | 'tool_use' }
| { type: 'content_delta'; text?: string; toolInput?: string }
| { type: 'tool_use_complete'; toolName: string; toolUseId: string }
| { type: 'tool_result'; toolUseId: string; content: any; isError: boolean }
| { type: 'permission_request'; requestId: string; toolName: string; input: any }
| { type: 'message_complete'; usage: Usage }
| { type: 'error'; message: string; code: string }
| { type: 'status'; state: 'thinking' | 'tool_executing' | 'idle' }
4.3 设置 (Settings)
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /api/settings |
获取合并后的设置 |
| GET | /api/settings/user |
获取用户级设置 |
| GET | /api/settings/project |
获取项目级设置 |
| PUT | /api/settings/user |
更新用户级设置 |
| PUT | /api/settings/project |
更新项目级设置 |
| GET | /api/permissions/mode |
获取当前权限模式 |
| PUT | /api/permissions/mode |
切换权限模式 |
数据来源: ~/.claude/settings.json + .claude/settings.json
4.4 模型 (Models)
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /api/models |
获取可用模型列表 |
| GET | /api/models/current |
获取当前选中模型 |
| PUT | /api/models/current |
切换模型 |
| GET | /api/effort |
获取当前 Effort 等级 |
| PUT | /api/effort |
设置 Effort 等级 |
4.5 定时任务 (Scheduled Tasks)
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /api/scheduled-tasks |
获取定时任务列表 |
| POST | /api/scheduled-tasks |
创建定时任务 |
| PUT | /api/scheduled-tasks/:id |
更新定时任务 |
| DELETE | /api/scheduled-tasks/:id |
删除定时任务 |
数据来源: .claude/scheduled_tasks.json
4.6 搜索 (Search)
| 方法 | 路径 | 描述 |
|---|---|---|
| POST | /api/search |
全局搜索(ripgrep) |
| POST | /api/search/sessions |
搜索会话历史 |
4.7 Agent 管理
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /api/agents |
获取 Agent 定义列表 |
| GET | /api/agents/:name |
获取 Agent 详情 |
| POST | /api/agents |
创建 Agent 定义 |
| PUT | /api/agents/:name |
更新 Agent 定义 |
| DELETE | /api/agents/:name |
删除 Agent 定义 |
| GET | /api/tasks |
获取后台任务列表 |
| GET | /api/tasks/:id |
获取任务详情 |
4.8 MCP 服务器管理
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /api/mcp/servers |
获取 MCP 服务器列表 |
| POST | /api/mcp/servers |
添加 MCP 服务器 |
| DELETE | /api/mcp/servers/:name |
移除 MCP 服务器 |
| GET | /api/mcp/tools |
获取 MCP 工具列表 |
4.9 状态与诊断
| 方法 | 路径 | 描述 |
|---|---|---|
| GET | /api/status |
服务器状态(健康检查) |
| GET | /api/status/diagnostics |
系统诊断信息 |
| GET | /api/status/usage |
Token 用量统计 |
| GET | /api/status/user |
用户信息 |
五、服务层设计
每个 Service 封装对现有工具函数的调用,提供统一的错误处理和数据转换:
// 示例: SessionService
class SessionService {
// 列出所有会话
async listSessions(options: { project?: string; limit?: number; offset?: number }): Promise<SessionListResponse>
// 获取会话消息
async getSessionMessages(sessionId: string): Promise<Message[]>
// 创建新会话
async createSession(workDir: string): Promise<SessionInfo>
// 删除会话
async deleteSession(sessionId: string): Promise<void>
// 重命名会话
async renameSession(sessionId: string, title: string): Promise<void>
}
关键实现:
SessionService调用loadMessageLogs()和loadTranscriptFile()SettingsService调用getSettings()和updateSettingsForSource()CronService调用readCronTasks()和writeCronTasks()SearchService调用 ripgrep 流式搜索ConversationService使用queryModelWithStreaming()+StreamingToolExecutor
六、WebSocket 协议
连接流程
1. 客户端连接: ws://host:port/ws/chat/{sessionId}
Headers: Authorization: Bearer {apiKey}
2. 服务器确认: { type: 'connected', sessionId: '...' }
3. 客户端发送消息: { type: 'user_message', content: '...' }
4. 服务器流式响应:
{ type: 'status', state: 'thinking' }
{ type: 'content_start', blockType: 'text' }
{ type: 'content_delta', text: 'Let me...' }
{ type: 'content_delta', text: ' help you...' }
{ type: 'content_start', blockType: 'tool_use', toolName: 'Bash' }
{ type: 'tool_use_complete', toolName: 'Bash', toolUseId: '...' }
{ type: 'permission_request', requestId: '...', toolName: 'Bash', input: {...} }
5. 客户端批准: { type: 'permission_response', requestId: '...', allowed: true }
6. 服务器继续:
{ type: 'tool_result', toolUseId: '...', content: '...', isError: false }
{ type: 'content_delta', text: 'Done!' }
{ type: 'message_complete', usage: { input_tokens: 1000, output_tokens: 500 } }
{ type: 'status', state: 'idle' }
七、鉴权方案
- 本地运行: 简单 API Key 验证(从 .env 读取)
- Header:
Authorization: Bearer {ANTHROPIC_API_KEY} - WebSocket: 首次连接时通过 URL query 或首条消息验证
- 不做复杂的用户系统,依赖 Anthropic API Key 鉴权
八、测试策略
单元测试
- 每个 Service 独立测试
- Mock 文件系统操作
- 验证输入输出格式
集成测试
- 启动测试服务器
- 发送 HTTP 请求验证响应
- WebSocket 连接和消息流测试
E2E 测试
- 完整对话流程(创建会话 → 发消息 → 收回复 → 停止 → 查看历史)
- 定时任务 CRUD
- 设置读写
- 搜索功能