acpx 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -16
- package/dist/{acp-jsonrpc-BNHXq7qK.js → acp-jsonrpc-C7pPk9Tw.js} +1 -1
- package/dist/{acp-jsonrpc-BNHXq7qK.js.map → acp-jsonrpc-C7pPk9Tw.js.map} +1 -1
- package/dist/cli-5s-E-Y99.js +176 -0
- package/dist/cli-5s-E-Y99.js.map +1 -0
- package/dist/cli.d.ts +1 -118
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +235 -331
- package/dist/cli.js.map +1 -1
- package/dist/flags-BkWInxAq.js +194 -0
- package/dist/flags-BkWInxAq.js.map +1 -0
- package/dist/flows-DnIYoHI1.js +1551 -0
- package/dist/flows-DnIYoHI1.js.map +1 -0
- package/dist/flows.d.ts +292 -0
- package/dist/flows.d.ts.map +1 -0
- package/dist/flows.js +2 -0
- package/dist/{output-BmkPP7qE.js → output-C58ukIo3.js} +137 -14
- package/dist/output-C58ukIo3.js.map +1 -0
- package/dist/{output-render-DEAaMxg8.js → output-render-C7w9NZ2H.js} +10 -10
- package/dist/output-render-C7w9NZ2H.js.map +1 -0
- package/dist/{queue-ipc-EQLpBMKv.js → queue-ipc-CgWf63GN.js} +258 -95
- package/dist/queue-ipc-CgWf63GN.js.map +1 -0
- package/dist/{session-C2Q8ktsN.js → session-BtpTC2pM.js} +687 -138
- package/dist/session-BtpTC2pM.js.map +1 -0
- package/dist/types-CeRKmEQ1.d.ts +137 -0
- package/dist/types-CeRKmEQ1.d.ts.map +1 -0
- package/package.json +36 -16
- package/skills/acpx/SKILL.md +23 -6
- package/dist/output-BmkPP7qE.js.map +0 -1
- package/dist/output-render-DEAaMxg8.js.map +0 -1
- package/dist/queue-ipc-EQLpBMKv.js.map +0 -1
- package/dist/runtime-session-id-C544sPPL.js +0 -31
- package/dist/runtime-session-id-C544sPPL.js.map +0 -1
- package/dist/session-C2Q8ktsN.js.map +0 -1
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import { t as isAcpJsonRpcMessage } from "./acp-jsonrpc-BNHXq7qK.js";
|
|
1
|
+
import { t as isAcpJsonRpcMessage } from "./acp-jsonrpc-C7pPk9Tw.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
|
-
|
|
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,
|
|
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-
|
|
1769
|
+
//# sourceMappingURL=queue-ipc-CgWf63GN.js.map
|