@agentclientprotocol/claude-agent-acp 0.85.2-preview.1 → 0.85.2-preview.11

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 (45) hide show
  1. package/README.md +1 -0
  2. package/dist/acp-agent.d.ts +113 -27
  3. package/dist/acp-agent.d.ts.map +1 -1
  4. package/dist/acp-agent.js +477 -175
  5. package/dist/air-extension.d.ts +2 -0
  6. package/dist/air-extension.d.ts.map +1 -1
  7. package/dist/air-extension.js +2 -0
  8. package/dist/diff.d.ts +42 -5
  9. package/dist/diff.d.ts.map +1 -1
  10. package/dist/diff.js +103 -26
  11. package/dist/mcp-command.d.ts +51 -0
  12. package/dist/mcp-command.d.ts.map +1 -0
  13. package/dist/mcp-command.js +321 -0
  14. package/dist/resumed-session.d.ts +16 -6
  15. package/dist/resumed-session.d.ts.map +1 -1
  16. package/dist/resumed-session.js +91 -25
  17. package/dist/session-mode.d.ts +14 -0
  18. package/dist/session-mode.d.ts.map +1 -1
  19. package/dist/session-mode.js +22 -0
  20. package/dist/tool-calls/client-capabilities.d.ts +16 -2
  21. package/dist/tool-calls/client-capabilities.d.ts.map +1 -1
  22. package/dist/tool-calls/client-capabilities.js +11 -3
  23. package/dist/tool-calls/reporters/file-edit.d.ts +1 -1
  24. package/dist/tool-calls/reporters/file-edit.d.ts.map +1 -1
  25. package/dist/tool-calls/reporters/file-edit.js +18 -14
  26. package/dist/turn-events.d.ts +71 -0
  27. package/dist/turn-events.d.ts.map +1 -0
  28. package/dist/turn-events.js +1 -0
  29. package/dist/usage-markdown.d.ts +2 -0
  30. package/dist/usage-markdown.d.ts.map +1 -1
  31. package/dist/usage-markdown.js +2 -1
  32. package/dist/utils.d.ts +12 -0
  33. package/dist/utils.d.ts.map +1 -1
  34. package/dist/utils.js +28 -0
  35. package/dist/v2/agent.d.ts.map +1 -1
  36. package/dist/v2/agent.js +27 -5
  37. package/dist/v2/prompt.d.ts +47 -0
  38. package/dist/v2/prompt.d.ts.map +1 -0
  39. package/dist/v2/prompt.js +153 -0
  40. package/dist/v2/session-update.d.ts.map +1 -1
  41. package/dist/v2/session-update.js +14 -0
  42. package/dist/v2/tool-call.d.ts +32 -0
  43. package/dist/v2/tool-call.d.ts.map +1 -0
  44. package/dist/v2/tool-call.js +42 -0
  45. package/package.json +2 -2
@@ -17,6 +17,8 @@ export declare const AIR_SKILL_KEY = "skill";
17
17
  export declare const AIR_CONTEXT_COMPACTION_KEY = "contextCompaction";
18
18
  export declare const AIR_GOAL_KEY = "goal";
19
19
  export declare const AIR_KIND_KEY = "kind";
20
+ /** The absolute path of the `SKILL.md` of a skill command in `available_commands_update`. */
21
+ export declare const AIR_SKILL_PATH_KEY = "skillPath";
20
22
  export declare const AIR_PERMISSION_KEY = "permission";
21
23
  export declare const AIR_CUSTOM_ANSWER_KEY = "customAnswer";
22
24
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"air-extension.d.ts","sourceRoot":"","sources":["../src/air-extension.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,uCAAuC,2BAA2B,CAAC;AAChF,eAAO,MAAM,0BAA0B,eAAe,CAAC;AACvD,eAAO,MAAM,8BAA8B,mBAAmB,CAAC;AAC/D,eAAO,MAAM,uCAAuC,qBAAqB,CAAC;AAC1E,eAAO,MAAM,yBAAyB,cAAc,CAAC;AACrD,4EAA4E;AAC5E,eAAO,MAAM,kCAAkC,sBAAsB,CAAC;AACtE;;;GAGG;AACH,eAAO,MAAM,wBAAwB,aAAa,CAAC;AAEnD,8EAA8E;AAC9E,eAAO,MAAM,qBAAqB,iBAAiB,CAAC;AACpD,eAAO,MAAM,gBAAgB,aAAa,CAAC;AAC3C,eAAO,MAAM,aAAa,UAAU,CAAC;AACrC,eAAO,MAAM,0BAA0B,sBAAsB,CAAC;AAC9D,eAAO,MAAM,YAAY,SAAS,CAAC;AACnC,eAAO,MAAM,YAAY,SAAS,CAAC;AACnC,eAAO,MAAM,kBAAkB,eAAe,CAAC;AAC/C,eAAO,MAAM,qBAAqB,iBAAiB,CAAC;AACpD;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AAQ3E,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,GAAG,YAAY,EAAE,MAAM,EAAE,2BAE1D;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,EAChD,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAczB;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,YAAY,EAAE,OAAO,GAAG,OAAO,CAE1D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,OAAO,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GACpC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAErC;AAED,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAKnF;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAY9F"}
1
+ {"version":3,"file":"air-extension.d.ts","sourceRoot":"","sources":["../src/air-extension.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,uCAAuC,2BAA2B,CAAC;AAChF,eAAO,MAAM,0BAA0B,eAAe,CAAC;AACvD,eAAO,MAAM,8BAA8B,mBAAmB,CAAC;AAC/D,eAAO,MAAM,uCAAuC,qBAAqB,CAAC;AAC1E,eAAO,MAAM,yBAAyB,cAAc,CAAC;AACrD,4EAA4E;AAC5E,eAAO,MAAM,kCAAkC,sBAAsB,CAAC;AACtE;;;GAGG;AACH,eAAO,MAAM,wBAAwB,aAAa,CAAC;AAEnD,8EAA8E;AAC9E,eAAO,MAAM,qBAAqB,iBAAiB,CAAC;AACpD,eAAO,MAAM,gBAAgB,aAAa,CAAC;AAC3C,eAAO,MAAM,aAAa,UAAU,CAAC;AACrC,eAAO,MAAM,0BAA0B,sBAAsB,CAAC;AAC9D,eAAO,MAAM,YAAY,SAAS,CAAC;AACnC,eAAO,MAAM,YAAY,SAAS,CAAC;AACnC,6FAA6F;AAC7F,eAAO,MAAM,kBAAkB,cAAc,CAAC;AAC9C,eAAO,MAAM,kBAAkB,eAAe,CAAC;AAC/C,eAAO,MAAM,qBAAqB,iBAAiB,CAAC;AACpD;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AAQ3E,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,GAAG,YAAY,EAAE,MAAM,EAAE,2BAE1D;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,EAChD,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAczB;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,YAAY,EAAE,OAAO,GAAG,OAAO,CAE1D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,OAAO,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GACpC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAErC;AAED,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAKnF;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAY9F"}
@@ -17,6 +17,8 @@ export const AIR_SKILL_KEY = "skill";
17
17
  export const AIR_CONTEXT_COMPACTION_KEY = "contextCompaction";
18
18
  export const AIR_GOAL_KEY = "goal";
19
19
  export const AIR_KIND_KEY = "kind";
20
+ /** The absolute path of the `SKILL.md` of a skill command in `available_commands_update`. */
21
+ export const AIR_SKILL_PATH_KEY = "skillPath";
20
22
  export const AIR_PERMISSION_KEY = "permission";
21
23
  export const AIR_CUSTOM_ANSWER_KEY = "customAnswer";
22
24
  /**
package/dist/diff.d.ts CHANGED
@@ -23,6 +23,17 @@ interface PatchHunk {
23
23
  }
24
24
  /** The kind of file change that a git patch describes. */
25
25
  type FileChange = "create" | "update";
26
+ /**
27
+ * The diff that carries an exact patch: AIR's `diffPatch` extension of a v1
28
+ * diff, or an ACP v2 diff.
29
+ */
30
+ export type PatchForm = "air" | "v2";
31
+ /**
32
+ * How a git patch names its file. `git` is git's own form: the leading slash
33
+ * dropped and the `a/` and `b/` prefixes added. `absolute` is the form of an
34
+ * ACP v2 `git_patch`, whose paths must be absolute: the path itself.
35
+ */
36
+ type GitPatchPaths = "git" | "absolute";
26
37
  /**
27
38
  * Builds the exact patch shown before Claude runs an Edit or Write tool.
28
39
  *
@@ -54,7 +65,7 @@ export declare function previewPatchContent(toolName: string, input: Record<stri
54
65
  * A written file that contains a CR or a byte order mark is declined, because
55
66
  * Claude removed those bytes from `originalFile`.
56
67
  */
57
- export declare function patchUpdateFromDiffToolResponse(toolResponse: unknown): Promise<{
68
+ export declare function patchUpdateFromDiffToolResponse(toolResponse: unknown, form?: PatchForm): Promise<{
58
69
  content: ToolCallContent[];
59
70
  locations: ToolCallLocation[];
60
71
  } | undefined>;
@@ -69,13 +80,39 @@ export declare function toolUpdateFromDiffToolResponse(toolResponse: unknown): {
69
80
  content?: ToolCallContent[];
70
81
  locations?: ToolCallLocation[];
71
82
  };
83
+ /**
84
+ * The ACP v2 diff of a finished Edit or Write: the exact patch of
85
+ * {@link patchUpdateFromDiffToolResponse} when it can be built, else the
86
+ * change with a patch from what the toolResponse holds.
87
+ *
88
+ * The fallback patch of an update comes from the `structuredPatch`, which is
89
+ * display data (see {@link patchUpdateFromDiffToolResponse}). That is enough
90
+ * for a v2 patch, which is renderable text, not a patch to apply. An update
91
+ * without hunks, such as one whose previous content was too large to diff,
92
+ * gets the change alone. An Edit with an empty `old_string` reports the same
93
+ * response for a created file and a filled empty one, so it gets no diff.
94
+ */
95
+ export declare function v2UpdateFromDiffToolResponse(toolResponse: unknown): Promise<{
96
+ content?: ToolCallContent[];
97
+ locations?: ToolCallLocation[];
98
+ }>;
72
99
  /**
73
100
  * The text of one git patch for `filePath`.
74
101
  *
75
- * The headers follow `git diff`: the path loses its leading slash, gets the
76
- * `a/` and `b/` prefixes, and is quoted when git would quote it. A created
77
- * file gets its mode line and a `/dev/null` side.
102
+ * The headers follow `git diff`: the path is quoted when git would quote it,
103
+ * and a created file gets its mode line and a `/dev/null` side. With `git`
104
+ * paths, the path loses its leading slash and gets the `a/` and `b/` prefixes.
105
+ */
106
+ export declare function gitPatchText(filePath: string, change: FileChange, hunks: PatchHunk[], paths?: GitPatchPaths): string;
107
+ /**
108
+ * The ACP v2 diff of a change to the text file `filePath`: the change and,
109
+ * given hunks, its git patch.
110
+ *
111
+ * The agent builds tool call content in v1 types, and v1 cannot express a v2
112
+ * diff, so the diff travels as v1 content. Nothing in the agent reads inside a
113
+ * diff, and only a v2 client gets one: the v2 surface sends it as it is
114
+ * (`src/v2/tool-call.ts`).
78
115
  */
79
- export declare function gitPatchText(filePath: string, change: FileChange, hunks: PatchHunk[]): string;
116
+ export declare function v2DiffContent(filePath: string, change: FileChange, hunks?: PatchHunk[]): ToolCallContent;
80
117
  export {};
81
118
  //# sourceMappingURL=diff.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAQ7E;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,QAAc,CAAC;AAkBhD;;;;;GAKG;AACH,UAAU,SAAS;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AA0BD,0DAA0D;AAC1D,KAAK,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEtC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,eAAe,EAAE,GAAG,SAAS,CAAC,CAkExC;AA0CD;;;;;;;;;;GAUG;AACH,wBAAsB,+BAA+B,CACnD,YAAY,EAAE,OAAO,GACpB,OAAO,CAAC;IAAE,OAAO,EAAE,eAAe,EAAE,CAAC;IAAC,SAAS,EAAE,gBAAgB,EAAE,CAAA;CAAE,GAAG,SAAS,CAAC,CA0CpF;AAED;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,OAAO,GAAG;IACrE,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAChC,CAoEA;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,CAM7F"}
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAS7E;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,QAAc,CAAC;AAkBhD;;;;;GAKG;AACH,UAAU,SAAS;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AA0BD,0DAA0D;AAC1D,KAAK,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAQtC;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,IAAI,CAAC;AAErC;;;;GAIG;AACH,KAAK,aAAa,GAAG,KAAK,GAAG,UAAU,CAAC;AAKxC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,eAAe,EAAE,GAAG,SAAS,CAAC,CAkExC;AA0CD;;;;;;;;;;GAUG;AACH,wBAAsB,+BAA+B,CACnD,YAAY,EAAE,OAAO,EACrB,IAAI,GAAE,SAAiB,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,eAAe,EAAE,CAAC;IAAC,SAAS,EAAE,gBAAgB,EAAE,CAAA;CAAE,GAAG,SAAS,CAAC,CA8CpF;AAED;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,OAAO,GAAG;IACrE,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAChC,CAoEA;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,4BAA4B,CAAC,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC;IACjF,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAChC,CAAC,CAgCD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,SAAS,EAAE,EAClB,KAAK,GAAE,aAAqB,GAC3B,MAAM,CAMR;AAmOD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,EAClB,KAAK,CAAC,EAAE,SAAS,EAAE,GAClB,eAAe,CAajB"}
package/dist/diff.js CHANGED
@@ -67,7 +67,7 @@ export async function previewPatchContent(toolName, input, cwd) {
67
67
  if (oldText !== null && (oldText.trim() !== "" || oldText.includes("\uFEFF"))) {
68
68
  return undefined;
69
69
  }
70
- return optionalContent(filePatch(filePath, oldText, newString)?.content);
70
+ return airPatch(filePath, oldText, newString);
71
71
  }
72
72
  if (oldText === null)
73
73
  return undefined;
@@ -78,7 +78,7 @@ export async function previewPatchContent(toolName, input, cwd) {
78
78
  return undefined;
79
79
  }
80
80
  const newText = replacedText(oldText, oldString, newString, edit.replace_all === true);
81
- return optionalContent(filePatch(filePath, oldText, newText)?.content);
81
+ return airPatch(filePath, oldText, newText);
82
82
  }
83
83
  if (toolName === "Write") {
84
84
  const write = normalizeWriteInput(input);
@@ -109,7 +109,7 @@ export async function previewPatchContent(toolName, input, cwd) {
109
109
  if (!isPatchableText(content))
110
110
  return standard;
111
111
  // A dense change can exceed the diff budget. The approval then shows the standard diff.
112
- return optionalContent(filePatch(filePath, oldText, content)?.content) ?? standard;
112
+ return airPatch(filePath, oldText, content) ?? standard;
113
113
  }
114
114
  return undefined;
115
115
  }
@@ -151,7 +151,7 @@ function replacedText(fileText, oldString, newString, replaceAll) {
151
151
  * A written file that contains a CR or a byte order mark is declined, because
152
152
  * Claude removed those bytes from `originalFile`.
153
153
  */
154
- export async function patchUpdateFromDiffToolResponse(toolResponse) {
154
+ export async function patchUpdateFromDiffToolResponse(toolResponse, form = "air") {
155
155
  if (!toolResponse || typeof toolResponse !== "object")
156
156
  return undefined;
157
157
  const response = toolResponse;
@@ -185,11 +185,15 @@ export async function patchUpdateFromDiffToolResponse(toolResponse) {
185
185
  return undefined;
186
186
  if (response.type === "create" && newText !== response.content)
187
187
  return undefined;
188
- const patch = filePatch(response.filePath, oldText, newText);
188
+ const patch = filePatch(oldText, newText);
189
189
  if (!patch)
190
190
  return undefined;
191
191
  return {
192
- content: [patch.content],
192
+ content: [
193
+ form === "v2"
194
+ ? v2DiffContent(response.filePath, patch.change, patch.hunks)
195
+ : airPatchContent(response.filePath, patch),
196
+ ],
193
197
  // A created file keeps the location of its Write tool call.
194
198
  locations: oldText === null
195
199
  ? [{ path: response.filePath }]
@@ -274,26 +278,75 @@ export function toolUpdateFromDiffToolResponse(toolResponse) {
274
278
  result.locations = locations;
275
279
  return result;
276
280
  }
281
+ /**
282
+ * The ACP v2 diff of a finished Edit or Write: the exact patch of
283
+ * {@link patchUpdateFromDiffToolResponse} when it can be built, else the
284
+ * change with a patch from what the toolResponse holds.
285
+ *
286
+ * The fallback patch of an update comes from the `structuredPatch`, which is
287
+ * display data (see {@link patchUpdateFromDiffToolResponse}). That is enough
288
+ * for a v2 patch, which is renderable text, not a patch to apply. An update
289
+ * without hunks, such as one whose previous content was too large to diff,
290
+ * gets the change alone. An Edit with an empty `old_string` reports the same
291
+ * response for a created file and a filled empty one, so it gets no diff.
292
+ */
293
+ export async function v2UpdateFromDiffToolResponse(toolResponse) {
294
+ const exact = await patchUpdateFromDiffToolResponse(toolResponse, "v2");
295
+ if (exact)
296
+ return exact;
297
+ if (!toolResponse || typeof toolResponse !== "object")
298
+ return {};
299
+ const response = toolResponse;
300
+ const filePath = response.filePath;
301
+ if (typeof filePath !== "string")
302
+ return {};
303
+ if (response.type === "create") {
304
+ const hunk = typeof response.content === "string" && isPatchableText(response.content)
305
+ ? wholeFileHunk(response.content)
306
+ : undefined;
307
+ return {
308
+ content: [v2DiffContent(filePath, "create", hunk && [hunk])],
309
+ locations: [{ path: filePath }],
310
+ };
311
+ }
312
+ if (response.type === undefined && response.oldString === "" && response.originalFile === "") {
313
+ return {};
314
+ }
315
+ // A Write whose content is the previous text changed nothing.
316
+ if (response.type === "update" && response.content === response.originalFile)
317
+ return {};
318
+ const hunks = Array.isArray(response.structuredPatch) && response.structuredPatch.length > 0
319
+ ? response.structuredPatch
320
+ : undefined;
321
+ return {
322
+ content: [v2DiffContent(filePath, "update", hunks)],
323
+ locations: hunks
324
+ ? hunks.map(({ newStart }) => ({ path: filePath, line: newStart }))
325
+ : [{ path: filePath }],
326
+ };
327
+ }
277
328
  /**
278
329
  * The text of one git patch for `filePath`.
279
330
  *
280
- * The headers follow `git diff`: the path loses its leading slash, gets the
281
- * `a/` and `b/` prefixes, and is quoted when git would quote it. A created
282
- * file gets its mode line and a `/dev/null` side.
331
+ * The headers follow `git diff`: the path is quoted when git would quote it,
332
+ * and a created file gets its mode line and a `/dev/null` side. With `git`
333
+ * paths, the path loses its leading slash and gets the `a/` and `b/` prefixes.
283
334
  */
284
- export function gitPatchText(filePath, change, hunks) {
335
+ export function gitPatchText(filePath, change, hunks, paths = "git") {
285
336
  return [
286
- ...gitPatchHeader(filePath, change),
337
+ ...gitPatchHeader(filePath, change, paths),
287
338
  ...hunks.flatMap((hunk) => [hunkHeader(hunk), ...hunk.lines]),
288
339
  "",
289
340
  ].join("\n");
290
341
  }
291
- function gitPatchHeader(filePath, change) {
292
- // git drops one leading slash of an absolute path; a Windows path gets
293
- // forward slashes so the header names the same file on every platform.
294
- const name = filePath.replaceAll("\\", "/").replace(/^\/+/u, "");
295
- const oldName = quoteGitPath("a/", name);
296
- const newName = quoteGitPath("b/", name);
342
+ function gitPatchHeader(filePath, change, paths) {
343
+ // A Windows path gets forward slashes so the header names the same file on
344
+ // every platform.
345
+ const slashed = filePath.replaceAll("\\", "/");
346
+ // git drops one leading slash of an absolute path.
347
+ const name = paths === "git" ? slashed.replace(/^\/+/u, "") : slashed;
348
+ const oldName = quoteGitPath(paths === "git" ? "a/" : "", name);
349
+ const newName = quoteGitPath(paths === "git" ? "b/" : "", name);
297
350
  // git ends a ---/+++ name that contains a space with a tab, for GNU patch.
298
351
  const tab = name.includes(" ") ? "\t" : "";
299
352
  return [
@@ -400,15 +453,15 @@ function textLines(text) {
400
453
  return text.match(/[^\n]*\n|[^\n]+$/g) ?? [];
401
454
  }
402
455
  /**
403
- * The git patch of a file change and its hunks. Returns undefined when
404
- * nothing changed or the diff runs out of its time budget.
456
+ * The patch of a change from `oldText`, null for a missing file, to
457
+ * `newText`. Returns undefined when nothing changed or the diff runs out of
458
+ * its time budget.
405
459
  */
406
- function filePatch(filePath, oldText, newText) {
460
+ function filePatch(oldText, newText) {
407
461
  const hunks = diffHunks(oldText, newText);
408
462
  if (!hunks || hunks.length === 0)
409
463
  return undefined;
410
- const change = oldText === null ? "create" : "update";
411
- return { content: patchContent(filePath, gitPatchText(filePath, change, hunks)), hunks };
464
+ return { change: oldText === null ? "create" : "update", hunks };
412
465
  }
413
466
  /**
414
467
  * Reads a file as patch input.
@@ -472,8 +525,10 @@ function isPatchableText(text) {
472
525
  !text.includes("\0") &&
473
526
  !text.includes("\r"));
474
527
  }
475
- function optionalContent(content) {
476
- return content ? [content] : undefined;
528
+ /** The AIR patch content of a change, or undefined when it has no patch. */
529
+ function airPatch(filePath, oldText, newText) {
530
+ const patch = filePatch(oldText, newText);
531
+ return patch && [airPatchContent(filePath, patch)];
477
532
  }
478
533
  /**
479
534
  * A diff block in the AIR patch form.
@@ -481,7 +536,7 @@ function optionalContent(content) {
481
536
  * `oldText: null` and `newText: ""` only satisfy the ACP schema. The adapter
482
537
  * sends this form only to a client that advertised `diffPatch`.
483
538
  */
484
- function patchContent(filePath, text) {
539
+ function airPatchContent(filePath, { change, hunks }) {
485
540
  return {
486
541
  type: "diff",
487
542
  path: filePath,
@@ -490,10 +545,32 @@ function patchContent(filePath, text) {
490
545
  _meta: withAirMeta(undefined, AIR_DIFF_PATCH_CAPABILITY, {
491
546
  version: 1,
492
547
  format: "git_patch",
493
- text,
548
+ text: gitPatchText(filePath, change, hunks),
494
549
  }),
495
550
  };
496
551
  }
552
+ /**
553
+ * The ACP v2 diff of a change to the text file `filePath`: the change and,
554
+ * given hunks, its git patch.
555
+ *
556
+ * The agent builds tool call content in v1 types, and v1 cannot express a v2
557
+ * diff, so the diff travels as v1 content. Nothing in the agent reads inside a
558
+ * diff, and only a v2 client gets one: the v2 surface sends it as it is
559
+ * (`src/v2/tool-call.ts`).
560
+ */
561
+ export function v2DiffContent(filePath, change, hunks) {
562
+ const fileChange = change === "create"
563
+ ? { operation: "add", path: filePath, fileType: "text" }
564
+ : { operation: "modify", path: filePath, fileType: "text" };
565
+ const diff = {
566
+ type: "diff",
567
+ changes: [fileChange],
568
+ ...(hunks?.length
569
+ ? { patch: { format: "git_patch", text: gitPatchText(filePath, change, hunks, "absolute") } }
570
+ : {}),
571
+ };
572
+ return diff;
573
+ }
497
574
  function resolveToolPath(filePath, cwd) {
498
575
  return path.isAbsolute(filePath) ? filePath : path.resolve(cwd ?? process.cwd(), filePath);
499
576
  }
@@ -0,0 +1,51 @@
1
+ import type { AvailableCommand } from "@agentclientprotocol/sdk";
2
+ import type { McpServerStatus, Query } from "@anthropic-ai/claude-agent-sdk";
3
+ /** The `/mcp` entry of `available_commands_update`. The adapter shows the
4
+ * servers as a list, and runs a reconnect, an enable, or a disable through
5
+ * the SDK control API. */
6
+ export declare const MCP_AVAILABLE_COMMAND: AvailableCommand;
7
+ /** A `/mcp` prompt that gets a replacement for its Claude Code text. `all` is
8
+ * true for `all` and for a reconnect without a server name, as in Claude
9
+ * Code. `server` is undefined for an enable or a disable without a name. */
10
+ export type McpCommand = {
11
+ action: "status";
12
+ } | {
13
+ action: "reconnect" | "enable" | "disable";
14
+ all: boolean;
15
+ server?: string;
16
+ };
17
+ /** Parse a prompt that is exactly `/mcp`, or `/mcp reconnect`, `/mcp enable`,
18
+ * or `/mcp disable` with an optional server name or `all`. Any other `/mcp`
19
+ * argument gives null, and the prompt gets no replacement. */
20
+ export declare function parseMcpCommand(text: string): McpCommand | null;
21
+ /** Read the MCP server status for the list after a `/mcp` command. Resolves
22
+ * to null when the read fails, takes too long, or `signal` aborts. Then the
23
+ * turn keeps the text of Claude Code. */
24
+ export declare function readMcpServerStatus(query: Pick<Query, "mcpServerStatus">, signal: AbortSignal, logError: (message: string) => void): Promise<McpServerStatus[] | null>;
25
+ /** Make an MCP error short and readable for one list item. The result has
26
+ * no leading wrapper segments, at most two sentences, and at most
27
+ * `MAX_ERROR_LENGTH` code points. A wrapper before an error code stays, so
28
+ * an error code is never alone. The result is empty for an error with only
29
+ * whitespace. */
30
+ export declare function cleanMcpError(error: string): string;
31
+ /** Markdown for `/mcp`: a summary line, one group of servers for each
32
+ * status, and the disabled servers on one line. A list reads better than a
33
+ * table in a narrow chat. */
34
+ export declare function formatMcpStatus(statuses: McpServerStatus[]): string;
35
+ /** The SDK query methods that `/mcp` uses. */
36
+ export type McpControlQuery = Pick<Query, "mcpServerStatus" | "reconnectMcpServer" | "toggleMcpServer">;
37
+ /** The result of {@link runMcpCommand}. `markdown` is null when the turn
38
+ * keeps the text of Claude Code. `reconnected` holds the servers that the
39
+ * adapter tried to reconnect. */
40
+ export type McpCommandOutcome = {
41
+ markdown: string | null;
42
+ reconnected: string[];
43
+ };
44
+ /** Run a `/mcp` command after Claude Code sent `originalOutput`, its text for
45
+ * the command. Claude Code refuses a reconnect, an enable, and a disable in
46
+ * SDK mode, so the adapter runs them through the SDK control API. The result
47
+ * of each server goes above the server list. An error of one server does
48
+ * not stop the others. When the first status read fails or `signal`
49
+ * aborts, the turn keeps the text of Claude Code. */
50
+ export declare function runMcpCommand(query: McpControlQuery, command: McpCommand, originalOutput: string, signal: AbortSignal, logError: (message: string) => void): Promise<McpCommandOutcome>;
51
+ //# sourceMappingURL=mcp-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-command.d.ts","sourceRoot":"","sources":["../src/mcp-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAI7E;;2BAE2B;AAC3B,eAAO,MAAM,qBAAqB,EAAE,gBAInC,CAAC;AAQF;;6EAE6E;AAC7E,MAAM,MAAM,UAAU,GAClB;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,GACpB;IAAE,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAElF;;+DAE+D;AAC/D,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAW/D;AAED;;0CAE0C;AAC1C,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,iBAAiB,CAAC,EACrC,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAClC,OAAO,CAAC,eAAe,EAAE,GAAG,IAAI,CAAC,CAkBnC;AAuED;;;;kBAIkB;AAClB,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAiBnD;AA2DD;;8BAE8B;AAC9B,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,MAAM,CA6BnE;AAED,8CAA8C;AAC9C,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,KAAK,EACL,iBAAiB,GAAG,oBAAoB,GAAG,iBAAiB,CAC7D,CAAC;AAEF;;kCAEkC;AAClC,MAAM,MAAM,iBAAiB,GAAG;IAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AA4DnF;;;;;sDAKsD;AACtD,wBAAsB,aAAa,CACjC,KAAK,EAAE,eAAe,EACtB,OAAO,EAAE,UAAU,EACnB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAClC,OAAO,CAAC,iBAAiB,CAAC,CAoD5B"}