acpx 0.4.1 → 0.5.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/dist/agent-registry-DGw0-3Tc.js +54 -0
- package/dist/agent-registry-DGw0-3Tc.js.map +1 -0
- package/dist/{cli-idpWyCOs.js → cli-CLRrs6eQ.js} +8 -12
- package/dist/cli-CLRrs6eQ.js.map +1 -0
- package/dist/cli.d.ts +2 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1018 -1009
- package/dist/cli.js.map +1 -1
- package/dist/client-DLTWuu4w.d.ts +116 -0
- package/dist/client-DLTWuu4w.d.ts.map +1 -0
- package/dist/{flags-CCcX9fZj.js → flags-BmubjvOw.js} +5 -55
- package/dist/flags-BmubjvOw.js.map +1 -0
- package/dist/{flows-BL1tSvZT.js → flows-CR7xCmkR.js} +471 -281
- package/dist/flows-CR7xCmkR.js.map +1 -0
- package/dist/flows.d.ts +5 -9
- package/dist/flows.d.ts.map +1 -1
- package/dist/flows.js +1 -1
- package/dist/{queue-ipc-CE8_QGX3.js → ipc-DN6M4Ui9.js} +12 -571
- package/dist/ipc-DN6M4Ui9.js.map +1 -0
- package/dist/{acp-jsonrpc-BbBgC5gO.js → jsonrpc-M3y-qzy8.js} +2 -2
- package/dist/jsonrpc-M3y-qzy8.js.map +1 -0
- package/dist/{output-Du3m6oPQ.js → output-Di0M9Et8.js} +6 -6
- package/dist/output-Di0M9Et8.js.map +1 -0
- package/dist/perf-metrics-D9QC81lB.js +568 -0
- package/dist/perf-metrics-D9QC81lB.js.map +1 -0
- package/dist/{session-RO_LZUnv.js → prompt-turn-Bt8T3SRR.js} +2304 -3632
- package/dist/prompt-turn-Bt8T3SRR.js.map +1 -0
- package/dist/{output-render-Bz58qaQn.js → render-BL5ynRkN.js} +7 -6
- package/dist/render-BL5ynRkN.js.map +1 -0
- package/dist/runtime.d.ts +266 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +984 -0
- package/dist/runtime.js.map +1 -0
- package/dist/session-BbN0SBgf.js +1488 -0
- package/dist/session-BbN0SBgf.js.map +1 -0
- package/dist/{types-CeRKmEQ1.d.ts → types-DXxLBQc3.d.ts} +40 -3
- package/dist/types-DXxLBQc3.d.ts.map +1 -0
- package/package.json +5 -3
- package/dist/acp-jsonrpc-BbBgC5gO.js.map +0 -1
- package/dist/cli-idpWyCOs.js.map +0 -1
- package/dist/flags-CCcX9fZj.js.map +0 -1
- package/dist/flows-BL1tSvZT.js.map +0 -1
- package/dist/output-Du3m6oPQ.js.map +0 -1
- package/dist/output-render-Bz58qaQn.js.map +0 -1
- package/dist/queue-ipc-CE8_QGX3.js.map +0 -1
- package/dist/session-RO_LZUnv.js.map +0 -1
- package/dist/types-CeRKmEQ1.d.ts.map +0 -1
|
@@ -1,570 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { B as QueueConnectionError, D as OUTPUT_ERROR_CODES, O as OUTPUT_ERROR_ORIGINS, V as QueueProtocolError, a as recordPerfDuration, f as isPromptInput, g as textPrompt, i as measurePerf, r as incrementPerfCounter, x as normalizeOutputError } from "./perf-metrics-D9QC81lB.js";
|
|
2
|
+
import { n as isAcpJsonRpcMessage } from "./jsonrpc-M3y-qzy8.js";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import fs from "node:fs/promises";
|
|
4
5
|
import os from "node:os";
|
|
5
6
|
import { createHash, randomUUID } from "node:crypto";
|
|
6
7
|
import net from "node:net";
|
|
7
|
-
//#region src/
|
|
8
|
-
const RESOURCE_NOT_FOUND_ACP_CODES = new Set([-32001, -32002]);
|
|
9
|
-
function asRecord$3(value) {
|
|
10
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
11
|
-
return value;
|
|
12
|
-
}
|
|
13
|
-
function toAcpErrorPayload(value) {
|
|
14
|
-
const record = asRecord$3(value);
|
|
15
|
-
if (!record) return;
|
|
16
|
-
if (typeof record.code !== "number" || !Number.isFinite(record.code)) return;
|
|
17
|
-
if (typeof record.message !== "string" || record.message.length === 0) return;
|
|
18
|
-
return {
|
|
19
|
-
code: record.code,
|
|
20
|
-
message: record.message,
|
|
21
|
-
data: record.data
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
function extractAcpErrorInternal(value, depth) {
|
|
25
|
-
if (depth > 5) return;
|
|
26
|
-
const direct = toAcpErrorPayload(value);
|
|
27
|
-
if (direct) return direct;
|
|
28
|
-
const record = asRecord$3(value);
|
|
29
|
-
if (!record) return;
|
|
30
|
-
if ("error" in record) {
|
|
31
|
-
const nested = extractAcpErrorInternal(record.error, depth + 1);
|
|
32
|
-
if (nested) return nested;
|
|
33
|
-
}
|
|
34
|
-
if ("acp" in record) {
|
|
35
|
-
const nested = extractAcpErrorInternal(record.acp, depth + 1);
|
|
36
|
-
if (nested) return nested;
|
|
37
|
-
}
|
|
38
|
-
if ("cause" in record) {
|
|
39
|
-
const nested = extractAcpErrorInternal(record.cause, depth + 1);
|
|
40
|
-
if (nested) return nested;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
function formatUnknownErrorMessage(error) {
|
|
44
|
-
if (error instanceof Error) return error.message;
|
|
45
|
-
if (error && typeof error === "object") {
|
|
46
|
-
const maybeMessage = error.message;
|
|
47
|
-
if (typeof maybeMessage === "string" && maybeMessage.length > 0) return maybeMessage;
|
|
48
|
-
try {
|
|
49
|
-
return JSON.stringify(error);
|
|
50
|
-
} catch {}
|
|
51
|
-
}
|
|
52
|
-
return String(error);
|
|
53
|
-
}
|
|
54
|
-
const SESSION_NOT_FOUND_PATTERN = /session\s+["'\w-]+\s+not found/i;
|
|
55
|
-
function isSessionNotFoundText(value) {
|
|
56
|
-
if (typeof value !== "string") return false;
|
|
57
|
-
const normalized = value.toLowerCase();
|
|
58
|
-
return normalized.includes("resource_not_found") || normalized.includes("resource not found") || normalized.includes("session not found") || normalized.includes("unknown session") || normalized.includes("invalid session identifier") || SESSION_NOT_FOUND_PATTERN.test(value);
|
|
59
|
-
}
|
|
60
|
-
function hasSessionNotFoundHint(value, depth = 0) {
|
|
61
|
-
if (depth > 4) return false;
|
|
62
|
-
if (isSessionNotFoundText(value)) return true;
|
|
63
|
-
if (Array.isArray(value)) return value.some((entry) => hasSessionNotFoundHint(entry, depth + 1));
|
|
64
|
-
const record = asRecord$3(value);
|
|
65
|
-
if (!record) return false;
|
|
66
|
-
return Object.values(record).some((entry) => hasSessionNotFoundHint(entry, depth + 1));
|
|
67
|
-
}
|
|
68
|
-
function extractAcpError(error) {
|
|
69
|
-
return extractAcpErrorInternal(error, 0);
|
|
70
|
-
}
|
|
71
|
-
function isAcpResourceNotFoundError(error) {
|
|
72
|
-
const acp = extractAcpError(error);
|
|
73
|
-
if (acp && RESOURCE_NOT_FOUND_ACP_CODES.has(acp.code)) return true;
|
|
74
|
-
if (acp) {
|
|
75
|
-
if (isSessionNotFoundText(acp.message)) return true;
|
|
76
|
-
if (hasSessionNotFoundHint(acp.data)) return true;
|
|
77
|
-
}
|
|
78
|
-
return isSessionNotFoundText(formatUnknownErrorMessage(error));
|
|
79
|
-
}
|
|
80
|
-
//#endregion
|
|
81
|
-
//#region src/errors.ts
|
|
82
|
-
var AcpxOperationalError = class extends Error {
|
|
83
|
-
outputCode;
|
|
84
|
-
detailCode;
|
|
85
|
-
origin;
|
|
86
|
-
retryable;
|
|
87
|
-
acp;
|
|
88
|
-
outputAlreadyEmitted;
|
|
89
|
-
constructor(message, options) {
|
|
90
|
-
super(message, options);
|
|
91
|
-
this.name = new.target.name;
|
|
92
|
-
this.outputCode = options?.outputCode;
|
|
93
|
-
this.detailCode = options?.detailCode;
|
|
94
|
-
this.origin = options?.origin;
|
|
95
|
-
this.retryable = options?.retryable;
|
|
96
|
-
this.acp = options?.acp;
|
|
97
|
-
this.outputAlreadyEmitted = options?.outputAlreadyEmitted;
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
var SessionNotFoundError = class extends AcpxOperationalError {
|
|
101
|
-
sessionId;
|
|
102
|
-
constructor(sessionId) {
|
|
103
|
-
super(`Session not found: ${sessionId}`);
|
|
104
|
-
this.sessionId = sessionId;
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
var SessionResolutionError = class extends AcpxOperationalError {};
|
|
108
|
-
var AgentSpawnError = class extends AcpxOperationalError {
|
|
109
|
-
agentCommand;
|
|
110
|
-
constructor(agentCommand, cause) {
|
|
111
|
-
super(`Failed to spawn agent command: ${agentCommand}`, { cause: cause instanceof Error ? cause : void 0 });
|
|
112
|
-
this.agentCommand = agentCommand;
|
|
113
|
-
}
|
|
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
|
-
};
|
|
142
|
-
var GeminiAcpStartupTimeoutError = class extends AcpxOperationalError {
|
|
143
|
-
constructor(message, options) {
|
|
144
|
-
super(message, {
|
|
145
|
-
outputCode: "TIMEOUT",
|
|
146
|
-
detailCode: "GEMINI_ACP_STARTUP_TIMEOUT",
|
|
147
|
-
origin: "acp",
|
|
148
|
-
...options
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
var SessionModeReplayError = class extends AcpxOperationalError {
|
|
153
|
-
constructor(message, options) {
|
|
154
|
-
super(message, {
|
|
155
|
-
outputCode: "RUNTIME",
|
|
156
|
-
detailCode: "SESSION_MODE_REPLAY_FAILED",
|
|
157
|
-
origin: "acp",
|
|
158
|
-
...options
|
|
159
|
-
});
|
|
160
|
-
}
|
|
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
|
-
};
|
|
172
|
-
var ClaudeAcpSessionCreateTimeoutError = class extends AcpxOperationalError {
|
|
173
|
-
constructor(message, options) {
|
|
174
|
-
super(message, {
|
|
175
|
-
outputCode: "TIMEOUT",
|
|
176
|
-
detailCode: "CLAUDE_ACP_SESSION_CREATE_TIMEOUT",
|
|
177
|
-
origin: "acp",
|
|
178
|
-
...options
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
};
|
|
182
|
-
var CopilotAcpUnsupportedError = class extends AcpxOperationalError {
|
|
183
|
-
constructor(message, options) {
|
|
184
|
-
super(message, {
|
|
185
|
-
outputCode: "RUNTIME",
|
|
186
|
-
detailCode: "COPILOT_ACP_UNSUPPORTED",
|
|
187
|
-
origin: "acp",
|
|
188
|
-
...options
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
var AuthPolicyError = class extends AcpxOperationalError {
|
|
193
|
-
constructor(message, options) {
|
|
194
|
-
super(message, {
|
|
195
|
-
outputCode: "RUNTIME",
|
|
196
|
-
detailCode: "AUTH_REQUIRED",
|
|
197
|
-
origin: "acp",
|
|
198
|
-
...options
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
};
|
|
202
|
-
var QueueConnectionError = class extends AcpxOperationalError {};
|
|
203
|
-
var QueueProtocolError = class extends AcpxOperationalError {};
|
|
204
|
-
var PermissionDeniedError = class extends AcpxOperationalError {};
|
|
205
|
-
var PermissionPromptUnavailableError = class extends AcpxOperationalError {
|
|
206
|
-
constructor() {
|
|
207
|
-
super("Permission prompt unavailable in non-interactive mode");
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
//#endregion
|
|
211
|
-
//#region src/prompt-content.ts
|
|
212
|
-
var PromptInputValidationError = class extends Error {
|
|
213
|
-
constructor(message) {
|
|
214
|
-
super(message);
|
|
215
|
-
this.name = "PromptInputValidationError";
|
|
216
|
-
}
|
|
217
|
-
};
|
|
218
|
-
function asRecord$2(value) {
|
|
219
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
220
|
-
return value;
|
|
221
|
-
}
|
|
222
|
-
function isNonEmptyString(value) {
|
|
223
|
-
return typeof value === "string" && value.trim().length > 0;
|
|
224
|
-
}
|
|
225
|
-
function isBase64Data(value) {
|
|
226
|
-
if (value.length === 0 || value.length % 4 !== 0) return false;
|
|
227
|
-
return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value);
|
|
228
|
-
}
|
|
229
|
-
function isImageMimeType(value) {
|
|
230
|
-
return /^image\/[A-Za-z0-9.+-]+$/i.test(value);
|
|
231
|
-
}
|
|
232
|
-
function isTextBlock(value) {
|
|
233
|
-
const record = asRecord$2(value);
|
|
234
|
-
return record?.type === "text" && typeof record.text === "string";
|
|
235
|
-
}
|
|
236
|
-
function isImageBlock(value) {
|
|
237
|
-
const record = asRecord$2(value);
|
|
238
|
-
return record?.type === "image" && isNonEmptyString(record.mimeType) && isImageMimeType(record.mimeType) && typeof record.data === "string" && isBase64Data(record.data);
|
|
239
|
-
}
|
|
240
|
-
function isResourceLinkBlock(value) {
|
|
241
|
-
const record = asRecord$2(value);
|
|
242
|
-
return record?.type === "resource_link" && isNonEmptyString(record.uri) && (record.title === void 0 || typeof record.title === "string") && (record.name === void 0 || typeof record.name === "string");
|
|
243
|
-
}
|
|
244
|
-
function isResourcePayload(value) {
|
|
245
|
-
const record = asRecord$2(value);
|
|
246
|
-
if (!record || !isNonEmptyString(record.uri)) return false;
|
|
247
|
-
return record.text === void 0 || typeof record.text === "string";
|
|
248
|
-
}
|
|
249
|
-
function isResourceBlock(value) {
|
|
250
|
-
const record = asRecord$2(value);
|
|
251
|
-
return record?.type === "resource" && isResourcePayload(record.resource);
|
|
252
|
-
}
|
|
253
|
-
function isContentBlock(value) {
|
|
254
|
-
return isTextBlock(value) || isImageBlock(value) || isResourceLinkBlock(value) || isResourceBlock(value);
|
|
255
|
-
}
|
|
256
|
-
function getContentBlockValidationError(value, index) {
|
|
257
|
-
const record = asRecord$2(value);
|
|
258
|
-
if (!record || typeof record.type !== "string") return `prompt[${index}] must be an ACP content block object`;
|
|
259
|
-
switch (record.type) {
|
|
260
|
-
case "text": return typeof record.text === "string" ? void 0 : `prompt[${index}] text block must include a string text field`;
|
|
261
|
-
case "image":
|
|
262
|
-
if (!isNonEmptyString(record.mimeType)) return `prompt[${index}] image block must include a non-empty mimeType`;
|
|
263
|
-
if (!isImageMimeType(record.mimeType)) return `prompt[${index}] image block mimeType must start with image/`;
|
|
264
|
-
if (typeof record.data !== "string" || record.data.length === 0) return `prompt[${index}] image block must include non-empty base64 data`;
|
|
265
|
-
if (!isBase64Data(record.data)) return `prompt[${index}] image block data must be valid base64`;
|
|
266
|
-
return;
|
|
267
|
-
case "resource_link":
|
|
268
|
-
if (!isNonEmptyString(record.uri)) return `prompt[${index}] resource_link block must include a non-empty uri`;
|
|
269
|
-
if (record.title !== void 0 && typeof record.title !== "string") return `prompt[${index}] resource_link block title must be a string when present`;
|
|
270
|
-
if (record.name !== void 0 && typeof record.name !== "string") return `prompt[${index}] resource_link block name must be a string when present`;
|
|
271
|
-
return;
|
|
272
|
-
case "resource":
|
|
273
|
-
if (!asRecord$2(record.resource)) return `prompt[${index}] resource block must include a resource object`;
|
|
274
|
-
if (!isResourcePayload(record.resource)) return `prompt[${index}] resource block resource must include a non-empty uri and optional text`;
|
|
275
|
-
return;
|
|
276
|
-
default: return `prompt[${index}] has unsupported content block type ${JSON.stringify(record.type)}`;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
function isPromptInput(value) {
|
|
280
|
-
return Array.isArray(value) && value.every((entry) => isContentBlock(entry));
|
|
281
|
-
}
|
|
282
|
-
function textPrompt(text) {
|
|
283
|
-
return [{
|
|
284
|
-
type: "text",
|
|
285
|
-
text
|
|
286
|
-
}];
|
|
287
|
-
}
|
|
288
|
-
function parseStructuredPrompt(source) {
|
|
289
|
-
if (!source.startsWith("[")) return;
|
|
290
|
-
try {
|
|
291
|
-
const parsed = JSON.parse(source);
|
|
292
|
-
if (isPromptInput(parsed)) return parsed;
|
|
293
|
-
if (Array.isArray(parsed)) throw new PromptInputValidationError(parsed.map((entry, index) => getContentBlockValidationError(entry, index)).find((message) => message !== void 0) ?? "Structured prompt JSON must be an array of valid ACP content blocks");
|
|
294
|
-
return;
|
|
295
|
-
} catch (error) {
|
|
296
|
-
if (error instanceof PromptInputValidationError) throw error;
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
function parsePromptSource(source) {
|
|
301
|
-
const trimmed = source.trim();
|
|
302
|
-
const structured = parseStructuredPrompt(trimmed);
|
|
303
|
-
if (structured) return structured;
|
|
304
|
-
if (!trimmed) return [];
|
|
305
|
-
return textPrompt(trimmed);
|
|
306
|
-
}
|
|
307
|
-
function mergePromptSourceWithText(source, suffixText) {
|
|
308
|
-
const prompt = parsePromptSource(source);
|
|
309
|
-
const appended = suffixText.trim();
|
|
310
|
-
if (!appended) return prompt;
|
|
311
|
-
if (prompt.length === 0) return textPrompt(appended);
|
|
312
|
-
return [...prompt, ...textPrompt(appended)];
|
|
313
|
-
}
|
|
314
|
-
function promptToDisplayText(prompt) {
|
|
315
|
-
return prompt.map((block) => {
|
|
316
|
-
switch (block.type) {
|
|
317
|
-
case "text": return block.text;
|
|
318
|
-
case "resource_link": return block.title ?? block.name ?? block.uri;
|
|
319
|
-
case "resource": return "text" in block.resource && typeof block.resource.text === "string" ? block.resource.text : block.resource.uri;
|
|
320
|
-
case "image": return `[image] ${block.mimeType}`;
|
|
321
|
-
default: return "";
|
|
322
|
-
}
|
|
323
|
-
}).filter((entry) => entry.trim().length > 0).join("\n\n").trim();
|
|
324
|
-
}
|
|
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
|
|
354
|
-
//#region src/types.ts
|
|
355
|
-
const EXIT_CODES = {
|
|
356
|
-
SUCCESS: 0,
|
|
357
|
-
ERROR: 1,
|
|
358
|
-
USAGE: 2,
|
|
359
|
-
TIMEOUT: 3,
|
|
360
|
-
NO_SESSION: 4,
|
|
361
|
-
PERMISSION_DENIED: 5,
|
|
362
|
-
INTERRUPTED: 130
|
|
363
|
-
};
|
|
364
|
-
const OUTPUT_FORMATS = [
|
|
365
|
-
"text",
|
|
366
|
-
"json",
|
|
367
|
-
"quiet"
|
|
368
|
-
];
|
|
369
|
-
const AUTH_POLICIES = ["skip", "fail"];
|
|
370
|
-
const NON_INTERACTIVE_PERMISSION_POLICIES = ["deny", "fail"];
|
|
371
|
-
const OUTPUT_ERROR_CODES = [
|
|
372
|
-
"NO_SESSION",
|
|
373
|
-
"TIMEOUT",
|
|
374
|
-
"PERMISSION_DENIED",
|
|
375
|
-
"PERMISSION_PROMPT_UNAVAILABLE",
|
|
376
|
-
"RUNTIME",
|
|
377
|
-
"USAGE"
|
|
378
|
-
];
|
|
379
|
-
const OUTPUT_ERROR_ORIGINS = [
|
|
380
|
-
"cli",
|
|
381
|
-
"runtime",
|
|
382
|
-
"queue",
|
|
383
|
-
"acp"
|
|
384
|
-
];
|
|
385
|
-
const SESSION_RECORD_SCHEMA = "acpx.session.v1";
|
|
386
|
-
//#endregion
|
|
387
|
-
//#region src/error-normalization.ts
|
|
388
|
-
const AUTH_REQUIRED_ACP_CODES = new Set([-32e3]);
|
|
389
|
-
const QUERY_CLOSED_BEFORE_RESPONSE_DETAIL = "query closed before response received";
|
|
390
|
-
function asRecord$1(value) {
|
|
391
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
392
|
-
return value;
|
|
393
|
-
}
|
|
394
|
-
function isAuthRequiredMessage(value) {
|
|
395
|
-
if (!value) return false;
|
|
396
|
-
const normalized = value.toLowerCase();
|
|
397
|
-
return normalized.includes("auth required") || normalized.includes("authentication required") || normalized.includes("authorization required") || normalized.includes("credential required") || normalized.includes("credentials required") || normalized.includes("token required") || normalized.includes("login required");
|
|
398
|
-
}
|
|
399
|
-
function isAcpAuthRequiredPayload(acp) {
|
|
400
|
-
if (!acp) return false;
|
|
401
|
-
if (!AUTH_REQUIRED_ACP_CODES.has(acp.code)) return false;
|
|
402
|
-
if (isAuthRequiredMessage(acp.message)) return true;
|
|
403
|
-
const data = asRecord$1(acp.data);
|
|
404
|
-
if (!data) return false;
|
|
405
|
-
if (data.authRequired === true) return true;
|
|
406
|
-
const methodId = data.methodId;
|
|
407
|
-
if (typeof methodId === "string" && methodId.trim().length > 0) return true;
|
|
408
|
-
const methods = data.methods;
|
|
409
|
-
if (Array.isArray(methods) && methods.length > 0) return true;
|
|
410
|
-
return false;
|
|
411
|
-
}
|
|
412
|
-
function isOutputErrorCode$1(value) {
|
|
413
|
-
return typeof value === "string" && OUTPUT_ERROR_CODES.includes(value);
|
|
414
|
-
}
|
|
415
|
-
function isOutputErrorOrigin$1(value) {
|
|
416
|
-
return typeof value === "string" && OUTPUT_ERROR_ORIGINS.includes(value);
|
|
417
|
-
}
|
|
418
|
-
function readOutputErrorMeta(error) {
|
|
419
|
-
const record = asRecord$1(error);
|
|
420
|
-
if (!record) return {};
|
|
421
|
-
return {
|
|
422
|
-
outputCode: isOutputErrorCode$1(record.outputCode) ? record.outputCode : void 0,
|
|
423
|
-
detailCode: typeof record.detailCode === "string" && record.detailCode.trim().length > 0 ? record.detailCode : void 0,
|
|
424
|
-
origin: isOutputErrorOrigin$1(record.origin) ? record.origin : void 0,
|
|
425
|
-
retryable: typeof record.retryable === "boolean" ? record.retryable : void 0,
|
|
426
|
-
acp: extractAcpError(record.acp)
|
|
427
|
-
};
|
|
428
|
-
}
|
|
429
|
-
function isTimeoutLike(error) {
|
|
430
|
-
return error instanceof Error && error.name === "TimeoutError";
|
|
431
|
-
}
|
|
432
|
-
function isNoSessionLike(error) {
|
|
433
|
-
return error instanceof Error && error.name === "NoSessionError";
|
|
434
|
-
}
|
|
435
|
-
function isUsageLike(error) {
|
|
436
|
-
if (!(error instanceof Error)) return false;
|
|
437
|
-
return error.name === "CommanderError" || error.name === "InvalidArgumentError" || asRecord$1(error)?.code === "commander.invalidArgument";
|
|
438
|
-
}
|
|
439
|
-
function formatErrorMessage(error) {
|
|
440
|
-
return formatUnknownErrorMessage(error);
|
|
441
|
-
}
|
|
442
|
-
function isAcpQueryClosedBeforeResponseError(error) {
|
|
443
|
-
const acp = extractAcpError(error);
|
|
444
|
-
if (!acp || acp.code !== -32603) return false;
|
|
445
|
-
const details = asRecord$1(acp.data)?.details;
|
|
446
|
-
if (typeof details !== "string") return false;
|
|
447
|
-
return details.toLowerCase().includes(QUERY_CLOSED_BEFORE_RESPONSE_DETAIL);
|
|
448
|
-
}
|
|
449
|
-
function mapErrorCode(error) {
|
|
450
|
-
if (error instanceof PermissionPromptUnavailableError) return "PERMISSION_PROMPT_UNAVAILABLE";
|
|
451
|
-
if (error instanceof PermissionDeniedError) return "PERMISSION_DENIED";
|
|
452
|
-
if (isTimeoutLike(error)) return "TIMEOUT";
|
|
453
|
-
if (isNoSessionLike(error) || isAcpResourceNotFoundError(error)) return "NO_SESSION";
|
|
454
|
-
if (isUsageLike(error)) return "USAGE";
|
|
455
|
-
}
|
|
456
|
-
function normalizeOutputError(error, options = {}) {
|
|
457
|
-
const meta = readOutputErrorMeta(error);
|
|
458
|
-
let code = mapErrorCode(error) ?? options.defaultCode ?? "RUNTIME";
|
|
459
|
-
if (meta.outputCode) code = meta.outputCode;
|
|
460
|
-
if (code === "RUNTIME" && isAcpResourceNotFoundError(error)) code = "NO_SESSION";
|
|
461
|
-
const acp = options.acp ?? meta.acp ?? extractAcpError(error);
|
|
462
|
-
const detailCode = meta.detailCode ?? options.detailCode ?? (error instanceof AuthPolicyError || isAcpAuthRequiredPayload(acp) ? "AUTH_REQUIRED" : void 0);
|
|
463
|
-
return {
|
|
464
|
-
code,
|
|
465
|
-
message: formatErrorMessage(error),
|
|
466
|
-
detailCode,
|
|
467
|
-
origin: meta.origin ?? options.origin,
|
|
468
|
-
retryable: meta.retryable ?? options.retryable,
|
|
469
|
-
acp
|
|
470
|
-
};
|
|
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
|
-
}
|
|
490
|
-
function exitCodeForOutputErrorCode(code) {
|
|
491
|
-
switch (code) {
|
|
492
|
-
case "USAGE": return EXIT_CODES.USAGE;
|
|
493
|
-
case "TIMEOUT": return EXIT_CODES.TIMEOUT;
|
|
494
|
-
case "NO_SESSION": return EXIT_CODES.NO_SESSION;
|
|
495
|
-
case "PERMISSION_DENIED":
|
|
496
|
-
case "PERMISSION_PROMPT_UNAVAILABLE": return EXIT_CODES.PERMISSION_DENIED;
|
|
497
|
-
default: return EXIT_CODES.ERROR;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
//#endregion
|
|
501
|
-
//#region src/perf-metrics.ts
|
|
502
|
-
const counters = /* @__PURE__ */ new Map();
|
|
503
|
-
const gauges = /* @__PURE__ */ new Map();
|
|
504
|
-
const timings = /* @__PURE__ */ new Map();
|
|
505
|
-
function hrNow() {
|
|
506
|
-
return process.hrtime.bigint();
|
|
507
|
-
}
|
|
508
|
-
function durationMs(start) {
|
|
509
|
-
return Number(process.hrtime.bigint() - start) / 1e6;
|
|
510
|
-
}
|
|
511
|
-
function roundMetric(value) {
|
|
512
|
-
return Number(value.toFixed(3));
|
|
513
|
-
}
|
|
514
|
-
function incrementPerfCounter(name, delta = 1) {
|
|
515
|
-
counters.set(name, (counters.get(name) ?? 0) + delta);
|
|
516
|
-
}
|
|
517
|
-
function setPerfGauge(name, value) {
|
|
518
|
-
gauges.set(name, value);
|
|
519
|
-
}
|
|
520
|
-
function recordPerfDuration(name, durationMsValue) {
|
|
521
|
-
const next = timings.get(name) ?? {
|
|
522
|
-
count: 0,
|
|
523
|
-
totalMs: 0,
|
|
524
|
-
maxMs: 0
|
|
525
|
-
};
|
|
526
|
-
next.count += 1;
|
|
527
|
-
next.totalMs += durationMsValue;
|
|
528
|
-
next.maxMs = Math.max(next.maxMs, durationMsValue);
|
|
529
|
-
timings.set(name, next);
|
|
530
|
-
}
|
|
531
|
-
async function measurePerf(name, run) {
|
|
532
|
-
const startedAt = hrNow();
|
|
533
|
-
try {
|
|
534
|
-
return await run();
|
|
535
|
-
} finally {
|
|
536
|
-
recordPerfDuration(name, durationMs(startedAt));
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
function startPerfTimer(name) {
|
|
540
|
-
const startedAt = hrNow();
|
|
541
|
-
return () => {
|
|
542
|
-
const elapsedMs = durationMs(startedAt);
|
|
543
|
-
recordPerfDuration(name, elapsedMs);
|
|
544
|
-
return elapsedMs;
|
|
545
|
-
};
|
|
546
|
-
}
|
|
547
|
-
function getPerfMetricsSnapshot() {
|
|
548
|
-
return {
|
|
549
|
-
counters: Object.fromEntries(counters.entries()),
|
|
550
|
-
gauges: Object.fromEntries(gauges.entries()),
|
|
551
|
-
timings: Object.fromEntries([...timings.entries()].map(([name, bucket]) => [name, {
|
|
552
|
-
count: bucket.count,
|
|
553
|
-
totalMs: roundMetric(bucket.totalMs),
|
|
554
|
-
maxMs: roundMetric(bucket.maxMs)
|
|
555
|
-
}]))
|
|
556
|
-
};
|
|
557
|
-
}
|
|
558
|
-
function resetPerfMetrics() {
|
|
559
|
-
counters.clear();
|
|
560
|
-
gauges.clear();
|
|
561
|
-
timings.clear();
|
|
562
|
-
}
|
|
563
|
-
function formatPerfMetric(name, durationMsValue) {
|
|
564
|
-
return `${name}=${roundMetric(durationMsValue)}ms`;
|
|
565
|
-
}
|
|
566
|
-
//#endregion
|
|
567
|
-
//#region src/queue-paths.ts
|
|
8
|
+
//#region src/cli/queue/paths.ts
|
|
568
9
|
function shortHash(value, length) {
|
|
569
10
|
return createHash("sha256").update(value).digest("hex").slice(0, length);
|
|
570
11
|
}
|
|
@@ -587,7 +28,7 @@ function queueSocketPath(sessionId, homeDir = os.homedir()) {
|
|
|
587
28
|
return path.join(queueSocketBaseDir(homeDir) ?? "/tmp", `${key}.sock`);
|
|
588
29
|
}
|
|
589
30
|
//#endregion
|
|
590
|
-
//#region src/queue
|
|
31
|
+
//#region src/cli/queue/lease-store.ts
|
|
591
32
|
const PROCESS_EXIT_GRACE_MS = 1500;
|
|
592
33
|
const PROCESS_POLL_MS = 50;
|
|
593
34
|
const QUEUE_OWNER_STALE_HEARTBEAT_MS = 15e3;
|
|
@@ -773,7 +214,7 @@ async function waitMs(ms) {
|
|
|
773
214
|
});
|
|
774
215
|
}
|
|
775
216
|
//#endregion
|
|
776
|
-
//#region src/queue
|
|
217
|
+
//#region src/cli/queue/ipc-transport.ts
|
|
777
218
|
const QUEUE_CONNECT_ATTEMPTS = 40;
|
|
778
219
|
const SOCKET_CONNECTION_TIMEOUT_MS = 5e3;
|
|
779
220
|
function shouldRetryQueueConnect(error) {
|
|
@@ -821,7 +262,7 @@ async function connectToQueueOwner(owner, maxAttempts = QUEUE_CONNECT_ATTEMPTS)
|
|
|
821
262
|
if (lastError && !shouldRetryQueueConnect(lastError)) throw lastError;
|
|
822
263
|
}
|
|
823
264
|
//#endregion
|
|
824
|
-
//#region src/queue
|
|
265
|
+
//#region src/cli/queue/ipc-health.ts
|
|
825
266
|
async function probeQueueOwnerHealth(sessionId) {
|
|
826
267
|
const ownerRecord = await readQueueOwnerRecord(sessionId);
|
|
827
268
|
if (!ownerRecord) return {
|
|
@@ -863,7 +304,7 @@ async function probeQueueOwnerHealth(sessionId) {
|
|
|
863
304
|
};
|
|
864
305
|
}
|
|
865
306
|
//#endregion
|
|
866
|
-
//#region src/queue
|
|
307
|
+
//#region src/cli/queue/messages.ts
|
|
867
308
|
function asRecord(value) {
|
|
868
309
|
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
869
310
|
return value;
|
|
@@ -1065,7 +506,7 @@ function parseQueueOwnerMessage(raw) {
|
|
|
1065
506
|
return null;
|
|
1066
507
|
}
|
|
1067
508
|
//#endregion
|
|
1068
|
-
//#region src/queue
|
|
509
|
+
//#region src/cli/queue/ipc-server.ts
|
|
1069
510
|
function makeQueueOwnerError(requestId, message, detailCode, options = {}) {
|
|
1070
511
|
return {
|
|
1071
512
|
type: "error",
|
|
@@ -1351,7 +792,7 @@ var SessionQueueOwner = class SessionQueueOwner {
|
|
|
1351
792
|
}
|
|
1352
793
|
};
|
|
1353
794
|
//#endregion
|
|
1354
|
-
//#region src/queue
|
|
795
|
+
//#region src/cli/queue/ipc.ts
|
|
1355
796
|
const MAX_MESSAGE_BUFFER_SIZE = 10 * 1024 * 1024;
|
|
1356
797
|
const STALE_OWNER_PROTOCOL_DETAIL_CODES = new Set(["QUEUE_PROTOCOL_MALFORMED_MESSAGE", "QUEUE_PROTOCOL_UNEXPECTED_RESPONSE"]);
|
|
1357
798
|
async function maybeRecoverStaleOwnerAfterProtocolMismatch(params) {
|
|
@@ -1764,6 +1205,6 @@ async function trySetConfigOptionOnRunningOwner(sessionId, configId, value, time
|
|
|
1764
1205
|
});
|
|
1765
1206
|
}
|
|
1766
1207
|
//#endregion
|
|
1767
|
-
export {
|
|
1208
|
+
export { trySubmitToRunningOwner as a, isProcessAlive as c, terminateProcess as d, terminateQueueOwnerForSession as f, trySetModelOnRunningOwner as i, refreshQueueOwnerLease as l, waitMs as m, trySetConfigOptionOnRunningOwner as n, SessionQueueOwner as o, tryAcquireQueueOwnerLease as p, trySetModeOnRunningOwner as r, probeQueueOwnerHealth as s, tryCancelOnRunningOwner as t, releaseQueueOwnerLease as u };
|
|
1768
1209
|
|
|
1769
|
-
//# sourceMappingURL=
|
|
1210
|
+
//# sourceMappingURL=ipc-DN6M4Ui9.js.map
|