poe-code 8.0.1 → 9.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/harness.js +28 -3
- package/dist/cli/commands/harness.js.map +1 -1
- package/dist/index.js +1516 -711
- package/dist/index.js.map +4 -4
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/safejs/dist/chunks/chunk-4YIDX44G.js +40 -0
- package/packages/safejs/dist/chunks/chunk-4YIDX44G.js.map +7 -0
- package/packages/safejs/dist/chunks/chunk-55ZK3CR7.js +7802 -0
- package/packages/safejs/dist/chunks/chunk-55ZK3CR7.js.map +7 -0
- package/packages/safejs/dist/chunks/{chunk-ME5BTAZT.js → chunk-GQBEEFVQ.js} +150 -19
- package/packages/safejs/dist/chunks/{chunk-ME5BTAZT.js.map → chunk-GQBEEFVQ.js.map} +4 -4
- package/packages/safejs/dist/chunks/chunk-NI4WFFTL.js +5701 -0
- package/packages/safejs/dist/chunks/chunk-NI4WFFTL.js.map +7 -0
- package/packages/safejs/dist/chunks/inMemory-RLZ4QGDZ.js +48 -0
- package/packages/safejs/dist/chunks/inMemory-RLZ4QGDZ.js.map +7 -0
- package/packages/safejs/dist/chunks/server-3SNT3RE2.js +12518 -0
- package/packages/safejs/dist/chunks/server-3SNT3RE2.js.map +7 -0
- package/packages/safejs/dist/chunks/types-BTF37PZ6.js +348 -0
- package/packages/safejs/dist/chunks/types-BTF37PZ6.js.map +7 -0
- package/packages/safejs/dist/cli.d.ts +2 -0
- package/packages/safejs/dist/cli.js +26 -2
- package/packages/safejs/dist/cli.js.map +2 -2
- package/packages/safejs/dist/core.js +2 -1
- package/packages/safejs/dist/index.d.ts +3 -0
- package/packages/safejs/dist/index.js +6 -287
- package/packages/safejs/dist/index.js.map +4 -4
- package/packages/safejs/dist/interp/host-bridge.d.ts +2 -0
- package/packages/safejs/dist/interp/host-bridge.js +20 -9
- package/packages/safejs/dist/interp/host-call.d.ts +5 -0
- package/packages/safejs/dist/interp/host-call.js +48 -3
- package/packages/safejs/dist/interp/resources.d.ts +7 -0
- package/packages/safejs/dist/interp/resources.js +36 -0
- package/packages/safejs/dist/modules/mcp-transport.d.ts +26 -0
- package/packages/safejs/dist/modules/mcp-transport.js +259 -0
- package/packages/safejs/dist/modules/mcp.d.ts +15 -1
- package/packages/safejs/dist/modules/mcp.js +107 -0
- package/packages/safejs/dist/run.js +6 -3
- package/packages/safejs/dist/snapshot/dump-format.d.ts +1 -1
- package/packages/safejs/dist/snapshot/dump-format.js +1 -1
- package/packages/safejs/dist/snapshot/replay-data.d.ts +1 -0
- package/packages/safejs/dist/snapshot/replay-data.js +3 -1
- package/packages/safejs/dist/snapshot/replay-inputs.d.ts +2 -2
- package/packages/safejs/dist/snapshot/replay-inputs.js +2 -1
- package/packages/safejs/dist/chunks/chunk-AVDRLE3Y.js +0 -3461
- package/packages/safejs/dist/chunks/chunk-AVDRLE3Y.js.map +0 -7
|
@@ -1,3461 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
SandboxError,
|
|
3
|
-
activateOtelSpan,
|
|
4
|
-
bindOtelSpan,
|
|
5
|
-
declareHostOperation,
|
|
6
|
-
deepCopyToSandbox,
|
|
7
|
-
getActiveOtelSink,
|
|
8
|
-
getOwnErrorCode,
|
|
9
|
-
hasOwnErrorCode,
|
|
10
|
-
hostErrorData,
|
|
11
|
-
isSandboxClosure,
|
|
12
|
-
safeAddEvent,
|
|
13
|
-
safeEndSpan,
|
|
14
|
-
safeRecordException,
|
|
15
|
-
safeStartSpan
|
|
16
|
-
} from "./chunk-ME5BTAZT.js";
|
|
17
|
-
|
|
18
|
-
// packages/safejs/src/error/format.ts
|
|
19
|
-
var DEFAULT_MAX_MESSAGE_LENGTH = 1e4;
|
|
20
|
-
var MAX_CAUSE_DEPTH = 20;
|
|
21
|
-
function formatInterpreterError(first, second) {
|
|
22
|
-
if (typeof first === "string" && isInterpreterDiagnostic(second)) {
|
|
23
|
-
return formatSourceDiagnostic(first, second, {
|
|
24
|
-
maxMessageLength: DEFAULT_MAX_MESSAGE_LENGTH
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
const options = second;
|
|
28
|
-
const formatted = formatTopLevelError(first, normalizeOptions(options));
|
|
29
|
-
if (options?.hostCallName === void 0) {
|
|
30
|
-
return formatted;
|
|
31
|
-
}
|
|
32
|
-
return wrapHostCall(formatted, options.hostCallName);
|
|
33
|
-
}
|
|
34
|
-
function normalizeOptions(options) {
|
|
35
|
-
return {
|
|
36
|
-
filename: options?.filename ?? "<input>",
|
|
37
|
-
hostCallName: options?.hostCallName ?? "",
|
|
38
|
-
maxMessageLength: options?.maxMessageLength ?? DEFAULT_MAX_MESSAGE_LENGTH,
|
|
39
|
-
source: options?.source ?? ""
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
function formatTopLevelError(error, options) {
|
|
43
|
-
if (isParseDiagnostic(error)) {
|
|
44
|
-
return formatParseDiagnostic(error, options.maxMessageLength);
|
|
45
|
-
}
|
|
46
|
-
if (error instanceof SandboxError) {
|
|
47
|
-
return formatSandboxError(error, options.maxMessageLength);
|
|
48
|
-
}
|
|
49
|
-
if (isSpanDiagnostic(error)) {
|
|
50
|
-
if (options.source === "") {
|
|
51
|
-
return truncate(error.message, options.maxMessageLength);
|
|
52
|
-
}
|
|
53
|
-
return formatSourceDiagnostic(options.source, {
|
|
54
|
-
kind: "InterpreterError",
|
|
55
|
-
filename: options.filename,
|
|
56
|
-
line: error.span.start.line,
|
|
57
|
-
column: error.span.start.column,
|
|
58
|
-
message: error.message
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
if (isErrorLike(error)) {
|
|
62
|
-
return formatErrorLike(error, options.maxMessageLength);
|
|
63
|
-
}
|
|
64
|
-
return `Thrown value: ${truncate(describeThrownValue(error), options.maxMessageLength)}`;
|
|
65
|
-
}
|
|
66
|
-
function formatParseDiagnostic(error, maxMessageLength) {
|
|
67
|
-
return [
|
|
68
|
-
`${error.kind}: ${error.filename}:${error.line}:${error.column}`,
|
|
69
|
-
"",
|
|
70
|
-
error.excerpt,
|
|
71
|
-
error.caret,
|
|
72
|
-
"",
|
|
73
|
-
truncate(error.message, maxMessageLength)
|
|
74
|
-
].join("\n");
|
|
75
|
-
}
|
|
76
|
-
function formatSandboxError(error, maxMessageLength) {
|
|
77
|
-
const lines = [formatErrorSummary(error, maxMessageLength)];
|
|
78
|
-
if (error.code === "budgetExceeded" && error.budget !== void 0) {
|
|
79
|
-
lines.push("", `Budget exceeded: ${error.budget} (${error.current} > ${error.limit})`);
|
|
80
|
-
}
|
|
81
|
-
return lines.join("\n");
|
|
82
|
-
}
|
|
83
|
-
function formatErrorLike(error, maxMessageLength) {
|
|
84
|
-
const stack = formatSandboxStack(error, maxMessageLength);
|
|
85
|
-
const causes = formatCauses(error, maxMessageLength);
|
|
86
|
-
if (causes.length === 0) {
|
|
87
|
-
return stack;
|
|
88
|
-
}
|
|
89
|
-
return [stack, "", ...causes].join("\n");
|
|
90
|
-
}
|
|
91
|
-
function formatSandboxStack(error, maxMessageLength) {
|
|
92
|
-
if (typeof error.stack !== "string") {
|
|
93
|
-
return formatErrorSummary(error, maxMessageLength);
|
|
94
|
-
}
|
|
95
|
-
const stackLines = splitLines(error.stack);
|
|
96
|
-
const header = stackLines[0] === void 0 || stackLines[0] === "" ? void 0 : stackLines[0];
|
|
97
|
-
const sandboxFrames = stackLines.slice(1).filter(isSandboxStackFrame);
|
|
98
|
-
if (sandboxFrames.length === 0) {
|
|
99
|
-
return formatErrorSummary(error, maxMessageLength);
|
|
100
|
-
}
|
|
101
|
-
return [
|
|
102
|
-
truncate(header ?? formatErrorSummary(error, maxMessageLength), maxMessageLength),
|
|
103
|
-
...sandboxFrames
|
|
104
|
-
].join("\n");
|
|
105
|
-
}
|
|
106
|
-
function isSandboxStackFrame(line) {
|
|
107
|
-
const trimmed = line.trimStart();
|
|
108
|
-
return trimmed.startsWith("at ") && trimmed.includes("(line ") && trimmed.includes(", column ") && trimmed.endsWith(")");
|
|
109
|
-
}
|
|
110
|
-
function formatCauses(error, maxMessageLength) {
|
|
111
|
-
const causes = [];
|
|
112
|
-
const seen = /* @__PURE__ */ new Set();
|
|
113
|
-
let current = readCause(error);
|
|
114
|
-
for (let depth = 0; depth < MAX_CAUSE_DEPTH && current !== void 0; depth += 1) {
|
|
115
|
-
if (seen.has(current)) {
|
|
116
|
-
causes.push("Caused by: [Circular cause]");
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
seen.add(current);
|
|
120
|
-
causes.push(`Caused by: ${formatCause(current, maxMessageLength)}`);
|
|
121
|
-
current = isObject(current) ? readCause(current) : void 0;
|
|
122
|
-
}
|
|
123
|
-
return causes;
|
|
124
|
-
}
|
|
125
|
-
function formatCause(cause, maxMessageLength) {
|
|
126
|
-
if (cause instanceof SandboxError) {
|
|
127
|
-
return formatErrorSummary(cause, maxMessageLength);
|
|
128
|
-
}
|
|
129
|
-
if (isErrorLike(cause)) {
|
|
130
|
-
return formatErrorSummary(cause, maxMessageLength);
|
|
131
|
-
}
|
|
132
|
-
return truncate(describeThrownValue(cause), maxMessageLength);
|
|
133
|
-
}
|
|
134
|
-
function readCause(value) {
|
|
135
|
-
return Object.prototype.hasOwnProperty.call(value, "cause") ? value.cause : void 0;
|
|
136
|
-
}
|
|
137
|
-
function wrapHostCall(formatted, hostCallName) {
|
|
138
|
-
const lines = splitLines(formatted);
|
|
139
|
-
const [firstLine = "", ...rest] = lines;
|
|
140
|
-
return [`Host call ${hostCallName} failed: ${firstLine}`, ...rest].join("\n");
|
|
141
|
-
}
|
|
142
|
-
function formatSourceDiagnostic(source, error, options = {}) {
|
|
143
|
-
const lines = splitLines(source);
|
|
144
|
-
const excerpt = createExcerpt(lines, error.line);
|
|
145
|
-
const lineNumberWidth = String(
|
|
146
|
-
excerpt[excerpt.length - 1]?.number ?? Math.max(error.line, 1)
|
|
147
|
-
).length;
|
|
148
|
-
const reportedLine = excerpt.find((line) => line.number === Math.max(error.line, 1)) ?? excerpt[excerpt.length - 1];
|
|
149
|
-
const caretPadding = createCaretPadding(
|
|
150
|
-
reportedLine?.content ?? "",
|
|
151
|
-
error.column,
|
|
152
|
-
reportedLine?.hasSource === true
|
|
153
|
-
);
|
|
154
|
-
return [
|
|
155
|
-
`${error.kind}: ${error.filename}:${error.line}:${error.column}`,
|
|
156
|
-
"",
|
|
157
|
-
...excerpt.map((line) => `${String(line.number).padStart(lineNumberWidth)} | ${line.content}`),
|
|
158
|
-
`${" ".repeat(lineNumberWidth)} | ${caretPadding}^`,
|
|
159
|
-
"",
|
|
160
|
-
truncate(error.message, options.maxMessageLength ?? DEFAULT_MAX_MESSAGE_LENGTH)
|
|
161
|
-
].join("\n");
|
|
162
|
-
}
|
|
163
|
-
function formatErrorSummary(error, maxMessageLength) {
|
|
164
|
-
const name = typeof error.name === "string" && error.name !== "" ? error.name : "Error";
|
|
165
|
-
const message = typeof error.message === "string" ? error.message : "";
|
|
166
|
-
if (message === "") {
|
|
167
|
-
return name;
|
|
168
|
-
}
|
|
169
|
-
return `${name}: ${truncate(message, maxMessageLength)}`;
|
|
170
|
-
}
|
|
171
|
-
function truncate(message, maxLength) {
|
|
172
|
-
if (message.length <= maxLength) {
|
|
173
|
-
return message;
|
|
174
|
-
}
|
|
175
|
-
return `${message.slice(0, maxLength)}... [truncated ${message.length - maxLength} chars]`;
|
|
176
|
-
}
|
|
177
|
-
function describeThrownValue(value) {
|
|
178
|
-
if (typeof value === "string") {
|
|
179
|
-
return JSON.stringify(value);
|
|
180
|
-
}
|
|
181
|
-
if (value === void 0 || value === null || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
182
|
-
return String(value);
|
|
183
|
-
}
|
|
184
|
-
if (typeof value === "symbol" || typeof value === "function") {
|
|
185
|
-
return safeString(value, "[Unserializable thrown value]");
|
|
186
|
-
}
|
|
187
|
-
return stringifyJsonish(value);
|
|
188
|
-
}
|
|
189
|
-
function stringifyJsonish(value) {
|
|
190
|
-
const seen = /* @__PURE__ */ new WeakSet();
|
|
191
|
-
try {
|
|
192
|
-
return JSON.stringify(value, (_key, nested) => {
|
|
193
|
-
if (typeof nested === "bigint") {
|
|
194
|
-
return String(nested);
|
|
195
|
-
}
|
|
196
|
-
if (!isObject(nested)) {
|
|
197
|
-
return nested;
|
|
198
|
-
}
|
|
199
|
-
if (seen.has(nested)) {
|
|
200
|
-
return "[Circular]";
|
|
201
|
-
}
|
|
202
|
-
seen.add(nested);
|
|
203
|
-
return nested;
|
|
204
|
-
});
|
|
205
|
-
} catch {
|
|
206
|
-
return safeString(value, "[Unserializable thrown value]");
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
function safeString(value, fallback) {
|
|
210
|
-
try {
|
|
211
|
-
return String(value);
|
|
212
|
-
} catch {
|
|
213
|
-
return fallback;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
function isInterpreterDiagnostic(value) {
|
|
217
|
-
return isObject(value) && typeof value.kind === "string" && typeof value.filename === "string" && typeof value.line === "number" && typeof value.column === "number" && typeof value.message === "string";
|
|
218
|
-
}
|
|
219
|
-
function isParseDiagnostic(value) {
|
|
220
|
-
return isInterpreterDiagnostic(value) && value.kind === "ParseError" && typeof value.excerpt === "string" && typeof value.caret === "string";
|
|
221
|
-
}
|
|
222
|
-
function isSpanDiagnostic(value) {
|
|
223
|
-
return isObject(value) && typeof value.message === "string" && isObject(value.span) && isObject(value.span.start) && typeof value.span.start.line === "number" && typeof value.span.start.column === "number";
|
|
224
|
-
}
|
|
225
|
-
function isErrorLike(value) {
|
|
226
|
-
if (!isObject(value)) {
|
|
227
|
-
return false;
|
|
228
|
-
}
|
|
229
|
-
return value instanceof Error || typeof value.name === "string" || typeof value.message === "string" || typeof value.stack === "string";
|
|
230
|
-
}
|
|
231
|
-
function isObject(value) {
|
|
232
|
-
return typeof value === "object" && value !== null;
|
|
233
|
-
}
|
|
234
|
-
function createExcerpt(sourceLines, reportedLine) {
|
|
235
|
-
const safeLineNumber = Math.max(reportedLine, 1);
|
|
236
|
-
if (safeLineNumber > sourceLines.length) {
|
|
237
|
-
return [
|
|
238
|
-
{
|
|
239
|
-
number: safeLineNumber,
|
|
240
|
-
content: "",
|
|
241
|
-
hasSource: false
|
|
242
|
-
}
|
|
243
|
-
];
|
|
244
|
-
}
|
|
245
|
-
const excerpt = [];
|
|
246
|
-
const startLine = Math.max(1, safeLineNumber - 2);
|
|
247
|
-
const endLine = Math.min(sourceLines.length, safeLineNumber + 1);
|
|
248
|
-
for (let line = startLine; line <= endLine; line += 1) {
|
|
249
|
-
excerpt.push({
|
|
250
|
-
number: line,
|
|
251
|
-
content: sourceLines[line - 1] ?? "",
|
|
252
|
-
hasSource: true
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
return excerpt;
|
|
256
|
-
}
|
|
257
|
-
function splitLines(source) {
|
|
258
|
-
return source.split(/\r\n|\n|\r/);
|
|
259
|
-
}
|
|
260
|
-
function createCaretPadding(line, column, hasSource) {
|
|
261
|
-
let padding = "";
|
|
262
|
-
const maxColumn = hasSource ? Math.max(Math.min(column - 1, line.length), 0) : Math.max(column - 1, 0);
|
|
263
|
-
for (const character of line.slice(0, maxColumn)) {
|
|
264
|
-
padding += character === " " ? " " : " ";
|
|
265
|
-
}
|
|
266
|
-
if (maxColumn > line.length) {
|
|
267
|
-
padding += " ".repeat(maxColumn - line.length);
|
|
268
|
-
}
|
|
269
|
-
return padding;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// packages/safejs/src/loader/extract-block.ts
|
|
273
|
-
function extractBlock(markdown, startLine = 1) {
|
|
274
|
-
let index = 0;
|
|
275
|
-
let line = startLine;
|
|
276
|
-
const blocks = [];
|
|
277
|
-
while (index < markdown.length) {
|
|
278
|
-
const lineStart = index;
|
|
279
|
-
const lineEnd = findLineEnd(markdown, index);
|
|
280
|
-
const lineContent = markdown.slice(lineStart, lineEnd.index);
|
|
281
|
-
const fence = readOpeningFence(lineContent);
|
|
282
|
-
if (fence !== void 0) {
|
|
283
|
-
const blockStart = lineEnd.index + lineEnd.lineBreakLength;
|
|
284
|
-
const closingFence = findClosingFence(markdown, blockStart, fence);
|
|
285
|
-
if (matchesScriptInfo(fence.info)) {
|
|
286
|
-
if (!closingFence.found) {
|
|
287
|
-
throw new Error(
|
|
288
|
-
`Unclosed ${readInfoWord(fence.info)} fenced block opened at line ${line}.`
|
|
289
|
-
);
|
|
290
|
-
}
|
|
291
|
-
blocks.push({ start: blockStart, end: closingFence.start, line });
|
|
292
|
-
}
|
|
293
|
-
const resumeIndex = findBlockResumeIndex(markdown, closingFence);
|
|
294
|
-
line += countLineBreaks(markdown, index, resumeIndex);
|
|
295
|
-
index = resumeIndex;
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
if (lineEnd.lineBreakLength === 0) {
|
|
299
|
-
break;
|
|
300
|
-
}
|
|
301
|
-
index = lineEnd.index + lineEnd.lineBreakLength;
|
|
302
|
-
line += 1;
|
|
303
|
-
}
|
|
304
|
-
if (blocks.length === 0)
|
|
305
|
-
return {
|
|
306
|
-
endOffset: markdown.length,
|
|
307
|
-
lineOffset: 1,
|
|
308
|
-
source: markdown,
|
|
309
|
-
startOffset: 0,
|
|
310
|
-
ranges: [[0, markdown.length]]
|
|
311
|
-
};
|
|
312
|
-
const first = blocks[0];
|
|
313
|
-
const parts = [];
|
|
314
|
-
let cursor = first.start;
|
|
315
|
-
for (const block of blocks) {
|
|
316
|
-
let gap = "";
|
|
317
|
-
for (let offset = cursor; offset < block.start; offset++) {
|
|
318
|
-
const character = markdown[offset];
|
|
319
|
-
gap += character === "\n" || character === "\r" ? character : " ";
|
|
320
|
-
}
|
|
321
|
-
parts.push(gap, markdown.slice(block.start, block.end));
|
|
322
|
-
cursor = block.end;
|
|
323
|
-
}
|
|
324
|
-
return {
|
|
325
|
-
endOffset: cursor,
|
|
326
|
-
lineOffset: first.line,
|
|
327
|
-
source: parts.join(""),
|
|
328
|
-
startOffset: first.start,
|
|
329
|
-
ranges: blocks.map((block) => [block.start, block.end])
|
|
330
|
-
};
|
|
331
|
-
}
|
|
332
|
-
function readOpeningFence(line) {
|
|
333
|
-
const fenceStart = readFenceStart(line);
|
|
334
|
-
if (fenceStart === void 0) {
|
|
335
|
-
return void 0;
|
|
336
|
-
}
|
|
337
|
-
let markerEnd = fenceStart.indentLength;
|
|
338
|
-
while (line[markerEnd] === fenceStart.markerCharacter) {
|
|
339
|
-
markerEnd += 1;
|
|
340
|
-
}
|
|
341
|
-
const marker = line.slice(fenceStart.indentLength, markerEnd);
|
|
342
|
-
if (marker.length < 3) {
|
|
343
|
-
return void 0;
|
|
344
|
-
}
|
|
345
|
-
const info = line.slice(markerEnd).trimStart();
|
|
346
|
-
return {
|
|
347
|
-
indent: line.slice(0, fenceStart.indentLength),
|
|
348
|
-
marker,
|
|
349
|
-
markerCharacter: fenceStart.markerCharacter,
|
|
350
|
-
info
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
function readFenceStart(line) {
|
|
354
|
-
let index = 0;
|
|
355
|
-
while (index < line.length && line[index] === " ") {
|
|
356
|
-
index += 1;
|
|
357
|
-
}
|
|
358
|
-
const markerCharacter = line[index];
|
|
359
|
-
return markerCharacter === "`" || markerCharacter === "~" ? {
|
|
360
|
-
indentLength: index,
|
|
361
|
-
markerCharacter
|
|
362
|
-
} : void 0;
|
|
363
|
-
}
|
|
364
|
-
function matchesScriptInfo(info) {
|
|
365
|
-
const infoWord = readInfoWord(info);
|
|
366
|
-
return infoWord === "js" || infoWord === "javascript" || infoWord === "ajs";
|
|
367
|
-
}
|
|
368
|
-
function readInfoWord(info) {
|
|
369
|
-
let index = 0;
|
|
370
|
-
while (index < info.length && !isWhitespace(info[index])) {
|
|
371
|
-
index += 1;
|
|
372
|
-
}
|
|
373
|
-
return info.slice(0, index);
|
|
374
|
-
}
|
|
375
|
-
function isWhitespace(character) {
|
|
376
|
-
return character === " " || character === " ";
|
|
377
|
-
}
|
|
378
|
-
function findBlockResumeIndex(markdown, closingFence) {
|
|
379
|
-
if (!closingFence.found || closingFence.start >= markdown.length) {
|
|
380
|
-
return markdown.length;
|
|
381
|
-
}
|
|
382
|
-
const closingLineEnd = findLineEnd(markdown, closingFence.start);
|
|
383
|
-
return closingLineEnd.index + closingLineEnd.lineBreakLength;
|
|
384
|
-
}
|
|
385
|
-
function countLineBreaks(markdown, start = 0, end = markdown.length) {
|
|
386
|
-
let count = 0;
|
|
387
|
-
let index = start;
|
|
388
|
-
while (index < end) {
|
|
389
|
-
const character = markdown[index];
|
|
390
|
-
if (character === "\n") {
|
|
391
|
-
count += 1;
|
|
392
|
-
index += 1;
|
|
393
|
-
continue;
|
|
394
|
-
}
|
|
395
|
-
if (character === "\r") {
|
|
396
|
-
count += 1;
|
|
397
|
-
index += markdown[index + 1] === "\n" ? 2 : 1;
|
|
398
|
-
continue;
|
|
399
|
-
}
|
|
400
|
-
index += 1;
|
|
401
|
-
}
|
|
402
|
-
return count;
|
|
403
|
-
}
|
|
404
|
-
function findClosingFence(markdown, searchStart, fence) {
|
|
405
|
-
let lineStart = searchStart;
|
|
406
|
-
while (lineStart <= markdown.length) {
|
|
407
|
-
const lineEnd = findLineEnd(markdown, lineStart);
|
|
408
|
-
const lineContent = markdown.slice(lineStart, lineEnd.index);
|
|
409
|
-
if (isClosingFence(lineContent, fence)) {
|
|
410
|
-
return {
|
|
411
|
-
found: true,
|
|
412
|
-
start: lineStart
|
|
413
|
-
};
|
|
414
|
-
}
|
|
415
|
-
if (lineEnd.lineBreakLength === 0) {
|
|
416
|
-
return {
|
|
417
|
-
found: false,
|
|
418
|
-
start: markdown.length
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
lineStart = lineEnd.index + lineEnd.lineBreakLength;
|
|
422
|
-
}
|
|
423
|
-
return {
|
|
424
|
-
found: false,
|
|
425
|
-
start: markdown.length
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
function isClosingFence(line, fence) {
|
|
429
|
-
const fenceStart = readFenceStart(line);
|
|
430
|
-
if (fenceStart === void 0 || fenceStart.markerCharacter !== fence.markerCharacter) {
|
|
431
|
-
return false;
|
|
432
|
-
}
|
|
433
|
-
const { indentLength } = fenceStart;
|
|
434
|
-
if (line.slice(0, indentLength) !== fence.indent) {
|
|
435
|
-
return false;
|
|
436
|
-
}
|
|
437
|
-
let markerEnd = indentLength;
|
|
438
|
-
while (line[markerEnd] === fence.markerCharacter) {
|
|
439
|
-
markerEnd += 1;
|
|
440
|
-
}
|
|
441
|
-
const closingMarker = line.slice(indentLength, markerEnd);
|
|
442
|
-
if (closingMarker.length < fence.marker.length) {
|
|
443
|
-
return false;
|
|
444
|
-
}
|
|
445
|
-
for (let index = markerEnd; index < line.length; index += 1) {
|
|
446
|
-
if (line[index] !== " ") {
|
|
447
|
-
return false;
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
return true;
|
|
451
|
-
}
|
|
452
|
-
function findLineEnd(markdown, start) {
|
|
453
|
-
let index = start;
|
|
454
|
-
while (index < markdown.length) {
|
|
455
|
-
const character = markdown[index];
|
|
456
|
-
if (character === "\n") {
|
|
457
|
-
return {
|
|
458
|
-
index,
|
|
459
|
-
lineBreakLength: 1
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
if (character === "\r") {
|
|
463
|
-
if (markdown[index + 1] === "\n") {
|
|
464
|
-
return {
|
|
465
|
-
index,
|
|
466
|
-
lineBreakLength: 2
|
|
467
|
-
};
|
|
468
|
-
}
|
|
469
|
-
return {
|
|
470
|
-
index,
|
|
471
|
-
lineBreakLength: 1
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
index += 1;
|
|
475
|
-
}
|
|
476
|
-
return {
|
|
477
|
-
index: markdown.length,
|
|
478
|
-
lineBreakLength: 0
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// packages/frontmatter/src/fences.ts
|
|
483
|
-
var MISSING_END_DELIMITER_MESSAGE = "Missing YAML frontmatter end delimiter (---).";
|
|
484
|
-
function inspectFrontmatterBlock(source) {
|
|
485
|
-
const content = source.startsWith("\uFEFF") ? source.slice(1) : source;
|
|
486
|
-
const sourceOffset = source.length - content.length;
|
|
487
|
-
const opening = readOpeningFence2(content);
|
|
488
|
-
if (opening === void 0) {
|
|
489
|
-
return { kind: "body", body: source };
|
|
490
|
-
}
|
|
491
|
-
const closing = findClosingFence2(content, opening.next);
|
|
492
|
-
if (closing === void 0) {
|
|
493
|
-
return {
|
|
494
|
-
kind: "missing-closing-fence",
|
|
495
|
-
raw: content.slice(opening.next),
|
|
496
|
-
rawStart: sourceOffset + opening.next,
|
|
497
|
-
rawEnd: source.length,
|
|
498
|
-
body: "",
|
|
499
|
-
message: MISSING_END_DELIMITER_MESSAGE,
|
|
500
|
-
position: source.length
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
return {
|
|
504
|
-
kind: "frontmatter",
|
|
505
|
-
raw: content.slice(opening.next, closing.index),
|
|
506
|
-
rawStart: sourceOffset + opening.next,
|
|
507
|
-
rawEnd: sourceOffset + closing.index,
|
|
508
|
-
body: content.slice(closing.end + closing.lineBreakLength)
|
|
509
|
-
};
|
|
510
|
-
}
|
|
511
|
-
function readOpeningFence2(source) {
|
|
512
|
-
if (!source.startsWith("---")) {
|
|
513
|
-
return void 0;
|
|
514
|
-
}
|
|
515
|
-
const lineEnd = findLineEnd2(source, 0);
|
|
516
|
-
if (lineEnd.lineBreakLength === 0 || !isFenceLine(source.slice(0, lineEnd.index))) {
|
|
517
|
-
return void 0;
|
|
518
|
-
}
|
|
519
|
-
return { next: lineEnd.index + lineEnd.lineBreakLength };
|
|
520
|
-
}
|
|
521
|
-
function findClosingFence2(source, start) {
|
|
522
|
-
let lineStart = start;
|
|
523
|
-
while (lineStart <= source.length) {
|
|
524
|
-
const lineEnd = findLineEnd2(source, lineStart);
|
|
525
|
-
if (isFenceLine(source.slice(lineStart, lineEnd.index))) {
|
|
526
|
-
return {
|
|
527
|
-
index: lineStart,
|
|
528
|
-
end: lineEnd.index,
|
|
529
|
-
lineBreakLength: lineEnd.lineBreakLength
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
if (lineEnd.lineBreakLength === 0) {
|
|
533
|
-
break;
|
|
534
|
-
}
|
|
535
|
-
lineStart = lineEnd.index + lineEnd.lineBreakLength;
|
|
536
|
-
}
|
|
537
|
-
return void 0;
|
|
538
|
-
}
|
|
539
|
-
function isFenceLine(line) {
|
|
540
|
-
if (!line.startsWith("---")) {
|
|
541
|
-
return false;
|
|
542
|
-
}
|
|
543
|
-
for (let index = 3; index < line.length; index += 1) {
|
|
544
|
-
const character = line[index];
|
|
545
|
-
if (character !== " " && character !== " ") {
|
|
546
|
-
return false;
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
return true;
|
|
550
|
-
}
|
|
551
|
-
function findLineEnd2(source, start) {
|
|
552
|
-
let index = start;
|
|
553
|
-
while (index < source.length) {
|
|
554
|
-
const character = source[index];
|
|
555
|
-
if (character === "\n") {
|
|
556
|
-
return { index, lineBreakLength: 1 };
|
|
557
|
-
}
|
|
558
|
-
if (character === "\r") {
|
|
559
|
-
return {
|
|
560
|
-
index,
|
|
561
|
-
lineBreakLength: source[index + 1] === "\n" ? 2 : 1
|
|
562
|
-
};
|
|
563
|
-
}
|
|
564
|
-
index += 1;
|
|
565
|
-
}
|
|
566
|
-
return { index: source.length, lineBreakLength: 0 };
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
// packages/frontmatter/src/parse.ts
|
|
570
|
-
import { LineCounter, parse, parseDocument } from "yaml";
|
|
571
|
-
var FrontmatterParseError = class extends Error {
|
|
572
|
-
constructor(message) {
|
|
573
|
-
super(message);
|
|
574
|
-
this.name = "FrontmatterParseError";
|
|
575
|
-
}
|
|
576
|
-
};
|
|
577
|
-
function parseFrontmatterDocument(source, options = {}) {
|
|
578
|
-
const split = inspectFrontmatterBlock(source);
|
|
579
|
-
const lineCounter = createSourceLineCounter(source);
|
|
580
|
-
if (split.kind === "body") {
|
|
581
|
-
return {
|
|
582
|
-
frontmatter: {},
|
|
583
|
-
body: split.body,
|
|
584
|
-
errors: [],
|
|
585
|
-
lineCounter
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
|
-
if (split.kind === "missing-closing-fence") {
|
|
589
|
-
return {
|
|
590
|
-
frontmatter: {},
|
|
591
|
-
body: split.body,
|
|
592
|
-
errors: [{ message: split.message, pos: [split.position, split.position] }],
|
|
593
|
-
lineCounter
|
|
594
|
-
};
|
|
595
|
-
}
|
|
596
|
-
const yamlLineCounter = new LineCounter();
|
|
597
|
-
const normalizedYaml = normalizeYamlLineEndings(split.raw);
|
|
598
|
-
const document = parseDocument(normalizedYaml, {
|
|
599
|
-
lineCounter: yamlLineCounter,
|
|
600
|
-
prettyErrors: false,
|
|
601
|
-
uniqueKeys: options.uniqueKeys ?? false
|
|
602
|
-
});
|
|
603
|
-
const errors = document.errors.map((error) => ({
|
|
604
|
-
message: error.message,
|
|
605
|
-
...error.pos === void 0 ? {} : { pos: translateYamlErrorPosition(error.pos, split) }
|
|
606
|
-
}));
|
|
607
|
-
if (errors.length > 0) {
|
|
608
|
-
return {
|
|
609
|
-
frontmatter: {},
|
|
610
|
-
body: split.body,
|
|
611
|
-
errors,
|
|
612
|
-
lineCounter
|
|
613
|
-
};
|
|
614
|
-
}
|
|
615
|
-
try {
|
|
616
|
-
return {
|
|
617
|
-
frontmatter: normalizeYamlFrontmatter(document.toJSON()),
|
|
618
|
-
body: split.body,
|
|
619
|
-
errors,
|
|
620
|
-
lineCounter
|
|
621
|
-
};
|
|
622
|
-
} catch (error) {
|
|
623
|
-
if (error instanceof FrontmatterParseError) {
|
|
624
|
-
return {
|
|
625
|
-
frontmatter: {},
|
|
626
|
-
body: split.body,
|
|
627
|
-
errors: [{ message: error.message }],
|
|
628
|
-
lineCounter
|
|
629
|
-
};
|
|
630
|
-
}
|
|
631
|
-
throw error;
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
function createSourceLineCounter(source) {
|
|
635
|
-
const lineCounter = new LineCounter();
|
|
636
|
-
lineCounter.addNewLine(0);
|
|
637
|
-
for (let index = 0; index < source.length; index += 1) {
|
|
638
|
-
const character = source[index];
|
|
639
|
-
if (character === "\n") {
|
|
640
|
-
lineCounter.addNewLine(index + 1);
|
|
641
|
-
continue;
|
|
642
|
-
}
|
|
643
|
-
if (character === "\r") {
|
|
644
|
-
lineCounter.addNewLine(index + (source[index + 1] === "\n" ? 2 : 1));
|
|
645
|
-
if (source[index + 1] === "\n") {
|
|
646
|
-
index += 1;
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
return lineCounter;
|
|
651
|
-
}
|
|
652
|
-
function translateYamlErrorPosition(pos, split) {
|
|
653
|
-
return pos.map((offset) => split.rawStart + normalizeYamlErrorOffset(split.raw, offset));
|
|
654
|
-
}
|
|
655
|
-
function normalizeYamlErrorOffset(raw, offset) {
|
|
656
|
-
if (offset >= raw.length && endsWithLineBreak(raw)) {
|
|
657
|
-
return findPreviousLineStart(raw, raw.length);
|
|
658
|
-
}
|
|
659
|
-
return offset;
|
|
660
|
-
}
|
|
661
|
-
function endsWithLineBreak(value) {
|
|
662
|
-
return value.endsWith("\n") || value.endsWith("\r");
|
|
663
|
-
}
|
|
664
|
-
function findPreviousLineStart(value, end) {
|
|
665
|
-
let index = end - 1;
|
|
666
|
-
if (value[index] === "\n") {
|
|
667
|
-
index -= 1;
|
|
668
|
-
}
|
|
669
|
-
if (value[index] === "\r") {
|
|
670
|
-
index -= 1;
|
|
671
|
-
}
|
|
672
|
-
while (index >= 0) {
|
|
673
|
-
const character = value[index];
|
|
674
|
-
if (character === "\n" || character === "\r") {
|
|
675
|
-
return index + 1;
|
|
676
|
-
}
|
|
677
|
-
index -= 1;
|
|
678
|
-
}
|
|
679
|
-
return 0;
|
|
680
|
-
}
|
|
681
|
-
function normalizeYamlLineEndings(value) {
|
|
682
|
-
if (!value.includes("\r")) {
|
|
683
|
-
return value;
|
|
684
|
-
}
|
|
685
|
-
let normalized = "";
|
|
686
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
687
|
-
const character = value[index];
|
|
688
|
-
if (character !== "\r") {
|
|
689
|
-
normalized += character;
|
|
690
|
-
continue;
|
|
691
|
-
}
|
|
692
|
-
if (value[index + 1] === "\n") {
|
|
693
|
-
normalized += "\r\n";
|
|
694
|
-
index += 1;
|
|
695
|
-
continue;
|
|
696
|
-
}
|
|
697
|
-
normalized += "\n";
|
|
698
|
-
}
|
|
699
|
-
return normalized;
|
|
700
|
-
}
|
|
701
|
-
function normalizeYamlFrontmatter(value) {
|
|
702
|
-
if (value === null || value === void 0) {
|
|
703
|
-
return {};
|
|
704
|
-
}
|
|
705
|
-
if (!isPlainRecord(value)) {
|
|
706
|
-
throw new FrontmatterParseError("YAML frontmatter must parse to an object.");
|
|
707
|
-
}
|
|
708
|
-
return normalizeYamlValue(value);
|
|
709
|
-
}
|
|
710
|
-
function normalizeYamlValue(value) {
|
|
711
|
-
if (Array.isArray(value)) {
|
|
712
|
-
return value.map((item) => normalizeYamlValue(item));
|
|
713
|
-
}
|
|
714
|
-
if (!isPlainRecord(value)) {
|
|
715
|
-
return value;
|
|
716
|
-
}
|
|
717
|
-
const normalized = {};
|
|
718
|
-
for (const [key, entryValue] of Object.entries(value)) {
|
|
719
|
-
Object.defineProperty(normalized, key, {
|
|
720
|
-
configurable: true,
|
|
721
|
-
enumerable: true,
|
|
722
|
-
value: normalizeYamlValue(entryValue),
|
|
723
|
-
writable: true
|
|
724
|
-
});
|
|
725
|
-
}
|
|
726
|
-
return normalized;
|
|
727
|
-
}
|
|
728
|
-
function isRecord(value) {
|
|
729
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
730
|
-
}
|
|
731
|
-
function isPlainRecord(value) {
|
|
732
|
-
if (!isRecord(value)) {
|
|
733
|
-
return false;
|
|
734
|
-
}
|
|
735
|
-
const prototype = Object.getPrototypeOf(value);
|
|
736
|
-
return prototype === Object.prototype || prototype === null;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
// packages/frontmatter/src/stringify.ts
|
|
740
|
-
import { stringify } from "yaml";
|
|
741
|
-
|
|
742
|
-
// packages/safejs/src/loader/frontmatter.ts
|
|
743
|
-
function splitFrontmatter(markdown) {
|
|
744
|
-
try {
|
|
745
|
-
const parsed = parseFrontmatterDocument(markdown);
|
|
746
|
-
if (parsed.errors.length > 0) {
|
|
747
|
-
const firstError = parsed.errors[0];
|
|
748
|
-
const line = firstError?.pos === void 0 ? 2 : parsed.lineCounter.linePos(firstError.pos[0]).line;
|
|
749
|
-
const message = firstError?.message ?? "unknown YAML parse error";
|
|
750
|
-
throw toSafeJSDiagnosticError(line, message);
|
|
751
|
-
}
|
|
752
|
-
return {
|
|
753
|
-
frontmatter: parsed.frontmatter,
|
|
754
|
-
body: parsed.body
|
|
755
|
-
};
|
|
756
|
-
} catch (error) {
|
|
757
|
-
if (error instanceof FrontmatterParseError) {
|
|
758
|
-
throw toSafeJSFrontmatterError(markdown, error);
|
|
759
|
-
}
|
|
760
|
-
throw error;
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
function toSafeJSDiagnosticError(line, message) {
|
|
764
|
-
if (message === "Missing YAML frontmatter end delimiter (---).") {
|
|
765
|
-
return new Error(`Invalid frontmatter at line ${line}: missing closing delimiter (---).`);
|
|
766
|
-
}
|
|
767
|
-
if (message === "YAML frontmatter must parse to an object.") {
|
|
768
|
-
return new Error(`Invalid frontmatter at line ${line}: expected a YAML mapping.`);
|
|
769
|
-
}
|
|
770
|
-
return new Error(`Invalid YAML frontmatter at line ${line}: ${message}`);
|
|
771
|
-
}
|
|
772
|
-
function toSafeJSFrontmatterError(markdown, error) {
|
|
773
|
-
if (error.message === "Missing YAML frontmatter end delimiter (---).") {
|
|
774
|
-
return new Error(
|
|
775
|
-
`Invalid frontmatter at line ${countLines(stripByteOrderMark(markdown))}: missing closing delimiter (---).`
|
|
776
|
-
);
|
|
777
|
-
}
|
|
778
|
-
if (error.message === "YAML frontmatter must parse to an object.") {
|
|
779
|
-
return new Error("Invalid frontmatter at line 2: expected a YAML mapping.");
|
|
780
|
-
}
|
|
781
|
-
if (error.message.startsWith("Invalid YAML frontmatter: ")) {
|
|
782
|
-
return new Error(`Invalid YAML frontmatter at line 2: ${error.message.slice(26)}`);
|
|
783
|
-
}
|
|
784
|
-
return error;
|
|
785
|
-
}
|
|
786
|
-
function stripByteOrderMark(value) {
|
|
787
|
-
return value.startsWith("\uFEFF") ? value.slice(1) : value;
|
|
788
|
-
}
|
|
789
|
-
function countLines(value) {
|
|
790
|
-
let count = 1;
|
|
791
|
-
for (const character of value) {
|
|
792
|
-
if (character === "\n") {
|
|
793
|
-
count += 1;
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
return count;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
// packages/safejs/src/lint/runtime-modules.ts
|
|
800
|
-
var AsyncFunction = (async () => void 0).constructor;
|
|
801
|
-
function createLintModulesFromRuntimeRegistry(modules) {
|
|
802
|
-
const entries = modules instanceof Map ? [...modules.entries()] : Object.entries(modules);
|
|
803
|
-
return new Map(
|
|
804
|
-
entries.map(([moduleName, moduleExports]) => [
|
|
805
|
-
moduleName,
|
|
806
|
-
{
|
|
807
|
-
exports: createLintModuleExports(moduleExports)
|
|
808
|
-
}
|
|
809
|
-
])
|
|
810
|
-
);
|
|
811
|
-
}
|
|
812
|
-
function createLintModuleExports(moduleExports) {
|
|
813
|
-
const entries = moduleExports instanceof Map ? [...moduleExports.entries()] : Object.entries(moduleExports);
|
|
814
|
-
return new Map(
|
|
815
|
-
entries.filter(([exportName]) => exportName.length > 0).map(([exportName, value]) => [exportName, createLintModuleExport(value)]).sort(([left], [right]) => left.localeCompare(right))
|
|
816
|
-
);
|
|
817
|
-
}
|
|
818
|
-
function createLintModuleExport(value) {
|
|
819
|
-
return isAsyncRuntimeExport(value) ? { async: true } : {};
|
|
820
|
-
}
|
|
821
|
-
function isAsyncRuntimeExport(value) {
|
|
822
|
-
if (isSandboxClosure(value)) {
|
|
823
|
-
return value.async === true;
|
|
824
|
-
}
|
|
825
|
-
return typeof value === "function" && value.constructor === AsyncFunction;
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
// packages/safejs/src/modules/agent.ts
|
|
829
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
830
|
-
|
|
831
|
-
// packages/agent-defs/src/agents/claude-code.ts
|
|
832
|
-
var claudeCodeAgent = {
|
|
833
|
-
id: "claude-code",
|
|
834
|
-
name: "claude-code",
|
|
835
|
-
label: "Claude Code",
|
|
836
|
-
summary: "Anthropic's agentic coding tool for the terminal.",
|
|
837
|
-
aliases: ["claude"],
|
|
838
|
-
binaryName: "claude",
|
|
839
|
-
apiShapes: ["anthropic-messages"],
|
|
840
|
-
otelCapture: {
|
|
841
|
-
env: {
|
|
842
|
-
CLAUDE_CODE_ENABLE_TELEMETRY: "1"
|
|
843
|
-
}
|
|
844
|
-
},
|
|
845
|
-
configPath: "~/.claude.json",
|
|
846
|
-
capabilities: ["spawn", "configure", "install", "test", "skill", "mcp"],
|
|
847
|
-
branding: {
|
|
848
|
-
colors: {
|
|
849
|
-
dark: "#C15F3C",
|
|
850
|
-
light: "#C15F3C"
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
};
|
|
854
|
-
|
|
855
|
-
// packages/agent-defs/src/agents/claude-desktop.ts
|
|
856
|
-
var claudeDesktopAgent = {
|
|
857
|
-
id: "claude-desktop",
|
|
858
|
-
name: "claude-desktop",
|
|
859
|
-
label: "Claude Desktop",
|
|
860
|
-
summary: "Anthropic's official desktop application for Claude",
|
|
861
|
-
configPath: "~/.config/Claude/claude_desktop_config.json",
|
|
862
|
-
configPaths: {
|
|
863
|
-
darwin: "~/Library/Application Support/Claude/claude_desktop_config.json",
|
|
864
|
-
linux: "~/.config/Claude/claude_desktop_config.json",
|
|
865
|
-
win32: "~/AppData/Roaming/Claude/claude_desktop_config.json"
|
|
866
|
-
},
|
|
867
|
-
capabilities: ["mcp"],
|
|
868
|
-
branding: {
|
|
869
|
-
colors: {
|
|
870
|
-
dark: "#D97757",
|
|
871
|
-
light: "#D97757"
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
};
|
|
875
|
-
|
|
876
|
-
// packages/agent-defs/src/agents/codex.ts
|
|
877
|
-
var codexAgent = {
|
|
878
|
-
id: "codex",
|
|
879
|
-
name: "codex",
|
|
880
|
-
label: "Codex",
|
|
881
|
-
summary: "OpenAI's coding agent for the terminal.",
|
|
882
|
-
binaryName: "codex",
|
|
883
|
-
apiShapes: ["openai-responses"],
|
|
884
|
-
otelCapture: {
|
|
885
|
-
args: (endpoint, content) => [
|
|
886
|
-
"-c",
|
|
887
|
-
`otel.trace_exporter={"otlp-http"={endpoint=${JSON.stringify(`${endpoint}/v1/traces`)},protocol="json"}}`,
|
|
888
|
-
"-c",
|
|
889
|
-
`otel.exporter={"otlp-http"={endpoint=${JSON.stringify(`${endpoint}/v1/logs`)},protocol="json"}}`,
|
|
890
|
-
"-c",
|
|
891
|
-
`otel.log_user_prompt=${content}`
|
|
892
|
-
]
|
|
893
|
-
},
|
|
894
|
-
configPath: "~/.codex/config.toml",
|
|
895
|
-
capabilities: ["spawn", "configure", "install", "test", "skill", "mcp"],
|
|
896
|
-
branding: {
|
|
897
|
-
colors: {
|
|
898
|
-
dark: "#D5D9DF",
|
|
899
|
-
light: "#7A7F86"
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
};
|
|
903
|
-
|
|
904
|
-
// packages/agent-defs/src/agents/cursor.ts
|
|
905
|
-
var cursorAgent = {
|
|
906
|
-
id: "cursor",
|
|
907
|
-
name: "cursor",
|
|
908
|
-
aliases: ["cursor-agent"],
|
|
909
|
-
label: "Cursor",
|
|
910
|
-
summary: "Cursor's CLI coding agent.",
|
|
911
|
-
binaryName: "cursor-agent",
|
|
912
|
-
configPath: "~/.cursor/mcp.json",
|
|
913
|
-
capabilities: ["spawn", "configure", "install", "test", "skill", "mcp"],
|
|
914
|
-
branding: {
|
|
915
|
-
colors: {
|
|
916
|
-
dark: "#FFFFFF",
|
|
917
|
-
light: "#000000"
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
};
|
|
921
|
-
|
|
922
|
-
// packages/agent-defs/src/agents/gemini-cli.ts
|
|
923
|
-
var geminiCliAgent = {
|
|
924
|
-
id: "gemini-cli",
|
|
925
|
-
name: "gemini-cli",
|
|
926
|
-
aliases: ["gemini"],
|
|
927
|
-
label: "Gemini CLI",
|
|
928
|
-
summary: "Google's open-source AI agent for the terminal.",
|
|
929
|
-
binaryName: "gemini",
|
|
930
|
-
configPath: "~/.gemini/settings.json",
|
|
931
|
-
apiShapes: ["google-generations"],
|
|
932
|
-
capabilities: ["spawn", "configure", "install", "test", "skill"],
|
|
933
|
-
branding: {
|
|
934
|
-
colors: {
|
|
935
|
-
dark: "#8AB4F8",
|
|
936
|
-
light: "#1A73E8"
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
};
|
|
940
|
-
|
|
941
|
-
// packages/agent-defs/src/agents/opencode.ts
|
|
942
|
-
var openCodeAgent = {
|
|
943
|
-
id: "opencode",
|
|
944
|
-
name: "opencode",
|
|
945
|
-
label: "OpenCode CLI",
|
|
946
|
-
summary: "Open-source AI coding agent for the terminal.",
|
|
947
|
-
binaryName: "opencode",
|
|
948
|
-
apiShapes: ["openai-chat-completions"],
|
|
949
|
-
otelCapture: {
|
|
950
|
-
env: {
|
|
951
|
-
OPENCODE_CONFIG_CONTENT: '{"experimental":{"openTelemetry":true}}'
|
|
952
|
-
}
|
|
953
|
-
},
|
|
954
|
-
configPath: "~/.config/opencode/opencode.json",
|
|
955
|
-
capabilities: ["spawn", "configure", "install", "test", "skill", "mcp"],
|
|
956
|
-
branding: {
|
|
957
|
-
colors: {
|
|
958
|
-
dark: "#4A4F55",
|
|
959
|
-
light: "#2F3338"
|
|
960
|
-
}
|
|
961
|
-
}
|
|
962
|
-
};
|
|
963
|
-
|
|
964
|
-
// packages/agent-defs/src/agents/kimi.ts
|
|
965
|
-
var kimiAgent = {
|
|
966
|
-
id: "kimi",
|
|
967
|
-
name: "kimi",
|
|
968
|
-
label: "Kimi",
|
|
969
|
-
summary: "Moonshot AI's coding agent for the terminal.",
|
|
970
|
-
aliases: ["kimi-cli"],
|
|
971
|
-
binaryName: "kimi",
|
|
972
|
-
apiShapes: ["openai-chat-completions"],
|
|
973
|
-
configPath: "~/.kimi/mcp.json",
|
|
974
|
-
capabilities: ["spawn", "configure", "install", "test", "mcp"],
|
|
975
|
-
branding: {
|
|
976
|
-
colors: {
|
|
977
|
-
dark: "#7B68EE",
|
|
978
|
-
light: "#6A5ACD"
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
};
|
|
982
|
-
|
|
983
|
-
// packages/agent-defs/src/agents/goose.ts
|
|
984
|
-
var gooseAgent = {
|
|
985
|
-
id: "goose",
|
|
986
|
-
name: "goose",
|
|
987
|
-
label: "Goose",
|
|
988
|
-
summary: "Block's open-source AI agent with ACP support.",
|
|
989
|
-
binaryName: "goose",
|
|
990
|
-
apiShapes: ["openai-chat-completions"],
|
|
991
|
-
otelCapture: {},
|
|
992
|
-
configPath: "~/.config/goose/config.yaml",
|
|
993
|
-
capabilities: ["spawn", "configure", "install", "test", "skill", "mcp"],
|
|
994
|
-
branding: {
|
|
995
|
-
colors: {
|
|
996
|
-
dark: "#FF6B35",
|
|
997
|
-
light: "#E85D26"
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
};
|
|
1001
|
-
|
|
1002
|
-
// packages/agent-defs/src/agents/pi.ts
|
|
1003
|
-
var piAgent = {
|
|
1004
|
-
id: "pi",
|
|
1005
|
-
name: "pi",
|
|
1006
|
-
aliases: ["pi-agent"],
|
|
1007
|
-
label: "Pi",
|
|
1008
|
-
summary: "Minimal AI coding agent for the terminal.",
|
|
1009
|
-
binaryName: "pi",
|
|
1010
|
-
capabilities: ["spawn"],
|
|
1011
|
-
branding: {
|
|
1012
|
-
colors: {
|
|
1013
|
-
dark: "#F2F2F2",
|
|
1014
|
-
light: "#242424"
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
};
|
|
1018
|
-
|
|
1019
|
-
// packages/agent-defs/src/agents/poe-agent.ts
|
|
1020
|
-
var poeAgentAgent = {
|
|
1021
|
-
id: "poe-agent",
|
|
1022
|
-
name: "poe-agent",
|
|
1023
|
-
label: "Poe Agent",
|
|
1024
|
-
summary: "Run one-shot prompts with the built-in Poe agent runtime.",
|
|
1025
|
-
apiShapes: ["openai-responses", "openai-chat-completions"],
|
|
1026
|
-
configPath: "~/.poe-code/config.json",
|
|
1027
|
-
capabilities: ["configure"],
|
|
1028
|
-
branding: {
|
|
1029
|
-
colors: {
|
|
1030
|
-
dark: "#A465F7",
|
|
1031
|
-
light: "#7A3FD3"
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
};
|
|
1035
|
-
|
|
1036
|
-
// packages/agent-defs/src/registry.ts
|
|
1037
|
-
function freezeAgent(agent) {
|
|
1038
|
-
if (agent.aliases !== void 0) {
|
|
1039
|
-
Object.freeze(agent.aliases);
|
|
1040
|
-
}
|
|
1041
|
-
if (agent.apiShapes !== void 0) {
|
|
1042
|
-
Object.freeze(agent.apiShapes);
|
|
1043
|
-
}
|
|
1044
|
-
if (agent.capabilities !== void 0) {
|
|
1045
|
-
Object.freeze(agent.capabilities);
|
|
1046
|
-
}
|
|
1047
|
-
if (agent.otelCapture?.env !== void 0) {
|
|
1048
|
-
Object.freeze(agent.otelCapture.env);
|
|
1049
|
-
}
|
|
1050
|
-
if (agent.otelCapture !== void 0) {
|
|
1051
|
-
Object.freeze(agent.otelCapture);
|
|
1052
|
-
}
|
|
1053
|
-
Object.freeze(agent.branding.colors);
|
|
1054
|
-
Object.freeze(agent.branding);
|
|
1055
|
-
return Object.freeze(agent);
|
|
1056
|
-
}
|
|
1057
|
-
var allAgents = Object.freeze([
|
|
1058
|
-
freezeAgent(claudeCodeAgent),
|
|
1059
|
-
freezeAgent(claudeDesktopAgent),
|
|
1060
|
-
freezeAgent(codexAgent),
|
|
1061
|
-
freezeAgent(cursorAgent),
|
|
1062
|
-
freezeAgent(geminiCliAgent),
|
|
1063
|
-
freezeAgent(openCodeAgent),
|
|
1064
|
-
freezeAgent(kimiAgent),
|
|
1065
|
-
freezeAgent(gooseAgent),
|
|
1066
|
-
freezeAgent(piAgent),
|
|
1067
|
-
freezeAgent(poeAgentAgent)
|
|
1068
|
-
]);
|
|
1069
|
-
var lookup = /* @__PURE__ */ new Map();
|
|
1070
|
-
for (const agent of allAgents) {
|
|
1071
|
-
const values = [agent.id, agent.name, ...agent.aliases ?? []];
|
|
1072
|
-
for (const value of values) {
|
|
1073
|
-
const normalized = value.toLowerCase();
|
|
1074
|
-
if (!lookup.has(normalized)) {
|
|
1075
|
-
lookup.set(normalized, agent.id);
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
function resolveAgentId(input) {
|
|
1080
|
-
if (!input) {
|
|
1081
|
-
return void 0;
|
|
1082
|
-
}
|
|
1083
|
-
return lookup.get(input.trim().toLowerCase());
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
|
-
// packages/agent-spawn/src/configs/mcp.ts
|
|
1087
|
-
function toJsonMcpServers(servers) {
|
|
1088
|
-
validateMcpSpawnConfig(servers);
|
|
1089
|
-
const out = /* @__PURE__ */ Object.create(null);
|
|
1090
|
-
for (const [name, server] of Object.entries(servers)) {
|
|
1091
|
-
const mapped = { command: server.command };
|
|
1092
|
-
if (server.args && server.args.length > 0) {
|
|
1093
|
-
mapped.args = server.args;
|
|
1094
|
-
}
|
|
1095
|
-
if (server.env && Object.keys(server.env).length > 0) {
|
|
1096
|
-
mapped.env = server.env;
|
|
1097
|
-
}
|
|
1098
|
-
if (server.timeout !== void 0) {
|
|
1099
|
-
mapped.timeout = server.timeout;
|
|
1100
|
-
}
|
|
1101
|
-
out[name] = mapped;
|
|
1102
|
-
}
|
|
1103
|
-
return out;
|
|
1104
|
-
}
|
|
1105
|
-
function toTomlString(value) {
|
|
1106
|
-
return JSON.stringify(value);
|
|
1107
|
-
}
|
|
1108
|
-
function toTomlArray(values) {
|
|
1109
|
-
const serialized = values.map((value) => toTomlString(value));
|
|
1110
|
-
return `[${serialized.join(", ")}]`;
|
|
1111
|
-
}
|
|
1112
|
-
function toTomlInlineTable(values) {
|
|
1113
|
-
const parts = [];
|
|
1114
|
-
for (const [key, value] of Object.entries(values)) {
|
|
1115
|
-
parts.push(`${JSON.stringify(key)}=${toTomlString(value)}`);
|
|
1116
|
-
}
|
|
1117
|
-
return `{${parts.join(", ")}}`;
|
|
1118
|
-
}
|
|
1119
|
-
function isTomlBareKeySegment(value) {
|
|
1120
|
-
if (value.length === 0) {
|
|
1121
|
-
return false;
|
|
1122
|
-
}
|
|
1123
|
-
for (const char of value) {
|
|
1124
|
-
const code = char.charCodeAt(0);
|
|
1125
|
-
const isDigit = code >= 48 && code <= 57;
|
|
1126
|
-
const isUpperAlpha = code >= 65 && code <= 90;
|
|
1127
|
-
const isLowerAlpha = code >= 97 && code <= 122;
|
|
1128
|
-
if (!isDigit && !isUpperAlpha && !isLowerAlpha && char !== "_" && char !== "-") {
|
|
1129
|
-
return false;
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
return true;
|
|
1133
|
-
}
|
|
1134
|
-
function toTomlKeySegment(value) {
|
|
1135
|
-
return isTomlBareKeySegment(value) ? value : JSON.stringify(value);
|
|
1136
|
-
}
|
|
1137
|
-
function validateMcpSpawnConfig(servers) {
|
|
1138
|
-
for (const [name, server] of Object.entries(servers)) {
|
|
1139
|
-
if (name.trim().length === 0) {
|
|
1140
|
-
throw new Error("MCP server name must be a non-empty string.");
|
|
1141
|
-
}
|
|
1142
|
-
if (typeof server.command !== "string" || server.command.trim().length === 0) {
|
|
1143
|
-
throw new Error(`MCP server "${name}" command must be a non-empty string.`);
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
}
|
|
1147
|
-
function serializeJsonMcpArgs(servers) {
|
|
1148
|
-
return ["--mcp-config", JSON.stringify({ mcpServers: toJsonMcpServers(servers) })];
|
|
1149
|
-
}
|
|
1150
|
-
function serializeOpenCodeMcpEnv(servers) {
|
|
1151
|
-
validateMcpSpawnConfig(servers);
|
|
1152
|
-
const mcp = /* @__PURE__ */ Object.create(null);
|
|
1153
|
-
for (const [name, server] of Object.entries(servers)) {
|
|
1154
|
-
if (server.timeout !== void 0) {
|
|
1155
|
-
throw new Error(`OpenCode MCP server "${name}" does not support timeout.`);
|
|
1156
|
-
}
|
|
1157
|
-
const entry = { type: "local", command: [server.command, ...server.args ?? []] };
|
|
1158
|
-
if (server.env && Object.keys(server.env).length > 0) {
|
|
1159
|
-
entry.environment = server.env;
|
|
1160
|
-
}
|
|
1161
|
-
mcp[name] = entry;
|
|
1162
|
-
}
|
|
1163
|
-
return { OPENCODE_CONFIG_CONTENT: JSON.stringify({ mcp }) };
|
|
1164
|
-
}
|
|
1165
|
-
function serializeCodexMcpArgs(servers) {
|
|
1166
|
-
validateMcpSpawnConfig(servers);
|
|
1167
|
-
const args = [];
|
|
1168
|
-
for (const [name, server] of Object.entries(servers)) {
|
|
1169
|
-
const prefix = `mcp_servers.${toTomlKeySegment(name)}`;
|
|
1170
|
-
args.push("-c", `${prefix}.command=${toTomlString(server.command)}`);
|
|
1171
|
-
if (server.autoApprove !== false) {
|
|
1172
|
-
args.push("-c", `${prefix}.default_tools_approval_mode=${toTomlString("approve")}`);
|
|
1173
|
-
}
|
|
1174
|
-
if (server.args && server.args.length > 0) {
|
|
1175
|
-
args.push("-c", `${prefix}.args=${toTomlArray(server.args)}`);
|
|
1176
|
-
}
|
|
1177
|
-
if (server.env && Object.keys(server.env).length > 0) {
|
|
1178
|
-
args.push("-c", `${prefix}.env=${toTomlInlineTable(server.env)}`);
|
|
1179
|
-
}
|
|
1180
|
-
if (server.timeout !== void 0) {
|
|
1181
|
-
args.push("-c", `${prefix}.timeout=${server.timeout}`);
|
|
1182
|
-
}
|
|
1183
|
-
}
|
|
1184
|
-
return args;
|
|
1185
|
-
}
|
|
1186
|
-
function serializeGooseMcpArgs(servers) {
|
|
1187
|
-
validateMcpSpawnConfig(servers);
|
|
1188
|
-
return Object.entries(servers).flatMap(([name, server]) => {
|
|
1189
|
-
if (server.env && Object.keys(server.env).length > 0) {
|
|
1190
|
-
throw new Error(`Goose MCP server "${name}" does not support env through --with-extension.`);
|
|
1191
|
-
}
|
|
1192
|
-
if (server.timeout !== void 0) {
|
|
1193
|
-
throw new Error(
|
|
1194
|
-
`Goose MCP server "${name}" does not support timeout through --with-extension.`
|
|
1195
|
-
);
|
|
1196
|
-
}
|
|
1197
|
-
return ["--with-extension", [server.command, ...server.args ?? []].join(" ")];
|
|
1198
|
-
});
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
// packages/agent-spawn/src/configs/claude-code.ts
|
|
1202
|
-
var claudeCodeSpawnConfig = {
|
|
1203
|
-
kind: "cli",
|
|
1204
|
-
agentId: "claude-code",
|
|
1205
|
-
// ACP adapter support: yes (adapter: "claude")
|
|
1206
|
-
adapter: "claude",
|
|
1207
|
-
promptFlag: "-p",
|
|
1208
|
-
modelFlag: "--model",
|
|
1209
|
-
modelStripProviderPrefix: true,
|
|
1210
|
-
modelTransform: (model) => model.replaceAll(".", "-"),
|
|
1211
|
-
defaultArgs: [
|
|
1212
|
-
"--output-format",
|
|
1213
|
-
"stream-json",
|
|
1214
|
-
"--verbose"
|
|
1215
|
-
],
|
|
1216
|
-
mcpArgs: serializeJsonMcpArgs,
|
|
1217
|
-
modes: {
|
|
1218
|
-
yolo: ["--dangerously-skip-permissions"],
|
|
1219
|
-
auto: ["--permission-mode", "auto"],
|
|
1220
|
-
edit: ["--permission-mode", "acceptEdits", "--allowedTools", "Bash,Read,Write,Edit,Glob,Grep,NotebookEdit"],
|
|
1221
|
-
// Plan mode alone still permits writes, so read mode pins a read-only
|
|
1222
|
-
// allowlist and hard-denies every mutating tool.
|
|
1223
|
-
read: [
|
|
1224
|
-
"--permission-mode",
|
|
1225
|
-
"plan",
|
|
1226
|
-
"--allowedTools",
|
|
1227
|
-
"Read,Glob,Grep",
|
|
1228
|
-
"--disallowedTools",
|
|
1229
|
-
"Bash,Write,Edit,MultiEdit,NotebookEdit"
|
|
1230
|
-
]
|
|
1231
|
-
},
|
|
1232
|
-
stdinMode: {
|
|
1233
|
-
omitPrompt: true,
|
|
1234
|
-
extraArgs: ["--input-format", "text"]
|
|
1235
|
-
},
|
|
1236
|
-
interactive: {
|
|
1237
|
-
defaultArgs: []
|
|
1238
|
-
},
|
|
1239
|
-
resume: {
|
|
1240
|
-
args: (threadId) => ["--resume", threadId]
|
|
1241
|
-
}
|
|
1242
|
-
};
|
|
1243
|
-
|
|
1244
|
-
// packages/agent-spawn/src/configs/codex.ts
|
|
1245
|
-
var codexSpawnConfig = {
|
|
1246
|
-
kind: "cli",
|
|
1247
|
-
agentId: "codex",
|
|
1248
|
-
// ACP adapter support: yes (adapter: "codex")
|
|
1249
|
-
adapter: "codex",
|
|
1250
|
-
promptFlag: "exec",
|
|
1251
|
-
modelFlag: "--model",
|
|
1252
|
-
modelStripProviderPrefix: true,
|
|
1253
|
-
defaultArgs: ["--skip-git-repo-check", "--json"],
|
|
1254
|
-
mcpArgs: serializeCodexMcpArgs,
|
|
1255
|
-
mcpArgsBeforeCommand: true,
|
|
1256
|
-
modes: {
|
|
1257
|
-
yolo: ["--dangerously-bypass-approvals-and-sandbox"],
|
|
1258
|
-
auto: [
|
|
1259
|
-
"-s",
|
|
1260
|
-
"danger-full-access",
|
|
1261
|
-
"-c",
|
|
1262
|
-
'approval_policy="on-request"',
|
|
1263
|
-
"-c",
|
|
1264
|
-
'approvals_reviewer="auto_review"'
|
|
1265
|
-
],
|
|
1266
|
-
edit: ["-s", "workspace-write"],
|
|
1267
|
-
read: ["-s", "read-only"]
|
|
1268
|
-
},
|
|
1269
|
-
stdinMode: {
|
|
1270
|
-
omitPrompt: true,
|
|
1271
|
-
extraArgs: ["-"]
|
|
1272
|
-
},
|
|
1273
|
-
interactive: {
|
|
1274
|
-
defaultArgs: ["-a", "never"]
|
|
1275
|
-
},
|
|
1276
|
-
resume: {
|
|
1277
|
-
args: (threadId) => ["resume", threadId],
|
|
1278
|
-
position: "beforePrompt",
|
|
1279
|
-
commandOptionsPosition: "beforeResume",
|
|
1280
|
-
hintArgs: (threadId, cwd) => ["resume", "-C", cwd, threadId]
|
|
1281
|
-
}
|
|
1282
|
-
};
|
|
1283
|
-
|
|
1284
|
-
// packages/agent-spawn/src/configs/opencode.ts
|
|
1285
|
-
var openCodeSpawnConfig = {
|
|
1286
|
-
kind: "cli",
|
|
1287
|
-
agentId: "opencode",
|
|
1288
|
-
// ACP adapter support: yes (adapter: "opencode").
|
|
1289
|
-
// OpenCode's `--format json` emits NDJSON events with `{ type, sessionID, part }`
|
|
1290
|
-
// (no `{ event, ... }` field), so it needs the OpenCode adapter (not "native").
|
|
1291
|
-
adapter: "opencode",
|
|
1292
|
-
promptFlag: "run",
|
|
1293
|
-
modelFlag: "--model",
|
|
1294
|
-
modelStripProviderPrefix: false,
|
|
1295
|
-
modelTransform: (model) => {
|
|
1296
|
-
return model.startsWith("poe/") ? model : `poe/${model}`;
|
|
1297
|
-
},
|
|
1298
|
-
defaultArgs: ["--format", "json"],
|
|
1299
|
-
modes: {
|
|
1300
|
-
// No auto: `opencode run` never asks; permissions come from opencode.json.
|
|
1301
|
-
yolo: [],
|
|
1302
|
-
edit: [],
|
|
1303
|
-
read: ["--agent", "plan"]
|
|
1304
|
-
},
|
|
1305
|
-
interactive: {
|
|
1306
|
-
defaultArgs: [],
|
|
1307
|
-
promptFlag: "--prompt"
|
|
1308
|
-
},
|
|
1309
|
-
resume: {
|
|
1310
|
-
args: (threadId) => ["--session", threadId],
|
|
1311
|
-
hintArgs: (threadId, cwd) => [cwd, "--session", threadId]
|
|
1312
|
-
},
|
|
1313
|
-
mcpEnv: serializeOpenCodeMcpEnv
|
|
1314
|
-
};
|
|
1315
|
-
var openCodeAcpSpawnConfig = {
|
|
1316
|
-
kind: "acp",
|
|
1317
|
-
agentId: "opencode",
|
|
1318
|
-
acpArgs: ["acp"],
|
|
1319
|
-
skipAuth: true,
|
|
1320
|
-
mcpEnv: serializeOpenCodeMcpEnv
|
|
1321
|
-
};
|
|
1322
|
-
|
|
1323
|
-
// packages/agent-spawn/src/configs/kimi.ts
|
|
1324
|
-
var kimiSpawnConfig = {
|
|
1325
|
-
kind: "cli",
|
|
1326
|
-
agentId: "kimi",
|
|
1327
|
-
// ACP adapter support: yes (adapter: "kimi").
|
|
1328
|
-
// Kimi's `--output-format stream-json` emits OpenAI-style `{ role, content }` JSON
|
|
1329
|
-
// (no `{ event, ... }` field), so it needs the Kimi adapter (not "native").
|
|
1330
|
-
adapter: "kimi",
|
|
1331
|
-
promptFlag: "-p",
|
|
1332
|
-
modelStripProviderPrefix: true,
|
|
1333
|
-
defaultArgs: ["--print", "--output-format", "stream-json"],
|
|
1334
|
-
mcpArgs: serializeJsonMcpArgs,
|
|
1335
|
-
modes: {
|
|
1336
|
-
// No auto: kimi --print mode has no approval channel.
|
|
1337
|
-
yolo: ["--yolo"],
|
|
1338
|
-
edit: [],
|
|
1339
|
-
read: []
|
|
1340
|
-
},
|
|
1341
|
-
stdinMode: {
|
|
1342
|
-
omitPrompt: true,
|
|
1343
|
-
extraArgs: ["--input-format", "stream-json"],
|
|
1344
|
-
automaticFallback: false
|
|
1345
|
-
},
|
|
1346
|
-
interactive: {
|
|
1347
|
-
defaultArgs: [],
|
|
1348
|
-
promptFlag: "-p"
|
|
1349
|
-
},
|
|
1350
|
-
resume: {
|
|
1351
|
-
args: (threadId, cwd) => ["--session", threadId, "--work-dir", cwd]
|
|
1352
|
-
}
|
|
1353
|
-
};
|
|
1354
|
-
var kimiAcpSpawnConfig = {
|
|
1355
|
-
kind: "acp",
|
|
1356
|
-
agentId: "kimi",
|
|
1357
|
-
acpArgs: ["acp"],
|
|
1358
|
-
supportsMcpServers: false
|
|
1359
|
-
};
|
|
1360
|
-
|
|
1361
|
-
// packages/agent-spawn/src/configs/goose.ts
|
|
1362
|
-
var gooseFileSecretsEnv = { GOOSE_DISABLE_KEYRING: "1" };
|
|
1363
|
-
var gooseSpawnConfig = {
|
|
1364
|
-
kind: "cli",
|
|
1365
|
-
agentId: "goose",
|
|
1366
|
-
adapter: "native",
|
|
1367
|
-
promptFlag: "--text",
|
|
1368
|
-
modelFlag: "--model",
|
|
1369
|
-
modelStripProviderPrefix: false,
|
|
1370
|
-
defaultArgs: ["run", "--output-format", "stream-json"],
|
|
1371
|
-
defaultArgsPosition: "beforePrompt",
|
|
1372
|
-
mcpArgs: serializeGooseMcpArgs,
|
|
1373
|
-
mcpArgsPosition: "beforePrompt",
|
|
1374
|
-
modes: {
|
|
1375
|
-
// No auto: GOOSE_MODE=approve prompts on the TTY and would hang a headless run.
|
|
1376
|
-
yolo: { env: { ...gooseFileSecretsEnv, GOOSE_MODE: "auto" } },
|
|
1377
|
-
edit: { env: { ...gooseFileSecretsEnv, GOOSE_MODE: "smart_approve" } },
|
|
1378
|
-
read: { env: { ...gooseFileSecretsEnv, GOOSE_MODE: "chat" } }
|
|
1379
|
-
},
|
|
1380
|
-
stdinMode: {
|
|
1381
|
-
omitPrompt: true,
|
|
1382
|
-
extraArgs: ["--instructions", "-"],
|
|
1383
|
-
automaticFallback: false
|
|
1384
|
-
},
|
|
1385
|
-
interactive: {
|
|
1386
|
-
defaultArgs: ["session"],
|
|
1387
|
-
defaultArgsPosition: "beforePrompt"
|
|
1388
|
-
},
|
|
1389
|
-
resume: {
|
|
1390
|
-
args: (threadId) => ["--resume", "--session-id", threadId],
|
|
1391
|
-
hintArgs: (threadId) => ["run", "--resume", "--session-id", threadId, "--text", "continue"]
|
|
1392
|
-
}
|
|
1393
|
-
};
|
|
1394
|
-
var gooseAcpSpawnConfig = {
|
|
1395
|
-
kind: "acp",
|
|
1396
|
-
agentId: "goose",
|
|
1397
|
-
acpArgs: ["acp"],
|
|
1398
|
-
env: gooseFileSecretsEnv,
|
|
1399
|
-
skipAuth: true
|
|
1400
|
-
};
|
|
1401
|
-
|
|
1402
|
-
// packages/agent-spawn/src/types.ts
|
|
1403
|
-
var SPAWN_MODES = ["yolo", "auto", "edit", "read"];
|
|
1404
|
-
var DEFAULT_SPAWN_MODE = "auto";
|
|
1405
|
-
|
|
1406
|
-
// packages/agent-spawn/src/configs/gemini-cli.ts
|
|
1407
|
-
var geminiApprovalModes = {
|
|
1408
|
-
yolo: "yolo",
|
|
1409
|
-
auto: "default",
|
|
1410
|
-
edit: "auto_edit",
|
|
1411
|
-
read: "plan"
|
|
1412
|
-
};
|
|
1413
|
-
var geminiCliAcpSpawnConfig = {
|
|
1414
|
-
kind: "acp",
|
|
1415
|
-
agentId: "gemini-cli",
|
|
1416
|
-
acpArgs: ({ model, mode, mcpServers }) => [
|
|
1417
|
-
"--acp",
|
|
1418
|
-
...model ? ["--model", model] : [],
|
|
1419
|
-
...mcpServers ? ["--allowed-mcp-server-names", Object.keys(mcpServers).join(",")] : [],
|
|
1420
|
-
...mcpServers ? ["--skip-trust"] : [],
|
|
1421
|
-
"--approval-mode",
|
|
1422
|
-
geminiApprovalModes[mode ?? DEFAULT_SPAWN_MODE]
|
|
1423
|
-
],
|
|
1424
|
-
env: {
|
|
1425
|
-
GEMINI_SANDBOX: "false"
|
|
1426
|
-
},
|
|
1427
|
-
skipAuth: true
|
|
1428
|
-
};
|
|
1429
|
-
|
|
1430
|
-
// packages/agent-spawn/src/configs/cursor.ts
|
|
1431
|
-
var cursorSpawnConfig = {
|
|
1432
|
-
kind: "cli",
|
|
1433
|
-
agentId: "cursor",
|
|
1434
|
-
adapter: "cursor",
|
|
1435
|
-
promptFlag: "-p",
|
|
1436
|
-
modelFlag: "--model",
|
|
1437
|
-
modelStripProviderPrefix: true,
|
|
1438
|
-
modelTransform: (model) => model.startsWith("claude-opus-") || model.startsWith("claude-sonnet-") || model.startsWith("claude-haiku-") ? model.replaceAll(".", "-") : model,
|
|
1439
|
-
defaultArgs: ["--output-format", "stream-json", "--trust", "--approve-mcps"],
|
|
1440
|
-
defaultArgsPosition: "beforePrompt",
|
|
1441
|
-
modes: {
|
|
1442
|
-
// No auto: cursor-agent print mode has no approval channel.
|
|
1443
|
-
yolo: ["--force", "--sandbox", "disabled"],
|
|
1444
|
-
edit: ["--force"],
|
|
1445
|
-
read: ["--mode", "plan"]
|
|
1446
|
-
},
|
|
1447
|
-
stdinMode: { omitPrompt: true, extraArgs: [] },
|
|
1448
|
-
mcpFile: {
|
|
1449
|
-
relativePath: ".cursor/mcp.json",
|
|
1450
|
-
content: (servers) => ({ mcpServers: toJsonMcpServers(servers) })
|
|
1451
|
-
},
|
|
1452
|
-
interactive: { defaultArgs: [] },
|
|
1453
|
-
resume: {
|
|
1454
|
-
args: (threadId) => ["--resume", threadId],
|
|
1455
|
-
position: "beforePrompt"
|
|
1456
|
-
}
|
|
1457
|
-
};
|
|
1458
|
-
|
|
1459
|
-
// packages/agent-spawn/src/configs/pi.ts
|
|
1460
|
-
var ALL_BUILTIN_TOOLS = "read,bash,edit,write,grep,find,ls";
|
|
1461
|
-
var EDIT_TOOLS = "read,edit,write,grep,find,ls";
|
|
1462
|
-
var READ_ONLY_TOOLS = "read,grep,find,ls";
|
|
1463
|
-
var piSpawnConfig = {
|
|
1464
|
-
kind: "cli",
|
|
1465
|
-
agentId: "pi",
|
|
1466
|
-
adapter: "pi",
|
|
1467
|
-
defaultArgs: ["--mode", "json", "--print"],
|
|
1468
|
-
defaultArgsPosition: "beforePrompt",
|
|
1469
|
-
modelFlag: "--model",
|
|
1470
|
-
modelStripProviderPrefix: false,
|
|
1471
|
-
modes: {
|
|
1472
|
-
yolo: ["--tools", ALL_BUILTIN_TOOLS, "--approve"],
|
|
1473
|
-
edit: ["--tools", EDIT_TOOLS, "--no-approve"],
|
|
1474
|
-
read: ["--tools", READ_ONLY_TOOLS, "--no-approve"]
|
|
1475
|
-
},
|
|
1476
|
-
stdinMode: {
|
|
1477
|
-
omitPrompt: true,
|
|
1478
|
-
extraArgs: []
|
|
1479
|
-
},
|
|
1480
|
-
interactive: {
|
|
1481
|
-
defaultArgs: []
|
|
1482
|
-
},
|
|
1483
|
-
resume: {
|
|
1484
|
-
args: (threadId) => ["--session", threadId],
|
|
1485
|
-
position: "beforePrompt"
|
|
1486
|
-
}
|
|
1487
|
-
};
|
|
1488
|
-
|
|
1489
|
-
// packages/agent-spawn/src/configs/index.ts
|
|
1490
|
-
function freezeConfig(config) {
|
|
1491
|
-
freezeValue(config);
|
|
1492
|
-
return config;
|
|
1493
|
-
}
|
|
1494
|
-
function freezeValue(value) {
|
|
1495
|
-
if (!value || typeof value !== "object" || Object.isFrozen(value)) {
|
|
1496
|
-
return;
|
|
1497
|
-
}
|
|
1498
|
-
for (const nested of Object.values(value)) {
|
|
1499
|
-
freezeValue(nested);
|
|
1500
|
-
}
|
|
1501
|
-
Object.freeze(value);
|
|
1502
|
-
}
|
|
1503
|
-
var allSpawnConfigs = Object.freeze([
|
|
1504
|
-
freezeConfig(claudeCodeSpawnConfig),
|
|
1505
|
-
freezeConfig(codexSpawnConfig),
|
|
1506
|
-
freezeConfig(cursorSpawnConfig),
|
|
1507
|
-
freezeConfig(piSpawnConfig),
|
|
1508
|
-
freezeConfig(openCodeSpawnConfig),
|
|
1509
|
-
freezeConfig(kimiSpawnConfig),
|
|
1510
|
-
freezeConfig(gooseSpawnConfig)
|
|
1511
|
-
]);
|
|
1512
|
-
var lookup2 = /* @__PURE__ */ new Map();
|
|
1513
|
-
for (const config of allSpawnConfigs) {
|
|
1514
|
-
lookup2.set(config.agentId, config);
|
|
1515
|
-
}
|
|
1516
|
-
var acpLookup = /* @__PURE__ */ new Map();
|
|
1517
|
-
acpLookup.set(openCodeAcpSpawnConfig.agentId, freezeConfig(openCodeAcpSpawnConfig));
|
|
1518
|
-
acpLookup.set(kimiAcpSpawnConfig.agentId, freezeConfig(kimiAcpSpawnConfig));
|
|
1519
|
-
acpLookup.set(gooseAcpSpawnConfig.agentId, freezeConfig(gooseAcpSpawnConfig));
|
|
1520
|
-
acpLookup.set(geminiCliAcpSpawnConfig.agentId, freezeConfig(geminiCliAcpSpawnConfig));
|
|
1521
|
-
function getSpawnConfig(input) {
|
|
1522
|
-
const resolvedId = resolveAgentId(input);
|
|
1523
|
-
if (!resolvedId) {
|
|
1524
|
-
return void 0;
|
|
1525
|
-
}
|
|
1526
|
-
return lookup2.get(resolvedId);
|
|
1527
|
-
}
|
|
1528
|
-
function supportsSpawnMode(input, mode) {
|
|
1529
|
-
const config = getSpawnConfig(input);
|
|
1530
|
-
if (config && config.kind === "cli") {
|
|
1531
|
-
return config.modes[mode] !== void 0;
|
|
1532
|
-
}
|
|
1533
|
-
return true;
|
|
1534
|
-
}
|
|
1535
|
-
|
|
1536
|
-
// packages/agent-spawn/src/parallel.ts
|
|
1537
|
-
var SpawnParallelError = class extends Error {
|
|
1538
|
-
index;
|
|
1539
|
-
result;
|
|
1540
|
-
results;
|
|
1541
|
-
constructor(index, result, results) {
|
|
1542
|
-
super(`spawn.parallel call ${index} failed with exit code ${result.exitCode}.`);
|
|
1543
|
-
this.name = "SpawnParallelError";
|
|
1544
|
-
this.index = index;
|
|
1545
|
-
this.result = result;
|
|
1546
|
-
this.results = results;
|
|
1547
|
-
}
|
|
1548
|
-
};
|
|
1549
|
-
function createSpawnParallel(spawnOnce) {
|
|
1550
|
-
return async function parallel(calls, options = {}) {
|
|
1551
|
-
const maxConcurrent = normalizeMaxConcurrent(options.maxConcurrent);
|
|
1552
|
-
const failFast = options.failFast ?? true;
|
|
1553
|
-
const requestedCheck = Object.hasOwn(options, "check") ? options.check : void 0;
|
|
1554
|
-
const check = requestedCheck === void 0 ? failFast : requestedCheck;
|
|
1555
|
-
if (typeof check !== "boolean") {
|
|
1556
|
-
throw new Error("spawn.parallel check must be a boolean.");
|
|
1557
|
-
}
|
|
1558
|
-
if (calls.length === 0) {
|
|
1559
|
-
return [];
|
|
1560
|
-
}
|
|
1561
|
-
const group = new AbortController();
|
|
1562
|
-
const results = new Array(calls.length);
|
|
1563
|
-
const errors = [];
|
|
1564
|
-
let nextIndex = 0;
|
|
1565
|
-
let primaryFailure;
|
|
1566
|
-
const removeParentAbort = linkParentAbort(options.signal, group, (error) => {
|
|
1567
|
-
primaryFailure ??= { reason: error };
|
|
1568
|
-
});
|
|
1569
|
-
const worker = async () => {
|
|
1570
|
-
while (primaryFailure === void 0) {
|
|
1571
|
-
const index = nextIndex;
|
|
1572
|
-
nextIndex += 1;
|
|
1573
|
-
if (index >= calls.length) {
|
|
1574
|
-
return;
|
|
1575
|
-
}
|
|
1576
|
-
try {
|
|
1577
|
-
const result = await runParallelCall(calls[index], spawnOnce, group.signal);
|
|
1578
|
-
results[index] = result;
|
|
1579
|
-
if (check && failFast && result.exitCode !== 0) {
|
|
1580
|
-
const error = new SpawnParallelError(index, result, results);
|
|
1581
|
-
primaryFailure ??= { reason: error };
|
|
1582
|
-
group.abort(error);
|
|
1583
|
-
return;
|
|
1584
|
-
}
|
|
1585
|
-
} catch (error) {
|
|
1586
|
-
if (failFast || group.signal.aborted) {
|
|
1587
|
-
primaryFailure ??= { reason: error };
|
|
1588
|
-
group.abort(error);
|
|
1589
|
-
return;
|
|
1590
|
-
}
|
|
1591
|
-
errors.push(error);
|
|
1592
|
-
}
|
|
1593
|
-
}
|
|
1594
|
-
};
|
|
1595
|
-
try {
|
|
1596
|
-
await Promise.allSettled(
|
|
1597
|
-
Array.from({ length: Math.min(maxConcurrent, calls.length) }, () => worker())
|
|
1598
|
-
);
|
|
1599
|
-
} finally {
|
|
1600
|
-
removeParentAbort();
|
|
1601
|
-
}
|
|
1602
|
-
if (primaryFailure !== void 0) {
|
|
1603
|
-
throw primaryFailure.reason;
|
|
1604
|
-
}
|
|
1605
|
-
if (errors.length > 0) {
|
|
1606
|
-
throw new AggregateError(
|
|
1607
|
-
errors,
|
|
1608
|
-
"spawn.parallel failed before every call returned a result."
|
|
1609
|
-
);
|
|
1610
|
-
}
|
|
1611
|
-
if (check) {
|
|
1612
|
-
const failedIndex = results.findIndex(
|
|
1613
|
-
(result) => result !== void 0 && result.exitCode !== 0
|
|
1614
|
-
);
|
|
1615
|
-
if (failedIndex >= 0) {
|
|
1616
|
-
throw new SpawnParallelError(failedIndex, results[failedIndex], results);
|
|
1617
|
-
}
|
|
1618
|
-
}
|
|
1619
|
-
return results;
|
|
1620
|
-
};
|
|
1621
|
-
}
|
|
1622
|
-
async function runParallelCall(call, spawnOnce, signal) {
|
|
1623
|
-
throwIfAborted(signal);
|
|
1624
|
-
if (typeof call === "function") {
|
|
1625
|
-
const handle = call(signal);
|
|
1626
|
-
const [result] = await Promise.all([handle.result, drainEvents(handle.events)]);
|
|
1627
|
-
return result;
|
|
1628
|
-
}
|
|
1629
|
-
if (!isSpawnTuple(call)) {
|
|
1630
|
-
throw new Error("spawn.parallel calls must be [service, options] tuples or spawn thunks.");
|
|
1631
|
-
}
|
|
1632
|
-
const { options, cleanup } = withAbortSignal(call[1], signal);
|
|
1633
|
-
try {
|
|
1634
|
-
const handle = spawnOnce(call[0], options);
|
|
1635
|
-
const [result] = await Promise.all([handle.result, drainEvents(handle.events)]);
|
|
1636
|
-
return result;
|
|
1637
|
-
} finally {
|
|
1638
|
-
cleanup();
|
|
1639
|
-
}
|
|
1640
|
-
}
|
|
1641
|
-
async function drainEvents(events) {
|
|
1642
|
-
for await (const ignoredEvent of events) {
|
|
1643
|
-
void ignoredEvent;
|
|
1644
|
-
}
|
|
1645
|
-
}
|
|
1646
|
-
function normalizeMaxConcurrent(maxConcurrent) {
|
|
1647
|
-
const value = maxConcurrent ?? 4;
|
|
1648
|
-
if (!Number.isInteger(value) || value < 1) {
|
|
1649
|
-
throw new Error("spawn.parallel maxConcurrent must be an integer greater than or equal to 1.");
|
|
1650
|
-
}
|
|
1651
|
-
return value;
|
|
1652
|
-
}
|
|
1653
|
-
function isSpawnTuple(call) {
|
|
1654
|
-
return Array.isArray(call) && call.length === 2;
|
|
1655
|
-
}
|
|
1656
|
-
function withAbortSignal(options, signal) {
|
|
1657
|
-
if (!options.signal) {
|
|
1658
|
-
return {
|
|
1659
|
-
options: { ...options, signal },
|
|
1660
|
-
cleanup() {
|
|
1661
|
-
}
|
|
1662
|
-
};
|
|
1663
|
-
}
|
|
1664
|
-
const controller = new AbortController();
|
|
1665
|
-
const callSignal = options.signal;
|
|
1666
|
-
const abortGroup = () => controller.abort(signal.reason);
|
|
1667
|
-
const abortCall = () => controller.abort(callSignal.reason);
|
|
1668
|
-
if (signal.aborted) {
|
|
1669
|
-
abortGroup();
|
|
1670
|
-
} else if (callSignal.aborted) {
|
|
1671
|
-
abortCall();
|
|
1672
|
-
} else {
|
|
1673
|
-
signal.addEventListener("abort", abortGroup, { once: true });
|
|
1674
|
-
callSignal.addEventListener("abort", abortCall, { once: true });
|
|
1675
|
-
}
|
|
1676
|
-
return {
|
|
1677
|
-
options: { ...options, signal: controller.signal },
|
|
1678
|
-
cleanup() {
|
|
1679
|
-
signal.removeEventListener("abort", abortGroup);
|
|
1680
|
-
callSignal.removeEventListener("abort", abortCall);
|
|
1681
|
-
}
|
|
1682
|
-
};
|
|
1683
|
-
}
|
|
1684
|
-
function linkParentAbort(parentSignal, group, setFailure) {
|
|
1685
|
-
if (!parentSignal) {
|
|
1686
|
-
return () => {
|
|
1687
|
-
};
|
|
1688
|
-
}
|
|
1689
|
-
const abort = () => {
|
|
1690
|
-
const error = parentSignal.reason;
|
|
1691
|
-
setFailure(error);
|
|
1692
|
-
group.abort(error);
|
|
1693
|
-
};
|
|
1694
|
-
if (parentSignal.aborted) {
|
|
1695
|
-
abort();
|
|
1696
|
-
return () => {
|
|
1697
|
-
};
|
|
1698
|
-
}
|
|
1699
|
-
parentSignal.addEventListener("abort", abort, { once: true });
|
|
1700
|
-
return () => parentSignal.removeEventListener("abort", abort);
|
|
1701
|
-
}
|
|
1702
|
-
function throwIfAborted(signal) {
|
|
1703
|
-
if (signal.aborted) {
|
|
1704
|
-
throw signal.reason;
|
|
1705
|
-
}
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
|
-
// packages/safejs/src/modules/agent.ts
|
|
1709
|
-
var AgentSpawnError = class extends Error {
|
|
1710
|
-
result;
|
|
1711
|
-
constructor(result) {
|
|
1712
|
-
super(createSpawnFailureMessage(result));
|
|
1713
|
-
this.name = "AgentSpawnError";
|
|
1714
|
-
this.result = result;
|
|
1715
|
-
hostErrorData.set(this, { result });
|
|
1716
|
-
}
|
|
1717
|
-
};
|
|
1718
|
-
var activeUsageAccumulator = new AsyncLocalStorage();
|
|
1719
|
-
function createSpawnUsageAccumulator() {
|
|
1720
|
-
let inputTokens = 0;
|
|
1721
|
-
let outputTokens = 0;
|
|
1722
|
-
let cachedTokens = 0;
|
|
1723
|
-
let costUsd;
|
|
1724
|
-
let spawnCount = 0;
|
|
1725
|
-
let attemptCount = 0;
|
|
1726
|
-
return {
|
|
1727
|
-
beginAttempt() {
|
|
1728
|
-
attemptCount += 1;
|
|
1729
|
-
},
|
|
1730
|
-
beginSpawn() {
|
|
1731
|
-
spawnCount += 1;
|
|
1732
|
-
},
|
|
1733
|
-
record(usage) {
|
|
1734
|
-
if (usage === void 0) {
|
|
1735
|
-
return;
|
|
1736
|
-
}
|
|
1737
|
-
inputTokens += usage.inputTokens;
|
|
1738
|
-
outputTokens += usage.outputTokens;
|
|
1739
|
-
cachedTokens += usage.cachedTokens ?? 0;
|
|
1740
|
-
if (usage.costUsd !== void 0) {
|
|
1741
|
-
costUsd = (costUsd ?? 0) + usage.costUsd;
|
|
1742
|
-
}
|
|
1743
|
-
},
|
|
1744
|
-
reset() {
|
|
1745
|
-
inputTokens = 0;
|
|
1746
|
-
outputTokens = 0;
|
|
1747
|
-
cachedTokens = 0;
|
|
1748
|
-
costUsd = void 0;
|
|
1749
|
-
spawnCount = 0;
|
|
1750
|
-
attemptCount = 0;
|
|
1751
|
-
},
|
|
1752
|
-
snapshot() {
|
|
1753
|
-
return {
|
|
1754
|
-
inputTokens,
|
|
1755
|
-
outputTokens,
|
|
1756
|
-
cachedTokens,
|
|
1757
|
-
...costUsd === void 0 ? {} : { costUsd },
|
|
1758
|
-
spawnCount,
|
|
1759
|
-
...attemptCount === spawnCount ? {} : { attemptCount }
|
|
1760
|
-
};
|
|
1761
|
-
}
|
|
1762
|
-
};
|
|
1763
|
-
}
|
|
1764
|
-
async function runWithSpawnUsageAccumulator(accumulator, operation) {
|
|
1765
|
-
accumulator.reset();
|
|
1766
|
-
return await activeUsageAccumulator.run(accumulator, operation);
|
|
1767
|
-
}
|
|
1768
|
-
function makeAgentModule(spawnAgent, moduleOptions = {}) {
|
|
1769
|
-
const defaultRetry = moduleOptions.defaultRetry === void 0 ? void 0 : normalizeRetryOptions(moduleOptions.defaultRetry);
|
|
1770
|
-
let nextSpawnId = 1;
|
|
1771
|
-
const spawnOnce = async (agentDef, options) => {
|
|
1772
|
-
const input = resolveSpawnInput(agentDef, options);
|
|
1773
|
-
const spawnId = nextSpawnId;
|
|
1774
|
-
nextSpawnId += 1;
|
|
1775
|
-
recordActiveSpawnStart();
|
|
1776
|
-
return runObservedSpawn(moduleOptions.otelSink, input, async () => {
|
|
1777
|
-
return defaultRetry === void 0 ? runSpawnAttempt(spawnAgent, input, moduleOptions.onEvent, spawnId) : runSpawnRetry(spawnAgent, input, defaultRetry, moduleOptions.onEvent, spawnId);
|
|
1778
|
-
});
|
|
1779
|
-
};
|
|
1780
|
-
return {
|
|
1781
|
-
spawn: Object.assign(spawnOnce, {
|
|
1782
|
-
async retry(agentDef, options, retryOptions) {
|
|
1783
|
-
const input = resolveSpawnInput(agentDef, options);
|
|
1784
|
-
const normalizedRetry = normalizeRetryOptions(retryOptions);
|
|
1785
|
-
const spawnId = nextSpawnId;
|
|
1786
|
-
nextSpawnId += 1;
|
|
1787
|
-
recordActiveSpawnStart();
|
|
1788
|
-
return await runObservedSpawn(
|
|
1789
|
-
moduleOptions.otelSink,
|
|
1790
|
-
input,
|
|
1791
|
-
() => runSpawnRetry(
|
|
1792
|
-
spawnAgent,
|
|
1793
|
-
input,
|
|
1794
|
-
normalizedRetry,
|
|
1795
|
-
moduleOptions.onEvent,
|
|
1796
|
-
spawnId
|
|
1797
|
-
)
|
|
1798
|
-
);
|
|
1799
|
-
},
|
|
1800
|
-
async parallel(calls, options = {}) {
|
|
1801
|
-
const check = readOptionalBoolean(getOwnProperty(options, "check"), "Agent parallel options check") ?? false;
|
|
1802
|
-
const parallel = createSpawnParallel((agentDef, spawnOptions) => ({
|
|
1803
|
-
events: (async function* () {
|
|
1804
|
-
})(),
|
|
1805
|
-
result: (() => {
|
|
1806
|
-
const input = resolveSpawnInput(agentDef, spawnOptions);
|
|
1807
|
-
const spawnId = nextSpawnId;
|
|
1808
|
-
nextSpawnId += 1;
|
|
1809
|
-
recordActiveSpawnStart();
|
|
1810
|
-
return runObservedSpawn(
|
|
1811
|
-
moduleOptions.otelSink,
|
|
1812
|
-
input,
|
|
1813
|
-
() => runSpawnRetry(
|
|
1814
|
-
spawnAgent,
|
|
1815
|
-
input,
|
|
1816
|
-
defaultRetry ?? oneAttemptRetryOptions,
|
|
1817
|
-
(event) => moduleOptions.onEvent?.(
|
|
1818
|
-
event.type === "spawn.failed" ? { ...event, checked: event.checked || check } : event
|
|
1819
|
-
),
|
|
1820
|
-
spawnId
|
|
1821
|
-
)
|
|
1822
|
-
);
|
|
1823
|
-
})()
|
|
1824
|
-
}));
|
|
1825
|
-
try {
|
|
1826
|
-
return await parallel(calls, { ...options, check });
|
|
1827
|
-
} catch (error) {
|
|
1828
|
-
if (error instanceof SpawnParallelError) {
|
|
1829
|
-
hostErrorData.set(error, {
|
|
1830
|
-
index: error.index,
|
|
1831
|
-
result: error.result,
|
|
1832
|
-
results: error.results
|
|
1833
|
-
});
|
|
1834
|
-
}
|
|
1835
|
-
throw error;
|
|
1836
|
-
}
|
|
1837
|
-
}
|
|
1838
|
-
})
|
|
1839
|
-
};
|
|
1840
|
-
}
|
|
1841
|
-
async function runSpawnAttempt(spawnAgent, input, onEvent, spawnId) {
|
|
1842
|
-
const task = resolveTaskLabel(input);
|
|
1843
|
-
const startedAt = Date.now();
|
|
1844
|
-
try {
|
|
1845
|
-
throwIfAborted2(input.signal);
|
|
1846
|
-
} catch (error) {
|
|
1847
|
-
emitSpawnCancelled(onEvent, spawnId, input.agent, task, 1, 1, Date.now() - startedAt, error);
|
|
1848
|
-
throw error;
|
|
1849
|
-
}
|
|
1850
|
-
emitSpawnEvent(onEvent, {
|
|
1851
|
-
type: "spawn.started",
|
|
1852
|
-
spawnId,
|
|
1853
|
-
agent: input.agent,
|
|
1854
|
-
task,
|
|
1855
|
-
attempt: 1,
|
|
1856
|
-
maxAttempts: 1
|
|
1857
|
-
});
|
|
1858
|
-
try {
|
|
1859
|
-
recordActiveSpawnAttempt();
|
|
1860
|
-
const result = validateSpawnResult(await spawnAgent(toProviderSpawnInput(input)));
|
|
1861
|
-
throwIfAborted2(input.signal);
|
|
1862
|
-
recordActiveSpawnUsage(result.usage);
|
|
1863
|
-
if (result.exitCode !== 0) {
|
|
1864
|
-
const error = new AgentSpawnError(result);
|
|
1865
|
-
if (input.check) {
|
|
1866
|
-
throw error;
|
|
1867
|
-
}
|
|
1868
|
-
emitFinalSpawnFailure(
|
|
1869
|
-
onEvent,
|
|
1870
|
-
spawnId,
|
|
1871
|
-
input.agent,
|
|
1872
|
-
task,
|
|
1873
|
-
1,
|
|
1874
|
-
1,
|
|
1875
|
-
result.durationMs,
|
|
1876
|
-
error,
|
|
1877
|
-
false
|
|
1878
|
-
);
|
|
1879
|
-
return result;
|
|
1880
|
-
}
|
|
1881
|
-
emitSpawnEvent(onEvent, {
|
|
1882
|
-
type: "spawn.succeeded",
|
|
1883
|
-
spawnId,
|
|
1884
|
-
agent: input.agent,
|
|
1885
|
-
task,
|
|
1886
|
-
attempt: 1,
|
|
1887
|
-
maxAttempts: 1,
|
|
1888
|
-
durationMs: result.durationMs
|
|
1889
|
-
});
|
|
1890
|
-
return result;
|
|
1891
|
-
} catch (error) {
|
|
1892
|
-
if (isAbortError(error, input.signal)) {
|
|
1893
|
-
const reason = input.signal?.aborted ? readAbortReason(input.signal) : error;
|
|
1894
|
-
emitSpawnCancelled(onEvent, spawnId, input.agent, task, 1, 1, Date.now() - startedAt, reason);
|
|
1895
|
-
throw reason;
|
|
1896
|
-
}
|
|
1897
|
-
emitSpawnEvent(onEvent, {
|
|
1898
|
-
type: "spawn.failed",
|
|
1899
|
-
checked: true,
|
|
1900
|
-
spawnId,
|
|
1901
|
-
agent: input.agent,
|
|
1902
|
-
task,
|
|
1903
|
-
attempt: 1,
|
|
1904
|
-
maxAttempts: 1,
|
|
1905
|
-
durationMs: Date.now() - startedAt,
|
|
1906
|
-
error: formatSpawnError(error)
|
|
1907
|
-
});
|
|
1908
|
-
throw error;
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
function runObservedSpawn(moduleSink, input, operation) {
|
|
1912
|
-
const otelSink = input.otelSink ?? moduleSink ?? getActiveOtelSink();
|
|
1913
|
-
const cwd = input.cwd ?? readCurrentWorkingDirectory();
|
|
1914
|
-
const span = safeStartSpan(otelSink, "agent.spawn", {
|
|
1915
|
-
agent: input.agent,
|
|
1916
|
-
mode: input.mode ?? DEFAULT_SPAWN_MODE,
|
|
1917
|
-
cwd
|
|
1918
|
-
});
|
|
1919
|
-
const deactivateSpan = activateOtelSpan(span);
|
|
1920
|
-
safeAddEvent(span, "prompt", { prompt: input.prompt });
|
|
1921
|
-
const promise = (async () => {
|
|
1922
|
-
try {
|
|
1923
|
-
const result = await operation();
|
|
1924
|
-
safeAddEvent(span, "summary", { summary: result.summary });
|
|
1925
|
-
safeAddEvent(span, "exit", {
|
|
1926
|
-
exitCode: result.exitCode,
|
|
1927
|
-
durationMs: result.durationMs
|
|
1928
|
-
});
|
|
1929
|
-
return result;
|
|
1930
|
-
} catch (error) {
|
|
1931
|
-
safeRecordException(otelSink, span, error);
|
|
1932
|
-
throw error;
|
|
1933
|
-
} finally {
|
|
1934
|
-
deactivateSpan();
|
|
1935
|
-
safeEndSpan(span);
|
|
1936
|
-
}
|
|
1937
|
-
})();
|
|
1938
|
-
bindOtelSpan(promise, span);
|
|
1939
|
-
return promise;
|
|
1940
|
-
}
|
|
1941
|
-
function readCurrentWorkingDirectory() {
|
|
1942
|
-
try {
|
|
1943
|
-
return process.cwd();
|
|
1944
|
-
} catch (error) {
|
|
1945
|
-
throw new Error(`Unable to resolve current working directory: ${formatSpawnError(error)}`);
|
|
1946
|
-
}
|
|
1947
|
-
}
|
|
1948
|
-
async function runSpawnRetry(spawnAgent, input, retryOptions, onEvent, spawnId) {
|
|
1949
|
-
const task = resolveTaskLabel(input);
|
|
1950
|
-
const startedAt = Date.now();
|
|
1951
|
-
for (let attempt = 1; attempt <= retryOptions.maxAttempts; attempt += 1) {
|
|
1952
|
-
try {
|
|
1953
|
-
throwIfAborted2(input.signal);
|
|
1954
|
-
} catch (error2) {
|
|
1955
|
-
emitSpawnCancelled(
|
|
1956
|
-
onEvent,
|
|
1957
|
-
spawnId,
|
|
1958
|
-
input.agent,
|
|
1959
|
-
task,
|
|
1960
|
-
attempt,
|
|
1961
|
-
retryOptions.maxAttempts,
|
|
1962
|
-
Date.now() - startedAt,
|
|
1963
|
-
error2
|
|
1964
|
-
);
|
|
1965
|
-
throw error2;
|
|
1966
|
-
}
|
|
1967
|
-
emitSpawnEvent(onEvent, {
|
|
1968
|
-
type: "spawn.started",
|
|
1969
|
-
spawnId,
|
|
1970
|
-
agent: input.agent,
|
|
1971
|
-
task,
|
|
1972
|
-
attempt,
|
|
1973
|
-
maxAttempts: retryOptions.maxAttempts
|
|
1974
|
-
});
|
|
1975
|
-
let result;
|
|
1976
|
-
try {
|
|
1977
|
-
recordActiveSpawnAttempt();
|
|
1978
|
-
result = validateSpawnResult(await spawnAgent(toProviderSpawnInput(input)));
|
|
1979
|
-
throwIfAborted2(input.signal);
|
|
1980
|
-
} catch (error2) {
|
|
1981
|
-
if (isAbortError(error2, input.signal)) {
|
|
1982
|
-
const reason = input.signal?.aborted ? readAbortReason(input.signal) : error2;
|
|
1983
|
-
emitSpawnCancelled(
|
|
1984
|
-
onEvent,
|
|
1985
|
-
spawnId,
|
|
1986
|
-
input.agent,
|
|
1987
|
-
task,
|
|
1988
|
-
attempt,
|
|
1989
|
-
retryOptions.maxAttempts,
|
|
1990
|
-
Date.now() - startedAt,
|
|
1991
|
-
reason
|
|
1992
|
-
);
|
|
1993
|
-
throw reason;
|
|
1994
|
-
}
|
|
1995
|
-
if (attempt >= retryOptions.maxAttempts) {
|
|
1996
|
-
emitFinalSpawnFailure(
|
|
1997
|
-
onEvent,
|
|
1998
|
-
spawnId,
|
|
1999
|
-
input.agent,
|
|
2000
|
-
task,
|
|
2001
|
-
attempt,
|
|
2002
|
-
retryOptions.maxAttempts,
|
|
2003
|
-
Date.now() - startedAt,
|
|
2004
|
-
error2
|
|
2005
|
-
);
|
|
2006
|
-
throw error2;
|
|
2007
|
-
}
|
|
2008
|
-
let retryable2;
|
|
2009
|
-
try {
|
|
2010
|
-
retryable2 = retryOptions.isErrorRetryable(error2);
|
|
2011
|
-
} catch (classifierError) {
|
|
2012
|
-
emitFinalSpawnFailure(
|
|
2013
|
-
onEvent,
|
|
2014
|
-
spawnId,
|
|
2015
|
-
input.agent,
|
|
2016
|
-
task,
|
|
2017
|
-
attempt,
|
|
2018
|
-
retryOptions.maxAttempts,
|
|
2019
|
-
Date.now() - startedAt,
|
|
2020
|
-
classifierError
|
|
2021
|
-
);
|
|
2022
|
-
throw classifierError;
|
|
2023
|
-
}
|
|
2024
|
-
if (!retryable2) {
|
|
2025
|
-
emitFinalSpawnFailure(
|
|
2026
|
-
onEvent,
|
|
2027
|
-
spawnId,
|
|
2028
|
-
input.agent,
|
|
2029
|
-
task,
|
|
2030
|
-
attempt,
|
|
2031
|
-
retryOptions.maxAttempts,
|
|
2032
|
-
Date.now() - startedAt,
|
|
2033
|
-
error2
|
|
2034
|
-
);
|
|
2035
|
-
throw error2;
|
|
2036
|
-
}
|
|
2037
|
-
try {
|
|
2038
|
-
await retryOrThrow(
|
|
2039
|
-
error2,
|
|
2040
|
-
input,
|
|
2041
|
-
retryOptions,
|
|
2042
|
-
onEvent,
|
|
2043
|
-
spawnId,
|
|
2044
|
-
task,
|
|
2045
|
-
attempt,
|
|
2046
|
-
Date.now() - startedAt
|
|
2047
|
-
);
|
|
2048
|
-
} catch (retryError) {
|
|
2049
|
-
if (isAbortError(retryError, input.signal)) {
|
|
2050
|
-
emitSpawnCancelled(
|
|
2051
|
-
onEvent,
|
|
2052
|
-
spawnId,
|
|
2053
|
-
input.agent,
|
|
2054
|
-
task,
|
|
2055
|
-
attempt,
|
|
2056
|
-
retryOptions.maxAttempts,
|
|
2057
|
-
Date.now() - startedAt,
|
|
2058
|
-
retryError
|
|
2059
|
-
);
|
|
2060
|
-
}
|
|
2061
|
-
throw retryError;
|
|
2062
|
-
}
|
|
2063
|
-
continue;
|
|
2064
|
-
}
|
|
2065
|
-
recordActiveSpawnUsage(result.usage);
|
|
2066
|
-
if (result.exitCode === 0) {
|
|
2067
|
-
emitSpawnEvent(onEvent, {
|
|
2068
|
-
type: "spawn.succeeded",
|
|
2069
|
-
spawnId,
|
|
2070
|
-
agent: input.agent,
|
|
2071
|
-
task,
|
|
2072
|
-
attempt,
|
|
2073
|
-
maxAttempts: retryOptions.maxAttempts,
|
|
2074
|
-
durationMs: Date.now() - startedAt
|
|
2075
|
-
});
|
|
2076
|
-
return result;
|
|
2077
|
-
}
|
|
2078
|
-
const error = new AgentSpawnError(result);
|
|
2079
|
-
if (attempt >= retryOptions.maxAttempts) {
|
|
2080
|
-
emitFinalSpawnFailure(
|
|
2081
|
-
onEvent,
|
|
2082
|
-
spawnId,
|
|
2083
|
-
input.agent,
|
|
2084
|
-
task,
|
|
2085
|
-
attempt,
|
|
2086
|
-
retryOptions.maxAttempts,
|
|
2087
|
-
Date.now() - startedAt,
|
|
2088
|
-
error,
|
|
2089
|
-
input.check
|
|
2090
|
-
);
|
|
2091
|
-
if (input.check) {
|
|
2092
|
-
throw error;
|
|
2093
|
-
}
|
|
2094
|
-
return result;
|
|
2095
|
-
}
|
|
2096
|
-
let retryable;
|
|
2097
|
-
try {
|
|
2098
|
-
retryable = retryOptions.isRetryable(result);
|
|
2099
|
-
} catch (classifierError) {
|
|
2100
|
-
emitFinalSpawnFailure(
|
|
2101
|
-
onEvent,
|
|
2102
|
-
spawnId,
|
|
2103
|
-
input.agent,
|
|
2104
|
-
task,
|
|
2105
|
-
attempt,
|
|
2106
|
-
retryOptions.maxAttempts,
|
|
2107
|
-
Date.now() - startedAt,
|
|
2108
|
-
classifierError
|
|
2109
|
-
);
|
|
2110
|
-
throw classifierError;
|
|
2111
|
-
}
|
|
2112
|
-
if (!retryable) {
|
|
2113
|
-
emitFinalSpawnFailure(
|
|
2114
|
-
onEvent,
|
|
2115
|
-
spawnId,
|
|
2116
|
-
input.agent,
|
|
2117
|
-
task,
|
|
2118
|
-
attempt,
|
|
2119
|
-
retryOptions.maxAttempts,
|
|
2120
|
-
Date.now() - startedAt,
|
|
2121
|
-
error,
|
|
2122
|
-
input.check
|
|
2123
|
-
);
|
|
2124
|
-
if (input.check) {
|
|
2125
|
-
throw error;
|
|
2126
|
-
}
|
|
2127
|
-
return result;
|
|
2128
|
-
}
|
|
2129
|
-
try {
|
|
2130
|
-
await scheduleRetry(error, input, retryOptions, onEvent, spawnId, task, attempt);
|
|
2131
|
-
} catch (retryError) {
|
|
2132
|
-
if (isAbortError(retryError, input.signal)) {
|
|
2133
|
-
emitSpawnCancelled(
|
|
2134
|
-
onEvent,
|
|
2135
|
-
spawnId,
|
|
2136
|
-
input.agent,
|
|
2137
|
-
task,
|
|
2138
|
-
attempt,
|
|
2139
|
-
retryOptions.maxAttempts,
|
|
2140
|
-
Date.now() - startedAt,
|
|
2141
|
-
retryError
|
|
2142
|
-
);
|
|
2143
|
-
}
|
|
2144
|
-
throw retryError;
|
|
2145
|
-
}
|
|
2146
|
-
}
|
|
2147
|
-
throw new Error("agent.spawn.retry reached an unreachable retry state.");
|
|
2148
|
-
}
|
|
2149
|
-
function emitSpawnCancelled(onEvent, spawnId, agent, task, attempt, maxAttempts, durationMs, error) {
|
|
2150
|
-
emitSpawnEvent(onEvent, {
|
|
2151
|
-
type: "spawn.cancelled",
|
|
2152
|
-
spawnId,
|
|
2153
|
-
agent,
|
|
2154
|
-
task,
|
|
2155
|
-
attempt,
|
|
2156
|
-
maxAttempts,
|
|
2157
|
-
durationMs,
|
|
2158
|
-
reason: formatSpawnError(error)
|
|
2159
|
-
});
|
|
2160
|
-
}
|
|
2161
|
-
async function retryOrThrow(error, input, retryOptions, onEvent, spawnId, task, attempt, durationMs) {
|
|
2162
|
-
if (attempt >= retryOptions.maxAttempts) {
|
|
2163
|
-
emitFinalSpawnFailure(
|
|
2164
|
-
onEvent,
|
|
2165
|
-
spawnId,
|
|
2166
|
-
input.agent,
|
|
2167
|
-
task,
|
|
2168
|
-
attempt,
|
|
2169
|
-
retryOptions.maxAttempts,
|
|
2170
|
-
durationMs,
|
|
2171
|
-
error
|
|
2172
|
-
);
|
|
2173
|
-
throw error;
|
|
2174
|
-
}
|
|
2175
|
-
await scheduleRetry(error, input, retryOptions, onEvent, spawnId, task, attempt);
|
|
2176
|
-
}
|
|
2177
|
-
async function scheduleRetry(error, input, retryOptions, onEvent, spawnId, task, attempt) {
|
|
2178
|
-
const delayMs = calculateBackoffMs(retryOptions.backoffMs, attempt);
|
|
2179
|
-
emitSpawnEvent(onEvent, {
|
|
2180
|
-
type: "spawn.retry",
|
|
2181
|
-
spawnId,
|
|
2182
|
-
agent: input.agent,
|
|
2183
|
-
task,
|
|
2184
|
-
attempt,
|
|
2185
|
-
maxAttempts: retryOptions.maxAttempts,
|
|
2186
|
-
delayMs,
|
|
2187
|
-
error: formatSpawnError(error)
|
|
2188
|
-
});
|
|
2189
|
-
await sleep(delayMs, input.signal);
|
|
2190
|
-
}
|
|
2191
|
-
function emitFinalSpawnFailure(onEvent, spawnId, agent, task, attempt, maxAttempts, durationMs, error, checked = true) {
|
|
2192
|
-
emitSpawnEvent(onEvent, {
|
|
2193
|
-
type: "spawn.failed",
|
|
2194
|
-
checked,
|
|
2195
|
-
spawnId,
|
|
2196
|
-
agent,
|
|
2197
|
-
task,
|
|
2198
|
-
attempt,
|
|
2199
|
-
maxAttempts,
|
|
2200
|
-
durationMs,
|
|
2201
|
-
error: formatSpawnError(error)
|
|
2202
|
-
});
|
|
2203
|
-
}
|
|
2204
|
-
function emitSpawnEvent(onEvent, event) {
|
|
2205
|
-
try {
|
|
2206
|
-
const agent = sanitizeLifecycleText(event.agent, 48) || "agent";
|
|
2207
|
-
const result = onEvent?.({ ...event, agent });
|
|
2208
|
-
if (isPromiseLike(result)) {
|
|
2209
|
-
void result.catch((error) => warnSpawnEventObserverFailure(error));
|
|
2210
|
-
}
|
|
2211
|
-
} catch (error) {
|
|
2212
|
-
warnSpawnEventObserverFailure(error);
|
|
2213
|
-
}
|
|
2214
|
-
}
|
|
2215
|
-
function isPromiseLike(value) {
|
|
2216
|
-
return typeof value === "object" && value !== null && "catch" in value && typeof value.catch === "function";
|
|
2217
|
-
}
|
|
2218
|
-
function warnSpawnEventObserverFailure(error) {
|
|
2219
|
-
console.warn(`Agent spawn event observer failed: ${formatSpawnError(error)}`);
|
|
2220
|
-
}
|
|
2221
|
-
function createTaskLabel(prompt) {
|
|
2222
|
-
const lines = prompt.split("\n").map((line) => line.trim());
|
|
2223
|
-
const taskHeadingIndex = lines.indexOf("# Task");
|
|
2224
|
-
const relevantLines = taskHeadingIndex < 0 ? lines : lines.slice(taskHeadingIndex + 1);
|
|
2225
|
-
const firstLine = sanitizeLifecycleText(
|
|
2226
|
-
relevantLines.find((line) => line.length > 0) ?? "agent task",
|
|
2227
|
-
72
|
|
2228
|
-
);
|
|
2229
|
-
if (firstLine.length === 0) {
|
|
2230
|
-
return "agent task";
|
|
2231
|
-
}
|
|
2232
|
-
return firstLine.length > 72 ? `${firstLine.slice(0, 71)}\u2026` : firstLine;
|
|
2233
|
-
}
|
|
2234
|
-
function resolveTaskLabel(input) {
|
|
2235
|
-
return input.label ?? createTaskLabel(input.prompt);
|
|
2236
|
-
}
|
|
2237
|
-
function isAbortError(error, signal) {
|
|
2238
|
-
return signal?.aborted === true || readErrorField(error, "name") === "AbortError";
|
|
2239
|
-
}
|
|
2240
|
-
function formatSpawnError(error) {
|
|
2241
|
-
return sanitizeLifecycleText(readErrorField(error, "message") ?? String(error), 400);
|
|
2242
|
-
}
|
|
2243
|
-
function sanitizeLifecycleText(value, maxLength) {
|
|
2244
|
-
let sanitized = "";
|
|
2245
|
-
for (const character of value) {
|
|
2246
|
-
const code = character.charCodeAt(0);
|
|
2247
|
-
if (character === "\n" || character === "\r" || character === " " || code < 32 || code === 127) {
|
|
2248
|
-
sanitized += " ";
|
|
2249
|
-
} else {
|
|
2250
|
-
sanitized += character;
|
|
2251
|
-
}
|
|
2252
|
-
}
|
|
2253
|
-
const compact = sanitized.split(" ").filter((part) => part.length > 0).join(" ");
|
|
2254
|
-
return compact.length > maxLength ? `${compact.slice(0, maxLength - 1)}\u2026` : compact;
|
|
2255
|
-
}
|
|
2256
|
-
function readErrorField(error, field) {
|
|
2257
|
-
if (typeof error !== "object" || error === null || !(field in error)) {
|
|
2258
|
-
return void 0;
|
|
2259
|
-
}
|
|
2260
|
-
const value = error[field];
|
|
2261
|
-
return typeof value === "string" ? value : void 0;
|
|
2262
|
-
}
|
|
2263
|
-
function normalizeRetryOptions(retryOptions) {
|
|
2264
|
-
if (!isRecord2(retryOptions)) {
|
|
2265
|
-
throw new Error("Agent spawn retry options must be an object.");
|
|
2266
|
-
}
|
|
2267
|
-
const maxAttempts = readFiniteNumber(
|
|
2268
|
-
getOwnProperty(retryOptions, "maxAttempts"),
|
|
2269
|
-
"Agent spawn retry maxAttempts"
|
|
2270
|
-
);
|
|
2271
|
-
if (!Number.isInteger(maxAttempts) || maxAttempts < 1) {
|
|
2272
|
-
throw new Error("Agent spawn retry maxAttempts must be an integer greater than or equal to 1.");
|
|
2273
|
-
}
|
|
2274
|
-
if (maxAttempts > 5) {
|
|
2275
|
-
throw new Error("Agent spawn retry maxAttempts must not exceed 5.");
|
|
2276
|
-
}
|
|
2277
|
-
const backoffMs = readNonNegativeFiniteNumber(
|
|
2278
|
-
getOwnProperty(retryOptions, "backoffMs"),
|
|
2279
|
-
"Agent spawn retry backoffMs"
|
|
2280
|
-
);
|
|
2281
|
-
const isRetryableValue = getOwnProperty(retryOptions, "isRetryable");
|
|
2282
|
-
if (isRetryableValue !== void 0 && typeof isRetryableValue !== "function") {
|
|
2283
|
-
throw new Error("Agent spawn retry isRetryable must be a function.");
|
|
2284
|
-
}
|
|
2285
|
-
const isRetryable = isRetryableValue === void 0 ? defaultIsRetryable : isRetryableValue;
|
|
2286
|
-
const isErrorRetryableValue = getOwnProperty(retryOptions, "isErrorRetryable");
|
|
2287
|
-
if (isErrorRetryableValue !== void 0 && typeof isErrorRetryableValue !== "function") {
|
|
2288
|
-
throw new Error("Agent spawn retry isErrorRetryable must be a function.");
|
|
2289
|
-
}
|
|
2290
|
-
return createNullRecord({
|
|
2291
|
-
maxAttempts,
|
|
2292
|
-
backoffMs,
|
|
2293
|
-
isErrorRetryable: isErrorRetryableValue === void 0 ? () => true : isErrorRetryableValue,
|
|
2294
|
-
isRetryable
|
|
2295
|
-
});
|
|
2296
|
-
}
|
|
2297
|
-
function defaultIsRetryable(result) {
|
|
2298
|
-
return result.exitCode === 1 || result.exitCode === 124 || result.exitCode === 125 || result.exitCode === 137;
|
|
2299
|
-
}
|
|
2300
|
-
var oneAttemptRetryOptions = {
|
|
2301
|
-
maxAttempts: 1,
|
|
2302
|
-
backoffMs: 0,
|
|
2303
|
-
isErrorRetryable: () => false,
|
|
2304
|
-
isRetryable: () => false
|
|
2305
|
-
};
|
|
2306
|
-
function calculateBackoffMs(baseBackoffMs, completedAttempt) {
|
|
2307
|
-
return Math.min(baseBackoffMs * 2 ** (completedAttempt - 1), 3e4);
|
|
2308
|
-
}
|
|
2309
|
-
function sleep(delayMs, signal) {
|
|
2310
|
-
throwIfAborted2(signal);
|
|
2311
|
-
return new Promise((resolve3, reject) => {
|
|
2312
|
-
const timeout = setTimeout(() => {
|
|
2313
|
-
signal?.removeEventListener("abort", onAbort);
|
|
2314
|
-
resolve3();
|
|
2315
|
-
}, delayMs);
|
|
2316
|
-
const onAbort = () => {
|
|
2317
|
-
clearTimeout(timeout);
|
|
2318
|
-
reject(readAbortReason(signal));
|
|
2319
|
-
};
|
|
2320
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
2321
|
-
});
|
|
2322
|
-
}
|
|
2323
|
-
function throwIfAborted2(signal) {
|
|
2324
|
-
if (signal?.aborted) {
|
|
2325
|
-
throw readAbortReason(signal);
|
|
2326
|
-
}
|
|
2327
|
-
}
|
|
2328
|
-
function readAbortReason(signal) {
|
|
2329
|
-
if (signal?.reason !== void 0) return signal.reason;
|
|
2330
|
-
const error = new Error("Agent spawn retry aborted");
|
|
2331
|
-
error.name = "AbortError";
|
|
2332
|
-
return error;
|
|
2333
|
-
}
|
|
2334
|
-
function resolveSpawnInput(agentDef, options) {
|
|
2335
|
-
const definition = normalizeAgentDefinition(agentDef);
|
|
2336
|
-
const normalizedOptions = normalizeSpawnOptions(options);
|
|
2337
|
-
const mode = normalizedOptions.mode ?? definition.mode;
|
|
2338
|
-
if (mode !== void 0 && !supportsSpawnMode(definition.agent, mode)) {
|
|
2339
|
-
throw new Error(`Agent "${definition.agent}" does not support mode "${mode}".`);
|
|
2340
|
-
}
|
|
2341
|
-
return createNullRecord({
|
|
2342
|
-
agent: definition.agent,
|
|
2343
|
-
prompt: prependSystemPrompt(definition.prompt, normalizedOptions.prompt),
|
|
2344
|
-
check: normalizedOptions.check ?? false,
|
|
2345
|
-
...normalizedOptions.label !== void 0 ? { label: normalizedOptions.label } : {},
|
|
2346
|
-
...normalizedOptions.model ?? definition.model ? { model: normalizedOptions.model ?? definition.model } : {},
|
|
2347
|
-
...normalizedOptions.mode ?? definition.mode ? { mode: normalizedOptions.mode ?? definition.mode } : {},
|
|
2348
|
-
...normalizedOptions.cwd ?? definition.cwd ? { cwd: normalizedOptions.cwd ?? definition.cwd } : {},
|
|
2349
|
-
...normalizedOptions.otelSink !== void 0 ? { otelSink: normalizedOptions.otelSink } : {},
|
|
2350
|
-
...normalizedOptions.mcp ?? definition.mcp ? { mcp: normalizedOptions.mcp ?? definition.mcp } : {},
|
|
2351
|
-
...normalizedOptions.timeoutMs !== void 0 ? { timeoutMs: normalizedOptions.timeoutMs } : {},
|
|
2352
|
-
...normalizedOptions.signal !== void 0 ? { signal: normalizedOptions.signal } : {}
|
|
2353
|
-
});
|
|
2354
|
-
}
|
|
2355
|
-
function normalizeAgentDefinition(agentDef) {
|
|
2356
|
-
if (typeof agentDef === "string") {
|
|
2357
|
-
return createNullRecord({
|
|
2358
|
-
agent: readRequiredAgent(agentDef)
|
|
2359
|
-
});
|
|
2360
|
-
}
|
|
2361
|
-
if (!isRecord2(agentDef)) {
|
|
2362
|
-
throw new Error("Agent definition must be a string or object.");
|
|
2363
|
-
}
|
|
2364
|
-
const prompt = getOwnProperty(agentDef, "prompt");
|
|
2365
|
-
const model = getOwnProperty(agentDef, "model");
|
|
2366
|
-
const mode = getOwnProperty(agentDef, "mode");
|
|
2367
|
-
const cwd = getOwnProperty(agentDef, "cwd");
|
|
2368
|
-
const mcp = getOwnProperty(agentDef, "mcp");
|
|
2369
|
-
return createNullRecord({
|
|
2370
|
-
agent: readRequiredAgent(getOwnProperty(agentDef, "agent")),
|
|
2371
|
-
...prompt === void 0 ? {} : { prompt: readOptionalString(prompt, "Agent definition prompt") },
|
|
2372
|
-
...model === void 0 ? {} : { model: readOptionalString(model, "Agent definition model") },
|
|
2373
|
-
...mode === void 0 ? {} : { mode: readSpawnMode(mode, "Agent definition mode") },
|
|
2374
|
-
...cwd === void 0 ? {} : { cwd: readOptionalString(cwd, "Agent definition cwd") },
|
|
2375
|
-
...mcp === void 0 ? {} : { mcp: readMcpConfig(mcp, "Agent definition mcp") }
|
|
2376
|
-
});
|
|
2377
|
-
}
|
|
2378
|
-
function normalizeSpawnOptions(options) {
|
|
2379
|
-
if (!isRecord2(options)) {
|
|
2380
|
-
throw new Error("Agent spawn options must be an object.");
|
|
2381
|
-
}
|
|
2382
|
-
const label = getOwnProperty(options, "label");
|
|
2383
|
-
const model = getOwnProperty(options, "model");
|
|
2384
|
-
const mode = getOwnProperty(options, "mode");
|
|
2385
|
-
const cwd = getOwnProperty(options, "cwd");
|
|
2386
|
-
const otelSink = getOwnProperty(options, "otelSink");
|
|
2387
|
-
const mcp = getOwnProperty(options, "mcp");
|
|
2388
|
-
const timeoutMs = getOwnProperty(options, "timeoutMs");
|
|
2389
|
-
const signal = getOwnProperty(options, "signal");
|
|
2390
|
-
return createNullRecord({
|
|
2391
|
-
prompt: readRequiredPrompt(getOwnProperty(options, "prompt")),
|
|
2392
|
-
check: readOptionalBoolean(getOwnProperty(options, "check"), "Agent spawn options check"),
|
|
2393
|
-
...label === void 0 ? {} : { label: readRequiredString(label, "Agent spawn options label") },
|
|
2394
|
-
...model === void 0 ? {} : { model: readOptionalString(model, "Agent spawn options model") },
|
|
2395
|
-
...mode === void 0 ? {} : { mode: readSpawnMode(mode, "Agent spawn options mode") },
|
|
2396
|
-
...cwd === void 0 ? {} : { cwd: readOptionalString(cwd, "Agent spawn options cwd") },
|
|
2397
|
-
...otelSink === void 0 ? {} : { otelSink: readOtelSink(otelSink) },
|
|
2398
|
-
...mcp === void 0 ? {} : { mcp: readMcpConfig(mcp, "Agent spawn options mcp") },
|
|
2399
|
-
...timeoutMs === void 0 ? {} : {
|
|
2400
|
-
timeoutMs: readNonNegativeFiniteNumber(timeoutMs, "Agent spawn options timeoutMs")
|
|
2401
|
-
},
|
|
2402
|
-
...signal === void 0 ? {} : { signal: readAbortSignal(signal, "Agent spawn options signal") }
|
|
2403
|
-
});
|
|
2404
|
-
}
|
|
2405
|
-
function toProviderSpawnInput(input) {
|
|
2406
|
-
const { label: ignoredLabel, check: ignoredCheck, ...providerInput } = input;
|
|
2407
|
-
void ignoredLabel;
|
|
2408
|
-
void ignoredCheck;
|
|
2409
|
-
return providerInput;
|
|
2410
|
-
}
|
|
2411
|
-
function readOptionalBoolean(value, label) {
|
|
2412
|
-
if (value === void 0) return void 0;
|
|
2413
|
-
if (typeof value !== "boolean") throw new Error(`${label} must be a boolean.`);
|
|
2414
|
-
return value;
|
|
2415
|
-
}
|
|
2416
|
-
function validateSpawnResult(result) {
|
|
2417
|
-
if (!isRecord2(result)) {
|
|
2418
|
-
throw new Error("spawnAgent must resolve to an object result.");
|
|
2419
|
-
}
|
|
2420
|
-
const usage = getOwnProperty(result, "usage");
|
|
2421
|
-
return createNullRecord({
|
|
2422
|
-
exitCode: readFiniteNumber(getOwnProperty(result, "exitCode"), "spawnAgent result exitCode"),
|
|
2423
|
-
stdout: readOptionalString(getOwnProperty(result, "stdout"), "spawnAgent result stdout") ?? "",
|
|
2424
|
-
stderr: readOptionalString(getOwnProperty(result, "stderr"), "spawnAgent result stderr") ?? "",
|
|
2425
|
-
summary: readOptionalString(getOwnProperty(result, "summary"), "spawnAgent result summary") ?? "",
|
|
2426
|
-
durationMs: readNonNegativeFiniteNumber(
|
|
2427
|
-
getOwnProperty(result, "durationMs"),
|
|
2428
|
-
"spawnAgent result durationMs"
|
|
2429
|
-
),
|
|
2430
|
-
...usage === void 0 ? {} : { usage: readSpawnUsage(usage) }
|
|
2431
|
-
});
|
|
2432
|
-
}
|
|
2433
|
-
function recordActiveSpawnUsage(usage) {
|
|
2434
|
-
activeUsageAccumulator.getStore()?.record(usage);
|
|
2435
|
-
}
|
|
2436
|
-
function recordActiveSpawnAttempt() {
|
|
2437
|
-
activeUsageAccumulator.getStore()?.beginAttempt?.();
|
|
2438
|
-
}
|
|
2439
|
-
function recordActiveSpawnStart() {
|
|
2440
|
-
activeUsageAccumulator.getStore()?.beginSpawn?.();
|
|
2441
|
-
}
|
|
2442
|
-
function readSpawnUsage(value) {
|
|
2443
|
-
if (!isRecord2(value)) {
|
|
2444
|
-
throw new Error("spawnAgent result usage must be an object.");
|
|
2445
|
-
}
|
|
2446
|
-
const cachedTokens = getOwnProperty(value, "cachedTokens");
|
|
2447
|
-
const costUsd = getOwnProperty(value, "costUsd");
|
|
2448
|
-
return createNullRecord({
|
|
2449
|
-
inputTokens: readNonNegativeFiniteNumber(
|
|
2450
|
-
getOwnProperty(value, "inputTokens"),
|
|
2451
|
-
"spawnAgent result usage inputTokens"
|
|
2452
|
-
),
|
|
2453
|
-
outputTokens: readNonNegativeFiniteNumber(
|
|
2454
|
-
getOwnProperty(value, "outputTokens"),
|
|
2455
|
-
"spawnAgent result usage outputTokens"
|
|
2456
|
-
),
|
|
2457
|
-
...cachedTokens === void 0 ? {} : {
|
|
2458
|
-
cachedTokens: readNonNegativeFiniteNumber(
|
|
2459
|
-
cachedTokens,
|
|
2460
|
-
"spawnAgent result usage cachedTokens"
|
|
2461
|
-
)
|
|
2462
|
-
},
|
|
2463
|
-
...costUsd === void 0 ? {} : {
|
|
2464
|
-
costUsd: readNonNegativeFiniteNumber(costUsd, "spawnAgent result usage costUsd")
|
|
2465
|
-
}
|
|
2466
|
-
});
|
|
2467
|
-
}
|
|
2468
|
-
function prependSystemPrompt(systemPrompt, userPrompt) {
|
|
2469
|
-
if (systemPrompt === void 0 || systemPrompt.trim().length === 0) {
|
|
2470
|
-
return userPrompt;
|
|
2471
|
-
}
|
|
2472
|
-
return `${systemPrompt}
|
|
2473
|
-
|
|
2474
|
-
# Task
|
|
2475
|
-
|
|
2476
|
-
${userPrompt}`;
|
|
2477
|
-
}
|
|
2478
|
-
function createSpawnFailureMessage(result) {
|
|
2479
|
-
const stderr = result.stderr.trim();
|
|
2480
|
-
const summary = result.summary.trim();
|
|
2481
|
-
return stderr.length > 0 ? `Agent spawn failed with exit code ${result.exitCode}: ${stderr}` : summary.length > 0 ? `Agent spawn failed with exit code ${result.exitCode}: ${summary}` : `Agent spawn failed with exit code ${result.exitCode}.`;
|
|
2482
|
-
}
|
|
2483
|
-
function readRequiredAgent(value) {
|
|
2484
|
-
const agent = readOptionalString(value, "Agent definition agent")?.trim();
|
|
2485
|
-
if (agent === void 0 || agent.length === 0) {
|
|
2486
|
-
throw new Error("Agent definition must define a non-empty agent.");
|
|
2487
|
-
}
|
|
2488
|
-
return agent;
|
|
2489
|
-
}
|
|
2490
|
-
function readRequiredString(value, label) {
|
|
2491
|
-
const text = readOptionalString(value, label)?.trim();
|
|
2492
|
-
if (text === void 0 || text.length === 0) {
|
|
2493
|
-
throw new Error(`${label} must be a non-empty string.`);
|
|
2494
|
-
}
|
|
2495
|
-
return text;
|
|
2496
|
-
}
|
|
2497
|
-
function readRequiredPrompt(value) {
|
|
2498
|
-
const prompt = readOptionalString(value, "Agent spawn options prompt");
|
|
2499
|
-
if (prompt === void 0 || prompt.trim().length === 0) {
|
|
2500
|
-
throw new Error("Agent spawn options must define a non-empty prompt.");
|
|
2501
|
-
}
|
|
2502
|
-
return prompt;
|
|
2503
|
-
}
|
|
2504
|
-
function readSpawnMode(value, label) {
|
|
2505
|
-
if (value === "read" || value === "edit" || value === "auto" || value === "yolo") {
|
|
2506
|
-
return value;
|
|
2507
|
-
}
|
|
2508
|
-
throw new Error(`${label} must be one of: read, edit, auto, yolo.`);
|
|
2509
|
-
}
|
|
2510
|
-
function readMcpConfig(value, label) {
|
|
2511
|
-
if (!isRecord2(value)) {
|
|
2512
|
-
throw new Error(`${label} must be an object.`);
|
|
2513
|
-
}
|
|
2514
|
-
const entries = Object.entries(value).map(
|
|
2515
|
-
([name, server]) => [name, readMcpServer(server, `${label}.${name}`)]
|
|
2516
|
-
);
|
|
2517
|
-
return createNullRecord(Object.fromEntries(entries));
|
|
2518
|
-
}
|
|
2519
|
-
function readMcpServer(value, label) {
|
|
2520
|
-
if (!isRecord2(value)) {
|
|
2521
|
-
throw new Error(`${label} must be an object.`);
|
|
2522
|
-
}
|
|
2523
|
-
const args = getOwnProperty(value, "args");
|
|
2524
|
-
const env = getOwnProperty(value, "env");
|
|
2525
|
-
const timeout = getOwnProperty(value, "timeout");
|
|
2526
|
-
return createNullRecord({
|
|
2527
|
-
command: readNonEmptyString(getOwnProperty(value, "command"), `${label}.command`),
|
|
2528
|
-
...args === void 0 ? {} : { args: readStringArray(args, `${label}.args`) },
|
|
2529
|
-
...env === void 0 ? {} : { env: readStringRecord(env, `${label}.env`) },
|
|
2530
|
-
...timeout === void 0 ? {} : { timeout: readPositiveFiniteNumber(timeout, `${label}.timeout`) }
|
|
2531
|
-
});
|
|
2532
|
-
}
|
|
2533
|
-
function readStringArray(value, label) {
|
|
2534
|
-
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
|
|
2535
|
-
throw new Error(`${label} must be an array of strings.`);
|
|
2536
|
-
}
|
|
2537
|
-
return [...value];
|
|
2538
|
-
}
|
|
2539
|
-
function readStringRecord(value, label) {
|
|
2540
|
-
if (!isRecord2(value)) {
|
|
2541
|
-
throw new Error(`${label} must be an object.`);
|
|
2542
|
-
}
|
|
2543
|
-
const entries = Object.entries(value);
|
|
2544
|
-
if (entries.some(([, entry]) => typeof entry !== "string")) {
|
|
2545
|
-
throw new Error(`${label} must be a string record.`);
|
|
2546
|
-
}
|
|
2547
|
-
return Object.fromEntries(entries);
|
|
2548
|
-
}
|
|
2549
|
-
function readOptionalString(value, label) {
|
|
2550
|
-
if (value === void 0) {
|
|
2551
|
-
return void 0;
|
|
2552
|
-
}
|
|
2553
|
-
if (typeof value !== "string") {
|
|
2554
|
-
throw new Error(`${label} must be a string.`);
|
|
2555
|
-
}
|
|
2556
|
-
return value;
|
|
2557
|
-
}
|
|
2558
|
-
function readNonEmptyString(value, label) {
|
|
2559
|
-
const text = readOptionalString(value, label);
|
|
2560
|
-
if (text === void 0 || text.trim().length === 0) {
|
|
2561
|
-
throw new Error(`${label} must be a non-empty string.`);
|
|
2562
|
-
}
|
|
2563
|
-
return text;
|
|
2564
|
-
}
|
|
2565
|
-
function readFiniteNumber(value, label) {
|
|
2566
|
-
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
2567
|
-
throw new Error(`${label} must be a finite number.`);
|
|
2568
|
-
}
|
|
2569
|
-
return value;
|
|
2570
|
-
}
|
|
2571
|
-
function readNonNegativeFiniteNumber(value, label) {
|
|
2572
|
-
const number = readFiniteNumber(value, label);
|
|
2573
|
-
if (number < 0) {
|
|
2574
|
-
throw new Error(`${label} must be a non-negative finite number.`);
|
|
2575
|
-
}
|
|
2576
|
-
return number;
|
|
2577
|
-
}
|
|
2578
|
-
function readPositiveFiniteNumber(value, label) {
|
|
2579
|
-
const number = readFiniteNumber(value, label);
|
|
2580
|
-
if (number <= 0) {
|
|
2581
|
-
throw new Error(`${label} must be a positive finite number.`);
|
|
2582
|
-
}
|
|
2583
|
-
return number;
|
|
2584
|
-
}
|
|
2585
|
-
function readAbortSignal(value, label) {
|
|
2586
|
-
if (typeof value !== "object" || value === null || typeof value.aborted !== "boolean" || typeof value.addEventListener !== "function" || typeof value.removeEventListener !== "function") {
|
|
2587
|
-
throw new Error(`${label} must be an AbortSignal.`);
|
|
2588
|
-
}
|
|
2589
|
-
return value;
|
|
2590
|
-
}
|
|
2591
|
-
function readOtelSink(value) {
|
|
2592
|
-
if (!isRecord2(value) || typeof value.startSpan !== "function" || typeof value.recordException !== "function") {
|
|
2593
|
-
throw new Error("Agent spawn options otelSink must be an OtelSink.");
|
|
2594
|
-
}
|
|
2595
|
-
return value;
|
|
2596
|
-
}
|
|
2597
|
-
function getOwnProperty(value, name) {
|
|
2598
|
-
return hasOwnProperty(value, name) ? value[name] : void 0;
|
|
2599
|
-
}
|
|
2600
|
-
function hasOwnProperty(value, name) {
|
|
2601
|
-
return Object.prototype.hasOwnProperty.call(value, name);
|
|
2602
|
-
}
|
|
2603
|
-
function createNullRecord(value) {
|
|
2604
|
-
return Object.assign(/* @__PURE__ */ Object.create(null), value);
|
|
2605
|
-
}
|
|
2606
|
-
function isRecord2(value) {
|
|
2607
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2608
|
-
}
|
|
2609
|
-
|
|
2610
|
-
// packages/safejs/src/modules/fail.ts
|
|
2611
|
-
var HarnessFailure = class extends Error {
|
|
2612
|
-
constructor(message) {
|
|
2613
|
-
super(message);
|
|
2614
|
-
this.name = "HarnessFailure";
|
|
2615
|
-
}
|
|
2616
|
-
};
|
|
2617
|
-
function makeFailModule() {
|
|
2618
|
-
function fail(message) {
|
|
2619
|
-
throw new HarnessFailure(readNonEmptyString2(message, "Harness failure message"));
|
|
2620
|
-
}
|
|
2621
|
-
return {
|
|
2622
|
-
default: fail
|
|
2623
|
-
};
|
|
2624
|
-
}
|
|
2625
|
-
function readNonEmptyString2(value, label) {
|
|
2626
|
-
if (typeof value !== "string") {
|
|
2627
|
-
throw new Error(`${label} must be a non-empty string.`);
|
|
2628
|
-
}
|
|
2629
|
-
if (value.trim().length === 0) {
|
|
2630
|
-
throw new Error(`${label} must be a non-empty string.`);
|
|
2631
|
-
}
|
|
2632
|
-
return value;
|
|
2633
|
-
}
|
|
2634
|
-
|
|
2635
|
-
// packages/safejs/src/modules/fs.ts
|
|
2636
|
-
import { constants as nodeFsConstants } from "node:fs";
|
|
2637
|
-
import * as nodeFsPromises from "node:fs/promises";
|
|
2638
|
-
import { dirname as dirname2, isAbsolute as isAbsolute2, resolve as resolve2 } from "node:path";
|
|
2639
|
-
import { inspect } from "node:util";
|
|
2640
|
-
import * as nodeUtil from "node:util";
|
|
2641
|
-
|
|
2642
|
-
// packages/safejs/src/modules/canonical-path.ts
|
|
2643
|
-
import { basename, dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
2644
|
-
var MISSING_PATH_CODES = ["ENOENT", "ENOTDIR"];
|
|
2645
|
-
var NOT_A_SYMLINK_CODES = [...MISSING_PATH_CODES, "EINVAL"];
|
|
2646
|
-
var MAX_SYMLINK_FOLLOWS = 32;
|
|
2647
|
-
async function resolveCanonicalPath({ realpath, readlink }, path) {
|
|
2648
|
-
const missingSegments = [];
|
|
2649
|
-
let current = path;
|
|
2650
|
-
let follows = 0;
|
|
2651
|
-
while (true) {
|
|
2652
|
-
try {
|
|
2653
|
-
const canonicalCurrent = await realpath(current);
|
|
2654
|
-
return resolve(canonicalCurrent, ...missingSegments.reverse());
|
|
2655
|
-
} catch (error) {
|
|
2656
|
-
if (!MISSING_PATH_CODES.includes(getOwnErrorCode(error) ?? "")) {
|
|
2657
|
-
throw error;
|
|
2658
|
-
}
|
|
2659
|
-
const target = await readSymlinkTarget(readlink, current);
|
|
2660
|
-
if (target !== void 0) {
|
|
2661
|
-
if (++follows > MAX_SYMLINK_FOLLOWS) {
|
|
2662
|
-
throw createLoopError(path);
|
|
2663
|
-
}
|
|
2664
|
-
current = isAbsolute(target) ? resolve(target) : resolve(dirname(current), target);
|
|
2665
|
-
continue;
|
|
2666
|
-
}
|
|
2667
|
-
const parent = dirname(current);
|
|
2668
|
-
if (parent === current) {
|
|
2669
|
-
return resolve(path);
|
|
2670
|
-
}
|
|
2671
|
-
missingSegments.push(basename(current));
|
|
2672
|
-
current = parent;
|
|
2673
|
-
}
|
|
2674
|
-
}
|
|
2675
|
-
}
|
|
2676
|
-
async function readSymlinkTarget(readlink, path) {
|
|
2677
|
-
try {
|
|
2678
|
-
return await readlink(path);
|
|
2679
|
-
} catch (error) {
|
|
2680
|
-
if (NOT_A_SYMLINK_CODES.includes(getOwnErrorCode(error) ?? "")) {
|
|
2681
|
-
return void 0;
|
|
2682
|
-
}
|
|
2683
|
-
throw error;
|
|
2684
|
-
}
|
|
2685
|
-
}
|
|
2686
|
-
function createLoopError(path) {
|
|
2687
|
-
const error = new Error(
|
|
2688
|
-
`ELOOP: too many symbolic links encountered, realpath '${path}'`
|
|
2689
|
-
);
|
|
2690
|
-
error.code = "ELOOP";
|
|
2691
|
-
return error;
|
|
2692
|
-
}
|
|
2693
|
-
async function containsPath(stat, canonicalRoot, canonicalPath) {
|
|
2694
|
-
if (containsCanonicalSpelling(canonicalRoot, canonicalPath)) {
|
|
2695
|
-
return true;
|
|
2696
|
-
}
|
|
2697
|
-
return descendsFromRoot(stat, canonicalRoot, canonicalPath);
|
|
2698
|
-
}
|
|
2699
|
-
async function isSamePath(stat, canonicalLeft, canonicalRight) {
|
|
2700
|
-
if (canonicalLeft === canonicalRight) {
|
|
2701
|
-
return true;
|
|
2702
|
-
}
|
|
2703
|
-
const [left, right] = await Promise.all([
|
|
2704
|
-
readIdentity(stat, canonicalLeft),
|
|
2705
|
-
readIdentity(stat, canonicalRight)
|
|
2706
|
-
]);
|
|
2707
|
-
return left !== void 0 && right !== void 0 && left.dev === right.dev && left.ino === right.ino;
|
|
2708
|
-
}
|
|
2709
|
-
function containsCanonicalSpelling(canonicalRoot, canonicalPath) {
|
|
2710
|
-
const relativePath = relative(canonicalRoot, canonicalPath);
|
|
2711
|
-
return !(relativePath === ".." || relativePath.startsWith(`..${sep}`) || isAbsolute(relativePath));
|
|
2712
|
-
}
|
|
2713
|
-
async function descendsFromRoot(stat, canonicalRoot, canonicalPath) {
|
|
2714
|
-
const root = await readIdentity(stat, canonicalRoot);
|
|
2715
|
-
if (root === void 0) {
|
|
2716
|
-
return false;
|
|
2717
|
-
}
|
|
2718
|
-
let current = canonicalPath;
|
|
2719
|
-
while (true) {
|
|
2720
|
-
const identity = await readIdentity(stat, current);
|
|
2721
|
-
if (identity !== void 0 && identity.dev === root.dev && identity.ino === root.ino) {
|
|
2722
|
-
return true;
|
|
2723
|
-
}
|
|
2724
|
-
const parent = dirname(current);
|
|
2725
|
-
if (parent === current) {
|
|
2726
|
-
return false;
|
|
2727
|
-
}
|
|
2728
|
-
current = parent;
|
|
2729
|
-
}
|
|
2730
|
-
}
|
|
2731
|
-
async function readIdentity(stat, path) {
|
|
2732
|
-
try {
|
|
2733
|
-
const { dev, ino } = await stat(path);
|
|
2734
|
-
return { dev, ino };
|
|
2735
|
-
} catch (error) {
|
|
2736
|
-
if (MISSING_PATH_CODES.includes(getOwnErrorCode(error) ?? "")) {
|
|
2737
|
-
return void 0;
|
|
2738
|
-
}
|
|
2739
|
-
throw error;
|
|
2740
|
-
}
|
|
2741
|
-
}
|
|
2742
|
-
|
|
2743
|
-
// packages/safejs/src/modules/fs.ts
|
|
2744
|
-
var BUFFER_BY_DEFAULT = {
|
|
2745
|
-
readFile: true,
|
|
2746
|
-
readdir: false,
|
|
2747
|
-
readlink: false,
|
|
2748
|
-
realpath: false,
|
|
2749
|
-
mkdtemp: false
|
|
2750
|
-
};
|
|
2751
|
-
var REFUSED_OPTION_REASONS = {
|
|
2752
|
-
signal: "the sandbox has no AbortController, and cancelling a run is the host's to request rather than the script's",
|
|
2753
|
-
// @types/node declares this on fs/promises stat and lstat and types
|
|
2754
|
-
// `throwIfNoEntry: false` as answering `Stats | undefined`, but the typings are
|
|
2755
|
-
// ahead of node: only the synchronous API reads the option. Forwarding it would
|
|
2756
|
-
// leave a script holding the ENOENT rejection the typings told it to expect
|
|
2757
|
-
// undefined for, so it is refused rather than dropped.
|
|
2758
|
-
throwIfNoEntry: "only node's synchronous stat reads it and fs/promises rejects a missing path whatever it says, so catch the ENOENT rejection instead",
|
|
2759
|
-
// cp's filter is a callback the host would invoke, which a sandbox closure can cross the
|
|
2760
|
-
// bridge to serve. It is refused for what happens around the call rather than during it:
|
|
2761
|
-
// the digest that identifies a host call across a snapshot is built by stringifying the
|
|
2762
|
-
// arguments, and a function does not survive that, so cp(filter: keep) and
|
|
2763
|
-
// cp(filter: drop) are one call to the resume machinery.
|
|
2764
|
-
filter: "a closure is dropped from the digest that identifies a host call across a snapshot, so a resumed run could reconcile against a copy that took a different set of files, and under a root it would read the rewritten host paths rather than the ones the script wrote \u2014 walk the tree with readdir and copy the entries you want instead"
|
|
2765
|
-
};
|
|
2766
|
-
var UNKNOWN_OPTION_REASON = "node declares no such option for it, and an unrecognised option is refused rather than silently ignored";
|
|
2767
|
-
var ROOT_REFUSED_DEREFERENCE_REASON = "a root canonicalizes cp's src and dest but never the paths nested inside the tree, so node would copy an escaping link's target inside root where the script could read it \u2014 copy without dereference and a nested link stays a link the root still refuses to read through";
|
|
2768
|
-
var FS_OPTION_SURFACE = {
|
|
2769
|
-
appendFile: {
|
|
2770
|
-
argument: 2,
|
|
2771
|
-
honoured: ["encoding", "mode", "flag", "flush"],
|
|
2772
|
-
// node's appendFile forwards to writeFile, so it honours a signal even though
|
|
2773
|
-
// @types/node does not declare one for it.
|
|
2774
|
-
refused: ["signal"]
|
|
2775
|
-
},
|
|
2776
|
-
// node reads cp's bag from a parameter it names opts rather than options, and validates
|
|
2777
|
-
// every key it knows — while still ignoring one it does not, which is what the unknown
|
|
2778
|
-
// refusal covers. mode is copyFile's flag set rather than a permission.
|
|
2779
|
-
cp: {
|
|
2780
|
-
argument: 2,
|
|
2781
|
-
honoured: [
|
|
2782
|
-
"dereference",
|
|
2783
|
-
"errorOnExist",
|
|
2784
|
-
"force",
|
|
2785
|
-
"mode",
|
|
2786
|
-
"preserveTimestamps",
|
|
2787
|
-
"recursive",
|
|
2788
|
-
"verbatimSymlinks"
|
|
2789
|
-
],
|
|
2790
|
-
refused: ["filter"]
|
|
2791
|
-
},
|
|
2792
|
-
lstat: { argument: 1, honoured: ["bigint"], refused: ["throwIfNoEntry"] },
|
|
2793
|
-
mkdir: { argument: 1, honoured: ["recursive", "mode"], refused: [] },
|
|
2794
|
-
mkdtemp: { argument: 1, honoured: ["encoding"], refused: [] },
|
|
2795
|
-
readFile: { argument: 1, honoured: ["encoding", "flag"], refused: ["signal"] },
|
|
2796
|
-
readdir: { argument: 1, honoured: ["encoding", "withFileTypes", "recursive"], refused: [] },
|
|
2797
|
-
readlink: { argument: 1, honoured: ["encoding"], refused: [] },
|
|
2798
|
-
realpath: { argument: 1, honoured: ["encoding"], refused: [] },
|
|
2799
|
-
rm: { argument: 1, honoured: ["force", "recursive", "maxRetries", "retryDelay"], refused: [] },
|
|
2800
|
-
rmdir: { argument: 1, honoured: ["recursive", "maxRetries", "retryDelay"], refused: [] },
|
|
2801
|
-
stat: { argument: 1, honoured: ["bigint"], refused: ["throwIfNoEntry"] },
|
|
2802
|
-
writeFile: { argument: 2, honoured: ["encoding", "mode", "flag", "flush"], refused: ["signal"] }
|
|
2803
|
-
};
|
|
2804
|
-
var STAT_NUMBER_FIELDS = [
|
|
2805
|
-
"dev",
|
|
2806
|
-
"mode",
|
|
2807
|
-
"nlink",
|
|
2808
|
-
"uid",
|
|
2809
|
-
"gid",
|
|
2810
|
-
"rdev",
|
|
2811
|
-
"blksize",
|
|
2812
|
-
"ino",
|
|
2813
|
-
"size",
|
|
2814
|
-
"blocks",
|
|
2815
|
-
"atimeMs",
|
|
2816
|
-
"mtimeMs",
|
|
2817
|
-
"ctimeMs",
|
|
2818
|
-
"birthtimeMs"
|
|
2819
|
-
];
|
|
2820
|
-
var FILE_TYPE_PREDICATES = [
|
|
2821
|
-
"isFile",
|
|
2822
|
-
"isDirectory",
|
|
2823
|
-
"isSymbolicLink",
|
|
2824
|
-
"isBlockDevice",
|
|
2825
|
-
"isCharacterDevice",
|
|
2826
|
-
"isFIFO",
|
|
2827
|
-
"isSocket"
|
|
2828
|
-
];
|
|
2829
|
-
var BUFFER_ENCODING = "buffer";
|
|
2830
|
-
var FS_SYSCALLS = {
|
|
2831
|
-
access: "access",
|
|
2832
|
-
appendFile: "open",
|
|
2833
|
-
chmod: "chmod",
|
|
2834
|
-
copyFile: "copyfile",
|
|
2835
|
-
// node's cp is its own JavaScript layer rather than a syscall wrapper, so it blames the
|
|
2836
|
-
// fs function by name: its ERR_FS_CP_* errors carry syscall 'cp'.
|
|
2837
|
-
cp: "cp",
|
|
2838
|
-
link: "link",
|
|
2839
|
-
lstat: "lstat",
|
|
2840
|
-
mkdir: "mkdir",
|
|
2841
|
-
mkdtemp: "mkdtemp",
|
|
2842
|
-
readFile: "open",
|
|
2843
|
-
readdir: "scandir",
|
|
2844
|
-
readlink: "readlink",
|
|
2845
|
-
realpath: "realpath",
|
|
2846
|
-
rename: "rename",
|
|
2847
|
-
rm: "lstat",
|
|
2848
|
-
rmdir: "rmdir",
|
|
2849
|
-
stat: "stat",
|
|
2850
|
-
symlink: "symlink",
|
|
2851
|
-
truncate: "open",
|
|
2852
|
-
utimes: "utime",
|
|
2853
|
-
writeFile: "open"
|
|
2854
|
-
};
|
|
2855
|
-
var FS_PATH_ARGUMENTS = {
|
|
2856
|
-
access: ["path"],
|
|
2857
|
-
appendFile: ["path"],
|
|
2858
|
-
chmod: ["path"],
|
|
2859
|
-
copyFile: ["src", "dest"],
|
|
2860
|
-
// node blames these by the same names it uses for copyFile's two paths.
|
|
2861
|
-
cp: ["src", "dest"],
|
|
2862
|
-
link: ["existingPath", "newPath"],
|
|
2863
|
-
lstat: ["path"],
|
|
2864
|
-
mkdir: ["path"],
|
|
2865
|
-
mkdtemp: ["prefix"],
|
|
2866
|
-
readFile: ["path"],
|
|
2867
|
-
readdir: ["path"],
|
|
2868
|
-
readlink: ["oldPath"],
|
|
2869
|
-
realpath: ["path"],
|
|
2870
|
-
rename: ["oldPath", "newPath"],
|
|
2871
|
-
rm: ["path"],
|
|
2872
|
-
rmdir: ["path"],
|
|
2873
|
-
stat: ["path"],
|
|
2874
|
-
symlink: ["target", "path"],
|
|
2875
|
-
truncate: ["path"],
|
|
2876
|
-
utimes: ["path"],
|
|
2877
|
-
writeFile: ["path"]
|
|
2878
|
-
};
|
|
2879
|
-
var ACCESS_DENIED_CODE = "EACCES";
|
|
2880
|
-
var INVALID_ARGUMENT_CODE = "ERR_INVALID_ARG_VALUE";
|
|
2881
|
-
var INVALID_ARGUMENT_TYPE_CODE = "ERR_INVALID_ARG_TYPE";
|
|
2882
|
-
var NULL_BYTE = "\0";
|
|
2883
|
-
var [ACCESS_DENIED_ERRNO, ACCESS_DENIED_MESSAGE] = readSystemError(ACCESS_DENIED_CODE);
|
|
2884
|
-
function makeFsModule(options = {}) {
|
|
2885
|
-
assertSupportedPlatform();
|
|
2886
|
-
const implementation = options.fs ?? nodeFsPromises;
|
|
2887
|
-
const fs = options.root === void 0 ? implementation : makeRootedFs(implementation, options.root);
|
|
2888
|
-
return {
|
|
2889
|
-
access: bind(fs, "access", "re-issue"),
|
|
2890
|
-
appendFile: bind(fs, "appendFile", "read-side-effect"),
|
|
2891
|
-
chmod: bind(fs, "chmod", "read-side-effect"),
|
|
2892
|
-
copyFile: bind(fs, "copyFile", "read-side-effect"),
|
|
2893
|
-
cp: bind(fs, "cp", "read-side-effect"),
|
|
2894
|
-
link: bind(fs, "link", "read-side-effect"),
|
|
2895
|
-
lstat: bindStat(fs, "lstat"),
|
|
2896
|
-
mkdir: bind(fs, "mkdir", "read-side-effect"),
|
|
2897
|
-
// Creates a directory, so it cannot be re-issued on resume like the other
|
|
2898
|
-
// string-result operations, but its name still crosses as a Buffer for a buffer
|
|
2899
|
-
// encoding and so goes through the same guard.
|
|
2900
|
-
mkdtemp: bindStringResult(fs, "mkdtemp", "read-side-effect"),
|
|
2901
|
-
readFile: bindStringResult(fs, "readFile"),
|
|
2902
|
-
readdir: bindReaddir(fs),
|
|
2903
|
-
readlink: bindStringResult(fs, "readlink"),
|
|
2904
|
-
realpath: bindStringResult(fs, "realpath"),
|
|
2905
|
-
rename: bind(fs, "rename", "read-side-effect"),
|
|
2906
|
-
rm: bind(fs, "rm", "read-side-effect"),
|
|
2907
|
-
rmdir: bind(fs, "rmdir", "read-side-effect"),
|
|
2908
|
-
stat: bindStat(fs, "stat"),
|
|
2909
|
-
symlink: bind(fs, "symlink", "read-side-effect"),
|
|
2910
|
-
truncate: bind(fs, "truncate", "read-side-effect"),
|
|
2911
|
-
utimes: bind(fs, "utimes", "read-side-effect"),
|
|
2912
|
-
writeFile: bind(fs, "writeFile", "read-side-effect"),
|
|
2913
|
-
constants: {
|
|
2914
|
-
F_OK: nodeFsConstants.F_OK,
|
|
2915
|
-
R_OK: nodeFsConstants.R_OK,
|
|
2916
|
-
W_OK: nodeFsConstants.W_OK,
|
|
2917
|
-
X_OK: nodeFsConstants.X_OK,
|
|
2918
|
-
COPYFILE_EXCL: nodeFsConstants.COPYFILE_EXCL
|
|
2919
|
-
}
|
|
2920
|
-
};
|
|
2921
|
-
}
|
|
2922
|
-
function assertSupportedPlatform() {
|
|
2923
|
-
if (process.platform !== "win32") {
|
|
2924
|
-
return;
|
|
2925
|
-
}
|
|
2926
|
-
throw new Error(
|
|
2927
|
-
"SafeJS's fs module does not support win32: node's fs answers a different code there (EPERM or UNKNOWN where darwin and linux answer EISDIR or ENOTEMPTY), a path carries a drive letter that root confinement has no rule for, and a symlink needs a privilege a script cannot hold. Run on darwin or linux, or build a host module for the surface you need."
|
|
2928
|
-
);
|
|
2929
|
-
}
|
|
2930
|
-
function bind(fs, name, policy) {
|
|
2931
|
-
return declare(
|
|
2932
|
-
name,
|
|
2933
|
-
policy,
|
|
2934
|
-
(...args) => invoke(fs, name, args)
|
|
2935
|
-
);
|
|
2936
|
-
}
|
|
2937
|
-
function bindStringResult(fs, name, policy = "re-issue") {
|
|
2938
|
-
return declare(name, policy, async (...args) => {
|
|
2939
|
-
assertNoBufferResult(name, args[1]);
|
|
2940
|
-
return await invoke(fs, name, args);
|
|
2941
|
-
});
|
|
2942
|
-
}
|
|
2943
|
-
function bindReaddir(fs) {
|
|
2944
|
-
return declare("readdir", "re-issue", async (...args) => {
|
|
2945
|
-
assertNoBufferResult("readdir", args[1]);
|
|
2946
|
-
const entries = await invoke(fs, "readdir", args);
|
|
2947
|
-
return entries.map((entry) => typeof entry === "string" ? entry : toSandboxDirent(entry));
|
|
2948
|
-
});
|
|
2949
|
-
}
|
|
2950
|
-
function bindStat(fs, name) {
|
|
2951
|
-
return declare(name, "re-issue", async (...args) => {
|
|
2952
|
-
assertNoBigIntResult(name, args[1]);
|
|
2953
|
-
return toSandboxStats(await invoke(fs, name, args));
|
|
2954
|
-
});
|
|
2955
|
-
}
|
|
2956
|
-
function declare(name, policy, operation) {
|
|
2957
|
-
const validated = async (...args) => {
|
|
2958
|
-
FS_PATH_ARGUMENTS[name].forEach(
|
|
2959
|
-
(argument, index) => assertSupportedPath(name, argument, args[index])
|
|
2960
|
-
);
|
|
2961
|
-
assertSupportedOptions(name, args);
|
|
2962
|
-
return await operation(...args);
|
|
2963
|
-
};
|
|
2964
|
-
Object.defineProperty(validated, "name", { value: name });
|
|
2965
|
-
declareHostOperation(validated, policy);
|
|
2966
|
-
return validated;
|
|
2967
|
-
}
|
|
2968
|
-
function invoke(fs, name, args) {
|
|
2969
|
-
return Reflect.apply(fs[name], fs, args);
|
|
2970
|
-
}
|
|
2971
|
-
function makeRootedFs(fs, root) {
|
|
2972
|
-
if (root.trim().length === 0) {
|
|
2973
|
-
throw new Error("fs module root must be a non-empty string.");
|
|
2974
|
-
}
|
|
2975
|
-
const rooted = {};
|
|
2976
|
-
for (const name of Object.keys(FS_SYSCALLS)) {
|
|
2977
|
-
rooted[name] = async (...args) => {
|
|
2978
|
-
assertRootCanConfineOptions(name, args);
|
|
2979
|
-
return invoke(fs, name, await resolvePathArguments(fs, root, name, args));
|
|
2980
|
-
};
|
|
2981
|
-
}
|
|
2982
|
-
return rooted;
|
|
2983
|
-
}
|
|
2984
|
-
function assertRootCanConfineOptions(name, args) {
|
|
2985
|
-
if (name !== "cp") {
|
|
2986
|
-
return;
|
|
2987
|
-
}
|
|
2988
|
-
const options = args[FS_OPTION_SURFACE.cp.argument];
|
|
2989
|
-
if (isObjectLike(options) && options.dereference === true) {
|
|
2990
|
-
throw createUnsupportedOptionError("cp", "dereference", ROOT_REFUSED_DEREFERENCE_REASON);
|
|
2991
|
-
}
|
|
2992
|
-
}
|
|
2993
|
-
async function resolvePathArguments(fs, root, name, args) {
|
|
2994
|
-
const canonicalRoot = await resolveCanonicalPath(readCanonicalPathFs(fs), resolve2(root));
|
|
2995
|
-
const resolved = [...args];
|
|
2996
|
-
if (name === "symlink") {
|
|
2997
|
-
const linkPath = readPath(canonicalRoot, args[1]);
|
|
2998
|
-
resolved[1] = linkPath;
|
|
2999
|
-
await assertInsideRoot(fs, canonicalRoot, name, [
|
|
3000
|
-
readPath(dirname2(linkPath), args[0]),
|
|
3001
|
-
linkPath
|
|
3002
|
-
]);
|
|
3003
|
-
return resolved;
|
|
3004
|
-
}
|
|
3005
|
-
const paths = FS_PATH_ARGUMENTS[name].map((_, index) => {
|
|
3006
|
-
const path = readPath(canonicalRoot, args[index]);
|
|
3007
|
-
resolved[index] = path;
|
|
3008
|
-
return path;
|
|
3009
|
-
});
|
|
3010
|
-
await assertInsideRoot(fs, canonicalRoot, name, paths);
|
|
3011
|
-
return resolved;
|
|
3012
|
-
}
|
|
3013
|
-
async function assertInsideRoot(fs, canonicalRoot, name, paths) {
|
|
3014
|
-
for (const path of paths) {
|
|
3015
|
-
if (await escapesRoot(fs, canonicalRoot, path)) {
|
|
3016
|
-
throw createAccessDeniedError(name, paths[0], paths[1]);
|
|
3017
|
-
}
|
|
3018
|
-
}
|
|
3019
|
-
}
|
|
3020
|
-
async function escapesRoot(fs, canonicalRoot, path) {
|
|
3021
|
-
const canonicalPath = await resolveCanonicalPath(readCanonicalPathFs(fs), path);
|
|
3022
|
-
return !await containsPath(readStat(fs), canonicalRoot, canonicalPath);
|
|
3023
|
-
}
|
|
3024
|
-
function readCanonicalPathFs(fs) {
|
|
3025
|
-
return {
|
|
3026
|
-
realpath: async (path) => await invoke(fs, "realpath", [path]),
|
|
3027
|
-
readlink: async (path) => await invoke(fs, "readlink", [path])
|
|
3028
|
-
};
|
|
3029
|
-
}
|
|
3030
|
-
function readStat(fs) {
|
|
3031
|
-
return async (path) => await invoke(fs, "stat", [path]);
|
|
3032
|
-
}
|
|
3033
|
-
function assertSupportedPath(name, argument, value) {
|
|
3034
|
-
if (typeof value === "string") {
|
|
3035
|
-
if (value.includes(NULL_BYTE)) {
|
|
3036
|
-
throw createNullByteError(argument, value);
|
|
3037
|
-
}
|
|
3038
|
-
return;
|
|
3039
|
-
}
|
|
3040
|
-
const form = readUnsupportedPathForm(value);
|
|
3041
|
-
throw form === void 0 ? createInvalidPathTypeError(argument, value) : createUnsupportedPathError(name, argument, form);
|
|
3042
|
-
}
|
|
3043
|
-
function readUnsupportedPathForm(value) {
|
|
3044
|
-
if (value instanceof Uint8Array) {
|
|
3045
|
-
return "a Buffer or Uint8Array";
|
|
3046
|
-
}
|
|
3047
|
-
return value instanceof URL ? "a URL" : void 0;
|
|
3048
|
-
}
|
|
3049
|
-
function createNullByteError(argument, value) {
|
|
3050
|
-
const error = new TypeError(
|
|
3051
|
-
`The argument '${argument}' must be a string, Uint8Array, or URL without null bytes. Received ${inspect(value)}`
|
|
3052
|
-
);
|
|
3053
|
-
error.code = INVALID_ARGUMENT_CODE;
|
|
3054
|
-
return error;
|
|
3055
|
-
}
|
|
3056
|
-
function createInvalidPathTypeError(argument, value) {
|
|
3057
|
-
const error = new TypeError(
|
|
3058
|
-
`The "${argument}" argument must be of type string or an instance of Buffer or URL. Received ${describeReceivedValue(value)}`
|
|
3059
|
-
);
|
|
3060
|
-
error.code = INVALID_ARGUMENT_TYPE_CODE;
|
|
3061
|
-
return error;
|
|
3062
|
-
}
|
|
3063
|
-
function createUnsupportedPathError(name, argument, form) {
|
|
3064
|
-
return new TypeError(
|
|
3065
|
-
`fs.${name} cannot accept ${form} as the '${argument}' argument inside SafeJS; pass the path as a string.`
|
|
3066
|
-
);
|
|
3067
|
-
}
|
|
3068
|
-
function describeReceivedValue(value) {
|
|
3069
|
-
if (value === null || value === void 0) {
|
|
3070
|
-
return String(value);
|
|
3071
|
-
}
|
|
3072
|
-
if (typeof value === "function") {
|
|
3073
|
-
return `function ${value.name}`;
|
|
3074
|
-
}
|
|
3075
|
-
if (typeof value === "object") {
|
|
3076
|
-
const constructorName = value.constructor?.name;
|
|
3077
|
-
return constructorName === void 0 ? inspect(value, { depth: -1 }) : `an instance of ${constructorName}`;
|
|
3078
|
-
}
|
|
3079
|
-
return `type ${typeof value} (${inspect(value)})`;
|
|
3080
|
-
}
|
|
3081
|
-
function readPath(base, value) {
|
|
3082
|
-
const path = value;
|
|
3083
|
-
return isAbsolute2(path) ? resolve2(path) : resolve2(base, path);
|
|
3084
|
-
}
|
|
3085
|
-
function createAccessDeniedError(name, path, dest) {
|
|
3086
|
-
const syscall = FS_SYSCALLS[name];
|
|
3087
|
-
const target = dest === void 0 ? `'${path}'` : `'${path}' -> '${dest}'`;
|
|
3088
|
-
const error = new Error(
|
|
3089
|
-
`${ACCESS_DENIED_CODE}: ${ACCESS_DENIED_MESSAGE}, ${syscall} ${target}`
|
|
3090
|
-
);
|
|
3091
|
-
error.code = ACCESS_DENIED_CODE;
|
|
3092
|
-
error.errno = ACCESS_DENIED_ERRNO;
|
|
3093
|
-
error.syscall = syscall;
|
|
3094
|
-
error.path = path;
|
|
3095
|
-
if (dest !== void 0) {
|
|
3096
|
-
error.dest = dest;
|
|
3097
|
-
}
|
|
3098
|
-
return error;
|
|
3099
|
-
}
|
|
3100
|
-
function readSystemError(code) {
|
|
3101
|
-
const fallback = /* @__PURE__ */ new Map([
|
|
3102
|
-
[process.platform === "win32" ? -4092 : -13, ["EACCES", "permission denied"]]
|
|
3103
|
-
]);
|
|
3104
|
-
const systemErrors = nodeUtil.getSystemErrorMap?.() ?? fallback;
|
|
3105
|
-
for (const [errno, [name, message]] of systemErrors) {
|
|
3106
|
-
if (name === code) {
|
|
3107
|
-
return [errno, message];
|
|
3108
|
-
}
|
|
3109
|
-
}
|
|
3110
|
-
throw new Error(`node does not define the ${code} system error.`);
|
|
3111
|
-
}
|
|
3112
|
-
function assertSupportedOptions(name, args) {
|
|
3113
|
-
const surface = FS_OPTION_SURFACE[name];
|
|
3114
|
-
if (surface === void 0 || !isObjectLike(args[surface.argument])) {
|
|
3115
|
-
return;
|
|
3116
|
-
}
|
|
3117
|
-
const options = args[surface.argument];
|
|
3118
|
-
for (const option of surface.refused) {
|
|
3119
|
-
if (option in options) {
|
|
3120
|
-
throw createUnsupportedOptionError(name, option, REFUSED_OPTION_REASONS[option]);
|
|
3121
|
-
}
|
|
3122
|
-
}
|
|
3123
|
-
for (const option in options) {
|
|
3124
|
-
if (!surface.honoured.includes(option)) {
|
|
3125
|
-
throw createUnsupportedOptionError(name, option, UNKNOWN_OPTION_REASON);
|
|
3126
|
-
}
|
|
3127
|
-
}
|
|
3128
|
-
}
|
|
3129
|
-
function assertNoBufferResult(operation, options) {
|
|
3130
|
-
if (readsBuffer(options, BUFFER_BY_DEFAULT[operation])) {
|
|
3131
|
-
throw createUnsupportedCapabilityError(
|
|
3132
|
-
operation,
|
|
3133
|
-
"return a Buffer",
|
|
3134
|
-
'pass a string encoding such as "utf8"'
|
|
3135
|
-
);
|
|
3136
|
-
}
|
|
3137
|
-
}
|
|
3138
|
-
function assertNoBigIntResult(operation, options) {
|
|
3139
|
-
if (isObjectLike(options) && options.bigint === true) {
|
|
3140
|
-
throw createUnsupportedCapabilityError(
|
|
3141
|
-
operation,
|
|
3142
|
-
"return BigInt fields",
|
|
3143
|
-
"omit bigint and read the *Ms timestamps instead"
|
|
3144
|
-
);
|
|
3145
|
-
}
|
|
3146
|
-
}
|
|
3147
|
-
function createUnsupportedOptionError(operation, option, reason) {
|
|
3148
|
-
return createUnsupportedCapabilityError(operation, `honour the '${option}' option`, reason);
|
|
3149
|
-
}
|
|
3150
|
-
function createUnsupportedCapabilityError(operation, capability, remedy) {
|
|
3151
|
-
return new TypeError(`fs.${operation} cannot ${capability} inside SafeJS; ${remedy}.`);
|
|
3152
|
-
}
|
|
3153
|
-
function readsBuffer(options, bufferByDefault) {
|
|
3154
|
-
if (typeof options === "string") {
|
|
3155
|
-
return options === BUFFER_ENCODING;
|
|
3156
|
-
}
|
|
3157
|
-
if (options === void 0 || options === null) {
|
|
3158
|
-
return bufferByDefault;
|
|
3159
|
-
}
|
|
3160
|
-
if (!isObjectLike(options)) {
|
|
3161
|
-
return false;
|
|
3162
|
-
}
|
|
3163
|
-
const { encoding } = options;
|
|
3164
|
-
if (encoding === BUFFER_ENCODING) {
|
|
3165
|
-
return true;
|
|
3166
|
-
}
|
|
3167
|
-
return (encoding === void 0 || encoding === null) && bufferByDefault;
|
|
3168
|
-
}
|
|
3169
|
-
function toSandboxStats(stats) {
|
|
3170
|
-
const numbers = {};
|
|
3171
|
-
for (const field of STAT_NUMBER_FIELDS) {
|
|
3172
|
-
numbers[field] = stats[field];
|
|
3173
|
-
}
|
|
3174
|
-
return { ...numbers, ...toFileTypePredicates(stats) };
|
|
3175
|
-
}
|
|
3176
|
-
function toSandboxDirent(dirent) {
|
|
3177
|
-
return {
|
|
3178
|
-
name: dirent.name,
|
|
3179
|
-
parentPath: dirent.parentPath,
|
|
3180
|
-
...toFileTypePredicates(dirent)
|
|
3181
|
-
};
|
|
3182
|
-
}
|
|
3183
|
-
function toFileTypePredicates(source) {
|
|
3184
|
-
const predicates = {};
|
|
3185
|
-
for (const predicate of FILE_TYPE_PREDICATES) {
|
|
3186
|
-
const result = source[predicate]();
|
|
3187
|
-
predicates[predicate] = () => result;
|
|
3188
|
-
}
|
|
3189
|
-
return predicates;
|
|
3190
|
-
}
|
|
3191
|
-
function isObjectLike(value) {
|
|
3192
|
-
return typeof value === "object" && value !== null || typeof value === "function";
|
|
3193
|
-
}
|
|
3194
|
-
|
|
3195
|
-
// packages/safejs/src/modules/harness.ts
|
|
3196
|
-
function makeHarnessModule(frontmatter, meta) {
|
|
3197
|
-
const copiedFrontmatter = copyHarnessValue(frontmatter);
|
|
3198
|
-
const constraints = readConstraints(copiedFrontmatter);
|
|
3199
|
-
return {
|
|
3200
|
-
tasks: copyHarnessValue(copiedFrontmatter.tasks),
|
|
3201
|
-
agents: copyHarnessValue(copiedFrontmatter.agents),
|
|
3202
|
-
meta: {
|
|
3203
|
-
kind: copyHarnessValue(meta.kind),
|
|
3204
|
-
version: copyHarnessValue(meta.version),
|
|
3205
|
-
filepath: meta.filepath,
|
|
3206
|
-
frontmatter: copiedFrontmatter
|
|
3207
|
-
},
|
|
3208
|
-
applyConstraints: (prompt) => applyConstraints(prompt, constraints)
|
|
3209
|
-
};
|
|
3210
|
-
}
|
|
3211
|
-
function copyHarnessValue(value) {
|
|
3212
|
-
return deepCopyToSandbox(value);
|
|
3213
|
-
}
|
|
3214
|
-
function readConstraints(frontmatter) {
|
|
3215
|
-
const constraints = /* @__PURE__ */ new Set();
|
|
3216
|
-
appendConstraintValues(constraints, frontmatter.principles);
|
|
3217
|
-
appendConstraintValues(constraints, frontmatter.constraints);
|
|
3218
|
-
return [...constraints];
|
|
3219
|
-
}
|
|
3220
|
-
function appendConstraintValues(constraints, value) {
|
|
3221
|
-
if (!Array.isArray(value)) {
|
|
3222
|
-
return;
|
|
3223
|
-
}
|
|
3224
|
-
for (const item of value) {
|
|
3225
|
-
if (typeof item !== "string") {
|
|
3226
|
-
throw new Error("constraints/principles must be strings");
|
|
3227
|
-
}
|
|
3228
|
-
constraints.add(item);
|
|
3229
|
-
}
|
|
3230
|
-
}
|
|
3231
|
-
function applyConstraints(prompt, constraints) {
|
|
3232
|
-
if (constraints.length === 0) {
|
|
3233
|
-
return prompt;
|
|
3234
|
-
}
|
|
3235
|
-
const preamble = `CONSTRAINTS (hard rules, honor all):
|
|
3236
|
-
${constraints.map((constraint) => `- ${constraint}`).join("\n")}`;
|
|
3237
|
-
return prompt.length === 0 ? preamble : `${preamble}
|
|
3238
|
-
|
|
3239
|
-
${prompt}`;
|
|
3240
|
-
}
|
|
3241
|
-
|
|
3242
|
-
// packages/safejs/src/output-stream.ts
|
|
3243
|
-
function createBrokenPipeState() {
|
|
3244
|
-
return { closed: false };
|
|
3245
|
-
}
|
|
3246
|
-
function createSafeOutputStream(stream, brokenPipe) {
|
|
3247
|
-
return {
|
|
3248
|
-
write(chunk) {
|
|
3249
|
-
if (brokenPipe.closed) {
|
|
3250
|
-
return;
|
|
3251
|
-
}
|
|
3252
|
-
try {
|
|
3253
|
-
stream.write(chunk);
|
|
3254
|
-
} catch (error) {
|
|
3255
|
-
if (isBrokenPipeError(error)) {
|
|
3256
|
-
brokenPipe.closed = true;
|
|
3257
|
-
return;
|
|
3258
|
-
}
|
|
3259
|
-
throw error;
|
|
3260
|
-
}
|
|
3261
|
-
}
|
|
3262
|
-
};
|
|
3263
|
-
}
|
|
3264
|
-
async function withBrokenPipeGuard(streams, brokenPipe, callback) {
|
|
3265
|
-
const removeListeners = streams.map((stream) => addBrokenPipeListener(stream, brokenPipe));
|
|
3266
|
-
try {
|
|
3267
|
-
return await callback();
|
|
3268
|
-
} finally {
|
|
3269
|
-
for (const removeListener of removeListeners) {
|
|
3270
|
-
removeListener();
|
|
3271
|
-
}
|
|
3272
|
-
}
|
|
3273
|
-
}
|
|
3274
|
-
function addBrokenPipeListener(stream, brokenPipe) {
|
|
3275
|
-
const onError = (error) => {
|
|
3276
|
-
if (isBrokenPipeError(error)) {
|
|
3277
|
-
brokenPipe.closed = true;
|
|
3278
|
-
return;
|
|
3279
|
-
}
|
|
3280
|
-
throw error;
|
|
3281
|
-
};
|
|
3282
|
-
stream.on?.("error", onError);
|
|
3283
|
-
return () => {
|
|
3284
|
-
stream.off?.("error", onError);
|
|
3285
|
-
};
|
|
3286
|
-
}
|
|
3287
|
-
function isBrokenPipeError(error) {
|
|
3288
|
-
return hasOwnErrorCode(error, "EPIPE");
|
|
3289
|
-
}
|
|
3290
|
-
|
|
3291
|
-
// packages/safejs/src/modules/log.ts
|
|
3292
|
-
function makeLogModule(sink = createJsonlStdoutSink()) {
|
|
3293
|
-
const normalizedSink = readSink(sink);
|
|
3294
|
-
return {
|
|
3295
|
-
info(...args) {
|
|
3296
|
-
normalizedSink({
|
|
3297
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3298
|
-
type: "info",
|
|
3299
|
-
args
|
|
3300
|
-
});
|
|
3301
|
-
},
|
|
3302
|
-
error(...args) {
|
|
3303
|
-
normalizedSink({
|
|
3304
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3305
|
-
type: "error",
|
|
3306
|
-
args
|
|
3307
|
-
});
|
|
3308
|
-
},
|
|
3309
|
-
event(name, payload) {
|
|
3310
|
-
normalizedSink({
|
|
3311
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3312
|
-
type: "event",
|
|
3313
|
-
name: readNonEmptyString3(name, "Event name"),
|
|
3314
|
-
payload
|
|
3315
|
-
});
|
|
3316
|
-
}
|
|
3317
|
-
};
|
|
3318
|
-
}
|
|
3319
|
-
function createJsonlStdoutSink() {
|
|
3320
|
-
const brokenPipe = createBrokenPipeState();
|
|
3321
|
-
const stdout = createSafeOutputStream(process.stdout, brokenPipe);
|
|
3322
|
-
addBrokenPipeListener(process.stdout, brokenPipe);
|
|
3323
|
-
return (entry) => {
|
|
3324
|
-
stdout.write(`${JSON.stringify(toJsonValue(entry, /* @__PURE__ */ new WeakSet()))}
|
|
3325
|
-
`);
|
|
3326
|
-
};
|
|
3327
|
-
}
|
|
3328
|
-
function readNonEmptyString3(value, label) {
|
|
3329
|
-
if (typeof value !== "string") {
|
|
3330
|
-
throw new Error(`${label} must be a non-empty string.`);
|
|
3331
|
-
}
|
|
3332
|
-
const normalizedValue = value.trim();
|
|
3333
|
-
if (normalizedValue.length === 0) {
|
|
3334
|
-
throw new Error(`${label} must be a non-empty string.`);
|
|
3335
|
-
}
|
|
3336
|
-
return normalizedValue;
|
|
3337
|
-
}
|
|
3338
|
-
function readSink(value) {
|
|
3339
|
-
if (typeof value !== "function") {
|
|
3340
|
-
throw new Error("Log sink must be a function.");
|
|
3341
|
-
}
|
|
3342
|
-
return value;
|
|
3343
|
-
}
|
|
3344
|
-
function toJsonValue(value, seen) {
|
|
3345
|
-
if (value === void 0) {
|
|
3346
|
-
return null;
|
|
3347
|
-
}
|
|
3348
|
-
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
3349
|
-
return value;
|
|
3350
|
-
}
|
|
3351
|
-
if (typeof value === "number") {
|
|
3352
|
-
return Number.isFinite(value) ? value : String(value);
|
|
3353
|
-
}
|
|
3354
|
-
if (typeof value === "bigint" || typeof value === "symbol") {
|
|
3355
|
-
return String(value);
|
|
3356
|
-
}
|
|
3357
|
-
if (typeof value === "function") {
|
|
3358
|
-
return `[Function ${value.name || "anonymous"}]`;
|
|
3359
|
-
}
|
|
3360
|
-
if (value instanceof Date) {
|
|
3361
|
-
return Number.isNaN(value.getTime()) ? "Invalid Date" : value.toISOString();
|
|
3362
|
-
}
|
|
3363
|
-
if (value instanceof Error) {
|
|
3364
|
-
const serializedError = {
|
|
3365
|
-
name: value.name,
|
|
3366
|
-
message: value.message
|
|
3367
|
-
};
|
|
3368
|
-
if (typeof value.stack === "string" && value.stack.length > 0) {
|
|
3369
|
-
serializedError.stack = value.stack;
|
|
3370
|
-
}
|
|
3371
|
-
if (Object.prototype.hasOwnProperty.call(value, "cause")) {
|
|
3372
|
-
serializedError.cause = toJsonValue(value.cause, seen);
|
|
3373
|
-
}
|
|
3374
|
-
return serializedError;
|
|
3375
|
-
}
|
|
3376
|
-
if (Array.isArray(value)) {
|
|
3377
|
-
if (seen.has(value)) {
|
|
3378
|
-
return "[Circular]";
|
|
3379
|
-
}
|
|
3380
|
-
seen.add(value);
|
|
3381
|
-
const normalized = value.map((entry) => toJsonValue(entry, seen));
|
|
3382
|
-
seen.delete(value);
|
|
3383
|
-
return normalized;
|
|
3384
|
-
}
|
|
3385
|
-
if (typeof value === "object") {
|
|
3386
|
-
if (seen.has(value)) {
|
|
3387
|
-
return "[Circular]";
|
|
3388
|
-
}
|
|
3389
|
-
seen.add(value);
|
|
3390
|
-
const normalized = /* @__PURE__ */ Object.create(null);
|
|
3391
|
-
for (const [key, entry] of Object.entries(value)) {
|
|
3392
|
-
normalized[key] = toJsonValue(entry, seen);
|
|
3393
|
-
}
|
|
3394
|
-
seen.delete(value);
|
|
3395
|
-
return normalized;
|
|
3396
|
-
}
|
|
3397
|
-
return String(value);
|
|
3398
|
-
}
|
|
3399
|
-
|
|
3400
|
-
// packages/safejs/src/modules/metric.ts
|
|
3401
|
-
function makeMetricModule(npmRunner) {
|
|
3402
|
-
return {
|
|
3403
|
-
async run(name) {
|
|
3404
|
-
const metricName = readNonEmptyString4(name, "Metric name");
|
|
3405
|
-
const scriptName = `metric:${metricName}`;
|
|
3406
|
-
const stdout = await npmRunner(scriptName);
|
|
3407
|
-
const score = parseMetricScore(stdout, scriptName);
|
|
3408
|
-
return score;
|
|
3409
|
-
}
|
|
3410
|
-
};
|
|
3411
|
-
}
|
|
3412
|
-
function parseMetricScore(stdout, scriptName) {
|
|
3413
|
-
if (typeof stdout !== "string") {
|
|
3414
|
-
throw new Error(`Metric runner for "${scriptName}" must resolve to a stdout string.`);
|
|
3415
|
-
}
|
|
3416
|
-
const scoreLine = stdout.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).at(-1);
|
|
3417
|
-
if (scoreLine === void 0) {
|
|
3418
|
-
throw new Error(`Metric script "${scriptName}" must print a numeric score.`);
|
|
3419
|
-
}
|
|
3420
|
-
const score = Number(scoreLine);
|
|
3421
|
-
if (!Number.isFinite(score)) {
|
|
3422
|
-
throw new Error(`Metric script "${scriptName}" must print a numeric score.`);
|
|
3423
|
-
}
|
|
3424
|
-
return score;
|
|
3425
|
-
}
|
|
3426
|
-
function readNonEmptyString4(value, label) {
|
|
3427
|
-
if (typeof value !== "string") {
|
|
3428
|
-
throw new Error(`${label} must be a non-empty string.`);
|
|
3429
|
-
}
|
|
3430
|
-
const normalizedValue = value.trim();
|
|
3431
|
-
if (normalizedValue.length === 0) {
|
|
3432
|
-
throw new Error(`${label} must be a non-empty string.`);
|
|
3433
|
-
}
|
|
3434
|
-
return normalizedValue;
|
|
3435
|
-
}
|
|
3436
|
-
|
|
3437
|
-
export {
|
|
3438
|
-
formatInterpreterError,
|
|
3439
|
-
SPAWN_MODES,
|
|
3440
|
-
supportsSpawnMode,
|
|
3441
|
-
extractBlock,
|
|
3442
|
-
countLineBreaks,
|
|
3443
|
-
splitFrontmatter,
|
|
3444
|
-
createLintModulesFromRuntimeRegistry,
|
|
3445
|
-
AgentSpawnError,
|
|
3446
|
-
createSpawnUsageAccumulator,
|
|
3447
|
-
runWithSpawnUsageAccumulator,
|
|
3448
|
-
makeAgentModule,
|
|
3449
|
-
makeFailModule,
|
|
3450
|
-
resolveCanonicalPath,
|
|
3451
|
-
containsPath,
|
|
3452
|
-
isSamePath,
|
|
3453
|
-
makeFsModule,
|
|
3454
|
-
makeHarnessModule,
|
|
3455
|
-
createBrokenPipeState,
|
|
3456
|
-
createSafeOutputStream,
|
|
3457
|
-
withBrokenPipeGuard,
|
|
3458
|
-
makeLogModule,
|
|
3459
|
-
makeMetricModule
|
|
3460
|
-
};
|
|
3461
|
-
//# sourceMappingURL=chunk-AVDRLE3Y.js.map
|