@usecontextlayer/ctxe 0.4.2 → 0.4.5
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.mjs +474 -198
- package/dist/cli.mjs.map +1 -1
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
3
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1a858cd0-cb9a-550b-a3f9-5ca9387cf7df")}catch(e){}}();
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import * as Sentry from "@sentry/node";
|
|
6
6
|
import * as xi from "node:fs";
|
|
@@ -59,7 +59,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
59
59
|
|
|
60
60
|
//#endregion
|
|
61
61
|
//#region package.json
|
|
62
|
-
var version$1 = "0.4.
|
|
62
|
+
var version$1 = "0.4.5";
|
|
63
63
|
|
|
64
64
|
//#endregion
|
|
65
65
|
//#region sentry.ts
|
|
@@ -7895,6 +7895,7 @@ const string$1 = (params) => {
|
|
|
7895
7895
|
};
|
|
7896
7896
|
const integer = /^-?\d+$/;
|
|
7897
7897
|
const number$1 = /^-?\d+(?:\.\d+)?$/;
|
|
7898
|
+
const boolean$1 = /^(?:true|false)$/i;
|
|
7898
7899
|
const lowercase = /^[^A-Z]*$/;
|
|
7899
7900
|
const uppercase = /^[^a-z]*$/;
|
|
7900
7901
|
|
|
@@ -8693,6 +8694,24 @@ const $ZodNumberFormat = /*@__PURE__*/ $constructor("$ZodNumberFormat", (inst, d
|
|
|
8693
8694
|
$ZodCheckNumberFormat.init(inst, def);
|
|
8694
8695
|
$ZodNumber.init(inst, def);
|
|
8695
8696
|
});
|
|
8697
|
+
const $ZodBoolean = /*@__PURE__*/ $constructor("$ZodBoolean", (inst, def) => {
|
|
8698
|
+
$ZodType.init(inst, def);
|
|
8699
|
+
inst._zod.pattern = boolean$1;
|
|
8700
|
+
inst._zod.parse = (payload, _ctx) => {
|
|
8701
|
+
if (def.coerce) try {
|
|
8702
|
+
payload.value = Boolean(payload.value);
|
|
8703
|
+
} catch (_) {}
|
|
8704
|
+
const input = payload.value;
|
|
8705
|
+
if (typeof input === "boolean") return payload;
|
|
8706
|
+
payload.issues.push({
|
|
8707
|
+
expected: "boolean",
|
|
8708
|
+
code: "invalid_type",
|
|
8709
|
+
input,
|
|
8710
|
+
inst
|
|
8711
|
+
});
|
|
8712
|
+
return payload;
|
|
8713
|
+
};
|
|
8714
|
+
});
|
|
8696
8715
|
const $ZodUnknown = /*@__PURE__*/ $constructor("$ZodUnknown", (inst, def) => {
|
|
8697
8716
|
$ZodType.init(inst, def);
|
|
8698
8717
|
inst._zod.parse = (payload) => payload;
|
|
@@ -9264,6 +9283,24 @@ const $ZodEnum = /*@__PURE__*/ $constructor("$ZodEnum", (inst, def) => {
|
|
|
9264
9283
|
return payload;
|
|
9265
9284
|
};
|
|
9266
9285
|
});
|
|
9286
|
+
const $ZodLiteral = /*@__PURE__*/ $constructor("$ZodLiteral", (inst, def) => {
|
|
9287
|
+
$ZodType.init(inst, def);
|
|
9288
|
+
if (def.values.length === 0) throw new Error("Cannot create literal schema with no valid values");
|
|
9289
|
+
const values = new Set(def.values);
|
|
9290
|
+
inst._zod.values = values;
|
|
9291
|
+
inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$`);
|
|
9292
|
+
inst._zod.parse = (payload, _ctx) => {
|
|
9293
|
+
const input = payload.value;
|
|
9294
|
+
if (values.has(input)) return payload;
|
|
9295
|
+
payload.issues.push({
|
|
9296
|
+
code: "invalid_value",
|
|
9297
|
+
values: def.values,
|
|
9298
|
+
input,
|
|
9299
|
+
inst
|
|
9300
|
+
});
|
|
9301
|
+
return payload;
|
|
9302
|
+
};
|
|
9303
|
+
});
|
|
9267
9304
|
const $ZodTransform = /*@__PURE__*/ $constructor("$ZodTransform", (inst, def) => {
|
|
9268
9305
|
$ZodType.init(inst, def);
|
|
9269
9306
|
inst._zod.optin = "optional";
|
|
@@ -9837,6 +9874,13 @@ function _int(Class, params) {
|
|
|
9837
9874
|
});
|
|
9838
9875
|
}
|
|
9839
9876
|
// @__NO_SIDE_EFFECTS__
|
|
9877
|
+
function _boolean(Class, params) {
|
|
9878
|
+
return new Class({
|
|
9879
|
+
type: "boolean",
|
|
9880
|
+
...normalizeParams(params)
|
|
9881
|
+
});
|
|
9882
|
+
}
|
|
9883
|
+
// @__NO_SIDE_EFFECTS__
|
|
9840
9884
|
function _unknown(Class) {
|
|
9841
9885
|
return new Class({ type: "unknown" });
|
|
9842
9886
|
}
|
|
@@ -10384,6 +10428,9 @@ const numberProcessor = (schema, ctx, _json, _params) => {
|
|
|
10384
10428
|
else if (typeof maximum === "number") json.maximum = maximum;
|
|
10385
10429
|
if (typeof multipleOf === "number") json.multipleOf = multipleOf;
|
|
10386
10430
|
};
|
|
10431
|
+
const booleanProcessor = (_schema, _ctx, json, _params) => {
|
|
10432
|
+
json.type = "boolean";
|
|
10433
|
+
};
|
|
10387
10434
|
const neverProcessor = (_schema, _ctx, json, _params) => {
|
|
10388
10435
|
json.not = {};
|
|
10389
10436
|
};
|
|
@@ -10395,6 +10442,27 @@ const enumProcessor = (schema, _ctx, json, _params) => {
|
|
|
10395
10442
|
if (values.every((v) => typeof v === "string")) json.type = "string";
|
|
10396
10443
|
json.enum = values;
|
|
10397
10444
|
};
|
|
10445
|
+
const literalProcessor = (schema, ctx, json, _params) => {
|
|
10446
|
+
const def = schema._zod.def;
|
|
10447
|
+
const vals = [];
|
|
10448
|
+
for (const val of def.values) if (val === void 0) {
|
|
10449
|
+
if (ctx.unrepresentable === "throw") throw new Error("Literal `undefined` cannot be represented in JSON Schema");
|
|
10450
|
+
} else if (typeof val === "bigint") if (ctx.unrepresentable === "throw") throw new Error("BigInt literals cannot be represented in JSON Schema");
|
|
10451
|
+
else vals.push(Number(val));
|
|
10452
|
+
else vals.push(val);
|
|
10453
|
+
if (vals.length === 0) {} else if (vals.length === 1) {
|
|
10454
|
+
const val = vals[0];
|
|
10455
|
+
json.type = val === null ? "null" : typeof val;
|
|
10456
|
+
if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") json.enum = [val];
|
|
10457
|
+
else json.const = val;
|
|
10458
|
+
} else {
|
|
10459
|
+
if (vals.every((v) => typeof v === "number")) json.type = "number";
|
|
10460
|
+
if (vals.every((v) => typeof v === "string")) json.type = "string";
|
|
10461
|
+
if (vals.every((v) => typeof v === "boolean")) json.type = "boolean";
|
|
10462
|
+
if (vals.every((v) => v === null)) json.type = "null";
|
|
10463
|
+
json.enum = vals;
|
|
10464
|
+
}
|
|
10465
|
+
};
|
|
10398
10466
|
const customProcessor = (_schema, ctx, _json, _params) => {
|
|
10399
10467
|
if (ctx.unrepresentable === "throw") throw new Error("Custom types cannot be represented in JSON Schema");
|
|
10400
10468
|
};
|
|
@@ -11050,6 +11118,14 @@ const ZodNumberFormat = /*@__PURE__*/ $constructor("ZodNumberFormat", (inst, def
|
|
|
11050
11118
|
function int(params) {
|
|
11051
11119
|
return _int(ZodNumberFormat, params);
|
|
11052
11120
|
}
|
|
11121
|
+
const ZodBoolean = /*@__PURE__*/ $constructor("ZodBoolean", (inst, def) => {
|
|
11122
|
+
$ZodBoolean.init(inst, def);
|
|
11123
|
+
ZodType.init(inst, def);
|
|
11124
|
+
inst._zod.processJSONSchema = (ctx, json, params) => booleanProcessor(inst, ctx, json, params);
|
|
11125
|
+
});
|
|
11126
|
+
function boolean(params) {
|
|
11127
|
+
return _boolean(ZodBoolean, params);
|
|
11128
|
+
}
|
|
11053
11129
|
const ZodUnknown = /*@__PURE__*/ $constructor("ZodUnknown", (inst, def) => {
|
|
11054
11130
|
$ZodUnknown.init(inst, def);
|
|
11055
11131
|
ZodType.init(inst, def);
|
|
@@ -11254,6 +11330,23 @@ function _enum(values, params) {
|
|
|
11254
11330
|
...normalizeParams(params)
|
|
11255
11331
|
});
|
|
11256
11332
|
}
|
|
11333
|
+
const ZodLiteral = /*@__PURE__*/ $constructor("ZodLiteral", (inst, def) => {
|
|
11334
|
+
$ZodLiteral.init(inst, def);
|
|
11335
|
+
ZodType.init(inst, def);
|
|
11336
|
+
inst._zod.processJSONSchema = (ctx, json, params) => literalProcessor(inst, ctx, json, params);
|
|
11337
|
+
inst.values = new Set(def.values);
|
|
11338
|
+
Object.defineProperty(inst, "value", { get() {
|
|
11339
|
+
if (def.values.length > 1) throw new Error("This schema contains multiple valid literal values. Use `.values` instead.");
|
|
11340
|
+
return def.values[0];
|
|
11341
|
+
} });
|
|
11342
|
+
});
|
|
11343
|
+
function literal(value, params) {
|
|
11344
|
+
return new ZodLiteral({
|
|
11345
|
+
type: "literal",
|
|
11346
|
+
values: Array.isArray(value) ? value : [value],
|
|
11347
|
+
...normalizeParams(params)
|
|
11348
|
+
});
|
|
11349
|
+
}
|
|
11257
11350
|
const ZodTransform = /*@__PURE__*/ $constructor("ZodTransform", (inst, def) => {
|
|
11258
11351
|
$ZodTransform.init(inst, def);
|
|
11259
11352
|
ZodType.init(inst, def);
|
|
@@ -29490,7 +29583,7 @@ function validate(raw, sourcePath) {
|
|
|
29490
29583
|
}
|
|
29491
29584
|
function applyDefaults(input) {
|
|
29492
29585
|
return {
|
|
29493
|
-
synthesizerImage: input.synthesizerImage ?? "ghcr.io/usecontextlayer/ctx-sandbox:0.4.
|
|
29586
|
+
synthesizerImage: input.synthesizerImage ?? "ghcr.io/usecontextlayer/ctx-sandbox:0.4.5",
|
|
29494
29587
|
...input.microsandbox !== void 0 ? { microsandbox: input.microsandbox } : {},
|
|
29495
29588
|
...input.oldestConsideredPoint !== void 0 ? { oldestConsideredPoint: input.oldestConsideredPoint } : {},
|
|
29496
29589
|
maxSliceSize: input.maxSliceSize ?? 864e5,
|
|
@@ -29507,14 +29600,18 @@ function formatZodError$1(error) {
|
|
|
29507
29600
|
}).join("; ");
|
|
29508
29601
|
}
|
|
29509
29602
|
function planLoopPass(input) {
|
|
29510
|
-
const
|
|
29603
|
+
const frontierDue = input.synthesizers.filter((synthesizer) => input.now - synthesizer.frontier >= input.tick);
|
|
29604
|
+
const due = frontierDue.filter((synthesizer) => synthesizer.notBefore === void 0 || synthesizer.notBefore <= input.now);
|
|
29511
29605
|
if (due.length > 0) return {
|
|
29512
29606
|
kind: "run",
|
|
29513
29607
|
order: due.map((synthesizer) => synthesizer.name).sort()
|
|
29514
29608
|
};
|
|
29609
|
+
const gates = frontierDue.map((synthesizer) => synthesizer.notBefore).filter((notBefore) => notBefore !== void 0);
|
|
29610
|
+
const gatedUntil = gates.length > 0 ? Math.min(...gates) : void 0;
|
|
29515
29611
|
return {
|
|
29516
29612
|
kind: "idle",
|
|
29517
|
-
wakeAt: input.synthesizers.length === 0 ? input.now + input.tick : Math.min(...input.synthesizers.map((synthesizer) => synthesizer.frontier + input.tick))
|
|
29613
|
+
wakeAt: input.synthesizers.length === 0 ? input.now + input.tick : Math.min(...input.synthesizers.map((synthesizer) => Math.max(synthesizer.frontier + input.tick, synthesizer.notBefore ?? 0))),
|
|
29614
|
+
...gatedUntil !== void 0 && { gatedUntil }
|
|
29518
29615
|
};
|
|
29519
29616
|
}
|
|
29520
29617
|
async function runEngineLoop(deps, options) {
|
|
@@ -29527,17 +29624,20 @@ async function runEngineLoop(deps, options) {
|
|
|
29527
29624
|
tick: options.tick
|
|
29528
29625
|
});
|
|
29529
29626
|
if (pass.kind === "idle") {
|
|
29530
|
-
if (options.mode === "backfill") return { stopReason: "caught_up" };
|
|
29627
|
+
if (options.mode === "backfill") return { stopReason: pass.gatedUntil !== void 0 ? "rate_limited" : "caught_up" };
|
|
29531
29628
|
await deps.sleep(Math.max(0, pass.wakeAt - deps.now()));
|
|
29532
29629
|
continue;
|
|
29533
29630
|
}
|
|
29534
29631
|
let advancedAny = false;
|
|
29632
|
+
let rateLimitedAny = false;
|
|
29535
29633
|
for (const name of pass.order) {
|
|
29536
29634
|
if (options.signal?.aborted) return { stopReason: "aborted" };
|
|
29537
|
-
|
|
29635
|
+
const outcome = await deps.runSlice(name);
|
|
29636
|
+
if (outcome.advanced) advancedAny = true;
|
|
29637
|
+
if (outcome.rateLimited) rateLimitedAny = true;
|
|
29538
29638
|
}
|
|
29539
29639
|
if (!advancedAny) {
|
|
29540
|
-
if (options.mode === "backfill") return { stopReason: "stalled" };
|
|
29640
|
+
if (options.mode === "backfill") return { stopReason: rateLimitedAny ? "rate_limited" : "stalled" };
|
|
29541
29641
|
await deps.sleep(options.tick);
|
|
29542
29642
|
}
|
|
29543
29643
|
}
|
|
@@ -29904,6 +30004,189 @@ function dirtyWorkingTreeIssue(paths) {
|
|
|
29904
30004
|
message: `Working tree is dirty:\n${formatWorkingTreePaths(paths)}\nRun 'ctxe repair' to roll back to HEAD (preserves .engine/runs/**).`
|
|
29905
30005
|
};
|
|
29906
30006
|
}
|
|
30007
|
+
const runTriggerSchema = _enum([
|
|
30008
|
+
"backfill",
|
|
30009
|
+
"daemon",
|
|
30010
|
+
"manual"
|
|
30011
|
+
]);
|
|
30012
|
+
_enum([
|
|
30013
|
+
"success",
|
|
30014
|
+
"failed",
|
|
30015
|
+
"timed_out",
|
|
30016
|
+
"rate_limited"
|
|
30017
|
+
]);
|
|
30018
|
+
const runStatusSchema = _enum([
|
|
30019
|
+
"starting",
|
|
30020
|
+
"running",
|
|
30021
|
+
"success",
|
|
30022
|
+
"failed",
|
|
30023
|
+
"timed_out",
|
|
30024
|
+
"rate_limited",
|
|
30025
|
+
"interrupted"
|
|
30026
|
+
]);
|
|
30027
|
+
const claudeResultSchema = strictObject({
|
|
30028
|
+
api_error_status: number().int().optional(),
|
|
30029
|
+
is_error: boolean(),
|
|
30030
|
+
num_turns: number().int(),
|
|
30031
|
+
subtype: string().min(1),
|
|
30032
|
+
terminal_reason: string().min(1).optional(),
|
|
30033
|
+
total_cost_usd: number()
|
|
30034
|
+
});
|
|
30035
|
+
const runRecordSchema = strictObject({
|
|
30036
|
+
claude_result: claudeResultSchema.optional(),
|
|
30037
|
+
completed_at: string().min(1).optional(),
|
|
30038
|
+
duration_ms: number().int().nonnegative().optional(),
|
|
30039
|
+
exit_code: number().int().optional(),
|
|
30040
|
+
rate_limit_resets_at: string().min(1).optional(),
|
|
30041
|
+
run_id: string().min(1),
|
|
30042
|
+
started_at: string().min(1),
|
|
30043
|
+
status: runStatusSchema,
|
|
30044
|
+
synthesizer: string().min(1),
|
|
30045
|
+
triggered_by: runTriggerSchema
|
|
30046
|
+
});
|
|
30047
|
+
const RECORD_FILE_NAME = "record.json";
|
|
30048
|
+
const STDERR_FILE_NAME = "stderr";
|
|
30049
|
+
function buildStartingRunRecord(input) {
|
|
30050
|
+
return {
|
|
30051
|
+
run_id: input.runId,
|
|
30052
|
+
started_at: input.startedAt,
|
|
30053
|
+
status: "starting",
|
|
30054
|
+
synthesizer: input.synthesizerName,
|
|
30055
|
+
triggered_by: input.trigger
|
|
30056
|
+
};
|
|
30057
|
+
}
|
|
30058
|
+
function buildRunningRunRecord(record) {
|
|
30059
|
+
return {
|
|
30060
|
+
...record,
|
|
30061
|
+
status: "running"
|
|
30062
|
+
};
|
|
30063
|
+
}
|
|
30064
|
+
function buildTerminalRunRecord(input) {
|
|
30065
|
+
return {
|
|
30066
|
+
...input.claudeResult !== void 0 && { claude_result: input.claudeResult },
|
|
30067
|
+
completed_at: input.completedAt,
|
|
30068
|
+
duration_ms: input.durationMs,
|
|
30069
|
+
exit_code: input.exitCode,
|
|
30070
|
+
...input.rateLimitResetsAt !== void 0 && { rate_limit_resets_at: input.rateLimitResetsAt },
|
|
30071
|
+
run_id: input.runId,
|
|
30072
|
+
started_at: input.startedAt,
|
|
30073
|
+
status: input.status,
|
|
30074
|
+
synthesizer: input.synthesizerName,
|
|
30075
|
+
triggered_by: input.trigger
|
|
30076
|
+
};
|
|
30077
|
+
}
|
|
30078
|
+
function buildInterruptedRunRecord(record, completedAt) {
|
|
30079
|
+
return {
|
|
30080
|
+
...record,
|
|
30081
|
+
completed_at: completedAt,
|
|
30082
|
+
status: "interrupted"
|
|
30083
|
+
};
|
|
30084
|
+
}
|
|
30085
|
+
function getRunDir(input) {
|
|
30086
|
+
return runDirPath(input.rootDir, input.synthesizerName, input.runId);
|
|
30087
|
+
}
|
|
30088
|
+
async function ensureRunDir(input) {
|
|
30089
|
+
const runDir = getRunDir(input);
|
|
30090
|
+
await mkdir(runDir, { recursive: true });
|
|
30091
|
+
return runDir;
|
|
30092
|
+
}
|
|
30093
|
+
async function writeRunRecord(runDir, record) {
|
|
30094
|
+
await mkdir(runDir, { recursive: true });
|
|
30095
|
+
await writeJsonFileAtomic(path.join(runDir, RECORD_FILE_NAME), runRecordSchema.parse(record));
|
|
30096
|
+
}
|
|
30097
|
+
async function readRunRecord(runDir) {
|
|
30098
|
+
const raw = await readFile(path.join(runDir, RECORD_FILE_NAME), "utf8");
|
|
30099
|
+
return runRecordSchema.parse(JSON.parse(raw));
|
|
30100
|
+
}
|
|
30101
|
+
async function listRunRecords(input) {
|
|
30102
|
+
const synthesizerNames = input.synthesizerName !== void 0 ? [input.synthesizerName] : await listSynthesizerRunDirNames(input.rootDir);
|
|
30103
|
+
const entries = [];
|
|
30104
|
+
for (const synthesizerName of synthesizerNames) {
|
|
30105
|
+
const synthesizerDir = synthesizerRunsDirPath(input.rootDir, synthesizerName);
|
|
30106
|
+
let runIds;
|
|
30107
|
+
try {
|
|
30108
|
+
runIds = await listDirectoryNames(synthesizerDir);
|
|
30109
|
+
} catch (error) {
|
|
30110
|
+
if (isNodeError(error) && error.code === "ENOENT") continue;
|
|
30111
|
+
throw error;
|
|
30112
|
+
}
|
|
30113
|
+
for (const runId of runIds) {
|
|
30114
|
+
const runDir = path.join(synthesizerDir, runId);
|
|
30115
|
+
try {
|
|
30116
|
+
entries.push({
|
|
30117
|
+
record: await readRunRecord(runDir),
|
|
30118
|
+
runDir,
|
|
30119
|
+
runId
|
|
30120
|
+
});
|
|
30121
|
+
} catch (error) {
|
|
30122
|
+
if (isNodeError(error) && error.code === "ENOENT") continue;
|
|
30123
|
+
throw error;
|
|
30124
|
+
}
|
|
30125
|
+
}
|
|
30126
|
+
}
|
|
30127
|
+
return entries.sort(compareRunRecordEntries);
|
|
30128
|
+
}
|
|
30129
|
+
async function readRunStderr(runDir) {
|
|
30130
|
+
return await readOptionalTextFile(path.join(runDir, STDERR_FILE_NAME));
|
|
30131
|
+
}
|
|
30132
|
+
async function writeRunStderr(input) {
|
|
30133
|
+
await mkdir(input.runDir, { recursive: true });
|
|
30134
|
+
await writeFileAtomic(path.join(input.runDir, STDERR_FILE_NAME), input.stderr);
|
|
30135
|
+
}
|
|
30136
|
+
async function markInterruptedRuns(rootDir) {
|
|
30137
|
+
const interrupted = [];
|
|
30138
|
+
const engineRunsDir = runsDirPath(rootDir);
|
|
30139
|
+
let synthesizerDirs;
|
|
30140
|
+
try {
|
|
30141
|
+
synthesizerDirs = await listDirectoryNames(engineRunsDir);
|
|
30142
|
+
} catch (error) {
|
|
30143
|
+
if (isNodeError(error) && error.code === "ENOENT") return [];
|
|
30144
|
+
throw error;
|
|
30145
|
+
}
|
|
30146
|
+
for (const synthesizerName of synthesizerDirs) {
|
|
30147
|
+
const synthesizerDir = path.join(engineRunsDir, synthesizerName);
|
|
30148
|
+
for (const runId of await listDirectoryNames(synthesizerDir)) {
|
|
30149
|
+
const runDir = path.join(synthesizerDir, runId);
|
|
30150
|
+
let record;
|
|
30151
|
+
try {
|
|
30152
|
+
record = await readRunRecord(runDir);
|
|
30153
|
+
} catch (error) {
|
|
30154
|
+
if (isNodeError(error) && error.code === "ENOENT") continue;
|
|
30155
|
+
throw error;
|
|
30156
|
+
}
|
|
30157
|
+
if (record.status !== "starting" && record.status !== "running") continue;
|
|
30158
|
+
const nextRecord = buildInterruptedRunRecord(record, (/* @__PURE__ */ new Date()).toISOString());
|
|
30159
|
+
await writeRunRecord(runDir, nextRecord);
|
|
30160
|
+
interrupted.push(nextRecord);
|
|
30161
|
+
}
|
|
30162
|
+
}
|
|
30163
|
+
return interrupted;
|
|
30164
|
+
}
|
|
30165
|
+
async function listDirectoryNames(dirPath) {
|
|
30166
|
+
return (await readdir$1(dirPath, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
30167
|
+
}
|
|
30168
|
+
async function listSynthesizerRunDirNames(rootDir) {
|
|
30169
|
+
const engineRunsDir = runsDirPath(rootDir);
|
|
30170
|
+
try {
|
|
30171
|
+
return await listDirectoryNames(engineRunsDir);
|
|
30172
|
+
} catch (error) {
|
|
30173
|
+
if (isNodeError(error) && error.code === "ENOENT") return [];
|
|
30174
|
+
throw error;
|
|
30175
|
+
}
|
|
30176
|
+
}
|
|
30177
|
+
async function readOptionalTextFile(filePath) {
|
|
30178
|
+
try {
|
|
30179
|
+
return await readFile(filePath, "utf8");
|
|
30180
|
+
} catch (error) {
|
|
30181
|
+
if (isNodeError(error) && error.code === "ENOENT") return null;
|
|
30182
|
+
throw error;
|
|
30183
|
+
}
|
|
30184
|
+
}
|
|
30185
|
+
function compareRunRecordEntries(left, right) {
|
|
30186
|
+
const timeCompare = Date.parse(right.record.started_at) - Date.parse(left.record.started_at);
|
|
30187
|
+
if (timeCompare !== 0) return timeCompare;
|
|
30188
|
+
return right.runId.localeCompare(left.runId);
|
|
30189
|
+
}
|
|
29907
30190
|
const synthesizerSpecFrontmatterSchema = strictObject({
|
|
29908
30191
|
description: string().optional(),
|
|
29909
30192
|
name: string().trim().min(1)
|
|
@@ -30461,12 +30744,15 @@ async function executeSynthesizerRun(input) {
|
|
|
30461
30744
|
const result = await input.executor.run(executorInput);
|
|
30462
30745
|
const completedAtMs = now().getTime();
|
|
30463
30746
|
const durationMs = Math.max(0, completedAtMs - startedAtMs);
|
|
30464
|
-
const status =
|
|
30747
|
+
const status = classifyOutcome(result.exitCode, result.observation);
|
|
30748
|
+
const rateLimitResetsAt = observedRateLimitResetsAt(result.observation);
|
|
30465
30749
|
return {
|
|
30466
30750
|
outcome: {
|
|
30467
30751
|
durationMs,
|
|
30468
30752
|
exitCode: result.exitCode,
|
|
30469
|
-
status
|
|
30753
|
+
status,
|
|
30754
|
+
...result.observation.result !== void 0 && { claudeResult: result.observation.result },
|
|
30755
|
+
...rateLimitResetsAt !== void 0 && { rateLimitResetsAt }
|
|
30470
30756
|
},
|
|
30471
30757
|
stderr: result.stderr
|
|
30472
30758
|
};
|
|
@@ -30482,11 +30768,19 @@ async function executeSynthesizerRun(input) {
|
|
|
30482
30768
|
};
|
|
30483
30769
|
}
|
|
30484
30770
|
}
|
|
30485
|
-
function
|
|
30771
|
+
function classifyOutcome(exitCode, observation) {
|
|
30486
30772
|
if (exitCode === 0) return "success";
|
|
30487
30773
|
if (exitCode === 124) return "timed_out";
|
|
30774
|
+
if (observation.result?.api_error_status === 429) return "rate_limited";
|
|
30775
|
+
if (observation.lastRateLimit?.status === "rejected") return "rate_limited";
|
|
30488
30776
|
return "failed";
|
|
30489
30777
|
}
|
|
30778
|
+
function observedRateLimitResetsAt(observation) {
|
|
30779
|
+
const rateLimit = observation.lastRateLimit;
|
|
30780
|
+
if (rateLimit === void 0) return void 0;
|
|
30781
|
+
if (rateLimit.status !== "rejected" || rateLimit.resetsAt === void 0) return;
|
|
30782
|
+
return msToIso(rateLimit.resetsAt * 1e3);
|
|
30783
|
+
}
|
|
30490
30784
|
function buildExecutorInput(input) {
|
|
30491
30785
|
return {
|
|
30492
30786
|
image: input.synthesizerImage,
|
|
@@ -30576,175 +30870,6 @@ function reconcileCursor(input) {
|
|
|
30576
30870
|
frontier: input.prevCursor.frontier
|
|
30577
30871
|
};
|
|
30578
30872
|
}
|
|
30579
|
-
const runTriggerSchema = _enum([
|
|
30580
|
-
"backfill",
|
|
30581
|
-
"daemon",
|
|
30582
|
-
"manual"
|
|
30583
|
-
]);
|
|
30584
|
-
_enum([
|
|
30585
|
-
"success",
|
|
30586
|
-
"failed",
|
|
30587
|
-
"timed_out"
|
|
30588
|
-
]);
|
|
30589
|
-
const runStatusSchema = _enum([
|
|
30590
|
-
"starting",
|
|
30591
|
-
"running",
|
|
30592
|
-
"success",
|
|
30593
|
-
"failed",
|
|
30594
|
-
"timed_out",
|
|
30595
|
-
"interrupted"
|
|
30596
|
-
]);
|
|
30597
|
-
const runRecordSchema = strictObject({
|
|
30598
|
-
completed_at: string().min(1).optional(),
|
|
30599
|
-
duration_ms: number().int().nonnegative().optional(),
|
|
30600
|
-
exit_code: number().int().optional(),
|
|
30601
|
-
run_id: string().min(1),
|
|
30602
|
-
started_at: string().min(1),
|
|
30603
|
-
status: runStatusSchema,
|
|
30604
|
-
synthesizer: string().min(1),
|
|
30605
|
-
triggered_by: runTriggerSchema
|
|
30606
|
-
});
|
|
30607
|
-
const RECORD_FILE_NAME = "record.json";
|
|
30608
|
-
const STDERR_FILE_NAME = "stderr";
|
|
30609
|
-
function buildStartingRunRecord(input) {
|
|
30610
|
-
return {
|
|
30611
|
-
run_id: input.runId,
|
|
30612
|
-
started_at: input.startedAt,
|
|
30613
|
-
status: "starting",
|
|
30614
|
-
synthesizer: input.synthesizerName,
|
|
30615
|
-
triggered_by: input.trigger
|
|
30616
|
-
};
|
|
30617
|
-
}
|
|
30618
|
-
function buildRunningRunRecord(record) {
|
|
30619
|
-
return {
|
|
30620
|
-
...record,
|
|
30621
|
-
status: "running"
|
|
30622
|
-
};
|
|
30623
|
-
}
|
|
30624
|
-
function buildTerminalRunRecord(input) {
|
|
30625
|
-
return {
|
|
30626
|
-
completed_at: input.completedAt,
|
|
30627
|
-
duration_ms: input.durationMs,
|
|
30628
|
-
exit_code: input.exitCode,
|
|
30629
|
-
run_id: input.runId,
|
|
30630
|
-
started_at: input.startedAt,
|
|
30631
|
-
status: input.status,
|
|
30632
|
-
synthesizer: input.synthesizerName,
|
|
30633
|
-
triggered_by: input.trigger
|
|
30634
|
-
};
|
|
30635
|
-
}
|
|
30636
|
-
function buildInterruptedRunRecord(record, completedAt) {
|
|
30637
|
-
return {
|
|
30638
|
-
...record,
|
|
30639
|
-
completed_at: completedAt,
|
|
30640
|
-
status: "interrupted"
|
|
30641
|
-
};
|
|
30642
|
-
}
|
|
30643
|
-
function getRunDir(input) {
|
|
30644
|
-
return runDirPath(input.rootDir, input.synthesizerName, input.runId);
|
|
30645
|
-
}
|
|
30646
|
-
async function ensureRunDir(input) {
|
|
30647
|
-
const runDir = getRunDir(input);
|
|
30648
|
-
await mkdir(runDir, { recursive: true });
|
|
30649
|
-
return runDir;
|
|
30650
|
-
}
|
|
30651
|
-
async function writeRunRecord(runDir, record) {
|
|
30652
|
-
await mkdir(runDir, { recursive: true });
|
|
30653
|
-
await writeJsonFileAtomic(path.join(runDir, RECORD_FILE_NAME), runRecordSchema.parse(record));
|
|
30654
|
-
}
|
|
30655
|
-
async function readRunRecord(runDir) {
|
|
30656
|
-
const raw = await readFile(path.join(runDir, RECORD_FILE_NAME), "utf8");
|
|
30657
|
-
return runRecordSchema.parse(JSON.parse(raw));
|
|
30658
|
-
}
|
|
30659
|
-
async function listRunRecords(input) {
|
|
30660
|
-
const synthesizerNames = input.synthesizerName !== void 0 ? [input.synthesizerName] : await listSynthesizerRunDirNames(input.rootDir);
|
|
30661
|
-
const entries = [];
|
|
30662
|
-
for (const synthesizerName of synthesizerNames) {
|
|
30663
|
-
const synthesizerDir = synthesizerRunsDirPath(input.rootDir, synthesizerName);
|
|
30664
|
-
let runIds;
|
|
30665
|
-
try {
|
|
30666
|
-
runIds = await listDirectoryNames(synthesizerDir);
|
|
30667
|
-
} catch (error) {
|
|
30668
|
-
if (isNodeError(error) && error.code === "ENOENT") continue;
|
|
30669
|
-
throw error;
|
|
30670
|
-
}
|
|
30671
|
-
for (const runId of runIds) {
|
|
30672
|
-
const runDir = path.join(synthesizerDir, runId);
|
|
30673
|
-
try {
|
|
30674
|
-
entries.push({
|
|
30675
|
-
record: await readRunRecord(runDir),
|
|
30676
|
-
runDir,
|
|
30677
|
-
runId
|
|
30678
|
-
});
|
|
30679
|
-
} catch (error) {
|
|
30680
|
-
if (isNodeError(error) && error.code === "ENOENT") continue;
|
|
30681
|
-
throw error;
|
|
30682
|
-
}
|
|
30683
|
-
}
|
|
30684
|
-
}
|
|
30685
|
-
return entries.sort(compareRunRecordEntries);
|
|
30686
|
-
}
|
|
30687
|
-
async function readRunStderr(runDir) {
|
|
30688
|
-
return await readOptionalTextFile(path.join(runDir, STDERR_FILE_NAME));
|
|
30689
|
-
}
|
|
30690
|
-
async function writeRunStderr(input) {
|
|
30691
|
-
await mkdir(input.runDir, { recursive: true });
|
|
30692
|
-
await writeFileAtomic(path.join(input.runDir, STDERR_FILE_NAME), input.stderr);
|
|
30693
|
-
}
|
|
30694
|
-
async function markInterruptedRuns(rootDir) {
|
|
30695
|
-
const interrupted = [];
|
|
30696
|
-
const engineRunsDir = runsDirPath(rootDir);
|
|
30697
|
-
let synthesizerDirs;
|
|
30698
|
-
try {
|
|
30699
|
-
synthesizerDirs = await listDirectoryNames(engineRunsDir);
|
|
30700
|
-
} catch (error) {
|
|
30701
|
-
if (isNodeError(error) && error.code === "ENOENT") return [];
|
|
30702
|
-
throw error;
|
|
30703
|
-
}
|
|
30704
|
-
for (const synthesizerName of synthesizerDirs) {
|
|
30705
|
-
const synthesizerDir = path.join(engineRunsDir, synthesizerName);
|
|
30706
|
-
for (const runId of await listDirectoryNames(synthesizerDir)) {
|
|
30707
|
-
const runDir = path.join(synthesizerDir, runId);
|
|
30708
|
-
let record;
|
|
30709
|
-
try {
|
|
30710
|
-
record = await readRunRecord(runDir);
|
|
30711
|
-
} catch (error) {
|
|
30712
|
-
if (isNodeError(error) && error.code === "ENOENT") continue;
|
|
30713
|
-
throw error;
|
|
30714
|
-
}
|
|
30715
|
-
if (record.status !== "starting" && record.status !== "running") continue;
|
|
30716
|
-
const nextRecord = buildInterruptedRunRecord(record, (/* @__PURE__ */ new Date()).toISOString());
|
|
30717
|
-
await writeRunRecord(runDir, nextRecord);
|
|
30718
|
-
interrupted.push(nextRecord);
|
|
30719
|
-
}
|
|
30720
|
-
}
|
|
30721
|
-
return interrupted;
|
|
30722
|
-
}
|
|
30723
|
-
async function listDirectoryNames(dirPath) {
|
|
30724
|
-
return (await readdir$1(dirPath, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
30725
|
-
}
|
|
30726
|
-
async function listSynthesizerRunDirNames(rootDir) {
|
|
30727
|
-
const engineRunsDir = runsDirPath(rootDir);
|
|
30728
|
-
try {
|
|
30729
|
-
return await listDirectoryNames(engineRunsDir);
|
|
30730
|
-
} catch (error) {
|
|
30731
|
-
if (isNodeError(error) && error.code === "ENOENT") return [];
|
|
30732
|
-
throw error;
|
|
30733
|
-
}
|
|
30734
|
-
}
|
|
30735
|
-
async function readOptionalTextFile(filePath) {
|
|
30736
|
-
try {
|
|
30737
|
-
return await readFile(filePath, "utf8");
|
|
30738
|
-
} catch (error) {
|
|
30739
|
-
if (isNodeError(error) && error.code === "ENOENT") return null;
|
|
30740
|
-
throw error;
|
|
30741
|
-
}
|
|
30742
|
-
}
|
|
30743
|
-
function compareRunRecordEntries(left, right) {
|
|
30744
|
-
const timeCompare = Date.parse(right.record.started_at) - Date.parse(left.record.started_at);
|
|
30745
|
-
if (timeCompare !== 0) return timeCompare;
|
|
30746
|
-
return right.runId.localeCompare(left.runId);
|
|
30747
|
-
}
|
|
30748
30873
|
function renderSliceJson(slice) {
|
|
30749
30874
|
const windows = {};
|
|
30750
30875
|
for (const [table, window] of Object.entries(slice)) windows[table] = {
|
|
@@ -30859,9 +30984,11 @@ async function finalizeFailedSynthesizerTransaction(input) {
|
|
|
30859
30984
|
function buildTerminalRecord(input) {
|
|
30860
30985
|
const { ctx, runResult, completedAt } = input;
|
|
30861
30986
|
return buildTerminalRunRecord({
|
|
30987
|
+
...runResult.outcome.claudeResult !== void 0 && { claudeResult: runResult.outcome.claudeResult },
|
|
30862
30988
|
completedAt,
|
|
30863
30989
|
durationMs: runResult.outcome.durationMs,
|
|
30864
30990
|
exitCode: runResult.outcome.exitCode,
|
|
30991
|
+
...runResult.outcome.rateLimitResetsAt !== void 0 && { rateLimitResetsAt: runResult.outcome.rateLimitResetsAt },
|
|
30865
30992
|
runId: ctx.runId,
|
|
30866
30993
|
startedAt: ctx.startedAt,
|
|
30867
30994
|
status: runResult.outcome.status,
|
|
@@ -30985,10 +31112,14 @@ var Engine = class {
|
|
|
30985
31112
|
listSynthesizers: async () => {
|
|
30986
31113
|
await this.refreshSynthesizers();
|
|
30987
31114
|
const specs = this.listSynthesizers().filter((spec) => options.scopeTo === void 0 || spec.name === options.scopeTo);
|
|
30988
|
-
return Promise.all(specs.map(async (spec) =>
|
|
30989
|
-
|
|
30990
|
-
|
|
30991
|
-
|
|
31115
|
+
return Promise.all(specs.map(async (spec) => {
|
|
31116
|
+
const notBefore = await this.readRateLimitGate(spec.name, clock().getTime());
|
|
31117
|
+
return {
|
|
31118
|
+
frontier: (await readCursor(rootDir, spec.name))?.frontier ?? 0,
|
|
31119
|
+
name: spec.name,
|
|
31120
|
+
...notBefore !== void 0 && { notBefore }
|
|
31121
|
+
};
|
|
31122
|
+
}));
|
|
30992
31123
|
},
|
|
30993
31124
|
now: () => clock().getTime(),
|
|
30994
31125
|
runSlice: async (name) => {
|
|
@@ -30999,11 +31130,17 @@ var Engine = class {
|
|
|
30999
31130
|
});
|
|
31000
31131
|
options.onSlice?.(outcome);
|
|
31001
31132
|
this.logSliceLag(name, outcome);
|
|
31002
|
-
return {
|
|
31133
|
+
return {
|
|
31134
|
+
advanced: outcome.record.status === "success",
|
|
31135
|
+
rateLimited: outcome.record.status === "rate_limited"
|
|
31136
|
+
};
|
|
31003
31137
|
} catch (error) {
|
|
31004
31138
|
if (error instanceof TransactionLockHeldError) {
|
|
31005
31139
|
this.logger.warn(`[engine] skipping '${name}': ${error.message}`);
|
|
31006
|
-
return {
|
|
31140
|
+
return {
|
|
31141
|
+
advanced: false,
|
|
31142
|
+
rateLimited: false
|
|
31143
|
+
};
|
|
31007
31144
|
}
|
|
31008
31145
|
throw error;
|
|
31009
31146
|
}
|
|
@@ -31011,6 +31148,18 @@ var Engine = class {
|
|
|
31011
31148
|
sleep: (ms) => sleepAbortable(ms, options.signal)
|
|
31012
31149
|
};
|
|
31013
31150
|
}
|
|
31151
|
+
async readRateLimitGate(synthesizerName, nowMs) {
|
|
31152
|
+
const latest = (await listRunRecords({
|
|
31153
|
+
rootDir: this.repo.rootDir,
|
|
31154
|
+
synthesizerName
|
|
31155
|
+
}))[0]?.record;
|
|
31156
|
+
if (latest?.status !== "rate_limited") return void 0;
|
|
31157
|
+
if (latest.rate_limit_resets_at === void 0) return void 0;
|
|
31158
|
+
const resetsAt = isoToMs(latest.rate_limit_resets_at, "rate_limit_resets_at");
|
|
31159
|
+
if (resetsAt <= nowMs) return void 0;
|
|
31160
|
+
this.logger.info(`[engine] '${synthesizerName}' rate limited — usage window resets ${latest.rate_limit_resets_at}; holding runs until then`);
|
|
31161
|
+
return resetsAt;
|
|
31162
|
+
}
|
|
31014
31163
|
logSliceLag(name, outcome) {
|
|
31015
31164
|
if (outcome.record.status !== "success") {
|
|
31016
31165
|
this.logger.warn(`[engine] '${name}' slice did not advance (status=${outcome.record.status})`);
|
|
@@ -31152,12 +31301,131 @@ function latestRunByName(entries) {
|
|
|
31152
31301
|
for (const { record } of entries) if (!latest.has(record.synthesizer)) latest.set(record.synthesizer, record);
|
|
31153
31302
|
return latest;
|
|
31154
31303
|
}
|
|
31304
|
+
const rateLimitEventSchema = object({
|
|
31305
|
+
rate_limit_info: object({
|
|
31306
|
+
resetsAt: number().optional(),
|
|
31307
|
+
status: string().min(1)
|
|
31308
|
+
}),
|
|
31309
|
+
type: literal("rate_limit_event")
|
|
31310
|
+
});
|
|
31311
|
+
const resultEventSchema = object({
|
|
31312
|
+
...claudeResultSchema.shape,
|
|
31313
|
+
type: literal("result")
|
|
31314
|
+
});
|
|
31315
|
+
var ClaudeStreamObserver = class {
|
|
31316
|
+
decoder = new TextDecoder("utf-8", { fatal: false });
|
|
31317
|
+
pendingLine = "";
|
|
31318
|
+
lastRateLimit;
|
|
31319
|
+
result;
|
|
31320
|
+
feed(chunk) {
|
|
31321
|
+
this.pendingLine += this.decoder.decode(chunk, { stream: true });
|
|
31322
|
+
for (;;) {
|
|
31323
|
+
const newlineAt = this.pendingLine.indexOf("\n");
|
|
31324
|
+
if (newlineAt === -1) return;
|
|
31325
|
+
const line = this.pendingLine.slice(0, newlineAt);
|
|
31326
|
+
this.pendingLine = this.pendingLine.slice(newlineAt + 1);
|
|
31327
|
+
this.observeLine(line);
|
|
31328
|
+
}
|
|
31329
|
+
}
|
|
31330
|
+
get resultSeen() {
|
|
31331
|
+
return this.result !== void 0;
|
|
31332
|
+
}
|
|
31333
|
+
observation() {
|
|
31334
|
+
const trailing = this.pendingLine + this.decoder.decode();
|
|
31335
|
+
this.pendingLine = "";
|
|
31336
|
+
if (trailing.length > 0) this.observeLine(trailing);
|
|
31337
|
+
return {
|
|
31338
|
+
...this.lastRateLimit !== void 0 && { lastRateLimit: this.lastRateLimit },
|
|
31339
|
+
...this.result !== void 0 && { result: this.result }
|
|
31340
|
+
};
|
|
31341
|
+
}
|
|
31342
|
+
observeLine(line) {
|
|
31343
|
+
if (line.trim().length === 0) return;
|
|
31344
|
+
let event;
|
|
31345
|
+
try {
|
|
31346
|
+
event = JSON.parse(line);
|
|
31347
|
+
} catch {
|
|
31348
|
+
return;
|
|
31349
|
+
}
|
|
31350
|
+
const rateLimit = rateLimitEventSchema.safeParse(event);
|
|
31351
|
+
if (rateLimit.success) {
|
|
31352
|
+
const { status, resetsAt } = rateLimit.data.rate_limit_info;
|
|
31353
|
+
this.lastRateLimit = {
|
|
31354
|
+
status,
|
|
31355
|
+
...resetsAt !== void 0 && { resetsAt }
|
|
31356
|
+
};
|
|
31357
|
+
return;
|
|
31358
|
+
}
|
|
31359
|
+
const result = resultEventSchema.safeParse(event);
|
|
31360
|
+
if (result.success) {
|
|
31361
|
+
const { type: _type, ...fields } = result.data;
|
|
31362
|
+
this.result = fields;
|
|
31363
|
+
}
|
|
31364
|
+
}
|
|
31365
|
+
};
|
|
31366
|
+
const GUEST_MEMORY_MIB = 2048;
|
|
31367
|
+
const EXEC_INACTIVITY_TIMEOUT_MS = 600 * 1e3;
|
|
31368
|
+
const EXEC_MAX_DURATION_MS = 7200 * 1e3;
|
|
31369
|
+
const EXEC_RESULT_GRACE_MS = 60 * 1e3;
|
|
31370
|
+
const DRAIN_TIMED_OUT = Symbol("drain-timed-out");
|
|
31371
|
+
async function drainExecStream(handle, options) {
|
|
31372
|
+
const observer = new ClaudeStreamObserver();
|
|
31373
|
+
const startedAt = Date.now();
|
|
31374
|
+
let lastEventAt = startedAt;
|
|
31375
|
+
let resultSeenAt;
|
|
31376
|
+
for (;;) {
|
|
31377
|
+
const ceilingDeadline = startedAt + options.maxDurationMs;
|
|
31378
|
+
const inactivityDeadline = lastEventAt + options.inactivityMs;
|
|
31379
|
+
const graceDeadline = resultSeenAt === void 0 ? Number.POSITIVE_INFINITY : resultSeenAt + options.resultGraceMs;
|
|
31380
|
+
const deadline = Math.min(ceilingDeadline, inactivityDeadline, graceDeadline);
|
|
31381
|
+
let timer;
|
|
31382
|
+
const timedOut = new Promise((resolve) => {
|
|
31383
|
+
timer = setTimeout(() => resolve(DRAIN_TIMED_OUT), Math.max(0, deadline - Date.now()));
|
|
31384
|
+
});
|
|
31385
|
+
const pending = handle.recv();
|
|
31386
|
+
let settled;
|
|
31387
|
+
try {
|
|
31388
|
+
settled = await Promise.race([pending, timedOut]);
|
|
31389
|
+
} finally {
|
|
31390
|
+
clearTimeout(timer);
|
|
31391
|
+
}
|
|
31392
|
+
if (settled === DRAIN_TIMED_OUT) {
|
|
31393
|
+
pending.catch(() => {});
|
|
31394
|
+
const observation = observer.observation();
|
|
31395
|
+
if (observation.result !== void 0) return {
|
|
31396
|
+
kind: "result_no_exit",
|
|
31397
|
+
observation,
|
|
31398
|
+
result: observation.result
|
|
31399
|
+
};
|
|
31400
|
+
return {
|
|
31401
|
+
kind: "timed_out",
|
|
31402
|
+
observation,
|
|
31403
|
+
reason: ceilingDeadline <= inactivityDeadline ? "max_duration" : "inactivity"
|
|
31404
|
+
};
|
|
31405
|
+
}
|
|
31406
|
+
if (settled === null) return {
|
|
31407
|
+
kind: "ended",
|
|
31408
|
+
observation: observer.observation()
|
|
31409
|
+
};
|
|
31410
|
+
lastEventAt = Date.now();
|
|
31411
|
+
if (settled.kind === "stderr") options.onStderr(settled.data);
|
|
31412
|
+
else if (settled.kind === "stdout") {
|
|
31413
|
+
observer.feed(settled.data);
|
|
31414
|
+
if (resultSeenAt === void 0 && observer.resultSeen) resultSeenAt = lastEventAt;
|
|
31415
|
+
} else if (settled.kind === "exited") return {
|
|
31416
|
+
exitCode: settled.code,
|
|
31417
|
+
kind: "exited",
|
|
31418
|
+
observation: observer.observation()
|
|
31419
|
+
};
|
|
31420
|
+
}
|
|
31421
|
+
}
|
|
31155
31422
|
var MicrosandboxClaudeExecutor = class {
|
|
31156
31423
|
async run(input) {
|
|
31157
31424
|
const microsandbox = await import("microsandbox");
|
|
31158
31425
|
const runPlan = buildMicrosandboxClaudeRunPlan(input);
|
|
31159
31426
|
const stderrParts = [];
|
|
31160
31427
|
let exitCode = 1;
|
|
31428
|
+
let observation = {};
|
|
31161
31429
|
let sandbox = null;
|
|
31162
31430
|
let authMaterial = null;
|
|
31163
31431
|
try {
|
|
@@ -31174,25 +31442,32 @@ var MicrosandboxClaudeExecutor = class {
|
|
|
31174
31442
|
synthesizerBody: input.synthesizerBody
|
|
31175
31443
|
});
|
|
31176
31444
|
await ensureHostFilesystemReady(fsPlan);
|
|
31177
|
-
let builder = microsandbox.Sandbox.builder(runPlan.sandboxName).image(runPlan.image).replace();
|
|
31445
|
+
let builder = microsandbox.Sandbox.builder(runPlan.sandboxName).image(runPlan.image).memory(GUEST_MEMORY_MIB).replace();
|
|
31178
31446
|
builder = applyUserMicrosandboxConfig(builder, runPlan.microsandboxConfig, stderrParts);
|
|
31179
31447
|
builder = applySandboxFilesystemPlan(builder, fsPlan);
|
|
31180
31448
|
sandbox = await builder.create();
|
|
31181
31449
|
const [cmd, ...args] = runPlan.command;
|
|
31182
31450
|
const stderrDecoder = new TextDecoder("utf-8", { fatal: false });
|
|
31183
31451
|
try {
|
|
31184
|
-
const
|
|
31185
|
-
|
|
31186
|
-
|
|
31452
|
+
const drained = await drainExecStream(await sandbox.execStreamWith(cmd, (e) => e.args(args)), {
|
|
31453
|
+
inactivityMs: EXEC_INACTIVITY_TIMEOUT_MS,
|
|
31454
|
+
maxDurationMs: EXEC_MAX_DURATION_MS,
|
|
31455
|
+
onStderr: (data) => stderrParts.push(stderrDecoder.decode(data, { stream: true })),
|
|
31456
|
+
resultGraceMs: EXEC_RESULT_GRACE_MS
|
|
31457
|
+
});
|
|
31187
31458
|
stderrParts.push(stderrDecoder.decode());
|
|
31188
|
-
|
|
31189
|
-
if (
|
|
31459
|
+
observation = drained.observation;
|
|
31460
|
+
if (drained.kind === "exited") exitCode = drained.exitCode;
|
|
31461
|
+
else if (drained.kind === "result_no_exit") {
|
|
31462
|
+
exitCode = drained.result.is_error ? 1 : 0;
|
|
31463
|
+
stderrParts.push(`claude emitted its terminal result (is_error: ${drained.result.is_error}) but never exited within ${EXEC_RESULT_GRACE_MS / 1e3}s; concluding the run from the result event and tearing the sandbox down\n`);
|
|
31464
|
+
} else if (drained.kind === "timed_out") {
|
|
31190
31465
|
exitCode = 124;
|
|
31191
|
-
stderrParts.push(`exec timed out: ${
|
|
31192
|
-
} else {
|
|
31193
|
-
exitCode = 1;
|
|
31194
|
-
stderrParts.push(`exec failed: ${formatError(error)}`);
|
|
31466
|
+
stderrParts.push(drained.reason === "inactivity" ? `exec stream timed out: no events for ${EXEC_INACTIVITY_TIMEOUT_MS / 6e4} minutes; abandoning the run and tearing the sandbox down\n` : `exec stream timed out: run exceeded the ${EXEC_MAX_DURATION_MS / 6e4}-minute ceiling; abandoning the run and tearing the sandbox down\n`);
|
|
31195
31467
|
}
|
|
31468
|
+
} catch (error) {
|
|
31469
|
+
exitCode = 1;
|
|
31470
|
+
stderrParts.push(`exec failed: ${formatError(error)}`);
|
|
31196
31471
|
}
|
|
31197
31472
|
} catch (error) {
|
|
31198
31473
|
exitCode = 1;
|
|
@@ -31214,6 +31489,7 @@ var MicrosandboxClaudeExecutor = class {
|
|
|
31214
31489
|
}
|
|
31215
31490
|
return {
|
|
31216
31491
|
exitCode,
|
|
31492
|
+
observation,
|
|
31217
31493
|
stderr: stderrParts.join("")
|
|
31218
31494
|
};
|
|
31219
31495
|
}
|
|
@@ -31550,7 +31826,7 @@ async function runBackfillCommand(input) {
|
|
|
31550
31826
|
...summary,
|
|
31551
31827
|
finalFrontier: summary.finalFrontier === null ? null : msToIso(summary.finalFrontier)
|
|
31552
31828
|
})}\n`);
|
|
31553
|
-
if (summary.stopReason === "stalled") process.exitCode = 1;
|
|
31829
|
+
if (summary.stopReason === "stalled" || summary.stopReason === "rate_limited") process.exitCode = 1;
|
|
31554
31830
|
}
|
|
31555
31831
|
|
|
31556
31832
|
//#endregion
|
|
@@ -31743,4 +32019,4 @@ runCli().catch((error) => {
|
|
|
31743
32019
|
//#endregion
|
|
31744
32020
|
export { createProgram, resolveRepoContext, resolveRuntimePaths, runCli };
|
|
31745
32021
|
//# sourceMappingURL=cli.mjs.map
|
|
31746
|
-
//# debugId=
|
|
32022
|
+
//# debugId=1a858cd0-cb9a-550b-a3f9-5ca9387cf7df
|