stitchkit 0.108.2 → 0.108.4
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/CHANGELOG.md +24 -0
- package/dist/agent-runtime/coding-tool-search-patch.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/coding-tools.js +3 -2
- package/dist/entrypoints/agent-runtime/sandbox.js +5 -3
- package/dist/entrypoints/cli.js +1 -1
- package/dist/entrypoints/contract.js +1 -1
- package/dist/entrypoints/index.js +1 -1
- package/dist/entrypoints/node.js +1 -1
- package/dist/entrypoints/process/owner-loss.d.ts +3 -0
- package/dist/entrypoints/process/owner-loss.d.ts.map +1 -0
- package/dist/entrypoints/process/owner-loss.js +6 -0
- package/dist/entrypoints/process.js +4 -2
- package/dist/entrypoints/server.js +1 -1
- package/dist/entrypoints/tools.js +1 -1
- package/dist/{index-k0kzhdw9.js → index-dasy32c8.js} +23 -634
- package/dist/index-dj1aycxw.js +639 -0
- package/dist/{index-4qh90tyw.js → index-fgq4w9bf.js} +23 -1
- package/dist/{index-vyaehh67.js → index-sjntc4az.js} +8 -5
- package/dist/process/owner-loss-guard.d.ts +9 -0
- package/dist/process/owner-loss-guard.d.ts.map +1 -1
- package/dist/tools/cli/args-fields.d.ts.map +1 -1
- package/llms/agent-runtime-coding-tools.txt +1 -1
- package/llms/agent-runtime.txt +3 -2
- package/llms/cli.2.txt +107 -0
- package/llms/cli.txt +8 -107
- package/llms/process-owner-loss.txt +18 -0
- package/llms/process.txt +18 -0
- package/llms/stitchkit.txt +1 -0
- package/llms-full.txt +39 -3
- package/llms.txt +6 -5
- package/package.json +5 -1
- /package/dist/{index-q4hjtyye.js → index-qd8x73e8.js} +0 -0
|
@@ -0,0 +1,639 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MAX_TIMER_MS
|
|
3
|
+
} from "./index-eemvahkc.js";
|
|
4
|
+
|
|
5
|
+
// src/process/contract.ts
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
var NativeCommandSettlementSchema = z.discriminatedUnion("kind", [
|
|
8
|
+
z.object({
|
|
9
|
+
kind: z.literal("exit"),
|
|
10
|
+
exitCode: z.number().int().nullable(),
|
|
11
|
+
signal: z.string().nullable()
|
|
12
|
+
}),
|
|
13
|
+
z.object({
|
|
14
|
+
kind: z.literal("stopped"),
|
|
15
|
+
cause: z.unknown(),
|
|
16
|
+
exitCode: z.number().int().nullable(),
|
|
17
|
+
signal: z.string().nullable()
|
|
18
|
+
}),
|
|
19
|
+
z.object({ kind: z.literal("error"), cause: z.unknown() })
|
|
20
|
+
]);
|
|
21
|
+
var COMMAND_CLEANUP_TIMEOUT_MS = 2000;
|
|
22
|
+
var MAX_COMMAND_STOP_GRACE_MS = 3600000;
|
|
23
|
+
var NativeCommandStopPolicySchema = z.strictObject({
|
|
24
|
+
target: z.enum(["group", "leader"]),
|
|
25
|
+
signal: z.enum(["SIGTERM", "SIGINT", "SIGHUP", "SIGQUIT", "SIGUSR1", "SIGUSR2"]).default("SIGTERM"),
|
|
26
|
+
graceMs: z.number().int().nonnegative().max(MAX_COMMAND_STOP_GRACE_MS),
|
|
27
|
+
killOn: z.custom((v) => v instanceof AbortSignal).optional()
|
|
28
|
+
});
|
|
29
|
+
var REMOVED_NATIVE_COMMAND_OPTIONS = {
|
|
30
|
+
killGraceMs: "stop: { target: 'group', graceMs } (removed in 0.105.0)"
|
|
31
|
+
};
|
|
32
|
+
function unknownOptionMessage(keys) {
|
|
33
|
+
return keys.map((key) => {
|
|
34
|
+
const name = String(key);
|
|
35
|
+
const replacement = Object.hasOwn(REMOVED_NATIVE_COMMAND_OPTIONS, name) ? REMOVED_NATIVE_COMMAND_OPTIONS[name] : undefined;
|
|
36
|
+
return replacement === undefined ? `Unknown runNativeCommand option ${name}` : `Unknown runNativeCommand option ${name}; use ${replacement}`;
|
|
37
|
+
}).join("; ");
|
|
38
|
+
}
|
|
39
|
+
var DEFAULT_GROUP_STOP = {
|
|
40
|
+
target: "group",
|
|
41
|
+
signal: "SIGTERM",
|
|
42
|
+
graceMs: 100
|
|
43
|
+
};
|
|
44
|
+
var DEFAULT_LEADER_STOP = {
|
|
45
|
+
target: "leader",
|
|
46
|
+
signal: "SIGTERM",
|
|
47
|
+
graceMs: 100
|
|
48
|
+
};
|
|
49
|
+
var NativeCommandOptionsSchema = z.strictObject({
|
|
50
|
+
executable: z.string().min(1),
|
|
51
|
+
args: z.array(z.string()).default([]),
|
|
52
|
+
cwd: z.string().optional(),
|
|
53
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
54
|
+
envPolicy: z.enum(["declared-only", "ambient"]).default("declared-only"),
|
|
55
|
+
signal: z.custom((v) => v instanceof AbortSignal).optional(),
|
|
56
|
+
timeoutMs: z.number().int().positive().max(MAX_TIMER_MS).optional(),
|
|
57
|
+
maxOutputBytes: z.number().int().positive().optional(),
|
|
58
|
+
capture: z.boolean().default(false),
|
|
59
|
+
stdin: z.custom((v) => v instanceof Uint8Array).optional(),
|
|
60
|
+
maxStdinBytes: z.number().int().positive().default(1024 * 1024),
|
|
61
|
+
onOutput: z.custom((v) => typeof v === "function").optional(),
|
|
62
|
+
onLeaderSettled: z.custom((v) => typeof v === "function").optional(),
|
|
63
|
+
onLeaderStarted: z.custom((v) => typeof v === "function").optional(),
|
|
64
|
+
drainTimeoutMs: z.number().int().positive().max(MAX_TIMER_MS).optional(),
|
|
65
|
+
group: z.enum(["own", "caller"]).default("own"),
|
|
66
|
+
ownerLoss: z.enum(["terminate"]).optional(),
|
|
67
|
+
stdio: z.enum(["pipe", "inherit"]).default("pipe"),
|
|
68
|
+
stop: NativeCommandStopPolicySchema.optional(),
|
|
69
|
+
descendants: z.enum(["terminate-after-leader", "leave"]).optional(),
|
|
70
|
+
cleanupTimeoutMs: z.number().int().positive().max(30000).default(COMMAND_CLEANUP_TIMEOUT_MS)
|
|
71
|
+
}, {
|
|
72
|
+
error: (issue) => issue.code === "unrecognized_keys" ? unknownOptionMessage(issue.keys) : undefined
|
|
73
|
+
}).check((ctx) => {
|
|
74
|
+
const input = ctx.value;
|
|
75
|
+
if (!input.signal && input.timeoutMs === undefined)
|
|
76
|
+
ctx.issues.push({
|
|
77
|
+
code: "custom",
|
|
78
|
+
input: ctx.value,
|
|
79
|
+
message: "Declare a caller signal or a finite timeout"
|
|
80
|
+
});
|
|
81
|
+
if (input.capture && input.maxOutputBytes === undefined)
|
|
82
|
+
ctx.issues.push({
|
|
83
|
+
code: "custom",
|
|
84
|
+
input: ctx.value,
|
|
85
|
+
message: "Capture requires a finite combined output budget"
|
|
86
|
+
});
|
|
87
|
+
if (input.stdin && input.stdin.byteLength > input.maxStdinBytes)
|
|
88
|
+
ctx.issues.push({
|
|
89
|
+
code: "custom",
|
|
90
|
+
input: ctx.value,
|
|
91
|
+
message: "stdin exceeds maxStdinBytes"
|
|
92
|
+
});
|
|
93
|
+
if (input.group === "caller" && input.stop?.target === "group")
|
|
94
|
+
ctx.issues.push({
|
|
95
|
+
code: "custom",
|
|
96
|
+
input: ctx.value,
|
|
97
|
+
message: "group: 'caller' stops only the leader; use stop.target 'leader'"
|
|
98
|
+
});
|
|
99
|
+
if (input.group === "caller" && input.descendants !== undefined)
|
|
100
|
+
ctx.issues.push({
|
|
101
|
+
code: "custom",
|
|
102
|
+
input: ctx.value,
|
|
103
|
+
message: "group: 'caller' has no group of its own, so descendants does not apply"
|
|
104
|
+
});
|
|
105
|
+
if (input.group === "caller" && input.ownerLoss !== undefined)
|
|
106
|
+
ctx.issues.push({
|
|
107
|
+
code: "custom",
|
|
108
|
+
input: ctx.value,
|
|
109
|
+
message: "ownerLoss: 'terminate' requires group: 'own'"
|
|
110
|
+
});
|
|
111
|
+
if (input.stdio === "inherit") {
|
|
112
|
+
const piped = [
|
|
113
|
+
input.capture && "capture",
|
|
114
|
+
input.onOutput && "onOutput",
|
|
115
|
+
input.stdin && "stdin",
|
|
116
|
+
input.maxOutputBytes !== undefined && "maxOutputBytes",
|
|
117
|
+
input.drainTimeoutMs !== undefined && "drainTimeoutMs"
|
|
118
|
+
].filter((name) => typeof name === "string");
|
|
119
|
+
for (const name of piped)
|
|
120
|
+
ctx.issues.push({
|
|
121
|
+
code: "custom",
|
|
122
|
+
input: ctx.value,
|
|
123
|
+
message: `stdio: 'inherit' leaves no pipe for ${name}`
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}).transform((input) => ({
|
|
127
|
+
...input,
|
|
128
|
+
stop: input.stop ?? (input.group === "caller" ? DEFAULT_LEADER_STOP : DEFAULT_GROUP_STOP),
|
|
129
|
+
descendants: input.descendants ?? "terminate-after-leader"
|
|
130
|
+
}));
|
|
131
|
+
var NativeCommandResultSchema = z.object({
|
|
132
|
+
exitCode: z.number().int().nullable(),
|
|
133
|
+
signal: z.string().nullable(),
|
|
134
|
+
descendantsStopped: z.boolean(),
|
|
135
|
+
stdout: z.instanceof(Uint8Array),
|
|
136
|
+
stderr: z.instanceof(Uint8Array)
|
|
137
|
+
});
|
|
138
|
+
var NativeCommandLimitReasonSchema = z.enum(["deadline", "output-budget"]);
|
|
139
|
+
|
|
140
|
+
class NativeCommandError2 extends Error {
|
|
141
|
+
code;
|
|
142
|
+
reason;
|
|
143
|
+
constructor(code, message, options) {
|
|
144
|
+
super(message, options);
|
|
145
|
+
this.code = code;
|
|
146
|
+
if (options?.reason !== undefined && code !== "COMMAND_LIMIT")
|
|
147
|
+
throw new TypeError("Only COMMAND_LIMIT accepts a limit reason");
|
|
148
|
+
this.reason = options?.reason === undefined ? undefined : NativeCommandLimitReasonSchema.parse(options.reason);
|
|
149
|
+
this.name = "NativeCommandError";
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// src/process/owner-loss-guard.ts
|
|
154
|
+
import { spawn } from "node:child_process";
|
|
155
|
+
import { Socket } from "node:net";
|
|
156
|
+
import { fileURLToPath } from "node:url";
|
|
157
|
+
|
|
158
|
+
// src/process/bun-child.ts
|
|
159
|
+
import { EventEmitter } from "node:events";
|
|
160
|
+
import { Readable, Writable } from "node:stream";
|
|
161
|
+
|
|
162
|
+
// src/process/owner-loss-control.ts
|
|
163
|
+
import { z as z2 } from "zod";
|
|
164
|
+
var MAX_GUARD_MESSAGE_BYTES = 4096;
|
|
165
|
+
var OwnerLossGuardMessageSchema = z2.discriminatedUnion("kind", [
|
|
166
|
+
z2.strictObject({ kind: z2.literal("started"), pid: z2.number().int().positive() }),
|
|
167
|
+
z2.strictObject({
|
|
168
|
+
kind: z2.literal("unavailable"),
|
|
169
|
+
message: z2.string().min(1).max(1024),
|
|
170
|
+
code: z2.string().min(1).max(64).optional()
|
|
171
|
+
})
|
|
172
|
+
]);
|
|
173
|
+
var guards = new WeakMap;
|
|
174
|
+
function abortOwnerLossLaunch(pid) {
|
|
175
|
+
if (pid === undefined)
|
|
176
|
+
return;
|
|
177
|
+
try {
|
|
178
|
+
process.kill(-pid, "SIGKILL");
|
|
179
|
+
} catch (error) {
|
|
180
|
+
if (!(error instanceof Error && ("code" in error) && error.code === "ESRCH"))
|
|
181
|
+
throw error;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function unavailable(message, cause) {
|
|
185
|
+
return new NativeCommandError2("COMMAND_UNAVAILABLE", "Command could not start", {
|
|
186
|
+
cause: cause ?? new Error(message)
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
function attachOwnerLossControl(child, control) {
|
|
190
|
+
const settled = Promise.withResolvers();
|
|
191
|
+
settled.promise.catch(() => {
|
|
192
|
+
return;
|
|
193
|
+
});
|
|
194
|
+
let complete = false;
|
|
195
|
+
let bytes = 0;
|
|
196
|
+
let text = "";
|
|
197
|
+
const decoder = new TextDecoder;
|
|
198
|
+
const ignoreSettledError = () => {
|
|
199
|
+
return;
|
|
200
|
+
};
|
|
201
|
+
const finish = (outcome) => {
|
|
202
|
+
if (complete)
|
|
203
|
+
return;
|
|
204
|
+
complete = true;
|
|
205
|
+
control.off("data", onData);
|
|
206
|
+
control.off("end", onMissing);
|
|
207
|
+
control.off("close", onMissing);
|
|
208
|
+
control.off("error", onError);
|
|
209
|
+
control.on("error", ignoreSettledError);
|
|
210
|
+
control.once("close", () => control.off("error", ignoreSettledError));
|
|
211
|
+
if ("pid" in outcome)
|
|
212
|
+
settled.resolve(outcome.pid);
|
|
213
|
+
else
|
|
214
|
+
settled.reject(outcome.error);
|
|
215
|
+
};
|
|
216
|
+
const onMissing = () => finish({ error: unavailable("Owner-loss guard exited before the command started") });
|
|
217
|
+
const onError = (cause) => finish({ error: unavailable("Owner-loss guard control failed", cause) });
|
|
218
|
+
const onData = (chunk) => {
|
|
219
|
+
if (complete)
|
|
220
|
+
return;
|
|
221
|
+
bytes += chunk.byteLength;
|
|
222
|
+
if (bytes > MAX_GUARD_MESSAGE_BYTES) {
|
|
223
|
+
finish({ error: unavailable("Owner-loss guard response exceeded its finite bound") });
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
text += decoder.decode(chunk, { stream: true });
|
|
227
|
+
const newline = text.indexOf(`
|
|
228
|
+
`);
|
|
229
|
+
if (newline < 0)
|
|
230
|
+
return;
|
|
231
|
+
try {
|
|
232
|
+
const message = OwnerLossGuardMessageSchema.parse(JSON.parse(text.slice(0, newline)));
|
|
233
|
+
if (message.kind === "started")
|
|
234
|
+
finish({ pid: message.pid });
|
|
235
|
+
else {
|
|
236
|
+
const cause = new Error(message.message);
|
|
237
|
+
if (message.code !== undefined)
|
|
238
|
+
Object.defineProperty(cause, "code", { value: message.code });
|
|
239
|
+
finish({ error: unavailable(message.message, cause) });
|
|
240
|
+
}
|
|
241
|
+
} catch (cause) {
|
|
242
|
+
finish({ error: unavailable("Owner-loss guard returned an invalid response", cause) });
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
control.on("data", onData);
|
|
246
|
+
control.once("end", onMissing);
|
|
247
|
+
control.once("close", onMissing);
|
|
248
|
+
control.once("error", onError);
|
|
249
|
+
child.on("exit", onMissing);
|
|
250
|
+
guards.set(child, { control, started: settled.promise });
|
|
251
|
+
}
|
|
252
|
+
function transferOwnerLossControl(source, target) {
|
|
253
|
+
const registration = guards.get(source);
|
|
254
|
+
if (registration !== undefined)
|
|
255
|
+
guards.set(target, registration);
|
|
256
|
+
}
|
|
257
|
+
async function awaitCommandStart(child) {
|
|
258
|
+
const registration = guards.get(child);
|
|
259
|
+
if (registration !== undefined)
|
|
260
|
+
await registration.started;
|
|
261
|
+
return child.pid;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// src/process/owner-loss-protocol.ts
|
|
265
|
+
var OWNER_LOSS_GUARD_FLAG = "--stitchkit-owner-loss-guard-v1";
|
|
266
|
+
function ownerLossAvailable(platform) {
|
|
267
|
+
return platform === "linux" || platform === "darwin";
|
|
268
|
+
}
|
|
269
|
+
function ownerLossGuardCommand(guard, executable, args) {
|
|
270
|
+
return [
|
|
271
|
+
process.execPath,
|
|
272
|
+
guard.entry,
|
|
273
|
+
OWNER_LOSS_GUARD_FLAG,
|
|
274
|
+
guard.signalTarget,
|
|
275
|
+
executable,
|
|
276
|
+
...args
|
|
277
|
+
];
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// src/process/owner-loss-socket.ts
|
|
281
|
+
import { connect } from "node:net";
|
|
282
|
+
function connectOwnerLossSocket(fd) {
|
|
283
|
+
return Reflect.apply(connect, undefined, [{ fd }]);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// src/process/bun-child.ts
|
|
287
|
+
function hostIsBun() {
|
|
288
|
+
return typeof Bun !== "undefined";
|
|
289
|
+
}
|
|
290
|
+
function readableOf(source) {
|
|
291
|
+
const reader = source.getReader();
|
|
292
|
+
let reading = false;
|
|
293
|
+
return new Readable({
|
|
294
|
+
read() {
|
|
295
|
+
if (reading)
|
|
296
|
+
return;
|
|
297
|
+
reading = true;
|
|
298
|
+
reader.read().then(({ done, value }) => {
|
|
299
|
+
reading = false;
|
|
300
|
+
if (done)
|
|
301
|
+
this.push(null);
|
|
302
|
+
else
|
|
303
|
+
this.push(value);
|
|
304
|
+
}, (error) => {
|
|
305
|
+
reading = false;
|
|
306
|
+
this.destroy(error instanceof Error ? error : new Error(String(error)));
|
|
307
|
+
});
|
|
308
|
+
},
|
|
309
|
+
destroy(error, done) {
|
|
310
|
+
reader.cancel().then(() => done(error), () => done(error));
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
var REPORTED_SPAWN_CODES = new Set(["ENOENT", "EACCES", "EAGAIN", "EMFILE", "ENFILE"]);
|
|
315
|
+
function reportedSpawnFailure(cause) {
|
|
316
|
+
return typeof cause === "object" && cause !== null && "code" in cause && typeof cause.code === "string" && REPORTED_SPAWN_CODES.has(cause.code);
|
|
317
|
+
}
|
|
318
|
+
var waitClosed = (stream) => stream.closed ? Promise.resolve() : new Promise((resolve) => stream.once("close", () => resolve()));
|
|
319
|
+
function defineBunChildren() {
|
|
320
|
+
|
|
321
|
+
class BunProcess extends EventEmitter {
|
|
322
|
+
pipes;
|
|
323
|
+
pid;
|
|
324
|
+
exitCode = null;
|
|
325
|
+
signalCode = null;
|
|
326
|
+
#subprocess;
|
|
327
|
+
constructor(pipes) {
|
|
328
|
+
super();
|
|
329
|
+
this.pipes = pipes;
|
|
330
|
+
}
|
|
331
|
+
watch(subprocess) {
|
|
332
|
+
this.pid = subprocess.pid;
|
|
333
|
+
this.#subprocess = subprocess;
|
|
334
|
+
subprocess.exited.then(() => {
|
|
335
|
+
this.exitCode = subprocess.exitCode;
|
|
336
|
+
this.signalCode = subprocess.signalCode;
|
|
337
|
+
this.emit("exit", this.exitCode, this.signalCode);
|
|
338
|
+
for (const pipe of this.pipes)
|
|
339
|
+
if (pipe.readableFlowing === null)
|
|
340
|
+
pipe.resume();
|
|
341
|
+
this.closeAfterPipes();
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
fail(cause) {
|
|
345
|
+
for (const pipe of this.pipes)
|
|
346
|
+
pipe.resume();
|
|
347
|
+
setImmediate(() => {
|
|
348
|
+
this.emit("error", cause);
|
|
349
|
+
this.closeAfterPipes();
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
kill(signal) {
|
|
353
|
+
const subprocess = this.#subprocess;
|
|
354
|
+
if (!subprocess || this.exitCode !== null || this.signalCode !== null)
|
|
355
|
+
return false;
|
|
356
|
+
try {
|
|
357
|
+
subprocess.kill(signal);
|
|
358
|
+
return true;
|
|
359
|
+
} catch {
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
closeAfterPipes() {
|
|
364
|
+
Promise.all(this.pipes.map(waitClosed)).then(() => this.emit("close", this.exitCode, this.signalCode));
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
class BunChild extends BunProcess {
|
|
369
|
+
stdin;
|
|
370
|
+
stdout;
|
|
371
|
+
stderr;
|
|
372
|
+
constructor(stdin, stdout, stderr) {
|
|
373
|
+
super([stdout, stderr]);
|
|
374
|
+
this.stdin = stdin;
|
|
375
|
+
this.stdout = stdout;
|
|
376
|
+
this.stderr = stderr;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return { BunProcess, BunChild };
|
|
380
|
+
}
|
|
381
|
+
var bunChildren;
|
|
382
|
+
function children() {
|
|
383
|
+
bunChildren ??= defineBunChildren();
|
|
384
|
+
return bunChildren;
|
|
385
|
+
}
|
|
386
|
+
function sinkWritable(sink) {
|
|
387
|
+
let ended = false;
|
|
388
|
+
const end = () => {
|
|
389
|
+
if (ended)
|
|
390
|
+
return Promise.resolve(0);
|
|
391
|
+
ended = true;
|
|
392
|
+
return Promise.resolve().then(() => sink.end());
|
|
393
|
+
};
|
|
394
|
+
return new Writable({
|
|
395
|
+
write(chunk, _encoding, done) {
|
|
396
|
+
Promise.resolve().then(() => sink.write(chunk)).then(() => done(), done);
|
|
397
|
+
},
|
|
398
|
+
final(done) {
|
|
399
|
+
end().then(() => done(), done);
|
|
400
|
+
},
|
|
401
|
+
destroy(error, done) {
|
|
402
|
+
end().then(() => done(error), () => done(error));
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
function spawnBunChild(input) {
|
|
407
|
+
const { BunChild } = children();
|
|
408
|
+
try {
|
|
409
|
+
const ownerLoss = input.ownerLoss;
|
|
410
|
+
const guarded = ownerLoss !== undefined;
|
|
411
|
+
const command = guarded ? ownerLossGuardCommand(ownerLoss, input.executable, input.args) : [input.executable, ...input.args];
|
|
412
|
+
const subprocess = guarded ? Bun.spawn(command, {
|
|
413
|
+
cwd: input.cwd,
|
|
414
|
+
env: input.env,
|
|
415
|
+
detached: input.group,
|
|
416
|
+
stdio: ["pipe", "pipe", "pipe", "socket-fd"]
|
|
417
|
+
}) : Bun.spawn(command, {
|
|
418
|
+
cwd: input.cwd,
|
|
419
|
+
env: input.env,
|
|
420
|
+
detached: input.group,
|
|
421
|
+
stdin: "pipe",
|
|
422
|
+
stdout: "pipe",
|
|
423
|
+
stderr: "pipe"
|
|
424
|
+
});
|
|
425
|
+
const child = new BunChild(sinkWritable(subprocess.stdin), readableOf(subprocess.stdout), readableOf(subprocess.stderr));
|
|
426
|
+
child.watch(subprocess);
|
|
427
|
+
if (guarded) {
|
|
428
|
+
const fd = subprocess.stdio[3];
|
|
429
|
+
if (typeof fd !== "number") {
|
|
430
|
+
abortOwnerLossLaunch(subprocess.pid);
|
|
431
|
+
throw new Error("Owner-loss guard supplied no control socket");
|
|
432
|
+
}
|
|
433
|
+
attachOwnerLossControl(child, connectOwnerLossSocket(fd));
|
|
434
|
+
}
|
|
435
|
+
return child;
|
|
436
|
+
} catch (cause) {
|
|
437
|
+
if (!reportedSpawnFailure(cause))
|
|
438
|
+
throw cause;
|
|
439
|
+
const child = new BunChild(new Writable({ write: (_chunk, _encoding, done) => done() }), Readable.from([]), Readable.from([]));
|
|
440
|
+
child.fail(cause);
|
|
441
|
+
return child;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
function spawnBunInheritedChild(input) {
|
|
445
|
+
const { BunProcess } = children();
|
|
446
|
+
const child = new BunProcess([]);
|
|
447
|
+
try {
|
|
448
|
+
const ownerLoss = input.ownerLoss;
|
|
449
|
+
const guarded = ownerLoss !== undefined;
|
|
450
|
+
const command = guarded ? ownerLossGuardCommand(ownerLoss, input.executable, input.args) : [input.executable, ...input.args];
|
|
451
|
+
const subprocess = guarded ? Bun.spawn(command, {
|
|
452
|
+
cwd: input.cwd,
|
|
453
|
+
env: input.env,
|
|
454
|
+
detached: input.group,
|
|
455
|
+
stdio: ["inherit", "inherit", "inherit", "socket-fd"]
|
|
456
|
+
}) : Bun.spawn(command, {
|
|
457
|
+
cwd: input.cwd,
|
|
458
|
+
env: input.env,
|
|
459
|
+
detached: input.group,
|
|
460
|
+
stdin: "inherit",
|
|
461
|
+
stdout: "inherit",
|
|
462
|
+
stderr: "inherit"
|
|
463
|
+
});
|
|
464
|
+
child.watch(subprocess);
|
|
465
|
+
if (guarded) {
|
|
466
|
+
const fd = subprocess.stdio[3];
|
|
467
|
+
if (typeof fd !== "number") {
|
|
468
|
+
abortOwnerLossLaunch(subprocess.pid);
|
|
469
|
+
throw new Error("Owner-loss guard supplied no control socket");
|
|
470
|
+
}
|
|
471
|
+
attachOwnerLossControl(child, connectOwnerLossSocket(fd));
|
|
472
|
+
}
|
|
473
|
+
} catch (cause) {
|
|
474
|
+
if (!reportedSpawnFailure(cause))
|
|
475
|
+
throw cause;
|
|
476
|
+
child.fail(cause);
|
|
477
|
+
}
|
|
478
|
+
return child;
|
|
479
|
+
}
|
|
480
|
+
function spawnBunGuardTarget(executable, args) {
|
|
481
|
+
return Bun.spawn([executable, ...args], {
|
|
482
|
+
stdin: "inherit",
|
|
483
|
+
stdout: "inherit",
|
|
484
|
+
stderr: "inherit"
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// src/process/owner-loss-guard.ts
|
|
489
|
+
var FORWARDED_SIGNALS = [
|
|
490
|
+
"SIGTERM",
|
|
491
|
+
"SIGINT",
|
|
492
|
+
"SIGHUP",
|
|
493
|
+
"SIGQUIT",
|
|
494
|
+
"SIGUSR1",
|
|
495
|
+
"SIGUSR2"
|
|
496
|
+
];
|
|
497
|
+
function causeMessage(cause) {
|
|
498
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
499
|
+
if (typeof cause === "object" && cause !== null && "code" in cause && typeof cause.code === "string")
|
|
500
|
+
return { message, code: cause.code };
|
|
501
|
+
return { message };
|
|
502
|
+
}
|
|
503
|
+
function guardMessage(control, message, written) {
|
|
504
|
+
control.write(`${JSON.stringify(message)}
|
|
505
|
+
`, written);
|
|
506
|
+
}
|
|
507
|
+
function mirrorTargetExit(control, code, signal) {
|
|
508
|
+
control.destroy();
|
|
509
|
+
if (signal !== null)
|
|
510
|
+
process.kill(process.pid, signal);
|
|
511
|
+
else
|
|
512
|
+
process.exitCode = code ?? 1;
|
|
513
|
+
}
|
|
514
|
+
function refuseTarget(control, cause) {
|
|
515
|
+
const detail = causeMessage(cause);
|
|
516
|
+
control.end(`${JSON.stringify({ kind: "unavailable", ...detail })}
|
|
517
|
+
`, () => {
|
|
518
|
+
process.exitCode = 127;
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
function spawnNodeTarget(executable, args, onStarted, onExit, onUnavailable) {
|
|
522
|
+
let child;
|
|
523
|
+
try {
|
|
524
|
+
child = spawn(executable, [...args], { stdio: "inherit" });
|
|
525
|
+
} catch (cause) {
|
|
526
|
+
onUnavailable(cause);
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
child.once("spawn", () => {
|
|
530
|
+
const pid = child.pid;
|
|
531
|
+
if (pid === undefined)
|
|
532
|
+
onUnavailable(new Error("Command started without a pid"));
|
|
533
|
+
else
|
|
534
|
+
onStarted(pid);
|
|
535
|
+
});
|
|
536
|
+
child.once("error", onUnavailable);
|
|
537
|
+
child.once("exit", onExit);
|
|
538
|
+
}
|
|
539
|
+
function spawnBunTarget(executable, args, onStarted, onExit, onUnavailable) {
|
|
540
|
+
let child;
|
|
541
|
+
try {
|
|
542
|
+
child = spawnBunGuardTarget(executable, args);
|
|
543
|
+
} catch (cause) {
|
|
544
|
+
onUnavailable(cause);
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
onStarted(child.pid);
|
|
548
|
+
child.exited.then(() => onExit(child.exitCode, child.signalCode));
|
|
549
|
+
}
|
|
550
|
+
function runOwnerLossGuard(signalTarget, executable, args) {
|
|
551
|
+
const bun = hostIsBun();
|
|
552
|
+
const control = bun ? connectOwnerLossSocket(3) : new Socket({ fd: 3, readable: true, writable: true });
|
|
553
|
+
let armed = true;
|
|
554
|
+
const ownerLost = () => {
|
|
555
|
+
if (!armed)
|
|
556
|
+
return;
|
|
557
|
+
process.kill(-process.pid, "SIGKILL");
|
|
558
|
+
};
|
|
559
|
+
control.once("end", ownerLost);
|
|
560
|
+
control.once("close", ownerLost);
|
|
561
|
+
control.once("error", ownerLost);
|
|
562
|
+
if (signalTarget !== "group" && signalTarget !== "leader" || executable === undefined) {
|
|
563
|
+
armed = false;
|
|
564
|
+
refuseTarget(control, new Error("Owner-loss guard received an invalid invocation"));
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
let targetPid;
|
|
568
|
+
let handshakeWritten = false;
|
|
569
|
+
let pendingTargetExit;
|
|
570
|
+
const forwarders = new Map;
|
|
571
|
+
if (signalTarget === "leader")
|
|
572
|
+
for (const signal of FORWARDED_SIGNALS) {
|
|
573
|
+
const forward = () => {
|
|
574
|
+
if (targetPid === undefined)
|
|
575
|
+
return;
|
|
576
|
+
try {
|
|
577
|
+
process.kill(targetPid, signal);
|
|
578
|
+
} catch (error) {
|
|
579
|
+
if (!(error instanceof Error && ("code" in error) && error.code === "ESRCH"))
|
|
580
|
+
throw error;
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
forwarders.set(signal, forward);
|
|
584
|
+
process.on(signal, forward);
|
|
585
|
+
}
|
|
586
|
+
const removeForwarders = () => {
|
|
587
|
+
for (const [signal, forward] of forwarders)
|
|
588
|
+
process.removeListener(signal, forward);
|
|
589
|
+
forwarders.clear();
|
|
590
|
+
};
|
|
591
|
+
const targetStarted = (pid) => {
|
|
592
|
+
targetPid = pid;
|
|
593
|
+
guardMessage(control, { kind: "started", pid }, () => {
|
|
594
|
+
handshakeWritten = true;
|
|
595
|
+
const pending = pendingTargetExit;
|
|
596
|
+
if (pending !== undefined) {
|
|
597
|
+
pendingTargetExit = undefined;
|
|
598
|
+
targetExit(pending.code, pending.signal);
|
|
599
|
+
}
|
|
600
|
+
});
|
|
601
|
+
};
|
|
602
|
+
const targetExit = (code, signal) => {
|
|
603
|
+
if (!handshakeWritten) {
|
|
604
|
+
pendingTargetExit = { code, signal };
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
armed = false;
|
|
608
|
+
removeForwarders();
|
|
609
|
+
mirrorTargetExit(control, code, signal);
|
|
610
|
+
};
|
|
611
|
+
const targetUnavailable = (cause) => {
|
|
612
|
+
armed = false;
|
|
613
|
+
removeForwarders();
|
|
614
|
+
refuseTarget(control, cause);
|
|
615
|
+
};
|
|
616
|
+
if (!bun)
|
|
617
|
+
spawnNodeTarget(executable, args, targetStarted, targetExit, targetUnavailable);
|
|
618
|
+
else
|
|
619
|
+
spawnBunTarget(executable, args, targetStarted, targetExit, targetUnavailable);
|
|
620
|
+
}
|
|
621
|
+
var guardInvocation = false;
|
|
622
|
+
function startOwnerLossGuardEntry() {
|
|
623
|
+
if (process.argv[2] !== OWNER_LOSS_GUARD_FLAG)
|
|
624
|
+
return;
|
|
625
|
+
const entry = process.argv[1];
|
|
626
|
+
if (entry === undefined || fileURLToPath(import.meta.url) !== entry)
|
|
627
|
+
return;
|
|
628
|
+
runOwnerLossGuard(process.argv[3], process.argv[4], process.argv.slice(5));
|
|
629
|
+
guardInvocation = true;
|
|
630
|
+
}
|
|
631
|
+
function bootstrapNativeCommandOwnerLoss2() {
|
|
632
|
+
return guardInvocation;
|
|
633
|
+
}
|
|
634
|
+
function ownerLossGuardEntry() {
|
|
635
|
+
return fileURLToPath(import.meta.url);
|
|
636
|
+
}
|
|
637
|
+
startOwnerLossGuardEntry();
|
|
638
|
+
|
|
639
|
+
export { COMMAND_CLEANUP_TIMEOUT_MS, NativeCommandOptionsSchema, NativeCommandError2, abortOwnerLossLaunch, attachOwnerLossControl, transferOwnerLossControl, awaitCommandStart, ownerLossAvailable, ownerLossGuardCommand, hostIsBun, spawnBunChild, spawnBunInheritedChild, bootstrapNativeCommandOwnerLoss2, ownerLossGuardEntry };
|
|
@@ -183,6 +183,25 @@ function unwrap(field) {
|
|
|
183
183
|
}
|
|
184
184
|
return field;
|
|
185
185
|
}
|
|
186
|
+
function literalKind(field) {
|
|
187
|
+
const base = unwrap(field);
|
|
188
|
+
if (base instanceof z.ZodLiteral) {
|
|
189
|
+
const kinds = new Set;
|
|
190
|
+
for (const value of base.values) {
|
|
191
|
+
const kind = typeof value;
|
|
192
|
+
if (kind !== "boolean" && kind !== "number" && kind !== "bigint" && kind !== "string")
|
|
193
|
+
return;
|
|
194
|
+
kinds.add(kind);
|
|
195
|
+
}
|
|
196
|
+
return kinds.size === 1 ? kinds.values().next().value : undefined;
|
|
197
|
+
}
|
|
198
|
+
if (base instanceof z.ZodUnion) {
|
|
199
|
+
const kinds = base.def.options.map(literalKind);
|
|
200
|
+
const first = kinds[0];
|
|
201
|
+
return first !== undefined && kinds.every((kind) => kind === first) ? first : undefined;
|
|
202
|
+
}
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
186
205
|
function classify(field) {
|
|
187
206
|
if (field instanceof z.ZodBoolean)
|
|
188
207
|
return "boolean";
|
|
@@ -198,7 +217,10 @@ function classify(field) {
|
|
|
198
217
|
return "array";
|
|
199
218
|
if (field instanceof z.ZodObject)
|
|
200
219
|
return "object";
|
|
201
|
-
|
|
220
|
+
const primitiveLiteral = literalKind(field);
|
|
221
|
+
if (primitiveLiteral !== undefined)
|
|
222
|
+
return primitiveLiteral;
|
|
223
|
+
if (field instanceof z.ZodString)
|
|
202
224
|
return "string";
|
|
203
225
|
return "other";
|
|
204
226
|
}
|
|
@@ -2,10 +2,8 @@ import {
|
|
|
2
2
|
loadDarwinBinding
|
|
3
3
|
} from "./index-2kbysk9s.js";
|
|
4
4
|
import {
|
|
5
|
-
NativeCommandError2
|
|
6
|
-
|
|
7
|
-
startNativeCommand
|
|
8
|
-
} from "./index-k0kzhdw9.js";
|
|
5
|
+
NativeCommandError2
|
|
6
|
+
} from "./index-dj1aycxw.js";
|
|
9
7
|
import {
|
|
10
8
|
probeAgentProcessSandboxOutcome,
|
|
11
9
|
missingSandboxRestrictions2,
|
|
@@ -13,6 +11,10 @@ import {
|
|
|
13
11
|
codingPathRefusal,
|
|
14
12
|
refuseMissingCodingPath
|
|
15
13
|
} from "./index-8ks9b85e.js";
|
|
14
|
+
import {
|
|
15
|
+
CommandStopped,
|
|
16
|
+
startNativeCommand
|
|
17
|
+
} from "./index-dasy32c8.js";
|
|
16
18
|
import {
|
|
17
19
|
NumericFileHandle,
|
|
18
20
|
descriptorPath,
|
|
@@ -923,7 +925,8 @@ async function editFile(config, limits, input) {
|
|
|
923
925
|
});
|
|
924
926
|
}
|
|
925
927
|
const replacements = input.replaceAll ? count : 1;
|
|
926
|
-
const
|
|
928
|
+
const literalReplacement = () => input.newText;
|
|
929
|
+
const changed = input.replaceAll ? source.replaceAll(input.oldText, literalReplacement) : source.replace(input.oldText, literalReplacement);
|
|
927
930
|
const bytes = Buffer.byteLength(changed);
|
|
928
931
|
const resultSha256 = sha256(changed);
|
|
929
932
|
if (bytes > limits.maxWriteBytes) {
|