claude-code-acp-ts 0.44.0 → 0.53.0-beta.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.
@@ -53,10 +53,11 @@ export declare function extractAskUserQuestions(input: Record<string, unknown>):
53
53
  * an array with a titled `anyOf` item enum. The enum `const` is always the
54
54
  * option label, since that is what the tool records as the answer.
55
55
  *
56
- * A trailing optional free-text field mirrors the CLI's custom-answer box: the
57
- * user can type their own answer instead of (or as well as) picking an option.
58
- * Nothing is marked required, so the user can also just skip — matching the
59
- * built-in tool, which always offers Skip + a free-text box.
56
+ * Each question is followed by its own optional free-text "custom answer" field
57
+ * (`question_<n>_custom`), mirroring the CLI's per-question "Other" box: the
58
+ * user can type their own answer instead of picking an option, scoped to that
59
+ * specific question. Nothing is marked required, so the user can also just skip
60
+ * — matching the built-in tool, which always offers Skip + a free-text box.
60
61
  */
61
62
  export declare function askUserQuestionsToCreateRequest(questions: AskUserQuestion[], sessionId: string, toolCallId: string | undefined): CreateElicitationRequest;
62
63
  /** Outcome of an AskUserQuestion elicitation, decoupled from any transport. */
@@ -71,10 +72,11 @@ export type AskUserQuestionOutcome = {
71
72
  *
72
73
  * Selected labels are read back from the indexed form fields and written into
73
74
  * `answers` as a `{ [questionText]: label }` map (comma-joining multi-selects)
74
- * — the key shape the tool's own `call()` reads. Free text from the custom-
75
- * answer field becomes the tool's top-level `response`. Decline yields empty
76
- * answers (the model is told the user skipped rather than the turn aborting);
77
- * cancel aborts the tool call.
75
+ * — the key shape the tool's own `call()` reads. A non-empty per-question
76
+ * custom-answer field (`question_<n>_custom`) takes precedence over that
77
+ * question's selection, since the user typed their own answer instead of
78
+ * picking one. Decline yields empty answers (the model is told the user skipped
79
+ * rather than the turn aborting); cancel aborts the tool call.
78
80
  */
79
81
  export declare function applyAskElicitationResponse(response: CreateElicitationResponse, toolInput: Record<string, unknown>, questions: AskUserQuestion[]): AskUserQuestionOutcome;
80
82
  //# sourceMappingURL=elicitation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"elicitation.d.ts","sourceRoot":"","sources":["../src/elicitation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EAI1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAC5F,OAAO,KAAK,EACV,oBAAoB,EAErB,MAAM,6CAA6C,CAAC;AAErD;;;;;;;;;;;;;GAaG;AAEH,yDAAyD;AACzD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,MAAM,GAChB,wBAAwB,GAAG,IAAI,CAyBjC;AAED;;;GAGG;AACH,wBAAgB,uCAAuC,CACrD,QAAQ,EAAE,yBAAyB,GAClC,iBAAiB,CAUnB;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,EAAE,GAAG,IAAI,CAUhG;AAUD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,eAAe,EAAE,EAC5B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,wBAAwB,CAyC1B;AAED,+EAA+E;AAC/E,MAAM,MAAM,sBAAsB,GAC9B;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAC7D;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEzB;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,yBAAyB,EACnC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,SAAS,EAAE,eAAe,EAAE,GAC3B,sBAAsB,CAiCxB"}
1
+ {"version":3,"file":"elicitation.d.ts","sourceRoot":"","sources":["../src/elicitation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EAI1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAC5F,OAAO,KAAK,EACV,oBAAoB,EAErB,MAAM,6CAA6C,CAAC;AAErD;;;;;;;;;;;;;GAaG;AAEH,yDAAyD;AACzD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,MAAM,GAChB,wBAAwB,GAAG,IAAI,CAyBjC;AAED;;;GAGG;AACH,wBAAgB,uCAAuC,CACrD,QAAQ,EAAE,yBAAyB,GAClC,iBAAiB,CAUnB;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,EAAE,GAAG,IAAI,CAUhG;AA4CD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,eAAe,EAAE,EAC5B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,wBAAwB,CAwD1B;AAED,+EAA+E;AAC/E,MAAM,MAAM,sBAAsB,GAC9B;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAC7D;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEzB;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,yBAAyB,EACnC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,SAAS,EAAE,eAAe,EAAE,GAC3B,sBAAsB,CAkCxB"}
@@ -62,8 +62,35 @@ export function extractAskUserQuestions(input) {
62
62
  function questionFieldKey(index) {
63
63
  return `question_${index}`;
64
64
  }
65
- /** Form-field key for the optional free-text "custom answer" field. */
66
- const CUSTOM_ANSWER_FIELD = "customAnswer";
65
+ /**
66
+ * Form-field key for the per-question free-text "custom answer" field that sits
67
+ * alongside `question_<n>`. Mirrors the first-party clients, where every
68
+ * question carries its own "Other" box rather than one form-level field.
69
+ */
70
+ function questionCustomFieldKey(index) {
71
+ return `question_${index}_custom`;
72
+ }
73
+ /**
74
+ * `_meta` key under which a bridged enum option carries its structured
75
+ * `description`/`preview`, since ACP's `EnumOption` has no field for either.
76
+ * Namespaced like the agent's other `_meta` extensions (`_claude/...`).
77
+ */
78
+ const OPTION_META_KEY = "_claude/askUserQuestionOption";
79
+ /**
80
+ * Build the `_meta` payload that carries an option's structured `description`
81
+ * and optional `preview` for clients that can render them as distinct fields.
82
+ * Returns `undefined` when neither is present, so we don't emit an empty `_meta`.
83
+ */
84
+ function askUserQuestionOptionMeta(option) {
85
+ const detail = {};
86
+ if (option.description) {
87
+ detail.description = option.description;
88
+ }
89
+ if (option.preview) {
90
+ detail.preview = option.preview;
91
+ }
92
+ return Object.keys(detail).length > 0 ? { [OPTION_META_KEY]: detail } : undefined;
93
+ }
67
94
  /**
68
95
  * Render the AskUserQuestion tool's questions as an ACP form elicitation.
69
96
  *
@@ -73,19 +100,35 @@ const CUSTOM_ANSWER_FIELD = "customAnswer";
73
100
  * an array with a titled `anyOf` item enum. The enum `const` is always the
74
101
  * option label, since that is what the tool records as the answer.
75
102
  *
76
- * A trailing optional free-text field mirrors the CLI's custom-answer box: the
77
- * user can type their own answer instead of (or as well as) picking an option.
78
- * Nothing is marked required, so the user can also just skip — matching the
79
- * built-in tool, which always offers Skip + a free-text box.
103
+ * Each question is followed by its own optional free-text "custom answer" field
104
+ * (`question_<n>_custom`), mirroring the CLI's per-question "Other" box: the
105
+ * user can type their own answer instead of picking an option, scoped to that
106
+ * specific question. Nothing is marked required, so the user can also just skip
107
+ * — matching the built-in tool, which always offers Skip + a free-text box.
80
108
  */
81
109
  export function askUserQuestionsToCreateRequest(questions, sessionId, toolCallId) {
82
110
  const single = questions.length === 1;
83
111
  const properties = {};
84
112
  questions.forEach((question, index) => {
85
- const options = question.options.map((option) => ({
86
- const: option.label,
87
- title: option.description ? `${option.label} — ${option.description}` : option.label,
88
- }));
113
+ const options = question.options.map((option) => {
114
+ const enumOption = {
115
+ const: option.label,
116
+ // `title` stays a flattened "label — description" string so clients that
117
+ // only read `const`/`title` still surface the description. Clients that
118
+ // understand the `_meta` below should prefer its structured fields (and
119
+ // treat `const` as the clean label) rather than parsing this title.
120
+ title: option.description ? `${option.label} — ${option.description}` : option.label,
121
+ };
122
+ // The SDK option carries a `description` (secondary text) and an optional
123
+ // `preview` (mockups, code snippets, comparisons shown on focus). Neither
124
+ // has a structural slot in `EnumOption`, so forward them under ACP's
125
+ // reserved `_meta` extension point for clients that can render them.
126
+ const meta = askUserQuestionOptionMeta(option);
127
+ if (meta) {
128
+ enumOption._meta = meta;
129
+ }
130
+ return enumOption;
131
+ });
89
132
  // For a single question the prompt is carried by `message`, so we don't
90
133
  // repeat it in the field description. With multiple questions each field
91
134
  // needs its own question text.
@@ -94,12 +137,12 @@ export function askUserQuestionsToCreateRequest(questions, sessionId, toolCallId
94
137
  properties[questionFieldKey(index)] = question.multiSelect
95
138
  ? { type: "array", title, description, items: { anyOf: options } }
96
139
  : { type: "string", title, description, oneOf: options };
140
+ properties[questionCustomFieldKey(index)] = {
141
+ type: "string",
142
+ title: "Other",
143
+ description: "Type your own answer instead of choosing an option above (optional).",
144
+ };
97
145
  });
98
- properties[CUSTOM_ANSWER_FIELD] = {
99
- type: "string",
100
- title: "Other",
101
- description: "Type your own answer instead of choosing an option above (optional).",
102
- };
103
146
  const requestedSchema = {
104
147
  type: "object",
105
148
  properties,
@@ -118,10 +161,11 @@ export function askUserQuestionsToCreateRequest(questions, sessionId, toolCallId
118
161
  *
119
162
  * Selected labels are read back from the indexed form fields and written into
120
163
  * `answers` as a `{ [questionText]: label }` map (comma-joining multi-selects)
121
- * — the key shape the tool's own `call()` reads. Free text from the custom-
122
- * answer field becomes the tool's top-level `response`. Decline yields empty
123
- * answers (the model is told the user skipped rather than the turn aborting);
124
- * cancel aborts the tool call.
164
+ * — the key shape the tool's own `call()` reads. A non-empty per-question
165
+ * custom-answer field (`question_<n>_custom`) takes precedence over that
166
+ * question's selection, since the user typed their own answer instead of
167
+ * picking one. Decline yields empty answers (the model is told the user skipped
168
+ * rather than the turn aborting); cancel aborts the tool call.
125
169
  */
126
170
  export function applyAskElicitationResponse(response, toolInput, questions) {
127
171
  if (response.action === "cancel") {
@@ -135,6 +179,13 @@ export function applyAskElicitationResponse(response, toolInput, questions) {
135
179
  // stay in sync with what the built-in tool's call() expects to read back.
136
180
  const answers = {};
137
181
  questions.forEach((question, index) => {
182
+ // A typed custom answer wins over the selection: the user chose to write
183
+ // their own answer for this question instead of picking an option.
184
+ const custom = content[questionCustomFieldKey(index)];
185
+ if (typeof custom === "string" && custom.trim() !== "") {
186
+ answers[question.question] = custom.trim();
187
+ return;
188
+ }
138
189
  const value = content[questionFieldKey(index)];
139
190
  if (value === undefined || value === null) {
140
191
  return;
@@ -145,13 +196,7 @@ export function applyAskElicitationResponse(response, toolInput, questions) {
145
196
  }
146
197
  answers[question.question] = text;
147
198
  });
148
- const updatedInput = { ...toolInput, answers };
149
- const custom = content[CUSTOM_ANSWER_FIELD];
150
- if (typeof custom === "string" && custom.trim() !== "") {
151
- const response = custom;
152
- updatedInput.response = response;
153
- }
154
- return { action: "answered", updatedInput };
199
+ return { action: "answered", updatedInput: { ...toolInput, answers } };
155
200
  }
156
201
  /**
157
202
  * Coerce an arbitrary MCP `requestedSchema` into an ACP `ElicitationSchema`.
package/dist/index.js CHANGED
@@ -2,10 +2,9 @@
2
2
  import { resolveSettings } from "@anthropic-ai/claude-agent-sdk";
3
3
  import { claudeCliPath, runAcp } from "./acp-agent.js";
4
4
  import packageJson from "../package.json" with { type: "json" };
5
- if (process.argv.includes("-v") || process.argv.includes("--version")) {
6
- console.log(packageJson.version);
7
- process.exit(0);
8
- }
5
+ // `--cli` is checked first so that `--version`/`-v` (and any other flags) are
6
+ // forwarded to the wrapped native CLI rather than swallowed by our own version
7
+ // handler below. Our version flag only applies when not delegating.
9
8
  if (process.argv.includes("--cli")) {
10
9
  const { spawn } = await import("node:child_process");
11
10
  const args = process.argv.slice(2).filter((arg) => arg !== "--cli");
@@ -36,6 +35,10 @@ if (process.argv.includes("--cli")) {
36
35
  process.exit(1);
37
36
  });
38
37
  }
38
+ else if (process.argv.includes("--version") || process.argv.includes("-v")) {
39
+ console.log(packageJson.version);
40
+ process.exit(0);
41
+ }
39
42
  else {
40
43
  // Apply env vars from the managed-policy tier before any SDK call so the
41
44
  // SDK subprocess inherits them. Going through resolveSettings (vs. a raw
package/dist/settings.js CHANGED
@@ -35,13 +35,16 @@ function getManagedSettingsPath() {
35
35
  * `filterEscalatingDefaultMode`, matching the CLI's trust policy.
36
36
  */
37
37
  export class SettingsManager {
38
+ cwd;
39
+ effective = {};
40
+ watchers = [];
41
+ onChange;
42
+ logger;
43
+ initialized = false;
44
+ disposed = false;
45
+ debounceTimer = null;
46
+ initPromise = null;
38
47
  constructor(cwd, options) {
39
- this.effective = {};
40
- this.watchers = [];
41
- this.initialized = false;
42
- this.disposed = false;
43
- this.debounceTimer = null;
44
- this.initPromise = null;
45
48
  this.cwd = cwd;
46
49
  this.onChange = options?.onChange;
47
50
  this.logger = options?.logger ?? console;
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
package/dist/tools.js CHANGED
@@ -325,7 +325,8 @@ export function toolUpdateFromToolResult(toolResult, toolUse, supportsTerminalOu
325
325
  if ("is_error" in toolResult &&
326
326
  toolResult.is_error &&
327
327
  toolResult.content &&
328
- toolResult.content.length > 0) {
328
+ toolResult.content.length > 0 &&
329
+ !(toolUse?.name === "Bash" && supportsTerminalOutput)) {
329
330
  // Only return errors
330
331
  return toAcpContentUpdate(toolResult.content, true);
331
332
  }
@@ -365,7 +366,9 @@ export function toolUpdateFromToolResult(toolResult, toolUse, supportsTerminalOu
365
366
  // Extract output and exit code from either format:
366
367
  // 1. BetaBashCodeExecutionResultBlock: { type: "bash_code_execution_result", stdout, stderr, return_code }
367
368
  // 2. Plain string content from a regular tool_result
368
- // 3. Array content (e.g. [{ type: "text", text: "..." }])
369
+ // 3. Array content (e.g. [{ type: "text", text: "..." }] for stdout,
370
+ // or [{ type: "image", source: {...} }] when the local Bash tool
371
+ // produces an image, e.g. piping a base64 data URI)
369
372
  let output = "";
370
373
  let exitCode = isError ? 1 : 0;
371
374
  if (result &&
@@ -379,11 +382,19 @@ export function toolUpdateFromToolResult(toolResult, toolUse, supportsTerminalOu
379
382
  else if (typeof result === "string") {
380
383
  output = result;
381
384
  }
382
- else if (Array.isArray(result) &&
383
- result.length > 0 &&
384
- "text" in result[0] &&
385
- typeof result[0].text === "string") {
386
- output = result.map((c) => c.text).join("\n");
385
+ else if (Array.isArray(result) && result.length > 0) {
386
+ const textOnly = result.every((c) => c && typeof c === "object" && typeof c.text === "string");
387
+ if (textOnly) {
388
+ output = result.map((c) => c.text).join("\n");
389
+ }
390
+ else {
391
+ // Image (or mixed non-text) content. Binary payloads can't be
392
+ // streamed through the terminal-output _meta channel, so bypass
393
+ // it and surface the blocks as ACP content. This handles the
394
+ // local Bash tool's image output, which previously failed the
395
+ // text-only guard and was silently dropped.
396
+ return toAcpContentUpdate(result, isError);
397
+ }
387
398
  }
388
399
  if (supportsTerminalOutput) {
389
400
  return {
package/dist/utils.js CHANGED
@@ -2,11 +2,9 @@
2
2
  import { WritableStream, ReadableStream } from "node:stream/web";
3
3
  // Useful for bridging push-based and async-iterator-based code.
4
4
  export class Pushable {
5
- constructor() {
6
- this.queue = [];
7
- this.resolvers = [];
8
- this.done = false;
9
- }
5
+ queue = [];
6
+ resolvers = [];
7
+ done = false;
10
8
  push(item) {
11
9
  if (this.resolvers.length > 0) {
12
10
  const resolve = this.resolvers.shift();
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.44.0",
6
+ "version": "0.53.0-beta.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",
@@ -59,23 +59,27 @@
59
59
  },
60
60
  "author": "Zed Industries",
61
61
  "license": "Apache-2.0",
62
+ "engines": {
63
+ "node": ">=22"
64
+ },
62
65
  "dependencies": {
63
- "@agentclientprotocol/sdk": "0.25.0",
64
- "@anthropic-ai/claude-agent-sdk": "0.3.170",
66
+ "@agentclientprotocol/sdk": "1.0.0",
67
+ "@anthropic-ai/claude-agent-sdk": "0.3.191",
65
68
  "zod": "^3.25.0 || ^4.0.0"
66
69
  },
67
70
  "devDependencies": {
68
- "@anthropic-ai/sdk": "0.104.1",
71
+ "@anthropic-ai/sdk": "0.106.0",
69
72
  "@eslint/js": "10.0.1",
70
- "@types/node": "25.9.2",
71
- "@typescript-eslint/eslint-plugin": "8.61.0",
72
- "@typescript-eslint/parser": "8.61.0",
73
- "eslint": "10.4.1",
73
+ "@tsconfig/node22": "22.0.5",
74
+ "@types/node": "26.0.1",
75
+ "@typescript-eslint/eslint-plugin": "8.62.0",
76
+ "@typescript-eslint/parser": "8.62.0",
77
+ "eslint": "10.5.0",
74
78
  "eslint-config-prettier": "10.1.8",
75
- "globals": "17.6.0",
79
+ "globals": "17.7.0",
76
80
  "prettier": "3.8.4",
77
81
  "ts-node": "10.9.2",
78
82
  "typescript": "6.0.3",
79
- "vitest": "4.1.8"
83
+ "vitest": "4.1.9"
80
84
  }
81
85
  }