@armadra/agent 0.9.0 → 0.9.1

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 CHANGED
@@ -5,6 +5,12 @@ English · [简体中文](CHANGELOG.zh-CN.md)
5
5
  > This file is in English starting with 0.6.0. Release notes for 0.1 through 0.5.1 are in Chinese in
6
6
  > [CHANGELOG.zh-CN.md](CHANGELOG.zh-CN.md). New entries go into both files.
7
7
 
8
+ ## 0.9.1 (2026-10-21)
9
+
10
+ ### ACP
11
+
12
+ - **`AcpClient` can serve `terminal/*`**: the new `onTerminal(method, params, signal)` constructor option makes `initialize` declare `clientCapabilities.terminal: true` and hands `terminal/create|output|wait_for_exit|kill|release` to the host; without it nothing changes on the wire. `AcpClient.features.terminal` is `true` (#218).
13
+
8
14
  ## 0.9.0 (2026-10-20)
9
15
 
10
16
  Version aligned with Armadra and armadra-cloud (all three products now share 0.9.0). No protocol constants changed.
@@ -4,6 +4,12 @@
4
4
 
5
5
  > 从 0.6.0 起 [CHANGELOG.md](CHANGELOG.md) 为英文,本文件保留中文记录(0.1–0.5.1 的完整历史在此)。新条目两份都要加。
6
6
 
7
+ ## 0.9.1(2026-10-21)
8
+
9
+ ### ACP
10
+
11
+ - **`AcpClient` 可接 `terminal/*`**:构造参数新增 `onTerminal(method, params, signal)`,给了它 `initialize` 才声明 `clientCapabilities.terminal: true`,并把 `terminal/create|output|wait_for_exit|kill|release` 交给宿主;不给时线路不变。`AcpClient.features.terminal` 为 `true`(#218)。
12
+
7
13
  ## 0.9.0(2026-10-20)
8
14
 
9
15
  版本号与 Armadra、armadra-cloud 对齐(三个产品统一为 0.9.0),协议常量无变化。
@@ -41,7 +41,7 @@ var AMA_VERSION;
41
41
  var init_version = __esm({
42
42
  "src/version.ts"() {
43
43
  "use strict";
44
- AMA_VERSION = true ? "0.9.0" : readPackageVersion();
44
+ AMA_VERSION = true ? "0.9.1" : readPackageVersion();
45
45
  }
46
46
  });
47
47
 
@@ -33890,9 +33890,10 @@ var init_client = __esm({
33890
33890
  * 本版客户端支持的可选能力,供宿主做特性检测(旧版没有这个字段,旧一点的只有 `mcpServers`):
33891
33891
  * - `mcpServers`:开会话时可经 {@link AcpSessionOptions} 传 MCP 服务器;
33892
33892
  * - `elicitation`:构造参数 `onElicitation` 接 `elicitation/create`;
33893
- * - `configOptions`:`setConfigOption` 与开会话答的 `configOptions`。
33893
+ * - `configOptions`:`setConfigOption` 与开会话答的 `configOptions`;
33894
+ * - `terminal`:构造参数 `onTerminal` 接 `terminal/*`。
33894
33895
  */
33895
- static features = { mcpServers: true, elicitation: true, configOptions: true };
33896
+ static features = { mcpServers: true, elicitation: true, configOptions: true, terminal: true };
33896
33897
  peer;
33897
33898
  /** sessionId → 挂起权限请求的取消器。 */
33898
33899
  pendingPermissions = /* @__PURE__ */ new Map();
@@ -33922,7 +33923,7 @@ var init_client = __esm({
33922
33923
  protocolVersion: ACP_PROTOCOL_VERSION,
33923
33924
  clientCapabilities: {
33924
33925
  fs: { readTextFile: false, writeTextFile: false },
33925
- terminal: false,
33926
+ terminal: this.options.onTerminal !== void 0,
33926
33927
  session: { configOptions: {} },
33927
33928
  ...this.options.onElicitation !== void 0 ? { elicitation: {} } : {}
33928
33929
  },
@@ -34007,6 +34008,8 @@ var init_client = __esm({
34007
34008
  async onRequest(method, params, connection) {
34008
34009
  if (method === ACP_METHODS.elicitationCreate && this.options.onElicitation !== void 0)
34009
34010
  return this.onElicitation(params, connection);
34011
+ if (method.startsWith("terminal/") && this.options.onTerminal !== void 0)
34012
+ return this.options.onTerminal(method, params, connection);
34010
34013
  if (method !== ACP_METHODS.requestPermission)
34011
34014
  throw new RpcError(RPC_ERRORS.methodNotFound, `client does not support ${method}`);
34012
34015
  const request = params;
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * JSON-RPC over NDJSON({@link JsonRpcPeer}),手写零依赖;`@armadra/agent/acp` 导出供 Armadra 复用。
5
5
  *
6
- * - 不声明 `fs` / `terminal` 能力:Agent 发来的 `fs/*`、`terminal/*` 请求一律 method not found。
6
+ * - 不声明 `fs` 能力:Agent 发来的 `fs/*` 请求一律 method not found。`terminal` 同理,除非构造参数给了
7
+ * `onTerminal`:此时声明 `terminal: true`,`terminal/*` 请求交给它(ama 自己作客户端不给)。
7
8
  * - `session/request_permission` 交给 `onPermission`(驱动再交给 ama 的审批通道,只交给人);
8
9
  * 没有处理器时按无人值守回首个 `reject_once`(没有则 cancelled)。
9
10
  * - `cancel(sessionId)` 发 `session/cancel` 通知,并让该会话所有挂起的权限请求回 `cancelled`
@@ -29,6 +30,12 @@ export interface AcpClientHandlers {
29
30
  * `signal`:该会话被 cancel、连接关闭时 abort(此时回 `{ action: "cancel" }`,不必再答)。
30
31
  */
31
32
  onElicitation?(params: AcpElicitationParams, signal: AbortSignal): Promise<AcpElicitationResult>;
33
+ /**
34
+ * `terminal/*`(create / output / wait_for_exit / kill / release):宿主替 Agent 起终端。给了它才声明
35
+ * `clientCapabilities.terminal: true` 并把这些请求交给它;`method` 是完整方法名,`params` 原样交回,返回值即
36
+ * 答复,抛 `RpcError` 回对应错误。`signal`:连接关闭时 abort。权限、cwd 限制与输出上限由宿主负责。
37
+ */
38
+ onTerminal?(method: string, params: unknown, signal: AbortSignal): Promise<unknown>;
32
39
  onProtocolError?(line: string, reason: string): void;
33
40
  onClose?(): void;
34
41
  }
@@ -45,12 +52,14 @@ export declare class AcpClient {
45
52
  * 本版客户端支持的可选能力,供宿主做特性检测(旧版没有这个字段,旧一点的只有 `mcpServers`):
46
53
  * - `mcpServers`:开会话时可经 {@link AcpSessionOptions} 传 MCP 服务器;
47
54
  * - `elicitation`:构造参数 `onElicitation` 接 `elicitation/create`;
48
- * - `configOptions`:`setConfigOption` 与开会话答的 `configOptions`。
55
+ * - `configOptions`:`setConfigOption` 与开会话答的 `configOptions`;
56
+ * - `terminal`:构造参数 `onTerminal` 接 `terminal/*`。
49
57
  */
50
58
  static readonly features: {
51
59
  readonly mcpServers: true;
52
60
  readonly elicitation: true;
53
61
  readonly configOptions: true;
62
+ readonly terminal: true;
54
63
  };
55
64
  private readonly peer;
56
65
  /** sessionId → 挂起权限请求的取消器。 */
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * JSON-RPC over NDJSON({@link JsonRpcPeer}),手写零依赖;`@armadra/agent/acp` 导出供 Armadra 复用。
5
5
  *
6
- * - 不声明 `fs` / `terminal` 能力:Agent 发来的 `fs/*`、`terminal/*` 请求一律 method not found。
6
+ * - 不声明 `fs` 能力:Agent 发来的 `fs/*` 请求一律 method not found。`terminal` 同理,除非构造参数给了
7
+ * `onTerminal`:此时声明 `terminal: true`,`terminal/*` 请求交给它(ama 自己作客户端不给)。
7
8
  * - `session/request_permission` 交给 `onPermission`(驱动再交给 ama 的审批通道,只交给人);
8
9
  * 没有处理器时按无人值守回首个 `reject_once`(没有则 cancelled)。
9
10
  * - `cancel(sessionId)` 发 `session/cancel` 通知,并让该会话所有挂起的权限请求回 `cancelled`
@@ -50,9 +51,10 @@ export class AcpClient {
50
51
  * 本版客户端支持的可选能力,供宿主做特性检测(旧版没有这个字段,旧一点的只有 `mcpServers`):
51
52
  * - `mcpServers`:开会话时可经 {@link AcpSessionOptions} 传 MCP 服务器;
52
53
  * - `elicitation`:构造参数 `onElicitation` 接 `elicitation/create`;
53
- * - `configOptions`:`setConfigOption` 与开会话答的 `configOptions`。
54
+ * - `configOptions`:`setConfigOption` 与开会话答的 `configOptions`;
55
+ * - `terminal`:构造参数 `onTerminal` 接 `terminal/*`。
54
56
  */
55
- static features = { mcpServers: true, elicitation: true, configOptions: true };
57
+ static features = { mcpServers: true, elicitation: true, configOptions: true, terminal: true };
56
58
  peer;
57
59
  /** sessionId → 挂起权限请求的取消器。 */
58
60
  pendingPermissions = new Map();
@@ -105,7 +107,7 @@ export class AcpClient {
105
107
  protocolVersion: ACP_PROTOCOL_VERSION,
106
108
  clientCapabilities: {
107
109
  fs: { readTextFile: false, writeTextFile: false },
108
- terminal: false,
110
+ terminal: this.options.onTerminal !== undefined,
109
111
  session: { configOptions: {} },
110
112
  ...(this.options.onElicitation !== undefined ? { elicitation: {} } : {}),
111
113
  },
@@ -175,6 +177,8 @@ export class AcpClient {
175
177
  async onRequest(method, params, connection) {
176
178
  if (method === ACP_METHODS.elicitationCreate && this.options.onElicitation !== undefined)
177
179
  return this.onElicitation(params, connection);
180
+ if (method.startsWith("terminal/") && this.options.onTerminal !== undefined)
181
+ return this.options.onTerminal(method, params, connection);
178
182
  if (method !== ACP_METHODS.requestPermission)
179
183
  throw new RpcError(RPC_ERRORS.methodNotFound, `client does not support ${method}`);
180
184
  const request = params;
@@ -149,7 +149,7 @@ The model uses ACP agents through `task(agent="acp:<program>")` (ama itself is `
149
149
 
150
150
  `AcpClient` (`@armadra/agent/acp`): `initialize`, `newSession`, `resumeSession` (preferred, no replay), `loadSession`, `listSessions`, `closeSession`, `prompt`, `setMode`, `cancel`.
151
151
 
152
- - Declared client capabilities: `session.configOptions: {}` (select options; boolean is not declared); `fs` / `terminal` are not declared (`fs/*` and `terminal/*` requests from the agent answer method not found), and neither is `auth.terminal` (ama has no interactive terminal to lend to the agent).
152
+ - Declared client capabilities: `session.configOptions: {}` (select options; boolean is not declared); `fs` is not declared (`fs/*` requests from the agent answer method not found) and `terminal` only when `onTerminal` is given (see below), and neither is `auth.terminal` (ama has no interactive terminal to lend to the agent).
153
153
  - `$/cancel_request` is on in both directions: aborting the `signal` of a request after it was sent tells the agent to withdraw it; when the agent withdraws a pending `session/request_permission` / `elicitation/create`, the handler's `signal` aborts and the answer is `cancelled` / `cancel` (a choice the handler makes afterwards does not count).
154
154
  - `session/request_permission` goes to `onPermission`; without a handler the first `reject_once` is answered (unattended).
155
155
  - `cancel(sessionId)` sends `session/cancel` and answers `cancelled` to that session's pending permission requests (required by the spec).
@@ -157,7 +157,8 @@ The model uses ACP agents through `task(agent="acp:<program>")` (ama itself is `
157
157
  - `mcpServers` of session-open calls (`newSession` / `resumeSession` / `loadSession`) defaults to an empty array; a host can pass a third argument `{ mcpServers }` (for stdio, `{ name, command, args, env: [{ name, value }] }`), which is forwarded to the agent as is. `AcpClient.features.mcpServers === true` signals support (older versions have no `features`). ama itself, as a client, still passes none.
158
158
  - `elicitation/create` (the agent asking a human for structured input): only when the constructor is given `onElicitation(params, signal)` does `initialize` declare `clientCapabilities.elicitation` and accept this request; otherwise it is not declared and the request answers method not found (as in older versions). Answers are normalized to `{ action: "accept" | "decline" | "cancel", content? }` (`content` only with accept; unknown actions count as cancel); pending ones answer `{ action: "cancel" }` on `cancel(sessionId)` and when the connection closes. ama itself, as a client, gives no handler and never fills in forms for a human.
159
159
  - Session config options: the `configOptions` of session-open answers (new / load / resume) are passed through; `setConfigOption(sessionId, configId, value)` sends `session/set_config_option`, and the answer is the new state of all options.
160
- - `AcpClient.features`: `{ mcpServers, elicitation, configOptions }`, for feature detection by hosts.
160
+ - `terminal/*` (the agent asking the host for a terminal): only when the constructor is given `onTerminal(method, params, signal)` does `initialize` declare `clientCapabilities.terminal: true`; `terminal/create|output|wait_for_exit|kill|release` are then handed to it with the params untouched, its return value is the answer and throwing `RpcError` answers with that error. Without it `terminal: false` is declared and the requests answer method not found (as in older versions). Permissions, cwd restriction and output limits are the host's job; ama itself, as a client, gives no handler.
161
+ - `AcpClient.features`: `{ mcpServers, elicitation, configOptions, terminal }`, for feature detection by hosts.
161
162
 
162
163
  `AcpDriver` implements the driver contract (`AgentDriver`) on top of the client:
163
164
 
@@ -155,8 +155,8 @@ stdin 关闭后等已开始的运行结束再退出(0);`ama` 进程的 std
155
155
 
156
156
  `AcpClient`(`@armadra/agent/acp`):`initialize`、`newSession`、`resumeSession`(优先,不回放)、`loadSession`、`listSessions`、`closeSession`、`prompt`、`setMode`、`cancel`。
157
157
 
158
- - 声明的客户端能力:`session.configOptions: {}`(接 select 型配置项,不声明 boolean);不声明 `fs` / `terminal`(Agent 发来的
159
- `fs/*`、`terminal/*` 请求回 method not found),也不声明 `auth.terminal`(ama 没有可借给 Agent 的交互终端)。
158
+ - 声明的客户端能力:`session.configOptions: {}`(接 select 型配置项,不声明 boolean);不声明 `fs`(Agent 发来的 `fs/*` 请求回 method not found);`terminal` 只在构造参数给了
159
+ `onTerminal` 时声明(见下),也不声明 `auth.terminal`(ama 没有可借给 Agent 的交互终端)。
160
160
  - 线路两侧开 `$/cancel_request`:本端请求的 `signal` 在发出后 abort 会通知 Agent 撤回;Agent 撤回挂起的
161
161
  `session/request_permission` / `elicitation/create` 时处理器的 `signal` abort,答 `cancelled` / `cancel`(处理器之后给的选择不作数)。
162
162
  - `session/request_permission` 交给 `onPermission`;没有处理器时回首个 `reject_once`(无人值守)。
@@ -171,7 +171,11 @@ stdin 关闭后等已开始的运行结束再退出(0);`ama` 进程的 std
171
171
  与连接关闭时挂起的一律回 `{ action: "cancel" }`。ama 自己作客户端时不给处理器,从不替人填表。
172
172
  - 会话配置项:开会话(new / load / resume)答的 `configOptions` 原样交回;`setConfigOption(sessionId, configId, value)` 发
173
173
  `session/set_config_option`,答复是全部配置项的新状态。
174
- - `AcpClient.features`:`{ mcpServers, elicitation, configOptions }`,宿主据此做特性检测。
174
+ - `terminal/*`(Agent 向宿主要终端):构造参数给了 `onTerminal(method, params, signal)` 才在 `initialize` 声明
175
+ `clientCapabilities.terminal: true`,并把 `terminal/create|output|wait_for_exit|kill|release` 连同原样参数交给它,返回值即答复,
176
+ 抛 `RpcError` 回对应错误;没给时声明 `terminal: false`、请求回 method not found(与旧版相同)。权限、cwd 限制与输出上限由宿主负责;
177
+ ama 自己作客户端时不给处理器。
178
+ - `AcpClient.features`:`{ mcpServers, elicitation, configOptions, terminal }`,宿主据此做特性检测。
175
179
 
176
180
  `AcpDriver` 在客户端之上实现驱动契约(`AgentDriver`):
177
181
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@armadra/agent",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "A coding and coordination agent that runs standalone or embedded in Armadra",
5
5
  "type": "module",
6
6
  "keywords": [