@armadra/agent 0.6.7 → 0.7.0
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 +70 -0
- package/CHANGELOG.zh-CN.md +51 -0
- package/README.md +4 -3
- package/README.zh-CN.md +1 -1
- package/dist/acp.d.ts +2 -2
- package/dist/acp.js +2 -2
- package/dist/ai/apis/shared.d.ts +7 -1
- package/dist/ai/apis/shared.js +10 -0
- package/dist/ai/fake/fake-provider.js +5 -1
- package/dist/ai/fake/fake-script.d.ts +5 -2
- package/dist/ai/fake/fake-script.js +6 -2
- package/dist/ai/types.d.ts +2 -1
- package/dist/bundle/ama.cjs +46181 -44829
- package/dist/cli/args.d.ts +6 -0
- package/dist/cli/args.js +46 -0
- package/dist/cli/bootstrap.js +13 -2
- package/dist/cli/compose-events.d.ts +10 -0
- package/dist/cli/compose-events.js +97 -0
- package/dist/cli/compose-session.d.ts +25 -4
- package/dist/cli/compose-session.js +130 -103
- package/dist/cli/compose.js +6 -1
- package/dist/cli/runtime.d.ts +3 -1
- package/dist/cli/subcommands/auth.d.ts +13 -1
- package/dist/cli/subcommands/auth.js +28 -1
- package/dist/drivers/acp/client.d.ts +28 -4
- package/dist/drivers/acp/client.js +78 -5
- package/dist/drivers/acp/driver.d.ts +15 -4
- package/dist/drivers/acp/driver.js +110 -33
- package/dist/drivers/acp/testing/fake-agent-main.d.ts +1 -1
- package/dist/drivers/acp/testing/fake-agent-main.js +10 -2
- package/dist/drivers/acp/testing/fake-agent.d.ts +24 -0
- package/dist/drivers/acp/testing/fake-agent.js +175 -6
- package/dist/drivers/acp/types.d.ts +156 -9
- package/dist/drivers/acp/types.js +13 -3
- package/dist/drivers/jsonrpc.d.ts +13 -3
- package/dist/drivers/jsonrpc.js +40 -7
- package/dist/drivers/turn.d.ts +15 -2
- package/dist/drivers/turn.js +33 -4
- package/dist/i18n/catalog.d.ts +59 -16
- package/dist/i18n/catalog.js +4 -1
- package/dist/i18n/messages/acp.d.ts +125 -0
- package/dist/i18n/messages/acp.js +126 -0
- package/dist/i18n/messages/auth.d.ts +2 -0
- package/dist/i18n/messages/auth.js +4 -2
- package/dist/i18n/messages/cli-args.d.ts +2 -0
- package/dist/i18n/messages/cli-args.js +2 -0
- package/dist/i18n/messages/cli.d.ts +4 -0
- package/dist/i18n/messages/cli.js +2 -0
- package/dist/i18n/messages/print.d.ts +3 -33
- package/dist/i18n/messages/print.js +3 -33
- package/dist/modes/acp/acp-auth-gate.d.ts +40 -0
- package/dist/modes/acp/acp-auth-gate.js +201 -0
- package/dist/modes/acp/acp-config.d.ts +43 -0
- package/dist/modes/acp/acp-config.js +151 -0
- package/dist/modes/acp/acp-connection.d.ts +29 -0
- package/dist/modes/acp/acp-connection.js +37 -0
- package/dist/modes/acp/acp-events.d.ts +59 -23
- package/dist/modes/acp/acp-events.js +154 -88
- package/dist/modes/acp/acp-mode.d.ts +13 -2
- package/dist/modes/acp/acp-mode.js +23 -8
- package/dist/modes/acp/acp-server.d.ts +59 -32
- package/dist/modes/acp/acp-server.js +322 -128
- package/dist/modes/acp/acp-sessions.d.ts +80 -0
- package/dist/modes/acp/acp-sessions.js +157 -0
- package/dist/modes/acp/acp-tool-text.d.ts +23 -0
- package/dist/modes/acp/acp-tool-text.js +83 -0
- package/dist/modes/print/json-event.d.ts +2 -1
- package/dist/modes/print/json-event.js +6 -1
- package/dist/tools/edit.d.ts +6 -2
- package/dist/tools/edit.js +19 -2
- package/dist/tools/types.d.ts +11 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/write.d.ts +1 -0
- package/dist/tools/write.js +21 -3
- package/docs/acp.md +151 -30
- package/docs/agents.md +2 -0
- package/docs/codemode.md +1 -1
- package/docs/en/acp.md +192 -0
- package/package.json +1 -1
package/dist/drivers/jsonrpc.js
CHANGED
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
* - 分帧复用 `modes/rpc/jsonl.ts`(只按 `\n` 切行、64 KiB 分片写、背压等 drain),写入串行;
|
|
6
6
|
* - 双向:本端可发请求 / 通知,也处理对端的请求(`onRequest` 抛 {@link RpcError} 即回错误)与通知;
|
|
7
7
|
* - `jsonrpcField: false` 时不写 `"jsonrpc":"2.0"`(Codex app-server 的线上形状),读取两种都认;
|
|
8
|
-
* - 连接关闭(输入流结束)时所有挂起的请求以 `connection_closed`
|
|
8
|
+
* - 连接关闭(输入流结束)时所有挂起的请求以 `connection_closed` 失败;
|
|
9
|
+
* - `cancelRequests: true`(ACP 两侧)时支持协议级取消 `$/cancel_request`:本端请求的 `signal` abort
|
|
10
|
+
* 会通知对端;对端撤回本端正在处理的请求时 abort 该请求的 `ctx.signal`,处理器此后抛错一律回 -32800。
|
|
11
|
+
* 缺省关闭(Codex app-server 不认),线上形状与之前逐字节相同。
|
|
9
12
|
*/
|
|
10
13
|
import { createLineReader, writeChunked } from "../modes/rpc/jsonl.js";
|
|
11
14
|
import { RPC_ERRORS } from "./acp/types.js";
|
|
@@ -19,9 +22,13 @@ export class RpcError extends Error {
|
|
|
19
22
|
this.name = "RpcError";
|
|
20
23
|
}
|
|
21
24
|
}
|
|
25
|
+
/** `$/cancel_request` 的方法名(与 ACP_METHODS.cancelRequest 相同;这里不依赖 ACP 词汇表)。 */
|
|
26
|
+
const CANCEL_REQUEST = "$/cancel_request";
|
|
22
27
|
export class JsonRpcPeer {
|
|
23
28
|
options;
|
|
24
29
|
pending = new Map();
|
|
30
|
+
/** 正在处理的对端请求(只在 `cancelRequests` 时记录),供 `$/cancel_request` 撤回。 */
|
|
31
|
+
inflight = new Map();
|
|
25
32
|
reader;
|
|
26
33
|
lifetime = new AbortController();
|
|
27
34
|
nextId = 1;
|
|
@@ -39,14 +46,19 @@ export class JsonRpcPeer {
|
|
|
39
46
|
get isOpen() {
|
|
40
47
|
return !this.isClosed;
|
|
41
48
|
}
|
|
42
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* 发请求;`signal` abort 时本端不再等。`cancelRequests` 开着时同时给对端发
|
|
51
|
+
* `$/cancel_request { requestId }`(已发出的请求才发),否则不通知对端。
|
|
52
|
+
*/
|
|
43
53
|
request(method, params, signal) {
|
|
44
54
|
if (this.isClosed)
|
|
45
55
|
return Promise.reject(closedError(method));
|
|
46
56
|
const id = this.nextId++;
|
|
47
57
|
return new Promise((resolve, reject) => {
|
|
48
58
|
const onAbort = () => {
|
|
49
|
-
this.pending.delete(id);
|
|
59
|
+
const sent = this.pending.delete(id);
|
|
60
|
+
if (sent && this.options.cancelRequests === true && !this.isClosed)
|
|
61
|
+
void this.notify(CANCEL_REQUEST, { requestId: id });
|
|
50
62
|
reject(new RpcError(RPC_ERRORS.internalError, `${method}: aborted`));
|
|
51
63
|
};
|
|
52
64
|
if (signal?.aborted === true)
|
|
@@ -116,6 +128,14 @@ export class JsonRpcPeer {
|
|
|
116
128
|
return;
|
|
117
129
|
}
|
|
118
130
|
if (typeof message.method === "string") {
|
|
131
|
+
if (message.method === CANCEL_REQUEST &&
|
|
132
|
+
this.options.cancelRequests === true &&
|
|
133
|
+
(message.id === undefined || message.id === null)) {
|
|
134
|
+
const requestId = message.params?.requestId;
|
|
135
|
+
if (typeof requestId === "string" || typeof requestId === "number")
|
|
136
|
+
this.inflight.get(requestId)?.abort();
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
119
139
|
if (message.id !== undefined && message.id !== null) {
|
|
120
140
|
void this.handleRequest(message.id, message.method, message.params);
|
|
121
141
|
}
|
|
@@ -154,14 +174,23 @@ export class JsonRpcPeer {
|
|
|
154
174
|
});
|
|
155
175
|
return;
|
|
156
176
|
}
|
|
177
|
+
let cancel;
|
|
178
|
+
let signal = this.lifetime.signal;
|
|
179
|
+
if (this.options.cancelRequests === true) {
|
|
180
|
+
cancel = new AbortController();
|
|
181
|
+
this.inflight.set(id, cancel);
|
|
182
|
+
signal = AbortSignal.any([this.lifetime.signal, cancel.signal]);
|
|
183
|
+
}
|
|
157
184
|
try {
|
|
158
|
-
const result = await handler(method, params, { id, signal
|
|
185
|
+
const result = await handler(method, params, { id, signal });
|
|
159
186
|
await this.send({ id, result: result ?? null });
|
|
160
187
|
}
|
|
161
188
|
catch (error) {
|
|
162
|
-
const rpc =
|
|
163
|
-
?
|
|
164
|
-
:
|
|
189
|
+
const rpc = cancel?.signal.aborted === true
|
|
190
|
+
? new RpcError(RPC_ERRORS.requestCancelled, `${method}: request cancelled`)
|
|
191
|
+
: error instanceof RpcError
|
|
192
|
+
? error
|
|
193
|
+
: new RpcError(RPC_ERRORS.internalError, error instanceof Error ? error.message : String(error));
|
|
165
194
|
await this.send({
|
|
166
195
|
id,
|
|
167
196
|
error: {
|
|
@@ -171,6 +200,10 @@ export class JsonRpcPeer {
|
|
|
171
200
|
},
|
|
172
201
|
});
|
|
173
202
|
}
|
|
203
|
+
finally {
|
|
204
|
+
if (cancel !== undefined && this.inflight.get(id) === cancel)
|
|
205
|
+
this.inflight.delete(id);
|
|
206
|
+
}
|
|
174
207
|
}
|
|
175
208
|
}
|
|
176
209
|
function closedError(method) {
|
package/dist/drivers/turn.d.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* 一个回合的结果汇总(各驱动共用)。[W5-E]
|
|
3
3
|
*
|
|
4
4
|
* 驱动把归一化后的 {@link DriverEvent} 交给收集器:它转发给 `onEvent`,同时累计最终文本、
|
|
5
|
-
* 工具摘要(≤ 20 行,§5.2)、触及的文件(edit / delete / move 类工具的 locations
|
|
5
|
+
* 工具摘要(≤ 20 行,§5.2)、触及的文件(edit / delete / move 类工具的 locations,以及带 diff 内容的
|
|
6
|
+
* 工具改动的路径——不论种类,见 {@link TurnCollector.noteDiff})与用量。
|
|
6
7
|
* 原始事件只在内存里流过,不落盘(§5.4 敏感数据)。
|
|
7
8
|
*/
|
|
8
9
|
import type { AcpToolKind, DriverEvent, DriverTurnResult } from "./types.js";
|
|
@@ -12,6 +13,10 @@ interface ToolState {
|
|
|
12
13
|
kind: AcpToolKind;
|
|
13
14
|
status: "pending" | "in_progress" | "completed" | "failed";
|
|
14
15
|
locations: string[];
|
|
16
|
+
/** 工具内容里 diff 的路径(ACP `content[].type === "diff"`)。 */
|
|
17
|
+
diffPaths?: string[];
|
|
18
|
+
/** 已转发过的状态(去重用)。 */
|
|
19
|
+
reported: Set<ToolState["status"]>;
|
|
15
20
|
}
|
|
16
21
|
export declare class TurnCollector {
|
|
17
22
|
private readonly onEvent;
|
|
@@ -20,8 +25,16 @@ export declare class TurnCollector {
|
|
|
20
25
|
private readonly order;
|
|
21
26
|
private usage;
|
|
22
27
|
constructor(onEvent: (event: DriverEvent) => void);
|
|
23
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* 归一化事件:累计后转发给 onEvent。同一工具调用回到已报过的状态(如审批前后
|
|
30
|
+
* `in_progress → pending → in_progress`)且标题、种类、位置都没变时不再转发,免得下游重复报进度。
|
|
31
|
+
*/
|
|
24
32
|
push(event: DriverEvent): void;
|
|
33
|
+
/**
|
|
34
|
+
* 记下工具改动的文件(diff 内容的路径):工具完成后计入 filesTouched,不论它报的种类。
|
|
35
|
+
* 在 `push` 该工具的 `tool_call` 之后调(未知的 id 忽略)。[ACP-D]
|
|
36
|
+
*/
|
|
37
|
+
noteDiff(id: string, paths: readonly string[]): void;
|
|
25
38
|
/** 工具调用的最近状态(驱动做 tool_call_update 时补全标题与种类)。 */
|
|
26
39
|
tool(id: string): Readonly<ToolState> | undefined;
|
|
27
40
|
/** 回合结束时的累计用量合并(`result.usage` 等)。 */
|
package/dist/drivers/turn.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* 一个回合的结果汇总(各驱动共用)。[W5-E]
|
|
3
3
|
*
|
|
4
4
|
* 驱动把归一化后的 {@link DriverEvent} 交给收集器:它转发给 `onEvent`,同时累计最终文本、
|
|
5
|
-
* 工具摘要(≤ 20 行,§5.2)、触及的文件(edit / delete / move 类工具的 locations
|
|
5
|
+
* 工具摘要(≤ 20 行,§5.2)、触及的文件(edit / delete / move 类工具的 locations,以及带 diff 内容的
|
|
6
|
+
* 工具改动的路径——不论种类,见 {@link TurnCollector.noteDiff})与用量。
|
|
6
7
|
* 原始事件只在内存里流过,不落盘(§5.4 敏感数据)。
|
|
7
8
|
*/
|
|
8
9
|
export const TOOL_SUMMARY_LINES = 20;
|
|
@@ -16,7 +17,10 @@ export class TurnCollector {
|
|
|
16
17
|
constructor(onEvent) {
|
|
17
18
|
this.onEvent = onEvent;
|
|
18
19
|
}
|
|
19
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* 归一化事件:累计后转发给 onEvent。同一工具调用回到已报过的状态(如审批前后
|
|
22
|
+
* `in_progress → pending → in_progress`)且标题、种类、位置都没变时不再转发,免得下游重复报进度。
|
|
23
|
+
*/
|
|
20
24
|
push(event) {
|
|
21
25
|
switch (event.type) {
|
|
22
26
|
case "message_delta":
|
|
@@ -29,10 +33,20 @@ export class TurnCollector {
|
|
|
29
33
|
kind: event.kind,
|
|
30
34
|
status: event.status,
|
|
31
35
|
locations: event.locations ?? known?.locations ?? [],
|
|
36
|
+
...(known?.diffPaths !== undefined ? { diffPaths: known.diffPaths } : {}),
|
|
37
|
+
reported: known?.reported ?? new Set(),
|
|
32
38
|
};
|
|
33
39
|
if (known === undefined)
|
|
34
40
|
this.order.push(event.id);
|
|
35
41
|
this.tools.set(event.id, next);
|
|
42
|
+
const repeat = known !== undefined &&
|
|
43
|
+
next.reported.has(event.status) &&
|
|
44
|
+
next.title === known.title &&
|
|
45
|
+
next.kind === known.kind &&
|
|
46
|
+
next.locations.join("\n") === known.locations.join("\n");
|
|
47
|
+
if (repeat)
|
|
48
|
+
return;
|
|
49
|
+
next.reported.add(event.status);
|
|
36
50
|
break;
|
|
37
51
|
}
|
|
38
52
|
case "usage":
|
|
@@ -43,6 +57,16 @@ export class TurnCollector {
|
|
|
43
57
|
}
|
|
44
58
|
this.onEvent(event);
|
|
45
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* 记下工具改动的文件(diff 内容的路径):工具完成后计入 filesTouched,不论它报的种类。
|
|
62
|
+
* 在 `push` 该工具的 `tool_call` 之后调(未知的 id 忽略)。[ACP-D]
|
|
63
|
+
*/
|
|
64
|
+
noteDiff(id, paths) {
|
|
65
|
+
const known = this.tools.get(id);
|
|
66
|
+
if (known === undefined || paths.length === 0)
|
|
67
|
+
return;
|
|
68
|
+
known.diffPaths = [...new Set([...(known.diffPaths ?? []), ...paths])];
|
|
69
|
+
}
|
|
46
70
|
/** 工具调用的最近状态(驱动做 tool_call_update 时补全标题与种类)。 */
|
|
47
71
|
tool(id) {
|
|
48
72
|
return this.tools.get(id);
|
|
@@ -67,10 +91,15 @@ export class TurnCollector {
|
|
|
67
91
|
}
|
|
68
92
|
result(stopReason) {
|
|
69
93
|
const files = new Set();
|
|
70
|
-
for (const tool of this.tools.values())
|
|
71
|
-
if (
|
|
94
|
+
for (const tool of this.tools.values()) {
|
|
95
|
+
if (tool.status !== "completed")
|
|
96
|
+
continue;
|
|
97
|
+
if (WRITE_KINDS.has(tool.kind))
|
|
72
98
|
for (const path of tool.locations)
|
|
73
99
|
files.add(path);
|
|
100
|
+
for (const path of tool.diffPaths ?? [])
|
|
101
|
+
files.add(path);
|
|
102
|
+
}
|
|
74
103
|
const lines = this.order.map((id) => {
|
|
75
104
|
const tool = this.tools.get(id);
|
|
76
105
|
return `${tool.status === "failed" ? "✗" : tool.status === "completed" ? "✓" : "…"} ${tool.kind} ${tool.title}`;
|
package/dist/i18n/catalog.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* 领域 → 所有者:cli / subcommands(I1);interactive / approval / plan / rewind / panels / permissions(I2);
|
|
6
6
|
* report / print / drivers / session / errors(I3);config(I4);agents(A);trace(T1 / T2);
|
|
7
|
-
* memory(M);auth(O);settings(S)。
|
|
7
|
+
* memory(M);auth(O);settings(S);acp(ACP-C0 新增,docs/acp-plan.md D15)。
|
|
8
8
|
*/
|
|
9
9
|
import type { Messages } from "./types.js";
|
|
10
10
|
import * as rewind from "./messages/rewind.js";
|
|
@@ -16,6 +16,7 @@ declare const en: {
|
|
|
16
16
|
flagsConflict: (flags: readonly string[]) => string;
|
|
17
17
|
invalidChoice: (option: string, choices: readonly string[], got: string) => string;
|
|
18
18
|
emptyValue: (option: string) => string;
|
|
19
|
+
unknownTerminalAuth: (id: string) => string;
|
|
19
20
|
fullscreenUnsupported: string;
|
|
20
21
|
maxTurnsPositive: (got: string) => string;
|
|
21
22
|
maxCostPositive: (got: string) => string;
|
|
@@ -162,6 +163,7 @@ declare const en: {
|
|
|
162
163
|
appendToolFailed: (name: string, message: string) => string;
|
|
163
164
|
notComposed: string;
|
|
164
165
|
switchWhileStreaming: string;
|
|
166
|
+
notLiveSession: string;
|
|
165
167
|
};
|
|
166
168
|
composeStore: {
|
|
167
169
|
ambiguousId: (id: string, candidates: readonly string[]) => string;
|
|
@@ -1279,21 +1281,6 @@ declare const en: {
|
|
|
1279
1281
|
noPlan: string;
|
|
1280
1282
|
badMode: (modes: readonly string[]) => string;
|
|
1281
1283
|
};
|
|
1282
|
-
acp: {
|
|
1283
|
-
missingParam: (key: string) => string;
|
|
1284
|
-
promptNotArray: string;
|
|
1285
|
-
unparsable: (reason: string) => string;
|
|
1286
|
-
missingProtocolVersion: string;
|
|
1287
|
-
fixedCwd: (cwd: string, got: string) => string;
|
|
1288
|
-
sessionNotFound: (id: string, error: string) => string;
|
|
1289
|
-
busy: string;
|
|
1290
|
-
modelFailed: string;
|
|
1291
|
-
unknownMode: (mode: string) => string;
|
|
1292
|
-
allowOnce: string;
|
|
1293
|
-
allowAlways: string;
|
|
1294
|
-
rejectOnce: string;
|
|
1295
|
-
truncated: (length: number) => string;
|
|
1296
|
-
};
|
|
1297
1284
|
};
|
|
1298
1285
|
config: {
|
|
1299
1286
|
keys: {
|
|
@@ -1995,6 +1982,7 @@ declare const en: {
|
|
|
1995
1982
|
unknownAction: (action: string) => string;
|
|
1996
1983
|
setPrompt: (provider: string) => string;
|
|
1997
1984
|
noKeyFromStdin: string;
|
|
1985
|
+
pickProvider: string;
|
|
1998
1986
|
saved: (provider: string, path: string) => string;
|
|
1999
1987
|
warning: (text: string) => string;
|
|
2000
1988
|
listEmpty: (path: string) => string;
|
|
@@ -2255,6 +2243,61 @@ declare const en: {
|
|
|
2255
2243
|
missingValue: string;
|
|
2256
2244
|
};
|
|
2257
2245
|
};
|
|
2246
|
+
acp: {
|
|
2247
|
+
core: {
|
|
2248
|
+
missingParam: (key: string) => string;
|
|
2249
|
+
promptNotArray: string;
|
|
2250
|
+
unparsable: (reason: string) => string;
|
|
2251
|
+
missingProtocolVersion: string;
|
|
2252
|
+
fixedCwd: (cwd: string, got: string) => string;
|
|
2253
|
+
sessionNotFound: (id: string, error: string) => string;
|
|
2254
|
+
modelFailed: string;
|
|
2255
|
+
unknownMode: (mode: string) => string;
|
|
2256
|
+
allowOnce: string;
|
|
2257
|
+
allowAlways: string;
|
|
2258
|
+
rejectOnce: string;
|
|
2259
|
+
unknownConfigOption: (id: string) => string;
|
|
2260
|
+
};
|
|
2261
|
+
auth: {
|
|
2262
|
+
chatgptName: string;
|
|
2263
|
+
chatgptDescription: string;
|
|
2264
|
+
apiKeyName: string;
|
|
2265
|
+
apiKeyDescription: string;
|
|
2266
|
+
notAgentMethod: string;
|
|
2267
|
+
waiting: (reason: string) => string;
|
|
2268
|
+
ready: (model: string) => string;
|
|
2269
|
+
};
|
|
2270
|
+
session: {
|
|
2271
|
+
notOpen: (id: string) => string;
|
|
2272
|
+
invalidCursor: string;
|
|
2273
|
+
ignoredMcp: (count: number) => string;
|
|
2274
|
+
ignoredDirs: (count: number) => string;
|
|
2275
|
+
};
|
|
2276
|
+
tools: {
|
|
2277
|
+
codemodePrefix: (title: string) => string;
|
|
2278
|
+
truncated: (length: number) => string;
|
|
2279
|
+
};
|
|
2280
|
+
config: {
|
|
2281
|
+
model: string;
|
|
2282
|
+
mode: string;
|
|
2283
|
+
thinking: string;
|
|
2284
|
+
levels: {
|
|
2285
|
+
off: string;
|
|
2286
|
+
minimal: string;
|
|
2287
|
+
low: string;
|
|
2288
|
+
medium: string;
|
|
2289
|
+
high: string;
|
|
2290
|
+
xhigh: string;
|
|
2291
|
+
};
|
|
2292
|
+
invalidValue: (id: string, value: string) => string;
|
|
2293
|
+
unknownModel: (ref: string) => string;
|
|
2294
|
+
};
|
|
2295
|
+
client: {
|
|
2296
|
+
authRequired: (agent: string, methods: readonly string[]) => string;
|
|
2297
|
+
authNoMethods: (agent: string) => string;
|
|
2298
|
+
authTerminal: (name: string, command: string) => string;
|
|
2299
|
+
};
|
|
2300
|
+
};
|
|
2258
2301
|
};
|
|
2259
2302
|
/** 运行期取用的目录形状:en 的形状、叶子放宽为 string / 同签名函数。 */
|
|
2260
2303
|
export type Catalog = Messages<typeof en>;
|
package/dist/i18n/catalog.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* 领域 → 所有者:cli / subcommands(I1);interactive / approval / plan / rewind / panels / permissions(I2);
|
|
6
6
|
* report / print / drivers / session / errors(I3);config(I4);agents(A);trace(T1 / T2);
|
|
7
|
-
* memory(M);auth(O);settings(S)。
|
|
7
|
+
* memory(M);auth(O);settings(S);acp(ACP-C0 新增,docs/acp-plan.md D15)。
|
|
8
8
|
*/
|
|
9
9
|
import * as cli from "./messages/cli.js";
|
|
10
10
|
import * as subcommands from "./messages/subcommands.js";
|
|
@@ -25,6 +25,7 @@ import * as trace from "./messages/trace.js";
|
|
|
25
25
|
import * as memory from "./messages/memory.js";
|
|
26
26
|
import * as auth from "./messages/auth.js";
|
|
27
27
|
import * as settings from "./messages/settings.js";
|
|
28
|
+
import * as acp from "./messages/acp.js";
|
|
28
29
|
const en = {
|
|
29
30
|
cli: cli.en,
|
|
30
31
|
subcommands: subcommands.en,
|
|
@@ -45,6 +46,7 @@ const en = {
|
|
|
45
46
|
memory: memory.en,
|
|
46
47
|
auth: auth.en,
|
|
47
48
|
settings: settings.en,
|
|
49
|
+
acp: acp.en,
|
|
48
50
|
};
|
|
49
51
|
const zh = {
|
|
50
52
|
cli: cli.zh,
|
|
@@ -66,6 +68,7 @@ const zh = {
|
|
|
66
68
|
memory: memory.zh,
|
|
67
69
|
auth: auth.zh,
|
|
68
70
|
settings: settings.zh,
|
|
71
|
+
acp: acp.zh,
|
|
69
72
|
};
|
|
70
73
|
export const CATALOGS = { en, zh };
|
|
71
74
|
/** 领域名(一级命名空间)。 */
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 消息目录:acp(键名规范见 docs/i18n.md)。[ACP-C0 从 print.acp 迁入,docs/acp-plan.md D15]
|
|
3
|
+
*
|
|
4
|
+
* en 是形状源;zh 用 `satisfies Messages<typeof en>`,缺键 / 多键 / 参数不符在 tsc 期报错。
|
|
5
|
+
* 整句一个键、禁止片段拼接;插值写成函数,条件分支写进函数体。
|
|
6
|
+
* 发给 ACP 客户端的 name / description / error message 是给人看的,走这里;`_meta`、id、value 等机器字段不翻译。
|
|
7
|
+
* 子对象各归一个批次:core(现有服务端文案)、auth(A)、session(B)、tools(C)、config / client(D)。
|
|
8
|
+
*/
|
|
9
|
+
export declare const en: {
|
|
10
|
+
/** ACP 服务端(`ama --mode acp`)的现有文案。 */
|
|
11
|
+
core: {
|
|
12
|
+
missingParam: (key: string) => string;
|
|
13
|
+
promptNotArray: string;
|
|
14
|
+
unparsable: (reason: string) => string;
|
|
15
|
+
missingProtocolVersion: string;
|
|
16
|
+
fixedCwd: (cwd: string, got: string) => string;
|
|
17
|
+
sessionNotFound: (id: string, error: string) => string;
|
|
18
|
+
modelFailed: string;
|
|
19
|
+
unknownMode: (mode: string) => string;
|
|
20
|
+
allowOnce: string;
|
|
21
|
+
allowAlways: string;
|
|
22
|
+
rejectOnce: string;
|
|
23
|
+
unknownConfigOption: (id: string) => string;
|
|
24
|
+
};
|
|
25
|
+
/** [ACP-A] 认证门与终端认证方法。 */
|
|
26
|
+
auth: {
|
|
27
|
+
chatgptName: string;
|
|
28
|
+
chatgptDescription: string;
|
|
29
|
+
apiKeyName: string;
|
|
30
|
+
apiKeyDescription: string;
|
|
31
|
+
notAgentMethod: string;
|
|
32
|
+
waiting: (reason: string) => string;
|
|
33
|
+
ready: (model: string) => string;
|
|
34
|
+
};
|
|
35
|
+
/** [ACP-B] 多会话与会话元数据。 */
|
|
36
|
+
session: {
|
|
37
|
+
notOpen: (id: string) => string;
|
|
38
|
+
invalidCursor: string;
|
|
39
|
+
ignoredMcp: (count: number) => string;
|
|
40
|
+
ignoredDirs: (count: number) => string;
|
|
41
|
+
};
|
|
42
|
+
/** [ACP-C] 工具调用映射。 */
|
|
43
|
+
tools: {
|
|
44
|
+
/** codemode 脚本里的内层调用的标题。 */
|
|
45
|
+
codemodePrefix: (title: string) => string;
|
|
46
|
+
truncated: (length: number) => string;
|
|
47
|
+
};
|
|
48
|
+
/** [ACP-D] 配置项与命令表。 */
|
|
49
|
+
config: {
|
|
50
|
+
model: string;
|
|
51
|
+
mode: string;
|
|
52
|
+
thinking: string;
|
|
53
|
+
levels: {
|
|
54
|
+
off: string;
|
|
55
|
+
minimal: string;
|
|
56
|
+
low: string;
|
|
57
|
+
medium: string;
|
|
58
|
+
high: string;
|
|
59
|
+
xhigh: string;
|
|
60
|
+
};
|
|
61
|
+
invalidValue: (id: string, value: string) => string;
|
|
62
|
+
unknownModel: (ref: string) => string;
|
|
63
|
+
};
|
|
64
|
+
/** [ACP-D] ama 作 ACP 客户端时的文案。 */
|
|
65
|
+
client: {
|
|
66
|
+
authRequired: (agent: string, methods: readonly string[]) => string;
|
|
67
|
+
authNoMethods: (agent: string) => string;
|
|
68
|
+
authTerminal: (name: string, command: string) => string;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
export declare const zh: {
|
|
72
|
+
core: {
|
|
73
|
+
missingParam: (key: string) => string;
|
|
74
|
+
promptNotArray: string;
|
|
75
|
+
unparsable: (reason: string) => string;
|
|
76
|
+
missingProtocolVersion: string;
|
|
77
|
+
fixedCwd: (cwd: string, got: string) => string;
|
|
78
|
+
sessionNotFound: (id: string, error: string) => string;
|
|
79
|
+
modelFailed: string;
|
|
80
|
+
unknownMode: (mode: string) => string;
|
|
81
|
+
allowOnce: string;
|
|
82
|
+
allowAlways: string;
|
|
83
|
+
rejectOnce: string;
|
|
84
|
+
unknownConfigOption: (id: string) => string;
|
|
85
|
+
};
|
|
86
|
+
auth: {
|
|
87
|
+
chatgptName: string;
|
|
88
|
+
chatgptDescription: string;
|
|
89
|
+
apiKeyName: string;
|
|
90
|
+
apiKeyDescription: string;
|
|
91
|
+
notAgentMethod: string;
|
|
92
|
+
waiting: (reason: string) => string;
|
|
93
|
+
ready: (model: string) => string;
|
|
94
|
+
};
|
|
95
|
+
session: {
|
|
96
|
+
notOpen: (id: string) => string;
|
|
97
|
+
invalidCursor: string;
|
|
98
|
+
ignoredMcp: (count: number) => string;
|
|
99
|
+
ignoredDirs: (count: number) => string;
|
|
100
|
+
};
|
|
101
|
+
tools: {
|
|
102
|
+
codemodePrefix: (title: string) => string;
|
|
103
|
+
truncated: (length: number) => string;
|
|
104
|
+
};
|
|
105
|
+
config: {
|
|
106
|
+
model: string;
|
|
107
|
+
mode: string;
|
|
108
|
+
thinking: string;
|
|
109
|
+
levels: {
|
|
110
|
+
off: string;
|
|
111
|
+
minimal: string;
|
|
112
|
+
low: string;
|
|
113
|
+
medium: string;
|
|
114
|
+
high: string;
|
|
115
|
+
xhigh: string;
|
|
116
|
+
};
|
|
117
|
+
invalidValue: (id: string, value: string) => string;
|
|
118
|
+
unknownModel: (ref: string) => string;
|
|
119
|
+
};
|
|
120
|
+
client: {
|
|
121
|
+
authRequired: (agent: string, methods: readonly string[]) => string;
|
|
122
|
+
authNoMethods: (agent: string) => string;
|
|
123
|
+
authTerminal: (name: string, command: string) => string;
|
|
124
|
+
};
|
|
125
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 消息目录:acp(键名规范见 docs/i18n.md)。[ACP-C0 从 print.acp 迁入,docs/acp-plan.md D15]
|
|
3
|
+
*
|
|
4
|
+
* en 是形状源;zh 用 `satisfies Messages<typeof en>`,缺键 / 多键 / 参数不符在 tsc 期报错。
|
|
5
|
+
* 整句一个键、禁止片段拼接;插值写成函数,条件分支写进函数体。
|
|
6
|
+
* 发给 ACP 客户端的 name / description / error message 是给人看的,走这里;`_meta`、id、value 等机器字段不翻译。
|
|
7
|
+
* 子对象各归一个批次:core(现有服务端文案)、auth(A)、session(B)、tools(C)、config / client(D)。
|
|
8
|
+
*/
|
|
9
|
+
import { plural } from "../format.js";
|
|
10
|
+
export const en = {
|
|
11
|
+
/** ACP 服务端(`ama --mode acp`)的现有文案。 */
|
|
12
|
+
core: {
|
|
13
|
+
missingParam: (key) => `missing ${key}`,
|
|
14
|
+
promptNotArray: "prompt must be an array of content blocks",
|
|
15
|
+
unparsable: (reason) => `ACP: unparsable input (${reason})`,
|
|
16
|
+
missingProtocolVersion: "missing protocolVersion",
|
|
17
|
+
fixedCwd: (cwd, got) => `the session directory of ama --mode acp is fixed to the start directory ${cwd} (got ${got})`,
|
|
18
|
+
sessionNotFound: (id, error) => `session ${id} not found: ${error}`,
|
|
19
|
+
modelFailed: "model request failed",
|
|
20
|
+
unknownMode: (mode) => `unknown mode: ${mode}`,
|
|
21
|
+
allowOnce: "Allow",
|
|
22
|
+
allowAlways: "Allow for this session",
|
|
23
|
+
rejectOnce: "Deny",
|
|
24
|
+
unknownConfigOption: (id) => `unknown config option: ${id}`,
|
|
25
|
+
},
|
|
26
|
+
/** [ACP-A] 认证门与终端认证方法。 */
|
|
27
|
+
auth: {
|
|
28
|
+
chatgptName: "Sign in with ChatGPT",
|
|
29
|
+
chatgptDescription: "Runs ama auth login chatgpt in a terminal (ChatGPT subscription)",
|
|
30
|
+
apiKeyName: "Enter an API key",
|
|
31
|
+
apiKeyDescription: "Runs ama auth set in a terminal: pick a provider, then paste its API key",
|
|
32
|
+
notAgentMethod: "ama only offers terminal auth methods, which are not passed to authenticate; run the method in a terminal",
|
|
33
|
+
waiting: (reason) => `no model available yet (${reason}); ACP stays up — sign in from the client's terminal login or run ama auth set, then open a session again`,
|
|
34
|
+
ready: (model) => `model available (${model}); ACP sessions are served from now on`,
|
|
35
|
+
},
|
|
36
|
+
/** [ACP-B] 多会话与会话元数据。 */
|
|
37
|
+
session: {
|
|
38
|
+
notOpen: (id) => `session ${id} is not open in this connection; send session/load or session/resume first`,
|
|
39
|
+
invalidCursor: "invalid cursor (pass back the nextCursor of a previous session/list)",
|
|
40
|
+
ignoredMcp: (count) => `ACP: ignoring ${plural(count, "MCP server")} from the client (ama does not connect MCP servers)`,
|
|
41
|
+
ignoredDirs: (count) => `ACP: ignoring ${plural(count, "additional directory", "additional directories")} from the client (the workspace is fixed to the start directory)`,
|
|
42
|
+
},
|
|
43
|
+
/** [ACP-C] 工具调用映射。 */
|
|
44
|
+
tools: {
|
|
45
|
+
/** codemode 脚本里的内层调用的标题。 */
|
|
46
|
+
codemodePrefix: (title) => `codemode › ${title}`,
|
|
47
|
+
truncated: (length) => `…(truncated, ${plural(length, "character")} in total)`,
|
|
48
|
+
},
|
|
49
|
+
/** [ACP-D] 配置项与命令表。 */
|
|
50
|
+
config: {
|
|
51
|
+
model: "Model",
|
|
52
|
+
mode: "Permission mode",
|
|
53
|
+
thinking: "Thinking level",
|
|
54
|
+
levels: {
|
|
55
|
+
off: "Off",
|
|
56
|
+
minimal: "Minimal",
|
|
57
|
+
low: "Low",
|
|
58
|
+
medium: "Medium",
|
|
59
|
+
high: "High",
|
|
60
|
+
xhigh: "Extra high",
|
|
61
|
+
},
|
|
62
|
+
invalidValue: (id, value) => `invalid value for config option ${id}: ${value}`,
|
|
63
|
+
unknownModel: (ref) => `unknown model: ${ref}`,
|
|
64
|
+
},
|
|
65
|
+
/** [ACP-D] ama 作 ACP 客户端时的文案。 */
|
|
66
|
+
client: {
|
|
67
|
+
authRequired: (agent, methods) => `${agent} requires sign-in. Sign in with one of: ${methods.join("; ")}; then try again`,
|
|
68
|
+
authNoMethods: (agent) => `${agent} requires sign-in and offers no sign-in method; sign in with the agent's own CLI, then try again`,
|
|
69
|
+
authTerminal: (name, command) => `${name} (run in a terminal: ${command})`,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
export const zh = {
|
|
73
|
+
core: {
|
|
74
|
+
missingParam: (key) => `缺少 ${key}`,
|
|
75
|
+
promptNotArray: "prompt 应为内容块数组",
|
|
76
|
+
unparsable: (reason) => `ACP:无法解析的输入(${reason})`,
|
|
77
|
+
missingProtocolVersion: "缺少 protocolVersion",
|
|
78
|
+
fixedCwd: (cwd, got) => `ama --mode acp 的会话目录固定为启动目录 ${cwd}(收到 ${got})`,
|
|
79
|
+
sessionNotFound: (id, error) => `找不到会话 ${id}:${error}`,
|
|
80
|
+
modelFailed: "模型请求失败",
|
|
81
|
+
unknownMode: (mode) => `未知模式:${mode}`,
|
|
82
|
+
allowOnce: "允许",
|
|
83
|
+
allowAlways: "本会话允许",
|
|
84
|
+
rejectOnce: "拒绝",
|
|
85
|
+
unknownConfigOption: (id) => `未知配置项:${id}`,
|
|
86
|
+
},
|
|
87
|
+
auth: {
|
|
88
|
+
chatgptName: "使用 ChatGPT 登录",
|
|
89
|
+
chatgptDescription: "在终端运行 ama auth login chatgpt(ChatGPT 订阅)",
|
|
90
|
+
apiKeyName: "填写 API key",
|
|
91
|
+
apiKeyDescription: "在终端运行 ama auth set:选供应商后粘贴它的 API key",
|
|
92
|
+
notAgentMethod: "ama 只提供终端型认证方法,这类方法不经 authenticate;请在终端里运行该方法",
|
|
93
|
+
waiting: (reason) => `暂无可用模型(${reason});ACP 连接保持——在客户端的终端登录或运行 ama auth set 后再开会话`,
|
|
94
|
+
ready: (model) => `模型已可用(${model}),开始处理 ACP 会话`,
|
|
95
|
+
},
|
|
96
|
+
session: {
|
|
97
|
+
notOpen: (id) => `会话 ${id} 没有在本连接中打开;先发 session/load 或 session/resume`,
|
|
98
|
+
invalidCursor: "无效的 cursor(应原样传回上一次 session/list 的 nextCursor)",
|
|
99
|
+
ignoredMcp: (count) => `ACP:忽略客户端给的 ${count} 个 MCP 服务器(ama 不连接 MCP)`,
|
|
100
|
+
ignoredDirs: (count) => `ACP:忽略客户端给的 ${count} 个附加目录(工作目录固定为启动目录)`,
|
|
101
|
+
},
|
|
102
|
+
tools: {
|
|
103
|
+
codemodePrefix: (title) => `codemode › ${title}`,
|
|
104
|
+
truncated: (length) => `…(已截断,共 ${length} 字符)`,
|
|
105
|
+
},
|
|
106
|
+
config: {
|
|
107
|
+
model: "模型",
|
|
108
|
+
mode: "权限模式",
|
|
109
|
+
thinking: "思考级别",
|
|
110
|
+
levels: {
|
|
111
|
+
off: "关",
|
|
112
|
+
minimal: "最低",
|
|
113
|
+
low: "低",
|
|
114
|
+
medium: "中",
|
|
115
|
+
high: "高",
|
|
116
|
+
xhigh: "超高",
|
|
117
|
+
},
|
|
118
|
+
invalidValue: (id, value) => `配置项 ${id} 的值无效:${value}`,
|
|
119
|
+
unknownModel: (ref) => `未知模型:${ref}`,
|
|
120
|
+
},
|
|
121
|
+
client: {
|
|
122
|
+
authRequired: (agent, methods) => `${agent} 需要先登录。可用的登录方式:${methods.join(";")};登录后再试`,
|
|
123
|
+
authNoMethods: (agent) => `${agent} 需要先登录,但没有提供登录方式;请用它自己的命令行登录后再试`,
|
|
124
|
+
authTerminal: (name, command) => `${name}(在终端里运行:${command})`,
|
|
125
|
+
},
|
|
126
|
+
};
|
|
@@ -19,6 +19,7 @@ export declare const en: {
|
|
|
19
19
|
unknownAction: (action: string) => string;
|
|
20
20
|
setPrompt: (provider: string) => string;
|
|
21
21
|
noKeyFromStdin: string;
|
|
22
|
+
pickProvider: string;
|
|
22
23
|
saved: (provider: string, path: string) => string;
|
|
23
24
|
warning: (text: string) => string;
|
|
24
25
|
listEmpty: (path: string) => string;
|
|
@@ -116,6 +117,7 @@ export declare const zh: {
|
|
|
116
117
|
unknownAction: (action: string) => string;
|
|
117
118
|
setPrompt: (provider: string) => string;
|
|
118
119
|
noKeyFromStdin: string;
|
|
120
|
+
pickProvider: string;
|
|
119
121
|
saved: (provider: string, path: string) => string;
|
|
120
122
|
warning: (text: string) => string;
|
|
121
123
|
listEmpty: (path: string) => string;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* 文案里从不放 token、code、账户 id;邮箱只放掩码。
|
|
7
7
|
*/
|
|
8
8
|
export const en = {
|
|
9
|
-
usage: `Usage: ama auth set <provider> [--auth-file <file>] read the key from stdin
|
|
9
|
+
usage: `Usage: ama auth set [<provider>] [--auth-file <file>] read the key from stdin (no provider on a TTY: pick one)
|
|
10
10
|
ama auth list [--auth-file <file>]
|
|
11
11
|
ama auth remove <provider> [--auth-file <file>]
|
|
12
12
|
ama auth login chatgpt [--flavor siwc|codex] [--paste | --device] [--port <n>] [--no-browser] [--yes] [--auth-file <file>]
|
|
@@ -20,6 +20,7 @@ export const en = {
|
|
|
20
20
|
unknownAction: (action) => `unknown auth subcommand: ${action}`,
|
|
21
21
|
setPrompt: (provider) => `Enter the API key for ${provider} (hidden), then press Enter: `,
|
|
22
22
|
noKeyFromStdin: "no key read from stdin",
|
|
23
|
+
pickProvider: "Which provider is the API key for?",
|
|
23
24
|
saved: (provider, path) => `Saved the key for ${provider} → ${path} (0600)`,
|
|
24
25
|
warning: (text) => `ama: warning: ${text}`,
|
|
25
26
|
listEmpty: (path) => `${path}: no saved keys`,
|
|
@@ -114,7 +115,7 @@ export const en = {
|
|
|
114
115
|
},
|
|
115
116
|
};
|
|
116
117
|
export const zh = {
|
|
117
|
-
usage: `用法:ama auth set <provider> [--auth-file <文件>] 从 stdin 读取 key
|
|
118
|
+
usage: `用法:ama auth set [<provider>] [--auth-file <文件>] 从 stdin 读取 key(TTY 下不给供应商则先选)
|
|
118
119
|
ama auth list [--auth-file <文件>]
|
|
119
120
|
ama auth remove <provider> [--auth-file <文件>]
|
|
120
121
|
ama auth login chatgpt [--flavor siwc|codex] [--paste | --device] [--port <n>] [--no-browser] [--yes] [--auth-file <文件>]
|
|
@@ -128,6 +129,7 @@ export const zh = {
|
|
|
128
129
|
unknownAction: (action) => `未知的 auth 子命令:${action}`,
|
|
129
130
|
setPrompt: (provider) => `输入 ${provider} 的 API key(不回显),回车结束:`,
|
|
130
131
|
noKeyFromStdin: "没有从 stdin 读到 key",
|
|
132
|
+
pickProvider: "这个 API key 属于哪个供应商?",
|
|
131
133
|
saved: (provider, path) => `已保存 ${provider} 的 key → ${path}(0600)`,
|
|
132
134
|
warning: (text) => `ama: 警告:${text}`,
|
|
133
135
|
listEmpty: (path) => `${path}:没有保存的 key`,
|