445 lines
16 KiB
Markdown
445 lines
16 KiB
Markdown
# CC-Web
|
||
|
||
Claude Code / Codex / Codex App 的 Web 远程协作工作台。
|
||
|
||

|
||

|
||
|
||
[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 22;root 用户可去掉 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 22;root 用户可去掉 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` 或 goals,ccweb 只能按运行时能力降级。
|
||
|
||
|
||
## 快速开始
|
||
|
||
### 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 做了重构和扩展。
|
||
|
||
感谢原项目作者、社区反馈和测试同学对这个工具方向的持续推动。
|