@agentclientprotocol/claude-agent-acp 0.94.1-preview.8 → 0.95.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.
@@ -1,4 +1,4 @@
1
- import { isNativeSubagentControlTool, nativeSubagentState, rfdEndState, rfdLabels, } from "./native-subagents.js";
1
+ import { HANDBACK_TOOL, handbackMessage, isNativeSubagentControlTool, launchReply, linkedSessionMessages, nativeSubagentState, rfdEndState, rfdLabels, } from "./native-subagents.js";
2
2
  import { noticeUpdate } from "./session-notices.js";
3
3
  export class RfdSubagentReplay {
4
4
  history;
@@ -11,6 +11,8 @@ export class RfdSubagentReplay {
11
11
  omitted = new Set();
12
12
  /** Children whose transcript could not be read: only their association is replayed. */
13
13
  withoutHistory = 0;
14
+ /** The SubagentHandback calls, with their report and whether their result failed. */
15
+ handbacks = new Map();
14
16
  constructor(history, publish) {
15
17
  this.history = history;
16
18
  this.publish = publish;
@@ -26,6 +28,11 @@ export class RfdSubagentReplay {
26
28
  if (isNativeSubagentControlTool(block.name)) {
27
29
  this.registerLaunch(block.id, inputOf(block), ownerSessionId);
28
30
  }
31
+ else if (block.name === HANDBACK_TOOL) {
32
+ const message = handbackMessage(block.input);
33
+ if (message)
34
+ this.handbacks.set(block.id, { message, failed: false, sent: false });
35
+ }
29
36
  else if (block.name === "SendMessage") {
30
37
  const input = inputOf(block);
31
38
  if (typeof input.to === "string" && typeof input.message === "string") {
@@ -40,6 +47,9 @@ export class RfdSubagentReplay {
40
47
  }
41
48
  }
42
49
  else if (block.type === "tool_result" && typeof block.tool_use_id === "string") {
50
+ const handback = this.handbacks.get(block.tool_use_id);
51
+ if (handback && block.is_error === true)
52
+ handback.failed = true;
43
53
  const child = this.children.get(block.tool_use_id);
44
54
  // A background launch answers at once; its result is not the end.
45
55
  if (child && !child.record.background) {
@@ -106,6 +116,42 @@ export class RfdSubagentReplay {
106
116
  await this.sendPrompt(child, child.input.prompt);
107
117
  }
108
118
  }
119
+ /**
120
+ * Takes a replayed update of a tool call, from the transcript of `owner`
121
+ * when it is a child's. Returns whether the client is not shown it: an
122
+ * update of the launch of a child that the replay shows, or of a successful
123
+ * SubagentHandback call of `owner`. A foreground launch's completed result
124
+ * goes out as the child's reply, and a hand-back as the child's message to
125
+ * its parent.
126
+ */
127
+ async toolCallUpdate(update, owner) {
128
+ if (update.sessionUpdate !== "tool_call" && update.sessionUpdate !== "tool_call_update") {
129
+ return false;
130
+ }
131
+ const handback = owner ? this.handbacks.get(update.toolCallId) : undefined;
132
+ if (owner && handback && !handback.failed) {
133
+ if (!handback.sent) {
134
+ handback.sent = true;
135
+ owner.handedBack = true;
136
+ for (const view of linkedSessionMessages(update.toolCallId, owner.sessionId, owner.parentSessionId, handback.message)) {
137
+ await this.publish(view);
138
+ }
139
+ }
140
+ return true;
141
+ }
142
+ const child = this.children.get(update.toolCallId);
143
+ if (!child)
144
+ return false;
145
+ if (update.status === "completed" &&
146
+ child.announced &&
147
+ !child.record.background &&
148
+ !child.handedBack) {
149
+ const reply = launchReply(child.launchId, child.sessionId, child.parentSessionId, update);
150
+ if (reply)
151
+ await this.publish(reply);
152
+ }
153
+ return true;
154
+ }
109
155
  /**
110
156
  * Takes a persisted task notification. Returns whether it was a child's:
111
157
  * its task id is the agent id.
@@ -168,10 +214,12 @@ export class RfdSubagentReplay {
168
214
  this.children.set(toolUseId, child);
169
215
  this.byAgentId.set(record.agentId, child);
170
216
  }
171
- /** The prompt of the launch, with the launch's id, as live. */
217
+ /** The prompt of the launch, with the launch's id, to the parent and the child, as live. */
172
218
  async sendPrompt(child, text) {
173
219
  child.promptSent = true;
174
- await this.sendMessage(child, child.launchId, text, child.parentSessionId);
220
+ for (const view of linkedSessionMessages(child.launchId, child.parentSessionId, child.sessionId, text)) {
221
+ await this.publish(view);
222
+ }
175
223
  }
176
224
  /**
177
225
  * A message that a SendMessage call delivered. Claude Code frames it for the
package/dist/tools.js CHANGED
@@ -294,7 +294,7 @@ export function clearHookCallbacks(ownerId) {
294
294
  export const createPostToolUseHook = (options) => async (input, toolUseID) => {
295
295
  if (input.hook_event_name === "PostToolUse") {
296
296
  // Handle EnterPlanMode tool - notify client of mode change after successful execution
297
- if (input.tool_name === "EnterPlanMode" && options?.onEnterPlanMode) {
297
+ if (input.tool_name === "EnterPlanMode" && !input.agent_id && options?.onEnterPlanMode) {
298
298
  await options.onEnterPlanMode();
299
299
  }
300
300
  if (toolUseID) {
@@ -1 +1 @@
1
- {"version":3,"file":"usage-markdown.d.ts","sourceRoot":"","sources":["../src/usage-markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AA8DjF,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,0BAA0B,GAAG,IAAI,CAMpF;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AASD,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AA+DD,iEAAiE;AACjE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,0BAA0B,GAAG,MAAM,CAiE7E"}
1
+ {"version":3,"file":"usage-markdown.d.ts","sourceRoot":"","sources":["../src/usage-markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AAsEjF,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,0BAA0B,GAAG,IAAI,CAMpF;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AASD,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AA0ED,iEAAiE;AACjE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,0BAA0B,GAAG,MAAM,CAiE7E"}
@@ -6,10 +6,18 @@ const usageWindowSchema = z
6
6
  .nullable()
7
7
  .optional();
8
8
  const contributionSchema = z.object({ name: z.string(), pct: percentSchema });
9
+ // Claude Code 2.1.305+ suggests one change per notable source, largest share first.
10
+ const recommendationSchema = z.object({
11
+ key: z.string(),
12
+ pct: percentSchema,
13
+ title: z.string(),
14
+ detail: z.string().optional(),
15
+ });
9
16
  const behaviorPeriodSchema = z.object({
10
17
  request_count: countSchema,
11
18
  session_count: countSchema,
12
19
  mcp_servers: z.array(contributionSchema),
20
+ recommendations: z.array(recommendationSchema).optional(),
13
21
  });
14
22
  const modelUsageSchema = z.object({
15
23
  inputTokens: countSchema,
@@ -107,6 +115,16 @@ function appendLimit(lines, label, window) {
107
115
  }
108
116
  function appendContributions(lines, label, period) {
109
117
  lines.push("", `**${label}** · ${period.request_count} requests · ${period.session_count} sessions`);
118
+ // Rendered in the order Claude Code sends them, as its own `/usage` does. The
119
+ // window's `fix` is left out: its messages must be queued at priority "later"
120
+ // with `client_composed` set, which an ACP prompt cannot express.
121
+ if (period.recommendations?.length) {
122
+ lines.push("");
123
+ for (const recommendation of period.recommendations) {
124
+ const detail = recommendation.detail ? ` · ${escapeMarkdown(recommendation.detail)}` : "";
125
+ lines.push(`- **${recommendation.pct}%** ${escapeMarkdown(recommendation.title)}${detail}`);
126
+ }
127
+ }
110
128
  if (period.mcp_servers.length === 0)
111
129
  return;
112
130
  lines.push("", "| MCP server | Usage |", "|:--|--:|");
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.94.1-preview.8",
6
+ "version": "0.95.0",
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",
@@ -65,25 +65,24 @@
65
65
  "node": ">=22"
66
66
  },
67
67
  "dependencies": {
68
- "@agentclientprotocol/sdk": "2.0.0",
69
- "@anthropic-ai/claude-agent-sdk": "0.3.303",
68
+ "@agentclientprotocol/sdk": "2.0.1",
69
+ "@anthropic-ai/claude-agent-sdk": "0.3.309",
70
70
  "diff": "9.0.0",
71
71
  "zod": "4.6.7"
72
72
  },
73
73
  "devDependencies": {
74
- "@anthropic-ai/sdk": "0.135.0",
74
+ "@anthropic-ai/sdk": "1.1.0",
75
75
  "@eslint/js": "10.0.1",
76
76
  "@tsconfig/node22": "22.0.6",
77
77
  "@types/node": "26.6.5",
78
- "@typescript-eslint/eslint-plugin": "8.71.2",
79
- "@typescript-eslint/parser": "8.71.2",
78
+ "@typescript-eslint/eslint-plugin": "8.72.0",
79
+ "@typescript-eslint/parser": "8.72.0",
80
80
  "ajv": "8.20.0",
81
81
  "ajv-formats": "3.0.1",
82
82
  "eslint": "10.13.0",
83
83
  "eslint-config-prettier": "10.1.8",
84
84
  "globals": "17.13.0",
85
85
  "prettier": "3.9.10",
86
- "ts-node": "10.9.2",
87
86
  "typescript": "6.0.3",
88
87
  "vitest": "5.0.5"
89
88
  }