@harmonyos-arkts/opencode-acp 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/README.zh.md +6 -3
- package/dist/index.cjs +1207 -279
- package/dist/index.cjs.map +4 -4
- package/docs/codebase-overview.md +191 -0
- package/package.json +7 -4
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Harmony-ACP 代码详解
|
|
2
|
+
|
|
3
|
+
## 各文件详细介绍
|
|
4
|
+
|
|
5
|
+
### `src/index.ts` — 入口 (114 行)
|
|
6
|
+
|
|
7
|
+
程序入口,负责三件事:
|
|
8
|
+
|
|
9
|
+
1. **CLI 参数解析** (`parseArgs`):支持 `--server`、`--cwd`、`--log`、`--help`
|
|
10
|
+
2. **服务器连接**:通过 `@opencode-ai/sdk` 创建客户端,调用 `health()` 验证 OpenCode 服务可达
|
|
11
|
+
3. **ACP 连接建立**:将 stdin/stdout 包装为 `ReadableStream`/`WritableStream`,通过 `ndJsonStream` 创建 NDJSON 双向流,然后实例化 `AgentSideConnection` 启动 ACP 协议
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
### `src/agent.ts` — ACP Agent (934 行,最大文件)
|
|
16
|
+
|
|
17
|
+
实现 ACP 协议的 `Agent` 接口,是整个代理的核心业务逻辑。主要职责:
|
|
18
|
+
|
|
19
|
+
#### 协议生命周期
|
|
20
|
+
|
|
21
|
+
- `initialize()` — 声明能力(loadSession、MCP、fork、resume 等)
|
|
22
|
+
- `authenticate()` — 占位,未实现
|
|
23
|
+
|
|
24
|
+
#### 会话管理
|
|
25
|
+
|
|
26
|
+
- `newSession()` — 在 OpenCode 创建会话,加载模型和模式
|
|
27
|
+
- `loadSession()` — 加载已有会话,**回放历史消息**给客户端
|
|
28
|
+
- `listSessions()` — 分页列出会话
|
|
29
|
+
- `unstable_forkSession()` / `unstable_resumeSession()` — 分叉和恢复会话
|
|
30
|
+
|
|
31
|
+
#### 提示执行
|
|
32
|
+
|
|
33
|
+
- `prompt()` — 将客户端 prompt 转换为 OpenCode SDK 调用,支持普通 prompt 和 `/command` 格式
|
|
34
|
+
- `cancel()` — 中止正在进行的会话
|
|
35
|
+
|
|
36
|
+
#### 配置
|
|
37
|
+
|
|
38
|
+
- `setSessionMode()` / `unstable_setSessionModel()` / `setSessionConfigOption()` — 运行时切换模型和模式
|
|
39
|
+
|
|
40
|
+
#### 内部辅助方法
|
|
41
|
+
|
|
42
|
+
| 方法 | 职责 |
|
|
43
|
+
|------|------|
|
|
44
|
+
| `defaultModel()` | 多级模型发现:配置 → opencode config → providers → fallback `opencode/big-pickle` |
|
|
45
|
+
| `loadSessionMode()` | 加载可用模型列表,注册 MCP 服务器,推送 `available_commands_update` |
|
|
46
|
+
| `processMessage()` | 消息回放(文本、工具调用、文件、推理等) |
|
|
47
|
+
| `replayToolPart()` | 工具调用回放(completed/error 状态) |
|
|
48
|
+
| `convertPromptParts()` | ACP prompt 格式 → OpenCode parts 格式 |
|
|
49
|
+
| `parseUri()` | 解析 `file://` 和 `zed://` URI |
|
|
50
|
+
| `logMessageContent()` | prompt 完成后抓取完整消息内容记录日志 |
|
|
51
|
+
| `buildUsage()` | 从 `AssistantMessage.tokens` 构建 ACP Usage 对象 |
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### `src/session-manager.ts` — 会话管理器 (182 行)
|
|
56
|
+
|
|
57
|
+
增强版会话跟踪,核心区别在于**自动发现子会话**。
|
|
58
|
+
|
|
59
|
+
#### 数据结构
|
|
60
|
+
|
|
61
|
+
- `sessions: Map<string, SessionState>` — 所有会话(含子会话)
|
|
62
|
+
- `children: Map<string, Set<string>>` — 父→子的索引
|
|
63
|
+
|
|
64
|
+
#### 关键方法
|
|
65
|
+
|
|
66
|
+
| 方法 | 职责 |
|
|
67
|
+
|------|------|
|
|
68
|
+
| `create()` / `load()` | 注册顶层会话(由 agent 调用) |
|
|
69
|
+
| `registerDiscovered()` | **核心增强**:通过 SSE 事件自动注册子会话,继承父会话的 cwd/mcpServers/model |
|
|
70
|
+
| `findRootSession()` | 向上遍历 parentID 链找到根会话 |
|
|
71
|
+
| `getRelatedSessions()` | 递归获取子树所有会话 |
|
|
72
|
+
| `getChildren()` | 获取直接子会话 ID 列表 |
|
|
73
|
+
| `getModel/setModel` | 会话模型状态管理 |
|
|
74
|
+
| `getVariant/setVariant` | 会话变体管理 |
|
|
75
|
+
| `getMode/setMode` | 会话模式管理 |
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
### `src/event-handler.ts` — SSE 事件处理 (618 行)
|
|
80
|
+
|
|
81
|
+
订阅 OpenCode SSE 事件流,路由到 ACP 客户端。实现"独立虚拟会话"策略。
|
|
82
|
+
|
|
83
|
+
#### 核心状态
|
|
84
|
+
|
|
85
|
+
| 字段 | 用途 |
|
|
86
|
+
|------|------|
|
|
87
|
+
| `messageBuffers` | 累积 text/thought chunk,边界时刷新为完整日志 |
|
|
88
|
+
| `bashSnapshots` | bash 输出去重(用简单哈希避免重复推送) |
|
|
89
|
+
| `toolStarts` | 跟踪已发送 `tool_call` 开始事件的 callID |
|
|
90
|
+
| `permissionQueues` | 按 sessionID 串行化权限请求 |
|
|
91
|
+
| `questionQueues` | 按 sessionID 串行化问题请求 |
|
|
92
|
+
|
|
93
|
+
#### 事件处理
|
|
94
|
+
|
|
95
|
+
| 事件类型 | 处理逻辑 |
|
|
96
|
+
|----------|----------|
|
|
97
|
+
| `session.created` / `session.updated` | 自动发现子会话,通过 `announceChildSession()` 向客户端广播虚拟会话(带 `_meta.parentSessionId`) |
|
|
98
|
+
| `permission.asked` | 转发给 ACP 客户端请求权限,支持 edit 的 diff 应用(用 `diff` 库的 `applyPatch`) |
|
|
99
|
+
| `question.asked` | 通过 `extMethod("questionAsked")` 转发给客户端,60 秒超时 |
|
|
100
|
+
| `message.part.delta` | 实时推送 `agent_message_chunk` / `agent_thought_chunk`,同时累积到 buffer |
|
|
101
|
+
| `message.part.updated` | 处理工具调用状态转换:pending → running → completed/error |
|
|
102
|
+
|
|
103
|
+
#### 消息缓冲机制
|
|
104
|
+
|
|
105
|
+
- `accumulateDelta()` — 累积 delta 到 buffer
|
|
106
|
+
- `flushMessageBuffer()` — 在边界事件(tool_call、新消息、stop)时刷新为 `agent_message_complete` 日志
|
|
107
|
+
- `flushAllBuffers()` — 停止时刷新所有剩余 buffer
|
|
108
|
+
|
|
109
|
+
#### 辅助
|
|
110
|
+
|
|
111
|
+
- `sendToClient()` — `connection.sessionUpdate()` 的包装,在发送前记录日志并刷新 buffer
|
|
112
|
+
- `resolveSession()` — 根据 sessionId 查找已注册会话或其祖先
|
|
113
|
+
- `bashOutput()` — 从工具 metadata 中提取 bash 输出
|
|
114
|
+
- `simpleHash()` — 简单字符串哈希,用于 bash 输出去重
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
### `src/logger.ts` — 结构化日志 (139 行)
|
|
119
|
+
|
|
120
|
+
JSONL 格式日志系统,写入 `~/.harmony-acp/logs/`,每次启动一个文件。
|
|
121
|
+
|
|
122
|
+
#### 5 个分类 API
|
|
123
|
+
|
|
124
|
+
| 函数 | 分类 | 用途 |
|
|
125
|
+
|------|------|------|
|
|
126
|
+
| `acpIn()` | `acp.in` | 客户端请求(editor → harmony-acp) |
|
|
127
|
+
| `acpOut()` | `acp.out` | 返回客户端的响应(harmony-acp → editor) |
|
|
128
|
+
| `ocCall()` | `oc.call` | 调用 OpenCode 的请求(harmony-acp → opencode) |
|
|
129
|
+
| `ocEvent()` | `oc.event` | OpenCode 的事件(opencode → harmony-acp) |
|
|
130
|
+
| `sysLog()` | `system` | 生命周期事件 |
|
|
131
|
+
|
|
132
|
+
#### 特性
|
|
133
|
+
|
|
134
|
+
- `initLogger()` — 创建日志文件,自动清理超过 30 个的旧日志
|
|
135
|
+
- `setLogEnabled()` — 默认关闭,需 `--log` 启用
|
|
136
|
+
- `sanitize()` — 常规日志截断到 2K 字符
|
|
137
|
+
- `acpAssembled()` / `sanitizeAssembled()` — 组装消息保留到 10K 字符
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
### `src/types.ts` — 类型定义 (53 行)
|
|
142
|
+
|
|
143
|
+
定义核心接口:
|
|
144
|
+
|
|
145
|
+
| 接口 | 用途 |
|
|
146
|
+
|------|------|
|
|
147
|
+
| `SessionState` | 增强会话状态(含 parentID、title、model、modeId) |
|
|
148
|
+
| `ACPConfig` | 服务器配置(sdk、serverUrl、cwd、defaultModel) |
|
|
149
|
+
| `ModeOption` | 会话模式选项 |
|
|
150
|
+
| `ModelOption` | 模型选项 |
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
### `src/utils.ts` — 工具函数 (53 行)
|
|
155
|
+
|
|
156
|
+
两个纯函数:
|
|
157
|
+
|
|
158
|
+
| 函数 | 用途 |
|
|
159
|
+
|------|------|
|
|
160
|
+
| `toToolKind()` | OpenCode 工具名 → ACP ToolKind 映射(bash→execute, edit/write→edit, grep/glob→search 等) |
|
|
161
|
+
| `toLocations()` | 从工具输入元数据中提取文件路径位置信息 |
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 数据流总览
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
编辑器 Harmony-ACP OpenCode Server
|
|
169
|
+
│ │ │
|
|
170
|
+
│── JSON-RPC (stdio) ────→ │ │
|
|
171
|
+
│ initialize/newSession │ ── HTTP POST (session.create) ────→ │
|
|
172
|
+
│ │ ←── JSON response ───────────────── │
|
|
173
|
+
│ │ │
|
|
174
|
+
│ prompt │ ── HTTP POST (session.prompt) ────→ │
|
|
175
|
+
│ │ │
|
|
176
|
+
│ │ ←── SSE stream (events) ─────────── │
|
|
177
|
+
│ │ message.part.delta │
|
|
178
|
+
│ │ message.part.updated │
|
|
179
|
+
│ │ permission.asked │
|
|
180
|
+
│ │ question.asked │
|
|
181
|
+
│ │ session.created (子会话发现) │
|
|
182
|
+
│ │ │
|
|
183
|
+
│←── sessionUpdate ─────── │ │
|
|
184
|
+
│ agent_message_chunk │ │
|
|
185
|
+
│ tool_call / update │ │
|
|
186
|
+
│ session_info_update │ │
|
|
187
|
+
│ usage_update │ │
|
|
188
|
+
│ │ │
|
|
189
|
+
│── requestPermission ──→ │ ── HTTP POST (permission.reply) ──→ │
|
|
190
|
+
│── extMethod(question) → │ ── HTTP POST (question.reply) ────→ │
|
|
191
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@harmonyos-arkts/opencode-acp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Enhanced ACP (Agent Client Protocol) server for OpenCode with subagent visibility",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -18,19 +18,22 @@
|
|
|
18
18
|
"build": "node scripts/build.mjs",
|
|
19
19
|
"typecheck": "tsc --noEmit",
|
|
20
20
|
"dev": "node --watch src/index.ts",
|
|
21
|
-
"test": "
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"test:watch": "vitest",
|
|
22
23
|
"test:integration": "node scripts/test-integration.mjs",
|
|
23
24
|
"logs": "node scripts/view-log.mjs",
|
|
24
25
|
"logs:filter": "node scripts/view-log.mjs --filter"
|
|
25
26
|
},
|
|
26
27
|
"dependencies": {
|
|
27
28
|
"@agentclientprotocol/sdk": "^0.16.1",
|
|
28
|
-
"@opencode-ai/sdk": "latest"
|
|
29
|
+
"@opencode-ai/sdk": "latest",
|
|
30
|
+
"diff": "^9.0.0"
|
|
29
31
|
},
|
|
30
32
|
"devDependencies": {
|
|
31
33
|
"@types/node": "^22.19.17",
|
|
32
34
|
"esbuild": "^0.25.0",
|
|
33
|
-
"typescript": "^5.7.0"
|
|
35
|
+
"typescript": "^5.7.0",
|
|
36
|
+
"vitest": "^4.1.5"
|
|
34
37
|
},
|
|
35
38
|
"engines": {
|
|
36
39
|
"node": ">=18.0.0"
|