@tunnelbox/core 0.1.27 → 0.1.29
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/dist/index.js +765 -8
- package/locales/de-DE.json +38 -1
- package/locales/en-US.json +38 -1
- package/locales/es-ES.json +38 -1
- package/locales/fr-FR.json +38 -1
- package/locales/ja-JP.json +38 -1
- package/locales/ko-KR.json +38 -1
- package/locales/zh-CN.json +38 -1
- package/locales/zh-TW.json +38 -1
- package/package.json +1 -1
- package/src/acp/client.ts +187 -0
- package/src/acp/index.ts +11 -0
- package/src/acp/map.ts +45 -0
- package/src/acp/mirror.ts +210 -0
- package/src/acp/permissions.ts +47 -0
- package/src/acp/protocol.ts +282 -0
- package/src/acp/supervisor.ts +158 -0
- package/src/index.ts +2 -1
- package/src/types.ts +7 -1
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Client Protocol (ACP) v1 的最小通用类型(JSON-RPC 2.0,NDJSON 帧)。
|
|
3
|
+
*
|
|
4
|
+
* 权威定义见 https://agentclientprotocol.com/ 。各 ACP 适配器(cursor/codebuddy/kimi/trae…)
|
|
5
|
+
* 复用本模块;只声明用到的子集,解析保持宽容。适配器专有扩展(如 Cursor 的 `cursor/*`)
|
|
6
|
+
* 由各适配器自行声明。
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export type RequestId = string | number;
|
|
10
|
+
|
|
11
|
+
// ---- JSON-RPC 2.0 信封 ----
|
|
12
|
+
|
|
13
|
+
export interface JsonRpcRequest {
|
|
14
|
+
jsonrpc: "2.0";
|
|
15
|
+
id: RequestId;
|
|
16
|
+
method: string;
|
|
17
|
+
params?: unknown;
|
|
18
|
+
}
|
|
19
|
+
export interface JsonRpcNotification {
|
|
20
|
+
jsonrpc: "2.0";
|
|
21
|
+
method: string;
|
|
22
|
+
params?: unknown;
|
|
23
|
+
}
|
|
24
|
+
export interface JsonRpcResponse {
|
|
25
|
+
jsonrpc: "2.0";
|
|
26
|
+
id: RequestId;
|
|
27
|
+
result: unknown;
|
|
28
|
+
}
|
|
29
|
+
export interface JsonRpcError {
|
|
30
|
+
jsonrpc: "2.0";
|
|
31
|
+
id: RequestId;
|
|
32
|
+
error: { code: number; message: string; data?: unknown };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ---- Content ----
|
|
36
|
+
|
|
37
|
+
export type ContentBlock =
|
|
38
|
+
| { type: "text"; text: string }
|
|
39
|
+
| { type: "image"; data: string; mimeType: string; uri?: string }
|
|
40
|
+
| { type: "audio"; data: string; mimeType: string }
|
|
41
|
+
| { type: "resource_link"; uri: string; name: string; mimeType?: string; title?: string; description?: string; size?: number }
|
|
42
|
+
| { type: "resource"; resource: { uri: string; text?: string; blob?: string; mimeType?: string } };
|
|
43
|
+
|
|
44
|
+
// ---- initialize / authenticate ----
|
|
45
|
+
|
|
46
|
+
export interface ClientCapabilities {
|
|
47
|
+
fs?: { readTextFile?: boolean; writeTextFile?: boolean };
|
|
48
|
+
terminal?: boolean;
|
|
49
|
+
/** 声明 `form` 后支持 elicitation 的 agent 才会下发 `elicitation/create` */
|
|
50
|
+
elicitation?: { form?: unknown; url?: unknown };
|
|
51
|
+
/** 部分 agent(CodeBuddy 等)用于把 AskUserQuestion 委派给客户端的扩展能力位 */
|
|
52
|
+
askUserQuestion?: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface InitializeParams {
|
|
56
|
+
protocolVersion: number;
|
|
57
|
+
clientCapabilities?: ClientCapabilities;
|
|
58
|
+
clientInfo?: { name: string; title?: string; version: string };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface AgentCapabilities {
|
|
62
|
+
loadSession?: boolean;
|
|
63
|
+
promptCapabilities?: { image?: boolean; audio?: boolean; embeddedContext?: boolean };
|
|
64
|
+
mcpCapabilities?: { http?: boolean; sse?: boolean };
|
|
65
|
+
/** CodeBuddy 扩展:multitaskSupport 等 */
|
|
66
|
+
multitaskSupport?: boolean;
|
|
67
|
+
sessionCapabilities?: {
|
|
68
|
+
list?: unknown;
|
|
69
|
+
resume?: unknown;
|
|
70
|
+
close?: unknown;
|
|
71
|
+
delete?: unknown;
|
|
72
|
+
fork?: unknown;
|
|
73
|
+
additionalDirectories?: unknown;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface AuthMethod {
|
|
78
|
+
id: string;
|
|
79
|
+
name?: string;
|
|
80
|
+
description?: string;
|
|
81
|
+
type?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface InitializeResult {
|
|
85
|
+
protocolVersion: number;
|
|
86
|
+
agentCapabilities?: AgentCapabilities;
|
|
87
|
+
agentInfo?: { name?: string; title?: string; version?: string };
|
|
88
|
+
authMethods?: AuthMethod[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface AuthenticateParams {
|
|
92
|
+
methodId: string;
|
|
93
|
+
}
|
|
94
|
+
export interface AuthenticateResult {
|
|
95
|
+
_meta?: Record<string, unknown>;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ---- 会话 ----
|
|
99
|
+
|
|
100
|
+
export interface SessionMode {
|
|
101
|
+
id: string;
|
|
102
|
+
name: string;
|
|
103
|
+
description?: string;
|
|
104
|
+
}
|
|
105
|
+
export interface SessionModeState {
|
|
106
|
+
currentModeId: string;
|
|
107
|
+
availableModes: SessionMode[];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** `session/new|load|resume` 返回的会话级配置项(mode/model/context_window/multitask…)。 */
|
|
111
|
+
export interface SessionConfigOption {
|
|
112
|
+
id: string;
|
|
113
|
+
name?: string;
|
|
114
|
+
type?: string;
|
|
115
|
+
description?: string;
|
|
116
|
+
currentValue?: unknown;
|
|
117
|
+
options?: { value: string; name?: string; description?: string }[];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface SessionNewParams {
|
|
121
|
+
cwd: string;
|
|
122
|
+
mcpServers?: unknown[];
|
|
123
|
+
additionalDirectories?: string[];
|
|
124
|
+
}
|
|
125
|
+
export interface SessionNewResult {
|
|
126
|
+
sessionId: string;
|
|
127
|
+
modes?: SessionModeState;
|
|
128
|
+
configOptions?: SessionConfigOption[];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface SessionLoadParams {
|
|
132
|
+
sessionId: string;
|
|
133
|
+
cwd: string;
|
|
134
|
+
mcpServers?: unknown[];
|
|
135
|
+
}
|
|
136
|
+
export interface SessionResumeParams {
|
|
137
|
+
sessionId: string;
|
|
138
|
+
cwd: string;
|
|
139
|
+
mcpServers?: unknown[];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface SessionPromptParams {
|
|
143
|
+
sessionId: string;
|
|
144
|
+
prompt: ContentBlock[];
|
|
145
|
+
/** 可选:本轮 conversationRequestId(部分 agent 支持) */
|
|
146
|
+
_meta?: Record<string, unknown>;
|
|
147
|
+
}
|
|
148
|
+
export type StopReason = "end_turn" | "max_tokens" | "max_turn_requests" | "refusal" | "cancelled" | string;
|
|
149
|
+
export interface SessionPromptResult {
|
|
150
|
+
stopReason: StopReason;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface SessionSetModeParams {
|
|
154
|
+
sessionId: string;
|
|
155
|
+
modeId: string;
|
|
156
|
+
}
|
|
157
|
+
export interface SessionSetConfigOptionParams {
|
|
158
|
+
sessionId: string;
|
|
159
|
+
configId: string;
|
|
160
|
+
value: unknown;
|
|
161
|
+
type?: string;
|
|
162
|
+
}
|
|
163
|
+
export interface SessionCancelParams {
|
|
164
|
+
sessionId: string;
|
|
165
|
+
}
|
|
166
|
+
export interface SessionDeleteParams {
|
|
167
|
+
sessionId: string;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ---- session/update ----
|
|
171
|
+
|
|
172
|
+
export type ToolKind =
|
|
173
|
+
| "read"
|
|
174
|
+
| "edit"
|
|
175
|
+
| "delete"
|
|
176
|
+
| "move"
|
|
177
|
+
| "search"
|
|
178
|
+
| "execute"
|
|
179
|
+
| "think"
|
|
180
|
+
| "fetch"
|
|
181
|
+
| "switch_mode"
|
|
182
|
+
| "other";
|
|
183
|
+
export type ToolCallStatus = "pending" | "in_progress" | "completed" | "failed";
|
|
184
|
+
|
|
185
|
+
export interface ToolCall {
|
|
186
|
+
toolCallId: string;
|
|
187
|
+
title?: string;
|
|
188
|
+
kind?: ToolKind;
|
|
189
|
+
status?: ToolCallStatus;
|
|
190
|
+
content?: unknown[];
|
|
191
|
+
locations?: unknown[];
|
|
192
|
+
rawInput?: unknown;
|
|
193
|
+
rawOutput?: unknown;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export interface PlanEntry {
|
|
197
|
+
content?: string;
|
|
198
|
+
priority?: string;
|
|
199
|
+
status?: string;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export type SessionUpdate =
|
|
203
|
+
| { sessionUpdate: "user_message_chunk"; messageId?: string; content?: ContentBlock }
|
|
204
|
+
| { sessionUpdate: "agent_message_chunk"; messageId?: string; content?: ContentBlock }
|
|
205
|
+
| { sessionUpdate: "agent_thought_chunk"; messageId?: string; content?: ContentBlock }
|
|
206
|
+
| ({ sessionUpdate: "tool_call" } & ToolCall)
|
|
207
|
+
| ({ sessionUpdate: "tool_call_update" } & Partial<ToolCall>)
|
|
208
|
+
| { sessionUpdate: "plan"; entries?: PlanEntry[] }
|
|
209
|
+
| { sessionUpdate: "available_commands_update"; availableCommands?: { name: string; description?: string }[] }
|
|
210
|
+
| { sessionUpdate: "current_mode_update"; modeId?: string }
|
|
211
|
+
| { sessionUpdate: "config_option_update"; configOptions?: SessionConfigOption[] }
|
|
212
|
+
| { sessionUpdate: "usage_update"; used?: number; size?: number; cost?: unknown }
|
|
213
|
+
| { sessionUpdate: "session_info_update"; title?: string; _meta?: Record<string, unknown> }
|
|
214
|
+
| { sessionUpdate: string; [k: string]: unknown };
|
|
215
|
+
|
|
216
|
+
export interface SessionUpdateNotification {
|
|
217
|
+
sessionId: string;
|
|
218
|
+
update: SessionUpdate;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ---- session/request_permission ----
|
|
222
|
+
|
|
223
|
+
/** ACP 标准 kind;各 agent 可能扩展 `allow_session` 等,故用宽松字符串。 */
|
|
224
|
+
export type PermissionOptionKind = string;
|
|
225
|
+
|
|
226
|
+
export interface PermissionOption {
|
|
227
|
+
optionId: string;
|
|
228
|
+
name: string;
|
|
229
|
+
kind: PermissionOptionKind;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export interface RequestPermissionParams {
|
|
233
|
+
sessionId?: string;
|
|
234
|
+
toolCall: ToolCall;
|
|
235
|
+
options: PermissionOption[];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export type RequestPermissionOutcome = { outcome: "selected"; optionId: string } | { outcome: "cancelled" };
|
|
239
|
+
export interface RequestPermissionResult {
|
|
240
|
+
outcome: RequestPermissionOutcome;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// ---- elicitation/create(agent → client 请求,需应答) ----
|
|
244
|
+
|
|
245
|
+
export interface ElicitationMeta {
|
|
246
|
+
[k: string]: unknown;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export interface ElicitationPropertySchema {
|
|
250
|
+
type?: string;
|
|
251
|
+
title?: string;
|
|
252
|
+
description?: string;
|
|
253
|
+
enum?: unknown[];
|
|
254
|
+
enumNames?: unknown[];
|
|
255
|
+
items?: unknown;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export interface ElicitationRequestedSchema {
|
|
259
|
+
type?: string;
|
|
260
|
+
properties?: Record<string, ElicitationPropertySchema>;
|
|
261
|
+
required?: string[];
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export interface ElicitationCreateParams {
|
|
265
|
+
sessionId?: string;
|
|
266
|
+
toolCallId?: string;
|
|
267
|
+
mode?: string;
|
|
268
|
+
message?: string;
|
|
269
|
+
requestedSchema?: ElicitationRequestedSchema;
|
|
270
|
+
_meta?: ElicitationMeta;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export type ElicitationCreateResult =
|
|
274
|
+
| { action: "accept"; content?: Record<string, unknown>; _meta?: Record<string, unknown> }
|
|
275
|
+
| { action: "decline"; _meta?: Record<string, unknown> }
|
|
276
|
+
| { action: "cancel"; _meta?: Record<string, unknown> };
|
|
277
|
+
|
|
278
|
+
/** `elicitation/complete`(agent → client 通知):撤卡,按 elicitationId 关联。 */
|
|
279
|
+
export interface ElicitationCompleteParams {
|
|
280
|
+
elicitationId?: string;
|
|
281
|
+
_meta?: ElicitationMeta;
|
|
282
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ACP 常驻子进程的生命周期管理:按需启动、`initialize` + 可选 `authenticate` 握手、
|
|
3
|
+
* 退出后清空句柄(下次请求自动重启并重新握手)。
|
|
4
|
+
*
|
|
5
|
+
* 全程只维护一个连接(stdio 单客户端);会话恢复由各适配器用 `session/load`(或 `session/resume`)完成。
|
|
6
|
+
* 由各 ACP 适配器(cursor/codebuddy/kimi/trae…)复用;spawn 参数、clientInfo、能力位、认证策略由适配器注入。
|
|
7
|
+
*/
|
|
8
|
+
import { AcpClient, type AcpHandlers } from "./client";
|
|
9
|
+
import type {
|
|
10
|
+
AgentCapabilities,
|
|
11
|
+
AuthMethod,
|
|
12
|
+
AuthenticateResult,
|
|
13
|
+
ClientCapabilities,
|
|
14
|
+
InitializeParams,
|
|
15
|
+
InitializeResult,
|
|
16
|
+
} from "./protocol";
|
|
17
|
+
|
|
18
|
+
const PROTOCOL_VERSION = 1;
|
|
19
|
+
|
|
20
|
+
export interface AcpSupervisorConfig {
|
|
21
|
+
/** ACP CLI 可执行名/路径 */
|
|
22
|
+
bin: string;
|
|
23
|
+
/** bin 之后的完整参数(如 `["--acp"]` 或 `["acp","serve"]`) */
|
|
24
|
+
args: string[];
|
|
25
|
+
/** 子进程 cwd */
|
|
26
|
+
cwd?: string;
|
|
27
|
+
/** 错误/日志标签(如 `codebuddy acp`) */
|
|
28
|
+
label: string;
|
|
29
|
+
/** initialize.clientInfo */
|
|
30
|
+
clientInfo: { name: string; title?: string; version: string };
|
|
31
|
+
/** initialize.clientCapabilities(缺省:不代理 fs/terminal、声明 elicitation.form) */
|
|
32
|
+
clientCapabilities?: ClientCapabilities;
|
|
33
|
+
/**
|
|
34
|
+
* 可选:ACP `authenticate` 的 methodId。缺省不调用(用于交互式登录的 agent);
|
|
35
|
+
* 非交互的 agent(如 Kimi 的 `login`)可传入以探测登录态。
|
|
36
|
+
*/
|
|
37
|
+
authMethod?: string;
|
|
38
|
+
/** 未配置 authMethod 时回调(由适配器输出本地化提示) */
|
|
39
|
+
onAuthSkipped?: () => void;
|
|
40
|
+
/** authenticate 结果回调(成功/失败) */
|
|
41
|
+
onAuthResult?: (r: { ok: boolean; result?: AuthenticateResult; error?: string }) => void;
|
|
42
|
+
/** 日志(已本地化) */
|
|
43
|
+
log: (msg: string) => void;
|
|
44
|
+
/** 子进程退出回调(供适配器做 fail-closed 处理) */
|
|
45
|
+
onExit?: (code: number | null, signal: string | null) => void;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export class AcpSupervisor {
|
|
49
|
+
private client: AcpClient | null = null;
|
|
50
|
+
private starting: Promise<AcpClient> | null = null;
|
|
51
|
+
private caps: AgentCapabilities = {};
|
|
52
|
+
private auth: AuthenticateResult | null = null;
|
|
53
|
+
|
|
54
|
+
/** 由适配器注入:通知 / 服务端请求处理。 */
|
|
55
|
+
onNotification: (method: string, params: unknown) => void = () => {};
|
|
56
|
+
onServerRequest: (id: string | number, method: string, params: unknown) => void = () => {};
|
|
57
|
+
|
|
58
|
+
constructor(private cfg: AcpSupervisorConfig) {}
|
|
59
|
+
|
|
60
|
+
get running(): boolean {
|
|
61
|
+
return !!this.client?.alive;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** 当前客户端(不触发启动);用于应答来自该连接的服务端请求。 */
|
|
65
|
+
get current(): AcpClient | null {
|
|
66
|
+
return this.client?.alive ? this.client : null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** initialize 协商得到的 agent 能力位(loadSession / sessionCapabilities 等)。 */
|
|
70
|
+
get capabilities(): AgentCapabilities {
|
|
71
|
+
return this.caps;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** `authenticate` 返回结果(未认证/未调用时为 null)。 */
|
|
75
|
+
get authResult(): AuthenticateResult | null {
|
|
76
|
+
return this.auth;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** 取得可用客户端(必要时启动并握手)。 */
|
|
80
|
+
async ensure(): Promise<AcpClient> {
|
|
81
|
+
if (this.client?.alive) return this.client;
|
|
82
|
+
if (!this.starting) {
|
|
83
|
+
this.starting = this.launch().finally(() => {
|
|
84
|
+
this.starting = null;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return this.starting;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
stop(): void {
|
|
91
|
+
this.client?.stop();
|
|
92
|
+
this.client = null;
|
|
93
|
+
this.caps = {};
|
|
94
|
+
this.auth = null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private async launch(): Promise<AcpClient> {
|
|
98
|
+
const handlers: AcpHandlers = {
|
|
99
|
+
onNotification: (method, params) => this.onNotification(method, params),
|
|
100
|
+
onServerRequest: (id, method, params) => this.onServerRequest(id, method, params),
|
|
101
|
+
onStderr: (line) => {
|
|
102
|
+
if (/\b(error|failed|panic|denied|unauthorized|auth|login|mcp|tunnelbox)\b/i.test(line)) {
|
|
103
|
+
this.cfg.log(`acp: ${line.slice(0, 300)}`);
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
onExit: (code, signal) => {
|
|
107
|
+
this.client = null;
|
|
108
|
+
this.caps = {};
|
|
109
|
+
this.auth = null;
|
|
110
|
+
this.cfg.log(`${this.cfg.label} exited (code=${code ?? "null"} signal=${signal ?? "null"})`);
|
|
111
|
+
this.cfg.onExit?.(code, signal);
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
const client = new AcpClient(this.cfg.bin, this.cfg.args, handlers, this.cfg.label);
|
|
115
|
+
await client.start(this.cfg.cwd);
|
|
116
|
+
const params: InitializeParams = {
|
|
117
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
118
|
+
clientCapabilities: this.cfg.clientCapabilities ?? {
|
|
119
|
+
// 不代理文件/终端工具(适配器只做远程 UI;工具在本机执行)
|
|
120
|
+
fs: { readTextFile: false, writeTextFile: false },
|
|
121
|
+
terminal: false,
|
|
122
|
+
// 声明 form 后支持 elicitation 的 agent 才会下发 elicitation/create
|
|
123
|
+
elicitation: { form: {} },
|
|
124
|
+
},
|
|
125
|
+
clientInfo: this.cfg.clientInfo,
|
|
126
|
+
};
|
|
127
|
+
const res = await client.request<InitializeResult>("initialize", params, 20_000);
|
|
128
|
+
this.caps = res?.agentCapabilities ?? {};
|
|
129
|
+
await this.authenticate(client, res?.authMethods);
|
|
130
|
+
this.client = client;
|
|
131
|
+
return client;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* 完成登录握手。仅当配置了 `authMethod` 时调用(交互式登录的 agent 应缺省不调用,避免挂起/弹登录);
|
|
136
|
+
* 非交互的 agent(如 Kimi `login`)可传入以探测登录态,失败不阻断启动。
|
|
137
|
+
*/
|
|
138
|
+
private async authenticate(client: AcpClient, methods: AuthMethod[] | undefined): Promise<void> {
|
|
139
|
+
const wanted = (this.cfg.authMethod || "").trim();
|
|
140
|
+
if (!wanted) {
|
|
141
|
+
this.cfg.onAuthSkipped?.();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const list = Array.isArray(methods) ? methods : [];
|
|
145
|
+
const preferred = list.find((m) => m.id === wanted) ?? list[0];
|
|
146
|
+
if (!preferred) {
|
|
147
|
+
this.cfg.onAuthResult?.({ ok: false, error: "no auth methods" });
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
const r = await client.request<AuthenticateResult>("authenticate", { methodId: preferred.id }, 120_000);
|
|
152
|
+
this.auth = r ?? {};
|
|
153
|
+
this.cfg.onAuthResult?.({ ok: true, result: r ?? {} });
|
|
154
|
+
} catch (e) {
|
|
155
|
+
this.cfg.onAuthResult?.({ ok: false, error: (e as Error).message });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @tunnelbox/core —— 共享核心。
|
|
3
|
-
* 供各智能体适配器(opencode 插件 / dsh / claude-code / codex / …)复用:
|
|
3
|
+
* 供各智能体适配器(opencode 插件 / dsh / claude-code / codex / cursor / codebuddy / kimi / trae / …)复用:
|
|
4
4
|
* 统一协议类型、中继客户端(静默重连)、状态持久化、二维码配对。
|
|
5
5
|
*/
|
|
6
6
|
export * from "./types";
|
|
@@ -12,3 +12,4 @@ export * from "./i18n";
|
|
|
12
12
|
export * from "./messages";
|
|
13
13
|
export * from "./cli";
|
|
14
14
|
export * from "./terminal";
|
|
15
|
+
export * from "./acp";
|
package/src/types.ts
CHANGED
|
@@ -23,7 +23,7 @@ export interface AgentInfo {
|
|
|
23
23
|
version: string;
|
|
24
24
|
platform?: string;
|
|
25
25
|
directory?: string;
|
|
26
|
-
/** 智能体类型:opencode | claude-code | codex | dsh | openclaw | hermes | cursor */
|
|
26
|
+
/** 智能体类型:opencode | claude-code | codex | dsh | openclaw | hermes | cursor | codebuddy | kimi | trae */
|
|
27
27
|
type?: string;
|
|
28
28
|
/** IANA 时区名(如 Asia/Shanghai),仅用于"电脑本地时间"展示 */
|
|
29
29
|
timezone?: string;
|
|
@@ -104,6 +104,12 @@ export interface PermissionRequest {
|
|
|
104
104
|
kind?: PermissionKind;
|
|
105
105
|
/** choice 类型的可选项(显示为按钮列表) */
|
|
106
106
|
options?: string[];
|
|
107
|
+
/**
|
|
108
|
+
* 宿主允许的"允许"作用域(缺省=全部:once/session/always)。
|
|
109
|
+
* 手机端据此渲染允许按钮,避免提供宿主会拒绝的作用域
|
|
110
|
+
* (如 OpenClaw exec 的 `unavailableDecisions:["allow-always"]`)。
|
|
111
|
+
*/
|
|
112
|
+
allowed?: PermissionScope[];
|
|
107
113
|
}
|
|
108
114
|
|
|
109
115
|
/** 手机端对权限请求的应答(permission.reply)。status=allow 时可携带 scope 表达允许作用域。 */
|