@harmonyos-arkts/opencode-acp 0.0.3 → 0.0.4
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/CHANGELOG.md +22 -0
- package/README.md +10 -10
- package/dist/index.cjs +239 -199
- package/dist/index.cjs.map +4 -4
- package/docs/mcp-extmethod-design.md +92 -76
- package/docs/provider-config-flow.md +35 -35
- package/docs/session-stats-to-vscode-design.md +18 -16
- package/package.json +2 -1
|
@@ -27,15 +27,15 @@ ACP Client (Editor) ← stdio/JSON-RPC → Harmony-ACP ← HTTP/SSE → OpenCode
|
|
|
27
27
|
|
|
28
28
|
## 暴露的 MCP 操作
|
|
29
29
|
|
|
30
|
-
| extMethod 名
|
|
31
|
-
|
|
32
|
-
| `mcp/status`
|
|
33
|
-
| `mcp/add`
|
|
34
|
-
| `mcp/connect`
|
|
35
|
-
| `mcp/disconnect`
|
|
36
|
-
| `mcp/auth/start`
|
|
37
|
-
| `mcp/auth/callback` | `sdk.mcp.auth.callback()` | 完成 OAuth 认证
|
|
38
|
-
| `mcp/auth/remove`
|
|
30
|
+
| extMethod 名 | 对应 SDK 调用 | 说明 |
|
|
31
|
+
| ------------------- | ------------------------- | ----------------------- |
|
|
32
|
+
| `mcp/status` | `sdk.mcp.status()` | 获取所有 MCP 服务器状态 |
|
|
33
|
+
| `mcp/add` | `sdk.mcp.add()` | 添加 MCP 服务器 |
|
|
34
|
+
| `mcp/connect` | `sdk.mcp.connect()` | 连接已禁用的服务器 |
|
|
35
|
+
| `mcp/disconnect` | `sdk.mcp.disconnect()` | 断开服务器 |
|
|
36
|
+
| `mcp/auth/start` | `sdk.mcp.auth.start()` | 启动 OAuth 认证 |
|
|
37
|
+
| `mcp/auth/callback` | `sdk.mcp.auth.callback()` | 完成 OAuth 认证 |
|
|
38
|
+
| `mcp/auth/remove` | `sdk.mcp.auth.remove()` | 删除 OAuth 凭据 |
|
|
39
39
|
|
|
40
40
|
### 各操作详细签名
|
|
41
41
|
|
|
@@ -44,13 +44,15 @@ ACP Client (Editor) ← stdio/JSON-RPC → Harmony-ACP ← HTTP/SSE → OpenCode
|
|
|
44
44
|
获取所有已配置 MCP 服务器的连接状态。
|
|
45
45
|
|
|
46
46
|
**请求参数:**
|
|
47
|
+
|
|
47
48
|
```typescript
|
|
48
49
|
{
|
|
49
|
-
sessionId: string
|
|
50
|
+
sessionId: string; // 用于获取 cwd
|
|
50
51
|
}
|
|
51
52
|
```
|
|
52
53
|
|
|
53
54
|
**响应:**
|
|
55
|
+
|
|
54
56
|
```typescript
|
|
55
57
|
{
|
|
56
58
|
[serverName: string]: {
|
|
@@ -65,6 +67,7 @@ ACP Client (Editor) ← stdio/JSON-RPC → Harmony-ACP ← HTTP/SSE → OpenCode
|
|
|
65
67
|
动态添加 MCP 服务器。
|
|
66
68
|
|
|
67
69
|
**请求参数:**
|
|
70
|
+
|
|
68
71
|
```typescript
|
|
69
72
|
{
|
|
70
73
|
sessionId: string
|
|
@@ -89,6 +92,7 @@ ACP Client (Editor) ← stdio/JSON-RPC → Harmony-ACP ← HTTP/SSE → OpenCode
|
|
|
89
92
|
```
|
|
90
93
|
|
|
91
94
|
**响应:**
|
|
95
|
+
|
|
92
96
|
```typescript
|
|
93
97
|
{
|
|
94
98
|
[serverName: string]: McpStatus // 添加后所有服务器状态
|
|
@@ -100,17 +104,19 @@ ACP Client (Editor) ← stdio/JSON-RPC → Harmony-ACP ← HTTP/SSE → OpenCode
|
|
|
100
104
|
连接一个已禁用/断开的 MCP 服务器。
|
|
101
105
|
|
|
102
106
|
**请求参数:**
|
|
107
|
+
|
|
103
108
|
```typescript
|
|
104
109
|
{
|
|
105
|
-
sessionId: string
|
|
106
|
-
name: string
|
|
110
|
+
sessionId: string;
|
|
111
|
+
name: string;
|
|
107
112
|
}
|
|
108
113
|
```
|
|
109
114
|
|
|
110
115
|
**响应:**
|
|
116
|
+
|
|
111
117
|
```typescript
|
|
112
118
|
{
|
|
113
|
-
success: true
|
|
119
|
+
success: true;
|
|
114
120
|
}
|
|
115
121
|
```
|
|
116
122
|
|
|
@@ -119,17 +125,19 @@ ACP Client (Editor) ← stdio/JSON-RPC → Harmony-ACP ← HTTP/SSE → OpenCode
|
|
|
119
125
|
断开一个 MCP 服务器。
|
|
120
126
|
|
|
121
127
|
**请求参数:**
|
|
128
|
+
|
|
122
129
|
```typescript
|
|
123
130
|
{
|
|
124
|
-
sessionId: string
|
|
125
|
-
name: string
|
|
131
|
+
sessionId: string;
|
|
132
|
+
name: string;
|
|
126
133
|
}
|
|
127
134
|
```
|
|
128
135
|
|
|
129
136
|
**响应:**
|
|
137
|
+
|
|
130
138
|
```typescript
|
|
131
139
|
{
|
|
132
|
-
success: true
|
|
140
|
+
success: true;
|
|
133
141
|
}
|
|
134
142
|
```
|
|
135
143
|
|
|
@@ -138,18 +146,20 @@ ACP Client (Editor) ← stdio/JSON-RPC → Harmony-ACP ← HTTP/SSE → OpenCode
|
|
|
138
146
|
启动 OAuth 认证流程,返回授权 URL。
|
|
139
147
|
|
|
140
148
|
**请求参数:**
|
|
149
|
+
|
|
141
150
|
```typescript
|
|
142
151
|
{
|
|
143
|
-
sessionId: string
|
|
144
|
-
name: string
|
|
152
|
+
sessionId: string;
|
|
153
|
+
name: string;
|
|
145
154
|
}
|
|
146
155
|
```
|
|
147
156
|
|
|
148
157
|
**响应:**
|
|
158
|
+
|
|
149
159
|
```typescript
|
|
150
160
|
{
|
|
151
|
-
authorizationUrl: string
|
|
152
|
-
oauthState: string
|
|
161
|
+
authorizationUrl: string;
|
|
162
|
+
oauthState: string;
|
|
153
163
|
}
|
|
154
164
|
```
|
|
155
165
|
|
|
@@ -160,17 +170,19 @@ ACP Client (Editor) ← stdio/JSON-RPC → Harmony-ACP ← HTTP/SSE → OpenCode
|
|
|
160
170
|
用授权码完成 OAuth 认证。
|
|
161
171
|
|
|
162
172
|
**请求参数:**
|
|
173
|
+
|
|
163
174
|
```typescript
|
|
164
175
|
{
|
|
165
|
-
sessionId: string
|
|
166
|
-
name: string
|
|
167
|
-
code: string
|
|
176
|
+
sessionId: string;
|
|
177
|
+
name: string;
|
|
178
|
+
code: string; // OAuth 授权码
|
|
168
179
|
}
|
|
169
180
|
```
|
|
170
181
|
|
|
171
182
|
**响应:**
|
|
183
|
+
|
|
172
184
|
```typescript
|
|
173
|
-
McpStatus
|
|
185
|
+
McpStatus; // 认证后的服务器状态
|
|
174
186
|
```
|
|
175
187
|
|
|
176
188
|
#### `mcp/auth/remove`
|
|
@@ -178,17 +190,19 @@ McpStatus // 认证后的服务器状态
|
|
|
178
190
|
删除 MCP 服务器的 OAuth 凭据。
|
|
179
191
|
|
|
180
192
|
**请求参数:**
|
|
193
|
+
|
|
181
194
|
```typescript
|
|
182
195
|
{
|
|
183
|
-
sessionId: string
|
|
184
|
-
name: string
|
|
196
|
+
sessionId: string;
|
|
197
|
+
name: string;
|
|
185
198
|
}
|
|
186
199
|
```
|
|
187
200
|
|
|
188
201
|
**响应:**
|
|
202
|
+
|
|
189
203
|
```typescript
|
|
190
204
|
{
|
|
191
|
-
success: true
|
|
205
|
+
success: true;
|
|
192
206
|
}
|
|
193
207
|
```
|
|
194
208
|
|
|
@@ -202,52 +216,52 @@ McpStatus // 认证后的服务器状态
|
|
|
202
216
|
|
|
203
217
|
```typescript
|
|
204
218
|
// src/mcp-manager.ts
|
|
205
|
-
import type { OpencodeClient } from "@opencode-ai/sdk/v2"
|
|
206
|
-
import { ocCall } from "./logger.js"
|
|
219
|
+
import type { OpencodeClient } from "@opencode-ai/sdk/v2";
|
|
220
|
+
import { ocCall } from "./logger.js";
|
|
207
221
|
|
|
208
222
|
export class McpManager {
|
|
209
223
|
constructor(private sdk: OpencodeClient) {}
|
|
210
224
|
|
|
211
225
|
async status(directory: string) {
|
|
212
|
-
ocCall("mcp.status", { directory })
|
|
213
|
-
const result = await this.sdk.mcp.status({ directory })
|
|
214
|
-
return result.data ?? {}
|
|
226
|
+
ocCall("mcp.status", { directory });
|
|
227
|
+
const result = await this.sdk.mcp.status({ directory });
|
|
228
|
+
return result.data ?? {};
|
|
215
229
|
}
|
|
216
230
|
|
|
217
231
|
async add(directory: string, name: string, config: any) {
|
|
218
|
-
ocCall("mcp.add", { directory, name })
|
|
219
|
-
const result = await this.sdk.mcp.add({ directory, name, config })
|
|
220
|
-
return result.data ?? {}
|
|
232
|
+
ocCall("mcp.add", { directory, name });
|
|
233
|
+
const result = await this.sdk.mcp.add({ directory, name, config });
|
|
234
|
+
return result.data ?? {};
|
|
221
235
|
}
|
|
222
236
|
|
|
223
237
|
async connect(directory: string, name: string) {
|
|
224
|
-
ocCall("mcp.connect", { directory, name })
|
|
225
|
-
await this.sdk.mcp.connect({ directory, name })
|
|
226
|
-
return { success: true }
|
|
238
|
+
ocCall("mcp.connect", { directory, name });
|
|
239
|
+
await this.sdk.mcp.connect({ directory, name });
|
|
240
|
+
return { success: true };
|
|
227
241
|
}
|
|
228
242
|
|
|
229
243
|
async disconnect(directory: string, name: string) {
|
|
230
|
-
ocCall("mcp.disconnect", { directory, name })
|
|
231
|
-
await this.sdk.mcp.disconnect({ directory, name })
|
|
232
|
-
return { success: true }
|
|
244
|
+
ocCall("mcp.disconnect", { directory, name });
|
|
245
|
+
await this.sdk.mcp.disconnect({ directory, name });
|
|
246
|
+
return { success: true };
|
|
233
247
|
}
|
|
234
248
|
|
|
235
249
|
async startAuth(directory: string, name: string) {
|
|
236
|
-
ocCall("mcp.auth.start", { directory, name })
|
|
237
|
-
const result = await this.sdk.mcp.auth.start({ directory, name })
|
|
238
|
-
return result.data
|
|
250
|
+
ocCall("mcp.auth.start", { directory, name });
|
|
251
|
+
const result = await this.sdk.mcp.auth.start({ directory, name });
|
|
252
|
+
return result.data;
|
|
239
253
|
}
|
|
240
254
|
|
|
241
255
|
async callbackAuth(directory: string, name: string, code: string) {
|
|
242
|
-
ocCall("mcp.auth.callback", { directory, name })
|
|
243
|
-
const result = await this.sdk.mcp.auth.callback({ directory, name, code })
|
|
244
|
-
return result.data
|
|
256
|
+
ocCall("mcp.auth.callback", { directory, name });
|
|
257
|
+
const result = await this.sdk.mcp.auth.callback({ directory, name, code });
|
|
258
|
+
return result.data;
|
|
245
259
|
}
|
|
246
260
|
|
|
247
261
|
async removeAuth(directory: string, name: string) {
|
|
248
|
-
ocCall("mcp.auth.remove", { directory, name })
|
|
249
|
-
await this.sdk.mcp.auth.remove({ directory, name })
|
|
250
|
-
return { success: true }
|
|
262
|
+
ocCall("mcp.auth.remove", { directory, name });
|
|
263
|
+
await this.sdk.mcp.auth.remove({ directory, name });
|
|
264
|
+
return { success: true };
|
|
251
265
|
}
|
|
252
266
|
}
|
|
253
267
|
```
|
|
@@ -259,45 +273,47 @@ export class McpManager {
|
|
|
259
273
|
```typescript
|
|
260
274
|
// agent.ts 中添加
|
|
261
275
|
|
|
262
|
-
import { McpManager } from "./mcp-manager.js"
|
|
276
|
+
import { McpManager } from "./mcp-manager.js";
|
|
263
277
|
|
|
264
278
|
export class Agent implements ACPAgent {
|
|
265
|
-
private mcpManager: McpManager
|
|
279
|
+
private mcpManager: McpManager;
|
|
266
280
|
|
|
267
281
|
constructor(config: ACPConfig) {
|
|
268
282
|
// ...
|
|
269
|
-
this.mcpManager = new McpManager(config.sdk)
|
|
283
|
+
this.mcpManager = new McpManager(config.sdk);
|
|
270
284
|
}
|
|
271
285
|
|
|
272
286
|
async extMethod(method: string, params: Record<string, unknown>): Promise<Record<string, unknown>> {
|
|
273
287
|
if (method.startsWith("mcp/")) {
|
|
274
|
-
return this.handleMcpMethod(method, params)
|
|
288
|
+
return this.handleMcpMethod(method, params);
|
|
275
289
|
}
|
|
276
|
-
throw new Error(`Unknown extMethod: ${method}`)
|
|
290
|
+
throw new Error(`Unknown extMethod: ${method}`);
|
|
277
291
|
}
|
|
278
292
|
|
|
279
293
|
private async handleMcpMethod(method: string, params: Record<string, unknown>) {
|
|
280
|
-
const sessionId = params.sessionId as string
|
|
281
|
-
const session = this.sessionManager.get(sessionId)
|
|
282
|
-
const directory = session.cwd
|
|
294
|
+
const sessionId = params.sessionId as string;
|
|
295
|
+
const session = this.sessionManager.get(sessionId);
|
|
296
|
+
const directory = session.cwd;
|
|
283
297
|
|
|
284
298
|
switch (method) {
|
|
285
299
|
case "mcp/status":
|
|
286
|
-
return this.mcpManager.status(directory) as Promise<Record<string, unknown
|
|
300
|
+
return this.mcpManager.status(directory) as Promise<Record<string, unknown>>;
|
|
287
301
|
case "mcp/add":
|
|
288
|
-
return this.mcpManager.add(directory, params.name as string, params.config) as Promise<Record<string, unknown
|
|
302
|
+
return this.mcpManager.add(directory, params.name as string, params.config) as Promise<Record<string, unknown>>;
|
|
289
303
|
case "mcp/connect":
|
|
290
|
-
return this.mcpManager.connect(directory, params.name as string)
|
|
304
|
+
return this.mcpManager.connect(directory, params.name as string);
|
|
291
305
|
case "mcp/disconnect":
|
|
292
|
-
return this.mcpManager.disconnect(directory, params.name as string)
|
|
306
|
+
return this.mcpManager.disconnect(directory, params.name as string);
|
|
293
307
|
case "mcp/auth/start":
|
|
294
|
-
return this.mcpManager.startAuth(directory, params.name as string) as Promise<Record<string, unknown
|
|
308
|
+
return this.mcpManager.startAuth(directory, params.name as string) as Promise<Record<string, unknown>>;
|
|
295
309
|
case "mcp/auth/callback":
|
|
296
|
-
return this.mcpManager.callbackAuth(directory, params.name as string, params.code as string) as Promise<
|
|
310
|
+
return this.mcpManager.callbackAuth(directory, params.name as string, params.code as string) as Promise<
|
|
311
|
+
Record<string, unknown>
|
|
312
|
+
>;
|
|
297
313
|
case "mcp/auth/remove":
|
|
298
|
-
return this.mcpManager.removeAuth(directory, params.name as string)
|
|
314
|
+
return this.mcpManager.removeAuth(directory, params.name as string);
|
|
299
315
|
default:
|
|
300
|
-
throw new Error(`Unknown MCP method: ${method}`)
|
|
316
|
+
throw new Error(`Unknown MCP method: ${method}`);
|
|
301
317
|
}
|
|
302
318
|
}
|
|
303
319
|
}
|
|
@@ -342,16 +358,16 @@ mcp: {
|
|
|
342
358
|
|
|
343
359
|
## 关键文件清单
|
|
344
360
|
|
|
345
|
-
| 文件
|
|
346
|
-
|
|
347
|
-
| `src/mcp-manager.ts`
|
|
348
|
-
| `src/agent.ts`
|
|
349
|
-
| `src/types.ts`
|
|
350
|
-
| `src/__tests__/mcp-manager.test.ts` | **新建** | McpManager 单元测试
|
|
351
|
-
| `src/__tests__/agent.test.ts`
|
|
352
|
-
| `src/__tests__/helpers/mock-sdk.ts` | **修改** | 补全 MCP mock 方法
|
|
353
|
-
| `README.md`
|
|
354
|
-
| `CHANGELOG.md`
|
|
361
|
+
| 文件 | 操作 | 说明 |
|
|
362
|
+
| ----------------------------------- | -------- | ------------------------------------------------------- |
|
|
363
|
+
| `src/mcp-manager.ts` | **新建** | MCP 操作封装,代理 SDK 调用 |
|
|
364
|
+
| `src/agent.ts` | **修改** | 添加 extMethod 路由、集成 McpManager、迁移 MCP 注册逻辑 |
|
|
365
|
+
| `src/types.ts` | **修改** | 添加 MCP 相关类型(可选) |
|
|
366
|
+
| `src/__tests__/mcp-manager.test.ts` | **新建** | McpManager 单元测试 |
|
|
367
|
+
| `src/__tests__/agent.test.ts` | **修改** | 添加 extMethod 测试 |
|
|
368
|
+
| `src/__tests__/helpers/mock-sdk.ts` | **修改** | 补全 MCP mock 方法 |
|
|
369
|
+
| `README.md` | **修改** | 文档更新 |
|
|
370
|
+
| `CHANGELOG.md` | **修改** | 记录变更 |
|
|
355
371
|
|
|
356
372
|
## 复用
|
|
357
373
|
|
|
@@ -4,20 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
OpenCode 有两个层面的 provider 数据:
|
|
6
6
|
|
|
7
|
-
| 数据源
|
|
8
|
-
|
|
9
|
-
| **数据库全量** | `GET /provider`
|
|
10
|
-
| **运行时可用** | `GET /config/providers` | 有凭证或 autoload 的 provider + 模型列表 | 模型选择下拉框
|
|
7
|
+
| 数据源 | 接口 | 内容 | 用途 |
|
|
8
|
+
| -------------- | ----------------------- | ---------------------------------------- | ------------------------ |
|
|
9
|
+
| **数据库全量** | `GET /provider` | models.dev 中的所有 provider(70+) | 发现哪些 provider 可配置 |
|
|
10
|
+
| **运行时可用** | `GET /config/providers` | 有凭证或 autoload 的 provider + 模型列表 | 模型选择下拉框 |
|
|
11
11
|
|
|
12
12
|
**关键**:`GET /config/providers` 返回的不是"有 API Key 的 provider",而是 `s.providers` 这个内部状态。进入 `s.providers` 的条件(`provider/provider.ts:1076-1285`):
|
|
13
13
|
|
|
14
|
-
| 条件
|
|
15
|
-
|
|
16
|
-
| 配置文件声明了 provider
|
|
17
|
-
| 环境变量有 key
|
|
18
|
-
| auth.json 有 key
|
|
19
|
-
| Plugin auth loader
|
|
20
|
-
| **Custom loader autoload** | 1258 行
|
|
14
|
+
| 条件 | 代码位置 | 说明 |
|
|
15
|
+
| -------------------------- | -------- | ----------------------------------------- |
|
|
16
|
+
| 配置文件声明了 provider | 1124 行 | `opencode.json` 中 `provider.<id>` 有配置 |
|
|
17
|
+
| 环境变量有 key | 1211 行 | 如 `ANTHROPIC_API_KEY=xxx` |
|
|
18
|
+
| auth.json 有 key | 1224 行 | 通过 `PUT /auth/:providerID` 存入的 |
|
|
19
|
+
| Plugin auth loader | 1237 行 | Plugin 提供的认证加载器 |
|
|
20
|
+
| **Custom loader autoload** | 1258 行 | **`opencode` provider 始终 autoload** |
|
|
21
21
|
|
|
22
22
|
### `opencode` Provider 的特殊性
|
|
23
23
|
|
|
@@ -28,14 +28,14 @@ OpenCode 有两个层面的 provider 数据:
|
|
|
28
28
|
if (!ok) {
|
|
29
29
|
// 删除付费模型,保留免费模型(cost.input === 0)
|
|
30
30
|
for (const [key, value] of Object.entries(input.models)) {
|
|
31
|
-
if (value.cost.input === 0) continue
|
|
32
|
-
delete input.models[key]
|
|
31
|
+
if (value.cost.input === 0) continue;
|
|
32
|
+
delete input.models[key];
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
return {
|
|
36
|
-
autoload: Object.keys(input.models).length > 0,
|
|
37
|
-
options: ok ? {} : { apiKey: "public" },
|
|
38
|
-
}
|
|
36
|
+
autoload: Object.keys(input.models).length > 0, // 有免费模型就 autoload
|
|
37
|
+
options: ok ? {} : { apiKey: "public" }, // 无 key 用 "public"
|
|
38
|
+
};
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
**这意味着**:即使零配置,`GET /config/providers` 也会返回 `opencode` provider,包含所有免费模型(如 `glm-4.6`、`big-pickle` 等)。TUI 的 `/models` 能看到 GLM 模型就是这个原因。
|
|
@@ -258,36 +258,36 @@ VSCode harmony-acp OpenCode Server
|
|
|
258
258
|
|
|
259
259
|
### 控制面路由(`routes/control/index.ts`)
|
|
260
260
|
|
|
261
|
-
| 方法
|
|
262
|
-
|
|
263
|
-
| `PUT`
|
|
264
|
-
| `DELETE` | `/auth/:providerID` | 移除凭证
|
|
261
|
+
| 方法 | 路径 | 用途 |
|
|
262
|
+
| -------- | ------------------- | ----------------------------------------------- |
|
|
263
|
+
| `PUT` | `/auth/:providerID` | 设置 API Key,写入 `~/.opencode/data/auth.json` |
|
|
264
|
+
| `DELETE` | `/auth/:providerID` | 移除凭证 |
|
|
265
265
|
|
|
266
266
|
### 实例面路由(`routes/instance/provider.ts`)
|
|
267
267
|
|
|
268
|
-
| 方法
|
|
269
|
-
|
|
270
|
-
| `GET`
|
|
271
|
-
| `GET`
|
|
268
|
+
| 方法 | 路径 | 用途 |
|
|
269
|
+
| ------ | ------------------------------ | ----------------------------------------------------- |
|
|
270
|
+
| `GET` | `/provider` | 返回全量 provider 列表 + connected 状态 |
|
|
271
|
+
| `GET` | `/provider/auth` | 返回每个 provider 的认证方式(API Key / OAuth) |
|
|
272
272
|
| `POST` | `/:providerID/oauth/authorize` | OAuth 授权(仅 Plugin 注册了 OAuth hook 的 provider) |
|
|
273
|
-
| `POST` | `/:providerID/oauth/callback`
|
|
273
|
+
| `POST` | `/:providerID/oauth/callback` | OAuth 回调 |
|
|
274
274
|
|
|
275
275
|
### 实例面路由(`routes/instance/config.ts`)
|
|
276
276
|
|
|
277
|
-
| 方法
|
|
278
|
-
|
|
277
|
+
| 方法 | 路径 | 用途 |
|
|
278
|
+
| ----- | ------------------- | -------------------------------------------------------------- |
|
|
279
279
|
| `GET` | `/config/providers` | 返回 `s.providers`(有凭证或 autoload 的 provider + 模型列表) |
|
|
280
280
|
|
|
281
281
|
## 两个 Provider 接口的区别
|
|
282
282
|
|
|
283
|
-
|
|
|
284
|
-
|
|
285
|
-
| 数据源
|
|
286
|
-
| 返回范围
|
|
287
|
-
| 用途
|
|
288
|
-
| 返回格式
|
|
289
|
-
| ACP extMethod | `provider/list`
|
|
290
|
-
| TUI 使用
|
|
283
|
+
| | `GET /provider` | `GET /config/providers` |
|
|
284
|
+
| ------------- | -------------------------------------- | ----------------------------------------- |
|
|
285
|
+
| 数据源 | models.dev 全量数据库 + connected 状态 | `s.providers` 内部状态(有凭证/autoload) |
|
|
286
|
+
| 返回范围 | **所有** provider(70+) | 仅"可用"的 provider |
|
|
287
|
+
| 用途 | 发现可配置的 provider、展示配置入口 | 模型选择下拉框的数据源 |
|
|
288
|
+
| 返回格式 | `{ all, default, connected }` | `{ providers, default }` |
|
|
289
|
+
| ACP extMethod | `provider/list` | 无(harmony-acp 内部调用) |
|
|
290
|
+
| TUI 使用 | `store.provider_next` | `store.provider`(`/models` 下拉框) |
|
|
291
291
|
|
|
292
292
|
## API Key 有效性判定
|
|
293
293
|
|
|
@@ -24,6 +24,7 @@ OpenCode session 表已持久化 `summary_additions`/`summary_deletions`/`summar
|
|
|
24
24
|
5. **文件级 diff 已有通道** — edit tool 的 tool_call_update 已返回 diff,无需重复传输
|
|
25
25
|
|
|
26
26
|
**数据格式:**
|
|
27
|
+
|
|
27
28
|
```typescript
|
|
28
29
|
usage_update._meta.codeChange = {
|
|
29
30
|
additions: number
|
|
@@ -84,9 +85,9 @@ usage_update._meta.codeChange = {
|
|
|
84
85
|
|
|
85
86
|
```typescript
|
|
86
87
|
export interface CodeChangeStats {
|
|
87
|
-
additions: number
|
|
88
|
-
deletions: number
|
|
89
|
-
files: number
|
|
88
|
+
additions: number;
|
|
89
|
+
deletions: number;
|
|
90
|
+
files: number;
|
|
90
91
|
}
|
|
91
92
|
```
|
|
92
93
|
|
|
@@ -113,6 +114,7 @@ case "session.diff": {
|
|
|
113
114
|
```
|
|
114
115
|
|
|
115
116
|
新增实例变量和方法:
|
|
117
|
+
|
|
116
118
|
- `diffStats: Map<string, CodeChangeStats>` — 存储 session 级 diff 聚合
|
|
117
119
|
- `getDiffStats(sessionId)` — 供 agent.ts 读取
|
|
118
120
|
- `setDiffStats(sessionId, stats)` — 供 agent.ts 回填历史数据
|
|
@@ -166,13 +168,13 @@ _meta: {
|
|
|
166
168
|
从返回数据中提取 summary,存入 EventHandler 的 `diffStats` map:
|
|
167
169
|
|
|
168
170
|
```typescript
|
|
169
|
-
const session = await this.sdk.session.get({ sessionID, directory })
|
|
171
|
+
const session = await this.sdk.session.get({ sessionID, directory });
|
|
170
172
|
if (session.data?.summary) {
|
|
171
173
|
this.eventHandler.setDiffStats(sessionID, {
|
|
172
174
|
additions: session.data.summary.additions,
|
|
173
175
|
deletions: session.data.summary.deletions,
|
|
174
176
|
files: session.data.summary.files,
|
|
175
|
-
})
|
|
177
|
+
});
|
|
176
178
|
}
|
|
177
179
|
```
|
|
178
180
|
|
|
@@ -188,22 +190,22 @@ if (session.data?.summary) {
|
|
|
188
190
|
|
|
189
191
|
## 涉及文件
|
|
190
192
|
|
|
191
|
-
| 文件
|
|
192
|
-
|
|
193
|
-
| `src/types.ts`
|
|
194
|
-
| `src/event-handler.ts` | 新增 `session.diff` 事件处理 + `diffStats` map + get/set/clear 方法
|
|
195
|
-
| `src/agent.ts`
|
|
193
|
+
| 文件 | 修改内容 |
|
|
194
|
+
| ---------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
195
|
+
| `src/types.ts` | 新增 `CodeChangeStats` 接口 |
|
|
196
|
+
| `src/event-handler.ts` | 新增 `session.diff` 事件处理 + `diffStats` map + get/set/clear 方法 |
|
|
197
|
+
| `src/agent.ts` | `sendUsageUpdate()` 附加 `_meta.codeChange`;`loadSession()`/`resumeSession()` 读取 `session.summary` |
|
|
196
198
|
|
|
197
199
|
---
|
|
198
200
|
|
|
199
201
|
## 依赖的 OpenCode 现有能力
|
|
200
202
|
|
|
201
|
-
| 能力
|
|
202
|
-
|
|
203
|
-
| `session.diff` SSE 事件 | OpenCode SDK `EventSessionDiff` | session 代码变更时实时推送 `SnapshotFileDiff[]`
|
|
204
|
-
| `Session.summary` 字段
|
|
205
|
-
| `UsageUpdate._meta`
|
|
206
|
-
| 已有 `_meta` 扩展模式
|
|
203
|
+
| 能力 | 来源 | 说明 |
|
|
204
|
+
| ----------------------- | ------------------------------- | --------------------------------------------------- |
|
|
205
|
+
| `session.diff` SSE 事件 | OpenCode SDK `EventSessionDiff` | session 代码变更时实时推送 `SnapshotFileDiff[]` |
|
|
206
|
+
| `Session.summary` 字段 | OpenCode SDK `Session` 类型 | 含 `additions`/`deletions`/`files`/`diffs` |
|
|
207
|
+
| `UsageUpdate._meta` | ACP 协议 | `{ [key: string]: unknown }` 扩展字段 |
|
|
208
|
+
| 已有 `_meta` 扩展模式 | harmony-acp `sendUsageUpdate()` | 已传递 `parentCost`/`childCost`/`childSessionCount` |
|
|
207
209
|
|
|
208
210
|
---
|
|
209
211
|
|
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.4",
|
|
4
4
|
"description": "Enhanced ACP (Agent Client Protocol) server for OpenCode with subagent visibility",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"test": "vitest run",
|
|
24
24
|
"test:watch": "vitest",
|
|
25
25
|
"test:integration": "node scripts/test-integration.mjs",
|
|
26
|
+
"test:mcp": "node scripts/test-mcp-extmethod.mjs",
|
|
26
27
|
"logs": "node scripts/view-log.mjs",
|
|
27
28
|
"logs:filter": "node scripts/view-log.mjs --filter"
|
|
28
29
|
},
|