Files
cc-web/README.md
2026-06-24 10:36:03 +08:00

445 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CC-Web
Claude Code / Codex / Codex App 的 Web 远程协作工作台。
![Node.js](https://img.shields.io/badge/Node.js-18+-339933?logo=node.js&logoColor=white)
![License](https://img.shields.io/badge/License-MIT-blue)
[English README](./README.en.md) | [更新日志](./CHANGELOG.md)
> 当前仓库已经不是原始 cc-web 的简单轻量封装版本。它在多轮真实使用中围绕
> Codex App、MCP、跨对话协作、子代理可视化、移动端体验和工程化回归做了大量扩展。
## 项目定位
CC-Web 现在更接近一个 **本地 Agent 编排台**
- 浏览器里统一管理 Claude、Codex CLI、Codex App 三类 Agent 会话
- 后端负责会话持久化、进程管理、Codex App app-server 接入、MCP 注入和通知
- 前端负责多会话切换、项目分组、富文本/工具调用渲染、图片附件、跨对话状态和移动端交互
- 内置 ccweb MCP让一个对话可以创建、投递、等待和接收其他 ccweb 对话的结果
## 相对原仓库的主要变化
| 方向 | 当前能力 |
|------|----------|
| 多 Agent | 支持 `claude``codex``codexapp` 三种会话,并按 Agent 隔离最近会话、模式和配置 |
| Codex App | 接入 Codex app-server支持流式消息、工具调用、审批、引导输入、Goal、MCP reload 和运行态恢复 |
| ccweb MCP | 内置 `ccweb` MCP server支持列会话、创建持久对话、跨对话发送、请求回复和等待回复查询 |
| 原生子代理 | Codex App 原生 `spawn_agent` / `wait_agent` 等协作工具会在页面中合并展示为子代理状态卡片 |
| 跨对话编排 | 子对话完成后可把结果写回来源对话;来源对话忙碌时进入等待队列,空闲后再投递 |
| 输入增强 | `/` 命令、`@` 文件/Prompt、`$` Skill、MCP 候选项、Codex skill `agents/openai.yaml` 元数据展示 |
| 会话体验 | 项目分组、项目折叠、搜索、置顶、快速在项目下新建会话、旧会话自动折叠 |
| 富内容 | Markdown、代码高亮、代码复制/预览、图片上传/粘贴/预览、附件过期清理 |
| 移动端 | 修复移动端会话切换、视口高度、触控复制、上传和通知体验 |
| 稳定性 | 进程恢复、Codex App 状态落盘、输出分段、自动 compact、回归脚本覆盖主路径 |
## 功能特性
### Agent 与会话
- **三类 Agent**Claude、Codex CLI、Codex App
- **独立会话空间**:切换 Agent 后只显示对应 Agent 的会话与最近记录
- **权限模式**:支持 `default``plan``yolo`
- **模型切换**Claude 使用预设映射Codex / Codex App 支持自由模型名
- **历史导入**:支持导入 `~/.claude/projects/``~/.codex/sessions/` 中的本地历史
- **后台任务**:浏览器关闭后子进程继续运行,重新打开后自动同步
### Codex App 集成
Codex App 模式用于贴近 Codex 官方 app-server 的能力,而不是复用旧 CLI 输出解析。
- 初始化后发送 `initialized` notification
- best-effort 启用 `goals` feature并探测 `collaborationMode/list`
- 使用 `collaborationMode` 传递模型、推理强度和开发者指令
- 支持 `/goal` 查看、设置、暂停、恢复和清除持久目标
- 支持交互式审批和 `request_user_input` 引导输入
- 支持运行中插入用户消息
- 支持 `config/mcpServer/reload`,不用重启整个 ccweb 就能重载当前对话 MCP
- 默认启用 Codex App worker 隔离,降低 app-server 异常对主进程的影响
- 将 Codex App streaming state 写入 `sessions/{id}-run/codexapp-state.json`,服务重启后可恢复
### ccweb MCP 与跨对话协作
ccweb 会给 Codex / Codex App 会话注入内置 MCP 配置,让 Agent 可以调度同一个 Web 工作台里的其他对话。
| MCP 工具 | 用途 |
|----------|------|
| `ccweb_list_conversations` | 列出可投递的 ccweb 对话,只返回轻量元数据 |
| `ccweb_create_conversation` | 创建新的 ccweb 持久对话,可指定 `cwd`、标题、模式和首条消息 |
| `ccweb_send_message` | 给指定对话投递消息,目标对话显示“来自某对话”的气泡 |
| `ccweb_request_reply` | 投递消息并等待目标对话本轮完成后返回结果 |
| `ccweb_list_pending_replies` | 查看当前来源对话等待中的跨对话回复 |
| `ccweb_get_pending_reply` | 按 `requestId` 读取等待回复的状态和正文 |
设计边界:
- **一次性并行研究** 优先使用 Codex App 原生子代理
- **需要长期可追踪、可继续打开聊天的任务** 使用 `ccweb_create_conversation`
- `ccweb_create_conversation` 默认继承来源对话 Agent未显式传 `mode` 时默认 `yolo`
- 跨对话返回内容会以只读展示消息写回来源对话,避免再次触发来源模型浪费 token
### 子代理状态展示
Codex App 原生协作工具会被转成页面上的子代理状态卡片:
- 合并展示 `spawn_agent` / `wait_agent` / `close_agent` 等工具调用
- 显示子代理运行中、已返回、已关闭等状态
- 支持手动关闭子代理
- 子代理结果可合并进父消息工具调用结果,便于后续追踪
### 输入框与快捷能力
- `/`:本地 slash command、MCP 工具和 MCP server 候选
- `@`:项目文件、目录、配置 Prompt 和 `~/.codex/prompts` Prompt
- `$`Codex Skill包含项目级 skill、用户级 skill 和元数据
- 支持 Codex skill 的 `agents/openai.yaml`:展示名称、描述、图标、默认提示词预览和 MCP 依赖
- 发送后持久化 mention 元数据,气泡中可显示已引用的 Prompt / File / Skill
- 支持笔记模式:先把内容记成可编辑气泡,稍后再发送给 Agent
### 前端体验
- 项目分组、折叠、搜索、置顶和项目内快速新建会话
- 会话运行中、等待跨对话回复、未读状态等可视化提示
- Markdown 渲染、代码块高亮、复制、预览
- 图片附件上传、剪贴板粘贴、缩略图和放大预览
- 附件大小限制 10MB单条消息最多 4 张图片,默认 7 天过期
- Agent 输出分隔线可显示时间,也可在设置中关闭
- 每条助手气泡末尾提供“定位到本条最后一段”的按钮
- 跨对话返回气泡支持折叠,并把折叠状态缓存到浏览器
- 多套主题,包含亮色与暗色方案
## 前提条件
- Node.js >= 18
- npm
- 已安装并登录需要使用的 Agent CLI
源码方式运行需要 Node.js >= 18。Node.js 版本过低时,可先执行:
```bash
# 已安装 nvm 时,使用当前 LTS 版本
nvm install --lts
nvm use --lts
node -v
# Ubuntu / Debian / WSL可固定安装 Node.js 22root 用户可去掉 sudo
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs
node -v
# RHEL / Rocky / AlmaLinux 8/9可固定安装 Node.js 22root 用户可去掉 sudo
curl -fsSL https://rpm.nodesource.com/setup_22.x | sudo bash -
sudo dnf install -y nodejs || sudo yum install -y nodejs
node -v
```
CentOS 7 这类老系统通常停在 `glibc 2.17`NodeSource Node.js 22 RPM 会要求
`glibc >= 2.28`,不要在这台机器上硬装。老系统部署请使用下面的
**Bun single executable** 方式。
```bash
npm install -g @anthropic-ai/claude-code
npm install -g @openai/codex
```
> Codex App 相关能力依赖当前 Codex CLI / app-server 是否暴露对应协议能力。
> 如果某个渠道没有 `spawn_agent`、`tool_search` 或 goalsccweb 只能按运行时能力降级。
## 快速开始
### Linux / macOS
```bash
git clone <cc-web-repo-url>
cd cc-web
./start.sh
```
`start.sh` 会执行以下动作:
- root 用户运行时提醒风险
- 检查 Node.js >= 18 和 npm
-`.env.example` 创建 `.env`
- 首次部署时引导设置登录密码
- 检查 Claude / Codex CLI 是否可用
- 自动安装 PM2
- 使用 `npm ci``npm install` 安装依赖
-`ccweb` 为默认 PM2 应用名启动或重启服务
临时前台运行:
```bash
npm install
npm start
```
启动后访问:
```text
http://localhost:8002
```
### CentOS 7 / 老 glibc
hapi 能在 CentOS 7 上运行,不是因为它在 CentOS 7 上安装了新版 Node而是因为
它在构建机用 `bun build --compile --target=bun-linux-x64-baseline` 产出 baseline
单文件二进制。cc-web 也按这个思路提供发布包构建。
在较新的 Linux 构建机或 CI 上执行:
```bash
npm install
npm run build:single-exe
```
默认会生成:
```text
dist-exe/bun-linux-x64-baseline/
```
把这个目录整体拷贝到 CentOS 7 后直接运行:
```bash
cd /opt/cc-web
chmod +x cc-web
PORT=8002 CC_WEB_PASSWORD='请改成强密码' ./cc-web
```
这个发布包只包含 cc-web 服务本体和前端资源,**不会把 Claude/Codex CLI 打进包里**。
运行时仍调用宿主机上的 CLI
```bash
export CLAUDE_PATH=/usr/local/bin/claude
export CODEX_PATH=/usr/local/bin/codex
PORT=8002 CC_WEB_PASSWORD='请改成强密码' ./cc-web
```
如果不设置 `CLAUDE_PATH` / `CODEX_PATH`,默认仍从宿主机 `PATH` 查找 `claude``codex`
### Windows
```cmd
git clone <cc-web-repo-url>
cd cc-web
npm install
copy .env.example .env
node server.js
```
也可以双击 `start.bat`
## 配置
### 环境变量
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `PORT` | `8002` | HTTP / WebSocket 监听端口 |
| `CC_WEB_PASSWORD` | 自动生成 | 首次启动登录密码;启动后会迁移到 `config/auth.json` |
| `CLAUDE_PATH` | `claude` | Claude CLI 可执行文件路径 |
| `CODEX_PATH` | `codex` | Codex CLI 可执行文件路径 |
| `PUSHPLUS_TOKEN` | 空 | 首次启动可迁移到通知配置 |
| `CC_WEB_CONFIG_DIR` | `./config` | 配置目录覆写,常用于测试隔离 |
| `CC_WEB_SESSIONS_DIR` | `./sessions` | 会话目录覆写,常用于测试隔离 |
| `CC_WEB_LOGS_DIR` | `./logs` | 日志目录覆写,常用于测试隔离 |
| `CC_WEB_CODEX_APP_WORKER` | 开启 | 设为 `0` / `false` / `off` 可关闭 Codex App worker |
| `CC_WEB_PROCESS_CLEAN_PATH` | 自动探测 | 清理旧 Codex app-server 进程时使用的匹配路径覆写 |
还有若干面向大历史、长输出和 Codex App 状态落盘的高级限制参数,例如:
- `CC_WEB_SESSION_PERSIST_MAX_MESSAGES`
- `CC_WEB_SESSION_MESSAGE_CONTENT_MAX_CHARS`
- `CC_WEB_SESSION_MAX_TOOL_CALLS_PER_MESSAGE`
- `CC_WEB_CODEX_APP_STATE_MAX_BYTES`
- `CC_WEB_CODEX_APP_RUNTIME_MAX_TOOL_CALLS`
- `CC_WEB_CROSS_CONVERSATION_MAX_CONTENT_CHARS`
- `CC_WEB_MCP_CREATE_CONVERSATION_MAX_HOP_COUNT`
默认值已按当前项目的长会话场景设置,通常不需要调整。
### 运行态文件
| 路径 | 说明 |
|------|------|
| `config/auth.json` | 登录密码配置,运行时生成 |
| `config/notify.json` | 通知渠道配置,运行时生成 |
| `config/codex.json` | Codex 默认模型等配置,运行时生成 |
| `config/cross-conversation-replies.json` | 跨对话等待回复状态 |
| `sessions/*.json` | ccweb 会话历史 |
| `sessions/{id}-run/` | 单次运行输出、PID、Codex App 状态 |
| `sessions/_attachments/` | 图片附件与元数据 |
| `logs/process.log` | 进程生命周期日志 |
不要提交真实 token、API Key、`.env`、真实会话数据和日志。
## 通知配置
点击侧边栏底部设置入口,可以配置:
| 通知方式 | 所需配置 |
|----------|----------|
| PushPlus | Token |
| Telegram | Bot Token + Chat ID |
| Server 酱 | SendKey |
| 飞书机器人 | Webhook URL |
| QQ / Qmsg | Qmsg Key |
Token 在 UI 中脱敏显示,配置写入 `config/notify.json`
## 项目结构
```text
cc-web/
├── server.js # HTTP / WebSocket / 会话 / 进程 / MCP / Codex App 编排
├── lib/
│ ├── agent-runtime.js # Claude / Codex CLI spawn spec 与事件解析
│ ├── codex-app-runtime.js # Codex App notification / tool / stream 归一化
│ ├── codex-app-server-client.js # Codex app-server JSON-RPC 客户端
│ ├── codex-app-worker.js # Codex App worker 进程入口
│ ├── codex-app-worker-client.js # 主进程到 worker 的客户端
│ ├── ccweb-mcp-server.js # 内置 ccweb MCP stdio server
│ └── codex-rollouts.js # Codex 本地 rollout 历史解析
├── public/
│ ├── index.html # 页面结构
│ ├── app.js # 前端状态、WebSocket、会话列表、消息渲染
│ ├── style.css # 主题、布局、移动端与工具调用样式
│ └── sw.js # Service Worker / 浏览器通知
├── scripts/
│ ├── regression.js # 隔离式回归脚本
│ ├── mock-claude.js # 回归用 mock Claude CLI
│ ├── mock-codex.js # 回归用 mock Codex CLI
│ └── mock-codex-app-server.js # 回归用 mock Codex app-server
├── config/ # 运行态配置目录
├── sessions/ # 运行态会话目录
├── logs/ # 运行态日志目录
├── AGENTS.md # 本项目 Agent 工作约定
├── .cbmignore # codebase-memory-mcp 索引忽略规则
├── .env.example
├── start.sh
├── start.bat
└── package.json
```
## 架构设计
```text
[Browser]
│ WebSocket / HTTP
[server.js]
├── Claude / Codex CLI detached process
├── Codex App app-server / worker
├── ccweb internal MCP API
├── sessions / run state / attachments
└── notifications / auth / process log
```
关键设计:
- 普通 Claude / Codex CLI 会话通过 detached 子进程运行
- Codex App 会话走 app-server JSON-RPC并可通过 worker 隔离
- 会话 JSON 是前端恢复和历史展示的主要数据源
- 运行中输出会同步写入 `{sessionId}-run/`,避免异常重启后完全丢失
- 内部 MCP token 只在本进程与子进程环境中传递,日志会做脱敏
- 跨对话消息不会包含对话全文摘要,避免上下文过大
## 回归测试
```bash
npm run regression
```
回归脚本会在临时目录中启动 mock Claude、mock Codex 和 mock Codex app-server覆盖
- 登录、会话创建、模式切换
- Claude / Codex 消息与图片附件
- Codex App streaming、tool call、审批、引导输入、Goal
- Composer 的 `/``@``$` 候选与 mention 持久化
- ccweb MCP 的创建对话、跨对话投递、等待回复和队列
- Codex App worker 恢复与异常状态保护
## 运维
### PM2
```bash
pm2 status ccweb
pm2 logs ccweb
pm2 restart ccweb --update-env
```
如果需要开机自启:
```bash
pm2 startup
pm2 save
```
### 重启前检查
修改 ccweb 项目后如果需要重启服务,应先确认当前会话列表中是否还有其他 `running` 对话。
- 除当前维护对话外没有其他运行中对话:可以重启
- 仍有其他运行中对话:暂缓重启,避免打断正在执行的 Agent
### systemd
如果不用 PM2可以使用 systemd。重点是只杀 Node.js 主进程,不主动杀 Claude / Codex 子进程。
```ini
[Unit]
Description=CC-Web
After=network.target
[Service]
Type=simple
User=your-user
WorkingDirectory=/path/to/cc-web
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=5
KillMode=process
[Install]
WantedBy=multi-user.target
```
## 开发约定
- 本项目代码理解优先使用 `codebase-memory-mcp`,项目名为 `home-cc-web`
- `graphify` 已弃用,不再作为主检索路径
- 涉及 Codex App 协议时优先对齐上游 app-server 参数形状
- 自定义跨会话能力走 `mcp_servers.ccweb`,不要优先回退到 dynamicTools
- 前端改动要同时考虑桌面端、移动端和深色主题
- 代码改动后至少运行 `npm run regression`
## 安全注意
- 不要用 root 用户部署
- 不要提交 `.env`、真实 API Key、真实通知 token、真实生产日志
- 内部 MCP token 不应暴露到前端或日志
- 图片附件会落盘到 `sessions/_attachments/`,默认 7 天过期
- 对公网开放时建议放到 HTTPS 反向代理后,并使用强密码
## 其他
本项目源自 cc-web并在实际使用中围绕 Codex App 与 ccweb MCP 做了重构和扩展。
感谢原项目作者、社区反馈和测试同学对这个工具方向的持续推动。