zidane 5.12.10 → 5.13.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 (122) hide show
  1. package/README.md +17 -0
  2. package/dist/acp-CEE6C0m_.js +1313 -0
  3. package/dist/acp-CEE6C0m_.js.map +1 -0
  4. package/dist/acp-cli.d.ts +1 -0
  5. package/dist/acp-cli.js +575 -0
  6. package/dist/acp-cli.js.map +1 -0
  7. package/dist/acp.d.ts +616 -0
  8. package/dist/acp.d.ts.map +1 -0
  9. package/dist/acp.js +2 -0
  10. package/dist/{agent-DFxjgQx5.d.ts → agent-D7ZL8B2X.d.ts} +359 -50
  11. package/dist/agent-D7ZL8B2X.d.ts.map +1 -0
  12. package/dist/atomic-write-Bgtr5JPu.js +100 -0
  13. package/dist/atomic-write-Bgtr5JPu.js.map +1 -0
  14. package/dist/chat/pure.d.ts +3 -3
  15. package/dist/chat.d.ts +17 -117
  16. package/dist/chat.d.ts.map +1 -1
  17. package/dist/chat.js +3 -3
  18. package/dist/contexts/daytona.d.ts +3 -3
  19. package/dist/contexts/docker.d.ts +1 -1
  20. package/dist/contexts/docker.d.ts.map +1 -1
  21. package/dist/contexts/docker.js +4 -1
  22. package/dist/contexts/docker.js.map +1 -1
  23. package/dist/contexts/e2b.d.ts +2 -2
  24. package/dist/{contexts-DglWSzmR.js → contexts-DHi8LPCp.js} +51 -9
  25. package/dist/contexts-DHi8LPCp.js.map +1 -0
  26. package/dist/contexts.d.ts +3 -3
  27. package/dist/contexts.js +1 -1
  28. package/dist/eval.d.ts +1 -1
  29. package/dist/eval.js +4 -4
  30. package/dist/glob-DCWXy_tr.js +128 -0
  31. package/dist/glob-DCWXy_tr.js.map +1 -0
  32. package/dist/{headless-Cbknpgjo.js → headless-Bz1SpTB-.js} +7 -7
  33. package/dist/headless-Bz1SpTB-.js.map +1 -0
  34. package/dist/headless.d.ts +1 -1
  35. package/dist/headless.js +1 -1
  36. package/dist/{index-C3wPsOFw.d.ts → index-BsyPeCSL.d.ts} +3 -3
  37. package/dist/{index-C3wPsOFw.d.ts.map → index-BsyPeCSL.d.ts.map} +1 -1
  38. package/dist/{index-DoQ0MHlp.d.ts → index-CDcQW-2S.d.ts} +87 -19
  39. package/dist/index-CDcQW-2S.d.ts.map +1 -0
  40. package/dist/{index-CrMb8jCE.d.ts → index-CF15aqlk.d.ts} +3 -3
  41. package/dist/{index-CrMb8jCE.d.ts.map → index-CF15aqlk.d.ts.map} +1 -1
  42. package/dist/index.d.ts +8 -7
  43. package/dist/index.js +12 -12
  44. package/dist/{interpolate-Da6kPCXn.js → interpolate-ConAiXGy.js} +2 -2
  45. package/dist/{interpolate-Da6kPCXn.js.map → interpolate-ConAiXGy.js.map} +1 -1
  46. package/dist/lazy-DLOurOC_.js +20 -0
  47. package/dist/lazy-DLOurOC_.js.map +1 -0
  48. package/dist/{logger-DZcTJ3YX.d.ts → logger-DItaCwPw.d.ts} +2 -2
  49. package/dist/{logger-DZcTJ3YX.d.ts.map → logger-DItaCwPw.d.ts.map} +1 -1
  50. package/dist/login-D5rb4IG8.js +267 -0
  51. package/dist/login-D5rb4IG8.js.map +1 -0
  52. package/dist/{mcp-Bl0n3bNL.js → mcp-C_TIj91j.js} +2 -2
  53. package/dist/{mcp-Bl0n3bNL.js.map → mcp-C_TIj91j.js.map} +1 -1
  54. package/dist/mcp.d.ts +1 -1
  55. package/dist/mcp.js +1 -1
  56. package/dist/{messages-CV_K9I6j.js → messages-CGazSyTL.js} +16 -13
  57. package/dist/messages-CGazSyTL.js.map +1 -0
  58. package/dist/output/stream-json.d.ts +2 -2
  59. package/dist/output/stream-json.js +1 -1
  60. package/dist/output/terminal.d.ts +2 -2
  61. package/dist/policy-DcGlpaNs.d.ts +129 -0
  62. package/dist/policy-DcGlpaNs.d.ts.map +1 -0
  63. package/dist/{presets-BsMR5nn6.js → presets-5IGiSsxm.js} +2 -2
  64. package/dist/{presets-BsMR5nn6.js.map → presets-5IGiSsxm.js.map} +1 -1
  65. package/dist/presets.d.ts +2 -2
  66. package/dist/presets.js +1 -1
  67. package/dist/{providers-C6rpOk0l.js → providers-DMPAmUuY.js} +47 -122
  68. package/dist/providers-DMPAmUuY.js.map +1 -0
  69. package/dist/providers.d.ts +1 -1
  70. package/dist/providers.js +2 -2
  71. package/dist/restate.d.ts +2 -2
  72. package/dist/restate.js +2 -1
  73. package/dist/restate.js.map +1 -1
  74. package/dist/session/sqlite.d.ts +1 -1
  75. package/dist/{session-nRmW_P8d.js → session-B69BQSn1.js} +2 -2
  76. package/dist/{session-nRmW_P8d.js.map → session-B69BQSn1.js.map} +1 -1
  77. package/dist/session.d.ts +1 -1
  78. package/dist/session.js +2 -2
  79. package/dist/skills.d.ts +2 -2
  80. package/dist/skills.js +1 -1
  81. package/dist/{tool-formatters-CCTIq3A-.d.ts → tool-formatters-CNSMadtp.d.ts} +9 -31
  82. package/dist/tool-formatters-CNSMadtp.d.ts.map +1 -0
  83. package/dist/tools/fetch-url.d.ts +1 -1
  84. package/dist/tools/web-search.d.ts +1 -1
  85. package/dist/{tools-fqToqHik.js → tools-CfS7rjuh.js} +2139 -1371
  86. package/dist/tools-CfS7rjuh.js.map +1 -0
  87. package/dist/tools.d.ts +2 -2
  88. package/dist/tools.js +1 -1
  89. package/dist/{transcript-anchors-Br_NijUC.js → transcript-anchors-B_a1edre.js} +1204 -105
  90. package/dist/transcript-anchors-B_a1edre.js.map +1 -0
  91. package/dist/{transcript-anchors-DxAfqo4i.d.ts → transcript-anchors-EG-SmZRu.d.ts} +17 -5
  92. package/dist/transcript-anchors-EG-SmZRu.d.ts.map +1 -0
  93. package/dist/tui.d.ts +3 -3
  94. package/dist/tui.d.ts.map +1 -1
  95. package/dist/tui.js +102 -148
  96. package/dist/tui.js.map +1 -1
  97. package/dist/{turn-operations-BTxf15kt.d.ts → turn-operations-DwtWRYr1.d.ts} +3 -3
  98. package/dist/{turn-operations-BTxf15kt.d.ts.map → turn-operations-DwtWRYr1.d.ts.map} +1 -1
  99. package/dist/{types-B39tBba1.d.ts → types-Bs2oY7Ux.d.ts} +27 -4
  100. package/dist/types-Bs2oY7Ux.d.ts.map +1 -0
  101. package/dist/types-DxHDaqN7.js.map +1 -1
  102. package/dist/types.d.ts +4 -4
  103. package/dist/types.js +1 -1
  104. package/docs/ACP.md +153 -0
  105. package/docs/ARCHITECTURE.md +6 -2
  106. package/docs/CHAT.md +29 -28
  107. package/docs/SKILL.md +1 -1
  108. package/docs/TUI.md +8 -8
  109. package/package.json +15 -5
  110. package/dist/agent-DFxjgQx5.d.ts.map +0 -1
  111. package/dist/contexts-DglWSzmR.js.map +0 -1
  112. package/dist/headless-Cbknpgjo.js.map +0 -1
  113. package/dist/index-DoQ0MHlp.d.ts.map +0 -1
  114. package/dist/login-uf01y_Yj.js +0 -1272
  115. package/dist/login-uf01y_Yj.js.map +0 -1
  116. package/dist/messages-CV_K9I6j.js.map +0 -1
  117. package/dist/providers-C6rpOk0l.js.map +0 -1
  118. package/dist/tool-formatters-CCTIq3A-.d.ts.map +0 -1
  119. package/dist/tools-fqToqHik.js.map +0 -1
  120. package/dist/transcript-anchors-Br_NijUC.js.map +0 -1
  121. package/dist/transcript-anchors-DxAfqo4i.d.ts.map +0 -1
  122. package/dist/types-B39tBba1.d.ts.map +0 -1
@@ -0,0 +1,1313 @@
1
+ import { d as createAgent } from "./tools-CfS7rjuh.js";
2
+ import { r as createProcessContext } from "./contexts-DHi8LPCp.js";
3
+ import { o as toolResultToText } from "./types-DxHDaqN7.js";
4
+ import { o as readStateKey, r as hashContent, s as resolveReadStateMap } from "./read-state-DH2IuQHX.js";
5
+ import { l as errorMessage } from "./errors-BpPfMo_4.js";
6
+ import { t as effectiveInputFromTurn } from "./stats-DAKBEKjc.js";
7
+ import { i as basic_default } from "./presets-5IGiSsxm.js";
8
+ import { r as loadSession, t as createSession } from "./session-B69BQSn1.js";
9
+ import { resolve } from "node:path";
10
+ import { Buffer } from "node:buffer";
11
+ //#region src/acp/json-rpc.ts
12
+ function createJsonRpcConnection(options) {
13
+ let nextId = 1;
14
+ let closed = false;
15
+ let buffer = Buffer.alloc(0);
16
+ const pending = /* @__PURE__ */ new Map();
17
+ const writeMessage = (message) => {
18
+ if (closed) return;
19
+ const json = JSON.stringify({
20
+ ...message,
21
+ jsonrpc: "2.0"
22
+ });
23
+ if (options.framing === "content-length") {
24
+ const bytes = Buffer.byteLength(json);
25
+ options.output.write(`Content-Length: ${bytes}\r\n\r\n${json}`);
26
+ return;
27
+ }
28
+ options.output.write(`${json}\n`);
29
+ };
30
+ const handleParsed = async (message) => {
31
+ if (!isObject$1(message)) {
32
+ writeMessage(errorResponse(null, -32600, "Invalid JSON-RPC message."));
33
+ return;
34
+ }
35
+ const msg = message;
36
+ if ("id" in msg && ("result" in msg || "error" in msg)) {
37
+ const request = pending.get(msg.id);
38
+ if (!request) return;
39
+ pending.delete(msg.id);
40
+ if ("error" in msg && msg.error) request.reject(new JsonRpcRemoteError(msg.error.message, msg.error.code, msg.error.data));
41
+ else request.resolve(msg.result);
42
+ return;
43
+ }
44
+ if (typeof msg.method !== "string") {
45
+ writeMessage(errorResponse(("id" in msg ? msg.id : null) ?? null, -32600, "Missing JSON-RPC method."));
46
+ return;
47
+ }
48
+ if ("id" in msg) {
49
+ try {
50
+ const response = await options.onRequest(msg);
51
+ if (response) writeMessage(response);
52
+ } catch (err) {
53
+ writeMessage(errorResponse(msg.id, -32603, err instanceof Error ? err.message : String(err)));
54
+ }
55
+ return;
56
+ }
57
+ try {
58
+ await options.onNotification?.(msg);
59
+ } catch (err) {
60
+ options.onError?.(err instanceof Error ? err : new Error(String(err)));
61
+ }
62
+ };
63
+ const onData = (chunk) => {
64
+ buffer = Buffer.concat([buffer, typeof chunk === "string" ? Buffer.from(chunk) : chunk]);
65
+ for (;;) {
66
+ let parsed;
67
+ try {
68
+ parsed = readNextMessage(buffer);
69
+ } catch (err) {
70
+ buffer = Buffer.alloc(0);
71
+ writeMessage(errorResponse(null, -32700, err instanceof Error ? err.message : String(err)));
72
+ break;
73
+ }
74
+ if (!parsed) break;
75
+ buffer = parsed.rest;
76
+ handleParsed(parsed.message);
77
+ }
78
+ };
79
+ const onError = (err) => {
80
+ options.onError?.(err);
81
+ };
82
+ return {
83
+ start() {
84
+ options.input.on("data", onData);
85
+ options.input.on("error", onError);
86
+ },
87
+ close() {
88
+ closed = true;
89
+ options.input.off("data", onData);
90
+ options.input.off("error", onError);
91
+ for (const request of pending.values()) request.reject(/* @__PURE__ */ new Error("JSON-RPC connection closed."));
92
+ pending.clear();
93
+ },
94
+ sendNotification(method, params) {
95
+ writeMessage({
96
+ jsonrpc: "2.0",
97
+ method,
98
+ ...params !== void 0 ? { params } : {}
99
+ });
100
+ },
101
+ sendRequest(method, params) {
102
+ if (closed) return Promise.reject(/* @__PURE__ */ new Error("JSON-RPC connection is closed."));
103
+ const id = nextId++;
104
+ writeMessage({
105
+ jsonrpc: "2.0",
106
+ id,
107
+ method,
108
+ ...params !== void 0 ? { params } : {}
109
+ });
110
+ return new Promise((resolve, reject) => {
111
+ pending.set(id, {
112
+ resolve,
113
+ reject
114
+ });
115
+ });
116
+ }
117
+ };
118
+ }
119
+ var JsonRpcRemoteError = class extends Error {
120
+ code;
121
+ data;
122
+ constructor(message, code, data) {
123
+ super(message);
124
+ this.code = code;
125
+ this.data = data;
126
+ this.name = "JsonRpcRemoteError";
127
+ }
128
+ };
129
+ function successResponse(id, result = {}) {
130
+ return {
131
+ jsonrpc: "2.0",
132
+ id,
133
+ result
134
+ };
135
+ }
136
+ function errorResponse(id, code, message, data) {
137
+ return {
138
+ jsonrpc: "2.0",
139
+ id,
140
+ error: {
141
+ code,
142
+ message,
143
+ ...data !== void 0 ? { data } : {}
144
+ }
145
+ };
146
+ }
147
+ function readNextMessage(input) {
148
+ if (input.length === 0) return null;
149
+ const headerEnd = input.indexOf("\r\n\r\n");
150
+ if (headerEnd >= 0) {
151
+ const header = input.subarray(0, headerEnd).toString("utf8");
152
+ const match = /^Content-Length:\s*(\d+)/im.exec(header);
153
+ if (!match) return readLineMessage(input);
154
+ const length = Number(match[1]);
155
+ const bodyStart = headerEnd + 4;
156
+ const bodyEnd = bodyStart + length;
157
+ if (input.length < bodyEnd) return null;
158
+ const body = input.subarray(bodyStart, bodyEnd).toString("utf8");
159
+ return {
160
+ message: JSON.parse(body),
161
+ rest: input.subarray(bodyEnd)
162
+ };
163
+ }
164
+ if (/^Content-Length:/i.test(input.subarray(0, Math.min(input.length, 32)).toString("utf8"))) return null;
165
+ return readLineMessage(input);
166
+ }
167
+ function readLineMessage(input) {
168
+ let rest = input;
169
+ for (;;) {
170
+ const lineEnd = rest.indexOf("\n");
171
+ if (lineEnd < 0) return null;
172
+ const line = rest.subarray(0, lineEnd).toString("utf8").trim();
173
+ rest = rest.subarray(lineEnd + 1);
174
+ if (line.length === 0) continue;
175
+ return {
176
+ message: JSON.parse(line),
177
+ rest
178
+ };
179
+ }
180
+ }
181
+ function isObject$1(value) {
182
+ return value !== null && typeof value === "object" && !Array.isArray(value);
183
+ }
184
+ //#endregion
185
+ //#region src/acp/mapping.ts
186
+ function acpMcpServersToZidane(servers) {
187
+ if (!servers) return [];
188
+ return servers.map((server) => {
189
+ if (server.type === "http") return {
190
+ name: server.name,
191
+ transport: "streamable-http",
192
+ url: server.url,
193
+ headers: headersToRecord(server.headers)
194
+ };
195
+ if (server.type === "sse") return {
196
+ name: server.name,
197
+ transport: "sse",
198
+ url: server.url,
199
+ headers: headersToRecord(server.headers)
200
+ };
201
+ const stdio = server;
202
+ return {
203
+ name: server.name,
204
+ transport: "stdio",
205
+ command: stdio.command,
206
+ args: stdio.args ?? [],
207
+ env: envToRecord(stdio.env)
208
+ };
209
+ });
210
+ }
211
+ function promptCapabilitiesForProvider(capabilities) {
212
+ return {
213
+ image: capabilities?.vision === true,
214
+ audio: capabilities?.audio === true,
215
+ embeddedContext: true
216
+ };
217
+ }
218
+ function mcpCapabilities() {
219
+ return {
220
+ http: true,
221
+ sse: true
222
+ };
223
+ }
224
+ function defaultModes(modes) {
225
+ return modes && modes.length > 0 ? [...modes] : [{
226
+ id: "build",
227
+ name: "Build",
228
+ description: "Full tool access for implementation work."
229
+ }, {
230
+ id: "plan",
231
+ name: "Plan",
232
+ description: "Planning-oriented mode; hosts may narrow tools separately."
233
+ }];
234
+ }
235
+ function makeModeState(modes, currentModeId) {
236
+ return {
237
+ currentModeId,
238
+ availableModes: [...modes]
239
+ };
240
+ }
241
+ function newSessionResponse(sessionId, modes, currentModeId, configOptions) {
242
+ return {
243
+ sessionId,
244
+ modes: makeModeState(modes, currentModeId),
245
+ ...configOptions && configOptions.length > 0 ? { configOptions } : {}
246
+ };
247
+ }
248
+ function acpPromptToPromptParts(prompt) {
249
+ const parts = [];
250
+ const warnings = [];
251
+ for (const block of prompt) switch (block.type) {
252
+ case "text":
253
+ parts.push({
254
+ type: "text",
255
+ text: block.text
256
+ });
257
+ break;
258
+ case "image":
259
+ if (block.data) parts.push({
260
+ type: "image",
261
+ mediaType: block.mimeType || "image/png",
262
+ data: block.data
263
+ });
264
+ else {
265
+ warnings.push(`Image resource linked instead of embedded: ${block.uri ?? "unknown URI"}`);
266
+ parts.push({
267
+ type: "text",
268
+ text: `[image resource: ${block.uri ?? "unavailable"}]`
269
+ });
270
+ }
271
+ break;
272
+ case "audio":
273
+ if (block.data) parts.push({
274
+ type: "audio",
275
+ mediaType: block.mimeType || "audio/mpeg",
276
+ data: block.data
277
+ });
278
+ else {
279
+ warnings.push("Audio block omitted because it did not include embedded data.");
280
+ parts.push({
281
+ type: "text",
282
+ text: "[audio resource omitted: no embedded data]"
283
+ });
284
+ }
285
+ break;
286
+ case "resource_link":
287
+ parts.push({
288
+ type: "text",
289
+ text: renderResourceLink(block)
290
+ });
291
+ break;
292
+ case "resource":
293
+ parts.push(resourceToPromptPart(block));
294
+ break;
295
+ default:
296
+ warnings.push("Unknown ACP content block converted to text.");
297
+ parts.push({
298
+ type: "text",
299
+ text: JSON.stringify(block)
300
+ });
301
+ break;
302
+ }
303
+ return {
304
+ prompt: parts,
305
+ warnings
306
+ };
307
+ }
308
+ function sessionBlocksToAcp(blocks) {
309
+ const out = [];
310
+ for (const block of blocks) if (block.type === "text" || block.type === "thinking") out.push({
311
+ type: "text",
312
+ text: block.text
313
+ });
314
+ else if (block.type === "image") out.push(imageBlockToAcp(block.mediaType, "data" in block ? block.data : void 0, "ref" in block ? block.ref : void 0, block.name));
315
+ else if (block.type === "audio") {
316
+ if (block.data) out.push({
317
+ type: "audio",
318
+ mimeType: block.mediaType,
319
+ data: block.data
320
+ });
321
+ } else if (block.type === "document") out.push(documentBlockToAcp(block.mediaType, "data" in block ? block.data : void 0, "ref" in block ? block.ref : void 0, block.encoding, block.name));
322
+ return out;
323
+ }
324
+ function toolResultToAcpContent(content) {
325
+ if (typeof content === "string") return [{
326
+ type: "content",
327
+ content: {
328
+ type: "text",
329
+ text: content
330
+ }
331
+ }];
332
+ return content.map((block) => {
333
+ if (block.type === "text") return {
334
+ type: "content",
335
+ content: {
336
+ type: "text",
337
+ text: block.text
338
+ }
339
+ };
340
+ if (block.type === "image") return {
341
+ type: "content",
342
+ content: imageBlockToAcp(block.mediaType, "data" in block ? block.data : void 0, "ref" in block ? block.ref : void 0, "name" in block ? block.name : void 0)
343
+ };
344
+ if (block.type === "audio" && block.data) return {
345
+ type: "content",
346
+ content: {
347
+ type: "audio",
348
+ mimeType: block.mediaType,
349
+ data: block.data
350
+ }
351
+ };
352
+ if (block.type === "document") return {
353
+ type: "content",
354
+ content: documentBlockToAcp(block.mediaType, "data" in block ? block.data : void 0, "ref" in block ? block.ref : void 0, block.encoding, "name" in block ? block.name : void 0)
355
+ };
356
+ return {
357
+ type: "content",
358
+ content: {
359
+ type: "text",
360
+ text: toolResultToText([block])
361
+ }
362
+ };
363
+ });
364
+ }
365
+ /**
366
+ * Build a spec-valid ACP image block. `ImageContent` requires `data` +
367
+ * `mimeType`; when we only have a reference (`ref`/uri) we fall back to a
368
+ * `resource_link` (which requires `name` + `uri`) so we never emit an image
369
+ * block missing its required `data`.
370
+ */
371
+ function imageBlockToAcp(mimeType, data, ref, name) {
372
+ if (data) return {
373
+ type: "image",
374
+ mimeType,
375
+ data,
376
+ ...ref ? { uri: ref } : {}
377
+ };
378
+ return {
379
+ type: "resource_link",
380
+ uri: ref ?? acpSyntheticUri("image", name),
381
+ name: name ?? "image",
382
+ mimeType
383
+ };
384
+ }
385
+ /**
386
+ * Build a spec-valid embedded `resource` (or a `resource_link` fallback for
387
+ * reference-only documents). `EmbeddedResource.resource` requires a `uri`
388
+ * plus either `text` (text payload) or `blob` (base64), so a synthetic URI is
389
+ * minted when the source block has none.
390
+ */
391
+ function documentBlockToAcp(mimeType, data, ref, encoding, name) {
392
+ const uri = ref ?? acpSyntheticUri("document", name);
393
+ if (typeof data !== "string") return {
394
+ type: "resource_link",
395
+ uri,
396
+ name: name ?? "document",
397
+ mimeType
398
+ };
399
+ return {
400
+ type: "resource",
401
+ resource: encoding === "text" ? {
402
+ uri,
403
+ text: data,
404
+ mimeType
405
+ } : {
406
+ uri,
407
+ blob: data,
408
+ mimeType
409
+ }
410
+ };
411
+ }
412
+ function acpSyntheticUri(kind, name) {
413
+ return `acp:///${kind}/${(name ?? kind).replace(/[^\w.-]+/g, "_")}`;
414
+ }
415
+ function toolKindForName(name) {
416
+ if (name === "read_file" || name === "list_files") return "read";
417
+ if (name === "write_file" || name === "edit" || name === "multi_edit") return "edit";
418
+ if (name === "grep" || name === "glob" || name === "tool_search") return "search";
419
+ if (name === "shell" || name === "wait_task" || name === "shell_kill") return "execute";
420
+ if (name === "web_search" || name === "fetch_url") return "fetch";
421
+ if (name === "present_plan" || name === "ask_user") return "think";
422
+ return "other";
423
+ }
424
+ function stopReasonFromRun(input) {
425
+ if (input.aborted) return "cancelled";
426
+ if (input.maxTurnsReached) return "max_turn_requests";
427
+ switch (lastFinishReason$1(input.turnUsage)) {
428
+ case "length": return "max_tokens";
429
+ case "content-filter":
430
+ case "error": return "refusal";
431
+ default: return "end_turn";
432
+ }
433
+ }
434
+ function usageCost(cost) {
435
+ if (typeof cost !== "number" || !Number.isFinite(cost)) return null;
436
+ return {
437
+ amount: cost,
438
+ currency: "USD"
439
+ };
440
+ }
441
+ function resolveAcpPath(cwd, path) {
442
+ return path.startsWith("/") ? path : resolve(cwd, path);
443
+ }
444
+ function lastFinishReason$1(turnUsage) {
445
+ for (let i = (turnUsage?.length ?? 0) - 1; i >= 0; i--) {
446
+ const reason = turnUsage?.[i]?.finishReason;
447
+ if (reason) return reason;
448
+ }
449
+ }
450
+ function headersToRecord(headers) {
451
+ const out = {};
452
+ for (const header of headers ?? []) out[header.name] = header.value;
453
+ return out;
454
+ }
455
+ function envToRecord(env) {
456
+ const out = {};
457
+ for (const item of env ?? []) out[item.name] = item.value;
458
+ return out;
459
+ }
460
+ function renderResourceLink(block) {
461
+ const label = block.title ?? block.name ?? block.uri;
462
+ return block.mimeType ? `[resource: ${label}](${block.uri}) (${block.mimeType})` : `[resource: ${label}](${block.uri})`;
463
+ }
464
+ function resourceToPromptPart(block) {
465
+ const resource = block.resource;
466
+ const mediaType = resource.mimeType ?? "text/plain";
467
+ const name = nameFromUri(resource.uri);
468
+ if ("text" in resource && typeof resource.text === "string") return {
469
+ type: "document",
470
+ mediaType,
471
+ data: resource.text,
472
+ encoding: "text",
473
+ ...name ? { name } : {}
474
+ };
475
+ if ("blob" in resource && typeof resource.blob === "string") return {
476
+ type: "document",
477
+ mediaType,
478
+ data: resource.blob,
479
+ encoding: "base64",
480
+ ...name ? { name } : {}
481
+ };
482
+ return {
483
+ type: "text",
484
+ text: `[resource omitted: ${resource.uri}]`
485
+ };
486
+ }
487
+ function nameFromUri(uri) {
488
+ if (!uri) return void 0;
489
+ const segment = uri.replace(/[/\\]+$/, "").split(/[/\\]/).pop();
490
+ return segment && segment.length > 0 ? segment : void 0;
491
+ }
492
+ //#endregion
493
+ //#region src/acp/client-tools.ts
494
+ function wrapToolsForAcpClient(tools, options) {
495
+ if (!tools) return void 0;
496
+ const wrapped = { ...tools };
497
+ const readFileEntry = findToolEntry(tools, "read_file");
498
+ const writeFileEntry = findToolEntry(tools, "write_file");
499
+ const shellEntry = findToolEntry(tools, "shell");
500
+ if (options.useClientFileSystem !== false && options.capabilities.fs?.readTextFile && readFileEntry) wrapped[readFileEntry.key] = wrapReadFile(readFileEntry.tool, options);
501
+ if (options.useClientFileSystem !== false && options.capabilities.fs?.writeTextFile && writeFileEntry) wrapped[writeFileEntry.key] = wrapWriteFile(writeFileEntry.tool, options);
502
+ if (options.useClientTerminal !== false && options.capabilities.terminal && shellEntry) wrapped[shellEntry.key] = wrapShell(shellEntry.tool, options);
503
+ return wrapped;
504
+ }
505
+ function findToolEntry(tools, canonicalName) {
506
+ for (const [key, tool] of Object.entries(tools)) if (key === canonicalName || tool.spec.name === canonicalName) return {
507
+ key,
508
+ tool
509
+ };
510
+ return null;
511
+ }
512
+ function wrapReadFile(base, options) {
513
+ return {
514
+ ...base,
515
+ async execute(input, ctx) {
516
+ const path = typeof input.path === "string" ? input.path : "";
517
+ if (!path) return "Read error: missing path.";
518
+ const absPath = resolveAcpPath(ctx.handle.cwd, path);
519
+ const line = lineOrDefault(input.offset);
520
+ const limit = positiveNumberOrNull(input.limit);
521
+ const response = await options.client.sendRequest("fs/read_text_file", {
522
+ sessionId: options.sessionId,
523
+ path: absPath,
524
+ line,
525
+ ...limit !== null ? { limit } : {}
526
+ });
527
+ const content = typeof response.content === "string" ? response.content : "";
528
+ seedReadState(ctx, absPath, content, line ?? 1, limit ?? Number.POSITIVE_INFINITY);
529
+ if (input.lineNumbers === false) return content;
530
+ return withLineNumbers(content, line ?? 1);
531
+ }
532
+ };
533
+ }
534
+ function wrapWriteFile(base, options) {
535
+ return {
536
+ ...base,
537
+ async execute(input, ctx) {
538
+ const path = typeof input.path === "string" ? input.path : "";
539
+ const content = typeof input.content === "string" ? input.content : "";
540
+ if (!path) return "Write error: missing path.";
541
+ const absPath = resolveAcpPath(ctx.handle.cwd, path);
542
+ await options.client.sendRequest("fs/write_text_file", {
543
+ sessionId: options.sessionId,
544
+ path: absPath,
545
+ content
546
+ });
547
+ seedReadState(ctx, absPath, content, 0, Number.POSITIVE_INFINITY);
548
+ ctx.reportOutcome?.("updated");
549
+ return `Wrote ${absPath} (${Buffer.byteLength(content)} bytes).`;
550
+ }
551
+ };
552
+ }
553
+ function wrapShell(base, options) {
554
+ return {
555
+ ...base,
556
+ spec: withoutShellBackgroundInput(base.spec),
557
+ async execute(input, ctx) {
558
+ const command = typeof input.command === "string" ? input.command : "";
559
+ if (!command) return "shell error: missing command.";
560
+ if (input.run_in_background === true) return "shell error: background mode is not supported through ACP terminal callbacks. Run the command in the foreground.";
561
+ const request = {
562
+ sessionId: options.sessionId,
563
+ command,
564
+ cwd: ctx.handle.cwd,
565
+ outputByteLimit: typeof input.maxOutputBytes === "number" ? input.maxOutputBytes : null
566
+ };
567
+ const created = await options.client.sendRequest("terminal/create", request);
568
+ const terminalId = typeof created.terminalId === "string" ? created.terminalId : "";
569
+ if (!terminalId) return "shell error: ACP client did not return a terminal id.";
570
+ try {
571
+ const exit = await options.client.sendRequest("terminal/wait_for_exit", {
572
+ sessionId: options.sessionId,
573
+ terminalId
574
+ });
575
+ return formatTerminalOutput(await options.client.sendRequest("terminal/output", {
576
+ sessionId: options.sessionId,
577
+ terminalId
578
+ }), exit);
579
+ } finally {
580
+ await options.client.sendRequest("terminal/release", {
581
+ sessionId: options.sessionId,
582
+ terminalId
583
+ }).catch(() => void 0);
584
+ }
585
+ }
586
+ };
587
+ }
588
+ function formatTerminalOutput(output, exit) {
589
+ const body = output.output || "(no output)";
590
+ const code = exit.exitCode ?? output.exitStatus?.exitCode;
591
+ const signal = exit.signal ?? output.exitStatus?.signal;
592
+ const suffix = signal ? `\n(signal ${signal})` : typeof code === "number" ? `\n(exit ${code})` : "";
593
+ return `${body}${output.truncated ? "\n(output truncated by ACP client)" : ""}${suffix}`;
594
+ }
595
+ function withoutShellBackgroundInput(spec) {
596
+ const properties = isRecord(spec.inputSchema.properties) ? spec.inputSchema.properties : void 0;
597
+ if (!properties || !Object.hasOwn(properties, "run_in_background")) return spec;
598
+ const { run_in_background: _runInBackground, ...nextProperties } = properties;
599
+ const required = Array.isArray(spec.inputSchema.required) ? spec.inputSchema.required.filter((name) => name !== "run_in_background") : spec.inputSchema.required;
600
+ return {
601
+ ...spec,
602
+ description: spec.description.split("\n").filter((line) => !line.includes("run_in_background") && !line.includes("<task-notification>") && !line.includes("background task")).join("\n"),
603
+ inputSchema: {
604
+ ...spec.inputSchema,
605
+ properties: nextProperties,
606
+ ...required ? { required } : {}
607
+ }
608
+ };
609
+ }
610
+ function withLineNumbers(content, start) {
611
+ return content.split("\n").map((line, index) => `${start + index}\t${line}`).join("\n");
612
+ }
613
+ function lineOrDefault(value) {
614
+ return typeof value === "number" && Number.isFinite(value) && value >= 1 ? Math.trunc(value) : 1;
615
+ }
616
+ function positiveNumberOrNull(value) {
617
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : null;
618
+ }
619
+ function isRecord(value) {
620
+ return value !== null && typeof value === "object" && !Array.isArray(value);
621
+ }
622
+ function seedReadState(ctx, path, content, offset, limit) {
623
+ const readState = resolveReadStateMap(ctx);
624
+ if (!readState) return;
625
+ readState.set(readStateKey(ctx.handle.cwd, path), {
626
+ contentHash: hashContent(content),
627
+ offset,
628
+ limit,
629
+ maxBytes: Number.POSITIVE_INFINITY,
630
+ mtimeMs: Date.now()
631
+ });
632
+ }
633
+ //#endregion
634
+ //#region src/acp/server.ts
635
+ const ACP_AGENT_VERSION = "1";
636
+ const DEFAULT_PERMISSION_OPTIONS = [
637
+ {
638
+ optionId: "allow_once",
639
+ name: "Allow once",
640
+ kind: "allow_once"
641
+ },
642
+ {
643
+ optionId: "allow_always",
644
+ name: "Always allow",
645
+ kind: "allow_always"
646
+ },
647
+ {
648
+ optionId: "reject_once",
649
+ name: "Reject once",
650
+ kind: "reject_once"
651
+ },
652
+ {
653
+ optionId: "reject_always",
654
+ name: "Always reject",
655
+ kind: "reject_always"
656
+ }
657
+ ];
658
+ function createAcpServer(options) {
659
+ return new AcpServerImpl(options);
660
+ }
661
+ var AcpServerImpl = class {
662
+ options;
663
+ peer = null;
664
+ clientCapabilities = {};
665
+ sessions = /* @__PURE__ */ new Map();
666
+ modes;
667
+ defaultModeId;
668
+ defaultConfigOptions;
669
+ constructor(options) {
670
+ this.options = options;
671
+ this.modes = defaultModes(options.modes);
672
+ this.defaultModeId = options.defaultModeId ?? this.modes[0]?.id ?? "build";
673
+ this.defaultConfigOptions = options.configOptions ?? [];
674
+ }
675
+ setPeer(peer) {
676
+ this.peer = peer;
677
+ }
678
+ async handleMessage(message) {
679
+ if (!isObject(message) || typeof message.method !== "string") return errorResponse(normalizeId("id" in message ? message.id : null), -32600, "Invalid JSON-RPC request.");
680
+ if (!("id" in message)) {
681
+ await this.handleNotification(message.method, message.params);
682
+ return null;
683
+ }
684
+ const request = message;
685
+ try {
686
+ const result = await this.handleRequest(request.method, request.params);
687
+ return successResponse(request.id, result);
688
+ } catch (err) {
689
+ const rpcError = toRpcError(err);
690
+ return errorResponse(request.id, rpcError.code, rpcError.message, rpcError.data);
691
+ }
692
+ }
693
+ async handleRequest(method, params) {
694
+ switch (method) {
695
+ case "initialize": return this.initialize(asObject(params));
696
+ case "authenticate": return this.authenticate(asObject(params));
697
+ case "logout": return this.logout();
698
+ case "session/new": return this.newSession(asObject(params));
699
+ case "session/load": return this.loadExistingSession(asObject(params));
700
+ case "session/resume": return this.resumeSession(asObject(params));
701
+ case "session/list": return this.listSessions(asObject(params));
702
+ case "session/delete": return this.deleteSession(asObject(params));
703
+ case "session/close": return this.closeSession(asObject(params));
704
+ case "session/prompt": return this.prompt(asObject(params));
705
+ case "session/set_mode": return this.setMode(asObject(params));
706
+ case "session/set_config_option": return this.setConfigOption(asObject(params));
707
+ default: throw new AcpProtocolError(-32601, `Unknown ACP method: ${method}`);
708
+ }
709
+ }
710
+ async notify(method, params) {
711
+ await this.peer?.sendNotification(method, params);
712
+ }
713
+ async close() {
714
+ const sessions = [...this.sessions.values()];
715
+ this.sessions.clear();
716
+ await Promise.allSettled(sessions.map(async (runtime) => {
717
+ runtime.abortController?.abort(/* @__PURE__ */ new Error("ACP server closing."));
718
+ await runtime.agent.destroy();
719
+ }));
720
+ }
721
+ async handleNotification(method, params) {
722
+ switch (method) {
723
+ case "session/cancel":
724
+ this.cancel(asObject(params));
725
+ break;
726
+ default: break;
727
+ }
728
+ }
729
+ initialize(params) {
730
+ this.clientCapabilities = params.clientCapabilities ?? {};
731
+ const provider = this.resolveProvider();
732
+ return {
733
+ protocolVersion: params.protocolVersion === 1 ? params.protocolVersion : 1,
734
+ agentCapabilities: {
735
+ loadSession: true,
736
+ promptCapabilities: promptCapabilitiesForProvider(provider.meta.capabilities),
737
+ mcpCapabilities: mcpCapabilities(),
738
+ sessionCapabilities: {
739
+ list: {},
740
+ delete: {},
741
+ resume: {},
742
+ close: {},
743
+ additionalDirectories: {}
744
+ },
745
+ auth: { ...this.options.logout ? { logout: {} } : {} }
746
+ },
747
+ agentInfo: this.options.agentInfo ?? {
748
+ name: "zidane",
749
+ title: "Zidane ACP",
750
+ version: ACP_AGENT_VERSION
751
+ },
752
+ authMethods: this.options.authMethods ?? []
753
+ };
754
+ }
755
+ async authenticate(params) {
756
+ if (!this.options.authenticate) return {};
757
+ return await this.options.authenticate(params);
758
+ }
759
+ async logout() {
760
+ if (!this.options.logout) return {};
761
+ return await this.options.logout();
762
+ }
763
+ async newSession(params) {
764
+ const runtime = await this.createRuntime(params);
765
+ this.deferAvailableCommands(runtime.sessionId);
766
+ return newSessionResponse(runtime.sessionId, this.modes, runtime.modeId, runtime.configOptions);
767
+ }
768
+ async loadExistingSession(params) {
769
+ const runtime = await this.createRuntime(params, params.sessionId, true);
770
+ await this.replayHistory(runtime);
771
+ this.deferAvailableCommands(runtime.sessionId);
772
+ return this.sessionStateResponse(runtime);
773
+ }
774
+ async resumeSession(params) {
775
+ const runtime = await this.createRuntime({
776
+ cwd: params.cwd,
777
+ additionalDirectories: params.additionalDirectories,
778
+ mcpServers: params.mcpServers ?? []
779
+ }, params.sessionId, true);
780
+ this.deferAvailableCommands(runtime.sessionId);
781
+ return this.sessionStateResponse(runtime);
782
+ }
783
+ sessionStateResponse(runtime) {
784
+ return {
785
+ modes: makeModeState(this.modes, runtime.modeId),
786
+ ...runtime.configOptions.length > 0 ? { configOptions: runtime.configOptions } : {}
787
+ };
788
+ }
789
+ deferAvailableCommands(sessionId) {
790
+ if (!this.options.commands || this.options.commands.length === 0) return;
791
+ setTimeout(() => {
792
+ this.sessionUpdate(sessionId, {
793
+ sessionUpdate: "available_commands_update",
794
+ availableCommands: this.options.commands
795
+ });
796
+ }, 0);
797
+ }
798
+ async replayHistory(runtime) {
799
+ for (const turn of runtime.session.turns) {
800
+ const blocks = sessionBlocksToAcp(turn.content);
801
+ if (blocks.length === 0) continue;
802
+ const sessionUpdate = turn.role === "assistant" ? "agent_message_chunk" : "user_message_chunk";
803
+ for (const content of blocks) await this.sessionUpdate(runtime.sessionId, {
804
+ sessionUpdate,
805
+ content
806
+ });
807
+ }
808
+ }
809
+ async listSessions(params) {
810
+ const store = this.options.store;
811
+ if (!store) return {
812
+ sessions: [...this.sessions.values()].filter((runtime) => !params.cwd || runtime.cwd === params.cwd).map((runtime) => sessionInfo(runtime)),
813
+ nextCursor: null
814
+ };
815
+ const ids = await store.list({
816
+ limit: 100,
817
+ ...params.cwd ? { projectRoot: params.cwd } : {}
818
+ });
819
+ const sessions = [];
820
+ for (const id of ids) {
821
+ const loaded = await store.load(id);
822
+ if (!loaded) continue;
823
+ const cwd = loaded.projectRoot ?? params.cwd ?? this.sessions.get(loaded.id)?.cwd;
824
+ if (!cwd) continue;
825
+ sessions.push({
826
+ sessionId: loaded.id,
827
+ cwd,
828
+ title: typeof loaded.metadata.title === "string" ? loaded.metadata.title : null,
829
+ updatedAt: new Date(loaded.updatedAt).toISOString()
830
+ });
831
+ }
832
+ return {
833
+ sessions,
834
+ nextCursor: null
835
+ };
836
+ }
837
+ async deleteSession(params) {
838
+ const runtime = this.sessions.get(params.sessionId);
839
+ if (runtime) {
840
+ runtime.abortController?.abort(/* @__PURE__ */ new Error("ACP session deleted."));
841
+ await runtime.agent.destroy();
842
+ this.sessions.delete(params.sessionId);
843
+ }
844
+ await this.options.store?.delete(params.sessionId);
845
+ return {};
846
+ }
847
+ async closeSession(params) {
848
+ const runtime = this.requireSession(params.sessionId);
849
+ runtime.abortController?.abort(/* @__PURE__ */ new Error("ACP session closed."));
850
+ await runtime.agent.destroy();
851
+ this.sessions.delete(params.sessionId);
852
+ return {};
853
+ }
854
+ async prompt(params) {
855
+ const runtime = this.requireSession(params.sessionId);
856
+ if (runtime.inFlight) throw new AcpProtocolError(-32600, `Session ${params.sessionId} already has an in-flight prompt.`);
857
+ const mapped = acpPromptToPromptParts(params.prompt);
858
+ const abortController = new AbortController();
859
+ runtime.abortController = abortController;
860
+ const run = async () => {
861
+ let stats;
862
+ let aborted = false;
863
+ try {
864
+ for (const warning of mapped.warnings) await this.sessionUpdate(runtime.sessionId, {
865
+ sessionUpdate: "agent_thought_chunk",
866
+ content: {
867
+ type: "text",
868
+ text: warning
869
+ }
870
+ });
871
+ stats = await runtime.agent.run({
872
+ prompt: mapped.prompt,
873
+ ...this.options.model ? { model: this.options.model } : {},
874
+ ...this.options.system ? { system: this.options.system } : {},
875
+ signal: abortController.signal
876
+ });
877
+ } catch (err) {
878
+ aborted = abortController.signal.aborted;
879
+ if (!aborted) throw err;
880
+ } finally {
881
+ runtime.abortController = void 0;
882
+ runtime.inFlight = void 0;
883
+ }
884
+ return { stopReason: stopReasonFromRun({
885
+ aborted: aborted || abortController.signal.aborted,
886
+ turnUsage: stats?.turnUsage,
887
+ maxTurnsReached: stats ? reachedMaxTurns(stats, this.options.behavior) : false
888
+ }) };
889
+ };
890
+ const inFlight = run();
891
+ runtime.inFlight = inFlight;
892
+ return await inFlight;
893
+ }
894
+ cancel(params) {
895
+ const runtime = this.sessions.get(params.sessionId);
896
+ runtime?.abortController?.abort(/* @__PURE__ */ new Error("Cancelled by ACP client."));
897
+ runtime?.agent.abort();
898
+ }
899
+ async setMode(params) {
900
+ const runtime = this.requireSession(params.sessionId);
901
+ if (!this.modes.some((mode) => mode.id === params.modeId)) throw new AcpProtocolError(-32602, `Unknown mode: ${params.modeId}`);
902
+ runtime.modeId = params.modeId;
903
+ await this.sessionUpdate(params.sessionId, {
904
+ sessionUpdate: "current_mode_update",
905
+ currentModeId: params.modeId
906
+ });
907
+ return {};
908
+ }
909
+ async setConfigOption(params) {
910
+ const runtime = this.requireSession(params.sessionId);
911
+ const configOptions = this.applyConfigSelection(runtime, params.configId, params.value);
912
+ runtime.config.set(params.configId, params.value);
913
+ await this.sessionUpdate(params.sessionId, {
914
+ sessionUpdate: "config_option_update",
915
+ configOptions
916
+ });
917
+ return { configOptions };
918
+ }
919
+ /** Reflect a `select` choice back into the advertised option set's `currentValue`. */
920
+ applyConfigSelection(runtime, configId, value) {
921
+ const option = runtime.configOptions.find((candidate) => candidate.id === configId);
922
+ if (!option) throw new AcpProtocolError(-32602, `Unknown config option: ${configId}`);
923
+ if (!configOptionHasValue(option, value)) throw new AcpProtocolError(-32602, `Invalid value for config option ${configId}: ${value}`);
924
+ runtime.configOptions = runtime.configOptions.map((candidate) => candidate.id === configId ? {
925
+ ...candidate,
926
+ currentValue: value
927
+ } : candidate);
928
+ return runtime.configOptions;
929
+ }
930
+ async createRuntime(params, requestedSessionId, mustExist = false) {
931
+ if (requestedSessionId) {
932
+ const existing = this.sessions.get(requestedSessionId);
933
+ if (existing) {
934
+ if (existing.cwd !== params.cwd) throw new AcpProtocolError(-32602, `Session ${requestedSessionId} belongs to cwd ${existing.cwd}, not ${params.cwd}.`);
935
+ const nextAdditionalDirectories = params.additionalDirectories ?? existing.additionalDirectories;
936
+ const nextMcpServers = params.mcpServers === void 0 ? existing.mcpServers : acpMcpServersToZidane(params.mcpServers);
937
+ if (!sameStringArray(existing.additionalDirectories, nextAdditionalDirectories)) throw new AcpProtocolError(-32602, `Session ${requestedSessionId} is already active with different additionalDirectories; close it before resuming with changed roots.`);
938
+ if (!sameJson(existing.mcpServers, nextMcpServers)) throw new AcpProtocolError(-32602, `Session ${requestedSessionId} is already active with different MCP servers; close it before resuming with changed MCP configuration.`);
939
+ return existing;
940
+ }
941
+ }
942
+ const mcpServers = acpMcpServersToZidane(params.mcpServers);
943
+ const session = await this.resolveSession(requestedSessionId, params.cwd, mustExist);
944
+ const execution = this.resolveExecution(params);
945
+ const provider = this.resolveProvider();
946
+ const sessionId = session.id;
947
+ const base = this.options.preset ?? basic_default;
948
+ const agentOptions = this.options.agentOptions ?? {};
949
+ const wrappedTools = wrapToolsForAcpClient(mergeTools(base.tools, agentOptions.tools, this.options.tools), {
950
+ client: this.requirePeer(),
951
+ sessionId,
952
+ capabilities: this.clientCapabilities,
953
+ useClientFileSystem: this.options.useClientFileSystem,
954
+ useClientTerminal: this.options.useClientTerminal
955
+ });
956
+ const behavior = {
957
+ ...base.behavior,
958
+ ...agentOptions.behavior,
959
+ ...this.options.behavior
960
+ };
961
+ const agent = createAgent({
962
+ ...base,
963
+ ...agentOptions,
964
+ provider,
965
+ execution,
966
+ session,
967
+ tools: wrappedTools,
968
+ behavior,
969
+ mcpServers: mergeMcpServers(base.mcpServers, agentOptions.mcpServers, this.options.agentOptions?.mcpServers, mcpServers),
970
+ ...this.options.system ? { system: this.options.system } : {}
971
+ });
972
+ const runtime = {
973
+ sessionId,
974
+ cwd: params.cwd,
975
+ additionalDirectories: params.additionalDirectories ?? [],
976
+ mcpServers,
977
+ session,
978
+ execution,
979
+ agent,
980
+ modeId: this.defaultModeId,
981
+ configOptions: cloneConfigOptions(this.defaultConfigOptions),
982
+ config: /* @__PURE__ */ new Map()
983
+ };
984
+ this.installHookAdapter(runtime);
985
+ this.sessions.set(sessionId, runtime);
986
+ session.setMeta("acp.cwd", params.cwd);
987
+ session.setMeta("acp.additionalDirectories", params.additionalDirectories ?? []);
988
+ if (session.store) await session.save().catch(() => void 0);
989
+ return runtime;
990
+ }
991
+ async resolveSession(sessionId, cwd, mustExist) {
992
+ const store = this.options.store;
993
+ if (sessionId && this.sessions.has(sessionId)) return this.sessions.get(sessionId).session;
994
+ if (sessionId && store) {
995
+ const existing = await loadSession(store, sessionId);
996
+ if (existing) return existing;
997
+ if (mustExist) throw new AcpProtocolError(-32002, `Unknown session: ${sessionId}`);
998
+ const created = await createSession({
999
+ id: sessionId,
1000
+ store,
1001
+ projectRoot: cwd,
1002
+ metadata: { title: "ACP session" }
1003
+ });
1004
+ await created.save();
1005
+ return created;
1006
+ }
1007
+ if (sessionId && mustExist) throw new AcpProtocolError(-32002, `Unknown session: ${sessionId}`);
1008
+ const created = await createSession({
1009
+ ...sessionId ? { id: sessionId } : {},
1010
+ ...store ? { store } : {},
1011
+ projectRoot: cwd,
1012
+ metadata: { title: "ACP session" }
1013
+ });
1014
+ if (store) await created.save();
1015
+ return created;
1016
+ }
1017
+ resolveExecution(params) {
1018
+ if (typeof this.options.execution === "function") return this.options.execution(params);
1019
+ return this.options.execution ?? createProcessContext({ cwd: params.cwd });
1020
+ }
1021
+ resolveProvider() {
1022
+ return typeof this.options.provider === "function" ? this.options.provider() : this.options.provider;
1023
+ }
1024
+ installHookAdapter(runtime) {
1025
+ const seenTools = /* @__PURE__ */ new Set();
1026
+ runtime.agent.hooks.hook("stream:text", ({ delta, turnId }) => {
1027
+ this.sessionUpdate(runtime.sessionId, {
1028
+ sessionUpdate: "agent_message_chunk",
1029
+ messageId: turnId,
1030
+ content: {
1031
+ type: "text",
1032
+ text: delta
1033
+ }
1034
+ });
1035
+ });
1036
+ runtime.agent.hooks.hook("stream:thinking", ({ delta, turnId }) => {
1037
+ this.sessionUpdate(runtime.sessionId, {
1038
+ sessionUpdate: "agent_thought_chunk",
1039
+ messageId: turnId,
1040
+ content: {
1041
+ type: "text",
1042
+ text: delta
1043
+ }
1044
+ });
1045
+ });
1046
+ runtime.agent.hooks.hook("tool:gate", async (ctx) => {
1047
+ if (!this.shouldRequestPermission(ctx.name, ctx.input)) return;
1048
+ const key = permissionKey(ctx.name, ctx.input);
1049
+ const cached = runtime.config.get(key);
1050
+ if (cached === "allow") return;
1051
+ if (cached === "reject") {
1052
+ ctx.block = true;
1053
+ ctx.reason = "Rejected by prior ACP permission decision.";
1054
+ return;
1055
+ }
1056
+ const outcome = await this.requestPermission(runtime, {
1057
+ toolCallId: ctx.callId,
1058
+ title: ctx.name,
1059
+ kind: toolKindForName(ctx.name),
1060
+ status: "pending",
1061
+ rawInput: ctx.input
1062
+ });
1063
+ if (outcome.outcome === "cancelled") {
1064
+ ctx.block = true;
1065
+ ctx.reason = "Cancelled by ACP client.";
1066
+ return;
1067
+ }
1068
+ if (outcome.optionId === "allow_always") runtime.config.set(key, "allow");
1069
+ if (outcome.optionId === "reject_always") runtime.config.set(key, "reject");
1070
+ if (outcome.optionId.startsWith("reject")) {
1071
+ ctx.block = true;
1072
+ ctx.reason = "Rejected by ACP client.";
1073
+ }
1074
+ });
1075
+ runtime.agent.hooks.hook("tool:dispatched", (ctx) => {
1076
+ seenTools.add(ctx.callId);
1077
+ const status = ctx.outcome === "gate-block" || ctx.outcome === "invalid-input" || ctx.outcome === "unknown" ? "failed" : "pending";
1078
+ this.sessionUpdate(runtime.sessionId, {
1079
+ sessionUpdate: "tool_call",
1080
+ toolCallId: ctx.callId,
1081
+ title: ctx.name,
1082
+ kind: toolKindForName(ctx.name),
1083
+ status,
1084
+ rawInput: ctx.input,
1085
+ ...status === "failed" ? { rawOutput: ctx.reason ?? ctx.outcome } : {}
1086
+ });
1087
+ });
1088
+ runtime.agent.hooks.hook("tool:before", (ctx) => {
1089
+ if (!seenTools.has(ctx.callId)) {
1090
+ this.sessionUpdate(runtime.sessionId, {
1091
+ sessionUpdate: "tool_call",
1092
+ toolCallId: ctx.callId,
1093
+ title: ctx.name,
1094
+ kind: toolKindForName(ctx.name),
1095
+ status: "in_progress",
1096
+ rawInput: ctx.input
1097
+ });
1098
+ return;
1099
+ }
1100
+ this.sessionUpdate(runtime.sessionId, {
1101
+ sessionUpdate: "tool_call_update",
1102
+ toolCallId: ctx.callId,
1103
+ status: "in_progress"
1104
+ });
1105
+ });
1106
+ runtime.agent.hooks.hook("tool:after", (ctx) => {
1107
+ this.sessionUpdate(runtime.sessionId, {
1108
+ sessionUpdate: "tool_call_update",
1109
+ toolCallId: ctx.callId,
1110
+ status: "completed",
1111
+ content: toolResultToAcpContent(ctx.result),
1112
+ rawOutput: ctx.result
1113
+ });
1114
+ });
1115
+ runtime.agent.hooks.hook("tool:error", (ctx) => {
1116
+ this.sessionUpdate(runtime.sessionId, {
1117
+ sessionUpdate: "tool_call_update",
1118
+ toolCallId: ctx.callId,
1119
+ status: "failed",
1120
+ rawOutput: errorMessage(ctx.error)
1121
+ });
1122
+ });
1123
+ runtime.agent.hooks.hook("tool:cancelled", (ctx) => {
1124
+ this.sessionUpdate(runtime.sessionId, {
1125
+ sessionUpdate: "tool_call_update",
1126
+ toolCallId: ctx.callId,
1127
+ status: "failed",
1128
+ rawOutput: ctx.reason ?? "cancelled"
1129
+ });
1130
+ });
1131
+ runtime.agent.hooks.hook("turn:after", ({ usage, cumulativeUsage }) => {
1132
+ const size = this.resolveContextWindow();
1133
+ if (size === void 0) return;
1134
+ const used = effectiveInputFromTurn(usage);
1135
+ if (used <= 0) return;
1136
+ const cost = usageCost(cumulativeUsage.cost);
1137
+ this.sessionUpdate(runtime.sessionId, {
1138
+ sessionUpdate: "usage_update",
1139
+ used,
1140
+ size,
1141
+ ...cost ? { cost } : {}
1142
+ });
1143
+ });
1144
+ }
1145
+ resolveContextWindow() {
1146
+ if (typeof this.options.contextWindow === "number" && this.options.contextWindow > 0) return this.options.contextWindow;
1147
+ const fromBehavior = this.options.behavior?.autoCompact;
1148
+ if (fromBehavior && typeof fromBehavior === "object" && typeof fromBehavior.contextWindow === "number" && fromBehavior.contextWindow > 0) return fromBehavior.contextWindow;
1149
+ const meta = this.resolveProvider().meta;
1150
+ if (typeof meta.contextWindow === "number" && meta.contextWindow > 0) return meta.contextWindow;
1151
+ }
1152
+ shouldRequestPermission(name, input) {
1153
+ const policy = this.options.permission;
1154
+ if (policy?.enabled !== true || !this.peer) return false;
1155
+ if (policy.toolMatcher) return policy.toolMatcher(name, input);
1156
+ return name === "shell" || name === "write_file" || name === "edit" || name === "multi_edit";
1157
+ }
1158
+ async requestPermission(runtime, toolCall) {
1159
+ const request = this.requirePeer().sendRequest("session/request_permission", {
1160
+ sessionId: runtime.sessionId,
1161
+ toolCall,
1162
+ options: this.options.permission?.options ?? DEFAULT_PERMISSION_OPTIONS
1163
+ });
1164
+ const aborted = new Promise((resolve) => {
1165
+ const signal = runtime.abortController?.signal;
1166
+ if (!signal) return;
1167
+ if (signal.aborted) {
1168
+ resolve({ outcome: { outcome: "cancelled" } });
1169
+ return;
1170
+ }
1171
+ signal.addEventListener("abort", () => resolve({ outcome: { outcome: "cancelled" } }), { once: true });
1172
+ });
1173
+ return (await Promise.race([request, aborted])).outcome ?? { outcome: "cancelled" };
1174
+ }
1175
+ async sessionUpdate(sessionId, update) {
1176
+ await this.notify("session/update", {
1177
+ sessionId,
1178
+ update
1179
+ });
1180
+ }
1181
+ requireSession(sessionId) {
1182
+ const runtime = this.sessions.get(sessionId);
1183
+ if (!runtime) throw new AcpProtocolError(-32002, `Unknown session: ${sessionId}`);
1184
+ return runtime;
1185
+ }
1186
+ requirePeer() {
1187
+ if (!this.peer) return {
1188
+ sendNotification: () => void 0,
1189
+ sendRequest: () => Promise.reject(new AcpProtocolError(-32601, "No ACP client peer is attached."))
1190
+ };
1191
+ return this.peer;
1192
+ }
1193
+ };
1194
+ var AcpProtocolError = class extends Error {
1195
+ code;
1196
+ data;
1197
+ constructor(code, message, data) {
1198
+ super(message);
1199
+ this.code = code;
1200
+ this.data = data;
1201
+ this.name = "AcpProtocolError";
1202
+ }
1203
+ };
1204
+ function mergeTools(...sources) {
1205
+ const out = {};
1206
+ for (const source of sources) if (source) Object.assign(out, source);
1207
+ return Object.keys(out).length > 0 ? out : void 0;
1208
+ }
1209
+ function mergeMcpServers(...sources) {
1210
+ const byName = /* @__PURE__ */ new Map();
1211
+ for (const source of sources) for (const server of source ?? []) byName.set(server.name, server);
1212
+ return [...byName.values()];
1213
+ }
1214
+ function cloneConfigOptions(options) {
1215
+ return options.map((option) => ({
1216
+ ...option,
1217
+ options: option.options.map((item) => "group" in item ? {
1218
+ ...item,
1219
+ options: item.options.map((child) => ({ ...child }))
1220
+ } : { ...item })
1221
+ }));
1222
+ }
1223
+ function configOptionHasValue(option, value) {
1224
+ for (const item of option.options) if ("group" in item) {
1225
+ if (item.options.some((child) => child.value === value)) return true;
1226
+ } else if (item.value === value) return true;
1227
+ return false;
1228
+ }
1229
+ function sameStringArray(left, right) {
1230
+ return left.length === right.length && left.every((value, index) => value === right[index]);
1231
+ }
1232
+ function sameJson(left, right) {
1233
+ return stableStringify(left) === stableStringify(right);
1234
+ }
1235
+ function asObject(value) {
1236
+ if (!isObject(value)) throw new AcpProtocolError(-32602, "Expected object parameters.");
1237
+ return value;
1238
+ }
1239
+ function isObject(value) {
1240
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1241
+ }
1242
+ function normalizeId(id) {
1243
+ return typeof id === "string" || typeof id === "number" || id === null ? id : null;
1244
+ }
1245
+ function toRpcError(err) {
1246
+ if (err instanceof AcpProtocolError) return {
1247
+ code: err.code,
1248
+ message: err.message,
1249
+ ...err.data !== void 0 ? { data: err.data } : {}
1250
+ };
1251
+ return {
1252
+ code: -32603,
1253
+ message: err instanceof Error ? err.message : String(err)
1254
+ };
1255
+ }
1256
+ function sessionInfo(runtime) {
1257
+ return {
1258
+ sessionId: runtime.sessionId,
1259
+ cwd: runtime.cwd,
1260
+ additionalDirectories: runtime.additionalDirectories,
1261
+ title: typeof runtime.session.metadata.title === "string" ? runtime.session.metadata.title : null,
1262
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1263
+ };
1264
+ }
1265
+ function permissionKey(name, input) {
1266
+ return `permission:${name}:${stableStringify(input)}`;
1267
+ }
1268
+ function stableStringify(value) {
1269
+ if (!isObject(value)) return JSON.stringify(value);
1270
+ const keys = Object.keys(value).sort();
1271
+ const out = {};
1272
+ for (const key of keys) out[key] = value[key];
1273
+ return JSON.stringify(out);
1274
+ }
1275
+ function reachedMaxTurns(stats, behavior) {
1276
+ const maxTurns = behavior?.maxTurns;
1277
+ return typeof maxTurns === "number" && stats.turns >= maxTurns && lastFinishReason(stats.turnUsage) !== "length";
1278
+ }
1279
+ function lastFinishReason(turnUsage) {
1280
+ for (let i = (turnUsage?.length ?? 0) - 1; i >= 0; i--) {
1281
+ const reason = turnUsage?.[i]?.finishReason;
1282
+ if (reason) return reason;
1283
+ }
1284
+ }
1285
+ //#endregion
1286
+ //#region src/acp/index.ts
1287
+ function runAcpStdioServer(options) {
1288
+ const server = createAcpServer(options);
1289
+ const connection = createJsonRpcConnection({
1290
+ input: options.input ?? process.stdin,
1291
+ output: options.output ?? process.stdout,
1292
+ framing: options.framing,
1293
+ onError: options.onError,
1294
+ onRequest: (message) => server.handleMessage(message),
1295
+ onNotification: async (message) => {
1296
+ await server.handleMessage(message);
1297
+ }
1298
+ });
1299
+ server.setPeer(connection);
1300
+ connection.start();
1301
+ return {
1302
+ server,
1303
+ connection,
1304
+ async close() {
1305
+ connection.close();
1306
+ await server.close();
1307
+ }
1308
+ };
1309
+ }
1310
+ //#endregion
1311
+ export { acpMcpServersToZidane as a, stopReasonFromRun as c, createJsonRpcConnection as d, wrapToolsForAcpClient as i, toolResultToAcpContent as l, AcpProtocolError as n, acpPromptToPromptParts as o, createAcpServer as r, sessionBlocksToAcp as s, runAcpStdioServer as t, JsonRpcRemoteError as u };
1312
+
1313
+ //# sourceMappingURL=acp-CEE6C0m_.js.map