@agentclientprotocol/claude-agent-acp 0.89.2-preview.9 → 0.90.1-preview.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.
Files changed (52) hide show
  1. package/README.md +56 -8
  2. package/dist/acp-agent.d.ts +50 -1
  3. package/dist/acp-agent.d.ts.map +1 -1
  4. package/dist/acp-agent.js +493 -147
  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 +228 -11
  17. package/dist/native-subagents.d.ts.map +1 -1
  18. package/dist/native-subagents.js +489 -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 +44 -2
  23. package/dist/subagent-history.d.ts.map +1 -1
  24. package/dist/subagent-history.js +116 -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
@@ -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"}
@@ -36,25 +36,12 @@ export function v1RestoreSessionRequest(params) {
36
36
  };
37
37
  }
38
38
  /**
39
- * The v1 requests that a v2 `session/fork` means.
40
- *
41
- * The agent's v1 fork copies the transcript into a new session and returns
42
- * only its id; a v1 client then resumes or loads it. A v2 fork returns the new
43
- * session with its config options, like `session/new`, so the client can
44
- * prompt it. The v2 surface therefore forks, then resumes the fork without
45
- * replay, with the request's `cwd`, `additionalDirectories`, and
46
- * `mcpServers`. The request's `_meta` goes to the fork alone.
39
+ * The v1 request of a v2 `session/fork`. In both versions the agent's fork
40
+ * returns a session that the client can prompt, with its config options.
47
41
  */
48
- export function v1ForkSessionRequests(params) {
49
- const { mcpServers, _meta, ...request } = params;
50
- const session = {
51
- ...request,
52
- ...(mcpServers ? { mcpServers: mcpServers.map(v1McpServer) } : {}),
53
- };
54
- return {
55
- fork: { ...session, ...(_meta != null ? { _meta } : {}) },
56
- resume: (sessionId) => ({ ...session, sessionId }),
57
- };
42
+ export function v1ForkSessionRequest(params) {
43
+ const { mcpServers, ...request } = params;
44
+ return { ...request, ...(mcpServers ? { mcpServers: mcpServers.map(v1McpServer) } : {}) };
58
45
  }
59
46
  /** v2 drops `modes`: the session mode is the `mode` config option, which the agent always lists. */
60
47
  export function v2NewSessionResponse(response) {
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The `_meta` of the tool calls of one ACP v2 connection, as the client stores
3
+ * it.
4
+ *
5
+ * The agent gives each v1 tool call report the `_meta` keys of that report.
6
+ * An AIR client merges them by key (see `ToolCallFieldTracker`), and another
7
+ * v1 client reads them per report. A v2 client stores a tool call's `_meta`,
8
+ * and a report that carries `_meta` replaces it. So the earlier keys must
9
+ * travel again, or the `{ toolName }` of a tool's result would replace, for
10
+ * example, the reason of the denial before it.
11
+ *
12
+ * {@link V2ToolCallMeta} therefore keeps the merged `_meta` of each tool call,
13
+ * with the `claudeCode` keys merged one by one and every other key replaced
14
+ * whole, as `ToolCallFieldTracker` models it. A report that changes it carries
15
+ * all of it; a report that changes nothing carries no `_meta`.
16
+ *
17
+ * `claudeCode.toolName` repeats the name of the tool, which v2 has a field
18
+ * for. It becomes the `name` of a tool call that has none yet, and is left out
19
+ * of the stored `_meta`. Subagent routing reads it before this, on the agent's
20
+ * v1 reports.
21
+ */
22
+ import type { ToolCall, ToolCallUpdate } from "@agentclientprotocol/sdk";
23
+ export declare class V2ToolCallMeta {
24
+ /** The stored `_meta` of each tool call, by session and tool call, oldest first. */
25
+ private readonly calls;
26
+ /**
27
+ * `report` with the tool call's whole `_meta` when the report changes it,
28
+ * without `_meta` when it does not, and with `name` when it names the tool
29
+ * call for the first time. `starts` says that the report starts the tool
30
+ * call (a v1 `tool_call`), which forgets what an earlier one stored.
31
+ */
32
+ apply<Report extends ToolCall | ToolCallUpdate>(sessionId: string, report: Report, starts: boolean): Report;
33
+ /**
34
+ * The tool call of a permission request's subject: like {@link apply}, but
35
+ * with the tool call's whole `_meta` even when the subject changes nothing,
36
+ * since a client can show the request from the request alone.
37
+ */
38
+ subject<Report extends ToolCall | ToolCallUpdate>(sessionId: string, toolCall: Report): Report;
39
+ /** Forgets the tool calls of a session, when it closes. */
40
+ forget(sessionId: string): void;
41
+ /** Stores the entry as the most recent one, and forgets the oldest one past the limit. */
42
+ private remember;
43
+ }
44
+ //# sourceMappingURL=tool-call-meta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-call-meta.d.ts","sourceRoot":"","sources":["../../src/v2/tool-call-meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAOzE,qBAAa,cAAc;IACzB,oFAAoF;IACpF,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqD;IAE3E;;;;;OAKG;IACH,KAAK,CAAC,MAAM,SAAS,QAAQ,GAAG,cAAc,EAC5C,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,GACd,MAAM;IA6BT;;;;OAIG;IACH,OAAO,CAAC,MAAM,SAAS,QAAQ,GAAG,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAO9F,2DAA2D;IAC3D,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAM/B,0FAA0F;IAC1F,OAAO,CAAC,QAAQ;CAQjB"}
@@ -0,0 +1,72 @@
1
+ /** The number of tool calls whose `_meta` a connection remembers. */
2
+ const TOOL_CALL_LIMIT = 2048;
3
+ export class V2ToolCallMeta {
4
+ /** The stored `_meta` of each tool call, by session and tool call, oldest first. */
5
+ calls = new Map();
6
+ /**
7
+ * `report` with the tool call's whole `_meta` when the report changes it,
8
+ * without `_meta` when it does not, and with `name` when it names the tool
9
+ * call for the first time. `starts` says that the report starts the tool
10
+ * call (a v1 `tool_call`), which forgets what an earlier one stored.
11
+ */
12
+ apply(sessionId, report, starts) {
13
+ const key = `${sessionId} ${report.toolCallId}`;
14
+ const call = (!starts && this.calls.get(key)) || { meta: {}, named: false };
15
+ this.remember(key, call);
16
+ const { _meta, ...fields } = report;
17
+ const result = fields;
18
+ const { toolName, ...claudeCode } = asRecord(_meta?.claudeCode) ?? {};
19
+ if (report.name != null) {
20
+ call.named = true;
21
+ }
22
+ else if (!call.named && typeof toolName === "string") {
23
+ result.name = toolName;
24
+ call.named = true;
25
+ }
26
+ const meta = { ...call.meta };
27
+ for (const [name, value] of Object.entries(_meta ?? {})) {
28
+ if (name !== "claudeCode")
29
+ meta[name] = value;
30
+ }
31
+ if (Object.keys(claudeCode).length > 0) {
32
+ meta.claudeCode = { ...asRecord(call.meta.claudeCode), ...claudeCode };
33
+ }
34
+ if (JSON.stringify(meta) !== JSON.stringify(call.meta)) {
35
+ call.meta = meta;
36
+ result._meta = meta;
37
+ }
38
+ return result;
39
+ }
40
+ /**
41
+ * The tool call of a permission request's subject: like {@link apply}, but
42
+ * with the tool call's whole `_meta` even when the subject changes nothing,
43
+ * since a client can show the request from the request alone.
44
+ */
45
+ subject(sessionId, toolCall) {
46
+ const result = this.apply(sessionId, toolCall, false);
47
+ const stored = this.calls.get(`${sessionId} ${toolCall.toolCallId}`)?.meta ?? {};
48
+ if (result._meta === undefined && Object.keys(stored).length > 0)
49
+ result._meta = stored;
50
+ return result;
51
+ }
52
+ /** Forgets the tool calls of a session, when it closes. */
53
+ forget(sessionId) {
54
+ for (const key of this.calls.keys()) {
55
+ if (key.startsWith(`${sessionId} `))
56
+ this.calls.delete(key);
57
+ }
58
+ }
59
+ /** Stores the entry as the most recent one, and forgets the oldest one past the limit. */
60
+ remember(key, call) {
61
+ this.calls.delete(key);
62
+ this.calls.set(key, call);
63
+ if (this.calls.size > TOOL_CALL_LIMIT) {
64
+ const oldest = this.calls.keys().next().value;
65
+ if (oldest !== undefined)
66
+ this.calls.delete(oldest);
67
+ }
68
+ }
69
+ }
70
+ function asRecord(value) {
71
+ return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
72
+ }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.89.2-preview.9",
6
+ "version": "0.90.1-preview.1",
7
7
  "description": "An ACP-compatible coding agent powered by the Claude Agent SDK (TypeScript)",
8
8
  "main": "dist/lib.js",
9
9
  "types": "dist/lib.d.ts",
@@ -66,25 +66,25 @@
66
66
  },
67
67
  "dependencies": {
68
68
  "@agentclientprotocol/sdk": "1.8.0",
69
- "@anthropic-ai/claude-agent-sdk": "0.3.293",
69
+ "@anthropic-ai/claude-agent-sdk": "0.3.296",
70
70
  "diff": "9.0.0",
71
- "zod": "4.6.5"
71
+ "zod": "4.6.7"
72
72
  },
73
73
  "devDependencies": {
74
- "@anthropic-ai/sdk": "0.132.1",
74
+ "@anthropic-ai/sdk": "0.133.0",
75
75
  "@eslint/js": "10.0.1",
76
76
  "@tsconfig/node22": "22.0.6",
77
- "@types/node": "26.6.4",
78
- "@typescript-eslint/eslint-plugin": "8.71.1",
79
- "@typescript-eslint/parser": "8.71.1",
77
+ "@types/node": "26.6.5",
78
+ "@typescript-eslint/eslint-plugin": "8.71.2",
79
+ "@typescript-eslint/parser": "8.71.2",
80
80
  "ajv": "8.20.0",
81
81
  "ajv-formats": "3.0.1",
82
82
  "eslint": "10.12.0",
83
83
  "eslint-config-prettier": "10.1.8",
84
84
  "globals": "17.13.0",
85
- "prettier": "3.9.9",
85
+ "prettier": "3.9.10",
86
86
  "ts-node": "10.9.2",
87
87
  "typescript": "6.0.3",
88
- "vitest": "5.0.3"
88
+ "vitest": "5.0.4"
89
89
  }
90
90
  }