acpx 0.3.1 → 0.4.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 (35) hide show
  1. package/README.md +65 -16
  2. package/dist/{acp-jsonrpc-BNHXq7qK.js → acp-jsonrpc-BbBgC5gO.js} +15 -2
  3. package/dist/acp-jsonrpc-BbBgC5gO.js.map +1 -0
  4. package/dist/cli-idpWyCOs.js +176 -0
  5. package/dist/cli-idpWyCOs.js.map +1 -0
  6. package/dist/cli.d.ts +1 -118
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +235 -336
  9. package/dist/cli.js.map +1 -1
  10. package/dist/flags-CCcX9fZj.js +194 -0
  11. package/dist/flags-CCcX9fZj.js.map +1 -0
  12. package/dist/flows-BL1tSvZT.js +1551 -0
  13. package/dist/flows-BL1tSvZT.js.map +1 -0
  14. package/dist/flows.d.ts +292 -0
  15. package/dist/flows.d.ts.map +1 -0
  16. package/dist/flows.js +2 -0
  17. package/dist/{output-BmkPP7qE.js → output-Du3m6oPQ.js} +139 -30
  18. package/dist/output-Du3m6oPQ.js.map +1 -0
  19. package/dist/{output-render-DEAaMxg8.js → output-render-Bz58qaQn.js} +10 -10
  20. package/dist/output-render-Bz58qaQn.js.map +1 -0
  21. package/dist/{queue-ipc-EQLpBMKv.js → queue-ipc-CE8_QGX3.js} +258 -95
  22. package/dist/queue-ipc-CE8_QGX3.js.map +1 -0
  23. package/dist/{session-C2Q8ktsN.js → session-RO_LZUnv.js} +687 -138
  24. package/dist/session-RO_LZUnv.js.map +1 -0
  25. package/dist/types-CeRKmEQ1.d.ts +137 -0
  26. package/dist/types-CeRKmEQ1.d.ts.map +1 -0
  27. package/package.json +44 -16
  28. package/skills/acpx/SKILL.md +22 -5
  29. package/dist/acp-jsonrpc-BNHXq7qK.js.map +0 -1
  30. package/dist/output-BmkPP7qE.js.map +0 -1
  31. package/dist/output-render-DEAaMxg8.js.map +0 -1
  32. package/dist/queue-ipc-EQLpBMKv.js.map +0 -1
  33. package/dist/runtime-session-id-C544sPPL.js +0 -31
  34. package/dist/runtime-session-id-C544sPPL.js.map +0 -1
  35. package/dist/session-C2Q8ktsN.js.map +0 -1
@@ -1,9 +1,8 @@
1
- import { t as __exportAll } from "./rolldown-runtime-CiIaOW0V.js";
2
- import { t as isAcpJsonRpcMessage } from "./acp-jsonrpc-BNHXq7qK.js";
1
+ import { n as isAcpJsonRpcMessage } from "./acp-jsonrpc-BbBgC5gO.js";
3
2
  import fs from "node:fs/promises";
4
3
  import path from "node:path";
5
- import { createHash, randomUUID } from "node:crypto";
6
4
  import os from "node:os";
5
+ import { createHash, randomUUID } from "node:crypto";
7
6
  import net from "node:net";
8
7
  //#region src/acp-error-shapes.ts
9
8
  const RESOURCE_NOT_FOUND_ACP_CODES = new Set([-32001, -32002]);
@@ -52,10 +51,11 @@ function formatUnknownErrorMessage(error) {
52
51
  }
53
52
  return String(error);
54
53
  }
54
+ const SESSION_NOT_FOUND_PATTERN = /session\s+["'\w-]+\s+not found/i;
55
55
  function isSessionNotFoundText(value) {
56
56
  if (typeof value !== "string") return false;
57
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");
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") || SESSION_NOT_FOUND_PATTERN.test(value);
59
59
  }
60
60
  function hasSessionNotFoundHint(value, depth = 0) {
61
61
  if (depth > 4) return false;
@@ -112,6 +112,33 @@ var AgentSpawnError = class extends AcpxOperationalError {
112
112
  this.agentCommand = agentCommand;
113
113
  }
114
114
  };
115
+ var AgentDisconnectedError = class extends AcpxOperationalError {
116
+ reason;
117
+ exitCode;
118
+ signal;
119
+ constructor(reason, exitCode, signal, options) {
120
+ super(`ACP agent disconnected during request (${reason}, exit=${exitCode ?? "null"}, signal=${signal ?? "null"})`, {
121
+ outputCode: "RUNTIME",
122
+ detailCode: "AGENT_DISCONNECTED",
123
+ origin: "acp",
124
+ ...options
125
+ });
126
+ this.reason = reason;
127
+ this.exitCode = exitCode;
128
+ this.signal = signal;
129
+ }
130
+ };
131
+ var SessionResumeRequiredError = class extends AcpxOperationalError {
132
+ constructor(message, options) {
133
+ super(message, {
134
+ outputCode: "RUNTIME",
135
+ detailCode: "SESSION_RESUME_REQUIRED",
136
+ origin: "acp",
137
+ retryable: true,
138
+ ...options
139
+ });
140
+ }
141
+ };
115
142
  var GeminiAcpStartupTimeoutError = class extends AcpxOperationalError {
116
143
  constructor(message, options) {
117
144
  super(message, {
@@ -132,6 +159,16 @@ var SessionModeReplayError = class extends AcpxOperationalError {
132
159
  });
133
160
  }
134
161
  };
162
+ var SessionModelReplayError = class extends AcpxOperationalError {
163
+ constructor(message, options) {
164
+ super(message, {
165
+ outputCode: "RUNTIME",
166
+ detailCode: "SESSION_MODEL_REPLAY_FAILED",
167
+ origin: "acp",
168
+ ...options
169
+ });
170
+ }
171
+ };
135
172
  var ClaudeAcpSessionCreateTimeoutError = class extends AcpxOperationalError {
136
173
  constructor(message, options) {
137
174
  super(message, {
@@ -286,6 +323,34 @@ function promptToDisplayText(prompt) {
286
323
  }).filter((entry) => entry.trim().length > 0).join("\n\n").trim();
287
324
  }
288
325
  //#endregion
326
+ //#region src/agent-session-id.ts
327
+ const AGENT_SESSION_ID_META_KEYS = ["agentSessionId", "sessionId"];
328
+ function normalizeAgentSessionId(value) {
329
+ if (typeof value !== "string") return;
330
+ const trimmed = value.trim();
331
+ return trimmed.length > 0 ? trimmed : void 0;
332
+ }
333
+ function asMetaRecord(meta) {
334
+ if (!meta || typeof meta !== "object" || Array.isArray(meta)) return;
335
+ return meta;
336
+ }
337
+ function extractAgentSessionId(meta) {
338
+ const record = asMetaRecord(meta);
339
+ if (!record) return;
340
+ for (const key of AGENT_SESSION_ID_META_KEYS) {
341
+ const normalized = normalizeAgentSessionId(record[key]);
342
+ if (normalized) return normalized;
343
+ }
344
+ }
345
+ //#endregion
346
+ //#region src/runtime-session-id.ts
347
+ function normalizeRuntimeSessionId(value) {
348
+ return normalizeAgentSessionId(value);
349
+ }
350
+ function extractRuntimeSessionId(meta) {
351
+ return extractAgentSessionId(meta);
352
+ }
353
+ //#endregion
289
354
  //#region src/types.ts
290
355
  const EXIT_CODES = {
291
356
  SUCCESS: 0,
@@ -404,6 +469,24 @@ function normalizeOutputError(error, options = {}) {
404
469
  acp
405
470
  };
406
471
  }
472
+ /**
473
+ * Returns true when an error from `client.prompt()` looks transient and
474
+ * can reasonably be retried (e.g. model-API 400/500, network hiccups that
475
+ * surface as ACP internal errors).
476
+ *
477
+ * Errors that are definitively non-recoverable (auth, missing session,
478
+ * invalid params, timeout, permission) return false.
479
+ */
480
+ function isRetryablePromptError(error) {
481
+ if (error instanceof PermissionDeniedError || error instanceof PermissionPromptUnavailableError) return false;
482
+ if (isTimeoutLike(error) || isNoSessionLike(error) || isUsageLike(error)) return false;
483
+ const acp = extractAcpError(error);
484
+ if (!acp) return false;
485
+ if (acp.code === -32001 || acp.code === -32002) return false;
486
+ if (isAcpAuthRequiredPayload(acp)) return false;
487
+ if (acp.code === -32601 || acp.code === -32602) return false;
488
+ return acp.code === -32603 || acp.code === -32700;
489
+ }
407
490
  function exitCodeForOutputErrorCode(code) {
408
491
  switch (code) {
409
492
  case "USAGE": return EXIT_CODES.USAGE;
@@ -690,6 +773,96 @@ async function waitMs(ms) {
690
773
  });
691
774
  }
692
775
  //#endregion
776
+ //#region src/queue-ipc-transport.ts
777
+ const QUEUE_CONNECT_ATTEMPTS = 40;
778
+ const SOCKET_CONNECTION_TIMEOUT_MS = 5e3;
779
+ function shouldRetryQueueConnect(error) {
780
+ const code = error.code;
781
+ return code === "ENOENT" || code === "ECONNREFUSED";
782
+ }
783
+ async function connectToSocket(socketPath, timeoutMs = SOCKET_CONNECTION_TIMEOUT_MS) {
784
+ return await new Promise((resolve, reject) => {
785
+ const socket = net.createConnection(socketPath);
786
+ let settled = false;
787
+ const timeout = setTimeout(() => {
788
+ if (settled) return;
789
+ settled = true;
790
+ socket.destroy();
791
+ reject(/* @__PURE__ */ new Error(`Connection to ${socketPath} timed out after ${timeoutMs}ms`));
792
+ }, timeoutMs);
793
+ const onConnect = () => {
794
+ if (settled) return;
795
+ settled = true;
796
+ clearTimeout(timeout);
797
+ socket.off("error", onError);
798
+ resolve(socket);
799
+ };
800
+ const onError = (error) => {
801
+ if (settled) return;
802
+ settled = true;
803
+ clearTimeout(timeout);
804
+ socket.off("connect", onConnect);
805
+ reject(error);
806
+ };
807
+ socket.once("connect", onConnect);
808
+ socket.once("error", onError);
809
+ });
810
+ }
811
+ async function connectToQueueOwner(owner, maxAttempts = QUEUE_CONNECT_ATTEMPTS) {
812
+ let lastError;
813
+ const attempts = Math.max(1, Math.trunc(maxAttempts));
814
+ for (let attempt = 0; attempt < attempts; attempt += 1) try {
815
+ return await measurePerf("queue.connect", async () => await connectToSocket(owner.socketPath));
816
+ } catch (error) {
817
+ lastError = error;
818
+ if (!shouldRetryQueueConnect(error)) throw error;
819
+ await waitMs(50);
820
+ }
821
+ if (lastError && !shouldRetryQueueConnect(lastError)) throw lastError;
822
+ }
823
+ //#endregion
824
+ //#region src/queue-ipc-health.ts
825
+ async function probeQueueOwnerHealth(sessionId) {
826
+ const ownerRecord = await readQueueOwnerRecord(sessionId);
827
+ if (!ownerRecord) return {
828
+ sessionId,
829
+ hasLease: false,
830
+ healthy: false,
831
+ socketReachable: false,
832
+ pidAlive: false
833
+ };
834
+ const owner = await readQueueOwnerStatus(sessionId);
835
+ if (!owner) return {
836
+ sessionId,
837
+ hasLease: false,
838
+ healthy: false,
839
+ socketReachable: false,
840
+ pidAlive: false
841
+ };
842
+ const pidAlive = owner.alive;
843
+ let socketReachable = false;
844
+ try {
845
+ const socket = await connectToQueueOwner(ownerRecord, 2);
846
+ if (socket) {
847
+ socketReachable = true;
848
+ if (!socket.destroyed) socket.end();
849
+ }
850
+ } catch {
851
+ socketReachable = false;
852
+ }
853
+ return {
854
+ sessionId,
855
+ hasLease: true,
856
+ healthy: socketReachable,
857
+ socketReachable,
858
+ pidAlive,
859
+ pid: owner.pid,
860
+ socketPath: owner.socketPath,
861
+ ownerGeneration: owner.ownerGeneration,
862
+ queueDepth: owner.queueDepth
863
+ };
864
+ }
865
+ //#endregion
693
866
  //#region src/queue-messages.ts
694
867
  function asRecord(value) {
695
868
  if (!value || typeof value !== "object" || Array.isArray(value)) return;
@@ -698,6 +871,9 @@ function asRecord(value) {
698
871
  function isPermissionMode(value) {
699
872
  return value === "approve-all" || value === "approve-reads" || value === "deny-all";
700
873
  }
874
+ function isSessionResumePolicy(value) {
875
+ return value === "allow-new" || value === "same-session-only";
876
+ }
701
877
  function isNonInteractivePermissionPolicy(value) {
702
878
  return value === "deny" || value === "fail";
703
879
  }
@@ -732,10 +908,11 @@ function parseQueueRequest(raw) {
732
908
  const timeoutRaw = request.timeoutMs;
733
909
  const timeoutMs = typeof timeoutRaw === "number" && Number.isFinite(timeoutRaw) && timeoutRaw > 0 ? Math.round(timeoutRaw) : void 0;
734
910
  if (request.type === "submit_prompt") {
911
+ const resumePolicy = request.resumePolicy == null ? void 0 : isSessionResumePolicy(request.resumePolicy) ? request.resumePolicy : null;
735
912
  const nonInteractivePermissions = request.nonInteractivePermissions == null ? void 0 : isNonInteractivePermissionPolicy(request.nonInteractivePermissions) ? request.nonInteractivePermissions : null;
736
913
  const suppressSdkConsoleErrors = request.suppressSdkConsoleErrors == null ? void 0 : typeof request.suppressSdkConsoleErrors === "boolean" ? request.suppressSdkConsoleErrors : null;
737
914
  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;
915
+ if (typeof request.message !== "string" || !isPermissionMode(request.permissionMode) || resumePolicy === null || prompt === null || nonInteractivePermissions === null || suppressSdkConsoleErrors === null || typeof request.waitForCompletion !== "boolean") return null;
739
916
  return {
740
917
  type: "submit_prompt",
741
918
  requestId: request.requestId,
@@ -743,6 +920,7 @@ function parseQueueRequest(raw) {
743
920
  message: request.message,
744
921
  prompt: prompt ?? textPrompt(request.message),
745
922
  permissionMode: request.permissionMode,
923
+ ...resumePolicy !== void 0 ? { resumePolicy } : {},
746
924
  nonInteractivePermissions,
747
925
  timeoutMs,
748
926
  ...suppressSdkConsoleErrors !== void 0 ? { suppressSdkConsoleErrors } : {},
@@ -764,6 +942,16 @@ function parseQueueRequest(raw) {
764
942
  timeoutMs
765
943
  };
766
944
  }
945
+ if (request.type === "set_model") {
946
+ if (typeof request.modelId !== "string" || request.modelId.trim().length === 0) return null;
947
+ return {
948
+ type: "set_model",
949
+ requestId: request.requestId,
950
+ ownerGeneration,
951
+ modelId: request.modelId,
952
+ timeoutMs
953
+ };
954
+ }
767
955
  if (request.type === "set_config_option") {
768
956
  if (typeof request.configId !== "string" || request.configId.trim().length === 0 || typeof request.value !== "string" || request.value.trim().length === 0) return null;
769
957
  return {
@@ -836,6 +1024,15 @@ function parseQueueOwnerMessage(raw) {
836
1024
  modeId: message.modeId
837
1025
  };
838
1026
  }
1027
+ if (message.type === "set_model_result") {
1028
+ if (typeof message.modelId !== "string") return null;
1029
+ return {
1030
+ type: "set_model_result",
1031
+ requestId: message.requestId,
1032
+ ownerGeneration,
1033
+ modelId: message.modelId
1034
+ };
1035
+ }
839
1036
  if (message.type === "set_config_option_result") {
840
1037
  const response = asRecord(message.response);
841
1038
  if (!response || !Array.isArray(response.configOptions)) return null;
@@ -1084,6 +1281,21 @@ var SessionQueueOwner = class SessionQueueOwner {
1084
1281
  });
1085
1282
  return;
1086
1283
  }
1284
+ if (request.type === "set_model") {
1285
+ this.handleControlRequest({
1286
+ socket,
1287
+ requestId: request.requestId,
1288
+ run: async () => {
1289
+ await this.controlHandlers.setSessionModel(request.modelId, request.timeoutMs);
1290
+ return {
1291
+ type: "set_model_result",
1292
+ requestId: request.requestId,
1293
+ modelId: request.modelId
1294
+ };
1295
+ }
1296
+ });
1297
+ return;
1298
+ }
1087
1299
  if (request.type === "set_config_option") {
1088
1300
  this.handleControlRequest({
1089
1301
  socket,
@@ -1101,6 +1313,7 @@ var SessionQueueOwner = class SessionQueueOwner {
1101
1313
  message: request.message,
1102
1314
  prompt: request.prompt ?? textPrompt(request.message),
1103
1315
  permissionMode: request.permissionMode,
1316
+ resumePolicy: request.resumePolicy,
1104
1317
  nonInteractivePermissions: request.nonInteractivePermissions,
1105
1318
  timeoutMs: request.timeoutMs,
1106
1319
  suppressSdkConsoleErrors: request.suppressSdkConsoleErrors,
@@ -1139,23 +1352,7 @@ var SessionQueueOwner = class SessionQueueOwner {
1139
1352
  };
1140
1353
  //#endregion
1141
1354
  //#region src/queue-ipc.ts
1142
- var queue_ipc_exports = /* @__PURE__ */ __exportAll({
1143
- QUEUE_CONNECT_RETRY_MS: () => 50,
1144
- SessionQueueOwner: () => SessionQueueOwner,
1145
- isProcessAlive: () => isProcessAlive,
1146
- probeQueueOwnerHealth: () => probeQueueOwnerHealth,
1147
- releaseQueueOwnerLease: () => releaseQueueOwnerLease,
1148
- terminateProcess: () => terminateProcess,
1149
- terminateQueueOwnerForSession: () => terminateQueueOwnerForSession,
1150
- tryAcquireQueueOwnerLease: () => tryAcquireQueueOwnerLease,
1151
- tryCancelOnRunningOwner: () => tryCancelOnRunningOwner,
1152
- trySetConfigOptionOnRunningOwner: () => trySetConfigOptionOnRunningOwner,
1153
- trySetModeOnRunningOwner: () => trySetModeOnRunningOwner,
1154
- trySubmitToRunningOwner: () => trySubmitToRunningOwner,
1155
- waitMs: () => waitMs
1156
- });
1157
- const QUEUE_CONNECT_ATTEMPTS = 40;
1158
- const QUEUE_CONNECT_RETRY_MS = 50;
1355
+ const MAX_MESSAGE_BUFFER_SIZE = 10 * 1024 * 1024;
1159
1356
  const STALE_OWNER_PROTOCOL_DETAIL_CODES = new Set(["QUEUE_PROTOCOL_MALFORMED_MESSAGE", "QUEUE_PROTOCOL_UNEXPECTED_RESPONSE"]);
1160
1357
  async function maybeRecoverStaleOwnerAfterProtocolMismatch(params) {
1161
1358
  if (!(params.error instanceof QueueProtocolError)) return false;
@@ -1166,77 +1363,6 @@ async function maybeRecoverStaleOwnerAfterProtocolMismatch(params) {
1166
1363
  if (params.verbose) process.stderr.write(`[acpx] dropped stale queue owner metadata after protocol mismatch for session ${params.sessionId} (${detailCode})\n`);
1167
1364
  return true;
1168
1365
  }
1169
- function shouldRetryQueueConnect(error) {
1170
- const code = error.code;
1171
- return code === "ENOENT" || code === "ECONNREFUSED";
1172
- }
1173
- async function connectToSocket(socketPath) {
1174
- return await new Promise((resolve, reject) => {
1175
- const socket = net.createConnection(socketPath);
1176
- const onConnect = () => {
1177
- socket.off("error", onError);
1178
- resolve(socket);
1179
- };
1180
- const onError = (error) => {
1181
- socket.off("connect", onConnect);
1182
- reject(error);
1183
- };
1184
- socket.once("connect", onConnect);
1185
- socket.once("error", onError);
1186
- });
1187
- }
1188
- async function connectToQueueOwner(owner, maxAttempts = QUEUE_CONNECT_ATTEMPTS) {
1189
- let lastError;
1190
- const attempts = Math.max(1, Math.trunc(maxAttempts));
1191
- for (let attempt = 0; attempt < attempts; attempt += 1) try {
1192
- return await measurePerf("queue.connect", async () => await connectToSocket(owner.socketPath));
1193
- } catch (error) {
1194
- lastError = error;
1195
- if (!shouldRetryQueueConnect(error)) throw error;
1196
- await waitMs(50);
1197
- }
1198
- if (lastError && !shouldRetryQueueConnect(lastError)) throw lastError;
1199
- }
1200
- async function probeQueueOwnerHealth(sessionId) {
1201
- const ownerRecord = await readQueueOwnerRecord(sessionId);
1202
- if (!ownerRecord) return {
1203
- sessionId,
1204
- hasLease: false,
1205
- healthy: false,
1206
- socketReachable: false,
1207
- pidAlive: false
1208
- };
1209
- const owner = await readQueueOwnerStatus(sessionId);
1210
- if (!owner) return {
1211
- sessionId,
1212
- hasLease: false,
1213
- healthy: false,
1214
- socketReachable: false,
1215
- pidAlive: false
1216
- };
1217
- const pidAlive = owner.alive;
1218
- let socketReachable = false;
1219
- try {
1220
- const socket = await connectToQueueOwner(ownerRecord, 2);
1221
- if (socket) {
1222
- socketReachable = true;
1223
- if (!socket.destroyed) socket.end();
1224
- }
1225
- } catch {
1226
- socketReachable = false;
1227
- }
1228
- return {
1229
- sessionId,
1230
- hasLease: true,
1231
- healthy: socketReachable,
1232
- socketReachable,
1233
- pidAlive,
1234
- pid: owner.pid,
1235
- socketPath: owner.socketPath,
1236
- ownerGeneration: owner.ownerGeneration,
1237
- queueDepth: owner.queueDepth
1238
- };
1239
- }
1240
1366
  function assertOwnerGeneration(owner, message) {
1241
1367
  if (owner.ownerGeneration !== void 0 && message.ownerGeneration !== void 0 && message.ownerGeneration !== owner.ownerGeneration) throw new QueueProtocolError("Queue owner returned mismatched generation", {
1242
1368
  detailCode: "QUEUE_OWNER_GENERATION_MISMATCH",
@@ -1313,6 +1439,11 @@ async function runQueueOwnerRequest(options) {
1313
1439
  };
1314
1440
  socket.on("data", (chunk) => {
1315
1441
  buffer += chunk;
1442
+ if (buffer.length > 10485760) {
1443
+ socket.destroy();
1444
+ finishReject(/* @__PURE__ */ new Error(`Message buffer exceeded ${MAX_MESSAGE_BUFFER_SIZE} bytes`));
1445
+ return;
1446
+ }
1316
1447
  let index = buffer.indexOf("\n");
1317
1448
  while (index >= 0) {
1318
1449
  const line = buffer.slice(0, index).trim();
@@ -1340,6 +1471,7 @@ async function submitToQueueOwner(owner, options) {
1340
1471
  message: options.message,
1341
1472
  prompt: options.prompt,
1342
1473
  permissionMode: options.permissionMode,
1474
+ resumePolicy: options.resumePolicy,
1343
1475
  nonInteractivePermissions: options.nonInteractivePermissions,
1344
1476
  timeoutMs: options.timeoutMs,
1345
1477
  suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
@@ -1512,6 +1644,23 @@ async function submitSetModeToQueueOwner(owner, modeId, timeoutMs) {
1512
1644
  });
1513
1645
  return true;
1514
1646
  }
1647
+ async function submitSetModelToQueueOwner(owner, modelId, timeoutMs) {
1648
+ const request = {
1649
+ type: "set_model",
1650
+ requestId: randomUUID(),
1651
+ ownerGeneration: owner.ownerGeneration,
1652
+ modelId,
1653
+ timeoutMs
1654
+ };
1655
+ const response = await submitControlToQueueOwner(owner, request, (message) => message.type === "set_model_result");
1656
+ if (!response) return;
1657
+ if (response.requestId !== request.requestId) throw new QueueProtocolError("Queue owner returned mismatched set_model response", {
1658
+ detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
1659
+ origin: "queue",
1660
+ retryable: true
1661
+ });
1662
+ return true;
1663
+ }
1515
1664
  async function submitSetConfigOptionToQueueOwner(owner, configId, value, timeoutMs) {
1516
1665
  const request = {
1517
1666
  type: "set_config_option",
@@ -1585,6 +1734,20 @@ async function trySetModeOnRunningOwner(sessionId, modeId, timeoutMs, verbose) {
1585
1734
  retryable: true
1586
1735
  });
1587
1736
  }
1737
+ async function trySetModelOnRunningOwner(sessionId, modelId, timeoutMs, verbose) {
1738
+ const owner = await readQueueOwnerRecord(sessionId);
1739
+ if (!owner) return;
1740
+ if (await submitSetModelToQueueOwner(owner, modelId, timeoutMs)) {
1741
+ if (verbose) process.stderr.write(`[acpx] requested session/set_model on owner pid ${owner.pid} for session ${sessionId}\n`);
1742
+ return true;
1743
+ }
1744
+ if (!(await probeQueueOwnerHealth(sessionId)).hasLease) return;
1745
+ throw new QueueConnectionError("Session queue owner is running but not accepting set_model requests", {
1746
+ detailCode: "QUEUE_NOT_ACCEPTING_REQUESTS",
1747
+ origin: "queue",
1748
+ retryable: true
1749
+ });
1750
+ }
1588
1751
  async function trySetConfigOptionOnRunningOwner(sessionId, configId, value, timeoutMs, verbose) {
1589
1752
  const owner = await readQueueOwnerRecord(sessionId);
1590
1753
  if (!owner) return;
@@ -1601,6 +1764,6 @@ async function trySetConfigOptionOnRunningOwner(sessionId, configId, value, time
1601
1764
  });
1602
1765
  }
1603
1766
  //#endregion
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 };
1767
+ export { extractAcpError as $, OUTPUT_FORMATS as A, AgentSpawnError as B, formatErrorMessage as C, AUTH_POLICIES as D, normalizeOutputError as E, mergePromptSourceWithText as F, PermissionDeniedError as G, ClaudeAcpSessionCreateTimeoutError as H, parsePromptSource as I, SessionModeReplayError as J, PermissionPromptUnavailableError as K, promptToDisplayText as L, extractRuntimeSessionId as M, normalizeRuntimeSessionId as N, EXIT_CODES as O, PromptInputValidationError as P, SessionResumeRequiredError as Q, textPrompt as R, exitCodeForOutputErrorCode as S, isRetryablePromptError as T, CopilotAcpUnsupportedError as U, AuthPolicyError as V, GeminiAcpStartupTimeoutError as W, SessionNotFoundError as X, SessionModelReplayError as Y, SessionResolutionError as Z, incrementPerfCounter as _, trySubmitToRunningOwner as a, setPerfGauge as b, isProcessAlive as c, terminateProcess as d, isAcpResourceNotFoundError as et, terminateQueueOwnerForSession as f, getPerfMetricsSnapshot as g, formatPerfMetric as h, trySetModelOnRunningOwner as i, SESSION_RECORD_SCHEMA as j, NON_INTERACTIVE_PERMISSION_POLICIES as k, refreshQueueOwnerLease as l, waitMs as m, trySetConfigOptionOnRunningOwner as n, SessionQueueOwner as o, tryAcquireQueueOwnerLease as p, QueueConnectionError as q, trySetModeOnRunningOwner as r, probeQueueOwnerHealth as s, tryCancelOnRunningOwner as t, releaseQueueOwnerLease as u, measurePerf as v, isAcpQueryClosedBeforeResponseError as w, startPerfTimer as x, resetPerfMetrics as y, AgentDisconnectedError as z };
1605
1768
 
1606
- //# sourceMappingURL=queue-ipc-EQLpBMKv.js.map
1769
+ //# sourceMappingURL=queue-ipc-CE8_QGX3.js.map