@lucascouts/claude-agent-acp-plus 0.2.0 → 0.4.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,5 @@
1
- import type { CreateElicitationRequest, CreateElicitationResponse } from "@agentclientprotocol/sdk";
1
+ import { CreateElicitationResponse } from "@agentclientprotocol/sdk";
2
+ import type { CreateElicitationRequest } from "@agentclientprotocol/sdk";
2
3
  import type { ElicitationRequest, ElicitationResult } from "@anthropic-ai/claude-agent-sdk";
3
4
  import type { AskUserQuestionInput } from "@anthropic-ai/claude-agent-sdk/sdk-tools.js";
4
5
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"elicitation.d.ts","sourceRoot":"","sources":["../src/elicitation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EAM1B,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;AAyCD;;;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;AAwBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,eAAe,EAAE,EAC5B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,wBAAwB,CAqD1B;AAED,+EAA+E;AAC/E,MAAM,MAAM,sBAAsB,GAChC;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEvF;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,yBAAyB,EACnC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,SAAS,EAAE,eAAe,EAAE,GAC3B,sBAAsB,CAkCxB;AAgBD;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,4BAA4B,CAAC;AAEtE;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,qBAAqB,GAAG,IAAI,CAW9B;AAYD;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,qBAAqB,EAC7B,SAAS,EAAE,MAAM,GAChB,wBAAwB,CA+B1B;AAED;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAAC,QAAQ,EAAE,yBAAyB,GAAG,MAAM,CAG7F"}
1
+ {"version":3,"file":"elicitation.d.ts","sourceRoot":"","sources":["../src/elicitation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EACV,wBAAwB,EAKzB,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;AAgBD;;;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;AAwBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,eAAe,EAAE,EAC5B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,wBAAwB,CAqD1B;AAED,+EAA+E;AAC/E,MAAM,MAAM,sBAAsB,GAChC;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEvF;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,yBAAyB,EACnC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,SAAS,EAAE,eAAe,EAAE,GAC3B,sBAAsB,CAkCxB;AAgBD;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,4BAA4B,CAAC;AAEtE;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,qBAAqB,GAAG,IAAI,CAW9B;AAYD;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,qBAAqB,EAC7B,SAAS,EAAE,MAAM,GAChB,wBAAwB,CA+B1B;AAED;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAAC,QAAQ,EAAE,yBAAyB,GAAG,MAAM,CAG7F"}
@@ -1,4 +1,5 @@
1
1
  import { randomUUID } from "node:crypto";
2
+ import { CreateElicitationResponse } from "@agentclientprotocol/sdk";
2
3
  /**
3
4
  * Convert an MCP elicitation request (from the SDK's `onElicitation` callback)
4
5
  * into an ACP `CreateElicitationRequest`. Returns `null` when the request can't
@@ -29,38 +30,16 @@ export function mcpElicitationToCreateRequest(request, sessionId) {
29
30
  requestedSchema: normalizeElicitationSchema(request.requestedSchema),
30
31
  };
31
32
  }
32
- /** A wire value allowed in elicitation form content. */
33
- function isElicitationContentValue(value) {
34
- return (typeof value === "string" ||
35
- typeof value === "number" ||
36
- typeof value === "boolean" ||
37
- (Array.isArray(value) && value.every((item) => typeof item === "string")));
38
- }
39
33
  /**
40
34
  * Content of an accepted elicitation response.
41
35
  *
42
- * The response union includes a custom/future-action variant whose `action` is
43
- * plain `string`, so a positive `=== "accept"` check can never narrow it away
44
- * and `content` reads as `unknown`. Rather than asserting which union member
45
- * this is, validate the values: the SDK's own wire validation has the same
46
- * blind spot (an accept response with malformed content parses via the
47
- * catch-all variant), so ill-typed values are dropped here either way.
36
+ * Uses the SDK's validating guard rather than an `action === "accept"` check:
37
+ * the guard both narrows past the union's custom/future variant and validates
38
+ * the payload, so a malformed accept (right tag, ill-typed content) yields
39
+ * empty content the same classification the SDK's wire validators apply.
48
40
  */
49
41
  function acceptedElicitationContent(response) {
50
- if (response.action !== "accept") {
51
- return {};
52
- }
53
- const { content } = response;
54
- if (!content || typeof content !== "object") {
55
- return {};
56
- }
57
- const validated = {};
58
- for (const [key, value] of Object.entries(content)) {
59
- if (isElicitationContentValue(value)) {
60
- validated[key] = value;
61
- }
62
- }
63
- return validated;
42
+ return CreateElicitationResponse.isAccept(response) ? (response.content ?? {}) : {};
64
43
  }
65
44
  /**
66
45
  * Map an ACP elicitation response back to the MCP `ElicitResult` the SDK expects
@@ -45,7 +45,7 @@ export function parseRewindInvocation(promptText) {
45
45
  if (/[\r\n]/.test(promptText.trim())) {
46
46
  return null;
47
47
  }
48
- const match = /^\/rewind(?:\s+(.*))?$/.exec(promptText.trim());
48
+ const match = promptText.trim().match(/^\/rewind(?:\s+(\S.*))?$/);
49
49
  if (!match) {
50
50
  return null;
51
51
  }
package/dist/tools.d.ts CHANGED
@@ -35,7 +35,7 @@ interface ToolUpdate {
35
35
  */
36
36
  export declare function toDisplayPath(filePath: string, cwd?: string): string;
37
37
  export declare function toolInfoFromToolUse(toolUse: any, supportsTerminalOutput?: boolean, cwd?: string): ToolInfo;
38
- export declare function toolUpdateFromToolResult(toolResult: ToolResultBlockParam | BetaToolResultBlockParam | BetaWebSearchToolResultBlockParam | BetaWebFetchToolResultBlockParam | WebSearchToolResultBlockParam | BetaCodeExecutionToolResultBlockParam | BetaBashCodeExecutionToolResultBlockParam | BetaTextEditorCodeExecutionToolResultBlockParam | BetaRequestMCPToolResultBlockParam | BetaToolSearchToolResultBlockParam, toolUse: any | undefined, supportsTerminalOutput?: boolean): ToolUpdate;
38
+ export declare function toolUpdateFromToolResult(toolResult: ToolResultBlockParam | BetaToolResultBlockParam | BetaWebSearchToolResultBlockParam | BetaWebFetchToolResultBlockParam | WebSearchToolResultBlockParam | BetaCodeExecutionToolResultBlockParam | BetaBashCodeExecutionToolResultBlockParam | BetaTextEditorCodeExecutionToolResultBlockParam | BetaRequestMCPToolResultBlockParam | BetaToolSearchToolResultBlockParam, toolUse: any | undefined, supportsTerminalOutput?: boolean, toolUseResult?: unknown): ToolUpdate;
39
39
  export type ClaudePlanEntry = {
40
40
  content: string;
41
41
  status: "pending" | "in_progress" | "completed";
@@ -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
@@ -338,7 +338,97 @@ export function toolInfoFromToolUse(toolUse, supportsTerminalOutput = false, cwd
338
338
  };
339
339
  }
340
340
  }
341
- export function toolUpdateFromToolResult(toolResult, toolUse, supportsTerminalOutput = false) {
341
+ /**
342
+ * Narrow the untyped message-level `tool_use_result` toward a per-tool Output
343
+ * shape: rejects everything but a plain non-null object (arrays pass a bare
344
+ * `typeof === "object"` check, so they're excluded here). The returned value
345
+ * is only *nominally* typed — it arrives over the wire from arbitrary CLI
346
+ * versions, so each caller must still guard the specific fields it reads
347
+ * before trusting them.
348
+ */
349
+ function structuredResult(toolUseResult) {
350
+ return toolUseResult !== null &&
351
+ typeof toolUseResult === "object" &&
352
+ !Array.isArray(toolUseResult)
353
+ ? toolUseResult
354
+ : undefined;
355
+ }
356
+ /**
357
+ * Strip the model-directed trailer from a raw Agent/Task tool_result text:
358
+ * a `<usage>…</usage>` totals block and/or an
359
+ * `agentId: <id> (use SendMessage …)` continuation line at the end of the
360
+ * text. Both patterns are tail-anchored and independent (older CLIs emit
361
+ * variants with only one of them), so a format change makes them stop
362
+ * matching rather than mangle the report.
363
+ */
364
+ function stripAgentTrailer(text) {
365
+ // Matched by index rather than by tail-anchored regexes: an unanchored
366
+ // `…\s*$` pattern retries from every start position, so it costs O(n²) on
367
+ // text that repeats the trailer's opening token — and a subagent can echo
368
+ // exactly such text verbatim into its report. The index form is linear and
369
+ // keeps the same tail-anchored, independent semantics.
370
+ let out = text;
371
+ const beforeUsage = out.trimEnd();
372
+ if (beforeUsage.endsWith("</usage>")) {
373
+ // FIRST `<usage>`, not the last: the original pattern was unanchored, so
374
+ // it matched from the leftmost opener and its lazy body then stretched to
375
+ // the final `</usage>` to satisfy `$` — i.e. everything from the first
376
+ // opener onward is part of the stripped trailer.
377
+ const start = beforeUsage.indexOf("<usage>");
378
+ if (start !== -1) {
379
+ out = beforeUsage.slice(0, start);
380
+ if (out.endsWith("\n"))
381
+ out = out.slice(0, -1);
382
+ }
383
+ }
384
+ // `agentId: <id> (…)`. The original `\n?` was optional, so the trailer did
385
+ // NOT have to start a line. Its match is nonetheless unique: `[^)]*` forbids
386
+ // `)` in the body, so the closing paren can only be the final character and
387
+ // the opener can only be the LAST `(` — which pins the whole match without
388
+ // scanning from every position.
389
+ const beforeAgentId = out.trimEnd();
390
+ if (beforeAgentId.endsWith(")")) {
391
+ const open = beforeAgentId.lastIndexOf("(");
392
+ const body = open === -1 ? null : beforeAgentId.slice(open + 1, beforeAgentId.length - 1);
393
+ // A `)` inside the body rules the trailer out (no earlier `(` can help:
394
+ // that stray `)` would still fall inside its body).
395
+ if (body !== null && !body.includes(")")) {
396
+ const head = beforeAgentId.slice(0, open);
397
+ if (head.endsWith(" ")) {
398
+ const beforeSpace = head.slice(0, -1);
399
+ const idStart = beforeSpace.lastIndexOf(" ") + 1;
400
+ const id = beforeSpace.slice(idStart);
401
+ if (AGENT_ID.test(id) && beforeSpace.slice(0, idStart).endsWith("agentId: ")) {
402
+ let start = idStart - "agentId: ".length;
403
+ if (start > 0 && beforeAgentId[start - 1] === "\n")
404
+ start -= 1;
405
+ out = beforeAgentId.slice(0, start);
406
+ }
407
+ }
408
+ }
409
+ }
410
+ return out;
411
+ }
412
+ /** The `<id>` of an `agentId:` trailer — tested only against an already
413
+ * isolated, space-delimited token, never scanned across the whole report. */
414
+ const AGENT_ID = /^[\w-]+$/;
415
+ /** Apply {@link stripAgentTrailer} across a raw tool_result `content` (plain
416
+ * string or block array), leaving non-text blocks untouched. */
417
+ function stripAgentTrailerFromContent(content) {
418
+ if (typeof content === "string") {
419
+ return stripAgentTrailer(content);
420
+ }
421
+ if (Array.isArray(content)) {
422
+ return content.map((block) => block !== null &&
423
+ typeof block === "object" &&
424
+ block.type === "text" &&
425
+ typeof block.text === "string"
426
+ ? { ...block, text: stripAgentTrailer(block.text) }
427
+ : block);
428
+ }
429
+ return content;
430
+ }
431
+ export function toolUpdateFromToolResult(toolResult, toolUse, supportsTerminalOutput = false, toolUseResult) {
342
432
  if ("is_error" in toolResult &&
343
433
  toolResult.is_error &&
344
434
  toolResult.content &&
@@ -347,8 +437,57 @@ export function toolUpdateFromToolResult(toolResult, toolUse, supportsTerminalOu
347
437
  // Only return errors
348
438
  return toAcpContentUpdate(toolResult.content, true);
349
439
  }
440
+ // Shared raw-text fallback: renders the tool_result content the model saw.
441
+ // The structured cases below fall back to this when `tool_use_result` is
442
+ // absent or fails its shape guard (older CLIs, replayed sessions).
443
+ const rawContentUpdate = () => toAcpContentUpdate(toolResult.content, "is_error" in toolResult ? toolResult.is_error : false);
350
444
  switch (toolUse?.name) {
351
- case "Read":
445
+ case "Read": {
446
+ // The raw tool_result text is the model-facing view: line-numbered
447
+ // content plus any appended <system-reminder> blocks (malicious-code
448
+ // checks, memory staleness notes, …) that clients shouldn't see. The
449
+ // structured FileReadOutput carries the clean content — rebuild the
450
+ // line-numbered view from it. Non-text variants (image/notebook/pdf)
451
+ // fall back to the raw content blocks, which already render fine.
452
+ const structuredRead = structuredResult(toolUseResult);
453
+ if (structuredRead?.type === "text" &&
454
+ typeof structuredRead.file?.content === "string" &&
455
+ // An empty file has nothing to line-number; keep the raw view (the
456
+ // model-facing "file is empty" note) rather than a phantom blank line.
457
+ structuredRead.file.content.length > 0) {
458
+ // startLine is typed non-optional but defended anyway; a Read's
459
+ // `offset` input is the same 1-based starting line, so it beats a
460
+ // blind 1 when an emitter omits the field.
461
+ const startLine = structuredRead.file.startLine ??
462
+ toolUse.input?.offset ??
463
+ 1;
464
+ // A trailing newline is a line terminator, not an extra line — don't
465
+ // number a phantom empty line after it.
466
+ let numbered = structuredRead.file.content
467
+ .replace(/\n$/, "")
468
+ .split("\n")
469
+ .map((line, i) => `${startLine + i}\t${line}`)
470
+ .join("\n");
471
+ // The model-facing truncation banner doesn't survive reconstruction
472
+ // from file.content (the SDK flag exists for exactly this case) —
473
+ // re-establish it so a partial first page doesn't read as the whole
474
+ // file.
475
+ if (structuredRead.file.truncatedByTokenCap) {
476
+ const { numLines, totalLines } = structuredRead.file;
477
+ const detail = typeof numLines === "number" && typeof totalLines === "number"
478
+ ? `: showing ${numLines} of ${totalLines} lines`
479
+ : "";
480
+ numbered += `\n[File truncated${detail}]`;
481
+ }
482
+ return {
483
+ content: [
484
+ {
485
+ type: "content",
486
+ content: { type: "text", text: markdownEscape(numbered) },
487
+ },
488
+ ],
489
+ };
490
+ }
352
491
  if (Array.isArray(toolResult.content) && toolResult.content.length > 0) {
353
492
  return {
354
493
  content: toolResult.content.map((content) => ({
@@ -376,19 +515,60 @@ export function toolUpdateFromToolResult(toolResult, toolUse, supportsTerminalOu
376
515
  };
377
516
  }
378
517
  return {};
518
+ }
379
519
  case "Bash": {
380
520
  const result = toolResult.content;
381
521
  const terminalId = "tool_use_id" in toolResult ? String(toolResult.tool_use_id) : "";
382
522
  const isError = "is_error" in toolResult && toolResult.is_error;
383
523
  // Extract output and exit code from either format:
384
- // 1. BetaBashCodeExecutionResultBlock: { type: "bash_code_execution_result", stdout, stderr, return_code }
385
- // 2. Plain string content from a regular tool_result
386
- // 3. Array content (e.g. [{ type: "text", text: "..." }] for stdout,
524
+ // 1. The structured BashOutput (message-level tool_use_result): its
525
+ // stdout/stderr exclude the model-directed suffixes the raw text
526
+ // carries (stale-read hints, gh rate-limit hints, the
527
+ // persisted-output wrapper for too-large outputs — the interruption
528
+ // and truncation facts those carried are re-established from the
529
+ // structured flags below). Skipped for image output (the raw content
530
+ // array carries the actual image blocks) and backgrounded commands
531
+ // (the raw text carries the background-task notice; structured
532
+ // stdout may be empty).
533
+ // 2. BetaBashCodeExecutionResultBlock: { type: "bash_code_execution_result", stdout, stderr, return_code }
534
+ // 3. Plain string content from a regular tool_result
535
+ // 4. Array content (e.g. [{ type: "text", text: "..." }] for stdout,
387
536
  // or [{ type: "image", source: {...} }] when the local Bash tool
388
537
  // produces an image, e.g. piping a base64 data URI)
389
538
  let output = "";
390
539
  let exitCode = isError ? 1 : 0;
391
- if (result &&
540
+ const structuredBash = structuredResult(toolUseResult);
541
+ if (structuredBash &&
542
+ typeof structuredBash.stdout === "string" &&
543
+ typeof structuredBash.stderr === "string" &&
544
+ !structuredBash.isImage &&
545
+ structuredBash.backgroundTaskId === undefined) {
546
+ output = [structuredBash.stdout, structuredBash.stderr].filter(Boolean).join("\n");
547
+ // Two raw-text notices don't survive the structured stdout/stderr —
548
+ // re-establish them so the client isn't shown a clean-looking result:
549
+ // the CLI appends its abort marker only to the model-facing text, and
550
+ // an aborted command isn't a success, so synthesize a failing exit
551
+ // code when the result wasn't already an error.
552
+ if (structuredBash.interrupted) {
553
+ output = [output, "[Command was aborted before completion]"].filter(Boolean).join("\n");
554
+ exitCode = 1;
555
+ }
556
+ // Structured stdout is clipped (~30k chars) when the full output was
557
+ // persisted to disk; without this note the clip is silent and the
558
+ // path to the full output is lost.
559
+ if (typeof structuredBash.persistedOutputPath === "string") {
560
+ const size = typeof structuredBash.persistedOutputSize === "number"
561
+ ? ` (${structuredBash.persistedOutputSize} bytes total)`
562
+ : "";
563
+ output = [
564
+ output,
565
+ `[Output truncated${size}: full output saved to ${structuredBash.persistedOutputPath}]`,
566
+ ]
567
+ .filter(Boolean)
568
+ .join("\n");
569
+ }
570
+ }
571
+ else if (result &&
392
572
  typeof result === "object" &&
393
573
  "type" in result &&
394
574
  result.type === "bash_code_execution_result") {
@@ -448,6 +628,36 @@ export function toolUpdateFromToolResult(toolResult, toolUse, supportsTerminalOu
448
628
  }
449
629
  return {};
450
630
  }
631
+ case "Agent":
632
+ case "Task": {
633
+ // The raw tool_result text ends with a model-directed trailer (an
634
+ // `agentId: … (use SendMessage …)` line plus a `<usage>` totals block)
635
+ // that ACP clients shouldn't see. The message-level `tool_use_result`
636
+ // carries the structured AgentOutput whose `content` is the subagent's
637
+ // report without the trailer — render from it when present (per the SDK
638
+ // 0.3.207 guidance) and fall back to the raw text otherwise (older CLIs,
639
+ // replayed sessions).
640
+ // Narrowed to the full union, not the completed variant — the status
641
+ // check below is what discriminates it, and pre-narrowing would let
642
+ // future field reads typecheck against a variant the runtime value may
643
+ // not be.
644
+ const structured = structuredResult(toolUseResult);
645
+ if (structured?.status === "completed" &&
646
+ Array.isArray(structured.content) &&
647
+ // A completed subagent can end with zero text blocks; an empty
648
+ // structured render would beat the raw fallback for no benefit.
649
+ structured.content.length > 0) {
650
+ return toAcpContentUpdate(structured.content, "is_error" in toolResult ? toolResult.is_error : false);
651
+ }
652
+ // No structured report to render from (replayed sessions —
653
+ // getSessionMessages doesn't expose the transcript's toolUseResult —
654
+ // and older CLIs). The SDK advises rendering from tool_use_result
655
+ // instead of parsing the text, but with no structured value the
656
+ // tail-anchored strip is the only cleanup available; if the trailer
657
+ // format changes it simply stops matching and the full raw text
658
+ // renders, no worse than before.
659
+ return toAcpContentUpdate(stripAgentTrailerFromContent(toolResult.content), "is_error" in toolResult ? toolResult.is_error : false);
660
+ }
451
661
  case "Edit": // Edit is handled in hooks
452
662
  case "Write": {
453
663
  return {};
@@ -455,11 +665,47 @@ export function toolUpdateFromToolResult(toolResult, toolUse, supportsTerminalOu
455
665
  case "ExitPlanMode": {
456
666
  return { title: "Exited Plan Mode" };
457
667
  }
668
+ case "WebSearch": {
669
+ // The raw tool_result text is a model-directed dump ("Web search
670
+ // results for query: …\n\nLinks: [{…json…}]"). The structured
671
+ // WebSearchOutput carries the hits — render them the way server-side
672
+ // web_search_result blocks render ("Title (url)").
673
+ const structuredSearch = structuredResult(toolUseResult);
674
+ if (structuredSearch && Array.isArray(structuredSearch.results)) {
675
+ const lines = structuredSearch.results.flatMap((entry) => typeof entry === "string"
676
+ ? [entry]
677
+ : Array.isArray(entry?.content)
678
+ ? // tool_use_result arrives untyped across CLI version skew —
679
+ // skip off-spec hits rather than rendering
680
+ // "undefined (undefined)" lines.
681
+ entry.content.flatMap((hit) => typeof hit?.title === "string" && typeof hit?.url === "string"
682
+ ? [formatWebSearchHit(hit)]
683
+ : [])
684
+ : []);
685
+ if (lines.length > 0) {
686
+ return {
687
+ content: [
688
+ {
689
+ type: "content",
690
+ content: { type: "text", text: lines.join("\n") },
691
+ },
692
+ ],
693
+ };
694
+ }
695
+ }
696
+ return rawContentUpdate();
697
+ }
458
698
  default: {
459
- return toAcpContentUpdate(toolResult.content, "is_error" in toolResult ? toolResult.is_error : false);
699
+ return rawContentUpdate();
460
700
  }
461
701
  }
462
702
  }
703
+ /** One display format for a web-search hit, shared by the structured
704
+ * WebSearchOutput render and the server-side `web_search_result` block so
705
+ * the two paths can't drift. */
706
+ function formatWebSearchHit(hit) {
707
+ return `${hit.title} (${hit.url})`;
708
+ }
463
709
  function toAcpContentUpdate(content, isError = false) {
464
710
  if (Array.isArray(content) && content.length > 0) {
465
711
  return {
@@ -524,7 +770,7 @@ function toAcpContentBlock(content, isError) {
524
770
  case "tool_search_tool_result_error":
525
771
  return wrapText(`Error: ${content.error_code}${content.error_message ? ` - ${content.error_message}` : ""}`);
526
772
  case "web_search_result":
527
- return wrapText(`${content.title} (${content.url})`);
773
+ return wrapText(formatWebSearchHit(content));
528
774
  case "web_search_tool_result_error":
529
775
  return wrapText(`Error: ${content.error_code}`);
530
776
  case "web_fetch_result":
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.2.0",
6
+ "version": "0.4.0",
7
7
  "description": "ACP adapter for the Claude Agent SDK with VS Code-parity UX for Zed and other ACP clients — checkbox multi-select questions, refusal consent dialog, dynamic agent name. Fork of claude-agent-acp.",
8
8
  "main": "dist/lib.js",
9
9
  "types": "dist/lib.d.ts",
@@ -61,24 +61,24 @@
61
61
  "author": "Zed Industries",
62
62
  "license": "Apache-2.0",
63
63
  "engines": {
64
- "node": ">=22"
64
+ "node": ">=24"
65
65
  },
66
66
  "dependencies": {
67
67
  "@agentclientprotocol/sdk": "1.2.1",
68
- "@anthropic-ai/claude-agent-sdk": "0.3.204",
68
+ "@anthropic-ai/claude-agent-sdk": "0.3.207",
69
69
  "zod": "^3.25.0 || ^4.0.0"
70
70
  },
71
71
  "devDependencies": {
72
- "@anthropic-ai/sdk": "0.110.0",
72
+ "@anthropic-ai/sdk": "0.111.0",
73
73
  "@eslint/js": "10.0.1",
74
- "@tsconfig/node22": "22.0.5",
74
+ "@tsconfig/node24": "24.0.4",
75
75
  "@types/node": "26.1.1",
76
76
  "@typescript-eslint/eslint-plugin": "8.63.0",
77
77
  "@typescript-eslint/parser": "8.63.0",
78
- "eslint": "10.6.0",
78
+ "eslint": "10.7.0",
79
79
  "eslint-config-prettier": "10.1.8",
80
80
  "globals": "17.7.0",
81
- "prettier": "3.9.4",
81
+ "prettier": "3.9.5",
82
82
  "ts-node": "10.9.2",
83
83
  "typescript": "6.0.3",
84
84
  "vitest": "4.1.10"