@usecontextlayer/ctxe 0.4.3 → 0.4.6
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 +941 -362
- 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]="ee0e5987-2fbc-50ed-9038-a0c4541b7548")}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.6";
|
|
63
63
|
|
|
64
64
|
//#endregion
|
|
65
65
|
//#region sentry.ts
|
|
@@ -7894,7 +7894,8 @@ const string$1 = (params) => {
|
|
|
7894
7894
|
return new RegExp(`^${regex}$`);
|
|
7895
7895
|
};
|
|
7896
7896
|
const integer = /^-?\d+$/;
|
|
7897
|
-
const number$
|
|
7897
|
+
const number$2 = /^-?\d+(?:\.\d+)?$/;
|
|
7898
|
+
const boolean$1 = /^(?:true|false)$/i;
|
|
7898
7899
|
const lowercase = /^[^A-Z]*$/;
|
|
7899
7900
|
const uppercase = /^[^a-z]*$/;
|
|
7900
7901
|
|
|
@@ -8671,7 +8672,7 @@ const $ZodJWT = /*@__PURE__*/ $constructor("$ZodJWT", (inst, def) => {
|
|
|
8671
8672
|
});
|
|
8672
8673
|
const $ZodNumber = /*@__PURE__*/ $constructor("$ZodNumber", (inst, def) => {
|
|
8673
8674
|
$ZodType.init(inst, def);
|
|
8674
|
-
inst._zod.pattern = inst._zod.bag.pattern ?? number$
|
|
8675
|
+
inst._zod.pattern = inst._zod.bag.pattern ?? number$2;
|
|
8675
8676
|
inst._zod.parse = (payload, _ctx) => {
|
|
8676
8677
|
if (def.coerce) try {
|
|
8677
8678
|
payload.value = Number(payload.value);
|
|
@@ -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;
|
|
@@ -9038,6 +9057,62 @@ const $ZodUnion = /*@__PURE__*/ $constructor("$ZodUnion", (inst, def) => {
|
|
|
9038
9057
|
});
|
|
9039
9058
|
};
|
|
9040
9059
|
});
|
|
9060
|
+
const $ZodDiscriminatedUnion = /*@__PURE__*/ $constructor("$ZodDiscriminatedUnion", (inst, def) => {
|
|
9061
|
+
def.inclusive = false;
|
|
9062
|
+
$ZodUnion.init(inst, def);
|
|
9063
|
+
const _super = inst._zod.parse;
|
|
9064
|
+
defineLazy(inst._zod, "propValues", () => {
|
|
9065
|
+
const propValues = {};
|
|
9066
|
+
for (const option of def.options) {
|
|
9067
|
+
const pv = option._zod.propValues;
|
|
9068
|
+
if (!pv || Object.keys(pv).length === 0) throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(option)}"`);
|
|
9069
|
+
for (const [k, v] of Object.entries(pv)) {
|
|
9070
|
+
if (!propValues[k]) propValues[k] = /* @__PURE__ */ new Set();
|
|
9071
|
+
for (const val of v) propValues[k].add(val);
|
|
9072
|
+
}
|
|
9073
|
+
}
|
|
9074
|
+
return propValues;
|
|
9075
|
+
});
|
|
9076
|
+
const disc = cached(() => {
|
|
9077
|
+
const opts = def.options;
|
|
9078
|
+
const map = /* @__PURE__ */ new Map();
|
|
9079
|
+
for (const o of opts) {
|
|
9080
|
+
const values = o._zod.propValues?.[def.discriminator];
|
|
9081
|
+
if (!values || values.size === 0) throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(o)}"`);
|
|
9082
|
+
for (const v of values) {
|
|
9083
|
+
if (map.has(v)) throw new Error(`Duplicate discriminator value "${String(v)}"`);
|
|
9084
|
+
map.set(v, o);
|
|
9085
|
+
}
|
|
9086
|
+
}
|
|
9087
|
+
return map;
|
|
9088
|
+
});
|
|
9089
|
+
inst._zod.parse = (payload, ctx) => {
|
|
9090
|
+
const input = payload.value;
|
|
9091
|
+
if (!isObject$1(input)) {
|
|
9092
|
+
payload.issues.push({
|
|
9093
|
+
code: "invalid_type",
|
|
9094
|
+
expected: "object",
|
|
9095
|
+
input,
|
|
9096
|
+
inst
|
|
9097
|
+
});
|
|
9098
|
+
return payload;
|
|
9099
|
+
}
|
|
9100
|
+
const opt = disc.value.get(input?.[def.discriminator]);
|
|
9101
|
+
if (opt) return opt._zod.run(payload, ctx);
|
|
9102
|
+
if (def.unionFallback || ctx.direction === "backward") return _super(payload, ctx);
|
|
9103
|
+
payload.issues.push({
|
|
9104
|
+
code: "invalid_union",
|
|
9105
|
+
errors: [],
|
|
9106
|
+
note: "No matching discriminator",
|
|
9107
|
+
discriminator: def.discriminator,
|
|
9108
|
+
options: Array.from(disc.value.keys()),
|
|
9109
|
+
input,
|
|
9110
|
+
path: [def.discriminator],
|
|
9111
|
+
inst
|
|
9112
|
+
});
|
|
9113
|
+
return payload;
|
|
9114
|
+
};
|
|
9115
|
+
});
|
|
9041
9116
|
const $ZodIntersection = /*@__PURE__*/ $constructor("$ZodIntersection", (inst, def) => {
|
|
9042
9117
|
$ZodType.init(inst, def);
|
|
9043
9118
|
inst._zod.parse = (payload, ctx) => {
|
|
@@ -9208,7 +9283,7 @@ const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => {
|
|
|
9208
9283
|
issues: []
|
|
9209
9284
|
}, ctx);
|
|
9210
9285
|
if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently");
|
|
9211
|
-
if (typeof key === "string" && number$
|
|
9286
|
+
if (typeof key === "string" && number$2.test(key) && keyResult.issues.length) {
|
|
9212
9287
|
const retryResult = def.keyType._zod.run({
|
|
9213
9288
|
value: Number(key),
|
|
9214
9289
|
issues: []
|
|
@@ -9264,6 +9339,24 @@ const $ZodEnum = /*@__PURE__*/ $constructor("$ZodEnum", (inst, def) => {
|
|
|
9264
9339
|
return payload;
|
|
9265
9340
|
};
|
|
9266
9341
|
});
|
|
9342
|
+
const $ZodLiteral = /*@__PURE__*/ $constructor("$ZodLiteral", (inst, def) => {
|
|
9343
|
+
$ZodType.init(inst, def);
|
|
9344
|
+
if (def.values.length === 0) throw new Error("Cannot create literal schema with no valid values");
|
|
9345
|
+
const values = new Set(def.values);
|
|
9346
|
+
inst._zod.values = values;
|
|
9347
|
+
inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$`);
|
|
9348
|
+
inst._zod.parse = (payload, _ctx) => {
|
|
9349
|
+
const input = payload.value;
|
|
9350
|
+
if (values.has(input)) return payload;
|
|
9351
|
+
payload.issues.push({
|
|
9352
|
+
code: "invalid_value",
|
|
9353
|
+
values: def.values,
|
|
9354
|
+
input,
|
|
9355
|
+
inst
|
|
9356
|
+
});
|
|
9357
|
+
return payload;
|
|
9358
|
+
};
|
|
9359
|
+
});
|
|
9267
9360
|
const $ZodTransform = /*@__PURE__*/ $constructor("$ZodTransform", (inst, def) => {
|
|
9268
9361
|
$ZodType.init(inst, def);
|
|
9269
9362
|
inst._zod.optin = "optional";
|
|
@@ -9827,6 +9920,15 @@ function _number(Class, params) {
|
|
|
9827
9920
|
});
|
|
9828
9921
|
}
|
|
9829
9922
|
// @__NO_SIDE_EFFECTS__
|
|
9923
|
+
function _coercedNumber(Class, params) {
|
|
9924
|
+
return new Class({
|
|
9925
|
+
type: "number",
|
|
9926
|
+
coerce: true,
|
|
9927
|
+
checks: [],
|
|
9928
|
+
...normalizeParams(params)
|
|
9929
|
+
});
|
|
9930
|
+
}
|
|
9931
|
+
// @__NO_SIDE_EFFECTS__
|
|
9830
9932
|
function _int(Class, params) {
|
|
9831
9933
|
return new Class({
|
|
9832
9934
|
type: "number",
|
|
@@ -9837,6 +9939,13 @@ function _int(Class, params) {
|
|
|
9837
9939
|
});
|
|
9838
9940
|
}
|
|
9839
9941
|
// @__NO_SIDE_EFFECTS__
|
|
9942
|
+
function _boolean(Class, params) {
|
|
9943
|
+
return new Class({
|
|
9944
|
+
type: "boolean",
|
|
9945
|
+
...normalizeParams(params)
|
|
9946
|
+
});
|
|
9947
|
+
}
|
|
9948
|
+
// @__NO_SIDE_EFFECTS__
|
|
9840
9949
|
function _unknown(Class) {
|
|
9841
9950
|
return new Class({ type: "unknown" });
|
|
9842
9951
|
}
|
|
@@ -10384,6 +10493,9 @@ const numberProcessor = (schema, ctx, _json, _params) => {
|
|
|
10384
10493
|
else if (typeof maximum === "number") json.maximum = maximum;
|
|
10385
10494
|
if (typeof multipleOf === "number") json.multipleOf = multipleOf;
|
|
10386
10495
|
};
|
|
10496
|
+
const booleanProcessor = (_schema, _ctx, json, _params) => {
|
|
10497
|
+
json.type = "boolean";
|
|
10498
|
+
};
|
|
10387
10499
|
const neverProcessor = (_schema, _ctx, json, _params) => {
|
|
10388
10500
|
json.not = {};
|
|
10389
10501
|
};
|
|
@@ -10395,6 +10507,27 @@ const enumProcessor = (schema, _ctx, json, _params) => {
|
|
|
10395
10507
|
if (values.every((v) => typeof v === "string")) json.type = "string";
|
|
10396
10508
|
json.enum = values;
|
|
10397
10509
|
};
|
|
10510
|
+
const literalProcessor = (schema, ctx, json, _params) => {
|
|
10511
|
+
const def = schema._zod.def;
|
|
10512
|
+
const vals = [];
|
|
10513
|
+
for (const val of def.values) if (val === void 0) {
|
|
10514
|
+
if (ctx.unrepresentable === "throw") throw new Error("Literal `undefined` cannot be represented in JSON Schema");
|
|
10515
|
+
} else if (typeof val === "bigint") if (ctx.unrepresentable === "throw") throw new Error("BigInt literals cannot be represented in JSON Schema");
|
|
10516
|
+
else vals.push(Number(val));
|
|
10517
|
+
else vals.push(val);
|
|
10518
|
+
if (vals.length === 0) {} else if (vals.length === 1) {
|
|
10519
|
+
const val = vals[0];
|
|
10520
|
+
json.type = val === null ? "null" : typeof val;
|
|
10521
|
+
if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") json.enum = [val];
|
|
10522
|
+
else json.const = val;
|
|
10523
|
+
} else {
|
|
10524
|
+
if (vals.every((v) => typeof v === "number")) json.type = "number";
|
|
10525
|
+
if (vals.every((v) => typeof v === "string")) json.type = "string";
|
|
10526
|
+
if (vals.every((v) => typeof v === "boolean")) json.type = "boolean";
|
|
10527
|
+
if (vals.every((v) => v === null)) json.type = "null";
|
|
10528
|
+
json.enum = vals;
|
|
10529
|
+
}
|
|
10530
|
+
};
|
|
10398
10531
|
const customProcessor = (_schema, ctx, _json, _params) => {
|
|
10399
10532
|
if (ctx.unrepresentable === "throw") throw new Error("Custom types cannot be represented in JSON Schema");
|
|
10400
10533
|
};
|
|
@@ -11040,7 +11173,7 @@ const ZodNumber = /*@__PURE__*/ $constructor("ZodNumber", (inst, def) => {
|
|
|
11040
11173
|
inst.isFinite = true;
|
|
11041
11174
|
inst.format = bag.format ?? null;
|
|
11042
11175
|
});
|
|
11043
|
-
function number(params) {
|
|
11176
|
+
function number$1(params) {
|
|
11044
11177
|
return _number(ZodNumber, params);
|
|
11045
11178
|
}
|
|
11046
11179
|
const ZodNumberFormat = /*@__PURE__*/ $constructor("ZodNumberFormat", (inst, def) => {
|
|
@@ -11050,6 +11183,14 @@ const ZodNumberFormat = /*@__PURE__*/ $constructor("ZodNumberFormat", (inst, def
|
|
|
11050
11183
|
function int(params) {
|
|
11051
11184
|
return _int(ZodNumberFormat, params);
|
|
11052
11185
|
}
|
|
11186
|
+
const ZodBoolean = /*@__PURE__*/ $constructor("ZodBoolean", (inst, def) => {
|
|
11187
|
+
$ZodBoolean.init(inst, def);
|
|
11188
|
+
ZodType.init(inst, def);
|
|
11189
|
+
inst._zod.processJSONSchema = (ctx, json, params) => booleanProcessor(inst, ctx, json, params);
|
|
11190
|
+
});
|
|
11191
|
+
function boolean(params) {
|
|
11192
|
+
return _boolean(ZodBoolean, params);
|
|
11193
|
+
}
|
|
11053
11194
|
const ZodUnknown = /*@__PURE__*/ $constructor("ZodUnknown", (inst, def) => {
|
|
11054
11195
|
$ZodUnknown.init(inst, def);
|
|
11055
11196
|
ZodType.init(inst, def);
|
|
@@ -11171,6 +11312,14 @@ function strictObject(shape, params) {
|
|
|
11171
11312
|
...normalizeParams(params)
|
|
11172
11313
|
});
|
|
11173
11314
|
}
|
|
11315
|
+
function looseObject(shape, params) {
|
|
11316
|
+
return new ZodObject({
|
|
11317
|
+
type: "object",
|
|
11318
|
+
shape,
|
|
11319
|
+
catchall: unknown(),
|
|
11320
|
+
...normalizeParams(params)
|
|
11321
|
+
});
|
|
11322
|
+
}
|
|
11174
11323
|
const ZodUnion = /*@__PURE__*/ $constructor("ZodUnion", (inst, def) => {
|
|
11175
11324
|
$ZodUnion.init(inst, def);
|
|
11176
11325
|
ZodType.init(inst, def);
|
|
@@ -11184,6 +11333,18 @@ function union(options, params) {
|
|
|
11184
11333
|
...normalizeParams(params)
|
|
11185
11334
|
});
|
|
11186
11335
|
}
|
|
11336
|
+
const ZodDiscriminatedUnion = /*@__PURE__*/ $constructor("ZodDiscriminatedUnion", (inst, def) => {
|
|
11337
|
+
ZodUnion.init(inst, def);
|
|
11338
|
+
$ZodDiscriminatedUnion.init(inst, def);
|
|
11339
|
+
});
|
|
11340
|
+
function discriminatedUnion(discriminator, options, params) {
|
|
11341
|
+
return new ZodDiscriminatedUnion({
|
|
11342
|
+
type: "union",
|
|
11343
|
+
options,
|
|
11344
|
+
discriminator,
|
|
11345
|
+
...normalizeParams(params)
|
|
11346
|
+
});
|
|
11347
|
+
}
|
|
11187
11348
|
const ZodIntersection = /*@__PURE__*/ $constructor("ZodIntersection", (inst, def) => {
|
|
11188
11349
|
$ZodIntersection.init(inst, def);
|
|
11189
11350
|
ZodType.init(inst, def);
|
|
@@ -11254,6 +11415,23 @@ function _enum(values, params) {
|
|
|
11254
11415
|
...normalizeParams(params)
|
|
11255
11416
|
});
|
|
11256
11417
|
}
|
|
11418
|
+
const ZodLiteral = /*@__PURE__*/ $constructor("ZodLiteral", (inst, def) => {
|
|
11419
|
+
$ZodLiteral.init(inst, def);
|
|
11420
|
+
ZodType.init(inst, def);
|
|
11421
|
+
inst._zod.processJSONSchema = (ctx, json, params) => literalProcessor(inst, ctx, json, params);
|
|
11422
|
+
inst.values = new Set(def.values);
|
|
11423
|
+
Object.defineProperty(inst, "value", { get() {
|
|
11424
|
+
if (def.values.length > 1) throw new Error("This schema contains multiple valid literal values. Use `.values` instead.");
|
|
11425
|
+
return def.values[0];
|
|
11426
|
+
} });
|
|
11427
|
+
});
|
|
11428
|
+
function literal(value, params) {
|
|
11429
|
+
return new ZodLiteral({
|
|
11430
|
+
type: "literal",
|
|
11431
|
+
values: Array.isArray(value) ? value : [value],
|
|
11432
|
+
...normalizeParams(params)
|
|
11433
|
+
});
|
|
11434
|
+
}
|
|
11257
11435
|
const ZodTransform = /*@__PURE__*/ $constructor("ZodTransform", (inst, def) => {
|
|
11258
11436
|
$ZodTransform.init(inst, def);
|
|
11259
11437
|
ZodType.init(inst, def);
|
|
@@ -11420,6 +11598,12 @@ function superRefine(fn, params) {
|
|
|
11420
11598
|
return _superRefine(fn, params);
|
|
11421
11599
|
}
|
|
11422
11600
|
|
|
11601
|
+
//#endregion
|
|
11602
|
+
//#region ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/coerce.js
|
|
11603
|
+
function number(params) {
|
|
11604
|
+
return _coercedNumber(ZodNumber, params);
|
|
11605
|
+
}
|
|
11606
|
+
|
|
11423
11607
|
//#endregion
|
|
11424
11608
|
//#region ../../node_modules/.pnpm/is-plain-obj@4.1.0/node_modules/is-plain-obj/index.js
|
|
11425
11609
|
function isPlainObject(value) {
|
|
@@ -17742,6 +17926,74 @@ const execaNode = createExeca(mapNode);
|
|
|
17742
17926
|
const $ = createExeca(mapScriptAsync, {}, deepScriptOptions, setScriptSync);
|
|
17743
17927
|
const { sendMessage, getOneMessage, getEachMessage, getCancelSignal } = getIpcExport();
|
|
17744
17928
|
|
|
17929
|
+
//#endregion
|
|
17930
|
+
//#region ../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/rng.js
|
|
17931
|
+
const rnds8 = new Uint8Array(16);
|
|
17932
|
+
function rng() {
|
|
17933
|
+
return crypto.getRandomValues(rnds8);
|
|
17934
|
+
}
|
|
17935
|
+
|
|
17936
|
+
//#endregion
|
|
17937
|
+
//#region ../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/stringify.js
|
|
17938
|
+
const byteToHex = [];
|
|
17939
|
+
for (let i = 0; i < 256; ++i) byteToHex.push((i + 256).toString(16).slice(1));
|
|
17940
|
+
function unsafeStringify(arr, offset = 0) {
|
|
17941
|
+
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
|
|
17942
|
+
}
|
|
17943
|
+
|
|
17944
|
+
//#endregion
|
|
17945
|
+
//#region ../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/v7.js
|
|
17946
|
+
const _state = {};
|
|
17947
|
+
function v7(options, buf, offset) {
|
|
17948
|
+
let bytes;
|
|
17949
|
+
if (options) bytes = v7Bytes(options.random ?? options.rng?.() ?? rng(), options.msecs, options.seq, buf, offset);
|
|
17950
|
+
else {
|
|
17951
|
+
const now = Date.now();
|
|
17952
|
+
const rnds = rng();
|
|
17953
|
+
updateV7State(_state, now, rnds);
|
|
17954
|
+
bytes = v7Bytes(rnds, _state.msecs, _state.seq, buf, offset);
|
|
17955
|
+
}
|
|
17956
|
+
return buf ?? unsafeStringify(bytes);
|
|
17957
|
+
}
|
|
17958
|
+
function updateV7State(state, now, rnds) {
|
|
17959
|
+
state.msecs ??= -Infinity;
|
|
17960
|
+
state.seq ??= 0;
|
|
17961
|
+
if (now > state.msecs) {
|
|
17962
|
+
state.seq = rnds[6] << 23 | rnds[7] << 16 | rnds[8] << 8 | rnds[9];
|
|
17963
|
+
state.msecs = now;
|
|
17964
|
+
} else {
|
|
17965
|
+
state.seq = state.seq + 1 | 0;
|
|
17966
|
+
if (state.seq === 0) state.msecs++;
|
|
17967
|
+
}
|
|
17968
|
+
return state;
|
|
17969
|
+
}
|
|
17970
|
+
function v7Bytes(rnds, msecs, seq, buf, offset = 0) {
|
|
17971
|
+
if (rnds.length < 16) throw new Error("Random bytes length must be >= 16");
|
|
17972
|
+
if (!buf) {
|
|
17973
|
+
buf = new Uint8Array(16);
|
|
17974
|
+
offset = 0;
|
|
17975
|
+
} else if (offset < 0 || offset + 16 > buf.length) throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
|
|
17976
|
+
msecs ??= Date.now();
|
|
17977
|
+
seq ??= rnds[6] * 127 << 24 | rnds[7] << 16 | rnds[8] << 8 | rnds[9];
|
|
17978
|
+
buf[offset++] = msecs / 1099511627776 & 255;
|
|
17979
|
+
buf[offset++] = msecs / 4294967296 & 255;
|
|
17980
|
+
buf[offset++] = msecs / 16777216 & 255;
|
|
17981
|
+
buf[offset++] = msecs / 65536 & 255;
|
|
17982
|
+
buf[offset++] = msecs / 256 & 255;
|
|
17983
|
+
buf[offset++] = msecs & 255;
|
|
17984
|
+
buf[offset++] = 112 | seq >>> 28 & 15;
|
|
17985
|
+
buf[offset++] = seq >>> 20 & 255;
|
|
17986
|
+
buf[offset++] = 128 | seq >>> 14 & 63;
|
|
17987
|
+
buf[offset++] = seq >>> 6 & 255;
|
|
17988
|
+
buf[offset++] = seq << 2 & 255 | rnds[10] & 3;
|
|
17989
|
+
buf[offset++] = rnds[11];
|
|
17990
|
+
buf[offset++] = rnds[12];
|
|
17991
|
+
buf[offset++] = rnds[13];
|
|
17992
|
+
buf[offset++] = rnds[14];
|
|
17993
|
+
buf[offset++] = rnds[15];
|
|
17994
|
+
return buf;
|
|
17995
|
+
}
|
|
17996
|
+
|
|
17745
17997
|
//#endregion
|
|
17746
17998
|
//#region ../../node_modules/.pnpm/kind-of@6.0.3/node_modules/kind-of/index.js
|
|
17747
17999
|
var require_kind_of = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
@@ -25968,74 +26220,6 @@ var require_gray_matter = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
25968
26220
|
module.exports = matter;
|
|
25969
26221
|
}));
|
|
25970
26222
|
|
|
25971
|
-
//#endregion
|
|
25972
|
-
//#region ../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/rng.js
|
|
25973
|
-
const rnds8 = new Uint8Array(16);
|
|
25974
|
-
function rng() {
|
|
25975
|
-
return crypto.getRandomValues(rnds8);
|
|
25976
|
-
}
|
|
25977
|
-
|
|
25978
|
-
//#endregion
|
|
25979
|
-
//#region ../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/stringify.js
|
|
25980
|
-
const byteToHex = [];
|
|
25981
|
-
for (let i = 0; i < 256; ++i) byteToHex.push((i + 256).toString(16).slice(1));
|
|
25982
|
-
function unsafeStringify(arr, offset = 0) {
|
|
25983
|
-
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
|
|
25984
|
-
}
|
|
25985
|
-
|
|
25986
|
-
//#endregion
|
|
25987
|
-
//#region ../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/v7.js
|
|
25988
|
-
const _state = {};
|
|
25989
|
-
function v7(options, buf, offset) {
|
|
25990
|
-
let bytes;
|
|
25991
|
-
if (options) bytes = v7Bytes(options.random ?? options.rng?.() ?? rng(), options.msecs, options.seq, buf, offset);
|
|
25992
|
-
else {
|
|
25993
|
-
const now = Date.now();
|
|
25994
|
-
const rnds = rng();
|
|
25995
|
-
updateV7State(_state, now, rnds);
|
|
25996
|
-
bytes = v7Bytes(rnds, _state.msecs, _state.seq, buf, offset);
|
|
25997
|
-
}
|
|
25998
|
-
return buf ?? unsafeStringify(bytes);
|
|
25999
|
-
}
|
|
26000
|
-
function updateV7State(state, now, rnds) {
|
|
26001
|
-
state.msecs ??= -Infinity;
|
|
26002
|
-
state.seq ??= 0;
|
|
26003
|
-
if (now > state.msecs) {
|
|
26004
|
-
state.seq = rnds[6] << 23 | rnds[7] << 16 | rnds[8] << 8 | rnds[9];
|
|
26005
|
-
state.msecs = now;
|
|
26006
|
-
} else {
|
|
26007
|
-
state.seq = state.seq + 1 | 0;
|
|
26008
|
-
if (state.seq === 0) state.msecs++;
|
|
26009
|
-
}
|
|
26010
|
-
return state;
|
|
26011
|
-
}
|
|
26012
|
-
function v7Bytes(rnds, msecs, seq, buf, offset = 0) {
|
|
26013
|
-
if (rnds.length < 16) throw new Error("Random bytes length must be >= 16");
|
|
26014
|
-
if (!buf) {
|
|
26015
|
-
buf = new Uint8Array(16);
|
|
26016
|
-
offset = 0;
|
|
26017
|
-
} else if (offset < 0 || offset + 16 > buf.length) throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
|
|
26018
|
-
msecs ??= Date.now();
|
|
26019
|
-
seq ??= rnds[6] * 127 << 24 | rnds[7] << 16 | rnds[8] << 8 | rnds[9];
|
|
26020
|
-
buf[offset++] = msecs / 1099511627776 & 255;
|
|
26021
|
-
buf[offset++] = msecs / 4294967296 & 255;
|
|
26022
|
-
buf[offset++] = msecs / 16777216 & 255;
|
|
26023
|
-
buf[offset++] = msecs / 65536 & 255;
|
|
26024
|
-
buf[offset++] = msecs / 256 & 255;
|
|
26025
|
-
buf[offset++] = msecs & 255;
|
|
26026
|
-
buf[offset++] = 112 | seq >>> 28 & 15;
|
|
26027
|
-
buf[offset++] = seq >>> 20 & 255;
|
|
26028
|
-
buf[offset++] = 128 | seq >>> 14 & 63;
|
|
26029
|
-
buf[offset++] = seq >>> 6 & 255;
|
|
26030
|
-
buf[offset++] = seq << 2 & 255 | rnds[10] & 3;
|
|
26031
|
-
buf[offset++] = rnds[11];
|
|
26032
|
-
buf[offset++] = rnds[12];
|
|
26033
|
-
buf[offset++] = rnds[13];
|
|
26034
|
-
buf[offset++] = rnds[14];
|
|
26035
|
-
buf[offset++] = rnds[15];
|
|
26036
|
-
return buf;
|
|
26037
|
-
}
|
|
26038
|
-
|
|
26039
26223
|
//#endregion
|
|
26040
26224
|
//#region ../../node_modules/.pnpm/graceful-fs@4.2.11/node_modules/graceful-fs/polyfills.js
|
|
26041
26225
|
var require_polyfills = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
@@ -27397,9 +27581,113 @@ var require_proper_lockfile = /* @__PURE__ */ __commonJSMin(((exports, module) =
|
|
|
27397
27581
|
}));
|
|
27398
27582
|
|
|
27399
27583
|
//#endregion
|
|
27400
|
-
//#region
|
|
27584
|
+
//#region ../base-schemas/dist/index.mjs
|
|
27401
27585
|
var import_gray_matter = /* @__PURE__ */ __toESM(require_gray_matter(), 1);
|
|
27402
27586
|
var import_proper_lockfile = /* @__PURE__ */ __toESM(require_proper_lockfile(), 1);
|
|
27587
|
+
const apiKeyAuthSchema = strictObject({
|
|
27588
|
+
api_key: string().trim().min(1),
|
|
27589
|
+
type: literal("api_key")
|
|
27590
|
+
}).meta({ title: "ApiKeyAuth" });
|
|
27591
|
+
const authenticatedAccountRefSchema = strictObject({
|
|
27592
|
+
account_id: string().trim().min(1),
|
|
27593
|
+
provider_id: string().trim().min(1),
|
|
27594
|
+
type: literal("authenticated_account")
|
|
27595
|
+
}).meta({ title: "AuthenticatedAccountRef" });
|
|
27596
|
+
const authenticatedAccountIdentitySchema = authenticatedAccountRefSchema.omit({ type: true }).meta({ title: "AuthenticatedAccountIdentity" });
|
|
27597
|
+
const bindingAuthNoneSchema = strictObject({ type: literal("none") }).meta({ title: "BindingAuthNone" });
|
|
27598
|
+
const clientCredentialsAuthSchema = strictObject({
|
|
27599
|
+
client_id: string().trim().min(1),
|
|
27600
|
+
client_secret: string().trim().min(1),
|
|
27601
|
+
type: literal("client_credentials")
|
|
27602
|
+
}).meta({ title: "ClientCredentialsAuth" });
|
|
27603
|
+
const bindingAuthSchema = discriminatedUnion("type", [
|
|
27604
|
+
bindingAuthNoneSchema,
|
|
27605
|
+
authenticatedAccountRefSchema,
|
|
27606
|
+
apiKeyAuthSchema,
|
|
27607
|
+
clientCredentialsAuthSchema
|
|
27608
|
+
]).meta({ title: "BindingAuth" });
|
|
27609
|
+
const MODES = ["dagster"];
|
|
27610
|
+
const modeSchema = _enum(MODES);
|
|
27611
|
+
const generatedAtSchema = string().datetime({ offset: true });
|
|
27612
|
+
const bindingModelNameSchema = string().trim().min(1).meta({ title: "BindingModelName" });
|
|
27613
|
+
const bindingModelsSchema = strictObject({
|
|
27614
|
+
active: array(bindingModelNameSchema).optional(),
|
|
27615
|
+
filter: string().trim().min(1).optional()
|
|
27616
|
+
}).meta({ title: "BindingModels" });
|
|
27617
|
+
const dagsterAllPlanBindingSchema = strictObject({
|
|
27618
|
+
auth: bindingAuthSchema,
|
|
27619
|
+
binding_id: string().uuid(),
|
|
27620
|
+
config: record(string(), unknown()),
|
|
27621
|
+
mode: modeSchema,
|
|
27622
|
+
models: bindingModelsSchema.optional(),
|
|
27623
|
+
plugin_id: string().trim().min(1)
|
|
27624
|
+
}).meta({ title: "PlanBinding" }).extend({ mode: literal("dagster") }).meta({ title: "DagsterAllPlanBinding" });
|
|
27625
|
+
const dagsterBindingPlanAllSchema = strictObject({
|
|
27626
|
+
bindings: array(dagsterAllPlanBindingSchema),
|
|
27627
|
+
generated_at: generatedAtSchema,
|
|
27628
|
+
version: literal(1)
|
|
27629
|
+
}).meta({ title: "DagsterBindingPlanAll" });
|
|
27630
|
+
const dagsterPluginPlanBindingSchema = dagsterAllPlanBindingSchema.omit({
|
|
27631
|
+
mode: true,
|
|
27632
|
+
plugin_id: true
|
|
27633
|
+
}).meta({ title: "DagsterPluginPlanBinding" });
|
|
27634
|
+
const dagsterBindingPlanPluginSchema = strictObject({
|
|
27635
|
+
bindings: array(dagsterPluginPlanBindingSchema),
|
|
27636
|
+
generated_at: generatedAtSchema,
|
|
27637
|
+
mode: literal("dagster"),
|
|
27638
|
+
plugin_id: string().trim().min(1),
|
|
27639
|
+
version: literal(1)
|
|
27640
|
+
}).meta({ title: "DagsterBindingPlanPlugin" });
|
|
27641
|
+
const RUN_STATUSES = [
|
|
27642
|
+
"QUEUED",
|
|
27643
|
+
"NOT_STARTED",
|
|
27644
|
+
"MANAGED",
|
|
27645
|
+
"STARTING",
|
|
27646
|
+
"STARTED",
|
|
27647
|
+
"SUCCESS",
|
|
27648
|
+
"FAILURE",
|
|
27649
|
+
"CANCELING",
|
|
27650
|
+
"CANCELED"
|
|
27651
|
+
];
|
|
27652
|
+
const runStatusSchema$1 = _enum(RUN_STATUSES).meta({ title: "RunStatus" });
|
|
27653
|
+
const stateTimestampSchema = string().datetime({ offset: true });
|
|
27654
|
+
const bindingStateSchema = strictObject({
|
|
27655
|
+
frontier: stateTimestampSchema.nullable(),
|
|
27656
|
+
last_run: stateTimestampSchema.nullable(),
|
|
27657
|
+
last_run_status: runStatusSchema$1.nullable(),
|
|
27658
|
+
plugin_id: string().trim().min(1)
|
|
27659
|
+
}).meta({ title: "BindingState" });
|
|
27660
|
+
const bindingStateResponseSchema = strictObject({
|
|
27661
|
+
bindings: record(string().uuid(), bindingStateSchema),
|
|
27662
|
+
version: literal(1)
|
|
27663
|
+
}).meta({ title: "BindingStateResponse" });
|
|
27664
|
+
const oauthAccessTokenSuccessSchema = looseObject({
|
|
27665
|
+
accessToken: string().trim().min(1),
|
|
27666
|
+
accessTokenExpiresAt: string().datetime({ offset: true })
|
|
27667
|
+
}).meta({ title: "OAuthAccessTokenSuccess" });
|
|
27668
|
+
const pluginAuthNoneSchema = strictObject({ type: literal("none") }).meta({ title: "PluginAuthNone" });
|
|
27669
|
+
const pluginAuthApiKeySchema = strictObject({ type: literal("api_key") }).meta({ title: "PluginAuthApiKey" });
|
|
27670
|
+
const pluginAuthClientCredentialsSchema = strictObject({ type: literal("client_credentials") }).meta({ title: "PluginAuthClientCredentials" });
|
|
27671
|
+
const pluginOAuthSchema = strictObject({
|
|
27672
|
+
provider_id: string().trim().min(1),
|
|
27673
|
+
scopes: array(string().trim().min(1)).min(1),
|
|
27674
|
+
type: literal("oauth")
|
|
27675
|
+
}).meta({ title: "PluginOAuth" });
|
|
27676
|
+
const pluginAuthSchema = discriminatedUnion("type", [
|
|
27677
|
+
pluginAuthNoneSchema,
|
|
27678
|
+
pluginAuthApiKeySchema,
|
|
27679
|
+
pluginAuthClientCredentialsSchema,
|
|
27680
|
+
pluginOAuthSchema
|
|
27681
|
+
]).meta({ title: "PluginAuth" });
|
|
27682
|
+
const pluginManifestSchema = strictObject({
|
|
27683
|
+
auth: pluginAuthSchema,
|
|
27684
|
+
mode: modeSchema,
|
|
27685
|
+
plugin_id: string().trim().min(1),
|
|
27686
|
+
skill: string().optional()
|
|
27687
|
+
}).meta({ title: "PluginManifest" });
|
|
27688
|
+
|
|
27689
|
+
//#endregion
|
|
27690
|
+
//#region ../../node_modules/.pnpm/postgres@3.4.9/node_modules/postgres/src/query.js
|
|
27403
27691
|
const originCache = /* @__PURE__ */ new Map(), originStackCache = /* @__PURE__ */ new Map(), originError = Symbol("OriginError");
|
|
27404
27692
|
const CLOSE = {};
|
|
27405
27693
|
var Query = class extends Promise {
|
|
@@ -29490,7 +29778,7 @@ function validate(raw, sourcePath) {
|
|
|
29490
29778
|
}
|
|
29491
29779
|
function applyDefaults(input) {
|
|
29492
29780
|
return {
|
|
29493
|
-
synthesizerImage: input.synthesizerImage ?? "ghcr.io/usecontextlayer/ctx-sandbox:0.4.
|
|
29781
|
+
synthesizerImage: input.synthesizerImage ?? "ghcr.io/usecontextlayer/ctx-sandbox:0.4.6",
|
|
29494
29782
|
...input.microsandbox !== void 0 ? { microsandbox: input.microsandbox } : {},
|
|
29495
29783
|
...input.oldestConsideredPoint !== void 0 ? { oldestConsideredPoint: input.oldestConsideredPoint } : {},
|
|
29496
29784
|
maxSliceSize: input.maxSliceSize ?? 864e5,
|
|
@@ -29506,38 +29794,65 @@ function formatZodError$1(error) {
|
|
|
29506
29794
|
return `${issue.path.length > 0 ? issue.path.join(".") : "root"}: ${issue.message}`;
|
|
29507
29795
|
}).join("; ");
|
|
29508
29796
|
}
|
|
29797
|
+
function gatePasses(input) {
|
|
29798
|
+
if (input.syncHorizon === null) return false;
|
|
29799
|
+
if (input.mode === "manual") return input.frontier < input.syncHorizon;
|
|
29800
|
+
return input.syncHorizon - input.frontier >= input.tick;
|
|
29801
|
+
}
|
|
29509
29802
|
function planLoopPass(input) {
|
|
29510
|
-
const
|
|
29511
|
-
|
|
29803
|
+
const horizon = input.syncHorizon;
|
|
29804
|
+
const horizonDue = horizon === null ? [] : input.synthesizers.filter((synthesizer) => gatePasses({
|
|
29805
|
+
frontier: synthesizer.frontier,
|
|
29806
|
+
mode: "loop",
|
|
29807
|
+
syncHorizon: horizon,
|
|
29808
|
+
tick: input.tick
|
|
29809
|
+
}));
|
|
29810
|
+
const due = horizonDue.filter((synthesizer) => (synthesizer.notBefore ?? 0) <= input.now);
|
|
29811
|
+
if (horizon !== null && due.length > 0) return {
|
|
29512
29812
|
kind: "run",
|
|
29513
|
-
order: due.map((synthesizer) => synthesizer.name).sort()
|
|
29813
|
+
order: due.map((synthesizer) => synthesizer.name).sort(),
|
|
29814
|
+
syncHorizon: horizon
|
|
29514
29815
|
};
|
|
29816
|
+
const held = new Set(horizonDue);
|
|
29515
29817
|
return {
|
|
29516
29818
|
kind: "idle",
|
|
29517
|
-
|
|
29819
|
+
reason: held.size > 0 ? "rate_limited" : "caught_up",
|
|
29820
|
+
wakeAt: input.synthesizers.length === 0 ? input.now + input.tick : Math.min(...input.synthesizers.map((synthesizer) => {
|
|
29821
|
+
if (held.has(synthesizer)) return synthesizer.notBefore ?? 0;
|
|
29822
|
+
return Math.max(synthesizer.notBefore ?? 0, input.now + input.tick);
|
|
29823
|
+
}))
|
|
29824
|
+
};
|
|
29825
|
+
}
|
|
29826
|
+
function concludeLoopPass(results) {
|
|
29827
|
+
if (results.includes("advanced")) return { kind: "progressed" };
|
|
29828
|
+
return {
|
|
29829
|
+
kind: "blocked",
|
|
29830
|
+
reason: results.includes("rate_limited") ? "rate_limited" : "stalled"
|
|
29518
29831
|
};
|
|
29519
29832
|
}
|
|
29520
29833
|
async function runEngineLoop(deps, options) {
|
|
29521
29834
|
for (;;) {
|
|
29522
29835
|
if (options.signal?.aborted) return { stopReason: "aborted" };
|
|
29523
|
-
const synthesizers = await deps.listSynthesizers();
|
|
29836
|
+
const [syncHorizon, synthesizers] = await Promise.all([deps.captureSyncHorizon(), deps.listSynthesizers()]);
|
|
29524
29837
|
const pass = planLoopPass({
|
|
29525
29838
|
now: deps.now(),
|
|
29839
|
+
syncHorizon,
|
|
29526
29840
|
synthesizers,
|
|
29527
29841
|
tick: options.tick
|
|
29528
29842
|
});
|
|
29529
29843
|
if (pass.kind === "idle") {
|
|
29530
|
-
if (options.mode === "backfill") return { stopReason:
|
|
29844
|
+
if (options.mode === "backfill") return { stopReason: pass.reason };
|
|
29531
29845
|
await deps.sleep(Math.max(0, pass.wakeAt - deps.now()));
|
|
29532
29846
|
continue;
|
|
29533
29847
|
}
|
|
29534
|
-
|
|
29848
|
+
const results = [];
|
|
29535
29849
|
for (const name of pass.order) {
|
|
29536
29850
|
if (options.signal?.aborted) return { stopReason: "aborted" };
|
|
29537
|
-
|
|
29851
|
+
results.push(await deps.runSlice(name, pass.syncHorizon));
|
|
29538
29852
|
}
|
|
29539
|
-
|
|
29540
|
-
|
|
29853
|
+
const conclusion = concludeLoopPass(results);
|
|
29854
|
+
if (conclusion.kind === "blocked") {
|
|
29855
|
+
if (options.mode === "backfill") return { stopReason: conclusion.reason };
|
|
29541
29856
|
await deps.sleep(options.tick);
|
|
29542
29857
|
}
|
|
29543
29858
|
}
|
|
@@ -29861,6 +30176,18 @@ function formatRelativeAge(ms) {
|
|
|
29861
30176
|
}
|
|
29862
30177
|
return rtf.format(-Math.round(value), "year");
|
|
29863
30178
|
}
|
|
30179
|
+
function formatDuration(ms) {
|
|
30180
|
+
let value = Math.trunc(ms) / 1e3;
|
|
30181
|
+
if (value < 1) return "under a second";
|
|
30182
|
+
for (const [unit, perNext] of DIVISIONS) {
|
|
30183
|
+
if (value < perNext) return pluralizeUnit(Math.round(value), unit);
|
|
30184
|
+
value /= perNext;
|
|
30185
|
+
}
|
|
30186
|
+
return pluralizeUnit(Math.round(value), "year");
|
|
30187
|
+
}
|
|
30188
|
+
function pluralizeUnit(value, unit) {
|
|
30189
|
+
return `${value} ${unit}${value === 1 ? "" : "s"}`;
|
|
30190
|
+
}
|
|
29864
30191
|
async function runRootPreflight(repo) {
|
|
29865
30192
|
await assertGitCheckout(repo);
|
|
29866
30193
|
const branch = await inspectBranchReadiness(repo);
|
|
@@ -29904,13 +30231,266 @@ function dirtyWorkingTreeIssue(paths) {
|
|
|
29904
30231
|
message: `Working tree is dirty:\n${formatWorkingTreePaths(paths)}\nRun 'ctxe repair' to roll back to HEAD (preserves .engine/runs/**).`
|
|
29905
30232
|
};
|
|
29906
30233
|
}
|
|
29907
|
-
const
|
|
29908
|
-
|
|
29909
|
-
|
|
29910
|
-
|
|
29911
|
-
|
|
29912
|
-
|
|
29913
|
-
|
|
30234
|
+
const runTriggerSchema = _enum([
|
|
30235
|
+
"backfill",
|
|
30236
|
+
"daemon",
|
|
30237
|
+
"manual"
|
|
30238
|
+
]);
|
|
30239
|
+
_enum([
|
|
30240
|
+
"success",
|
|
30241
|
+
"failed",
|
|
30242
|
+
"timed_out",
|
|
30243
|
+
"rate_limited"
|
|
30244
|
+
]);
|
|
30245
|
+
const runStatusSchema = _enum([
|
|
30246
|
+
"starting",
|
|
30247
|
+
"running",
|
|
30248
|
+
"success",
|
|
30249
|
+
"failed",
|
|
30250
|
+
"timed_out",
|
|
30251
|
+
"rate_limited",
|
|
30252
|
+
"interrupted"
|
|
30253
|
+
]);
|
|
30254
|
+
const claudeResultSchema = strictObject({
|
|
30255
|
+
api_error_status: number$1().int().optional(),
|
|
30256
|
+
is_error: boolean(),
|
|
30257
|
+
num_turns: number$1().int(),
|
|
30258
|
+
subtype: string().min(1),
|
|
30259
|
+
terminal_reason: string().min(1).optional(),
|
|
30260
|
+
total_cost_usd: number$1()
|
|
30261
|
+
});
|
|
30262
|
+
const runRecordSchema = strictObject({
|
|
30263
|
+
claude_result: claudeResultSchema.optional(),
|
|
30264
|
+
completed_at: string().min(1).optional(),
|
|
30265
|
+
duration_ms: number$1().int().nonnegative().optional(),
|
|
30266
|
+
exit_code: number$1().int().optional(),
|
|
30267
|
+
rate_limit_resets_at: string().min(1).optional(),
|
|
30268
|
+
run_id: string().min(1),
|
|
30269
|
+
started_at: string().min(1),
|
|
30270
|
+
status: runStatusSchema,
|
|
30271
|
+
synthesizer: string().min(1),
|
|
30272
|
+
triggered_by: runTriggerSchema
|
|
30273
|
+
});
|
|
30274
|
+
const RECORD_FILE_NAME = "record.json";
|
|
30275
|
+
const STDERR_FILE_NAME = "stderr";
|
|
30276
|
+
function buildStartingRunRecord(input) {
|
|
30277
|
+
return {
|
|
30278
|
+
run_id: input.runId,
|
|
30279
|
+
started_at: input.startedAt,
|
|
30280
|
+
status: "starting",
|
|
30281
|
+
synthesizer: input.synthesizerName,
|
|
30282
|
+
triggered_by: input.trigger
|
|
30283
|
+
};
|
|
30284
|
+
}
|
|
30285
|
+
function buildRunningRunRecord(record) {
|
|
30286
|
+
return {
|
|
30287
|
+
...record,
|
|
30288
|
+
status: "running"
|
|
30289
|
+
};
|
|
30290
|
+
}
|
|
30291
|
+
function buildTerminalRunRecord(input) {
|
|
30292
|
+
return {
|
|
30293
|
+
...input.claudeResult !== void 0 && { claude_result: input.claudeResult },
|
|
30294
|
+
completed_at: input.completedAt,
|
|
30295
|
+
duration_ms: input.durationMs,
|
|
30296
|
+
exit_code: input.exitCode,
|
|
30297
|
+
...input.rateLimitResetsAt !== void 0 && { rate_limit_resets_at: input.rateLimitResetsAt },
|
|
30298
|
+
run_id: input.runId,
|
|
30299
|
+
started_at: input.startedAt,
|
|
30300
|
+
status: input.status,
|
|
30301
|
+
synthesizer: input.synthesizerName,
|
|
30302
|
+
triggered_by: input.trigger
|
|
30303
|
+
};
|
|
30304
|
+
}
|
|
30305
|
+
function buildInterruptedRunRecord(record, completedAt) {
|
|
30306
|
+
return {
|
|
30307
|
+
...record,
|
|
30308
|
+
completed_at: completedAt,
|
|
30309
|
+
status: "interrupted"
|
|
30310
|
+
};
|
|
30311
|
+
}
|
|
30312
|
+
function getRunDir(input) {
|
|
30313
|
+
return runDirPath(input.rootDir, input.synthesizerName, input.runId);
|
|
30314
|
+
}
|
|
30315
|
+
async function ensureRunDir(input) {
|
|
30316
|
+
const runDir = getRunDir(input);
|
|
30317
|
+
await mkdir(runDir, { recursive: true });
|
|
30318
|
+
return runDir;
|
|
30319
|
+
}
|
|
30320
|
+
async function writeRunRecord(runDir, record) {
|
|
30321
|
+
await mkdir(runDir, { recursive: true });
|
|
30322
|
+
await writeJsonFileAtomic(path.join(runDir, RECORD_FILE_NAME), runRecordSchema.parse(record));
|
|
30323
|
+
}
|
|
30324
|
+
async function readRunRecord(runDir) {
|
|
30325
|
+
const raw = await readFile(path.join(runDir, RECORD_FILE_NAME), "utf8");
|
|
30326
|
+
return runRecordSchema.parse(JSON.parse(raw));
|
|
30327
|
+
}
|
|
30328
|
+
async function readLatestRunRecord(input) {
|
|
30329
|
+
const synthesizerDir = synthesizerRunsDirPath(input.rootDir, input.synthesizerName);
|
|
30330
|
+
let runIds;
|
|
30331
|
+
try {
|
|
30332
|
+
runIds = await listDirectoryNames(synthesizerDir);
|
|
30333
|
+
} catch (error) {
|
|
30334
|
+
if (isNodeError(error) && error.code === "ENOENT") return null;
|
|
30335
|
+
throw error;
|
|
30336
|
+
}
|
|
30337
|
+
const latest = runIds.reduce((max, runId) => max === null || runId > max ? runId : max, null);
|
|
30338
|
+
if (latest === null) return null;
|
|
30339
|
+
try {
|
|
30340
|
+
return await readRunRecord(path.join(synthesizerDir, latest));
|
|
30341
|
+
} catch (error) {
|
|
30342
|
+
if (isNodeError(error) && error.code === "ENOENT") return null;
|
|
30343
|
+
throw error;
|
|
30344
|
+
}
|
|
30345
|
+
}
|
|
30346
|
+
async function listRunRecords(input) {
|
|
30347
|
+
const synthesizerNames = input.synthesizerName !== void 0 ? [input.synthesizerName] : await listSynthesizerRunDirNames(input.rootDir);
|
|
30348
|
+
const entries = [];
|
|
30349
|
+
for (const synthesizerName of synthesizerNames) {
|
|
30350
|
+
const synthesizerDir = synthesizerRunsDirPath(input.rootDir, synthesizerName);
|
|
30351
|
+
let runIds;
|
|
30352
|
+
try {
|
|
30353
|
+
runIds = await listDirectoryNames(synthesizerDir);
|
|
30354
|
+
} catch (error) {
|
|
30355
|
+
if (isNodeError(error) && error.code === "ENOENT") continue;
|
|
30356
|
+
throw error;
|
|
30357
|
+
}
|
|
30358
|
+
for (const runId of runIds) {
|
|
30359
|
+
const runDir = path.join(synthesizerDir, runId);
|
|
30360
|
+
try {
|
|
30361
|
+
entries.push({
|
|
30362
|
+
record: await readRunRecord(runDir),
|
|
30363
|
+
runDir,
|
|
30364
|
+
runId
|
|
30365
|
+
});
|
|
30366
|
+
} catch (error) {
|
|
30367
|
+
if (isNodeError(error) && error.code === "ENOENT") continue;
|
|
30368
|
+
throw error;
|
|
30369
|
+
}
|
|
30370
|
+
}
|
|
30371
|
+
}
|
|
30372
|
+
return entries.sort(compareRunRecordEntries);
|
|
30373
|
+
}
|
|
30374
|
+
async function readRunStderr(runDir) {
|
|
30375
|
+
return await readOptionalTextFile(path.join(runDir, STDERR_FILE_NAME));
|
|
30376
|
+
}
|
|
30377
|
+
async function writeRunStderr(input) {
|
|
30378
|
+
await mkdir(input.runDir, { recursive: true });
|
|
30379
|
+
await writeFileAtomic(path.join(input.runDir, STDERR_FILE_NAME), input.stderr);
|
|
30380
|
+
}
|
|
30381
|
+
async function markInterruptedRuns(rootDir) {
|
|
30382
|
+
const interrupted = [];
|
|
30383
|
+
const engineRunsDir = runsDirPath(rootDir);
|
|
30384
|
+
let synthesizerDirs;
|
|
30385
|
+
try {
|
|
30386
|
+
synthesizerDirs = await listDirectoryNames(engineRunsDir);
|
|
30387
|
+
} catch (error) {
|
|
30388
|
+
if (isNodeError(error) && error.code === "ENOENT") return [];
|
|
30389
|
+
throw error;
|
|
30390
|
+
}
|
|
30391
|
+
for (const synthesizerName of synthesizerDirs) {
|
|
30392
|
+
const synthesizerDir = path.join(engineRunsDir, synthesizerName);
|
|
30393
|
+
for (const runId of await listDirectoryNames(synthesizerDir)) {
|
|
30394
|
+
const runDir = path.join(synthesizerDir, runId);
|
|
30395
|
+
let record;
|
|
30396
|
+
try {
|
|
30397
|
+
record = await readRunRecord(runDir);
|
|
30398
|
+
} catch (error) {
|
|
30399
|
+
if (isNodeError(error) && error.code === "ENOENT") continue;
|
|
30400
|
+
throw error;
|
|
30401
|
+
}
|
|
30402
|
+
if (record.status !== "starting" && record.status !== "running") continue;
|
|
30403
|
+
const nextRecord = buildInterruptedRunRecord(record, (/* @__PURE__ */ new Date()).toISOString());
|
|
30404
|
+
await writeRunRecord(runDir, nextRecord);
|
|
30405
|
+
interrupted.push(nextRecord);
|
|
30406
|
+
}
|
|
30407
|
+
}
|
|
30408
|
+
return interrupted;
|
|
30409
|
+
}
|
|
30410
|
+
async function listDirectoryNames(dirPath) {
|
|
30411
|
+
return (await readdir$1(dirPath, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
30412
|
+
}
|
|
30413
|
+
async function listSynthesizerRunDirNames(rootDir) {
|
|
30414
|
+
const engineRunsDir = runsDirPath(rootDir);
|
|
30415
|
+
try {
|
|
30416
|
+
return await listDirectoryNames(engineRunsDir);
|
|
30417
|
+
} catch (error) {
|
|
30418
|
+
if (isNodeError(error) && error.code === "ENOENT") return [];
|
|
30419
|
+
throw error;
|
|
30420
|
+
}
|
|
30421
|
+
}
|
|
30422
|
+
async function readOptionalTextFile(filePath) {
|
|
30423
|
+
try {
|
|
30424
|
+
return await readFile(filePath, "utf8");
|
|
30425
|
+
} catch (error) {
|
|
30426
|
+
if (isNodeError(error) && error.code === "ENOENT") return null;
|
|
30427
|
+
throw error;
|
|
30428
|
+
}
|
|
30429
|
+
}
|
|
30430
|
+
function compareRunRecordEntries(left, right) {
|
|
30431
|
+
const timeCompare = Date.parse(right.record.started_at) - Date.parse(left.record.started_at);
|
|
30432
|
+
if (timeCompare !== 0) return timeCompare;
|
|
30433
|
+
return right.runId.localeCompare(left.runId);
|
|
30434
|
+
}
|
|
30435
|
+
async function runRootFastForward(repo) {
|
|
30436
|
+
await assertGitCheckout(repo);
|
|
30437
|
+
const branch = await inspectBranchReadiness(repo);
|
|
30438
|
+
const tree = await inspectWorkingTree(repo);
|
|
30439
|
+
if (branch.kind === "no_origin") throw new Error("RootRepair requires 'origin' to be configured in remote mode. Provisioning must add origin before repair.");
|
|
30440
|
+
if (branch.kind === "local_head_without_remote_main") throw new Error(`RootRepair refuses to act: local HEAD is at ${branch.localSha} but origin/${repo.branch} does not exist. Operator must reconcile manually.`);
|
|
30441
|
+
const needsFastForward = branch.kind === "local_unborn_remote_has_main" || branch.kind === "remote_mismatch";
|
|
30442
|
+
if (needsFastForward && !tree.clean) throw new Error(formatCombinedRepairError(repo, branch, tree));
|
|
30443
|
+
if (needsFastForward) return {
|
|
30444
|
+
kind: "fast_forward",
|
|
30445
|
+
...await fastForwardRoot(repo)
|
|
30446
|
+
};
|
|
30447
|
+
return { kind: "no_op" };
|
|
30448
|
+
}
|
|
30449
|
+
async function runRootRepair(repo) {
|
|
30450
|
+
const fastForward = await runRootFastForward(repo);
|
|
30451
|
+
if (fastForward.kind === "fast_forward") return fastForward;
|
|
30452
|
+
if (!(await inspectWorkingTree(repo)).clean) return await runDirtyRootRepair(repo);
|
|
30453
|
+
return { kind: "no_op" };
|
|
30454
|
+
}
|
|
30455
|
+
async function runDirtyRootRepair(repo) {
|
|
30456
|
+
await repairDirtyRoot(repo);
|
|
30457
|
+
const interruptedRunIds = (await markInterruptedRuns(repo.rootDir)).map((record) => record.run_id);
|
|
30458
|
+
if ((await inspectWorkingTree(repo)).clean) return {
|
|
30459
|
+
commit: null,
|
|
30460
|
+
interruptedRunIds,
|
|
30461
|
+
kind: "dirty_root_repair"
|
|
30462
|
+
};
|
|
30463
|
+
const { sha } = await commitRootRepair(repo, {
|
|
30464
|
+
interruptedRunIds,
|
|
30465
|
+
repairId: v7()
|
|
30466
|
+
});
|
|
30467
|
+
await pushToOrigin(repo);
|
|
30468
|
+
return {
|
|
30469
|
+
commit: {
|
|
30470
|
+
pushed: repo.mode === "remote",
|
|
30471
|
+
sha
|
|
30472
|
+
},
|
|
30473
|
+
interruptedRunIds,
|
|
30474
|
+
kind: "dirty_root_repair"
|
|
30475
|
+
};
|
|
30476
|
+
}
|
|
30477
|
+
function formatCombinedRepairError(repo, branch, tree) {
|
|
30478
|
+
const dirtyPaths = tree.clean ? "(clean)" : formatWorkingTreePaths(tree.paths);
|
|
30479
|
+
return [
|
|
30480
|
+
"RootRepair refuses to combine branch fast-forward with dirty-root repair in v1.",
|
|
30481
|
+
`Branch: ${branch.kind === "local_unborn_remote_has_main" ? `local checkout is unborn but origin/${repo.branch} exists` : branch.kind === "remote_mismatch" ? `local HEAD does not match origin/${repo.branch}` : `branch state is '${branch.kind}'`}.`,
|
|
30482
|
+
"Dirty paths:",
|
|
30483
|
+
dirtyPaths,
|
|
30484
|
+
"Operator must inspect and choose the order manually."
|
|
30485
|
+
].join("\n");
|
|
30486
|
+
}
|
|
30487
|
+
const synthesizerSpecFrontmatterSchema = strictObject({
|
|
30488
|
+
description: string().optional(),
|
|
30489
|
+
name: string().trim().min(1)
|
|
30490
|
+
});
|
|
30491
|
+
function parseSynthesizerSpecMarkdown(content, sourcePath) {
|
|
30492
|
+
if (!hasYamlFrontmatter(content)) return {
|
|
30493
|
+
kind: "not_synthesizer",
|
|
29914
30494
|
reason: "missing_frontmatter",
|
|
29915
30495
|
sourcePath
|
|
29916
30496
|
};
|
|
@@ -30461,12 +31041,15 @@ async function executeSynthesizerRun(input) {
|
|
|
30461
31041
|
const result = await input.executor.run(executorInput);
|
|
30462
31042
|
const completedAtMs = now().getTime();
|
|
30463
31043
|
const durationMs = Math.max(0, completedAtMs - startedAtMs);
|
|
30464
|
-
const status =
|
|
31044
|
+
const status = classifyOutcome(result.exitCode, result.observation);
|
|
31045
|
+
const rateLimitResetsAt = observedRateLimitResetsAt(result.observation);
|
|
30465
31046
|
return {
|
|
30466
31047
|
outcome: {
|
|
30467
31048
|
durationMs,
|
|
30468
31049
|
exitCode: result.exitCode,
|
|
30469
|
-
status
|
|
31050
|
+
status,
|
|
31051
|
+
...result.observation.result !== void 0 && { claudeResult: result.observation.result },
|
|
31052
|
+
...rateLimitResetsAt !== void 0 && { rateLimitResetsAt }
|
|
30470
31053
|
},
|
|
30471
31054
|
stderr: result.stderr
|
|
30472
31055
|
};
|
|
@@ -30482,11 +31065,19 @@ async function executeSynthesizerRun(input) {
|
|
|
30482
31065
|
};
|
|
30483
31066
|
}
|
|
30484
31067
|
}
|
|
30485
|
-
function
|
|
31068
|
+
function classifyOutcome(exitCode, observation) {
|
|
30486
31069
|
if (exitCode === 0) return "success";
|
|
30487
31070
|
if (exitCode === 124) return "timed_out";
|
|
31071
|
+
if (observation.result?.api_error_status === 429) return "rate_limited";
|
|
31072
|
+
if (observation.lastRateLimit?.status === "rejected") return "rate_limited";
|
|
30488
31073
|
return "failed";
|
|
30489
31074
|
}
|
|
31075
|
+
function observedRateLimitResetsAt(observation) {
|
|
31076
|
+
const rateLimit = observation.lastRateLimit;
|
|
31077
|
+
if (rateLimit === void 0) return void 0;
|
|
31078
|
+
if (rateLimit.status !== "rejected" || rateLimit.resetsAt === void 0) return;
|
|
31079
|
+
return msToIso(rateLimit.resetsAt * 1e3);
|
|
31080
|
+
}
|
|
30490
31081
|
function buildExecutorInput(input) {
|
|
30491
31082
|
return {
|
|
30492
31083
|
image: input.synthesizerImage,
|
|
@@ -30512,7 +31103,7 @@ function buildSandboxName(synthesizerName, runId) {
|
|
|
30512
31103
|
return `ctxe-${synthesizerName.slice(0, 24).toLowerCase()}-${runId.slice(-8).toLowerCase()}`;
|
|
30513
31104
|
}
|
|
30514
31105
|
function planCeiling(input) {
|
|
30515
|
-
return Math.min(input.prevCursor.frontier + input.config.maxSliceSize, input.
|
|
31106
|
+
return Math.min(input.prevCursor.frontier + input.config.maxSliceSize, input.syncHorizon);
|
|
30516
31107
|
}
|
|
30517
31108
|
function buildSlice(input) {
|
|
30518
31109
|
const slice = {};
|
|
@@ -30541,11 +31132,11 @@ function nextCursor(input) {
|
|
|
30541
31132
|
};
|
|
30542
31133
|
}
|
|
30543
31134
|
function plan(input) {
|
|
30544
|
-
const ceiling = planCeiling({
|
|
31135
|
+
const ceiling = Math.max(planCeiling({
|
|
30545
31136
|
config: input.config,
|
|
30546
31137
|
prevCursor: input.prevCursor,
|
|
30547
|
-
|
|
30548
|
-
});
|
|
31138
|
+
syncHorizon: input.syncHorizon
|
|
31139
|
+
}), input.prevCursor.frontier);
|
|
30549
31140
|
const slice = buildSlice({
|
|
30550
31141
|
ceiling,
|
|
30551
31142
|
floors: input.prevCursor.floors
|
|
@@ -30576,175 +31167,6 @@ function reconcileCursor(input) {
|
|
|
30576
31167
|
frontier: input.prevCursor.frontier
|
|
30577
31168
|
};
|
|
30578
31169
|
}
|
|
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
31170
|
function renderSliceJson(slice) {
|
|
30749
31171
|
const windows = {};
|
|
30750
31172
|
for (const [table, window] of Object.entries(slice)) windows[table] = {
|
|
@@ -30754,10 +31176,13 @@ function renderSliceJson(slice) {
|
|
|
30754
31176
|
return `${JSON.stringify(windows, null, " ")}\n`;
|
|
30755
31177
|
}
|
|
30756
31178
|
const DEFAULT_OLDEST_LOOKBACK_MS = 720 * 60 * 60 * 1e3;
|
|
31179
|
+
function resolveOldest(config, beginMs) {
|
|
31180
|
+
return config.oldestConsideredPoint ?? beginMs - DEFAULT_OLDEST_LOOKBACK_MS;
|
|
31181
|
+
}
|
|
30757
31182
|
async function openSynthesizerTransaction(input) {
|
|
30758
|
-
const now = input.now ?? (() => /* @__PURE__ */ new Date());
|
|
30759
31183
|
const runId = assertSafeEngineName((input.runIdFactory ?? v7)());
|
|
30760
|
-
const
|
|
31184
|
+
const begin = (input.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
31185
|
+
const startedAt = begin.toISOString();
|
|
30761
31186
|
const runDir = await ensureRunDir({
|
|
30762
31187
|
rootDir: input.repo.rootDir,
|
|
30763
31188
|
runId,
|
|
@@ -30778,25 +31203,24 @@ async function openSynthesizerTransaction(input) {
|
|
|
30778
31203
|
synthesizer: input.synthesizer,
|
|
30779
31204
|
trigger: input.trigger
|
|
30780
31205
|
});
|
|
30781
|
-
const
|
|
31206
|
+
const persistedCursor = await readCursor(input.repo.rootDir, input.synthesizer.name);
|
|
30782
31207
|
const planConfig = {
|
|
30783
31208
|
maxSliceSize: input.config.maxSliceSize,
|
|
30784
|
-
oldestConsideredPoint: input.config.
|
|
31209
|
+
oldestConsideredPoint: resolveOldest(input.config, begin.getTime())
|
|
30785
31210
|
};
|
|
30786
31211
|
const { next, slice } = plan({
|
|
30787
31212
|
config: planConfig,
|
|
30788
31213
|
prevCursor: reconcileCursor({
|
|
30789
31214
|
config: planConfig,
|
|
30790
|
-
prevCursor:
|
|
31215
|
+
prevCursor: persistedCursor,
|
|
30791
31216
|
tables: Object.keys(watermark)
|
|
30792
31217
|
}),
|
|
30793
|
-
|
|
31218
|
+
syncHorizon: input.syncHorizon,
|
|
30794
31219
|
watermark
|
|
30795
31220
|
});
|
|
30796
31221
|
await writeRunRecord(runDir, buildRunningRunRecord(startingRecord));
|
|
30797
31222
|
return {
|
|
30798
31223
|
next,
|
|
30799
|
-
reachedWallclock: next.frontier === wallclock,
|
|
30800
31224
|
runDir,
|
|
30801
31225
|
runId,
|
|
30802
31226
|
sliceJson: renderSliceJson(slice),
|
|
@@ -30859,9 +31283,11 @@ async function finalizeFailedSynthesizerTransaction(input) {
|
|
|
30859
31283
|
function buildTerminalRecord(input) {
|
|
30860
31284
|
const { ctx, runResult, completedAt } = input;
|
|
30861
31285
|
return buildTerminalRunRecord({
|
|
31286
|
+
...runResult.outcome.claudeResult !== void 0 && { claudeResult: runResult.outcome.claudeResult },
|
|
30862
31287
|
completedAt,
|
|
30863
31288
|
durationMs: runResult.outcome.durationMs,
|
|
30864
31289
|
exitCode: runResult.outcome.exitCode,
|
|
31290
|
+
...runResult.outcome.rateLimitResetsAt !== void 0 && { rateLimitResetsAt: runResult.outcome.rateLimitResetsAt },
|
|
30865
31291
|
runId: ctx.runId,
|
|
30866
31292
|
startedAt: ctx.startedAt,
|
|
30867
31293
|
status: runResult.outcome.status,
|
|
@@ -30901,6 +31327,7 @@ var Engine = class {
|
|
|
30901
31327
|
now;
|
|
30902
31328
|
runIdFactory;
|
|
30903
31329
|
repo;
|
|
31330
|
+
syncHorizonCapture;
|
|
30904
31331
|
watermarkCapture;
|
|
30905
31332
|
synthesizers = /* @__PURE__ */ new Map();
|
|
30906
31333
|
config = null;
|
|
@@ -30918,13 +31345,19 @@ var Engine = class {
|
|
|
30918
31345
|
mode: options.git?.mode ?? DEFAULT_GIT_MODE,
|
|
30919
31346
|
rootDir: path.resolve(options.rootDir)
|
|
30920
31347
|
};
|
|
31348
|
+
this.syncHorizonCapture = options.syncHorizonCapture;
|
|
30921
31349
|
this.watermarkCapture = options.watermarkCapture;
|
|
30922
31350
|
}
|
|
30923
31351
|
async runDaemon(options = {}) {
|
|
30924
31352
|
if (this.daemonRunning) throw new Error("Engine.runDaemon is already running.");
|
|
30925
31353
|
this.daemonRunning = true;
|
|
30926
31354
|
try {
|
|
30927
|
-
|
|
31355
|
+
let report = await runRootPreflight(this.repo);
|
|
31356
|
+
if (!report.ready) {
|
|
31357
|
+
const repaired = await runRootFastForward(this.repo);
|
|
31358
|
+
if (repaired.kind === "fast_forward") this.logger.info(`[engine] root was behind origin/${this.repo.branch} — fast-forwarded ${repaired.from ?? "(unborn)"} → ${repaired.to}`);
|
|
31359
|
+
report = await runRootPreflight(this.repo);
|
|
31360
|
+
}
|
|
30928
31361
|
if (!report.ready) throw new Error(formatPreflightFailure(this.repo.rootDir, report.issues));
|
|
30929
31362
|
await this.ensureLoaded();
|
|
30930
31363
|
await runEngineLoop(this.buildLoopDeps({
|
|
@@ -30941,10 +31374,24 @@ var Engine = class {
|
|
|
30941
31374
|
}
|
|
30942
31375
|
async runOnce(synthesizerName) {
|
|
30943
31376
|
await this.prepareSynthesizerRun(synthesizerName);
|
|
30944
|
-
|
|
31377
|
+
const config = this.requireConfig();
|
|
31378
|
+
const syncHorizon = await this.syncHorizonCapture();
|
|
31379
|
+
const frontier = (await readCursor(this.repo.rootDir, synthesizerName))?.frontier ?? resolveOldest(config, this.nowDate().getTime());
|
|
31380
|
+
if (syncHorizon === null || !gatePasses({
|
|
31381
|
+
frontier,
|
|
31382
|
+
mode: "manual",
|
|
31383
|
+
syncHorizon,
|
|
31384
|
+
tick: config.tick
|
|
31385
|
+
})) return { kind: "caught_up" };
|
|
31386
|
+
const { record } = await this.runSynthesizerTransaction({
|
|
31387
|
+
syncHorizon,
|
|
30945
31388
|
synthesizerName,
|
|
30946
31389
|
trigger: "manual"
|
|
30947
|
-
})
|
|
31390
|
+
});
|
|
31391
|
+
return {
|
|
31392
|
+
kind: "ran",
|
|
31393
|
+
record
|
|
31394
|
+
};
|
|
30948
31395
|
}
|
|
30949
31396
|
async backfill(synthesizerName, options = {}) {
|
|
30950
31397
|
await this.prepareSynthesizerRun(synthesizerName);
|
|
@@ -30978,32 +31425,43 @@ var Engine = class {
|
|
|
30978
31425
|
getDiscoveryErrors() {
|
|
30979
31426
|
return [...this.discoveryErrors];
|
|
30980
31427
|
}
|
|
31428
|
+
nowDate() {
|
|
31429
|
+
return (this.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
31430
|
+
}
|
|
30981
31431
|
buildLoopDeps(options) {
|
|
30982
31432
|
const rootDir = this.repo.rootDir;
|
|
30983
|
-
const clock = this.now ?? (() => /* @__PURE__ */ new Date());
|
|
30984
31433
|
return {
|
|
31434
|
+
captureSyncHorizon: this.syncHorizonCapture,
|
|
30985
31435
|
listSynthesizers: async () => {
|
|
30986
31436
|
await this.refreshSynthesizers();
|
|
30987
31437
|
const specs = this.listSynthesizers().filter((spec) => options.scopeTo === void 0 || spec.name === options.scopeTo);
|
|
30988
|
-
|
|
30989
|
-
|
|
30990
|
-
|
|
30991
|
-
|
|
31438
|
+
const passNowMs = this.nowDate().getTime();
|
|
31439
|
+
const config = this.requireConfig();
|
|
31440
|
+
return Promise.all(specs.map(async (spec) => {
|
|
31441
|
+
const notBefore = await this.readRateLimitGate(spec.name, passNowMs);
|
|
31442
|
+
return {
|
|
31443
|
+
frontier: (await readCursor(rootDir, spec.name))?.frontier ?? resolveOldest(config, passNowMs),
|
|
31444
|
+
name: spec.name,
|
|
31445
|
+
...notBefore !== void 0 && { notBefore }
|
|
31446
|
+
};
|
|
31447
|
+
}));
|
|
30992
31448
|
},
|
|
30993
|
-
now: () =>
|
|
30994
|
-
runSlice: async (name) => {
|
|
31449
|
+
now: () => this.nowDate().getTime(),
|
|
31450
|
+
runSlice: async (name, syncHorizon) => {
|
|
30995
31451
|
try {
|
|
30996
31452
|
const outcome = await this.runSynthesizerTransaction({
|
|
31453
|
+
syncHorizon,
|
|
30997
31454
|
synthesizerName: name,
|
|
30998
31455
|
trigger: options.trigger
|
|
30999
31456
|
});
|
|
31000
31457
|
options.onSlice?.(outcome);
|
|
31001
31458
|
this.logSliceLag(name, outcome);
|
|
31002
|
-
|
|
31459
|
+
const status = outcome.record.status;
|
|
31460
|
+
return status === "success" ? "advanced" : status === "rate_limited" ? "rate_limited" : "failed";
|
|
31003
31461
|
} catch (error) {
|
|
31004
31462
|
if (error instanceof TransactionLockHeldError) {
|
|
31005
31463
|
this.logger.warn(`[engine] skipping '${name}': ${error.message}`);
|
|
31006
|
-
return
|
|
31464
|
+
return "failed";
|
|
31007
31465
|
}
|
|
31008
31466
|
throw error;
|
|
31009
31467
|
}
|
|
@@ -31011,13 +31469,24 @@ var Engine = class {
|
|
|
31011
31469
|
sleep: (ms) => sleepAbortable(ms, options.signal)
|
|
31012
31470
|
};
|
|
31013
31471
|
}
|
|
31472
|
+
async readRateLimitGate(synthesizerName, nowMs) {
|
|
31473
|
+
const latest = await readLatestRunRecord({
|
|
31474
|
+
rootDir: this.repo.rootDir,
|
|
31475
|
+
synthesizerName
|
|
31476
|
+
});
|
|
31477
|
+
if (latest?.status !== "rate_limited") return void 0;
|
|
31478
|
+
if (latest.rate_limit_resets_at === void 0) return void 0;
|
|
31479
|
+
const resetsAt = isoToMs(latest.rate_limit_resets_at, "rate_limit_resets_at");
|
|
31480
|
+
if (resetsAt <= nowMs) return void 0;
|
|
31481
|
+
this.logger.info(`[engine] '${synthesizerName}' rate limited — usage window resets ${latest.rate_limit_resets_at}; holding runs until then`);
|
|
31482
|
+
return resetsAt;
|
|
31483
|
+
}
|
|
31014
31484
|
logSliceLag(name, outcome) {
|
|
31015
31485
|
if (outcome.record.status !== "success") {
|
|
31016
31486
|
this.logger.warn(`[engine] '${name}' slice did not advance (status=${outcome.record.status})`);
|
|
31017
31487
|
return;
|
|
31018
31488
|
}
|
|
31019
|
-
const
|
|
31020
|
-
const lagMs = Math.max(0, clock().getTime() - outcome.frontier);
|
|
31489
|
+
const lagMs = Math.max(0, this.nowDate().getTime() - outcome.frontier);
|
|
31021
31490
|
const note = `[engine] '${name}' frontier ${formatRelativeAge(lagMs)}`;
|
|
31022
31491
|
if (lagMs > LAG_BEHIND_TICKS * this.requireConfig().tick) this.logger.warn(`${note} — behind`);
|
|
31023
31492
|
else this.logger.info(note);
|
|
@@ -31042,6 +31511,7 @@ var Engine = class {
|
|
|
31042
31511
|
now: this.now,
|
|
31043
31512
|
repo: this.repo,
|
|
31044
31513
|
runIdFactory: this.runIdFactory,
|
|
31514
|
+
syncHorizon: request.syncHorizon,
|
|
31045
31515
|
synthesizer,
|
|
31046
31516
|
trigger: request.trigger,
|
|
31047
31517
|
watermarkCapture: this.watermarkCapture
|
|
@@ -31068,7 +31538,6 @@ var Engine = class {
|
|
|
31068
31538
|
});
|
|
31069
31539
|
return {
|
|
31070
31540
|
frontier: ctx.next.frontier,
|
|
31071
|
-
reachedWallclock: ctx.reachedWallclock,
|
|
31072
31541
|
record
|
|
31073
31542
|
};
|
|
31074
31543
|
} finally {
|
|
@@ -31118,10 +31587,24 @@ function formatPreflightFailure(rootDir, issues) {
|
|
|
31118
31587
|
return `Engine root '${rootDir}' is not ready:\n${issues.map((issue) => ` [${issue.code}] ${issue.message}`).join("\n")}`;
|
|
31119
31588
|
}
|
|
31120
31589
|
function assembleEngineStatus(input) {
|
|
31590
|
+
const observation = input.syncHorizon;
|
|
31591
|
+
const horizon = observation.kind === "captured" ? observation.horizon : null;
|
|
31121
31592
|
const synthesizers = input.synthesizers.map((synthesizer) => {
|
|
31122
|
-
const
|
|
31593
|
+
const frontier = synthesizer.frontier;
|
|
31594
|
+
const lagMs = frontier === null ? null : Math.max(0, input.now - frontier);
|
|
31595
|
+
let horizonGapMs = null;
|
|
31596
|
+
let horizonGapText;
|
|
31597
|
+
if (frontier === null) horizonGapText = "never run";
|
|
31598
|
+
else if (observation.kind === "unavailable") horizonGapText = "control plane unavailable";
|
|
31599
|
+
else if (horizon === null) horizonGapText = "no binding has synced";
|
|
31600
|
+
else {
|
|
31601
|
+
horizonGapMs = Math.max(0, horizon - frontier);
|
|
31602
|
+
horizonGapText = horizonGapMs === 0 ? "caught up to the sync horizon" : `${formatDuration(horizonGapMs)} of synced ground pending`;
|
|
31603
|
+
}
|
|
31123
31604
|
return {
|
|
31124
|
-
frontier:
|
|
31605
|
+
frontier: frontier === null ? null : msToIso(frontier),
|
|
31606
|
+
horizonGapMs,
|
|
31607
|
+
horizonGapText,
|
|
31125
31608
|
lagMs,
|
|
31126
31609
|
lagText: lagMs === null ? "never run" : formatRelativeAge(lagMs),
|
|
31127
31610
|
latestRun: synthesizer.latestRun,
|
|
@@ -31130,21 +31613,37 @@ function assembleEngineStatus(input) {
|
|
|
31130
31613
|
}).sort((left, right) => left.name.localeCompare(right.name));
|
|
31131
31614
|
return {
|
|
31132
31615
|
now: msToIso(input.now),
|
|
31616
|
+
syncHorizon: horizon === null ? null : msToIso(horizon),
|
|
31617
|
+
...observation.kind === "unavailable" && { syncHorizonError: `control plane unavailable: ${observation.error}` },
|
|
31133
31618
|
synthesizers
|
|
31134
31619
|
};
|
|
31135
31620
|
}
|
|
31136
31621
|
async function loadEngineStatus(input) {
|
|
31137
31622
|
const now = input.now ?? Date.now();
|
|
31623
|
+
let syncHorizon;
|
|
31624
|
+
try {
|
|
31625
|
+
syncHorizon = {
|
|
31626
|
+
horizon: await input.syncHorizonCapture(),
|
|
31627
|
+
kind: "captured"
|
|
31628
|
+
};
|
|
31629
|
+
} catch (error) {
|
|
31630
|
+
syncHorizon = {
|
|
31631
|
+
error: error instanceof Error ? error.message : String(error),
|
|
31632
|
+
kind: "unavailable"
|
|
31633
|
+
};
|
|
31634
|
+
}
|
|
31138
31635
|
const discovery = await discoverSynthesizers(path.resolve(input.rootDir, SYNTHESIZERS_DIR_RELATIVE));
|
|
31139
31636
|
const latestByName = latestRunByName(await listRunRecords({ rootDir: input.rootDir }));
|
|
31140
31637
|
const names = discovery.synthesizers.map((synthesizer) => synthesizer.name).filter((name) => input.synthesizerName === void 0 || name === input.synthesizerName);
|
|
31638
|
+
const synthesizers = await Promise.all(names.map(async (name) => ({
|
|
31639
|
+
frontier: (await readCursor(input.rootDir, name))?.frontier ?? null,
|
|
31640
|
+
latestRun: latestByName.get(name) ?? null,
|
|
31641
|
+
name
|
|
31642
|
+
})));
|
|
31141
31643
|
return assembleEngineStatus({
|
|
31142
31644
|
now,
|
|
31143
|
-
|
|
31144
|
-
|
|
31145
|
-
latestRun: latestByName.get(name) ?? null,
|
|
31146
|
-
name
|
|
31147
|
-
})))
|
|
31645
|
+
syncHorizon,
|
|
31646
|
+
synthesizers
|
|
31148
31647
|
});
|
|
31149
31648
|
}
|
|
31150
31649
|
function latestRunByName(entries) {
|
|
@@ -31152,17 +31651,83 @@ function latestRunByName(entries) {
|
|
|
31152
31651
|
for (const { record } of entries) if (!latest.has(record.synthesizer)) latest.set(record.synthesizer, record);
|
|
31153
31652
|
return latest;
|
|
31154
31653
|
}
|
|
31654
|
+
const rateLimitEventSchema = object({
|
|
31655
|
+
rate_limit_info: object({
|
|
31656
|
+
resetsAt: number$1().optional(),
|
|
31657
|
+
status: string().min(1)
|
|
31658
|
+
}),
|
|
31659
|
+
type: literal("rate_limit_event")
|
|
31660
|
+
});
|
|
31661
|
+
const resultEventSchema = object({
|
|
31662
|
+
...claudeResultSchema.shape,
|
|
31663
|
+
type: literal("result")
|
|
31664
|
+
});
|
|
31665
|
+
var ClaudeStreamObserver = class {
|
|
31666
|
+
decoder = new TextDecoder("utf-8", { fatal: false });
|
|
31667
|
+
pendingLine = "";
|
|
31668
|
+
lastRateLimit;
|
|
31669
|
+
result;
|
|
31670
|
+
feed(chunk) {
|
|
31671
|
+
this.pendingLine += this.decoder.decode(chunk, { stream: true });
|
|
31672
|
+
for (;;) {
|
|
31673
|
+
const newlineAt = this.pendingLine.indexOf("\n");
|
|
31674
|
+
if (newlineAt === -1) return;
|
|
31675
|
+
const line = this.pendingLine.slice(0, newlineAt);
|
|
31676
|
+
this.pendingLine = this.pendingLine.slice(newlineAt + 1);
|
|
31677
|
+
this.observeLine(line);
|
|
31678
|
+
}
|
|
31679
|
+
}
|
|
31680
|
+
get resultSeen() {
|
|
31681
|
+
return this.result !== void 0;
|
|
31682
|
+
}
|
|
31683
|
+
observation() {
|
|
31684
|
+
const trailing = this.pendingLine + this.decoder.decode();
|
|
31685
|
+
this.pendingLine = "";
|
|
31686
|
+
if (trailing.length > 0) this.observeLine(trailing);
|
|
31687
|
+
return {
|
|
31688
|
+
...this.lastRateLimit !== void 0 && { lastRateLimit: this.lastRateLimit },
|
|
31689
|
+
...this.result !== void 0 && { result: this.result }
|
|
31690
|
+
};
|
|
31691
|
+
}
|
|
31692
|
+
observeLine(line) {
|
|
31693
|
+
if (line.trim().length === 0) return;
|
|
31694
|
+
let event;
|
|
31695
|
+
try {
|
|
31696
|
+
event = JSON.parse(line);
|
|
31697
|
+
} catch {
|
|
31698
|
+
return;
|
|
31699
|
+
}
|
|
31700
|
+
const rateLimit = rateLimitEventSchema.safeParse(event);
|
|
31701
|
+
if (rateLimit.success) {
|
|
31702
|
+
const { status, resetsAt } = rateLimit.data.rate_limit_info;
|
|
31703
|
+
this.lastRateLimit = {
|
|
31704
|
+
status,
|
|
31705
|
+
...resetsAt !== void 0 && { resetsAt }
|
|
31706
|
+
};
|
|
31707
|
+
return;
|
|
31708
|
+
}
|
|
31709
|
+
const result = resultEventSchema.safeParse(event);
|
|
31710
|
+
if (result.success) {
|
|
31711
|
+
const { type: _type, ...fields } = result.data;
|
|
31712
|
+
this.result = fields;
|
|
31713
|
+
}
|
|
31714
|
+
}
|
|
31715
|
+
};
|
|
31155
31716
|
const GUEST_MEMORY_MIB = 2048;
|
|
31156
31717
|
const EXEC_INACTIVITY_TIMEOUT_MS = 600 * 1e3;
|
|
31157
31718
|
const EXEC_MAX_DURATION_MS = 7200 * 1e3;
|
|
31719
|
+
const EXEC_RESULT_GRACE_MS = 60 * 1e3;
|
|
31158
31720
|
const DRAIN_TIMED_OUT = Symbol("drain-timed-out");
|
|
31159
31721
|
async function drainExecStream(handle, options) {
|
|
31722
|
+
const observer = new ClaudeStreamObserver();
|
|
31160
31723
|
const startedAt = Date.now();
|
|
31161
31724
|
let lastEventAt = startedAt;
|
|
31725
|
+
let resultSeenAt;
|
|
31162
31726
|
for (;;) {
|
|
31163
31727
|
const ceilingDeadline = startedAt + options.maxDurationMs;
|
|
31164
31728
|
const inactivityDeadline = lastEventAt + options.inactivityMs;
|
|
31165
|
-
const
|
|
31729
|
+
const graceDeadline = resultSeenAt === void 0 ? Number.POSITIVE_INFINITY : resultSeenAt + options.resultGraceMs;
|
|
31730
|
+
const deadline = Math.min(ceilingDeadline, inactivityDeadline, graceDeadline);
|
|
31166
31731
|
let timer;
|
|
31167
31732
|
const timedOut = new Promise((resolve) => {
|
|
31168
31733
|
timer = setTimeout(() => resolve(DRAIN_TIMED_OUT), Math.max(0, deadline - Date.now()));
|
|
@@ -31176,17 +31741,31 @@ async function drainExecStream(handle, options) {
|
|
|
31176
31741
|
}
|
|
31177
31742
|
if (settled === DRAIN_TIMED_OUT) {
|
|
31178
31743
|
pending.catch(() => {});
|
|
31744
|
+
const observation = observer.observation();
|
|
31745
|
+
if (observation.result !== void 0) return {
|
|
31746
|
+
kind: "result_no_exit",
|
|
31747
|
+
observation,
|
|
31748
|
+
result: observation.result
|
|
31749
|
+
};
|
|
31179
31750
|
return {
|
|
31180
31751
|
kind: "timed_out",
|
|
31752
|
+
observation,
|
|
31181
31753
|
reason: ceilingDeadline <= inactivityDeadline ? "max_duration" : "inactivity"
|
|
31182
31754
|
};
|
|
31183
31755
|
}
|
|
31184
|
-
if (settled === null) return {
|
|
31756
|
+
if (settled === null) return {
|
|
31757
|
+
kind: "ended",
|
|
31758
|
+
observation: observer.observation()
|
|
31759
|
+
};
|
|
31185
31760
|
lastEventAt = Date.now();
|
|
31186
31761
|
if (settled.kind === "stderr") options.onStderr(settled.data);
|
|
31187
|
-
else if (settled.kind === "
|
|
31762
|
+
else if (settled.kind === "stdout") {
|
|
31763
|
+
observer.feed(settled.data);
|
|
31764
|
+
if (resultSeenAt === void 0 && observer.resultSeen) resultSeenAt = lastEventAt;
|
|
31765
|
+
} else if (settled.kind === "exited") return {
|
|
31188
31766
|
exitCode: settled.code,
|
|
31189
|
-
kind: "exited"
|
|
31767
|
+
kind: "exited",
|
|
31768
|
+
observation: observer.observation()
|
|
31190
31769
|
};
|
|
31191
31770
|
}
|
|
31192
31771
|
}
|
|
@@ -31196,6 +31775,7 @@ var MicrosandboxClaudeExecutor = class {
|
|
|
31196
31775
|
const runPlan = buildMicrosandboxClaudeRunPlan(input);
|
|
31197
31776
|
const stderrParts = [];
|
|
31198
31777
|
let exitCode = 1;
|
|
31778
|
+
let observation = {};
|
|
31199
31779
|
let sandbox = null;
|
|
31200
31780
|
let authMaterial = null;
|
|
31201
31781
|
try {
|
|
@@ -31222,11 +31802,16 @@ var MicrosandboxClaudeExecutor = class {
|
|
|
31222
31802
|
const drained = await drainExecStream(await sandbox.execStreamWith(cmd, (e) => e.args(args)), {
|
|
31223
31803
|
inactivityMs: EXEC_INACTIVITY_TIMEOUT_MS,
|
|
31224
31804
|
maxDurationMs: EXEC_MAX_DURATION_MS,
|
|
31225
|
-
onStderr: (data) => stderrParts.push(stderrDecoder.decode(data, { stream: true }))
|
|
31805
|
+
onStderr: (data) => stderrParts.push(stderrDecoder.decode(data, { stream: true })),
|
|
31806
|
+
resultGraceMs: EXEC_RESULT_GRACE_MS
|
|
31226
31807
|
});
|
|
31227
31808
|
stderrParts.push(stderrDecoder.decode());
|
|
31809
|
+
observation = drained.observation;
|
|
31228
31810
|
if (drained.kind === "exited") exitCode = drained.exitCode;
|
|
31229
|
-
else if (drained.kind === "
|
|
31811
|
+
else if (drained.kind === "result_no_exit") {
|
|
31812
|
+
exitCode = drained.result.is_error ? 1 : 0;
|
|
31813
|
+
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`);
|
|
31814
|
+
} else if (drained.kind === "timed_out") {
|
|
31230
31815
|
exitCode = 124;
|
|
31231
31816
|
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
31817
|
}
|
|
@@ -31254,6 +31839,7 @@ var MicrosandboxClaudeExecutor = class {
|
|
|
31254
31839
|
}
|
|
31255
31840
|
return {
|
|
31256
31841
|
exitCode,
|
|
31842
|
+
observation,
|
|
31257
31843
|
stderr: stderrParts.join("")
|
|
31258
31844
|
};
|
|
31259
31845
|
}
|
|
@@ -31339,53 +31925,6 @@ function applyRegistry(builder, value) {
|
|
|
31339
31925
|
return r;
|
|
31340
31926
|
});
|
|
31341
31927
|
}
|
|
31342
|
-
async function runRootRepair(repo) {
|
|
31343
|
-
await assertGitCheckout(repo);
|
|
31344
|
-
const branch = await inspectBranchReadiness(repo);
|
|
31345
|
-
const tree = await inspectWorkingTree(repo);
|
|
31346
|
-
if (branch.kind === "no_origin") throw new Error("RootRepair requires 'origin' to be configured in remote mode. Provisioning must add origin before repair.");
|
|
31347
|
-
if (branch.kind === "local_head_without_remote_main") throw new Error(`RootRepair refuses to act: local HEAD is at ${branch.localSha} but origin/${repo.branch} does not exist. Operator must reconcile manually.`);
|
|
31348
|
-
const needsFastForward = branch.kind === "local_unborn_remote_has_main" || branch.kind === "remote_mismatch";
|
|
31349
|
-
if (needsFastForward && !tree.clean) throw new Error(formatCombinedRepairError(repo, branch, tree));
|
|
31350
|
-
if (needsFastForward) return {
|
|
31351
|
-
kind: "fast_forward",
|
|
31352
|
-
...await fastForwardRoot(repo)
|
|
31353
|
-
};
|
|
31354
|
-
if (!tree.clean) return await runDirtyRootRepair(repo);
|
|
31355
|
-
return { kind: "no_op" };
|
|
31356
|
-
}
|
|
31357
|
-
async function runDirtyRootRepair(repo) {
|
|
31358
|
-
await repairDirtyRoot(repo);
|
|
31359
|
-
const interruptedRunIds = (await markInterruptedRuns(repo.rootDir)).map((record) => record.run_id);
|
|
31360
|
-
if ((await inspectWorkingTree(repo)).clean) return {
|
|
31361
|
-
commit: null,
|
|
31362
|
-
interruptedRunIds,
|
|
31363
|
-
kind: "dirty_root_repair"
|
|
31364
|
-
};
|
|
31365
|
-
const { sha } = await commitRootRepair(repo, {
|
|
31366
|
-
interruptedRunIds,
|
|
31367
|
-
repairId: v7()
|
|
31368
|
-
});
|
|
31369
|
-
await pushToOrigin(repo);
|
|
31370
|
-
return {
|
|
31371
|
-
commit: {
|
|
31372
|
-
pushed: repo.mode === "remote",
|
|
31373
|
-
sha
|
|
31374
|
-
},
|
|
31375
|
-
interruptedRunIds,
|
|
31376
|
-
kind: "dirty_root_repair"
|
|
31377
|
-
};
|
|
31378
|
-
}
|
|
31379
|
-
function formatCombinedRepairError(repo, branch, tree) {
|
|
31380
|
-
const dirtyPaths = tree.clean ? "(clean)" : formatWorkingTreePaths(tree.paths);
|
|
31381
|
-
return [
|
|
31382
|
-
"RootRepair refuses to combine branch fast-forward with dirty-root repair in v1.",
|
|
31383
|
-
`Branch: ${branch.kind === "local_unborn_remote_has_main" ? `local checkout is unborn but origin/${repo.branch} exists` : branch.kind === "remote_mismatch" ? `local HEAD does not match origin/${repo.branch}` : `branch state is '${branch.kind}'`}.`,
|
|
31384
|
-
"Dirty paths:",
|
|
31385
|
-
dirtyPaths,
|
|
31386
|
-
"Operator must inspect and choose the order manually."
|
|
31387
|
-
].join("\n");
|
|
31388
|
-
}
|
|
31389
31928
|
const RESERVED_OUTPUT_SUBDIRS = new Set(["types", "views"]);
|
|
31390
31929
|
const OUTPUT_DIR_RELATIVE = "output";
|
|
31391
31930
|
const CURSORS_DIR_RELATIVE = ".engine/cursors";
|
|
@@ -31433,6 +31972,26 @@ function formatNotReadyError(repo, issues) {
|
|
|
31433
31972
|
"Commit your authored config (or run 'ctxe repair'), or pass --force to reset anyway."
|
|
31434
31973
|
].join("\n");
|
|
31435
31974
|
}
|
|
31975
|
+
function foldSyncHorizon(response) {
|
|
31976
|
+
let horizon = null;
|
|
31977
|
+
for (const [bindingId, state] of Object.entries(response.bindings)) {
|
|
31978
|
+
if (state.frontier === null) continue;
|
|
31979
|
+
const ms = isoToMs(state.frontier, `binding ${bindingId} frontier`);
|
|
31980
|
+
if (horizon === null || ms < horizon) horizon = ms;
|
|
31981
|
+
}
|
|
31982
|
+
return horizon;
|
|
31983
|
+
}
|
|
31984
|
+
async function captureSyncHorizon(input) {
|
|
31985
|
+
const fetchImpl = input.fetchImpl ?? globalThis.fetch;
|
|
31986
|
+
const url = new URL("/api/v1/state", input.controlPlaneUrl);
|
|
31987
|
+
url.searchParams.set("root_dir", input.contextBaseRootDir);
|
|
31988
|
+
const response = await fetchImpl(url);
|
|
31989
|
+
if (!response.ok) {
|
|
31990
|
+
const body = await response.text();
|
|
31991
|
+
throw new Error(`Sync horizon request to ${url.toString()} failed: ${response.status} ${response.statusText} — ${body}`);
|
|
31992
|
+
}
|
|
31993
|
+
return foldSyncHorizon(bindingStateResponseSchema.parse(await response.json()));
|
|
31994
|
+
}
|
|
31436
31995
|
const SOURCE_UPDATED_AT_COLUMN = "_ctx_source_updated_at";
|
|
31437
31996
|
async function captureWatermark(input) {
|
|
31438
31997
|
const sql = src_default(input.databaseUrl);
|
|
@@ -31497,11 +32056,17 @@ function quoteIdentifier(identifier) {
|
|
|
31497
32056
|
//#endregion
|
|
31498
32057
|
//#region env.ts
|
|
31499
32058
|
const nonEmptyStringSchema = string().trim().min(1);
|
|
32059
|
+
const LOCAL_CONTROL_PLANE_HOST = "127.0.0.1";
|
|
31500
32060
|
const envSchema = object({
|
|
32061
|
+
CTXB_CONTROL_PLANE_PORT: number().int().min(1).max(65535).default(3999),
|
|
31501
32062
|
CTXB_DATABASE_URL: nonEmptyStringSchema.optional(),
|
|
32063
|
+
CTXB_ROOT_DIR: nonEmptyStringSchema.optional(),
|
|
31502
32064
|
CTXE_GIT_MODE: _enum(["local", "remote"]).default("remote"),
|
|
31503
32065
|
CTXE_ROOT_DIR: nonEmptyStringSchema.optional()
|
|
31504
|
-
})
|
|
32066
|
+
}).transform((input) => ({
|
|
32067
|
+
...input,
|
|
32068
|
+
CTXB_CONTROL_PLANE_URL: new URL(`http://${LOCAL_CONTROL_PLANE_HOST}:${input.CTXB_CONTROL_PLANE_PORT}`).toString().replace(/\/+$/, "")
|
|
32069
|
+
}));
|
|
31505
32070
|
function parseEngineCliEnv(rawEnv) {
|
|
31506
32071
|
return envSchema.parse(rawEnv);
|
|
31507
32072
|
}
|
|
@@ -31509,6 +32074,13 @@ const env = parseEngineCliEnv(process.env);
|
|
|
31509
32074
|
|
|
31510
32075
|
//#endregion
|
|
31511
32076
|
//#region commands/build-engine.ts
|
|
32077
|
+
function buildSyncHorizonCapture(paths) {
|
|
32078
|
+
const contextBaseRootDir = env.CTXB_ROOT_DIR ?? paths.rootDir;
|
|
32079
|
+
return async () => captureSyncHorizon({
|
|
32080
|
+
contextBaseRootDir,
|
|
32081
|
+
controlPlaneUrl: env.CTXB_CONTROL_PLANE_URL
|
|
32082
|
+
});
|
|
32083
|
+
}
|
|
31512
32084
|
function buildEngine(input) {
|
|
31513
32085
|
const watermarkCapture = async () => captureWatermark({ databaseUrl: input.databaseUrl });
|
|
31514
32086
|
return new Engine({
|
|
@@ -31516,6 +32088,7 @@ function buildEngine(input) {
|
|
|
31516
32088
|
executor: new MicrosandboxClaudeExecutor(),
|
|
31517
32089
|
git: { mode: env.CTXE_GIT_MODE },
|
|
31518
32090
|
rootDir: input.paths.rootDir,
|
|
32091
|
+
syncHorizonCapture: buildSyncHorizonCapture(input.paths),
|
|
31519
32092
|
watermarkCapture
|
|
31520
32093
|
});
|
|
31521
32094
|
}
|
|
@@ -31556,9 +32129,10 @@ async function runEngineListCommand(paths) {
|
|
|
31556
32129
|
process.stdout.write(`${formatJsonOutput(output)}\n`);
|
|
31557
32130
|
if (output.errors.length > 0) process.exitCode = 1;
|
|
31558
32131
|
}
|
|
31559
|
-
async function runEngineStatusCommand(synthesizerName, paths) {
|
|
32132
|
+
async function runEngineStatusCommand(synthesizerName, paths, syncHorizonCapture) {
|
|
31560
32133
|
const status = await loadEngineStatus({
|
|
31561
32134
|
rootDir: paths.rootDir,
|
|
32135
|
+
syncHorizonCapture,
|
|
31562
32136
|
...synthesizerName ? { synthesizerName } : {}
|
|
31563
32137
|
});
|
|
31564
32138
|
process.stdout.write(`${formatJsonOutput(status)}\n`);
|
|
@@ -31590,7 +32164,7 @@ async function runBackfillCommand(input) {
|
|
|
31590
32164
|
...summary,
|
|
31591
32165
|
finalFrontier: summary.finalFrontier === null ? null : msToIso(summary.finalFrontier)
|
|
31592
32166
|
})}\n`);
|
|
31593
|
-
if (summary.stopReason === "stalled") process.exitCode = 1;
|
|
32167
|
+
if (summary.stopReason === "stalled" || summary.stopReason === "rate_limited") process.exitCode = 1;
|
|
31594
32168
|
}
|
|
31595
32169
|
|
|
31596
32170
|
//#endregion
|
|
@@ -31634,12 +32208,16 @@ async function runResetCommand(input) {
|
|
|
31634
32208
|
//#endregion
|
|
31635
32209
|
//#region commands/run.ts
|
|
31636
32210
|
async function runRunCommand(input) {
|
|
31637
|
-
const
|
|
32211
|
+
const outcome = await buildEngine({
|
|
31638
32212
|
databaseUrl: resolveDatabaseUrl({ cliValue: input.databaseUrl }),
|
|
31639
32213
|
paths: input.paths
|
|
31640
32214
|
}).runOnce(input.synthesizerName);
|
|
31641
|
-
|
|
31642
|
-
|
|
32215
|
+
if (outcome.kind === "caught_up") {
|
|
32216
|
+
process.stdout.write(`${formatJsonOutput({ status: "caught_up" })}\n`);
|
|
32217
|
+
return;
|
|
32218
|
+
}
|
|
32219
|
+
process.stdout.write(`${formatJsonOutput(outcome.record)}\n`);
|
|
32220
|
+
if (outcome.record.status !== "success") process.exitCode = 1;
|
|
31643
32221
|
}
|
|
31644
32222
|
|
|
31645
32223
|
//#endregion
|
|
@@ -31721,8 +32299,9 @@ function createProgram() {
|
|
|
31721
32299
|
program.command("list").description("List synthesizers").action(async function() {
|
|
31722
32300
|
await runEngineListCommand(resolveRuntimePaths(this));
|
|
31723
32301
|
});
|
|
31724
|
-
program.command("status").argument("[synthesizer]", "Only show this synthesizer").description("Print each synthesizer's freshness as JSON: its frontier (the source-time its cursor has reached), how far that lags behind now, and its latest run.").action(async function(synthesizerName) {
|
|
31725
|
-
|
|
32302
|
+
program.command("status").argument("[synthesizer]", "Only show this synthesizer").description("Print each synthesizer's freshness as JSON: its frontier (the source-time its cursor has reached), how far that lags behind now (output staleness), how much confirmed-synced ground is still pending below the sync horizon (whether the engine is keeping up — the planner's own measure), and its latest run.").action(async function(synthesizerName) {
|
|
32303
|
+
const paths = resolveRuntimePaths(this);
|
|
32304
|
+
await runEngineStatusCommand(synthesizerName, paths, buildSyncHorizonCapture(paths));
|
|
31726
32305
|
});
|
|
31727
32306
|
program.command("logs").argument("<synthesizer>", "Synthesizer name").option("--run-id <id>", "Print stderr for a specific run id").description("Print the engine's per-run stderr for a synthesizer run. The Claude session transcript is a separate file at <rootDir>/.claude/projects/<claude-encoded-rootDir>/<runId>.jsonl, where <claude-encoded-rootDir> is Claude Code's own cwd-derived project key (the guest workdir mirrors the host rootDir, so the key matches what host Claude produces in the same directory). The run id and the Claude --session-id are the same UUIDv7 value.").action(async function(synthesizerName, options) {
|
|
31728
32307
|
await runEngineLogsCommand(synthesizerName, options, resolveRuntimePaths(this));
|
|
@@ -31740,14 +32319,14 @@ function createProgram() {
|
|
|
31740
32319
|
yes: options.yes ?? false
|
|
31741
32320
|
});
|
|
31742
32321
|
});
|
|
31743
|
-
program.command("run").argument("<synthesizer>", "Synthesizer name").option("--database-url <url>", "Postgres URL of the ContextBase database the synthesizer reads from. Falls back to CTXB_DATABASE_URL.").description("Run a single synthesizer once.
|
|
32322
|
+
program.command("run").argument("<synthesizer>", "Synthesizer name").option("--database-url <url>", "Postgres URL of the ContextBase database the synthesizer reads from. Falls back to CTXB_DATABASE_URL.").description("Run a single synthesizer once. Prints caught_up and exits zero when there is no new synced ground; exits non-zero on any non-success run (failed, timed-out, or rate-limited).").action(async function(synthesizerName, options) {
|
|
31744
32323
|
await runRunCommand({
|
|
31745
32324
|
databaseUrl: options.databaseUrl,
|
|
31746
32325
|
paths: resolveRuntimePaths(this),
|
|
31747
32326
|
synthesizerName
|
|
31748
32327
|
});
|
|
31749
32328
|
});
|
|
31750
|
-
program.command("backfill").argument("<synthesizer>", "Synthesizer name").option("--database-url <url>", "Postgres URL of the ContextBase database the synthesizer reads from. Falls back to CTXB_DATABASE_URL.").description("Walk a synthesizer's cursor forward slice-by-slice until it catches up to
|
|
32329
|
+
program.command("backfill").argument("<synthesizer>", "Synthesizer name").option("--database-url <url>", "Postgres URL of the ContextBase database the synthesizer reads from. Falls back to CTXB_DATABASE_URL.").description("Walk a synthesizer's cursor forward slice-by-slice until it catches up to the sync horizon. The same loop the daemon runs, without the sleep. Streams each slice's run record; prints a summary; exits non-zero if a slice fails or the usage window is rate-limited.").action(async function(synthesizerName, options) {
|
|
31751
32330
|
await runBackfillCommand({
|
|
31752
32331
|
databaseUrl: options.databaseUrl,
|
|
31753
32332
|
paths: resolveRuntimePaths(this),
|
|
@@ -31783,4 +32362,4 @@ runCli().catch((error) => {
|
|
|
31783
32362
|
//#endregion
|
|
31784
32363
|
export { createProgram, resolveRepoContext, resolveRuntimePaths, runCli };
|
|
31785
32364
|
//# sourceMappingURL=cli.mjs.map
|
|
31786
|
-
//# debugId=
|
|
32365
|
+
//# debugId=ee0e5987-2fbc-50ed-9038-a0c4541b7548
|