@usecontextlayer/ctxe 0.4.3 → 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 +430 -194
- 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,17 +31301,83 @@ 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
|
+
};
|
|
31155
31366
|
const GUEST_MEMORY_MIB = 2048;
|
|
31156
31367
|
const EXEC_INACTIVITY_TIMEOUT_MS = 600 * 1e3;
|
|
31157
31368
|
const EXEC_MAX_DURATION_MS = 7200 * 1e3;
|
|
31369
|
+
const EXEC_RESULT_GRACE_MS = 60 * 1e3;
|
|
31158
31370
|
const DRAIN_TIMED_OUT = Symbol("drain-timed-out");
|
|
31159
31371
|
async function drainExecStream(handle, options) {
|
|
31372
|
+
const observer = new ClaudeStreamObserver();
|
|
31160
31373
|
const startedAt = Date.now();
|
|
31161
31374
|
let lastEventAt = startedAt;
|
|
31375
|
+
let resultSeenAt;
|
|
31162
31376
|
for (;;) {
|
|
31163
31377
|
const ceilingDeadline = startedAt + options.maxDurationMs;
|
|
31164
31378
|
const inactivityDeadline = lastEventAt + options.inactivityMs;
|
|
31165
|
-
const
|
|
31379
|
+
const graceDeadline = resultSeenAt === void 0 ? Number.POSITIVE_INFINITY : resultSeenAt + options.resultGraceMs;
|
|
31380
|
+
const deadline = Math.min(ceilingDeadline, inactivityDeadline, graceDeadline);
|
|
31166
31381
|
let timer;
|
|
31167
31382
|
const timedOut = new Promise((resolve) => {
|
|
31168
31383
|
timer = setTimeout(() => resolve(DRAIN_TIMED_OUT), Math.max(0, deadline - Date.now()));
|
|
@@ -31176,17 +31391,31 @@ async function drainExecStream(handle, options) {
|
|
|
31176
31391
|
}
|
|
31177
31392
|
if (settled === DRAIN_TIMED_OUT) {
|
|
31178
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
|
+
};
|
|
31179
31400
|
return {
|
|
31180
31401
|
kind: "timed_out",
|
|
31402
|
+
observation,
|
|
31181
31403
|
reason: ceilingDeadline <= inactivityDeadline ? "max_duration" : "inactivity"
|
|
31182
31404
|
};
|
|
31183
31405
|
}
|
|
31184
|
-
if (settled === null) return {
|
|
31406
|
+
if (settled === null) return {
|
|
31407
|
+
kind: "ended",
|
|
31408
|
+
observation: observer.observation()
|
|
31409
|
+
};
|
|
31185
31410
|
lastEventAt = Date.now();
|
|
31186
31411
|
if (settled.kind === "stderr") options.onStderr(settled.data);
|
|
31187
|
-
else if (settled.kind === "
|
|
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 {
|
|
31188
31416
|
exitCode: settled.code,
|
|
31189
|
-
kind: "exited"
|
|
31417
|
+
kind: "exited",
|
|
31418
|
+
observation: observer.observation()
|
|
31190
31419
|
};
|
|
31191
31420
|
}
|
|
31192
31421
|
}
|
|
@@ -31196,6 +31425,7 @@ var MicrosandboxClaudeExecutor = class {
|
|
|
31196
31425
|
const runPlan = buildMicrosandboxClaudeRunPlan(input);
|
|
31197
31426
|
const stderrParts = [];
|
|
31198
31427
|
let exitCode = 1;
|
|
31428
|
+
let observation = {};
|
|
31199
31429
|
let sandbox = null;
|
|
31200
31430
|
let authMaterial = null;
|
|
31201
31431
|
try {
|
|
@@ -31222,11 +31452,16 @@ var MicrosandboxClaudeExecutor = class {
|
|
|
31222
31452
|
const drained = await drainExecStream(await sandbox.execStreamWith(cmd, (e) => e.args(args)), {
|
|
31223
31453
|
inactivityMs: EXEC_INACTIVITY_TIMEOUT_MS,
|
|
31224
31454
|
maxDurationMs: EXEC_MAX_DURATION_MS,
|
|
31225
|
-
onStderr: (data) => stderrParts.push(stderrDecoder.decode(data, { stream: true }))
|
|
31455
|
+
onStderr: (data) => stderrParts.push(stderrDecoder.decode(data, { stream: true })),
|
|
31456
|
+
resultGraceMs: EXEC_RESULT_GRACE_MS
|
|
31226
31457
|
});
|
|
31227
31458
|
stderrParts.push(stderrDecoder.decode());
|
|
31459
|
+
observation = drained.observation;
|
|
31228
31460
|
if (drained.kind === "exited") exitCode = drained.exitCode;
|
|
31229
|
-
else if (drained.kind === "
|
|
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") {
|
|
31230
31465
|
exitCode = 124;
|
|
31231
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`);
|
|
31232
31467
|
}
|
|
@@ -31254,6 +31489,7 @@ var MicrosandboxClaudeExecutor = class {
|
|
|
31254
31489
|
}
|
|
31255
31490
|
return {
|
|
31256
31491
|
exitCode,
|
|
31492
|
+
observation,
|
|
31257
31493
|
stderr: stderrParts.join("")
|
|
31258
31494
|
};
|
|
31259
31495
|
}
|
|
@@ -31590,7 +31826,7 @@ async function runBackfillCommand(input) {
|
|
|
31590
31826
|
...summary,
|
|
31591
31827
|
finalFrontier: summary.finalFrontier === null ? null : msToIso(summary.finalFrontier)
|
|
31592
31828
|
})}\n`);
|
|
31593
|
-
if (summary.stopReason === "stalled") process.exitCode = 1;
|
|
31829
|
+
if (summary.stopReason === "stalled" || summary.stopReason === "rate_limited") process.exitCode = 1;
|
|
31594
31830
|
}
|
|
31595
31831
|
|
|
31596
31832
|
//#endregion
|
|
@@ -31783,4 +32019,4 @@ runCli().catch((error) => {
|
|
|
31783
32019
|
//#endregion
|
|
31784
32020
|
export { createProgram, resolveRepoContext, resolveRuntimePaths, runCli };
|
|
31785
32021
|
//# sourceMappingURL=cli.mjs.map
|
|
31786
|
-
//# debugId=
|
|
32022
|
+
//# debugId=1a858cd0-cb9a-550b-a3f9-5ca9387cf7df
|