acpx 0.7.0 → 0.9.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 +14 -6
- package/dist/{cli-T-Z-9x6a.js → cli-Bf3yjqzE.js} +35 -10
- package/dist/cli-Bf3yjqzE.js.map +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +724 -241
- package/dist/cli.js.map +1 -1
- package/dist/{client-COPilhO_.d.ts → client-BssohYqM.d.ts} +35 -4
- package/dist/client-BssohYqM.d.ts.map +1 -0
- package/dist/flags-C-rwARqg.js +260 -0
- package/dist/flags-C-rwARqg.js.map +1 -0
- package/dist/{flows-CF8w1rPI.js → flows-WLs26_5Y.js} +405 -337
- package/dist/flows-WLs26_5Y.js.map +1 -0
- package/dist/flows.d.ts +23 -2
- package/dist/flows.d.ts.map +1 -1
- package/dist/flows.js +1 -1
- package/dist/{prompt-turn-CVPMWdj1.js → live-checkpoint-D5d-K9s1.js} +2487 -609
- package/dist/live-checkpoint-D5d-K9s1.js.map +1 -0
- package/dist/output-DPg20dvn.js +4146 -0
- package/dist/output-DPg20dvn.js.map +1 -0
- package/dist/runtime.d.ts +56 -4
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +676 -393
- package/dist/runtime.js.map +1 -1
- package/dist/{types-CVBeQyi3.d.ts → session-options-CFudjdkU.d.ts} +62 -3
- package/dist/session-options-CFudjdkU.d.ts.map +1 -0
- package/package.json +30 -25
- package/skills/acpx/SKILL.md +211 -13
- package/dist/cli-T-Z-9x6a.js.map +0 -1
- package/dist/client-COPilhO_.d.ts.map +0 -1
- package/dist/flags-Dj-IXgo9.js +0 -163
- package/dist/flags-Dj-IXgo9.js.map +0 -1
- package/dist/flows-CF8w1rPI.js.map +0 -1
- package/dist/ipc-ABXlXzGP.js +0 -1290
- package/dist/ipc-ABXlXzGP.js.map +0 -1
- package/dist/jsonrpc-DSxh2w5R.js +0 -68
- package/dist/jsonrpc-DSxh2w5R.js.map +0 -1
- package/dist/output-DmHvT8vm.js +0 -807
- package/dist/output-DmHvT8vm.js.map +0 -1
- package/dist/perf-metrics-C2pXfxvR.js +0 -598
- package/dist/perf-metrics-C2pXfxvR.js.map +0 -1
- package/dist/prompt-turn-CVPMWdj1.js.map +0 -1
- package/dist/render-N5YwotCy.js +0 -172
- package/dist/render-N5YwotCy.js.map +0 -1
- package/dist/rolldown-runtime-CiIaOW0V.js +0 -13
- package/dist/session-CDaQe6BH.js +0 -1538
- package/dist/session-CDaQe6BH.js.map +0 -1
- package/dist/session-options-pCbHn_n7.d.ts +0 -13
- package/dist/session-options-pCbHn_n7.d.ts.map +0 -1
- package/dist/types-CVBeQyi3.d.ts.map +0 -1
package/dist/ipc-ABXlXzGP.js
DELETED
|
@@ -1,1290 +0,0 @@
|
|
|
1
|
-
import { H as QueueConnectionError, O as OUTPUT_ERROR_CODES, U as QueueProtocolError, a as recordPerfDuration, f as isPromptInput, g as textPrompt, i as measurePerf, k as OUTPUT_ERROR_ORIGINS, r as incrementPerfCounter, w as toAcpErrorPayload, x as normalizeOutputError } from "./perf-metrics-C2pXfxvR.js";
|
|
2
|
-
import { n as isAcpJsonRpcMessage } from "./jsonrpc-DSxh2w5R.js";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import fs from "node:fs/promises";
|
|
5
|
-
import os from "node:os";
|
|
6
|
-
import { createHash, randomInt, randomUUID } from "node:crypto";
|
|
7
|
-
import net from "node:net";
|
|
8
|
-
//#region src/cli/queue/paths.ts
|
|
9
|
-
function shortHash(value, length) {
|
|
10
|
-
return createHash("sha256").update(value).digest("hex").slice(0, length);
|
|
11
|
-
}
|
|
12
|
-
function queueKeyForSession(sessionId) {
|
|
13
|
-
return shortHash(sessionId, 24);
|
|
14
|
-
}
|
|
15
|
-
function queueBaseDir(homeDir = os.homedir()) {
|
|
16
|
-
return path.join(homeDir, ".acpx", "queues");
|
|
17
|
-
}
|
|
18
|
-
function queueSocketBaseDir(homeDir = os.homedir()) {
|
|
19
|
-
if (process.platform === "win32") return;
|
|
20
|
-
return path.join("/tmp", `acpx-${shortHash(homeDir, 10)}`);
|
|
21
|
-
}
|
|
22
|
-
function queueLockFilePath(sessionId, homeDir = os.homedir()) {
|
|
23
|
-
return path.join(queueBaseDir(homeDir), `${queueKeyForSession(sessionId)}.lock`);
|
|
24
|
-
}
|
|
25
|
-
function queueSocketPath(sessionId, homeDir = os.homedir()) {
|
|
26
|
-
const key = queueKeyForSession(sessionId);
|
|
27
|
-
if (process.platform === "win32") return `\\\\.\\pipe\\acpx-${key}`;
|
|
28
|
-
return path.join(queueSocketBaseDir(homeDir) ?? "/tmp", `${key}.sock`);
|
|
29
|
-
}
|
|
30
|
-
//#endregion
|
|
31
|
-
//#region src/cli/queue/lease-store.ts
|
|
32
|
-
const PROCESS_EXIT_GRACE_MS = 1500;
|
|
33
|
-
const PROCESS_POLL_MS = 50;
|
|
34
|
-
const QUEUE_OWNER_STALE_HEARTBEAT_MS = 15e3;
|
|
35
|
-
function parseQueueOwnerRecord(raw) {
|
|
36
|
-
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
37
|
-
const record = raw;
|
|
38
|
-
if (!Number.isInteger(record.pid) || record.pid <= 0 || typeof record.sessionId !== "string" || typeof record.socketPath !== "string" || typeof record.createdAt !== "string" || typeof record.heartbeatAt !== "string" || !Number.isInteger(record.ownerGeneration) || record.ownerGeneration <= 0 || !Number.isInteger(record.queueDepth) || record.queueDepth < 0) return null;
|
|
39
|
-
return {
|
|
40
|
-
pid: record.pid,
|
|
41
|
-
sessionId: record.sessionId,
|
|
42
|
-
socketPath: record.socketPath,
|
|
43
|
-
createdAt: record.createdAt,
|
|
44
|
-
heartbeatAt: record.heartbeatAt,
|
|
45
|
-
ownerGeneration: record.ownerGeneration,
|
|
46
|
-
queueDepth: record.queueDepth
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
function createOwnerGeneration() {
|
|
50
|
-
return randomInt(1, 2 ** 48);
|
|
51
|
-
}
|
|
52
|
-
function nowIso() {
|
|
53
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
54
|
-
}
|
|
55
|
-
function isQueueOwnerHeartbeatStale(owner) {
|
|
56
|
-
const heartbeatMs = Date.parse(owner.heartbeatAt);
|
|
57
|
-
if (!Number.isFinite(heartbeatMs)) return true;
|
|
58
|
-
return Date.now() - heartbeatMs > QUEUE_OWNER_STALE_HEARTBEAT_MS;
|
|
59
|
-
}
|
|
60
|
-
async function ensureQueueDir() {
|
|
61
|
-
const baseDir = queueBaseDir();
|
|
62
|
-
await fs.mkdir(baseDir, {
|
|
63
|
-
recursive: true,
|
|
64
|
-
mode: 448
|
|
65
|
-
});
|
|
66
|
-
await fs.chmod(baseDir, 448);
|
|
67
|
-
const socketDir = queueSocketBaseDir();
|
|
68
|
-
if (socketDir) {
|
|
69
|
-
await fs.mkdir(socketDir, {
|
|
70
|
-
recursive: true,
|
|
71
|
-
mode: 448
|
|
72
|
-
});
|
|
73
|
-
await fs.chmod(socketDir, 448);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
async function removeSocketFile(socketPath) {
|
|
77
|
-
if (process.platform === "win32") return;
|
|
78
|
-
try {
|
|
79
|
-
await fs.unlink(socketPath);
|
|
80
|
-
} catch (error) {
|
|
81
|
-
if (error.code !== "ENOENT") throw error;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
async function waitForProcessExit(pid, timeoutMs) {
|
|
85
|
-
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
86
|
-
while (Date.now() <= deadline) {
|
|
87
|
-
if (!isProcessAlive(pid)) return true;
|
|
88
|
-
await waitMs(PROCESS_POLL_MS);
|
|
89
|
-
}
|
|
90
|
-
return !isProcessAlive(pid);
|
|
91
|
-
}
|
|
92
|
-
async function cleanupStaleQueueOwner(sessionId, owner) {
|
|
93
|
-
const lockPath = queueLockFilePath(sessionId);
|
|
94
|
-
await removeSocketFile(owner?.socketPath ?? queueSocketPath(sessionId)).catch(() => {});
|
|
95
|
-
await fs.unlink(lockPath).catch((error) => {
|
|
96
|
-
if (error.code !== "ENOENT") throw error;
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
async function readQueueOwnerRecord(sessionId) {
|
|
100
|
-
const lockPath = queueLockFilePath(sessionId);
|
|
101
|
-
try {
|
|
102
|
-
const payload = await fs.readFile(lockPath, "utf8");
|
|
103
|
-
return parseQueueOwnerRecord(JSON.parse(payload)) ?? void 0;
|
|
104
|
-
} catch {
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
function isProcessAlive(pid) {
|
|
109
|
-
if (!pid || !Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
|
|
110
|
-
try {
|
|
111
|
-
process.kill(pid, 0);
|
|
112
|
-
return true;
|
|
113
|
-
} catch {
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
async function terminateProcess(pid) {
|
|
118
|
-
if (!isProcessAlive(pid)) return false;
|
|
119
|
-
try {
|
|
120
|
-
process.kill(pid, "SIGTERM");
|
|
121
|
-
} catch {
|
|
122
|
-
return false;
|
|
123
|
-
}
|
|
124
|
-
if (await waitForProcessExit(pid, PROCESS_EXIT_GRACE_MS)) return true;
|
|
125
|
-
try {
|
|
126
|
-
process.kill(pid, "SIGKILL");
|
|
127
|
-
} catch {
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
await waitForProcessExit(pid, PROCESS_EXIT_GRACE_MS);
|
|
131
|
-
return true;
|
|
132
|
-
}
|
|
133
|
-
async function ensureOwnerIsUsable(sessionId, owner) {
|
|
134
|
-
const alive = isProcessAlive(owner.pid);
|
|
135
|
-
const stale = isQueueOwnerHeartbeatStale(owner);
|
|
136
|
-
if (alive && !stale) return true;
|
|
137
|
-
if (alive) await terminateProcess(owner.pid).catch(() => {});
|
|
138
|
-
await cleanupStaleQueueOwner(sessionId, owner);
|
|
139
|
-
return false;
|
|
140
|
-
}
|
|
141
|
-
async function readQueueOwnerStatus(sessionId) {
|
|
142
|
-
const owner = await readQueueOwnerRecord(sessionId);
|
|
143
|
-
if (!owner) return;
|
|
144
|
-
const alive = await ensureOwnerIsUsable(sessionId, owner);
|
|
145
|
-
if (!alive) return;
|
|
146
|
-
return {
|
|
147
|
-
pid: owner.pid,
|
|
148
|
-
socketPath: owner.socketPath,
|
|
149
|
-
heartbeatAt: owner.heartbeatAt,
|
|
150
|
-
ownerGeneration: owner.ownerGeneration,
|
|
151
|
-
queueDepth: owner.queueDepth,
|
|
152
|
-
alive,
|
|
153
|
-
stale: isQueueOwnerHeartbeatStale(owner)
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
async function tryAcquireQueueOwnerLease(sessionId, nowIsoFactory = nowIso) {
|
|
157
|
-
await ensureQueueDir();
|
|
158
|
-
const lockPath = queueLockFilePath(sessionId);
|
|
159
|
-
const socketPath = queueSocketPath(sessionId);
|
|
160
|
-
const createdAt = nowIsoFactory();
|
|
161
|
-
const ownerGeneration = createOwnerGeneration();
|
|
162
|
-
const payload = JSON.stringify({
|
|
163
|
-
pid: process.pid,
|
|
164
|
-
sessionId,
|
|
165
|
-
socketPath,
|
|
166
|
-
createdAt,
|
|
167
|
-
heartbeatAt: createdAt,
|
|
168
|
-
ownerGeneration,
|
|
169
|
-
queueDepth: 0
|
|
170
|
-
}, null, 2);
|
|
171
|
-
try {
|
|
172
|
-
await fs.writeFile(lockPath, `${payload}\n`, {
|
|
173
|
-
encoding: "utf8",
|
|
174
|
-
flag: "wx"
|
|
175
|
-
});
|
|
176
|
-
await removeSocketFile(socketPath).catch(() => {});
|
|
177
|
-
return {
|
|
178
|
-
sessionId,
|
|
179
|
-
lockPath,
|
|
180
|
-
socketPath,
|
|
181
|
-
createdAt,
|
|
182
|
-
ownerGeneration
|
|
183
|
-
};
|
|
184
|
-
} catch (error) {
|
|
185
|
-
if (error.code !== "EEXIST") throw error;
|
|
186
|
-
const owner = await readQueueOwnerRecord(sessionId);
|
|
187
|
-
if (!owner) {
|
|
188
|
-
await cleanupStaleQueueOwner(sessionId, owner);
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
if (!isProcessAlive(owner.pid) || isQueueOwnerHeartbeatStale(owner)) {
|
|
192
|
-
if (isProcessAlive(owner.pid)) await terminateProcess(owner.pid).catch(() => {});
|
|
193
|
-
await cleanupStaleQueueOwner(sessionId, owner);
|
|
194
|
-
}
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
async function refreshQueueOwnerLease(lease, options, nowIsoFactory = nowIso) {
|
|
199
|
-
const payload = JSON.stringify({
|
|
200
|
-
pid: process.pid,
|
|
201
|
-
sessionId: lease.sessionId,
|
|
202
|
-
socketPath: lease.socketPath,
|
|
203
|
-
createdAt: lease.createdAt,
|
|
204
|
-
heartbeatAt: nowIsoFactory(),
|
|
205
|
-
ownerGeneration: lease.ownerGeneration,
|
|
206
|
-
queueDepth: Math.max(0, Math.round(options.queueDepth))
|
|
207
|
-
}, null, 2);
|
|
208
|
-
await fs.writeFile(lease.lockPath, `${payload}\n`, { encoding: "utf8" });
|
|
209
|
-
}
|
|
210
|
-
async function releaseQueueOwnerLease(lease) {
|
|
211
|
-
await removeSocketFile(lease.socketPath).catch(() => {});
|
|
212
|
-
await fs.unlink(lease.lockPath).catch((error) => {
|
|
213
|
-
if (error.code !== "ENOENT") throw error;
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
async function terminateQueueOwnerForSession(sessionId) {
|
|
217
|
-
const owner = await readQueueOwnerRecord(sessionId);
|
|
218
|
-
if (!owner) return;
|
|
219
|
-
if (isProcessAlive(owner.pid)) await terminateProcess(owner.pid);
|
|
220
|
-
await cleanupStaleQueueOwner(sessionId, owner);
|
|
221
|
-
}
|
|
222
|
-
async function waitMs(ms) {
|
|
223
|
-
await new Promise((resolve) => {
|
|
224
|
-
setTimeout(resolve, ms);
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
//#endregion
|
|
228
|
-
//#region src/cli/queue/ipc-transport.ts
|
|
229
|
-
const QUEUE_CONNECT_ATTEMPTS = 40;
|
|
230
|
-
const SOCKET_CONNECTION_TIMEOUT_MS = 5e3;
|
|
231
|
-
function shouldRetryQueueConnect(error) {
|
|
232
|
-
const code = error.code;
|
|
233
|
-
return code === "ENOENT" || code === "ECONNREFUSED";
|
|
234
|
-
}
|
|
235
|
-
async function connectToSocket(socketPath, timeoutMs = SOCKET_CONNECTION_TIMEOUT_MS) {
|
|
236
|
-
return await new Promise((resolve, reject) => {
|
|
237
|
-
const socket = net.createConnection(socketPath);
|
|
238
|
-
let settled = false;
|
|
239
|
-
const timeout = setTimeout(() => {
|
|
240
|
-
if (settled) return;
|
|
241
|
-
settled = true;
|
|
242
|
-
socket.destroy();
|
|
243
|
-
reject(/* @__PURE__ */ new Error(`Connection to ${socketPath} timed out after ${timeoutMs}ms`));
|
|
244
|
-
}, timeoutMs);
|
|
245
|
-
const onConnect = () => {
|
|
246
|
-
if (settled) return;
|
|
247
|
-
settled = true;
|
|
248
|
-
clearTimeout(timeout);
|
|
249
|
-
socket.off("error", onError);
|
|
250
|
-
resolve(socket);
|
|
251
|
-
};
|
|
252
|
-
const onError = (error) => {
|
|
253
|
-
if (settled) return;
|
|
254
|
-
settled = true;
|
|
255
|
-
clearTimeout(timeout);
|
|
256
|
-
socket.off("connect", onConnect);
|
|
257
|
-
reject(error);
|
|
258
|
-
};
|
|
259
|
-
socket.once("connect", onConnect);
|
|
260
|
-
socket.once("error", onError);
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
async function connectToQueueOwner(owner, maxAttempts = QUEUE_CONNECT_ATTEMPTS) {
|
|
264
|
-
let lastError;
|
|
265
|
-
const attempts = Math.max(1, Math.trunc(maxAttempts));
|
|
266
|
-
for (let attempt = 0; attempt < attempts; attempt += 1) try {
|
|
267
|
-
return await measurePerf("queue.connect", async () => await connectToSocket(owner.socketPath));
|
|
268
|
-
} catch (error) {
|
|
269
|
-
lastError = error;
|
|
270
|
-
if (!shouldRetryQueueConnect(error)) throw error;
|
|
271
|
-
await waitMs(50);
|
|
272
|
-
}
|
|
273
|
-
if (lastError && !shouldRetryQueueConnect(lastError)) throw lastError;
|
|
274
|
-
}
|
|
275
|
-
//#endregion
|
|
276
|
-
//#region src/cli/queue/ipc-health.ts
|
|
277
|
-
async function probeQueueOwnerHealth(sessionId) {
|
|
278
|
-
const ownerRecord = await readQueueOwnerRecord(sessionId);
|
|
279
|
-
if (!ownerRecord) return {
|
|
280
|
-
sessionId,
|
|
281
|
-
hasLease: false,
|
|
282
|
-
healthy: false,
|
|
283
|
-
socketReachable: false,
|
|
284
|
-
pidAlive: false
|
|
285
|
-
};
|
|
286
|
-
const owner = await readQueueOwnerStatus(sessionId);
|
|
287
|
-
if (!owner) return {
|
|
288
|
-
sessionId,
|
|
289
|
-
hasLease: false,
|
|
290
|
-
healthy: false,
|
|
291
|
-
socketReachable: false,
|
|
292
|
-
pidAlive: false
|
|
293
|
-
};
|
|
294
|
-
const pidAlive = owner.alive;
|
|
295
|
-
let socketReachable = false;
|
|
296
|
-
try {
|
|
297
|
-
const socket = await connectToQueueOwner(ownerRecord, 2);
|
|
298
|
-
if (socket) {
|
|
299
|
-
socketReachable = true;
|
|
300
|
-
if (!socket.destroyed) socket.end();
|
|
301
|
-
}
|
|
302
|
-
} catch {
|
|
303
|
-
socketReachable = false;
|
|
304
|
-
}
|
|
305
|
-
return {
|
|
306
|
-
sessionId,
|
|
307
|
-
hasLease: true,
|
|
308
|
-
healthy: socketReachable,
|
|
309
|
-
socketReachable,
|
|
310
|
-
pidAlive,
|
|
311
|
-
pid: owner.pid,
|
|
312
|
-
socketPath: owner.socketPath,
|
|
313
|
-
ownerGeneration: owner.ownerGeneration,
|
|
314
|
-
queueDepth: owner.queueDepth
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
//#endregion
|
|
318
|
-
//#region src/cli/queue/messages.ts
|
|
319
|
-
function asRecord(value) {
|
|
320
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
321
|
-
return value;
|
|
322
|
-
}
|
|
323
|
-
function isPermissionMode(value) {
|
|
324
|
-
return value === "approve-all" || value === "approve-reads" || value === "deny-all";
|
|
325
|
-
}
|
|
326
|
-
function isSessionResumePolicy(value) {
|
|
327
|
-
return value === "allow-new" || value === "same-session-only";
|
|
328
|
-
}
|
|
329
|
-
function isNonInteractivePermissionPolicy(value) {
|
|
330
|
-
return value === "deny" || value === "fail";
|
|
331
|
-
}
|
|
332
|
-
function isOutputErrorCode(value) {
|
|
333
|
-
return typeof value === "string" && OUTPUT_ERROR_CODES.includes(value);
|
|
334
|
-
}
|
|
335
|
-
function isOutputErrorOrigin(value) {
|
|
336
|
-
return typeof value === "string" && OUTPUT_ERROR_ORIGINS.includes(value);
|
|
337
|
-
}
|
|
338
|
-
function parseSessionOptions(value) {
|
|
339
|
-
if (value == null) return;
|
|
340
|
-
const record = asRecord(value);
|
|
341
|
-
if (!record) return null;
|
|
342
|
-
const sessionOptions = {};
|
|
343
|
-
if (record.model != null) {
|
|
344
|
-
if (typeof record.model !== "string" || record.model.trim().length === 0) return null;
|
|
345
|
-
sessionOptions.model = record.model;
|
|
346
|
-
}
|
|
347
|
-
if (record.allowedTools != null) {
|
|
348
|
-
if (!Array.isArray(record.allowedTools)) return null;
|
|
349
|
-
const allowedTools = record.allowedTools.filter((tool) => typeof tool === "string");
|
|
350
|
-
if (allowedTools.length !== record.allowedTools.length) return null;
|
|
351
|
-
sessionOptions.allowedTools = allowedTools;
|
|
352
|
-
}
|
|
353
|
-
if (record.maxTurns != null) {
|
|
354
|
-
if (typeof record.maxTurns !== "number" || !Number.isFinite(record.maxTurns)) return null;
|
|
355
|
-
sessionOptions.maxTurns = Math.max(1, Math.round(record.maxTurns));
|
|
356
|
-
}
|
|
357
|
-
if (record.systemPrompt != null) if (typeof record.systemPrompt === "string") sessionOptions.systemPrompt = record.systemPrompt;
|
|
358
|
-
else {
|
|
359
|
-
const systemPrompt = asRecord(record.systemPrompt);
|
|
360
|
-
if (!systemPrompt || typeof systemPrompt.append !== "string") return null;
|
|
361
|
-
sessionOptions.systemPrompt = { append: systemPrompt.append };
|
|
362
|
-
}
|
|
363
|
-
return sessionOptions;
|
|
364
|
-
}
|
|
365
|
-
function parseOwnerGeneration(value) {
|
|
366
|
-
if (value == null) return;
|
|
367
|
-
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) return null;
|
|
368
|
-
return value;
|
|
369
|
-
}
|
|
370
|
-
function parseQueueRequest(raw) {
|
|
371
|
-
const request = asRecord(raw);
|
|
372
|
-
if (!request) return null;
|
|
373
|
-
if (typeof request.type !== "string" || typeof request.requestId !== "string") return null;
|
|
374
|
-
const ownerGeneration = parseOwnerGeneration(request.ownerGeneration);
|
|
375
|
-
if (ownerGeneration === null) return null;
|
|
376
|
-
const timeoutRaw = request.timeoutMs;
|
|
377
|
-
const timeoutMs = typeof timeoutRaw === "number" && Number.isFinite(timeoutRaw) && timeoutRaw > 0 ? Math.round(timeoutRaw) : void 0;
|
|
378
|
-
if (request.type === "submit_prompt") {
|
|
379
|
-
const resumePolicy = request.resumePolicy == null ? void 0 : isSessionResumePolicy(request.resumePolicy) ? request.resumePolicy : null;
|
|
380
|
-
const nonInteractivePermissions = request.nonInteractivePermissions == null ? void 0 : isNonInteractivePermissionPolicy(request.nonInteractivePermissions) ? request.nonInteractivePermissions : null;
|
|
381
|
-
const suppressSdkConsoleErrors = request.suppressSdkConsoleErrors == null ? void 0 : typeof request.suppressSdkConsoleErrors === "boolean" ? request.suppressSdkConsoleErrors : null;
|
|
382
|
-
const sessionOptions = parseSessionOptions(request.sessionOptions);
|
|
383
|
-
const prompt = request.prompt == null ? void 0 : isPromptInput(request.prompt) ? request.prompt : null;
|
|
384
|
-
if (typeof request.message !== "string" || !isPermissionMode(request.permissionMode) || resumePolicy === null || prompt === null || nonInteractivePermissions === null || suppressSdkConsoleErrors === null || sessionOptions === null || typeof request.waitForCompletion !== "boolean") return null;
|
|
385
|
-
return {
|
|
386
|
-
type: "submit_prompt",
|
|
387
|
-
requestId: request.requestId,
|
|
388
|
-
ownerGeneration,
|
|
389
|
-
message: request.message,
|
|
390
|
-
prompt: prompt ?? textPrompt(request.message),
|
|
391
|
-
permissionMode: request.permissionMode,
|
|
392
|
-
...resumePolicy !== void 0 ? { resumePolicy } : {},
|
|
393
|
-
nonInteractivePermissions,
|
|
394
|
-
timeoutMs,
|
|
395
|
-
...suppressSdkConsoleErrors !== void 0 ? { suppressSdkConsoleErrors } : {},
|
|
396
|
-
waitForCompletion: request.waitForCompletion,
|
|
397
|
-
...sessionOptions !== void 0 ? { sessionOptions } : {}
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
if (request.type === "cancel_prompt") return {
|
|
401
|
-
type: "cancel_prompt",
|
|
402
|
-
requestId: request.requestId,
|
|
403
|
-
ownerGeneration
|
|
404
|
-
};
|
|
405
|
-
if (request.type === "close_session") return {
|
|
406
|
-
type: "close_session",
|
|
407
|
-
requestId: request.requestId,
|
|
408
|
-
ownerGeneration,
|
|
409
|
-
timeoutMs
|
|
410
|
-
};
|
|
411
|
-
if (request.type === "set_mode") {
|
|
412
|
-
if (typeof request.modeId !== "string" || request.modeId.trim().length === 0) return null;
|
|
413
|
-
return {
|
|
414
|
-
type: "set_mode",
|
|
415
|
-
requestId: request.requestId,
|
|
416
|
-
ownerGeneration,
|
|
417
|
-
modeId: request.modeId,
|
|
418
|
-
timeoutMs
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
if (request.type === "set_model") {
|
|
422
|
-
if (typeof request.modelId !== "string" || request.modelId.trim().length === 0) return null;
|
|
423
|
-
return {
|
|
424
|
-
type: "set_model",
|
|
425
|
-
requestId: request.requestId,
|
|
426
|
-
ownerGeneration,
|
|
427
|
-
modelId: request.modelId,
|
|
428
|
-
timeoutMs
|
|
429
|
-
};
|
|
430
|
-
}
|
|
431
|
-
if (request.type === "set_config_option") {
|
|
432
|
-
if (typeof request.configId !== "string" || request.configId.trim().length === 0 || typeof request.value !== "string" || request.value.trim().length === 0) return null;
|
|
433
|
-
return {
|
|
434
|
-
type: "set_config_option",
|
|
435
|
-
requestId: request.requestId,
|
|
436
|
-
ownerGeneration,
|
|
437
|
-
configId: request.configId,
|
|
438
|
-
value: request.value,
|
|
439
|
-
timeoutMs
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
|
-
return null;
|
|
443
|
-
}
|
|
444
|
-
function parseSessionSendResult(raw) {
|
|
445
|
-
const result = asRecord(raw);
|
|
446
|
-
if (!result) return null;
|
|
447
|
-
if (typeof result.stopReason !== "string" || typeof result.sessionId !== "string" || typeof result.resumed !== "boolean") return null;
|
|
448
|
-
const permissionStats = asRecord(result.permissionStats);
|
|
449
|
-
const record = asRecord(result.record);
|
|
450
|
-
if (!permissionStats || !record) return null;
|
|
451
|
-
if (!(typeof permissionStats.requested === "number" && typeof permissionStats.approved === "number" && typeof permissionStats.denied === "number" && typeof permissionStats.cancelled === "number")) return null;
|
|
452
|
-
if (!(typeof record.acpxRecordId === "string" && typeof record.acpSessionId === "string" && typeof record.agentCommand === "string" && typeof record.cwd === "string" && typeof record.createdAt === "string" && typeof record.lastUsedAt === "string" && Array.isArray(record.messages) && typeof record.updated_at === "string" && typeof record.lastSeq === "number" && Number.isInteger(record.lastSeq) && !!record.eventLog && typeof record.eventLog === "object")) return null;
|
|
453
|
-
return result;
|
|
454
|
-
}
|
|
455
|
-
function parseQueueOwnerMessage(raw) {
|
|
456
|
-
const message = asRecord(raw);
|
|
457
|
-
if (!message || typeof message.type !== "string") return null;
|
|
458
|
-
if (typeof message.requestId !== "string") return null;
|
|
459
|
-
const ownerGeneration = parseOwnerGeneration(message.ownerGeneration);
|
|
460
|
-
if (ownerGeneration === null) return null;
|
|
461
|
-
if (message.type === "accepted") return {
|
|
462
|
-
type: "accepted",
|
|
463
|
-
requestId: message.requestId,
|
|
464
|
-
ownerGeneration
|
|
465
|
-
};
|
|
466
|
-
if (message.type === "event") {
|
|
467
|
-
if (!isAcpJsonRpcMessage(message.message)) return null;
|
|
468
|
-
return {
|
|
469
|
-
type: "event",
|
|
470
|
-
requestId: message.requestId,
|
|
471
|
-
ownerGeneration,
|
|
472
|
-
message: message.message
|
|
473
|
-
};
|
|
474
|
-
}
|
|
475
|
-
if (message.type === "result") {
|
|
476
|
-
const parsedResult = parseSessionSendResult(message.result);
|
|
477
|
-
if (!parsedResult) return null;
|
|
478
|
-
return {
|
|
479
|
-
type: "result",
|
|
480
|
-
requestId: message.requestId,
|
|
481
|
-
ownerGeneration,
|
|
482
|
-
result: parsedResult
|
|
483
|
-
};
|
|
484
|
-
}
|
|
485
|
-
if (message.type === "cancel_result") {
|
|
486
|
-
if (typeof message.cancelled !== "boolean") return null;
|
|
487
|
-
return {
|
|
488
|
-
type: "cancel_result",
|
|
489
|
-
requestId: message.requestId,
|
|
490
|
-
ownerGeneration,
|
|
491
|
-
cancelled: message.cancelled
|
|
492
|
-
};
|
|
493
|
-
}
|
|
494
|
-
if (message.type === "set_mode_result") {
|
|
495
|
-
if (typeof message.modeId !== "string") return null;
|
|
496
|
-
return {
|
|
497
|
-
type: "set_mode_result",
|
|
498
|
-
requestId: message.requestId,
|
|
499
|
-
ownerGeneration,
|
|
500
|
-
modeId: message.modeId
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
if (message.type === "set_model_result") {
|
|
504
|
-
if (typeof message.modelId !== "string") return null;
|
|
505
|
-
return {
|
|
506
|
-
type: "set_model_result",
|
|
507
|
-
requestId: message.requestId,
|
|
508
|
-
ownerGeneration,
|
|
509
|
-
modelId: message.modelId
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
|
-
if (message.type === "set_config_option_result") {
|
|
513
|
-
const response = asRecord(message.response);
|
|
514
|
-
if (!response || !Array.isArray(response.configOptions)) return null;
|
|
515
|
-
return {
|
|
516
|
-
type: "set_config_option_result",
|
|
517
|
-
requestId: message.requestId,
|
|
518
|
-
ownerGeneration,
|
|
519
|
-
response
|
|
520
|
-
};
|
|
521
|
-
}
|
|
522
|
-
if (message.type === "error") {
|
|
523
|
-
if (typeof message.message !== "string" || !isOutputErrorCode(message.code) || !isOutputErrorOrigin(message.origin)) return null;
|
|
524
|
-
const detailCode = typeof message.detailCode === "string" && message.detailCode.trim().length > 0 ? message.detailCode : void 0;
|
|
525
|
-
const retryable = typeof message.retryable === "boolean" ? message.retryable : void 0;
|
|
526
|
-
const acp = toAcpErrorPayload(message.acp);
|
|
527
|
-
const outputAlreadyEmitted = typeof message.outputAlreadyEmitted === "boolean" ? message.outputAlreadyEmitted : void 0;
|
|
528
|
-
return {
|
|
529
|
-
type: "error",
|
|
530
|
-
requestId: message.requestId,
|
|
531
|
-
ownerGeneration,
|
|
532
|
-
code: message.code,
|
|
533
|
-
detailCode,
|
|
534
|
-
origin: message.origin,
|
|
535
|
-
message: message.message,
|
|
536
|
-
retryable,
|
|
537
|
-
acp,
|
|
538
|
-
...outputAlreadyEmitted === void 0 ? {} : { outputAlreadyEmitted }
|
|
539
|
-
};
|
|
540
|
-
}
|
|
541
|
-
return null;
|
|
542
|
-
}
|
|
543
|
-
//#endregion
|
|
544
|
-
//#region src/cli/queue/ipc-server.ts
|
|
545
|
-
function makeQueueOwnerError(requestId, message, detailCode, options = {}) {
|
|
546
|
-
return {
|
|
547
|
-
type: "error",
|
|
548
|
-
requestId,
|
|
549
|
-
ownerGeneration: void 0,
|
|
550
|
-
code: "RUNTIME",
|
|
551
|
-
detailCode,
|
|
552
|
-
origin: "queue",
|
|
553
|
-
retryable: options.retryable,
|
|
554
|
-
message
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
function makeQueueOwnerErrorFromUnknown(requestId, error, detailCode, options = {}) {
|
|
558
|
-
const normalized = normalizeOutputError(error, {
|
|
559
|
-
defaultCode: "RUNTIME",
|
|
560
|
-
origin: "queue",
|
|
561
|
-
detailCode,
|
|
562
|
-
retryable: options.retryable
|
|
563
|
-
});
|
|
564
|
-
return {
|
|
565
|
-
type: "error",
|
|
566
|
-
requestId,
|
|
567
|
-
code: normalized.code,
|
|
568
|
-
detailCode: normalized.detailCode,
|
|
569
|
-
origin: normalized.origin,
|
|
570
|
-
message: normalized.message,
|
|
571
|
-
retryable: normalized.retryable,
|
|
572
|
-
acp: normalized.acp
|
|
573
|
-
};
|
|
574
|
-
}
|
|
575
|
-
function writeQueueMessage(socket, message) {
|
|
576
|
-
if (socket.destroyed || !socket.writable) return;
|
|
577
|
-
socket.write(`${JSON.stringify(message)}\n`);
|
|
578
|
-
}
|
|
579
|
-
var SessionQueueOwner = class SessionQueueOwner {
|
|
580
|
-
server;
|
|
581
|
-
controlHandlers;
|
|
582
|
-
ownerGeneration;
|
|
583
|
-
maxQueueDepth;
|
|
584
|
-
onQueueDepthChanged;
|
|
585
|
-
pending = [];
|
|
586
|
-
waiters = [];
|
|
587
|
-
closed = false;
|
|
588
|
-
constructor(server, controlHandlers, lease, options) {
|
|
589
|
-
this.server = server;
|
|
590
|
-
this.controlHandlers = controlHandlers;
|
|
591
|
-
this.ownerGeneration = lease.ownerGeneration;
|
|
592
|
-
this.maxQueueDepth = Math.max(1, Math.round(options.maxQueueDepth));
|
|
593
|
-
this.onQueueDepthChanged = options.onQueueDepthChanged;
|
|
594
|
-
}
|
|
595
|
-
static async start(lease, controlHandlers, options = { maxQueueDepth: 16 }) {
|
|
596
|
-
const ownerRef = { current: void 0 };
|
|
597
|
-
const server = net.createServer((socket) => {
|
|
598
|
-
ownerRef.current?.handleConnection(socket);
|
|
599
|
-
});
|
|
600
|
-
ownerRef.current = new SessionQueueOwner(server, controlHandlers, lease, options);
|
|
601
|
-
await new Promise((resolve, reject) => {
|
|
602
|
-
const onListening = () => {
|
|
603
|
-
server.off("error", onError);
|
|
604
|
-
resolve();
|
|
605
|
-
};
|
|
606
|
-
const onError = (error) => {
|
|
607
|
-
server.off("listening", onListening);
|
|
608
|
-
reject(error);
|
|
609
|
-
};
|
|
610
|
-
server.once("listening", onListening);
|
|
611
|
-
server.once("error", onError);
|
|
612
|
-
server.listen(lease.socketPath);
|
|
613
|
-
});
|
|
614
|
-
return ownerRef.current;
|
|
615
|
-
}
|
|
616
|
-
async close() {
|
|
617
|
-
if (this.closed) return;
|
|
618
|
-
this.closed = true;
|
|
619
|
-
for (const waiter of this.waiters.splice(0)) waiter(void 0);
|
|
620
|
-
for (const task of this.pending.splice(0)) {
|
|
621
|
-
if (task.waitForCompletion) task.send(makeQueueOwnerError(task.requestId, "Queue owner shutting down before prompt execution", "QUEUE_OWNER_SHUTTING_DOWN", { retryable: true }));
|
|
622
|
-
task.close();
|
|
623
|
-
}
|
|
624
|
-
this.emitQueueDepth();
|
|
625
|
-
await new Promise((resolve) => {
|
|
626
|
-
this.server.close(() => resolve());
|
|
627
|
-
});
|
|
628
|
-
}
|
|
629
|
-
async nextTask(timeoutMs) {
|
|
630
|
-
if (this.pending.length > 0) {
|
|
631
|
-
const task = this.pending.shift();
|
|
632
|
-
this.emitQueueDepth();
|
|
633
|
-
if (task) recordPerfDuration("queue.owner.wait_ms", Date.now() - task.enqueuedAt);
|
|
634
|
-
return task;
|
|
635
|
-
}
|
|
636
|
-
if (this.closed) return;
|
|
637
|
-
return await new Promise((resolve) => {
|
|
638
|
-
const timer = timeoutMs != null && setTimeout(() => {
|
|
639
|
-
const index = this.waiters.indexOf(waiter);
|
|
640
|
-
if (index >= 0) this.waiters.splice(index, 1);
|
|
641
|
-
resolve(void 0);
|
|
642
|
-
}, Math.max(0, timeoutMs));
|
|
643
|
-
const waiter = (task) => {
|
|
644
|
-
if (timer) clearTimeout(timer);
|
|
645
|
-
resolve(task);
|
|
646
|
-
};
|
|
647
|
-
this.waiters.push(waiter);
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
|
-
queueDepth() {
|
|
651
|
-
return this.pending.length;
|
|
652
|
-
}
|
|
653
|
-
emitQueueDepth() {
|
|
654
|
-
this.onQueueDepthChanged?.(this.pending.length);
|
|
655
|
-
}
|
|
656
|
-
enqueue(task) {
|
|
657
|
-
if (this.closed) {
|
|
658
|
-
if (task.waitForCompletion) task.send(makeQueueOwnerError(task.requestId, "Queue owner is shutting down", "QUEUE_OWNER_SHUTTING_DOWN", { retryable: true }));
|
|
659
|
-
task.close();
|
|
660
|
-
return;
|
|
661
|
-
}
|
|
662
|
-
const waiter = this.waiters.shift();
|
|
663
|
-
if (waiter) {
|
|
664
|
-
waiter(task);
|
|
665
|
-
return;
|
|
666
|
-
}
|
|
667
|
-
if (this.pending.length >= this.maxQueueDepth) {
|
|
668
|
-
if (task.waitForCompletion) task.send({
|
|
669
|
-
...makeQueueOwnerError(task.requestId, `Queue owner is overloaded (${this.pending.length}/${this.maxQueueDepth} queued)`, "QUEUE_OWNER_OVERLOADED", { retryable: true }),
|
|
670
|
-
ownerGeneration: this.ownerGeneration
|
|
671
|
-
});
|
|
672
|
-
task.close();
|
|
673
|
-
return;
|
|
674
|
-
}
|
|
675
|
-
this.pending.push(task);
|
|
676
|
-
this.emitQueueDepth();
|
|
677
|
-
}
|
|
678
|
-
handleControlRequest(options) {
|
|
679
|
-
writeQueueMessage(options.socket, {
|
|
680
|
-
type: "accepted",
|
|
681
|
-
requestId: options.requestId,
|
|
682
|
-
ownerGeneration: this.ownerGeneration
|
|
683
|
-
});
|
|
684
|
-
options.run().then((message) => {
|
|
685
|
-
writeQueueMessage(options.socket, {
|
|
686
|
-
...message,
|
|
687
|
-
ownerGeneration: this.ownerGeneration
|
|
688
|
-
});
|
|
689
|
-
}).catch((error) => {
|
|
690
|
-
writeQueueMessage(options.socket, {
|
|
691
|
-
...makeQueueOwnerErrorFromUnknown(options.requestId, error, "QUEUE_CONTROL_REQUEST_FAILED"),
|
|
692
|
-
ownerGeneration: this.ownerGeneration
|
|
693
|
-
});
|
|
694
|
-
}).finally(() => {
|
|
695
|
-
if (!options.socket.destroyed) options.socket.end();
|
|
696
|
-
});
|
|
697
|
-
}
|
|
698
|
-
handleConnection(socket) {
|
|
699
|
-
socket.setEncoding("utf8");
|
|
700
|
-
if (this.closed) {
|
|
701
|
-
writeQueueMessage(socket, makeQueueOwnerError("unknown", "Queue owner is closed", "QUEUE_OWNER_CLOSED", { retryable: true }));
|
|
702
|
-
socket.end();
|
|
703
|
-
return;
|
|
704
|
-
}
|
|
705
|
-
let buffer = "";
|
|
706
|
-
let handled = false;
|
|
707
|
-
const fail = (requestId, message, detailCode) => {
|
|
708
|
-
writeQueueMessage(socket, {
|
|
709
|
-
...makeQueueOwnerError(requestId, message, detailCode, { retryable: false }),
|
|
710
|
-
ownerGeneration: this.ownerGeneration
|
|
711
|
-
});
|
|
712
|
-
socket.end();
|
|
713
|
-
};
|
|
714
|
-
const processLine = (line) => {
|
|
715
|
-
if (handled) return;
|
|
716
|
-
handled = true;
|
|
717
|
-
let parsed;
|
|
718
|
-
try {
|
|
719
|
-
parsed = JSON.parse(line);
|
|
720
|
-
} catch {
|
|
721
|
-
fail("unknown", "Invalid queue request payload", "QUEUE_REQUEST_PAYLOAD_INVALID_JSON");
|
|
722
|
-
return;
|
|
723
|
-
}
|
|
724
|
-
const request = parseQueueRequest(parsed);
|
|
725
|
-
if (!request) {
|
|
726
|
-
fail("unknown", "Invalid queue request", "QUEUE_REQUEST_INVALID");
|
|
727
|
-
return;
|
|
728
|
-
}
|
|
729
|
-
if (request.ownerGeneration !== void 0 && this.ownerGeneration !== void 0 && request.ownerGeneration !== this.ownerGeneration) {
|
|
730
|
-
fail(request.requestId, "Queue request targeted a stale queue owner generation", "QUEUE_OWNER_GENERATION_MISMATCH");
|
|
731
|
-
return;
|
|
732
|
-
}
|
|
733
|
-
if (request.type === "cancel_prompt") {
|
|
734
|
-
this.handleControlRequest({
|
|
735
|
-
socket,
|
|
736
|
-
requestId: request.requestId,
|
|
737
|
-
run: async () => ({
|
|
738
|
-
type: "cancel_result",
|
|
739
|
-
requestId: request.requestId,
|
|
740
|
-
cancelled: await this.controlHandlers.cancelPrompt()
|
|
741
|
-
})
|
|
742
|
-
});
|
|
743
|
-
return;
|
|
744
|
-
}
|
|
745
|
-
if (request.type === "close_session") {
|
|
746
|
-
this.handleControlRequest({
|
|
747
|
-
socket,
|
|
748
|
-
requestId: request.requestId,
|
|
749
|
-
run: async () => ({
|
|
750
|
-
type: "close_session_result",
|
|
751
|
-
requestId: request.requestId,
|
|
752
|
-
closed: await this.controlHandlers.closeSession(request.timeoutMs)
|
|
753
|
-
})
|
|
754
|
-
});
|
|
755
|
-
return;
|
|
756
|
-
}
|
|
757
|
-
if (request.type === "set_mode") {
|
|
758
|
-
this.handleControlRequest({
|
|
759
|
-
socket,
|
|
760
|
-
requestId: request.requestId,
|
|
761
|
-
run: async () => {
|
|
762
|
-
await this.controlHandlers.setSessionMode(request.modeId, request.timeoutMs);
|
|
763
|
-
return {
|
|
764
|
-
type: "set_mode_result",
|
|
765
|
-
requestId: request.requestId,
|
|
766
|
-
modeId: request.modeId
|
|
767
|
-
};
|
|
768
|
-
}
|
|
769
|
-
});
|
|
770
|
-
return;
|
|
771
|
-
}
|
|
772
|
-
if (request.type === "set_model") {
|
|
773
|
-
this.handleControlRequest({
|
|
774
|
-
socket,
|
|
775
|
-
requestId: request.requestId,
|
|
776
|
-
run: async () => {
|
|
777
|
-
await this.controlHandlers.setSessionModel(request.modelId, request.timeoutMs);
|
|
778
|
-
return {
|
|
779
|
-
type: "set_model_result",
|
|
780
|
-
requestId: request.requestId,
|
|
781
|
-
modelId: request.modelId
|
|
782
|
-
};
|
|
783
|
-
}
|
|
784
|
-
});
|
|
785
|
-
return;
|
|
786
|
-
}
|
|
787
|
-
if (request.type === "set_config_option") {
|
|
788
|
-
this.handleControlRequest({
|
|
789
|
-
socket,
|
|
790
|
-
requestId: request.requestId,
|
|
791
|
-
run: async () => ({
|
|
792
|
-
type: "set_config_option_result",
|
|
793
|
-
requestId: request.requestId,
|
|
794
|
-
response: await this.controlHandlers.setSessionConfigOption(request.configId, request.value, request.timeoutMs)
|
|
795
|
-
})
|
|
796
|
-
});
|
|
797
|
-
return;
|
|
798
|
-
}
|
|
799
|
-
const task = {
|
|
800
|
-
requestId: request.requestId,
|
|
801
|
-
message: request.message,
|
|
802
|
-
prompt: request.prompt ?? textPrompt(request.message),
|
|
803
|
-
permissionMode: request.permissionMode,
|
|
804
|
-
resumePolicy: request.resumePolicy,
|
|
805
|
-
nonInteractivePermissions: request.nonInteractivePermissions,
|
|
806
|
-
timeoutMs: request.timeoutMs,
|
|
807
|
-
suppressSdkConsoleErrors: request.suppressSdkConsoleErrors,
|
|
808
|
-
sessionOptions: request.sessionOptions,
|
|
809
|
-
waitForCompletion: request.waitForCompletion,
|
|
810
|
-
enqueuedAt: Date.now(),
|
|
811
|
-
send: (message) => {
|
|
812
|
-
writeQueueMessage(socket, {
|
|
813
|
-
...message,
|
|
814
|
-
ownerGeneration: this.ownerGeneration
|
|
815
|
-
});
|
|
816
|
-
},
|
|
817
|
-
close: () => {
|
|
818
|
-
if (!socket.destroyed) socket.end();
|
|
819
|
-
}
|
|
820
|
-
};
|
|
821
|
-
writeQueueMessage(socket, {
|
|
822
|
-
type: "accepted",
|
|
823
|
-
requestId: request.requestId,
|
|
824
|
-
ownerGeneration: this.ownerGeneration
|
|
825
|
-
});
|
|
826
|
-
if (!request.waitForCompletion) task.close();
|
|
827
|
-
this.enqueue(task);
|
|
828
|
-
};
|
|
829
|
-
socket.on("data", (chunk) => {
|
|
830
|
-
buffer += chunk;
|
|
831
|
-
let index = buffer.indexOf("\n");
|
|
832
|
-
while (index >= 0) {
|
|
833
|
-
const line = buffer.slice(0, index).trim();
|
|
834
|
-
buffer = buffer.slice(index + 1);
|
|
835
|
-
if (line.length > 0) processLine(line);
|
|
836
|
-
index = buffer.indexOf("\n");
|
|
837
|
-
}
|
|
838
|
-
});
|
|
839
|
-
socket.on("error", () => {});
|
|
840
|
-
}
|
|
841
|
-
};
|
|
842
|
-
//#endregion
|
|
843
|
-
//#region src/cli/queue/ipc.ts
|
|
844
|
-
const MAX_MESSAGE_BUFFER_SIZE = 10 * 1024 * 1024;
|
|
845
|
-
const STALE_OWNER_PROTOCOL_DETAIL_CODES = new Set(["QUEUE_PROTOCOL_MALFORMED_MESSAGE", "QUEUE_PROTOCOL_UNEXPECTED_RESPONSE"]);
|
|
846
|
-
async function maybeRecoverStaleOwnerAfterProtocolMismatch(params) {
|
|
847
|
-
if (!(params.error instanceof QueueProtocolError)) return false;
|
|
848
|
-
const detailCode = params.error.detailCode;
|
|
849
|
-
if (!detailCode || !STALE_OWNER_PROTOCOL_DETAIL_CODES.has(detailCode)) return false;
|
|
850
|
-
await terminateQueueOwnerForSession(params.sessionId).catch(() => {});
|
|
851
|
-
incrementPerfCounter("queue.owner.stale_recovered");
|
|
852
|
-
if (params.verbose) process.stderr.write(`[acpx] dropped stale queue owner metadata after protocol mismatch for session ${params.sessionId} (${detailCode})\n`);
|
|
853
|
-
return true;
|
|
854
|
-
}
|
|
855
|
-
function assertOwnerGeneration(owner, message) {
|
|
856
|
-
if (owner.ownerGeneration !== void 0 && message.ownerGeneration !== void 0 && message.ownerGeneration !== owner.ownerGeneration) throw new QueueProtocolError("Queue owner returned mismatched generation", {
|
|
857
|
-
detailCode: "QUEUE_OWNER_GENERATION_MISMATCH",
|
|
858
|
-
origin: "queue",
|
|
859
|
-
retryable: true
|
|
860
|
-
});
|
|
861
|
-
return message;
|
|
862
|
-
}
|
|
863
|
-
function makeMalformedQueueMessageError() {
|
|
864
|
-
return new QueueProtocolError("Queue owner sent malformed message", {
|
|
865
|
-
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
866
|
-
origin: "queue",
|
|
867
|
-
retryable: true
|
|
868
|
-
});
|
|
869
|
-
}
|
|
870
|
-
function parseQueueOwnerResponseLine(owner, requestId, line) {
|
|
871
|
-
let parsed;
|
|
872
|
-
try {
|
|
873
|
-
parsed = JSON.parse(line);
|
|
874
|
-
} catch {
|
|
875
|
-
throw new QueueProtocolError("Queue owner sent invalid JSON payload", {
|
|
876
|
-
detailCode: "QUEUE_PROTOCOL_INVALID_JSON",
|
|
877
|
-
origin: "queue",
|
|
878
|
-
retryable: true
|
|
879
|
-
});
|
|
880
|
-
}
|
|
881
|
-
const parsedMessage = parseQueueOwnerMessage(parsed);
|
|
882
|
-
if (!parsedMessage) throw makeMalformedQueueMessageError();
|
|
883
|
-
const message = assertOwnerGeneration(owner, parsedMessage);
|
|
884
|
-
if (message.requestId !== requestId) throw makeMalformedQueueMessageError();
|
|
885
|
-
return message;
|
|
886
|
-
}
|
|
887
|
-
async function runQueueOwnerRequest(options) {
|
|
888
|
-
const socket = await connectToQueueOwner(options.owner);
|
|
889
|
-
if (!socket) return;
|
|
890
|
-
socket.setEncoding("utf8");
|
|
891
|
-
return await new Promise((resolve, reject) => {
|
|
892
|
-
let settled = false;
|
|
893
|
-
let buffer = "";
|
|
894
|
-
const state = { acknowledged: false };
|
|
895
|
-
const finishResolve = (result) => {
|
|
896
|
-
if (settled) return;
|
|
897
|
-
settled = true;
|
|
898
|
-
socket.removeAllListeners();
|
|
899
|
-
if (!socket.destroyed) socket.end();
|
|
900
|
-
resolve(result);
|
|
901
|
-
};
|
|
902
|
-
const finishReject = (error) => {
|
|
903
|
-
if (settled) return;
|
|
904
|
-
settled = true;
|
|
905
|
-
socket.removeAllListeners();
|
|
906
|
-
if (!socket.destroyed) socket.destroy();
|
|
907
|
-
reject(error);
|
|
908
|
-
};
|
|
909
|
-
const controls = {
|
|
910
|
-
state,
|
|
911
|
-
resolve: finishResolve,
|
|
912
|
-
reject: finishReject
|
|
913
|
-
};
|
|
914
|
-
const processLine = (line) => {
|
|
915
|
-
let message;
|
|
916
|
-
try {
|
|
917
|
-
message = parseQueueOwnerResponseLine(options.owner, options.request.requestId, line);
|
|
918
|
-
} catch (error) {
|
|
919
|
-
finishReject(error);
|
|
920
|
-
return;
|
|
921
|
-
}
|
|
922
|
-
if (message.type === "accepted") {
|
|
923
|
-
state.acknowledged = true;
|
|
924
|
-
options.onAccepted?.(controls);
|
|
925
|
-
return;
|
|
926
|
-
}
|
|
927
|
-
options.onMessage(message, controls);
|
|
928
|
-
};
|
|
929
|
-
socket.on("data", (chunk) => {
|
|
930
|
-
buffer += chunk;
|
|
931
|
-
if (buffer.length > 10485760) {
|
|
932
|
-
socket.destroy();
|
|
933
|
-
finishReject(/* @__PURE__ */ new Error(`Message buffer exceeded ${MAX_MESSAGE_BUFFER_SIZE} bytes`));
|
|
934
|
-
return;
|
|
935
|
-
}
|
|
936
|
-
let index = buffer.indexOf("\n");
|
|
937
|
-
while (index >= 0) {
|
|
938
|
-
const line = buffer.slice(0, index).trim();
|
|
939
|
-
buffer = buffer.slice(index + 1);
|
|
940
|
-
if (line.length > 0) processLine(line);
|
|
941
|
-
index = buffer.indexOf("\n");
|
|
942
|
-
}
|
|
943
|
-
});
|
|
944
|
-
socket.once("error", (error) => {
|
|
945
|
-
finishReject(error);
|
|
946
|
-
});
|
|
947
|
-
socket.once("close", () => {
|
|
948
|
-
if (settled) return;
|
|
949
|
-
options.onClose(controls);
|
|
950
|
-
});
|
|
951
|
-
socket.write(`${JSON.stringify(options.request)}\n`);
|
|
952
|
-
});
|
|
953
|
-
}
|
|
954
|
-
async function submitToQueueOwner(owner, options) {
|
|
955
|
-
const requestId = randomUUID();
|
|
956
|
-
const request = {
|
|
957
|
-
type: "submit_prompt",
|
|
958
|
-
requestId,
|
|
959
|
-
ownerGeneration: owner.ownerGeneration,
|
|
960
|
-
message: options.message,
|
|
961
|
-
prompt: options.prompt,
|
|
962
|
-
permissionMode: options.permissionMode,
|
|
963
|
-
resumePolicy: options.resumePolicy,
|
|
964
|
-
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
965
|
-
timeoutMs: options.timeoutMs,
|
|
966
|
-
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
967
|
-
waitForCompletion: options.waitForCompletion,
|
|
968
|
-
sessionOptions: options.sessionOptions
|
|
969
|
-
};
|
|
970
|
-
options.outputFormatter.setContext({ sessionId: options.sessionId });
|
|
971
|
-
return await runQueueOwnerRequest({
|
|
972
|
-
owner,
|
|
973
|
-
request,
|
|
974
|
-
onAccepted: ({ resolve }) => {
|
|
975
|
-
options.outputFormatter.setContext({ sessionId: options.sessionId });
|
|
976
|
-
if (!options.waitForCompletion) resolve({
|
|
977
|
-
queued: true,
|
|
978
|
-
sessionId: options.sessionId,
|
|
979
|
-
requestId
|
|
980
|
-
});
|
|
981
|
-
},
|
|
982
|
-
onMessage: (message, { state, resolve, reject }) => {
|
|
983
|
-
if (message.type === "error") {
|
|
984
|
-
options.outputFormatter.setContext({ sessionId: options.sessionId });
|
|
985
|
-
const queueErrorAlreadyEmitted = options.errorEmissionPolicy?.queueErrorAlreadyEmitted ?? true;
|
|
986
|
-
if (!(message.outputAlreadyEmitted === true) || !queueErrorAlreadyEmitted) {
|
|
987
|
-
options.outputFormatter.onError({
|
|
988
|
-
code: message.code ?? "RUNTIME",
|
|
989
|
-
detailCode: message.detailCode,
|
|
990
|
-
origin: message.origin ?? "queue",
|
|
991
|
-
message: message.message,
|
|
992
|
-
retryable: message.retryable,
|
|
993
|
-
acp: message.acp
|
|
994
|
-
});
|
|
995
|
-
options.outputFormatter.flush();
|
|
996
|
-
}
|
|
997
|
-
reject(new QueueConnectionError(message.message, {
|
|
998
|
-
outputCode: message.code,
|
|
999
|
-
detailCode: message.detailCode,
|
|
1000
|
-
origin: message.origin ?? "queue",
|
|
1001
|
-
retryable: message.retryable,
|
|
1002
|
-
acp: message.acp,
|
|
1003
|
-
...queueErrorAlreadyEmitted ? { outputAlreadyEmitted: true } : {}
|
|
1004
|
-
}));
|
|
1005
|
-
return;
|
|
1006
|
-
}
|
|
1007
|
-
if (!state.acknowledged) {
|
|
1008
|
-
reject(new QueueConnectionError("Queue owner did not acknowledge request", {
|
|
1009
|
-
detailCode: "QUEUE_ACK_MISSING",
|
|
1010
|
-
origin: "queue",
|
|
1011
|
-
retryable: true
|
|
1012
|
-
}));
|
|
1013
|
-
return;
|
|
1014
|
-
}
|
|
1015
|
-
if (message.type === "event") {
|
|
1016
|
-
options.outputFormatter.onAcpMessage(message.message);
|
|
1017
|
-
return;
|
|
1018
|
-
}
|
|
1019
|
-
if (message.type === "result") {
|
|
1020
|
-
options.outputFormatter.flush();
|
|
1021
|
-
resolve(message.result);
|
|
1022
|
-
return;
|
|
1023
|
-
}
|
|
1024
|
-
reject(new QueueProtocolError("Queue owner returned unexpected response", {
|
|
1025
|
-
detailCode: "QUEUE_PROTOCOL_UNEXPECTED_RESPONSE",
|
|
1026
|
-
origin: "queue",
|
|
1027
|
-
retryable: true
|
|
1028
|
-
}));
|
|
1029
|
-
},
|
|
1030
|
-
onClose: ({ state, resolve, reject }) => {
|
|
1031
|
-
if (!state.acknowledged) {
|
|
1032
|
-
reject(new QueueConnectionError("Queue owner disconnected before acknowledging request", {
|
|
1033
|
-
detailCode: "QUEUE_DISCONNECTED_BEFORE_ACK",
|
|
1034
|
-
origin: "queue",
|
|
1035
|
-
retryable: true
|
|
1036
|
-
}));
|
|
1037
|
-
return;
|
|
1038
|
-
}
|
|
1039
|
-
if (!options.waitForCompletion) {
|
|
1040
|
-
resolve({
|
|
1041
|
-
queued: true,
|
|
1042
|
-
sessionId: options.sessionId,
|
|
1043
|
-
requestId
|
|
1044
|
-
});
|
|
1045
|
-
return;
|
|
1046
|
-
}
|
|
1047
|
-
reject(new QueueConnectionError("Queue owner disconnected before prompt completion", {
|
|
1048
|
-
detailCode: "QUEUE_DISCONNECTED_BEFORE_COMPLETION",
|
|
1049
|
-
origin: "queue",
|
|
1050
|
-
retryable: true
|
|
1051
|
-
}));
|
|
1052
|
-
}
|
|
1053
|
-
});
|
|
1054
|
-
}
|
|
1055
|
-
async function submitControlToQueueOwner(owner, request, isExpectedResponse) {
|
|
1056
|
-
return await runQueueOwnerRequest({
|
|
1057
|
-
owner,
|
|
1058
|
-
request,
|
|
1059
|
-
onMessage: (message, { state, resolve, reject }) => {
|
|
1060
|
-
if (message.type === "error") {
|
|
1061
|
-
reject(new QueueConnectionError(message.message, {
|
|
1062
|
-
outputCode: message.code,
|
|
1063
|
-
detailCode: message.detailCode,
|
|
1064
|
-
origin: message.origin ?? "queue",
|
|
1065
|
-
retryable: message.retryable,
|
|
1066
|
-
acp: message.acp
|
|
1067
|
-
}));
|
|
1068
|
-
return;
|
|
1069
|
-
}
|
|
1070
|
-
if (!state.acknowledged) {
|
|
1071
|
-
reject(new QueueConnectionError("Queue owner did not acknowledge request", {
|
|
1072
|
-
detailCode: "QUEUE_ACK_MISSING",
|
|
1073
|
-
origin: "queue",
|
|
1074
|
-
retryable: true
|
|
1075
|
-
}));
|
|
1076
|
-
return;
|
|
1077
|
-
}
|
|
1078
|
-
if (!isExpectedResponse(message)) {
|
|
1079
|
-
reject(new QueueProtocolError("Queue owner returned unexpected response", {
|
|
1080
|
-
detailCode: "QUEUE_PROTOCOL_UNEXPECTED_RESPONSE",
|
|
1081
|
-
origin: "queue",
|
|
1082
|
-
retryable: true
|
|
1083
|
-
}));
|
|
1084
|
-
return;
|
|
1085
|
-
}
|
|
1086
|
-
resolve(message);
|
|
1087
|
-
},
|
|
1088
|
-
onClose: ({ state, reject }) => {
|
|
1089
|
-
if (!state.acknowledged) {
|
|
1090
|
-
reject(new QueueConnectionError("Queue owner disconnected before acknowledging request", {
|
|
1091
|
-
detailCode: "QUEUE_DISCONNECTED_BEFORE_ACK",
|
|
1092
|
-
origin: "queue",
|
|
1093
|
-
retryable: true
|
|
1094
|
-
}));
|
|
1095
|
-
return;
|
|
1096
|
-
}
|
|
1097
|
-
reject(new QueueConnectionError("Queue owner disconnected before responding", {
|
|
1098
|
-
detailCode: "QUEUE_DISCONNECTED_BEFORE_COMPLETION",
|
|
1099
|
-
origin: "queue",
|
|
1100
|
-
retryable: true
|
|
1101
|
-
}));
|
|
1102
|
-
}
|
|
1103
|
-
});
|
|
1104
|
-
}
|
|
1105
|
-
async function submitCancelToQueueOwner(owner) {
|
|
1106
|
-
const request = {
|
|
1107
|
-
type: "cancel_prompt",
|
|
1108
|
-
requestId: randomUUID(),
|
|
1109
|
-
ownerGeneration: owner.ownerGeneration
|
|
1110
|
-
};
|
|
1111
|
-
const response = await submitControlToQueueOwner(owner, request, (message) => message.type === "cancel_result");
|
|
1112
|
-
if (!response) return;
|
|
1113
|
-
if (response.requestId !== request.requestId) throw new QueueProtocolError("Queue owner returned mismatched cancel response", {
|
|
1114
|
-
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
1115
|
-
origin: "queue",
|
|
1116
|
-
retryable: true
|
|
1117
|
-
});
|
|
1118
|
-
return response.cancelled;
|
|
1119
|
-
}
|
|
1120
|
-
async function submitSetModeToQueueOwner(owner, modeId, timeoutMs) {
|
|
1121
|
-
const request = {
|
|
1122
|
-
type: "set_mode",
|
|
1123
|
-
requestId: randomUUID(),
|
|
1124
|
-
ownerGeneration: owner.ownerGeneration,
|
|
1125
|
-
modeId,
|
|
1126
|
-
timeoutMs
|
|
1127
|
-
};
|
|
1128
|
-
const response = await submitControlToQueueOwner(owner, request, (message) => message.type === "set_mode_result");
|
|
1129
|
-
if (!response) return;
|
|
1130
|
-
if (response.requestId !== request.requestId) throw new QueueProtocolError("Queue owner returned mismatched set_mode response", {
|
|
1131
|
-
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
1132
|
-
origin: "queue",
|
|
1133
|
-
retryable: true
|
|
1134
|
-
});
|
|
1135
|
-
return true;
|
|
1136
|
-
}
|
|
1137
|
-
async function submitSetModelToQueueOwner(owner, modelId, timeoutMs) {
|
|
1138
|
-
const request = {
|
|
1139
|
-
type: "set_model",
|
|
1140
|
-
requestId: randomUUID(),
|
|
1141
|
-
ownerGeneration: owner.ownerGeneration,
|
|
1142
|
-
modelId,
|
|
1143
|
-
timeoutMs
|
|
1144
|
-
};
|
|
1145
|
-
const response = await submitControlToQueueOwner(owner, request, (message) => message.type === "set_model_result");
|
|
1146
|
-
if (!response) return;
|
|
1147
|
-
if (response.requestId !== request.requestId) throw new QueueProtocolError("Queue owner returned mismatched set_model response", {
|
|
1148
|
-
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
1149
|
-
origin: "queue",
|
|
1150
|
-
retryable: true
|
|
1151
|
-
});
|
|
1152
|
-
return true;
|
|
1153
|
-
}
|
|
1154
|
-
async function submitSetConfigOptionToQueueOwner(owner, configId, value, timeoutMs) {
|
|
1155
|
-
const request = {
|
|
1156
|
-
type: "set_config_option",
|
|
1157
|
-
requestId: randomUUID(),
|
|
1158
|
-
ownerGeneration: owner.ownerGeneration,
|
|
1159
|
-
configId,
|
|
1160
|
-
value,
|
|
1161
|
-
timeoutMs
|
|
1162
|
-
};
|
|
1163
|
-
const response = await submitControlToQueueOwner(owner, request, (message) => message.type === "set_config_option_result");
|
|
1164
|
-
if (!response) return;
|
|
1165
|
-
if (response.requestId !== request.requestId) throw new QueueProtocolError("Queue owner returned mismatched set_config_option response", {
|
|
1166
|
-
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
1167
|
-
origin: "queue",
|
|
1168
|
-
retryable: true
|
|
1169
|
-
});
|
|
1170
|
-
return response.response;
|
|
1171
|
-
}
|
|
1172
|
-
async function submitCloseSessionToQueueOwner(owner, timeoutMs) {
|
|
1173
|
-
const request = {
|
|
1174
|
-
type: "close_session",
|
|
1175
|
-
requestId: randomUUID(),
|
|
1176
|
-
ownerGeneration: owner.ownerGeneration,
|
|
1177
|
-
timeoutMs
|
|
1178
|
-
};
|
|
1179
|
-
const response = await submitControlToQueueOwner(owner, request, (message) => message.type === "close_session_result");
|
|
1180
|
-
if (!response) return;
|
|
1181
|
-
if (response.requestId !== request.requestId) throw new QueueProtocolError("Queue owner returned mismatched close_session response", {
|
|
1182
|
-
detailCode: "QUEUE_PROTOCOL_MALFORMED_MESSAGE",
|
|
1183
|
-
origin: "queue",
|
|
1184
|
-
retryable: true
|
|
1185
|
-
});
|
|
1186
|
-
return response.closed;
|
|
1187
|
-
}
|
|
1188
|
-
async function trySubmitToRunningOwner(options) {
|
|
1189
|
-
const owner = await readQueueOwnerRecord(options.sessionId);
|
|
1190
|
-
if (!owner) return;
|
|
1191
|
-
let submitted;
|
|
1192
|
-
try {
|
|
1193
|
-
submitted = await submitToQueueOwner(owner, options);
|
|
1194
|
-
} catch (error) {
|
|
1195
|
-
if (await maybeRecoverStaleOwnerAfterProtocolMismatch({
|
|
1196
|
-
sessionId: options.sessionId,
|
|
1197
|
-
owner,
|
|
1198
|
-
error,
|
|
1199
|
-
verbose: options.verbose
|
|
1200
|
-
})) return;
|
|
1201
|
-
throw error;
|
|
1202
|
-
}
|
|
1203
|
-
if (submitted) {
|
|
1204
|
-
if (options.verbose) process.stderr.write(`[acpx] queued prompt on active owner pid ${owner.pid} for session ${options.sessionId}\n`);
|
|
1205
|
-
return submitted;
|
|
1206
|
-
}
|
|
1207
|
-
if (!(await probeQueueOwnerHealth(options.sessionId)).hasLease) return;
|
|
1208
|
-
throw new QueueConnectionError("Session queue owner is running but not accepting queue requests", {
|
|
1209
|
-
detailCode: "QUEUE_NOT_ACCEPTING_REQUESTS",
|
|
1210
|
-
origin: "queue",
|
|
1211
|
-
retryable: true
|
|
1212
|
-
});
|
|
1213
|
-
}
|
|
1214
|
-
async function tryCloseSessionOnRunningOwner(options) {
|
|
1215
|
-
const owner = await readQueueOwnerRecord(options.sessionId);
|
|
1216
|
-
if (!owner) return;
|
|
1217
|
-
const closed = await submitCloseSessionToQueueOwner(owner, options.timeoutMs);
|
|
1218
|
-
if (closed !== void 0) {
|
|
1219
|
-
if (options.verbose) process.stderr.write(`[acpx] requested session/close on active owner pid ${owner.pid} for session ${options.sessionId}\n`);
|
|
1220
|
-
return closed;
|
|
1221
|
-
}
|
|
1222
|
-
if (!(await probeQueueOwnerHealth(options.sessionId)).hasLease) return;
|
|
1223
|
-
throw new QueueConnectionError("Session queue owner is running but not accepting close_session requests", {
|
|
1224
|
-
detailCode: "QUEUE_NOT_ACCEPTING_REQUESTS",
|
|
1225
|
-
origin: "queue",
|
|
1226
|
-
retryable: true
|
|
1227
|
-
});
|
|
1228
|
-
}
|
|
1229
|
-
async function tryCancelOnRunningOwner(options) {
|
|
1230
|
-
const owner = await readQueueOwnerRecord(options.sessionId);
|
|
1231
|
-
if (!owner) return;
|
|
1232
|
-
const cancelled = await submitCancelToQueueOwner(owner);
|
|
1233
|
-
if (cancelled !== void 0) {
|
|
1234
|
-
if (options.verbose) process.stderr.write(`[acpx] requested cancel on active owner pid ${owner.pid} for session ${options.sessionId}\n`);
|
|
1235
|
-
return cancelled;
|
|
1236
|
-
}
|
|
1237
|
-
if (!(await probeQueueOwnerHealth(options.sessionId)).hasLease) return;
|
|
1238
|
-
throw new QueueConnectionError("Session queue owner is running but not accepting cancel requests", {
|
|
1239
|
-
detailCode: "QUEUE_NOT_ACCEPTING_REQUESTS",
|
|
1240
|
-
origin: "queue",
|
|
1241
|
-
retryable: true
|
|
1242
|
-
});
|
|
1243
|
-
}
|
|
1244
|
-
async function trySetModeOnRunningOwner(sessionId, modeId, timeoutMs, verbose) {
|
|
1245
|
-
const owner = await readQueueOwnerRecord(sessionId);
|
|
1246
|
-
if (!owner) return;
|
|
1247
|
-
if (await submitSetModeToQueueOwner(owner, modeId, timeoutMs)) {
|
|
1248
|
-
if (verbose) process.stderr.write(`[acpx] requested session/set_mode on owner pid ${owner.pid} for session ${sessionId}\n`);
|
|
1249
|
-
return true;
|
|
1250
|
-
}
|
|
1251
|
-
if (!(await probeQueueOwnerHealth(sessionId)).hasLease) return;
|
|
1252
|
-
throw new QueueConnectionError("Session queue owner is running but not accepting set_mode requests", {
|
|
1253
|
-
detailCode: "QUEUE_NOT_ACCEPTING_REQUESTS",
|
|
1254
|
-
origin: "queue",
|
|
1255
|
-
retryable: true
|
|
1256
|
-
});
|
|
1257
|
-
}
|
|
1258
|
-
async function trySetModelOnRunningOwner(sessionId, modelId, timeoutMs, verbose) {
|
|
1259
|
-
const owner = await readQueueOwnerRecord(sessionId);
|
|
1260
|
-
if (!owner) return;
|
|
1261
|
-
if (await submitSetModelToQueueOwner(owner, modelId, timeoutMs)) {
|
|
1262
|
-
if (verbose) process.stderr.write(`[acpx] requested session/set_model on owner pid ${owner.pid} for session ${sessionId}\n`);
|
|
1263
|
-
return true;
|
|
1264
|
-
}
|
|
1265
|
-
if (!(await probeQueueOwnerHealth(sessionId)).hasLease) return;
|
|
1266
|
-
throw new QueueConnectionError("Session queue owner is running but not accepting set_model requests", {
|
|
1267
|
-
detailCode: "QUEUE_NOT_ACCEPTING_REQUESTS",
|
|
1268
|
-
origin: "queue",
|
|
1269
|
-
retryable: true
|
|
1270
|
-
});
|
|
1271
|
-
}
|
|
1272
|
-
async function trySetConfigOptionOnRunningOwner(sessionId, configId, value, timeoutMs, verbose) {
|
|
1273
|
-
const owner = await readQueueOwnerRecord(sessionId);
|
|
1274
|
-
if (!owner) return;
|
|
1275
|
-
const response = await submitSetConfigOptionToQueueOwner(owner, configId, value, timeoutMs);
|
|
1276
|
-
if (response) {
|
|
1277
|
-
if (verbose) process.stderr.write(`[acpx] requested session/set_config_option on owner pid ${owner.pid} for session ${sessionId}\n`);
|
|
1278
|
-
return response;
|
|
1279
|
-
}
|
|
1280
|
-
if (!(await probeQueueOwnerHealth(sessionId)).hasLease) return;
|
|
1281
|
-
throw new QueueConnectionError("Session queue owner is running but not accepting set_config_option requests", {
|
|
1282
|
-
detailCode: "QUEUE_NOT_ACCEPTING_REQUESTS",
|
|
1283
|
-
origin: "queue",
|
|
1284
|
-
retryable: true
|
|
1285
|
-
});
|
|
1286
|
-
}
|
|
1287
|
-
//#endregion
|
|
1288
|
-
export { trySetModelOnRunningOwner as a, probeQueueOwnerHealth as c, releaseQueueOwnerLease as d, terminateProcess as f, waitMs as h, trySetModeOnRunningOwner as i, isProcessAlive as l, tryAcquireQueueOwnerLease as m, tryCloseSessionOnRunningOwner as n, trySubmitToRunningOwner as o, terminateQueueOwnerForSession as p, trySetConfigOptionOnRunningOwner as r, SessionQueueOwner as s, tryCancelOnRunningOwner as t, refreshQueueOwnerLease as u };
|
|
1289
|
-
|
|
1290
|
-
//# sourceMappingURL=ipc-ABXlXzGP.js.map
|