Skip to content

Commit 3cb1e50

Browse files
feat: 添加对 ACP 协议的支持 (#284)
* feat: 适配 zed acp 协议 * docs: 完善 acp 文档
1 parent cfab161 commit 3cb1e50

File tree

16 files changed

+4339
-2
lines changed

16 files changed

+4339
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
| 特性 | 说明 | 文档 |
1818
|------|------|------|
1919
| **Claude 群控技术** | Pipe IPC 多实例协作:同机 main/sub 自动编排 + LAN 跨机器零配置发现与通讯,`/pipes` 选择面板 + `Shift+↓` 交互 + 消息广播路由 | [Pipe IPC](https://ccb.agent-aura.top/docs/features/pipes-and-lan) / [LAN](https://ccb.agent-aura.top/docs/features/lan-pipes) |
20+
| ACP 协议一等一支持 | 支持接入 Zed、Cursor 等 IDE,支持会话恢复、Skills、权限桥接 | [文档](https://ccb.agent-aura.top/docs/features/acp-zed) |
2021
| Remote Control 私有部署 | Docker 自托管 RCS + Web UI | [文档](https://ccb.agent-aura.top/docs/features/remote-control-self-hosting) |
2122
| /dream 记忆整理 | 自动整理和优化记忆文件 | [文档](https://ccb.agent-aura.top/docs/features/auto-dream) |
2223
| Web Search | 内置网页搜索工具 | [文档](https://ccb.agent-aura.top/docs/features/web-browser-tool) |

build.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ const DEFAULT_BUILD_FEATURES = [
3030
'ULTRAPLAN',
3131
// P2: daemon + remote control server
3232
'DAEMON',
33+
// ACP (Agent Client Protocol) agent mode
34+
'ACP',
3335
// PR-package restored features
3436
'WORKFLOW_SCRIPTS',
3537
'HISTORY_SNIP',

bun.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/features/acp-zed.md

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
# ACP (Agent Client Protocol) — Zed / IDE 集成
2+
3+
> Feature Flag: `FEATURE_ACP=1`(build 和 dev 模式默认启用)
4+
> 实现状态:可用(支持 Zed、Cursor 等 ACP 客户端)
5+
> 源码目录:`src/services/acp/`
6+
7+
## 一、功能概述
8+
9+
ACP (Agent Client Protocol) 是一种标准化的 stdio 协议,允许 IDE 和编辑器通过 stdin/stdout 的 NDJSON 流驱动 AI Agent。CCB 实现了完整的 ACP agent 端,可以被 Zed、Cursor 等支持 ACP 的客户端直接调用。
10+
11+
### 核心特性
12+
13+
- **会话管理**:新建 / 恢复 / 加载 / 分叉 / 关闭会话
14+
- **历史回放**:恢复会话时自动加载并回放对话历史
15+
- **权限桥接**:ACP 客户端的权限决策映射到 CCB 的工具权限系统
16+
- **斜杠命令 & Skills**:加载真实命令列表,支持 `/commit``/review` 等 prompt 型 skill
17+
- **Context Window 跟踪**:精确的 usage_update,含 model prefix matching
18+
- **Prompt 排队**:支持连续发送多条 prompt,自动排队处理
19+
- **模式切换**:auto / default / acceptEdits / plan / dontAsk / bypassPermissions
20+
- **模型切换**:运行时切换 AI 模型
21+
22+
## 二、架构
23+
24+
```
25+
┌──────────────┐ NDJSON/stdio ┌──────────────────┐
26+
│ Zed / IDE │ ◄────────────────► │ CCB ACP Agent │
27+
│ (Client) │ stdin / stdout │ (Agent) │
28+
└──────────────┘ │ │
29+
│ entry.ts │ ← stdio → NDJSON stream
30+
│ agent.ts │ ← ACP protocol handler
31+
│ bridge.ts │ ← SDKMessage → ACP SessionUpdate
32+
│ permissions.ts │ ← 权限桥接
33+
│ utils.ts │ ← 通用工具
34+
│ │
35+
│ QueryEngine │ ← 内部查询引擎
36+
└──────────────────┘
37+
```
38+
39+
### 文件职责
40+
41+
| 文件 | 职责 |
42+
|------|------|
43+
| `entry.ts` | 入口,创建 stdio → NDJSON stream,启动 `AgentSideConnection` |
44+
| `agent.ts` | 实现 ACP `Agent` 接口:会话 CRUD、prompt、cancel、模式/模型切换 |
45+
| `bridge.ts` | `SDKMessage` → ACP `SessionUpdate` 转换:文本/思考/工具/用量/编辑 diff |
46+
| `permissions.ts` | ACP `requestPermission()` → CCB `CanUseToolFn` 桥接 |
47+
| `utils.ts` | Pushable、流转换、权限模式解析、session fingerprint、路径显示 |
48+
49+
## 三、配置 Zed 编辑器
50+
51+
### 3.1 Zed settings.json 配置
52+
53+
打开 Zed 的 `settings.json``Cmd+,` → Open Settings),添加 `agent_servers` 配置:
54+
55+
```json
56+
{
57+
"agent_servers": {
58+
"ccb": {
59+
"type": "custom",
60+
"command": "ccb",
61+
"args": ["--acp"]
62+
}
63+
}
64+
}
65+
```
66+
67+
### 3.3 API 认证配置
68+
69+
CCB 的 ACP agent 在启动时会自动加载 `settings.json` 中的环境变量(`ANTHROPIC_BASE_URL``ANTHROPIC_AUTH_TOKEN` 等)。确保已通过 `/login` 配置好 API 供应商。
70+
71+
也可通过环境变量传入:
72+
73+
```json
74+
{
75+
"agent_servers": {
76+
"claude-code": {
77+
"command": "ccb",
78+
"args": ["--acp"],
79+
"env": {
80+
"ANTHROPIC_BASE_URL": "https://api.example.com/v1",
81+
"ANTHROPIC_AUTH_TOKEN": "sk-xxx"
82+
}
83+
}
84+
}
85+
}
86+
```
87+
88+
### 3.4 在 Zed 中使用
89+
90+
1. 配置完成后重启 Zed
91+
2. 打开任意项目目录
92+
3.`Cmd+'`(macOS)或 `Ctrl+'`(Linux)打开 Agent Panel
93+
4. 在 Agent Panel 顶部的下拉菜单中选择 **claude-code**
94+
5. 开始对话
95+
96+
### 3.5 功能说明
97+
98+
| 功能 | 操作 |
99+
|------|------|
100+
| 对话 | 在 Agent Panel 中直接输入消息 |
101+
| 斜杠命令 | 输入 `/` 查看可用 skills 列表(如 `/commit``/review`|
102+
| 工具权限 | 弹出权限请求时选择 Allow / Reject / Always Allow |
103+
| 模式切换 | 通过 Agent Panel 的设置菜单切换 auto/default/plan 等模式 |
104+
| 模型切换 | 通过 Agent Panel 的设置菜单切换 AI 模型 |
105+
| 会话恢复 | 关闭重开 Zed 后,之前的会话可自动恢复(含历史消息) |
106+
107+
## 四、配置其他 ACP 客户端
108+
109+
ACP 是开放协议,任何支持 ACP 的客户端都可以连接 CCB。通用配置模式:
110+
111+
```
112+
命令: ccb --acp
113+
参数: ["--acp"]
114+
通信: stdin/stdout NDJSON
115+
协议版本: ACP v1
116+
```
117+
118+
### 4.1 Cursor
119+
120+
在 Cursor 的设置中配置 MCP / Agent Server,使用同样的 `ccb --acp` 命令。
121+
122+
### 4.2 自定义客户端
123+
124+
使用 `@agentclientprotocol/sdk` 可以快速构建 ACP 客户端:
125+
126+
```typescript
127+
import { ClientSideConnection, ndJsonStream } from '@agentclientprotocol/sdk'
128+
129+
// 创建连接(将 ccb --acp 作为子进程启动)
130+
const child = spawn('ccb', ['--acp'])
131+
const stream = ndJsonStream(
132+
Writable.toWeb(child.stdin),
133+
Readable.toWeb(child.stdout),
134+
)
135+
136+
const client = new ClientSideConnection(stream)
137+
138+
// 初始化
139+
await client.initialize({ clientCapabilities: {} })
140+
141+
// 创建会话
142+
const { sessionId } = await client.newSession({
143+
cwd: '/path/to/project',
144+
})
145+
146+
// 发送 prompt
147+
const response = await client.prompt({
148+
sessionId,
149+
prompt: [{ type: 'text', text: 'Hello, explain this project' }],
150+
})
151+
152+
// 监听 session 更新
153+
client.on('sessionUpdate', (update) => {
154+
console.log('Update:', update)
155+
})
156+
```
157+
158+
## 五、ACP 协议支持矩阵
159+
160+
| 方法 | 状态 | 说明 |
161+
|------|------|------|
162+
| `initialize` || 返回 agent 信息和能力 |
163+
| `authenticate` || 无需认证(自托管) |
164+
| `newSession` || 创建新会话 |
165+
| `resumeSession` || 恢复已有会话(含历史回放) |
166+
| `loadSession` || 加载指定会话(含历史回放) |
167+
| `listSessions` || 列出可用会话 |
168+
| `forkSession` || 分叉会话 |
169+
| `closeSession` || 关闭会话 |
170+
| `prompt` || 发送消息,支持排队 |
171+
| `cancel` || 取消当前/排队的 prompt |
172+
| `setSessionMode` || 切换权限模式 |
173+
| `setSessionModel` || 切换 AI 模型 |
174+
| `setSessionConfigOption` || 动态修改配置 |
175+
176+
### SessionUpdate 类型
177+
178+
| 类型 | 状态 | 说明 |
179+
|------|------|------|
180+
| `agent_message_chunk` || 助手文本消息 |
181+
| `agent_thought_chunk` || 思考/推理内容 |
182+
| `user_message_chunk` || 用户消息(历史回放) |
183+
| `tool_call` || 工具调用开始 |
184+
| `tool_call_update` || 工具调用结果/状态更新 |
185+
| `usage_update` || token 用量 + context window |
186+
| `plan` || TodoWrite → plan entries |
187+
| `available_commands_update` || 斜杠命令 & skills 列表 |
188+
| `current_mode_update` || 模式切换通知 |
189+
| `config_option_update` || 配置更新通知 |

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,9 @@
5959
"rcs": "bun run scripts/rcs.ts"
6060
},
6161
"dependencies": {
62-
"ws": "^8.20.0",
63-
"@claude-code-best/mcp-chrome-bridge": "^2.0.7"
62+
"@agentclientprotocol/sdk": "^0.19.0",
63+
"@claude-code-best/mcp-chrome-bridge": "^2.0.7",
64+
"ws": "^8.20.0"
6465
},
6566
"devDependencies": {
6667
"@alcalzone/ansi-tokenize": "^0.3.0",

scripts/dev.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ const DEFAULT_FEATURES = [
3737
"KAIROS_BRIEF", "AWAY_SUMMARY", "ULTRAPLAN",
3838
// P2: daemon + remote control server
3939
"DAEMON",
40+
// ACP (Agent Client Protocol) agent mode
41+
"ACP",
4042
// PR-package restored features
4143
"WORKFLOW_SCRIPTS",
4244
"HISTORY_SNIP",

src/QueryEngine.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,17 @@ export class QueryEngine {
11841184
this.abortController.abort()
11851185
}
11861186

1187+
/** Reset the abort controller so the next submitMessage() call can start
1188+
* with a fresh, non-aborted signal. Must be called after interrupt(). */
1189+
resetAbortController(): void {
1190+
this.abortController = createAbortController()
1191+
}
1192+
1193+
/** Expose the current abort signal for external consumers (e.g. ACP bridge). */
1194+
getAbortSignal(): AbortSignal {
1195+
return this.abortController.signal
1196+
}
1197+
11871198
getMessages(): readonly Message[] {
11881199
return this.mutableMessages
11891200
}

src/entrypoints/cli.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,14 @@ async function main(): Promise<void> {
132132
return
133133
}
134134

135+
// Fast-path for `--acp` — ACP (Agent Client Protocol) agent mode over stdio.
136+
if (feature('ACP') && process.argv[2] === '--acp') {
137+
profileCheckpoint('cli_acp_path')
138+
const { runAcpAgent } = await import('../services/acp/entry.js')
139+
await runAcpAgent()
140+
return
141+
}
142+
135143
// Fast-path for `--daemon-worker=<kind>` (internal — supervisor spawns this).
136144
// Must come before the daemon subcommand check: spawned per-worker, so
137145
// perf-sensitive. No enableConfigs(), no analytics sinks at this layer —

0 commit comments

Comments
 (0)