acpx 0.1.16 → 0.3.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,11 +1,83 @@
1
- import { t as __exportAll } from "./rolldown-runtime-CjeV3_4I.js";
2
- import { t as isAcpJsonRpcMessage } from "./acp-jsonrpc-CGT_1Mel.js";
1
+ import { t as __exportAll } from "./rolldown-runtime-CiIaOW0V.js";
2
+ import { t as isAcpJsonRpcMessage } from "./acp-jsonrpc-BNHXq7qK.js";
3
3
  import fs from "node:fs/promises";
4
4
  import path from "node:path";
5
5
  import { createHash, randomUUID } from "node:crypto";
6
6
  import os from "node:os";
7
7
  import net from "node:net";
8
-
8
+ //#region src/acp-error-shapes.ts
9
+ const RESOURCE_NOT_FOUND_ACP_CODES = new Set([-32001, -32002]);
10
+ function asRecord$3(value) {
11
+ if (!value || typeof value !== "object" || Array.isArray(value)) return;
12
+ return value;
13
+ }
14
+ function toAcpErrorPayload(value) {
15
+ const record = asRecord$3(value);
16
+ if (!record) return;
17
+ if (typeof record.code !== "number" || !Number.isFinite(record.code)) return;
18
+ if (typeof record.message !== "string" || record.message.length === 0) return;
19
+ return {
20
+ code: record.code,
21
+ message: record.message,
22
+ data: record.data
23
+ };
24
+ }
25
+ function extractAcpErrorInternal(value, depth) {
26
+ if (depth > 5) return;
27
+ const direct = toAcpErrorPayload(value);
28
+ if (direct) return direct;
29
+ const record = asRecord$3(value);
30
+ if (!record) return;
31
+ if ("error" in record) {
32
+ const nested = extractAcpErrorInternal(record.error, depth + 1);
33
+ if (nested) return nested;
34
+ }
35
+ if ("acp" in record) {
36
+ const nested = extractAcpErrorInternal(record.acp, depth + 1);
37
+ if (nested) return nested;
38
+ }
39
+ if ("cause" in record) {
40
+ const nested = extractAcpErrorInternal(record.cause, depth + 1);
41
+ if (nested) return nested;
42
+ }
43
+ }
44
+ function formatUnknownErrorMessage(error) {
45
+ if (error instanceof Error) return error.message;
46
+ if (error && typeof error === "object") {
47
+ const maybeMessage = error.message;
48
+ if (typeof maybeMessage === "string" && maybeMessage.length > 0) return maybeMessage;
49
+ try {
50
+ return JSON.stringify(error);
51
+ } catch {}
52
+ }
53
+ return String(error);
54
+ }
55
+ function isSessionNotFoundText(value) {
56
+ if (typeof value !== "string") return false;
57
+ const normalized = value.toLowerCase();
58
+ return normalized.includes("resource_not_found") || normalized.includes("resource not found") || normalized.includes("session not found") || normalized.includes("unknown session") || normalized.includes("invalid session identifier");
59
+ }
60
+ function hasSessionNotFoundHint(value, depth = 0) {
61
+ if (depth > 4) return false;
62
+ if (isSessionNotFoundText(value)) return true;
63
+ if (Array.isArray(value)) return value.some((entry) => hasSessionNotFoundHint(entry, depth + 1));
64
+ const record = asRecord$3(value);
65
+ if (!record) return false;
66
+ return Object.values(record).some((entry) => hasSessionNotFoundHint(entry, depth + 1));
67
+ }
68
+ function extractAcpError(error) {
69
+ return extractAcpErrorInternal(error, 0);
70
+ }
71
+ function isAcpResourceNotFoundError(error) {
72
+ const acp = extractAcpError(error);
73
+ if (acp && RESOURCE_NOT_FOUND_ACP_CODES.has(acp.code)) return true;
74
+ if (acp) {
75
+ if (isSessionNotFoundText(acp.message)) return true;
76
+ if (hasSessionNotFoundHint(acp.data)) return true;
77
+ }
78
+ return isSessionNotFoundText(formatUnknownErrorMessage(error));
79
+ }
80
+ //#endregion
9
81
  //#region src/errors.ts
10
82
  var AcpxOperationalError = class extends Error {
11
83
  outputCode;
@@ -98,7 +170,121 @@ var PermissionPromptUnavailableError = class extends AcpxOperationalError {
98
170
  super("Permission prompt unavailable in non-interactive mode");
99
171
  }
100
172
  };
101
-
173
+ //#endregion
174
+ //#region src/prompt-content.ts
175
+ var PromptInputValidationError = class extends Error {
176
+ constructor(message) {
177
+ super(message);
178
+ this.name = "PromptInputValidationError";
179
+ }
180
+ };
181
+ function asRecord$2(value) {
182
+ if (!value || typeof value !== "object" || Array.isArray(value)) return;
183
+ return value;
184
+ }
185
+ function isNonEmptyString(value) {
186
+ return typeof value === "string" && value.trim().length > 0;
187
+ }
188
+ function isBase64Data(value) {
189
+ if (value.length === 0 || value.length % 4 !== 0) return false;
190
+ return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value);
191
+ }
192
+ function isImageMimeType(value) {
193
+ return /^image\/[A-Za-z0-9.+-]+$/i.test(value);
194
+ }
195
+ function isTextBlock(value) {
196
+ const record = asRecord$2(value);
197
+ return record?.type === "text" && typeof record.text === "string";
198
+ }
199
+ function isImageBlock(value) {
200
+ const record = asRecord$2(value);
201
+ return record?.type === "image" && isNonEmptyString(record.mimeType) && isImageMimeType(record.mimeType) && typeof record.data === "string" && isBase64Data(record.data);
202
+ }
203
+ function isResourceLinkBlock(value) {
204
+ const record = asRecord$2(value);
205
+ return record?.type === "resource_link" && isNonEmptyString(record.uri) && (record.title === void 0 || typeof record.title === "string") && (record.name === void 0 || typeof record.name === "string");
206
+ }
207
+ function isResourcePayload(value) {
208
+ const record = asRecord$2(value);
209
+ if (!record || !isNonEmptyString(record.uri)) return false;
210
+ return record.text === void 0 || typeof record.text === "string";
211
+ }
212
+ function isResourceBlock(value) {
213
+ const record = asRecord$2(value);
214
+ return record?.type === "resource" && isResourcePayload(record.resource);
215
+ }
216
+ function isContentBlock(value) {
217
+ return isTextBlock(value) || isImageBlock(value) || isResourceLinkBlock(value) || isResourceBlock(value);
218
+ }
219
+ function getContentBlockValidationError(value, index) {
220
+ const record = asRecord$2(value);
221
+ if (!record || typeof record.type !== "string") return `prompt[${index}] must be an ACP content block object`;
222
+ switch (record.type) {
223
+ case "text": return typeof record.text === "string" ? void 0 : `prompt[${index}] text block must include a string text field`;
224
+ case "image":
225
+ if (!isNonEmptyString(record.mimeType)) return `prompt[${index}] image block must include a non-empty mimeType`;
226
+ if (!isImageMimeType(record.mimeType)) return `prompt[${index}] image block mimeType must start with image/`;
227
+ if (typeof record.data !== "string" || record.data.length === 0) return `prompt[${index}] image block must include non-empty base64 data`;
228
+ if (!isBase64Data(record.data)) return `prompt[${index}] image block data must be valid base64`;
229
+ return;
230
+ case "resource_link":
231
+ if (!isNonEmptyString(record.uri)) return `prompt[${index}] resource_link block must include a non-empty uri`;
232
+ if (record.title !== void 0 && typeof record.title !== "string") return `prompt[${index}] resource_link block title must be a string when present`;
233
+ if (record.name !== void 0 && typeof record.name !== "string") return `prompt[${index}] resource_link block name must be a string when present`;
234
+ return;
235
+ case "resource":
236
+ if (!asRecord$2(record.resource)) return `prompt[${index}] resource block must include a resource object`;
237
+ if (!isResourcePayload(record.resource)) return `prompt[${index}] resource block resource must include a non-empty uri and optional text`;
238
+ return;
239
+ default: return `prompt[${index}] has unsupported content block type ${JSON.stringify(record.type)}`;
240
+ }
241
+ }
242
+ function isPromptInput(value) {
243
+ return Array.isArray(value) && value.every((entry) => isContentBlock(entry));
244
+ }
245
+ function textPrompt(text) {
246
+ return [{
247
+ type: "text",
248
+ text
249
+ }];
250
+ }
251
+ function parseStructuredPrompt(source) {
252
+ if (!source.startsWith("[")) return;
253
+ try {
254
+ const parsed = JSON.parse(source);
255
+ if (isPromptInput(parsed)) return parsed;
256
+ if (Array.isArray(parsed)) throw new PromptInputValidationError(parsed.map((entry, index) => getContentBlockValidationError(entry, index)).find((message) => message !== void 0) ?? "Structured prompt JSON must be an array of valid ACP content blocks");
257
+ return;
258
+ } catch (error) {
259
+ if (error instanceof PromptInputValidationError) throw error;
260
+ return;
261
+ }
262
+ }
263
+ function parsePromptSource(source) {
264
+ const trimmed = source.trim();
265
+ const structured = parseStructuredPrompt(trimmed);
266
+ if (structured) return structured;
267
+ if (!trimmed) return [];
268
+ return textPrompt(trimmed);
269
+ }
270
+ function mergePromptSourceWithText(source, suffixText) {
271
+ const prompt = parsePromptSource(source);
272
+ const appended = suffixText.trim();
273
+ if (!appended) return prompt;
274
+ if (prompt.length === 0) return textPrompt(appended);
275
+ return [...prompt, ...textPrompt(appended)];
276
+ }
277
+ function promptToDisplayText(prompt) {
278
+ return prompt.map((block) => {
279
+ switch (block.type) {
280
+ case "text": return block.text;
281
+ case "resource_link": return block.title ?? block.name ?? block.uri;
282
+ case "resource": return "text" in block.resource && typeof block.resource.text === "string" ? block.resource.text : block.resource.uri;
283
+ case "image": return `[image] ${block.mimeType}`;
284
+ default: return "";
285
+ }
286
+ }).filter((entry) => entry.trim().length > 0).join("\n\n").trim();
287
+ }
102
288
  //#endregion
103
289
  //#region src/types.ts
104
290
  const EXIT_CODES = {
@@ -132,10 +318,8 @@ const OUTPUT_ERROR_ORIGINS = [
132
318
  "acp"
133
319
  ];
134
320
  const SESSION_RECORD_SCHEMA = "acpx.session.v1";
135
-
136
321
  //#endregion
137
322
  //#region src/error-normalization.ts
138
- const RESOURCE_NOT_FOUND_ACP_CODES = new Set([-32002]);
139
323
  const AUTH_REQUIRED_ACP_CODES = new Set([-32e3]);
140
324
  const QUERY_CLOSED_BEFORE_RESPONSE_DETAIL = "query closed before response received";
141
325
  function asRecord$1(value) {
@@ -174,35 +358,9 @@ function readOutputErrorMeta(error) {
174
358
  detailCode: typeof record.detailCode === "string" && record.detailCode.trim().length > 0 ? record.detailCode : void 0,
175
359
  origin: isOutputErrorOrigin$1(record.origin) ? record.origin : void 0,
176
360
  retryable: typeof record.retryable === "boolean" ? record.retryable : void 0,
177
- acp: toAcpErrorPayload(record.acp)
361
+ acp: extractAcpError(record.acp)
178
362
  };
179
363
  }
180
- function toAcpErrorPayload(value) {
181
- const record = asRecord$1(value);
182
- if (!record) return;
183
- if (typeof record.code !== "number" || !Number.isFinite(record.code)) return;
184
- if (typeof record.message !== "string" || record.message.length === 0) return;
185
- return {
186
- code: record.code,
187
- message: record.message,
188
- data: record.data
189
- };
190
- }
191
- function extractAcpErrorInternal(value, depth) {
192
- if (depth > 5) return;
193
- const direct = toAcpErrorPayload(value);
194
- if (direct) return direct;
195
- const record = asRecord$1(value);
196
- if (!record) return;
197
- if ("error" in record) {
198
- const nested = extractAcpErrorInternal(record.error, depth + 1);
199
- if (nested) return nested;
200
- }
201
- if ("cause" in record) {
202
- const nested = extractAcpErrorInternal(record.cause, depth + 1);
203
- if (nested) return nested;
204
- }
205
- }
206
364
  function isTimeoutLike(error) {
207
365
  return error instanceof Error && error.name === "TimeoutError";
208
366
  }
@@ -214,22 +372,7 @@ function isUsageLike(error) {
214
372
  return error.name === "CommanderError" || error.name === "InvalidArgumentError" || asRecord$1(error)?.code === "commander.invalidArgument";
215
373
  }
216
374
  function formatErrorMessage(error) {
217
- if (error instanceof Error) return error.message;
218
- if (error && typeof error === "object") {
219
- const maybeMessage = error.message;
220
- if (typeof maybeMessage === "string" && maybeMessage.length > 0) return maybeMessage;
221
- try {
222
- return JSON.stringify(error);
223
- } catch {}
224
- }
225
- return String(error);
226
- }
227
- function extractAcpError(error) {
228
- return extractAcpErrorInternal(error, 0);
229
- }
230
- function isAcpResourceNotFoundError(error) {
231
- const acp = extractAcpError(error);
232
- return Boolean(acp && RESOURCE_NOT_FOUND_ACP_CODES.has(acp.code));
375
+ return formatUnknownErrorMessage(error);
233
376
  }
234
377
  function isAcpQueryClosedBeforeResponseError(error) {
235
378
  const acp = extractAcpError(error);
@@ -271,7 +414,6 @@ function exitCodeForOutputErrorCode(code) {
271
414
  default: return EXIT_CODES.ERROR;
272
415
  }
273
416
  }
274
-
275
417
  //#endregion
276
418
  //#region src/perf-metrics.ts
277
419
  const counters = /* @__PURE__ */ new Map();
@@ -338,7 +480,6 @@ function resetPerfMetrics() {
338
480
  function formatPerfMetric(name, durationMsValue) {
339
481
  return `${name}=${roundMetric(durationMsValue)}ms`;
340
482
  }
341
-
342
483
  //#endregion
343
484
  //#region src/queue-paths.ts
344
485
  function shortHash(value, length) {
@@ -362,7 +503,6 @@ function queueSocketPath(sessionId, homeDir = os.homedir()) {
362
503
  if (process.platform === "win32") return `\\\\.\\pipe\\acpx-${key}`;
363
504
  return path.join(queueSocketBaseDir(homeDir) ?? "/tmp", `${key}.sock`);
364
505
  }
365
-
366
506
  //#endregion
367
507
  //#region src/queue-lease-store.ts
368
508
  const PROCESS_EXIT_GRACE_MS = 1500;
@@ -549,7 +689,6 @@ async function waitMs(ms) {
549
689
  setTimeout(resolve, ms);
550
690
  });
551
691
  }
552
-
553
692
  //#endregion
554
693
  //#region src/queue-messages.ts
555
694
  function asRecord(value) {
@@ -595,12 +734,14 @@ function parseQueueRequest(raw) {
595
734
  if (request.type === "submit_prompt") {
596
735
  const nonInteractivePermissions = request.nonInteractivePermissions == null ? void 0 : isNonInteractivePermissionPolicy(request.nonInteractivePermissions) ? request.nonInteractivePermissions : null;
597
736
  const suppressSdkConsoleErrors = request.suppressSdkConsoleErrors == null ? void 0 : typeof request.suppressSdkConsoleErrors === "boolean" ? request.suppressSdkConsoleErrors : null;
598
- if (typeof request.message !== "string" || !isPermissionMode(request.permissionMode) || nonInteractivePermissions === null || suppressSdkConsoleErrors === null || typeof request.waitForCompletion !== "boolean") return null;
737
+ const prompt = request.prompt == null ? void 0 : isPromptInput(request.prompt) ? request.prompt : null;
738
+ if (typeof request.message !== "string" || !isPermissionMode(request.permissionMode) || prompt === null || nonInteractivePermissions === null || suppressSdkConsoleErrors === null || typeof request.waitForCompletion !== "boolean") return null;
599
739
  return {
600
740
  type: "submit_prompt",
601
741
  requestId: request.requestId,
602
742
  ownerGeneration,
603
743
  message: request.message,
744
+ prompt: prompt ?? textPrompt(request.message),
604
745
  permissionMode: request.permissionMode,
605
746
  nonInteractivePermissions,
606
747
  timeoutMs,
@@ -726,7 +867,6 @@ function parseQueueOwnerMessage(raw) {
726
867
  }
727
868
  return null;
728
869
  }
729
-
730
870
  //#endregion
731
871
  //#region src/queue-ipc-server.ts
732
872
  function makeQueueOwnerError(requestId, message, detailCode, options = {}) {
@@ -862,6 +1002,26 @@ var SessionQueueOwner = class SessionQueueOwner {
862
1002
  this.pending.push(task);
863
1003
  this.emitQueueDepth();
864
1004
  }
1005
+ handleControlRequest(options) {
1006
+ writeQueueMessage(options.socket, {
1007
+ type: "accepted",
1008
+ requestId: options.requestId,
1009
+ ownerGeneration: this.ownerGeneration
1010
+ });
1011
+ options.run().then((message) => {
1012
+ writeQueueMessage(options.socket, {
1013
+ ...message,
1014
+ ownerGeneration: this.ownerGeneration
1015
+ });
1016
+ }).catch((error) => {
1017
+ writeQueueMessage(options.socket, {
1018
+ ...makeQueueOwnerErrorFromUnknown(options.requestId, error, "QUEUE_CONTROL_REQUEST_FAILED"),
1019
+ ownerGeneration: this.ownerGeneration
1020
+ });
1021
+ }).finally(() => {
1022
+ if (!options.socket.destroyed) options.socket.end();
1023
+ });
1024
+ }
865
1025
  handleConnection(socket) {
866
1026
  socket.setEncoding("utf8");
867
1027
  if (this.closed) {
@@ -898,77 +1058,48 @@ var SessionQueueOwner = class SessionQueueOwner {
898
1058
  return;
899
1059
  }
900
1060
  if (request.type === "cancel_prompt") {
901
- writeQueueMessage(socket, {
902
- type: "accepted",
1061
+ this.handleControlRequest({
1062
+ socket,
903
1063
  requestId: request.requestId,
904
- ownerGeneration: this.ownerGeneration
905
- });
906
- this.controlHandlers.cancelPrompt().then((cancelled) => {
907
- writeQueueMessage(socket, {
1064
+ run: async () => ({
908
1065
  type: "cancel_result",
909
1066
  requestId: request.requestId,
910
- ownerGeneration: this.ownerGeneration,
911
- cancelled
912
- });
913
- }).catch((error) => {
914
- writeQueueMessage(socket, {
915
- ...makeQueueOwnerErrorFromUnknown(request.requestId, error, "QUEUE_CONTROL_REQUEST_FAILED"),
916
- ownerGeneration: this.ownerGeneration
917
- });
918
- }).finally(() => {
919
- if (!socket.destroyed) socket.end();
1067
+ cancelled: await this.controlHandlers.cancelPrompt()
1068
+ })
920
1069
  });
921
1070
  return;
922
1071
  }
923
1072
  if (request.type === "set_mode") {
924
- writeQueueMessage(socket, {
925
- type: "accepted",
1073
+ this.handleControlRequest({
1074
+ socket,
926
1075
  requestId: request.requestId,
927
- ownerGeneration: this.ownerGeneration
928
- });
929
- this.controlHandlers.setSessionMode(request.modeId, request.timeoutMs).then(() => {
930
- writeQueueMessage(socket, {
931
- type: "set_mode_result",
932
- requestId: request.requestId,
933
- ownerGeneration: this.ownerGeneration,
934
- modeId: request.modeId
935
- });
936
- }).catch((error) => {
937
- writeQueueMessage(socket, {
938
- ...makeQueueOwnerErrorFromUnknown(request.requestId, error, "QUEUE_CONTROL_REQUEST_FAILED"),
939
- ownerGeneration: this.ownerGeneration
940
- });
941
- }).finally(() => {
942
- if (!socket.destroyed) socket.end();
1076
+ run: async () => {
1077
+ await this.controlHandlers.setSessionMode(request.modeId, request.timeoutMs);
1078
+ return {
1079
+ type: "set_mode_result",
1080
+ requestId: request.requestId,
1081
+ modeId: request.modeId
1082
+ };
1083
+ }
943
1084
  });
944
1085
  return;
945
1086
  }
946
1087
  if (request.type === "set_config_option") {
947
- writeQueueMessage(socket, {
948
- type: "accepted",
1088
+ this.handleControlRequest({
1089
+ socket,
949
1090
  requestId: request.requestId,
950
- ownerGeneration: this.ownerGeneration
951
- });
952
- this.controlHandlers.setSessionConfigOption(request.configId, request.value, request.timeoutMs).then((response) => {
953
- writeQueueMessage(socket, {
1091
+ run: async () => ({
954
1092
  type: "set_config_option_result",
955
1093
  requestId: request.requestId,
956
- ownerGeneration: this.ownerGeneration,
957
- response
958
- });
959
- }).catch((error) => {
960
- writeQueueMessage(socket, {
961
- ...makeQueueOwnerErrorFromUnknown(request.requestId, error, "QUEUE_CONTROL_REQUEST_FAILED"),
962
- ownerGeneration: this.ownerGeneration
963
- });
964
- }).finally(() => {
965
- if (!socket.destroyed) socket.end();
1094
+ response: await this.controlHandlers.setSessionConfigOption(request.configId, request.value, request.timeoutMs)
1095
+ })
966
1096
  });
967
1097
  return;
968
1098
  }
969
1099
  const task = {
970
1100
  requestId: request.requestId,
971
1101
  message: request.message,
1102
+ prompt: request.prompt ?? textPrompt(request.message),
972
1103
  permissionMode: request.permissionMode,
973
1104
  nonInteractivePermissions: request.nonInteractivePermissions,
974
1105
  timeoutMs: request.timeoutMs,
@@ -1006,11 +1137,10 @@ var SessionQueueOwner = class SessionQueueOwner {
1006
1137
  socket.on("error", () => {});
1007
1138
  }
1008
1139
  };
1009
-
1010
1140
  //#endregion
1011
1141
  //#region src/queue-ipc.ts
1012
1142
  var queue_ipc_exports = /* @__PURE__ */ __exportAll({
1013
- QUEUE_CONNECT_RETRY_MS: () => QUEUE_CONNECT_RETRY_MS,
1143
+ QUEUE_CONNECT_RETRY_MS: () => 50,
1014
1144
  SessionQueueOwner: () => SessionQueueOwner,
1015
1145
  isProcessAlive: () => isProcessAlive,
1016
1146
  probeQueueOwnerHealth: () => probeQueueOwnerHealth,
@@ -1063,7 +1193,7 @@ async function connectToQueueOwner(owner, maxAttempts = QUEUE_CONNECT_ATTEMPTS)
1063
1193
  } catch (error) {
1064
1194
  lastError = error;
1065
1195
  if (!shouldRetryQueueConnect(error)) throw error;
1066
- await waitMs(QUEUE_CONNECT_RETRY_MS);
1196
+ await waitMs(50);
1067
1197
  }
1068
1198
  if (lastError && !shouldRetryQueueConnect(lastError)) throw lastError;
1069
1199
  }
@@ -1115,27 +1245,38 @@ function assertOwnerGeneration(owner, message) {
1115
1245
  });
1116
1246
  return message;
1117
1247
  }
1118
- async function submitToQueueOwner(owner, options) {
1119
- const socket = await connectToQueueOwner(owner);
1248
+ function makeMalformedQueueMessageError() {
1249
+ return new QueueProtocolError("Queue owner sent malformed message", {
1250
+ detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
1251
+ origin: "queue",
1252
+ retryable: true
1253
+ });
1254
+ }
1255
+ function parseQueueOwnerResponseLine(owner, requestId, line) {
1256
+ let parsed;
1257
+ try {
1258
+ parsed = JSON.parse(line);
1259
+ } catch {
1260
+ throw new QueueProtocolError("Queue owner sent invalid JSON payload", {
1261
+ detailCode: "QUEUE_PROTOCOL_INVALID_JSON",
1262
+ origin: "queue",
1263
+ retryable: true
1264
+ });
1265
+ }
1266
+ const parsedMessage = parseQueueOwnerMessage(parsed);
1267
+ if (!parsedMessage) throw makeMalformedQueueMessageError();
1268
+ const message = assertOwnerGeneration(owner, parsedMessage);
1269
+ if (message.requestId !== requestId) throw makeMalformedQueueMessageError();
1270
+ return message;
1271
+ }
1272
+ async function runQueueOwnerRequest(options) {
1273
+ const socket = await connectToQueueOwner(options.owner);
1120
1274
  if (!socket) return;
1121
1275
  socket.setEncoding("utf8");
1122
- const requestId = randomUUID();
1123
- const request = {
1124
- type: "submit_prompt",
1125
- requestId,
1126
- ownerGeneration: owner.ownerGeneration,
1127
- message: options.message,
1128
- permissionMode: options.permissionMode,
1129
- nonInteractivePermissions: options.nonInteractivePermissions,
1130
- timeoutMs: options.timeoutMs,
1131
- suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
1132
- waitForCompletion: options.waitForCompletion
1133
- };
1134
- options.outputFormatter.setContext({ sessionId: options.sessionId });
1135
1276
  return await new Promise((resolve, reject) => {
1136
1277
  let settled = false;
1137
- let acknowledged = false;
1138
1278
  let buffer = "";
1279
+ const state = { acknowledged: false };
1139
1280
  const finishResolve = (result) => {
1140
1281
  if (settled) return;
1141
1282
  settled = true;
@@ -1150,46 +1291,73 @@ async function submitToQueueOwner(owner, options) {
1150
1291
  if (!socket.destroyed) socket.destroy();
1151
1292
  reject(error);
1152
1293
  };
1294
+ const controls = {
1295
+ state,
1296
+ resolve: finishResolve,
1297
+ reject: finishReject
1298
+ };
1153
1299
  const processLine = (line) => {
1154
- let parsed;
1300
+ let message;
1155
1301
  try {
1156
- parsed = JSON.parse(line);
1157
- } catch {
1158
- finishReject(new QueueProtocolError("Queue owner sent invalid JSON payload", {
1159
- detailCode: "QUEUE_PROTOCOL_INVALID_JSON",
1160
- origin: "queue",
1161
- retryable: true
1162
- }));
1163
- return;
1164
- }
1165
- const parsedMessage = parseQueueOwnerMessage(parsed);
1166
- if (!parsedMessage) {
1167
- finishReject(new QueueProtocolError("Queue owner sent malformed message", {
1168
- detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
1169
- origin: "queue",
1170
- retryable: true
1171
- }));
1172
- return;
1173
- }
1174
- const message = assertOwnerGeneration(owner, parsedMessage);
1175
- if (message.requestId !== requestId) {
1176
- finishReject(new QueueProtocolError("Queue owner sent malformed message", {
1177
- detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
1178
- origin: "queue",
1179
- retryable: true
1180
- }));
1302
+ message = parseQueueOwnerResponseLine(options.owner, options.request.requestId, line);
1303
+ } catch (error) {
1304
+ finishReject(error);
1181
1305
  return;
1182
1306
  }
1183
1307
  if (message.type === "accepted") {
1184
- acknowledged = true;
1185
- options.outputFormatter.setContext({ sessionId: options.sessionId });
1186
- if (!options.waitForCompletion) finishResolve({
1187
- queued: true,
1188
- sessionId: options.sessionId,
1189
- requestId
1190
- });
1308
+ state.acknowledged = true;
1309
+ options.onAccepted?.(controls);
1191
1310
  return;
1192
1311
  }
1312
+ options.onMessage(message, controls);
1313
+ };
1314
+ socket.on("data", (chunk) => {
1315
+ buffer += chunk;
1316
+ let index = buffer.indexOf("\n");
1317
+ while (index >= 0) {
1318
+ const line = buffer.slice(0, index).trim();
1319
+ buffer = buffer.slice(index + 1);
1320
+ if (line.length > 0) processLine(line);
1321
+ index = buffer.indexOf("\n");
1322
+ }
1323
+ });
1324
+ socket.once("error", (error) => {
1325
+ finishReject(error);
1326
+ });
1327
+ socket.once("close", () => {
1328
+ if (settled) return;
1329
+ options.onClose(controls);
1330
+ });
1331
+ socket.write(`${JSON.stringify(options.request)}\n`);
1332
+ });
1333
+ }
1334
+ async function submitToQueueOwner(owner, options) {
1335
+ const requestId = randomUUID();
1336
+ const request = {
1337
+ type: "submit_prompt",
1338
+ requestId,
1339
+ ownerGeneration: owner.ownerGeneration,
1340
+ message: options.message,
1341
+ prompt: options.prompt,
1342
+ permissionMode: options.permissionMode,
1343
+ nonInteractivePermissions: options.nonInteractivePermissions,
1344
+ timeoutMs: options.timeoutMs,
1345
+ suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
1346
+ waitForCompletion: options.waitForCompletion
1347
+ };
1348
+ options.outputFormatter.setContext({ sessionId: options.sessionId });
1349
+ return await runQueueOwnerRequest({
1350
+ owner,
1351
+ request,
1352
+ onAccepted: ({ resolve }) => {
1353
+ options.outputFormatter.setContext({ sessionId: options.sessionId });
1354
+ if (!options.waitForCompletion) resolve({
1355
+ queued: true,
1356
+ sessionId: options.sessionId,
1357
+ requestId
1358
+ });
1359
+ },
1360
+ onMessage: (message, { state, resolve, reject }) => {
1193
1361
  if (message.type === "error") {
1194
1362
  options.outputFormatter.setContext({ sessionId: options.sessionId });
1195
1363
  const queueErrorAlreadyEmitted = options.errorEmissionPolicy?.queueErrorAlreadyEmitted ?? true;
@@ -1204,7 +1372,7 @@ async function submitToQueueOwner(owner, options) {
1204
1372
  });
1205
1373
  options.outputFormatter.flush();
1206
1374
  }
1207
- finishReject(new QueueConnectionError(message.message, {
1375
+ reject(new QueueConnectionError(message.message, {
1208
1376
  outputCode: message.code,
1209
1377
  detailCode: message.detailCode,
1210
1378
  origin: message.origin ?? "queue",
@@ -1214,8 +1382,8 @@ async function submitToQueueOwner(owner, options) {
1214
1382
  }));
1215
1383
  return;
1216
1384
  }
1217
- if (!acknowledged) {
1218
- finishReject(new QueueConnectionError("Queue owner did not acknowledge request", {
1385
+ if (!state.acknowledged) {
1386
+ reject(new QueueConnectionError("Queue owner did not acknowledge request", {
1219
1387
  detailCode: "QUEUE_ACK_MISSING",
1220
1388
  origin: "queue",
1221
1389
  retryable: true
@@ -1228,32 +1396,18 @@ async function submitToQueueOwner(owner, options) {
1228
1396
  }
1229
1397
  if (message.type === "result") {
1230
1398
  options.outputFormatter.flush();
1231
- finishResolve(message.result);
1399
+ resolve(message.result);
1232
1400
  return;
1233
1401
  }
1234
- finishReject(new QueueProtocolError("Queue owner returned unexpected response", {
1402
+ reject(new QueueProtocolError("Queue owner returned unexpected response", {
1235
1403
  detailCode: "QUEUE_PROTOCOL_UNEXPECTED_RESPONSE",
1236
1404
  origin: "queue",
1237
1405
  retryable: true
1238
1406
  }));
1239
- };
1240
- socket.on("data", (chunk) => {
1241
- buffer += chunk;
1242
- let index = buffer.indexOf("\n");
1243
- while (index >= 0) {
1244
- const line = buffer.slice(0, index).trim();
1245
- buffer = buffer.slice(index + 1);
1246
- if (line.length > 0) processLine(line);
1247
- index = buffer.indexOf("\n");
1248
- }
1249
- });
1250
- socket.once("error", (error) => {
1251
- finishReject(error);
1252
- });
1253
- socket.once("close", () => {
1254
- if (settled) return;
1255
- if (!acknowledged) {
1256
- finishReject(new QueueConnectionError("Queue owner disconnected before acknowledging request", {
1407
+ },
1408
+ onClose: ({ state, resolve, reject }) => {
1409
+ if (!state.acknowledged) {
1410
+ reject(new QueueConnectionError("Queue owner disconnected before acknowledging request", {
1257
1411
  detailCode: "QUEUE_DISCONNECTED_BEFORE_ACK",
1258
1412
  origin: "queue",
1259
1413
  retryable: true
@@ -1261,80 +1415,28 @@ async function submitToQueueOwner(owner, options) {
1261
1415
  return;
1262
1416
  }
1263
1417
  if (!options.waitForCompletion) {
1264
- finishResolve({
1418
+ resolve({
1265
1419
  queued: true,
1266
1420
  sessionId: options.sessionId,
1267
1421
  requestId
1268
1422
  });
1269
1423
  return;
1270
1424
  }
1271
- finishReject(new QueueConnectionError("Queue owner disconnected before prompt completion", {
1425
+ reject(new QueueConnectionError("Queue owner disconnected before prompt completion", {
1272
1426
  detailCode: "QUEUE_DISCONNECTED_BEFORE_COMPLETION",
1273
1427
  origin: "queue",
1274
1428
  retryable: true
1275
1429
  }));
1276
- });
1277
- socket.write(`${JSON.stringify(request)}\n`);
1430
+ }
1278
1431
  });
1279
1432
  }
1280
1433
  async function submitControlToQueueOwner(owner, request, isExpectedResponse) {
1281
- const socket = await connectToQueueOwner(owner);
1282
- if (!socket) return;
1283
- socket.setEncoding("utf8");
1284
- return await new Promise((resolve, reject) => {
1285
- let settled = false;
1286
- let acknowledged = false;
1287
- let buffer = "";
1288
- const finishResolve = (result) => {
1289
- if (settled) return;
1290
- settled = true;
1291
- socket.removeAllListeners();
1292
- if (!socket.destroyed) socket.end();
1293
- resolve(result);
1294
- };
1295
- const finishReject = (error) => {
1296
- if (settled) return;
1297
- settled = true;
1298
- socket.removeAllListeners();
1299
- if (!socket.destroyed) socket.destroy();
1300
- reject(error);
1301
- };
1302
- const processLine = (line) => {
1303
- let parsed;
1304
- try {
1305
- parsed = JSON.parse(line);
1306
- } catch {
1307
- finishReject(new QueueProtocolError("Queue owner sent invalid JSON payload", {
1308
- detailCode: "QUEUE_PROTOCOL_INVALID_JSON",
1309
- origin: "queue",
1310
- retryable: true
1311
- }));
1312
- return;
1313
- }
1314
- const parsedMessage = parseQueueOwnerMessage(parsed);
1315
- if (!parsedMessage) {
1316
- finishReject(new QueueProtocolError("Queue owner sent malformed message", {
1317
- detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
1318
- origin: "queue",
1319
- retryable: true
1320
- }));
1321
- return;
1322
- }
1323
- const message = assertOwnerGeneration(owner, parsedMessage);
1324
- if (message.requestId !== request.requestId) {
1325
- finishReject(new QueueProtocolError("Queue owner sent malformed message", {
1326
- detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
1327
- origin: "queue",
1328
- retryable: true
1329
- }));
1330
- return;
1331
- }
1332
- if (message.type === "accepted") {
1333
- acknowledged = true;
1334
- return;
1335
- }
1434
+ return await runQueueOwnerRequest({
1435
+ owner,
1436
+ request,
1437
+ onMessage: (message, { state, resolve, reject }) => {
1336
1438
  if (message.type === "error") {
1337
- finishReject(new QueueConnectionError(message.message, {
1439
+ reject(new QueueConnectionError(message.message, {
1338
1440
  outputCode: message.code,
1339
1441
  detailCode: message.detailCode,
1340
1442
  origin: message.origin ?? "queue",
@@ -1343,8 +1445,8 @@ async function submitControlToQueueOwner(owner, request, isExpectedResponse) {
1343
1445
  }));
1344
1446
  return;
1345
1447
  }
1346
- if (!acknowledged) {
1347
- finishReject(new QueueConnectionError("Queue owner did not acknowledge request", {
1448
+ if (!state.acknowledged) {
1449
+ reject(new QueueConnectionError("Queue owner did not acknowledge request", {
1348
1450
  detailCode: "QUEUE_ACK_MISSING",
1349
1451
  origin: "queue",
1350
1452
  retryable: true
@@ -1352,45 +1454,30 @@ async function submitControlToQueueOwner(owner, request, isExpectedResponse) {
1352
1454
  return;
1353
1455
  }
1354
1456
  if (!isExpectedResponse(message)) {
1355
- finishReject(new QueueProtocolError("Queue owner returned unexpected response", {
1457
+ reject(new QueueProtocolError("Queue owner returned unexpected response", {
1356
1458
  detailCode: "QUEUE_PROTOCOL_UNEXPECTED_RESPONSE",
1357
1459
  origin: "queue",
1358
1460
  retryable: true
1359
1461
  }));
1360
1462
  return;
1361
1463
  }
1362
- finishResolve(message);
1363
- };
1364
- socket.on("data", (chunk) => {
1365
- buffer += chunk;
1366
- let index = buffer.indexOf("\n");
1367
- while (index >= 0) {
1368
- const line = buffer.slice(0, index).trim();
1369
- buffer = buffer.slice(index + 1);
1370
- if (line.length > 0) processLine(line);
1371
- index = buffer.indexOf("\n");
1372
- }
1373
- });
1374
- socket.once("error", (error) => {
1375
- finishReject(error);
1376
- });
1377
- socket.once("close", () => {
1378
- if (settled) return;
1379
- if (!acknowledged) {
1380
- finishReject(new QueueConnectionError("Queue owner disconnected before acknowledging request", {
1464
+ resolve(message);
1465
+ },
1466
+ onClose: ({ state, reject }) => {
1467
+ if (!state.acknowledged) {
1468
+ reject(new QueueConnectionError("Queue owner disconnected before acknowledging request", {
1381
1469
  detailCode: "QUEUE_DISCONNECTED_BEFORE_ACK",
1382
1470
  origin: "queue",
1383
1471
  retryable: true
1384
1472
  }));
1385
1473
  return;
1386
1474
  }
1387
- finishReject(new QueueConnectionError("Queue owner disconnected before responding", {
1475
+ reject(new QueueConnectionError("Queue owner disconnected before responding", {
1388
1476
  detailCode: "QUEUE_DISCONNECTED_BEFORE_COMPLETION",
1389
1477
  origin: "queue",
1390
1478
  retryable: true
1391
1479
  }));
1392
- });
1393
- socket.write(`${JSON.stringify(request)}\n`);
1480
+ }
1394
1481
  });
1395
1482
  }
1396
1483
  async function submitCancelToQueueOwner(owner) {
@@ -1513,7 +1600,7 @@ async function trySetConfigOptionOnRunningOwner(sessionId, configId, value, time
1513
1600
  retryable: true
1514
1601
  });
1515
1602
  }
1516
-
1517
1603
  //#endregion
1518
- export { EXIT_CODES as A, PermissionPromptUnavailableError as B, exitCodeForOutputErrorCode as C, isAcpResourceNotFoundError as D, isAcpQueryClosedBeforeResponseError as E, AuthPolicyError as F, SessionModeReplayError as H, ClaudeAcpSessionCreateTimeoutError as I, CopilotAcpUnsupportedError as L, OUTPUT_FORMATS as M, SESSION_RECORD_SCHEMA as N, normalizeOutputError as O, AgentSpawnError as P, GeminiAcpStartupTimeoutError as R, startPerfTimer as S, formatErrorMessage as T, SessionNotFoundError as U, QueueConnectionError as V, SessionResolutionError as W, getPerfMetricsSnapshot as _, trySetConfigOptionOnRunningOwner as a, resetPerfMetrics as b, SessionQueueOwner as c, releaseQueueOwnerLease as d, terminateProcess as f, formatPerfMetric as g, waitMs as h, tryCancelOnRunningOwner as i, NON_INTERACTIVE_PERMISSION_POLICIES as j, AUTH_POLICIES as k, isProcessAlive as l, tryAcquireQueueOwnerLease as m, probeQueueOwnerHealth as n, trySetModeOnRunningOwner as o, terminateQueueOwnerForSession as p, queue_ipc_exports as r, trySubmitToRunningOwner as s, QUEUE_CONNECT_RETRY_MS as t, refreshQueueOwnerLease as u, incrementPerfCounter as v, extractAcpError as w, setPerfGauge as x, measurePerf as y, PermissionDeniedError as z };
1519
- //# sourceMappingURL=queue-ipc-CEetz4_7.js.map
1604
+ export { OUTPUT_FORMATS as A, CopilotAcpUnsupportedError as B, exitCodeForOutputErrorCode as C, AUTH_POLICIES as D, normalizeOutputError as E, promptToDisplayText as F, SessionModeReplayError as G, PermissionDeniedError as H, textPrompt as I, extractAcpError as J, SessionNotFoundError as K, AgentSpawnError as L, PromptInputValidationError as M, mergePromptSourceWithText as N, EXIT_CODES as O, parsePromptSource as P, AuthPolicyError as R, startPerfTimer as S, isAcpQueryClosedBeforeResponseError as T, PermissionPromptUnavailableError as U, GeminiAcpStartupTimeoutError as V, QueueConnectionError as W, isAcpResourceNotFoundError as Y, getPerfMetricsSnapshot as _, trySetConfigOptionOnRunningOwner as a, resetPerfMetrics as b, SessionQueueOwner as c, releaseQueueOwnerLease as d, terminateProcess as f, formatPerfMetric as g, waitMs as h, tryCancelOnRunningOwner as i, SESSION_RECORD_SCHEMA as j, NON_INTERACTIVE_PERMISSION_POLICIES as k, isProcessAlive as l, tryAcquireQueueOwnerLease as m, probeQueueOwnerHealth as n, trySetModeOnRunningOwner as o, terminateQueueOwnerForSession as p, SessionResolutionError as q, queue_ipc_exports as r, trySubmitToRunningOwner as s, QUEUE_CONNECT_RETRY_MS as t, refreshQueueOwnerLease as u, incrementPerfCounter as v, formatErrorMessage as w, setPerfGauge as x, measurePerf as y, ClaudeAcpSessionCreateTimeoutError as z };
1605
+
1606
+ //# sourceMappingURL=queue-ipc-EQLpBMKv.js.map