@agentclientprotocol/claude-agent-acp 0.89.2-preview.8 → 0.90.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.
Files changed (52) hide show
  1. package/README.md +51 -8
  2. package/dist/acp-agent.d.ts +52 -3
  3. package/dist/acp-agent.d.ts.map +1 -1
  4. package/dist/acp-agent.js +507 -139
  5. package/dist/acp-subagents.d.ts +16 -6
  6. package/dist/acp-subagents.d.ts.map +1 -1
  7. package/dist/acp-subagents.js +8 -2
  8. package/dist/async-tasks.d.ts +4 -1
  9. package/dist/async-tasks.d.ts.map +1 -1
  10. package/dist/auth-status.d.ts +2 -2
  11. package/dist/auth-status.d.ts.map +1 -1
  12. package/dist/auth-status.js +18 -4
  13. package/dist/exit-plan.d.ts +17 -0
  14. package/dist/exit-plan.d.ts.map +1 -1
  15. package/dist/exit-plan.js +34 -0
  16. package/dist/native-subagents.d.ts +190 -11
  17. package/dist/native-subagents.d.ts.map +1 -1
  18. package/dist/native-subagents.js +419 -40
  19. package/dist/settings.d.ts +6 -0
  20. package/dist/settings.d.ts.map +1 -1
  21. package/dist/settings.js +13 -0
  22. package/dist/subagent-history.d.ts +27 -2
  23. package/dist/subagent-history.d.ts.map +1 -1
  24. package/dist/subagent-history.js +38 -10
  25. package/dist/subagent-replay.d.ts +108 -0
  26. package/dist/subagent-replay.d.ts.map +1 -0
  27. package/dist/subagent-replay.js +261 -0
  28. package/dist/tool-calls/background.d.ts +9 -0
  29. package/dist/tool-calls/background.d.ts.map +1 -1
  30. package/dist/tool-calls/background.js +25 -0
  31. package/dist/tool-calls/renderer.d.ts +30 -9
  32. package/dist/tool-calls/renderer.d.ts.map +1 -1
  33. package/dist/tool-calls/renderer.js +48 -22
  34. package/dist/tool-calls/reporters/bash.d.ts +7 -0
  35. package/dist/tool-calls/reporters/bash.d.ts.map +1 -1
  36. package/dist/tool-calls/reporters/bash.js +16 -1
  37. package/dist/tool-calls/reporters/search.d.ts.map +1 -1
  38. package/dist/tool-calls/reporters/search.js +20 -2
  39. package/dist/v2/agent.d.ts.map +1 -1
  40. package/dist/v2/agent.js +45 -12
  41. package/dist/v2/initialize.d.ts.map +1 -1
  42. package/dist/v2/initialize.js +10 -1
  43. package/dist/v2/session-update.d.ts +11 -0
  44. package/dist/v2/session-update.d.ts.map +1 -1
  45. package/dist/v2/session-update.js +67 -0
  46. package/dist/v2/session.d.ts +3 -12
  47. package/dist/v2/session.d.ts.map +1 -1
  48. package/dist/v2/session.js +5 -18
  49. package/dist/v2/tool-call-meta.d.ts +44 -0
  50. package/dist/v2/tool-call-meta.d.ts.map +1 -0
  51. package/dist/v2/tool-call-meta.js +72 -0
  52. package/package.json +9 -9
@@ -84,16 +84,32 @@ export declare class AcpToolCallRenderer {
84
84
  /** True when the renderer reports the history of a loaded session. */
85
85
  replay?: boolean);
86
86
  static for(capabilities: AcpClientCapabilities | null | undefined, replay?: boolean): AcpToolCallRenderer;
87
+ /**
88
+ * Whether the client keeps a tool call's `_meta` across reports: AIR merges
89
+ * its keys, and v2 stores it. Such a client gets no `toolResponse` text that
90
+ * the tool call's content already shows, which it would otherwise keep.
91
+ */
92
+ private get keepsMeta();
87
93
  /**
88
94
  * The status of a tool result. Claude Code reports a run that it aborted in
89
- * one of two ways: an error result whose `nonExecution` kind says so (a
90
- * cancelled turn), or a command result that says `interrupted` (for example,
91
- * a steering message landed just before the command started). Such a run is
92
- * `cancelled` for a v2 client, which has that status. Every other client gets
93
- * `failed` for the error, with the kind in `_meta.claudeCode.nonExecutionKind`,
94
- * and `completed` for the command.
95
+ * one of three ways:
96
+ * - an error result whose `nonExecution` kind says so (`interrupted`,
97
+ * `cancelled`);
98
+ * - a command result that says `interrupted` (for example, a steering
99
+ * message landed just before the command started);
100
+ * - any error result of the work that a `session/cancel` stopped
101
+ * (`run.cancelled`). The kind does not say so there: CLI 2.1.293 stamps a
102
+ * command that the interrupt killed `user-rejected`, as if the user had
103
+ * refused it.
104
+ *
105
+ * Such a run is `cancelled` for a v2 client, which has that status. Every
106
+ * other client gets `failed` for the error, with the kind in
107
+ * `_meta.claudeCode.nonExecutionKind`, and `completed` for the command.
95
108
  */
96
- resultStatus(isError: boolean, nonExecution: ToolResultMeta | undefined, interrupted?: boolean): ToolCallStatus;
109
+ resultStatus(isError: boolean, nonExecution: ToolResultMeta | undefined, run?: {
110
+ interrupted?: boolean;
111
+ cancelled?: boolean;
112
+ }): ToolCallStatus;
97
113
  /** The facts of a tool use. */
98
114
  facts(toolUse: Pick<ToolUse, "name" | "input">, cwd?: string): ToolUseFacts;
99
115
  /** The standard fields of a tool use: the title, the kind, the content, and the locations. */
@@ -159,6 +175,7 @@ export declare class AcpToolCallRenderer {
159
175
  result(toolUse: ToolUse, result: ResultBlock, options?: {
160
176
  structured?: unknown;
161
177
  nonExecution?: ToolResultMeta;
178
+ cancelled?: boolean;
162
179
  }): ToolCallUpdate[];
163
180
  /**
164
181
  * Whether AIR shows [toolUse] as the list of viewed files: a read or a
@@ -169,7 +186,8 @@ export declare class AcpToolCallRenderer {
169
186
  /**
170
187
  * The report of a PostToolUse hook: the final change of an edit tool, and
171
188
  * the `status` and `isAsync` markers of the `tool_response`. The rest of the
172
- * `tool_response` repeats output that the content already carries.
189
+ * `tool_response` repeats output that the content already carries, such as
190
+ * the whole text of a written file.
173
191
  */
174
192
  hookResult(toolUse: Pick<ToolUse, "id" | "name">, toolResponse: unknown, cwd?: string): Promise<ToolCallUpdate | undefined>;
175
193
  /**
@@ -203,11 +221,14 @@ export declare class AcpToolCallRenderer {
203
221
  * reached a complete assistant message, for example because Claude switched
204
222
  * to a steering message), a v2 client gets `cancelled` and every other
205
223
  * client `failed`, since v1 has no `cancelled`. If Claude Code ran it but
206
- * returned no result, it failed.
224
+ * returned no result, it failed, unless a `session/cancel` ended the turn
225
+ * (`cancelled`): the cancel stopped the run, so a v2 client gets `cancelled`
226
+ * for it too.
207
227
  */
208
228
  unfinished(call: {
209
229
  toolCallId: string;
210
230
  ran: boolean;
231
+ cancelled?: boolean;
211
232
  }): ToolCallUpdate;
212
233
  /**
213
234
  * The report of a tool progress beat. The field tracker sends the
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/tool-calls/renderer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/tool-calls/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,IAAI,qBAAqB,EAC3C,wBAAwB,EACxB,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,cAAc,EACf,MAAM,0BAA0B,CAAC;AAQlC,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAClF,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM5F,MAAM,MAAM,cAAc,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;AAa3D,wFAAwF;AACxF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAExF;AAED,yCAAyC;AACzC,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,CAAC,EAAE;QAKX,QAAQ,CAAC,EAAE,MAAM,CAAC;QAKlB,YAAY,CAAC,EAAE,OAAO,CAAC;QAIvB,eAAe,CAAC,EAAE,MAAM,CAAC;QAMzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAG1B,YAAY,CAAC,EAAE,MAAM,CAAC;QAEtB,SAAS,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC;KAC9C,CAAC;IAEF,SAAS,CAAC,EAAE;QACV,GAAG,CAAC,EAAE;YACJ,OAAO,CAAC,EAAE,MAAM,CAAC;YAGjB,YAAY,CAAC,EAAE,MAAM,CAAC;YAGtB,QAAQ,CAAC,EAAE,IAAI,CAAC;YAGhB,KAAK,CAAC,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,IAAI,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC;YACxC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;SACxB,CAAC;KACH,CAAC;IAEF,gBAAgB,CAAC,EAAE,IAAI,CAAC;IAExB,aAAa,CAAC,EAAE;QACd,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,eAAe,CAAC,EAAE;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,qBAAqB,CAAC,EAAE;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,aAAa,CAAC,EAAE;QACd,WAAW,EAAE,MAAM,CAAC;QACpB;;;WAGG;QACH,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;KACvB,CAAC;CACH,CAAC;AAEF,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC/B,wDAAwD;IACxD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,KAAK,CAAC,EAAE,IAAI,CACV,cAAc,EACd,eAAe,GAAG,iBAAiB,GAAG,uBAAuB,GAAG,eAAe,CAChF,CAAC;CACH;AAED,4DAA4D;AAC5D,KAAK,WAAW,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;AAE/C;;;;;;;;GAQG;AACH,qBAAa,mBAAmB;IAE5B,QAAQ,CAAC,YAAY,EAAE,kBAAkB;IACzC,sEAAsE;IACtE,QAAQ,CAAC,MAAM;gBAFN,YAAY,GAAE,kBAA6C;IACpE,sEAAsE;IAC7D,MAAM,UAAQ;IAGzB,MAAM,CAAC,GAAG,CACR,YAAY,EAAE,qBAAqB,GAAG,IAAI,GAAG,SAAS,EACtD,MAAM,UAAQ,GACb,mBAAmB;IAItB;;;;OAIG;IACH,OAAO,KAAK,SAAS,GAEpB;IAED;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CACV,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,cAAc,GAAG,SAAS,EACxC,GAAG,GAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO,GACvD,cAAc;IAQjB,+BAA+B;IAC/B,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY;IAQ3E,8FAA8F;IAC9F,QAAQ,CACN,OAAO,EAAE,OAAO,EAChB,GAAG,CAAC,EAAE,MAAM,GACX;QACD,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;QAC3B,OAAO,EAAE,eAAe,EAAE,CAAC;QAC3B,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;KAChC;IAUD;;;OAGG;IACH,QAAQ,CACN,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,CAAC;QAAC,cAAc,CAAC,EAAE,eAAe,EAAE,CAAA;KAAO,GAC1F,cAAc;IA4BjB,6DAA6D;IAC7D,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc;IAc1D;;;;;;OAMG;IACH,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM;;;;;;;;;IAarF;;;;;OAKG;IACH,kBAAkB,CAChB,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE;QACP,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,cAAc,CAAC,EAAE,eAAe,EAAE,CAAC;QACnC,cAAc,CAAC,EAAE,gBAAgB,EAAE,CAAC;QACpC,IAAI,CAAC,EAAE,cAAc,CAAC;QACtB,4EAA4E;QAC5E,eAAe,CAAC,EAAE,eAAe,EAAE,CAAC;KAChC,GACL,wBAAwB,CAAC,UAAU,CAAC;IAgCvC,kCAAkC;IAClC,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE,OAAO,GAAG,eAAe;IAqBzF,+EAA+E;IAC/E,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE,OAAO,GAAG,cAAc;IAIzF,OAAO,CAAC,cAAc;IA0DtB;;;;;OAKG;IACH,MAAM,CACJ,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,cAAc,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO,GACzF,cAAc,EAAE;IA2EnB;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAWvB;;;;;OAKG;IACG,UAAU,CACd,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,MAAM,CAAC,EACrC,YAAY,EAAE,OAAO,EACrB,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IA4BtC;;;OAGG;IACH,YAAY,CAAC,MAAM,EAAE;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;KAChD,GAAG,cAAc;IAyBlB;;;;OAIG;IACH,gBAAgB,CAAC,MAAM,EAAE;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,cAAc;IA2BlB;;;;;;;;;OASG;IACH,UAAU,CAAC,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,cAAc;IAkB3F;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,aAAa,CAAC,EAAE,OAAO,CAAC;KACzB,GAAG,cAAc;IAsBlB;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO;IAgBzD;;;;OAIG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,eAAe,EAAE;IAS1E;;;;;OAKG;IACH,WAAW,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc;CAyBtF"}
@@ -5,6 +5,7 @@ import { ClientCapabilities } from "./client-capabilities.js";
5
5
  import { resultText, textContent, toAcpContentUpdate, toolResponseMarkers } from "./content.js";
6
6
  import { reporterFor } from "./reporters/index.js";
7
7
  import { resolveSkillPath } from "./reporters/interaction.js";
8
+ import { shellDescription } from "./reporters/bash.js";
8
9
  import { grepPath } from "./reporters/search.js";
9
10
  /** The id suffix of the call that clears the plan file of an approved plan for AIR. */
10
11
  const PLAN_FILE_CLEAR_SUFFIX = ":plan-file-clear";
@@ -40,17 +41,33 @@ export class AcpToolCallRenderer {
40
41
  static for(capabilities, replay = false) {
41
42
  return new AcpToolCallRenderer(ClientCapabilities.from(capabilities), replay);
42
43
  }
44
+ /**
45
+ * Whether the client keeps a tool call's `_meta` across reports: AIR merges
46
+ * its keys, and v2 stores it. Such a client gets no `toolResponse` text that
47
+ * the tool call's content already shows, which it would otherwise keep.
48
+ */
49
+ get keepsMeta() {
50
+ return this.capabilities.air.client || this.capabilities.v2;
51
+ }
43
52
  /**
44
53
  * The status of a tool result. Claude Code reports a run that it aborted in
45
- * one of two ways: an error result whose `nonExecution` kind says so (a
46
- * cancelled turn), or a command result that says `interrupted` (for example,
47
- * a steering message landed just before the command started). Such a run is
48
- * `cancelled` for a v2 client, which has that status. Every other client gets
49
- * `failed` for the error, with the kind in `_meta.claudeCode.nonExecutionKind`,
50
- * and `completed` for the command.
54
+ * one of three ways:
55
+ * - an error result whose `nonExecution` kind says so (`interrupted`,
56
+ * `cancelled`);
57
+ * - a command result that says `interrupted` (for example, a steering
58
+ * message landed just before the command started);
59
+ * - any error result of the work that a `session/cancel` stopped
60
+ * (`run.cancelled`). The kind does not say so there: CLI 2.1.293 stamps a
61
+ * command that the interrupt killed `user-rejected`, as if the user had
62
+ * refused it.
63
+ *
64
+ * Such a run is `cancelled` for a v2 client, which has that status. Every
65
+ * other client gets `failed` for the error, with the kind in
66
+ * `_meta.claudeCode.nonExecutionKind`, and `completed` for the command.
51
67
  */
52
- resultStatus(isError, nonExecution, interrupted = false) {
53
- const aborted = interrupted || (isError && isAbortedToolResult(nonExecution));
68
+ resultStatus(isError, nonExecution, run = {}) {
69
+ const aborted = run.interrupted === true ||
70
+ (isError && (run.cancelled === true || isAbortedToolResult(nonExecution)));
54
71
  if (this.capabilities.v2 && aborted)
55
72
  return V2_CANCELLED;
56
73
  return isError ? "failed" : "completed";
@@ -306,7 +323,10 @@ export class AcpToolCallRenderer {
306
323
  },
307
324
  toolCallId: toolUse.id,
308
325
  sessionUpdate: "tool_call_update",
309
- status: this.resultStatus(result.is_error === true, options.nonExecution, facts.command?.interrupted === true),
326
+ status: this.resultStatus(result.is_error === true, options.nonExecution, {
327
+ interrupted: facts.command?.interrupted === true,
328
+ cancelled: options.cancelled,
329
+ }),
310
330
  ...(rawOutput !== undefined ? { rawOutput } : {}),
311
331
  ...(planFilePath ? { rawInput: planFileInput(toolUse.input, planFilePath) } : {}),
312
332
  ...fields,
@@ -346,14 +366,15 @@ export class AcpToolCallRenderer {
346
366
  /**
347
367
  * The report of a PostToolUse hook: the final change of an edit tool, and
348
368
  * the `status` and `isAsync` markers of the `tool_response`. The rest of the
349
- * `tool_response` repeats output that the content already carries.
369
+ * `tool_response` repeats output that the content already carries, such as
370
+ * the whole text of a written file.
350
371
  */
351
372
  async hookResult(toolUse, toolResponse, cwd) {
352
373
  const reporter = reporterFor(toolUse.name);
353
374
  const change = reporter.hookResult
354
375
  ? await reporter.hookResult(toolResponse, { cwd, capabilities: this.capabilities })
355
376
  : {};
356
- if (!this.capabilities.air.client) {
377
+ if (!this.keepsMeta) {
357
378
  // The upstream shape: the whole tool_response, on every hook.
358
379
  return {
359
380
  _meta: { claudeCode: { toolResponse, toolName: toolUse.name } },
@@ -409,9 +430,10 @@ export class AcpToolCallRenderer {
409
430
  */
410
431
  permissionDenied(denial) {
411
432
  const reason = denial.decisionReason ?? denial.message;
412
- // AIR gets the SDK message only when it differs from the reason, which
413
- // the content shows. Every other client gets the upstream toolResponse.
414
- const extraMessage = !this.capabilities.air.client
433
+ // AIR and v2 get the SDK message only when it differs from the reason,
434
+ // which the content shows. Every other client gets the upstream
435
+ // toolResponse.
436
+ const extraMessage = !this.keepsMeta
415
437
  ? { decisionReason: denial.decisionReason, message: denial.message }
416
438
  : denial.decisionReason !== undefined &&
417
439
  denial.message !== undefined &&
@@ -438,17 +460,22 @@ export class AcpToolCallRenderer {
438
460
  * reached a complete assistant message, for example because Claude switched
439
461
  * to a steering message), a v2 client gets `cancelled` and every other
440
462
  * client `failed`, since v1 has no `cancelled`. If Claude Code ran it but
441
- * returned no result, it failed.
463
+ * returned no result, it failed, unless a `session/cancel` ended the turn
464
+ * (`cancelled`): the cancel stopped the run, so a v2 client gets `cancelled`
465
+ * for it too.
442
466
  */
443
467
  unfinished(call) {
468
+ const stopped = !call.ran || call.cancelled === true;
444
469
  return {
445
470
  sessionUpdate: "tool_call_update",
446
471
  toolCallId: call.toolCallId,
447
- status: !call.ran && this.capabilities.v2 ? V2_CANCELLED : "failed",
472
+ status: stopped && this.capabilities.v2 ? V2_CANCELLED : "failed",
448
473
  content: [
449
- textContent(call.ran
450
- ? "Claude ended the turn without returning a result for this tool."
451
- : "Claude stopped this tool call before it ran."),
474
+ textContent(!call.ran
475
+ ? "Claude stopped this tool call before it ran."
476
+ : call.cancelled
477
+ ? "The turn was cancelled before this tool call returned a result."
478
+ : "Claude ended the turn without returning a result for this tool."),
452
479
  ],
453
480
  };
454
481
  }
@@ -519,9 +546,8 @@ export class AcpToolCallRenderer {
519
546
  const input = toolUse.input !== null && typeof toolUse.input === "object"
520
547
  ? toolUse.input
521
548
  : {};
522
- const description = (toolUse.name === "Bash" || toolUse.name === "PowerShell") &&
523
- typeof input.description === "string"
524
- ? input.description
549
+ const description = toolUse.name === "Bash" || toolUse.name === "PowerShell"
550
+ ? shellDescription(input)
525
551
  : undefined;
526
552
  const skillName = toolUse.name === "Skill" && typeof input.skill === "string" ? input.skill : undefined;
527
553
  const subagent = toolUse.name === "Agent" || toolUse.name === "Task";
@@ -1,4 +1,11 @@
1
1
  import type { ToolReporter, ToolResultContext, ToolResultFacts, ToolUseFacts } from "../facts.js";
2
+ /**
3
+ * Reads a Bash or PowerShell input's description the way the CLI validates it.
4
+ * Since CLI 2.1.295 the CLI accepts `command_description` for `description`.
5
+ * The streamed tool use keeps the original key. The canonical key wins when
6
+ * both spellings are present.
7
+ */
8
+ export declare function shellDescription(input: unknown): string | undefined;
2
9
  /** Bash and PowerShell: a command whose output goes to the terminal channel. */
3
10
  export declare class BashReporter implements ToolReporter {
4
11
  toolUse(input: unknown): ToolUseFacts;
@@ -1 +1 @@
1
- {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/tool-calls/reporters/bash.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAElG,gFAAgF;AAChF,qBAAa,YAAa,YAAW,YAAY;IAC/C,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY;IAUrC,iFAAiF;IACjF,WAAW,CAAC,OAAO,EAAE,iBAAiB,GAAG,eAAe,GAAG,SAAS;IAIpE,UAAU,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,iBAAiB,GAAG,eAAe;CAsFvE"}
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/tool-calls/reporters/bash.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAElG;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAKnE;AAED,gFAAgF;AAChF,qBAAa,YAAa,YAAW,YAAY;IAC/C,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY;IAWrC,iFAAiF;IACjF,WAAW,CAAC,OAAO,EAAE,iBAAiB,GAAG,eAAe,GAAG,SAAS;IAIpE,UAAU,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,iBAAiB,GAAG,eAAe;CAsFvE"}
@@ -1,13 +1,28 @@
1
1
  import { structuredResult, textContent, toAcpContentUpdate } from "../content.js";
2
+ /**
3
+ * Reads a Bash or PowerShell input's description the way the CLI validates it.
4
+ * Since CLI 2.1.295 the CLI accepts `command_description` for `description`.
5
+ * The streamed tool use keeps the original key. The canonical key wins when
6
+ * both spellings are present.
7
+ */
8
+ export function shellDescription(input) {
9
+ if (!input || typeof input !== "object")
10
+ return undefined;
11
+ const raw = input;
12
+ if (typeof raw.description === "string")
13
+ return raw.description;
14
+ return typeof raw.command_description === "string" ? raw.command_description : undefined;
15
+ }
2
16
  /** Bash and PowerShell: a command whose output goes to the terminal channel. */
3
17
  export class BashReporter {
4
18
  toolUse(input) {
5
19
  const bash = input;
20
+ const description = shellDescription(input);
6
21
  return {
7
22
  title: bash?.command ? bash.command : "Terminal",
8
23
  kind: "execute",
9
24
  command: true,
10
- ...(bash?.description ? { display: [textContent(bash.description)] } : {}),
25
+ ...(description ? { display: [textContent(description)] } : {}),
11
26
  };
12
27
  }
13
28
  /** A client with a terminal reads a failed command from the terminal channel. */
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/tool-calls/reporters/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE9D,iDAAiD;AACjD,qBAAa,YAAa,YAAW,YAAY;IAC/C,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY;CAWtC;AAED,2DAA2D;AAC3D,qBAAa,YAAa,YAAW,YAAY;IAC/C,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY;CAmBtC;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAK3D"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/tool-calls/reporters/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE9D,iDAAiD;AACjD,qBAAa,YAAa,YAAW,YAAY;IAC/C,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY;CAWtC;AAED,2DAA2D;AAC3D,qBAAa,YAAa,YAAW,YAAY;IAC/C,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY;CAoBtC;AAgBD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAK3D"}
@@ -29,9 +29,10 @@ export class GrepReporter {
29
29
  label += ` -B ${grep["-B"]}`;
30
30
  if (grep?.["-C"] !== undefined)
31
31
  label += ` -C ${grep["-C"]}`;
32
- if (grep?.output_mode === "files_with_matches")
32
+ const outputMode = grepOutputMode(input);
33
+ if (outputMode === "files_with_matches")
33
34
  label += " -l";
34
- else if (grep?.output_mode === "count")
35
+ else if (outputMode === "count")
35
36
  label += " -c";
36
37
  if (grep?.head_limit !== undefined)
37
38
  label += ` | head -${grep.head_limit}`;
@@ -49,6 +50,23 @@ export class GrepReporter {
49
50
  return { title: label, kind: "search" };
50
51
  }
51
52
  }
53
+ /**
54
+ * Reads a Grep input's output mode the way the CLI validates it. Since CLI
55
+ * 2.1.295 the CLI reads a `-l` or `-c` flag (`true` or `"true"`) as
56
+ * `output_mode: "files_with_matches"` or `"count"` when `output_mode` is unset.
57
+ */
58
+ function grepOutputMode(input) {
59
+ if (!input || typeof input !== "object")
60
+ return undefined;
61
+ const raw = input;
62
+ if (typeof raw.output_mode === "string")
63
+ return raw.output_mode;
64
+ if (raw["-l"] === true || raw["-l"] === "true")
65
+ return "files_with_matches";
66
+ if (raw["-c"] === true || raw["-c"] === "true")
67
+ return "count";
68
+ return undefined;
69
+ }
52
70
  /**
53
71
  * Reads a Grep input's path the way the CLI validates it. Since CLI 2.1.292
54
72
  * the CLI accepts `file_path` for `path`. The streamed tool use keeps the
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/v2/agent.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,MAAM,0CAA0C,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAkB,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAmB9E;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GACvC,EAAE,CAAC,QAAQ,CA0Eb"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/v2/agent.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,MAAM,0CAA0C,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAkB,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAoB9E;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GACvC,EAAE,CAAC,QAAQ,CA2Eb"}
package/dist/v2/agent.js CHANGED
@@ -3,9 +3,10 @@ import { ClaudeAcpAgent } from "../acp-agent.js";
3
3
  import { v1InitializeRequest, v2InitializeResponse } from "./initialize.js";
4
4
  import { v1PermissionResponse, v2PermissionRequest } from "./permission.js";
5
5
  import { v2Foreground, v2Prompt } from "./prompt.js";
6
- import { v1ForkSessionRequests, v1NewSessionRequest, v1RestoreSessionRequest, v1SetSessionConfigOptionRequest, v2AvailableCommands, v2ConfigOptions, v2NewSessionResponse, v2ResumeSessionResponse, } from "./session.js";
7
- import { v2SessionUpdate } from "./session-update.js";
6
+ import { v1ForkSessionRequest, v1NewSessionRequest, v1RestoreSessionRequest, v1SetSessionConfigOptionRequest, v2AvailableCommands, v2ConfigOptions, v2NewSessionResponse, v2ResumeSessionResponse, } from "./session.js";
7
+ import { v2ChildStateUpdate, v2SessionUpdate } from "./session-update.js";
8
8
  import { V2Terminals } from "./terminal.js";
9
+ import { V2ToolCallMeta } from "./tool-call-meta.js";
9
10
  /**
10
11
  * The ACP v2 surface, for one connection.
11
12
  *
@@ -55,17 +56,18 @@ export function v2AgentApp(logger, onAgent) {
55
56
  };
56
57
  })
57
58
  .onRequest(v2.methods.agent.session.fork, async ({ params }) => {
58
- const requests = v1ForkSessionRequests(params);
59
- const { sessionId } = await agent.unstable_forkSession(requests.fork);
59
+ // The agent starts the forked session, so the client can prompt it.
60
+ const response = await agent.unstable_forkSession(v1ForkSessionRequest(params));
60
61
  return {
61
- sessionId,
62
- ...v2ResumeSessionResponse(await agent.resumeSession(requests.resume(sessionId))),
63
- ...(await setupCommands(agent, sessionId, logger)),
62
+ sessionId: response.sessionId,
63
+ ...v2ResumeSessionResponse(response),
64
+ ...(await setupCommands(agent, response.sessionId, logger)),
64
65
  };
65
66
  })
66
67
  .onRequest(v2.methods.agent.session.close, async ({ params }) => {
67
68
  const response = await agent.closeSession(params);
68
69
  client.terminals.forget(params.sessionId);
70
+ client.toolCallMeta.forget(params.sessionId);
69
71
  return response;
70
72
  })
71
73
  .onRequest(v2.methods.agent.session.delete, ({ params }) => agent.deleteSession(params))
@@ -105,11 +107,16 @@ class V2ClientConnection {
105
107
  logger;
106
108
  /**
107
109
  * The sessions whose history replays, each with the messages that the
108
- * replay has cleared so far.
110
+ * replay has cleared so far. A subagent that a replay announces replays
111
+ * with it.
109
112
  */
110
113
  replays = new Map();
114
+ /** The session whose replay announced each replaying subagent. */
115
+ replayRoots = new Map();
111
116
  /** The display terminals of the commands that the agent runs. */
112
117
  terminals = new V2Terminals();
118
+ /** The `_meta` that the client stores for each tool call. */
119
+ toolCallMeta = new V2ToolCallMeta();
113
120
  constructor(ctx, logger) {
114
121
  this.ctx = ctx;
115
122
  this.logger = logger;
@@ -129,6 +136,12 @@ class V2ClientConnection {
129
136
  }
130
137
  finally {
131
138
  this.replays.delete(sessionId);
139
+ for (const [child, root] of this.replayRoots) {
140
+ if (root !== sessionId)
141
+ continue;
142
+ this.replays.delete(child);
143
+ this.replayRoots.delete(child);
144
+ }
132
145
  }
133
146
  }
134
147
  /**
@@ -152,17 +165,32 @@ class V2ClientConnection {
152
165
  return this.ctx.notify(method, params);
153
166
  }
154
167
  async sessionUpdate({ update, ...notification }) {
168
+ // A subagent that a replay announces replays too, so its messages are
169
+ // cleared before their first replayed chunk, as the parent's are.
170
+ if (update.sessionUpdate === "subagent_update" &&
171
+ this.replays.has(notification.sessionId) &&
172
+ !this.replays.has(update.sessionId)) {
173
+ this.replays.set(update.sessionId, new Set());
174
+ this.replayRoots.set(update.sessionId, this.replayRoots.get(notification.sessionId) ?? notification.sessionId);
175
+ }
155
176
  const updates = this.v2Updates(notification.sessionId, update).flatMap((v2Update) => {
156
177
  const clear = this.replayClear(notification.sessionId, v2Update);
157
178
  return clear ? [clear, v2Update] : [v2Update];
158
179
  });
180
+ // A subagent's work state also goes to the child's own stream, after the
181
+ // parent's copy.
182
+ const childState = v2ChildStateUpdate(update);
159
183
  // Every update goes to the connection before any is awaited, so an update
160
184
  // that another call sends meanwhile cannot come between them.
161
- await Promise.all(updates.map((v2Update) => this.ctx.notify(v2.methods.client.session.update, { ...notification, update: v2Update })));
185
+ await Promise.all([
186
+ ...updates.map((v2Update) => this.ctx.notify(v2.methods.client.session.update, { ...notification, update: v2Update })),
187
+ ...(childState ? [this.ctx.notify(v2.methods.client.session.update, childState)] : []),
188
+ ]);
162
189
  }
163
190
  /**
164
191
  * The v2 updates of a v1 update: for a tool call report, the updates of its
165
- * terminal first, then the report itself (see {@link V2Terminals}).
192
+ * terminal first (see {@link V2Terminals}), then the report itself, with the
193
+ * `_meta` that the client stores (see {@link V2ToolCallMeta}).
166
194
  */
167
195
  v2Updates(sessionId, update) {
168
196
  if (update.sessionUpdate !== "tool_call" && update.sessionUpdate !== "tool_call_update") {
@@ -170,7 +198,10 @@ class V2ClientConnection {
170
198
  return v2Update ? [v2Update] : [];
171
199
  }
172
200
  const { terminal, report } = this.terminals.split(sessionId, update);
173
- const reportUpdate = report && v2SessionUpdate(report);
201
+ if (!report)
202
+ return terminal;
203
+ const starts = report.sessionUpdate === "tool_call";
204
+ const reportUpdate = v2SessionUpdate(this.toolCallMeta.apply(sessionId, report, starts));
174
205
  return [...terminal, ...(reportUpdate ? [reportUpdate] : [])];
175
206
  }
176
207
  /**
@@ -192,7 +223,9 @@ class V2ClientConnection {
192
223
  return emptyMessage(kind, messageId);
193
224
  }
194
225
  async requestPermission(params, signal) {
195
- const response = await this.ctx.request(v2.methods.client.session.requestPermission, v2PermissionRequest(params), { cancellationSignal: signal });
226
+ // The subject is an update of the tool call, with its stored `_meta`.
227
+ const toolCall = this.toolCallMeta.subject(params.sessionId, params.toolCall);
228
+ const response = await this.ctx.request(v2.methods.client.session.requestPermission, v2PermissionRequest({ ...params, toolCall }), { cancellationSignal: signal });
196
229
  return v1PermissionResponse(response);
197
230
  }
198
231
  // Elicitation is the same in v1 and v2.
@@ -1 +1 @@
1
- {"version":3,"file":"initialize.d.ts","sourceRoot":"","sources":["../../src/v2/initialize.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,0CAA0C,CAAC;AAE/D,0DAA0D;AAC1D,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,EAAE,CAAC,iBAAiB,GAAG,iBAAiB,CA0BpF;AASD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,EAAE,CAAC,kBAAkB,CAuBxF"}
1
+ {"version":3,"file":"initialize.d.ts","sourceRoot":"","sources":["../../src/v2/initialize.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,0CAA0C,CAAC;AAE/D,0DAA0D;AAC1D,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,EAAE,CAAC,iBAAiB,GAAG,iBAAiB,CAmCpF;AASD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,EAAE,CAAC,kBAAkB,CAuBxF"}
@@ -26,6 +26,15 @@ export function v1InitializeRequest(request) {
26
26
  // compaction as a compaction entity rather than as a "Compact
27
27
  // conversation" tool call, also on replay.
28
28
  session: { configOptions: { boolean: {} }, notices: {}, compaction: {} },
29
+ // Every v2 client takes `plan_update`, with the draft's markdown and file
30
+ // plans, and `plan_removed`; v1 asks for the `plan` marker. With it, the
31
+ // agent shows an approved ExitPlanMode plan as a markdown plan.
32
+ plan: {},
33
+ // Subagent updates are part of v2's baseline session model (the subagents
34
+ // RFD), so every v2 client takes them; v1 asks for the `subagents`
35
+ // capability. With it, the agent reports each Agent or Task subagent as a
36
+ // child session.
37
+ subagents: {},
29
38
  // v1 marks terminal auth support with a boolean, v2 with an object.
30
39
  auth: {
31
40
  terminal: capabilities?.auth?.terminal != null,
@@ -78,7 +87,7 @@ export function v2InitializeResponse(response) {
78
87
  * - The session baseline: `session/new`, `list`, `resume` (with replay),
79
88
  * `close`, `prompt`, `cancel`, and `update`.
80
89
  * - `session/delete`, `session/fork` (which returns a session the client can
81
- * prompt, see `v1ForkSessionRequests`), and `additionalDirectories`.
90
+ * prompt at once), and `additionalDirectories`.
82
91
  * - The prompt content and MCP transports that the agent's v1 `initialize`
83
92
  * lists: images, embedded context, and HTTP servers. Stdio servers are in the
84
93
  * v1 baseline; v2 has no SSE transport.
@@ -18,4 +18,15 @@ export declare const SESSION_PLAN_ID = "plan";
18
18
  * an error rather than a silently missing update.
19
19
  */
20
20
  export declare function v2SessionUpdate(update: AcpSessionNotification["update"]): v2.SessionUpdate | undefined;
21
+ /**
22
+ * The child's own `state_update` for a v1 `subagent_update` that reports the
23
+ * child's work state, or `undefined` when it reports none.
24
+ *
25
+ * v1 reports a child's work state only on its parent, as the `state` of the
26
+ * `subagent_update`. v2 reports it on the child's own stream, as for any
27
+ * session, and mirrors it on the parent (the subagents RFD). The child's copy
28
+ * goes right after the parent's: never before the announcement, and both
29
+ * copies of a state before any later state.
30
+ */
31
+ export declare function v2ChildStateUpdate(update: AcpSessionNotification["update"]): v2.UpdateSessionNotification | undefined;
21
32
  //# sourceMappingURL=session-update.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-update.d.ts","sourceRoot":"","sources":["../../src/v2/session-update.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,0CAA0C,CAAC;AAC/D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAIlE;;;;GAIG;AACH,eAAO,MAAM,eAAe,SAAS,CAAC;AAEtC;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,sBAAsB,CAAC,QAAQ,CAAC,GACvC,EAAE,CAAC,aAAa,GAAG,SAAS,CA0C9B"}
1
+ {"version":3,"file":"session-update.d.ts","sourceRoot":"","sources":["../../src/v2/session-update.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,0CAA0C,CAAC;AAC/D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAIlE;;;;GAIG;AACH,eAAO,MAAM,eAAe,SAAS,CAAC;AAEtC;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,sBAAsB,CAAC,QAAQ,CAAC,GACvC,EAAE,CAAC,aAAa,GAAG,SAAS,CAyD9B;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,sBAAsB,CAAC,QAAQ,CAAC,GACvC,EAAE,CAAC,yBAAyB,GAAG,SAAS,CAM1C"}
@@ -45,6 +45,21 @@ export function v2SessionUpdate(update) {
45
45
  plan: { type: "items", planId: SESSION_PLAN_ID, entries: update.entries },
46
46
  ...(update._meta != null ? { _meta: update._meta } : {}),
47
47
  };
48
+ case "plan_update":
49
+ case "plan_removed":
50
+ // v1's draft plan operations have v2's shape.
51
+ return update;
52
+ case "subagent_update": {
53
+ // The subagents RFD gives it the same shape in v1 and v2. One that
54
+ // reports a state also has a copy on the child's stream (see
55
+ // `v2ChildStateUpdate`).
56
+ const { state, ...association } = update;
57
+ return { ...association, ...(state != null ? { state: v2SubagentState(state) } : {}) };
58
+ }
59
+ case "session_message":
60
+ case "session_message_chunk":
61
+ // The subagents RFD gives these the same shape in v1 and v2.
62
+ return update;
48
63
  case "current_mode_update":
49
64
  // v2 has no modes: the mode is the `mode` config option. Every mode
50
65
  // change also reaches the client as a `config_option_update` or in the
@@ -54,3 +69,55 @@ export function v2SessionUpdate(update) {
54
69
  throw new Error(`The ACP v2 surface does not translate ${update.sessionUpdate} session updates yet`);
55
70
  }
56
71
  }
72
+ /**
73
+ * The child's own `state_update` for a v1 `subagent_update` that reports the
74
+ * child's work state, or `undefined` when it reports none.
75
+ *
76
+ * v1 reports a child's work state only on its parent, as the `state` of the
77
+ * `subagent_update`. v2 reports it on the child's own stream, as for any
78
+ * session, and mirrors it on the parent (the subagents RFD). The child's copy
79
+ * goes right after the parent's: never before the announcement, and both
80
+ * copies of a state before any later state.
81
+ */
82
+ export function v2ChildStateUpdate(update) {
83
+ if (update.sessionUpdate !== "subagent_update" || update.state == null)
84
+ return undefined;
85
+ return {
86
+ sessionId: update.sessionId,
87
+ update: { sessionUpdate: "state_update", ...v2SubagentState(update.state) },
88
+ };
89
+ }
90
+ /** The work states of the subagents RFD, and the stop reasons of its `idle`. */
91
+ const SUBAGENT_STATES = new Set([
92
+ "running",
93
+ "requires_action",
94
+ "unknown",
95
+ "idle",
96
+ ]);
97
+ const IDLE_STOP_REASONS = new Set([
98
+ undefined,
99
+ null,
100
+ "end_turn",
101
+ "max_tokens",
102
+ "max_turn_requests",
103
+ "refusal",
104
+ "cancelled",
105
+ "error",
106
+ ]);
107
+ /**
108
+ * The v2 form of a subagent's v1 work state.
109
+ *
110
+ * The RFD's states have the same shape in v1 and v2. Each version also types
111
+ * an open member for states and stop reasons it does not know, and those two
112
+ * members are typed apart. So the state is checked to be one of the RFD's, and
113
+ * any other throws, as an update kind that this surface does not translate
114
+ * does.
115
+ */
116
+ function v2SubagentState(state) {
117
+ const stopReason = state.stopReason;
118
+ if (!SUBAGENT_STATES.has(state.state) ||
119
+ (state.state === "idle" && !IDLE_STOP_REASONS.has(stopReason))) {
120
+ throw new Error(`The ACP v2 surface does not translate the subagent state ${state.state}${state.state === "idle" ? ` with the stop reason ${String(stopReason)}` : ""}`);
121
+ }
122
+ return state;
123
+ }
@@ -23,19 +23,10 @@ export declare function v1RestoreSessionRequest(params: v2.ResumeSessionRequest)
23
23
  request: LoadSessionRequest;
24
24
  };
25
25
  /**
26
- * The v1 requests that a v2 `session/fork` means.
27
- *
28
- * The agent's v1 fork copies the transcript into a new session and returns
29
- * only its id; a v1 client then resumes or loads it. A v2 fork returns the new
30
- * session with its config options, like `session/new`, so the client can
31
- * prompt it. The v2 surface therefore forks, then resumes the fork without
32
- * replay, with the request's `cwd`, `additionalDirectories`, and
33
- * `mcpServers`. The request's `_meta` goes to the fork alone.
26
+ * The v1 request of a v2 `session/fork`. In both versions the agent's fork
27
+ * returns a session that the client can prompt, with its config options.
34
28
  */
35
- export declare function v1ForkSessionRequests(params: v2.ForkSessionRequest): {
36
- fork: ForkSessionRequest;
37
- resume: (sessionId: string) => ResumeSessionRequest;
38
- };
29
+ export declare function v1ForkSessionRequest(params: v2.ForkSessionRequest): ForkSessionRequest;
39
30
  /** v2 drops `modes`: the session mode is the `mode` config option, which the agent always lists. */
40
31
  export declare function v2NewSessionResponse(response: NewSessionResponse): v2.NewSessionResponse;
41
32
  export declare function v2ResumeSessionResponse(response: ResumeSessionResponse): v2.ResumeSessionResponse;
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/v2/session.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAEvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EAGxB,KAAK,6BAA6B,EACnC,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,0CAA0C,CAAC;AAE/D,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,EAAE,CAAC,iBAAiB,GAAG,iBAAiB,CAInF;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,EAAE,CAAC,oBAAoB,GAE7B;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,GACnD;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,CAkBlD;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,EAAE,CAAC,kBAAkB,GAAG;IACpE,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,oBAAoB,CAAC;CACrD,CAUA;AAED,oGAAoG;AACpG,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,EAAE,CAAC,kBAAkB,CAExF;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,EAAE,CAAC,qBAAqB,CAKjG;AAED,uEAAuE;AACvE,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,EAAE,CAAC,6BAA6B,GACvC,6BAA6B,CAgB/B;AAED,sFAAsF;AACtF,wBAAgB,eAAe,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,EAAE,CAAC,mBAAmB,EAAE,CAQxF;AAWD,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC,gBAAgB,EAAE,CAKvF"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/v2/session.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAEvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EAGxB,KAAK,6BAA6B,EACnC,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,0CAA0C,CAAC;AAE/D,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,EAAE,CAAC,iBAAiB,GAAG,iBAAiB,CAInF;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,EAAE,CAAC,oBAAoB,GAE7B;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,GACnD;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,CAkBlD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,EAAE,CAAC,kBAAkB,GAAG,kBAAkB,CAGtF;AAED,oGAAoG;AACpG,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,EAAE,CAAC,kBAAkB,CAExF;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,EAAE,CAAC,qBAAqB,CAKjG;AAED,uEAAuE;AACvE,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,EAAE,CAAC,6BAA6B,GACvC,6BAA6B,CAgB/B;AAED,sFAAsF;AACtF,wBAAgB,eAAe,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,EAAE,CAAC,mBAAmB,EAAE,CAQxF;AAWD,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC,gBAAgB,EAAE,CAKvF"}