@usecontextlayer/ctxe 0.4.5 → 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 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]="1a858cd0-cb9a-550b-a3f9-5ca9387cf7df")}catch(e){}}();
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.5";
62
+ var version$1 = "0.4.6";
63
63
 
64
64
  //#endregion
65
65
  //#region sentry.ts
@@ -7894,7 +7894,7 @@ const string$1 = (params) => {
7894
7894
  return new RegExp(`^${regex}$`);
7895
7895
  };
7896
7896
  const integer = /^-?\d+$/;
7897
- const number$1 = /^-?\d+(?:\.\d+)?$/;
7897
+ const number$2 = /^-?\d+(?:\.\d+)?$/;
7898
7898
  const boolean$1 = /^(?:true|false)$/i;
7899
7899
  const lowercase = /^[^A-Z]*$/;
7900
7900
  const uppercase = /^[^a-z]*$/;
@@ -8672,7 +8672,7 @@ const $ZodJWT = /*@__PURE__*/ $constructor("$ZodJWT", (inst, def) => {
8672
8672
  });
8673
8673
  const $ZodNumber = /*@__PURE__*/ $constructor("$ZodNumber", (inst, def) => {
8674
8674
  $ZodType.init(inst, def);
8675
- inst._zod.pattern = inst._zod.bag.pattern ?? number$1;
8675
+ inst._zod.pattern = inst._zod.bag.pattern ?? number$2;
8676
8676
  inst._zod.parse = (payload, _ctx) => {
8677
8677
  if (def.coerce) try {
8678
8678
  payload.value = Number(payload.value);
@@ -9057,6 +9057,62 @@ const $ZodUnion = /*@__PURE__*/ $constructor("$ZodUnion", (inst, def) => {
9057
9057
  });
9058
9058
  };
9059
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
+ });
9060
9116
  const $ZodIntersection = /*@__PURE__*/ $constructor("$ZodIntersection", (inst, def) => {
9061
9117
  $ZodType.init(inst, def);
9062
9118
  inst._zod.parse = (payload, ctx) => {
@@ -9227,7 +9283,7 @@ const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => {
9227
9283
  issues: []
9228
9284
  }, ctx);
9229
9285
  if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently");
9230
- if (typeof key === "string" && number$1.test(key) && keyResult.issues.length) {
9286
+ if (typeof key === "string" && number$2.test(key) && keyResult.issues.length) {
9231
9287
  const retryResult = def.keyType._zod.run({
9232
9288
  value: Number(key),
9233
9289
  issues: []
@@ -9864,6 +9920,15 @@ function _number(Class, params) {
9864
9920
  });
9865
9921
  }
9866
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__
9867
9932
  function _int(Class, params) {
9868
9933
  return new Class({
9869
9934
  type: "number",
@@ -11108,7 +11173,7 @@ const ZodNumber = /*@__PURE__*/ $constructor("ZodNumber", (inst, def) => {
11108
11173
  inst.isFinite = true;
11109
11174
  inst.format = bag.format ?? null;
11110
11175
  });
11111
- function number(params) {
11176
+ function number$1(params) {
11112
11177
  return _number(ZodNumber, params);
11113
11178
  }
11114
11179
  const ZodNumberFormat = /*@__PURE__*/ $constructor("ZodNumberFormat", (inst, def) => {
@@ -11247,6 +11312,14 @@ function strictObject(shape, params) {
11247
11312
  ...normalizeParams(params)
11248
11313
  });
11249
11314
  }
11315
+ function looseObject(shape, params) {
11316
+ return new ZodObject({
11317
+ type: "object",
11318
+ shape,
11319
+ catchall: unknown(),
11320
+ ...normalizeParams(params)
11321
+ });
11322
+ }
11250
11323
  const ZodUnion = /*@__PURE__*/ $constructor("ZodUnion", (inst, def) => {
11251
11324
  $ZodUnion.init(inst, def);
11252
11325
  ZodType.init(inst, def);
@@ -11260,6 +11333,18 @@ function union(options, params) {
11260
11333
  ...normalizeParams(params)
11261
11334
  });
11262
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
+ }
11263
11348
  const ZodIntersection = /*@__PURE__*/ $constructor("ZodIntersection", (inst, def) => {
11264
11349
  $ZodIntersection.init(inst, def);
11265
11350
  ZodType.init(inst, def);
@@ -11513,6 +11598,12 @@ function superRefine(fn, params) {
11513
11598
  return _superRefine(fn, params);
11514
11599
  }
11515
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
+
11516
11607
  //#endregion
11517
11608
  //#region ../../node_modules/.pnpm/is-plain-obj@4.1.0/node_modules/is-plain-obj/index.js
11518
11609
  function isPlainObject(value) {
@@ -17835,6 +17926,74 @@ const execaNode = createExeca(mapNode);
17835
17926
  const $ = createExeca(mapScriptAsync, {}, deepScriptOptions, setScriptSync);
17836
17927
  const { sendMessage, getOneMessage, getEachMessage, getCancelSignal } = getIpcExport();
17837
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
+
17838
17997
  //#endregion
17839
17998
  //#region ../../node_modules/.pnpm/kind-of@6.0.3/node_modules/kind-of/index.js
17840
17999
  var require_kind_of = /* @__PURE__ */ __commonJSMin(((exports, module) => {
@@ -26061,74 +26220,6 @@ var require_gray_matter = /* @__PURE__ */ __commonJSMin(((exports, module) => {
26061
26220
  module.exports = matter;
26062
26221
  }));
26063
26222
 
26064
- //#endregion
26065
- //#region ../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/rng.js
26066
- const rnds8 = new Uint8Array(16);
26067
- function rng() {
26068
- return crypto.getRandomValues(rnds8);
26069
- }
26070
-
26071
- //#endregion
26072
- //#region ../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/stringify.js
26073
- const byteToHex = [];
26074
- for (let i = 0; i < 256; ++i) byteToHex.push((i + 256).toString(16).slice(1));
26075
- function unsafeStringify(arr, offset = 0) {
26076
- 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();
26077
- }
26078
-
26079
- //#endregion
26080
- //#region ../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/v7.js
26081
- const _state = {};
26082
- function v7(options, buf, offset) {
26083
- let bytes;
26084
- if (options) bytes = v7Bytes(options.random ?? options.rng?.() ?? rng(), options.msecs, options.seq, buf, offset);
26085
- else {
26086
- const now = Date.now();
26087
- const rnds = rng();
26088
- updateV7State(_state, now, rnds);
26089
- bytes = v7Bytes(rnds, _state.msecs, _state.seq, buf, offset);
26090
- }
26091
- return buf ?? unsafeStringify(bytes);
26092
- }
26093
- function updateV7State(state, now, rnds) {
26094
- state.msecs ??= -Infinity;
26095
- state.seq ??= 0;
26096
- if (now > state.msecs) {
26097
- state.seq = rnds[6] << 23 | rnds[7] << 16 | rnds[8] << 8 | rnds[9];
26098
- state.msecs = now;
26099
- } else {
26100
- state.seq = state.seq + 1 | 0;
26101
- if (state.seq === 0) state.msecs++;
26102
- }
26103
- return state;
26104
- }
26105
- function v7Bytes(rnds, msecs, seq, buf, offset = 0) {
26106
- if (rnds.length < 16) throw new Error("Random bytes length must be >= 16");
26107
- if (!buf) {
26108
- buf = new Uint8Array(16);
26109
- offset = 0;
26110
- } else if (offset < 0 || offset + 16 > buf.length) throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
26111
- msecs ??= Date.now();
26112
- seq ??= rnds[6] * 127 << 24 | rnds[7] << 16 | rnds[8] << 8 | rnds[9];
26113
- buf[offset++] = msecs / 1099511627776 & 255;
26114
- buf[offset++] = msecs / 4294967296 & 255;
26115
- buf[offset++] = msecs / 16777216 & 255;
26116
- buf[offset++] = msecs / 65536 & 255;
26117
- buf[offset++] = msecs / 256 & 255;
26118
- buf[offset++] = msecs & 255;
26119
- buf[offset++] = 112 | seq >>> 28 & 15;
26120
- buf[offset++] = seq >>> 20 & 255;
26121
- buf[offset++] = 128 | seq >>> 14 & 63;
26122
- buf[offset++] = seq >>> 6 & 255;
26123
- buf[offset++] = seq << 2 & 255 | rnds[10] & 3;
26124
- buf[offset++] = rnds[11];
26125
- buf[offset++] = rnds[12];
26126
- buf[offset++] = rnds[13];
26127
- buf[offset++] = rnds[14];
26128
- buf[offset++] = rnds[15];
26129
- return buf;
26130
- }
26131
-
26132
26223
  //#endregion
26133
26224
  //#region ../../node_modules/.pnpm/graceful-fs@4.2.11/node_modules/graceful-fs/polyfills.js
26134
26225
  var require_polyfills = /* @__PURE__ */ __commonJSMin(((exports, module) => {
@@ -27490,9 +27581,113 @@ var require_proper_lockfile = /* @__PURE__ */ __commonJSMin(((exports, module) =
27490
27581
  }));
27491
27582
 
27492
27583
  //#endregion
27493
- //#region ../../node_modules/.pnpm/postgres@3.4.9/node_modules/postgres/src/query.js
27584
+ //#region ../base-schemas/dist/index.mjs
27494
27585
  var import_gray_matter = /* @__PURE__ */ __toESM(require_gray_matter(), 1);
27495
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
27496
27691
  const originCache = /* @__PURE__ */ new Map(), originStackCache = /* @__PURE__ */ new Map(), originError = Symbol("OriginError");
27497
27692
  const CLOSE = {};
27498
27693
  var Query = class extends Promise {
@@ -29583,7 +29778,7 @@ function validate(raw, sourcePath) {
29583
29778
  }
29584
29779
  function applyDefaults(input) {
29585
29780
  return {
29586
- synthesizerImage: input.synthesizerImage ?? "ghcr.io/usecontextlayer/ctx-sandbox:0.4.5",
29781
+ synthesizerImage: input.synthesizerImage ?? "ghcr.io/usecontextlayer/ctx-sandbox:0.4.6",
29587
29782
  ...input.microsandbox !== void 0 ? { microsandbox: input.microsandbox } : {},
29588
29783
  ...input.oldestConsideredPoint !== void 0 ? { oldestConsideredPoint: input.oldestConsideredPoint } : {},
29589
29784
  maxSliceSize: input.maxSliceSize ?? 864e5,
@@ -29599,45 +29794,65 @@ function formatZodError$1(error) {
29599
29794
  return `${issue.path.length > 0 ? issue.path.join(".") : "root"}: ${issue.message}`;
29600
29795
  }).join("; ");
29601
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
+ }
29602
29802
  function planLoopPass(input) {
29603
- const frontierDue = input.synthesizers.filter((synthesizer) => input.now - synthesizer.frontier >= input.tick);
29604
- const due = frontierDue.filter((synthesizer) => synthesizer.notBefore === void 0 || synthesizer.notBefore <= input.now);
29605
- if (due.length > 0) return {
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 {
29606
29812
  kind: "run",
29607
- order: due.map((synthesizer) => synthesizer.name).sort()
29813
+ order: due.map((synthesizer) => synthesizer.name).sort(),
29814
+ syncHorizon: horizon
29608
29815
  };
29609
- const gates = frontierDue.map((synthesizer) => synthesizer.notBefore).filter((notBefore) => notBefore !== void 0);
29610
- const gatedUntil = gates.length > 0 ? Math.min(...gates) : void 0;
29816
+ const held = new Set(horizonDue);
29611
29817
  return {
29612
29818
  kind: "idle",
29613
- wakeAt: input.synthesizers.length === 0 ? input.now + input.tick : Math.min(...input.synthesizers.map((synthesizer) => Math.max(synthesizer.frontier + input.tick, synthesizer.notBefore ?? 0))),
29614
- ...gatedUntil !== void 0 && { gatedUntil }
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"
29615
29831
  };
29616
29832
  }
29617
29833
  async function runEngineLoop(deps, options) {
29618
29834
  for (;;) {
29619
29835
  if (options.signal?.aborted) return { stopReason: "aborted" };
29620
- const synthesizers = await deps.listSynthesizers();
29836
+ const [syncHorizon, synthesizers] = await Promise.all([deps.captureSyncHorizon(), deps.listSynthesizers()]);
29621
29837
  const pass = planLoopPass({
29622
29838
  now: deps.now(),
29839
+ syncHorizon,
29623
29840
  synthesizers,
29624
29841
  tick: options.tick
29625
29842
  });
29626
29843
  if (pass.kind === "idle") {
29627
- if (options.mode === "backfill") return { stopReason: pass.gatedUntil !== void 0 ? "rate_limited" : "caught_up" };
29844
+ if (options.mode === "backfill") return { stopReason: pass.reason };
29628
29845
  await deps.sleep(Math.max(0, pass.wakeAt - deps.now()));
29629
29846
  continue;
29630
29847
  }
29631
- let advancedAny = false;
29632
- let rateLimitedAny = false;
29848
+ const results = [];
29633
29849
  for (const name of pass.order) {
29634
29850
  if (options.signal?.aborted) return { stopReason: "aborted" };
29635
- const outcome = await deps.runSlice(name);
29636
- if (outcome.advanced) advancedAny = true;
29637
- if (outcome.rateLimited) rateLimitedAny = true;
29851
+ results.push(await deps.runSlice(name, pass.syncHorizon));
29638
29852
  }
29639
- if (!advancedAny) {
29640
- if (options.mode === "backfill") return { stopReason: rateLimitedAny ? "rate_limited" : "stalled" };
29853
+ const conclusion = concludeLoopPass(results);
29854
+ if (conclusion.kind === "blocked") {
29855
+ if (options.mode === "backfill") return { stopReason: conclusion.reason };
29641
29856
  await deps.sleep(options.tick);
29642
29857
  }
29643
29858
  }
@@ -29961,6 +30176,18 @@ function formatRelativeAge(ms) {
29961
30176
  }
29962
30177
  return rtf.format(-Math.round(value), "year");
29963
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
+ }
29964
30191
  async function runRootPreflight(repo) {
29965
30192
  await assertGitCheckout(repo);
29966
30193
  const branch = await inspectBranchReadiness(repo);
@@ -30025,18 +30252,18 @@ const runStatusSchema = _enum([
30025
30252
  "interrupted"
30026
30253
  ]);
30027
30254
  const claudeResultSchema = strictObject({
30028
- api_error_status: number().int().optional(),
30255
+ api_error_status: number$1().int().optional(),
30029
30256
  is_error: boolean(),
30030
- num_turns: number().int(),
30257
+ num_turns: number$1().int(),
30031
30258
  subtype: string().min(1),
30032
30259
  terminal_reason: string().min(1).optional(),
30033
- total_cost_usd: number()
30260
+ total_cost_usd: number$1()
30034
30261
  });
30035
30262
  const runRecordSchema = strictObject({
30036
30263
  claude_result: claudeResultSchema.optional(),
30037
30264
  completed_at: string().min(1).optional(),
30038
- duration_ms: number().int().nonnegative().optional(),
30039
- exit_code: number().int().optional(),
30265
+ duration_ms: number$1().int().nonnegative().optional(),
30266
+ exit_code: number$1().int().optional(),
30040
30267
  rate_limit_resets_at: string().min(1).optional(),
30041
30268
  run_id: string().min(1),
30042
30269
  started_at: string().min(1),
@@ -30098,6 +30325,24 @@ async function readRunRecord(runDir) {
30098
30325
  const raw = await readFile(path.join(runDir, RECORD_FILE_NAME), "utf8");
30099
30326
  return runRecordSchema.parse(JSON.parse(raw));
30100
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
+ }
30101
30346
  async function listRunRecords(input) {
30102
30347
  const synthesizerNames = input.synthesizerName !== void 0 ? [input.synthesizerName] : await listSynthesizerRunDirNames(input.rootDir);
30103
30348
  const entries = [];
@@ -30187,6 +30432,58 @@ function compareRunRecordEntries(left, right) {
30187
30432
  if (timeCompare !== 0) return timeCompare;
30188
30433
  return right.runId.localeCompare(left.runId);
30189
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
+ }
30190
30487
  const synthesizerSpecFrontmatterSchema = strictObject({
30191
30488
  description: string().optional(),
30192
30489
  name: string().trim().min(1)
@@ -30806,7 +31103,7 @@ function buildSandboxName(synthesizerName, runId) {
30806
31103
  return `ctxe-${synthesizerName.slice(0, 24).toLowerCase()}-${runId.slice(-8).toLowerCase()}`;
30807
31104
  }
30808
31105
  function planCeiling(input) {
30809
- return Math.min(input.prevCursor.frontier + input.config.maxSliceSize, input.wallclock);
31106
+ return Math.min(input.prevCursor.frontier + input.config.maxSliceSize, input.syncHorizon);
30810
31107
  }
30811
31108
  function buildSlice(input) {
30812
31109
  const slice = {};
@@ -30835,11 +31132,11 @@ function nextCursor(input) {
30835
31132
  };
30836
31133
  }
30837
31134
  function plan(input) {
30838
- const ceiling = planCeiling({
31135
+ const ceiling = Math.max(planCeiling({
30839
31136
  config: input.config,
30840
31137
  prevCursor: input.prevCursor,
30841
- wallclock: input.wallclock
30842
- });
31138
+ syncHorizon: input.syncHorizon
31139
+ }), input.prevCursor.frontier);
30843
31140
  const slice = buildSlice({
30844
31141
  ceiling,
30845
31142
  floors: input.prevCursor.floors
@@ -30879,10 +31176,13 @@ function renderSliceJson(slice) {
30879
31176
  return `${JSON.stringify(windows, null, " ")}\n`;
30880
31177
  }
30881
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
+ }
30882
31182
  async function openSynthesizerTransaction(input) {
30883
- const now = input.now ?? (() => /* @__PURE__ */ new Date());
30884
31183
  const runId = assertSafeEngineName((input.runIdFactory ?? v7)());
30885
- const startedAt = now().toISOString();
31184
+ const begin = (input.now ?? (() => /* @__PURE__ */ new Date()))();
31185
+ const startedAt = begin.toISOString();
30886
31186
  const runDir = await ensureRunDir({
30887
31187
  rootDir: input.repo.rootDir,
30888
31188
  runId,
@@ -30903,25 +31203,24 @@ async function openSynthesizerTransaction(input) {
30903
31203
  synthesizer: input.synthesizer,
30904
31204
  trigger: input.trigger
30905
31205
  });
30906
- const wallclock = isoToMs(startedAt, "transaction startedAt");
31206
+ const persistedCursor = await readCursor(input.repo.rootDir, input.synthesizer.name);
30907
31207
  const planConfig = {
30908
31208
  maxSliceSize: input.config.maxSliceSize,
30909
- oldestConsideredPoint: input.config.oldestConsideredPoint ?? wallclock - DEFAULT_OLDEST_LOOKBACK_MS
31209
+ oldestConsideredPoint: resolveOldest(input.config, begin.getTime())
30910
31210
  };
30911
31211
  const { next, slice } = plan({
30912
31212
  config: planConfig,
30913
31213
  prevCursor: reconcileCursor({
30914
31214
  config: planConfig,
30915
- prevCursor: await readCursor(input.repo.rootDir, input.synthesizer.name),
31215
+ prevCursor: persistedCursor,
30916
31216
  tables: Object.keys(watermark)
30917
31217
  }),
30918
- wallclock,
31218
+ syncHorizon: input.syncHorizon,
30919
31219
  watermark
30920
31220
  });
30921
31221
  await writeRunRecord(runDir, buildRunningRunRecord(startingRecord));
30922
31222
  return {
30923
31223
  next,
30924
- reachedWallclock: next.frontier === wallclock,
30925
31224
  runDir,
30926
31225
  runId,
30927
31226
  sliceJson: renderSliceJson(slice),
@@ -31028,6 +31327,7 @@ var Engine = class {
31028
31327
  now;
31029
31328
  runIdFactory;
31030
31329
  repo;
31330
+ syncHorizonCapture;
31031
31331
  watermarkCapture;
31032
31332
  synthesizers = /* @__PURE__ */ new Map();
31033
31333
  config = null;
@@ -31045,13 +31345,19 @@ var Engine = class {
31045
31345
  mode: options.git?.mode ?? DEFAULT_GIT_MODE,
31046
31346
  rootDir: path.resolve(options.rootDir)
31047
31347
  };
31348
+ this.syncHorizonCapture = options.syncHorizonCapture;
31048
31349
  this.watermarkCapture = options.watermarkCapture;
31049
31350
  }
31050
31351
  async runDaemon(options = {}) {
31051
31352
  if (this.daemonRunning) throw new Error("Engine.runDaemon is already running.");
31052
31353
  this.daemonRunning = true;
31053
31354
  try {
31054
- const report = await runRootPreflight(this.repo);
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
+ }
31055
31361
  if (!report.ready) throw new Error(formatPreflightFailure(this.repo.rootDir, report.issues));
31056
31362
  await this.ensureLoaded();
31057
31363
  await runEngineLoop(this.buildLoopDeps({
@@ -31068,10 +31374,24 @@ var Engine = class {
31068
31374
  }
31069
31375
  async runOnce(synthesizerName) {
31070
31376
  await this.prepareSynthesizerRun(synthesizerName);
31071
- return (await this.runSynthesizerTransaction({
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,
31072
31388
  synthesizerName,
31073
31389
  trigger: "manual"
31074
- })).record;
31390
+ });
31391
+ return {
31392
+ kind: "ran",
31393
+ record
31394
+ };
31075
31395
  }
31076
31396
  async backfill(synthesizerName, options = {}) {
31077
31397
  await this.prepareSynthesizerRun(synthesizerName);
@@ -31105,42 +31425,43 @@ var Engine = class {
31105
31425
  getDiscoveryErrors() {
31106
31426
  return [...this.discoveryErrors];
31107
31427
  }
31428
+ nowDate() {
31429
+ return (this.now ?? (() => /* @__PURE__ */ new Date()))();
31430
+ }
31108
31431
  buildLoopDeps(options) {
31109
31432
  const rootDir = this.repo.rootDir;
31110
- const clock = this.now ?? (() => /* @__PURE__ */ new Date());
31111
31433
  return {
31434
+ captureSyncHorizon: this.syncHorizonCapture,
31112
31435
  listSynthesizers: async () => {
31113
31436
  await this.refreshSynthesizers();
31114
31437
  const specs = this.listSynthesizers().filter((spec) => options.scopeTo === void 0 || spec.name === options.scopeTo);
31438
+ const passNowMs = this.nowDate().getTime();
31439
+ const config = this.requireConfig();
31115
31440
  return Promise.all(specs.map(async (spec) => {
31116
- const notBefore = await this.readRateLimitGate(spec.name, clock().getTime());
31441
+ const notBefore = await this.readRateLimitGate(spec.name, passNowMs);
31117
31442
  return {
31118
- frontier: (await readCursor(rootDir, spec.name))?.frontier ?? 0,
31443
+ frontier: (await readCursor(rootDir, spec.name))?.frontier ?? resolveOldest(config, passNowMs),
31119
31444
  name: spec.name,
31120
31445
  ...notBefore !== void 0 && { notBefore }
31121
31446
  };
31122
31447
  }));
31123
31448
  },
31124
- now: () => clock().getTime(),
31125
- runSlice: async (name) => {
31449
+ now: () => this.nowDate().getTime(),
31450
+ runSlice: async (name, syncHorizon) => {
31126
31451
  try {
31127
31452
  const outcome = await this.runSynthesizerTransaction({
31453
+ syncHorizon,
31128
31454
  synthesizerName: name,
31129
31455
  trigger: options.trigger
31130
31456
  });
31131
31457
  options.onSlice?.(outcome);
31132
31458
  this.logSliceLag(name, outcome);
31133
- return {
31134
- advanced: outcome.record.status === "success",
31135
- rateLimited: outcome.record.status === "rate_limited"
31136
- };
31459
+ const status = outcome.record.status;
31460
+ return status === "success" ? "advanced" : status === "rate_limited" ? "rate_limited" : "failed";
31137
31461
  } catch (error) {
31138
31462
  if (error instanceof TransactionLockHeldError) {
31139
31463
  this.logger.warn(`[engine] skipping '${name}': ${error.message}`);
31140
- return {
31141
- advanced: false,
31142
- rateLimited: false
31143
- };
31464
+ return "failed";
31144
31465
  }
31145
31466
  throw error;
31146
31467
  }
@@ -31149,10 +31470,10 @@ var Engine = class {
31149
31470
  };
31150
31471
  }
31151
31472
  async readRateLimitGate(synthesizerName, nowMs) {
31152
- const latest = (await listRunRecords({
31473
+ const latest = await readLatestRunRecord({
31153
31474
  rootDir: this.repo.rootDir,
31154
31475
  synthesizerName
31155
- }))[0]?.record;
31476
+ });
31156
31477
  if (latest?.status !== "rate_limited") return void 0;
31157
31478
  if (latest.rate_limit_resets_at === void 0) return void 0;
31158
31479
  const resetsAt = isoToMs(latest.rate_limit_resets_at, "rate_limit_resets_at");
@@ -31165,8 +31486,7 @@ var Engine = class {
31165
31486
  this.logger.warn(`[engine] '${name}' slice did not advance (status=${outcome.record.status})`);
31166
31487
  return;
31167
31488
  }
31168
- const clock = this.now ?? (() => /* @__PURE__ */ new Date());
31169
- const lagMs = Math.max(0, clock().getTime() - outcome.frontier);
31489
+ const lagMs = Math.max(0, this.nowDate().getTime() - outcome.frontier);
31170
31490
  const note = `[engine] '${name}' frontier ${formatRelativeAge(lagMs)}`;
31171
31491
  if (lagMs > LAG_BEHIND_TICKS * this.requireConfig().tick) this.logger.warn(`${note} — behind`);
31172
31492
  else this.logger.info(note);
@@ -31191,6 +31511,7 @@ var Engine = class {
31191
31511
  now: this.now,
31192
31512
  repo: this.repo,
31193
31513
  runIdFactory: this.runIdFactory,
31514
+ syncHorizon: request.syncHorizon,
31194
31515
  synthesizer,
31195
31516
  trigger: request.trigger,
31196
31517
  watermarkCapture: this.watermarkCapture
@@ -31217,7 +31538,6 @@ var Engine = class {
31217
31538
  });
31218
31539
  return {
31219
31540
  frontier: ctx.next.frontier,
31220
- reachedWallclock: ctx.reachedWallclock,
31221
31541
  record
31222
31542
  };
31223
31543
  } finally {
@@ -31267,10 +31587,24 @@ function formatPreflightFailure(rootDir, issues) {
31267
31587
  return `Engine root '${rootDir}' is not ready:\n${issues.map((issue) => ` [${issue.code}] ${issue.message}`).join("\n")}`;
31268
31588
  }
31269
31589
  function assembleEngineStatus(input) {
31590
+ const observation = input.syncHorizon;
31591
+ const horizon = observation.kind === "captured" ? observation.horizon : null;
31270
31592
  const synthesizers = input.synthesizers.map((synthesizer) => {
31271
- const lagMs = synthesizer.frontier === null ? null : Math.max(0, input.now - synthesizer.frontier);
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
+ }
31272
31604
  return {
31273
- frontier: synthesizer.frontier === null ? null : msToIso(synthesizer.frontier),
31605
+ frontier: frontier === null ? null : msToIso(frontier),
31606
+ horizonGapMs,
31607
+ horizonGapText,
31274
31608
  lagMs,
31275
31609
  lagText: lagMs === null ? "never run" : formatRelativeAge(lagMs),
31276
31610
  latestRun: synthesizer.latestRun,
@@ -31279,21 +31613,37 @@ function assembleEngineStatus(input) {
31279
31613
  }).sort((left, right) => left.name.localeCompare(right.name));
31280
31614
  return {
31281
31615
  now: msToIso(input.now),
31616
+ syncHorizon: horizon === null ? null : msToIso(horizon),
31617
+ ...observation.kind === "unavailable" && { syncHorizonError: `control plane unavailable: ${observation.error}` },
31282
31618
  synthesizers
31283
31619
  };
31284
31620
  }
31285
31621
  async function loadEngineStatus(input) {
31286
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
+ }
31287
31635
  const discovery = await discoverSynthesizers(path.resolve(input.rootDir, SYNTHESIZERS_DIR_RELATIVE));
31288
31636
  const latestByName = latestRunByName(await listRunRecords({ rootDir: input.rootDir }));
31289
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
+ })));
31290
31643
  return assembleEngineStatus({
31291
31644
  now,
31292
- synthesizers: await Promise.all(names.map(async (name) => ({
31293
- frontier: (await readCursor(input.rootDir, name))?.frontier ?? null,
31294
- latestRun: latestByName.get(name) ?? null,
31295
- name
31296
- })))
31645
+ syncHorizon,
31646
+ synthesizers
31297
31647
  });
31298
31648
  }
31299
31649
  function latestRunByName(entries) {
@@ -31303,7 +31653,7 @@ function latestRunByName(entries) {
31303
31653
  }
31304
31654
  const rateLimitEventSchema = object({
31305
31655
  rate_limit_info: object({
31306
- resetsAt: number().optional(),
31656
+ resetsAt: number$1().optional(),
31307
31657
  status: string().min(1)
31308
31658
  }),
31309
31659
  type: literal("rate_limit_event")
@@ -31575,53 +31925,6 @@ function applyRegistry(builder, value) {
31575
31925
  return r;
31576
31926
  });
31577
31927
  }
31578
- async function runRootRepair(repo) {
31579
- await assertGitCheckout(repo);
31580
- const branch = await inspectBranchReadiness(repo);
31581
- const tree = await inspectWorkingTree(repo);
31582
- if (branch.kind === "no_origin") throw new Error("RootRepair requires 'origin' to be configured in remote mode. Provisioning must add origin before repair.");
31583
- 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.`);
31584
- const needsFastForward = branch.kind === "local_unborn_remote_has_main" || branch.kind === "remote_mismatch";
31585
- if (needsFastForward && !tree.clean) throw new Error(formatCombinedRepairError(repo, branch, tree));
31586
- if (needsFastForward) return {
31587
- kind: "fast_forward",
31588
- ...await fastForwardRoot(repo)
31589
- };
31590
- if (!tree.clean) return await runDirtyRootRepair(repo);
31591
- return { kind: "no_op" };
31592
- }
31593
- async function runDirtyRootRepair(repo) {
31594
- await repairDirtyRoot(repo);
31595
- const interruptedRunIds = (await markInterruptedRuns(repo.rootDir)).map((record) => record.run_id);
31596
- if ((await inspectWorkingTree(repo)).clean) return {
31597
- commit: null,
31598
- interruptedRunIds,
31599
- kind: "dirty_root_repair"
31600
- };
31601
- const { sha } = await commitRootRepair(repo, {
31602
- interruptedRunIds,
31603
- repairId: v7()
31604
- });
31605
- await pushToOrigin(repo);
31606
- return {
31607
- commit: {
31608
- pushed: repo.mode === "remote",
31609
- sha
31610
- },
31611
- interruptedRunIds,
31612
- kind: "dirty_root_repair"
31613
- };
31614
- }
31615
- function formatCombinedRepairError(repo, branch, tree) {
31616
- const dirtyPaths = tree.clean ? "(clean)" : formatWorkingTreePaths(tree.paths);
31617
- return [
31618
- "RootRepair refuses to combine branch fast-forward with dirty-root repair in v1.",
31619
- `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}'`}.`,
31620
- "Dirty paths:",
31621
- dirtyPaths,
31622
- "Operator must inspect and choose the order manually."
31623
- ].join("\n");
31624
- }
31625
31928
  const RESERVED_OUTPUT_SUBDIRS = new Set(["types", "views"]);
31626
31929
  const OUTPUT_DIR_RELATIVE = "output";
31627
31930
  const CURSORS_DIR_RELATIVE = ".engine/cursors";
@@ -31669,6 +31972,26 @@ function formatNotReadyError(repo, issues) {
31669
31972
  "Commit your authored config (or run 'ctxe repair'), or pass --force to reset anyway."
31670
31973
  ].join("\n");
31671
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
+ }
31672
31995
  const SOURCE_UPDATED_AT_COLUMN = "_ctx_source_updated_at";
31673
31996
  async function captureWatermark(input) {
31674
31997
  const sql = src_default(input.databaseUrl);
@@ -31733,11 +32056,17 @@ function quoteIdentifier(identifier) {
31733
32056
  //#endregion
31734
32057
  //#region env.ts
31735
32058
  const nonEmptyStringSchema = string().trim().min(1);
32059
+ const LOCAL_CONTROL_PLANE_HOST = "127.0.0.1";
31736
32060
  const envSchema = object({
32061
+ CTXB_CONTROL_PLANE_PORT: number().int().min(1).max(65535).default(3999),
31737
32062
  CTXB_DATABASE_URL: nonEmptyStringSchema.optional(),
32063
+ CTXB_ROOT_DIR: nonEmptyStringSchema.optional(),
31738
32064
  CTXE_GIT_MODE: _enum(["local", "remote"]).default("remote"),
31739
32065
  CTXE_ROOT_DIR: nonEmptyStringSchema.optional()
31740
- });
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
+ }));
31741
32070
  function parseEngineCliEnv(rawEnv) {
31742
32071
  return envSchema.parse(rawEnv);
31743
32072
  }
@@ -31745,6 +32074,13 @@ const env = parseEngineCliEnv(process.env);
31745
32074
 
31746
32075
  //#endregion
31747
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
+ }
31748
32084
  function buildEngine(input) {
31749
32085
  const watermarkCapture = async () => captureWatermark({ databaseUrl: input.databaseUrl });
31750
32086
  return new Engine({
@@ -31752,6 +32088,7 @@ function buildEngine(input) {
31752
32088
  executor: new MicrosandboxClaudeExecutor(),
31753
32089
  git: { mode: env.CTXE_GIT_MODE },
31754
32090
  rootDir: input.paths.rootDir,
32091
+ syncHorizonCapture: buildSyncHorizonCapture(input.paths),
31755
32092
  watermarkCapture
31756
32093
  });
31757
32094
  }
@@ -31792,9 +32129,10 @@ async function runEngineListCommand(paths) {
31792
32129
  process.stdout.write(`${formatJsonOutput(output)}\n`);
31793
32130
  if (output.errors.length > 0) process.exitCode = 1;
31794
32131
  }
31795
- async function runEngineStatusCommand(synthesizerName, paths) {
32132
+ async function runEngineStatusCommand(synthesizerName, paths, syncHorizonCapture) {
31796
32133
  const status = await loadEngineStatus({
31797
32134
  rootDir: paths.rootDir,
32135
+ syncHorizonCapture,
31798
32136
  ...synthesizerName ? { synthesizerName } : {}
31799
32137
  });
31800
32138
  process.stdout.write(`${formatJsonOutput(status)}\n`);
@@ -31870,12 +32208,16 @@ async function runResetCommand(input) {
31870
32208
  //#endregion
31871
32209
  //#region commands/run.ts
31872
32210
  async function runRunCommand(input) {
31873
- const record = await buildEngine({
32211
+ const outcome = await buildEngine({
31874
32212
  databaseUrl: resolveDatabaseUrl({ cliValue: input.databaseUrl }),
31875
32213
  paths: input.paths
31876
32214
  }).runOnce(input.synthesizerName);
31877
- process.stdout.write(`${formatJsonOutput(record)}\n`);
31878
- if (record.status !== "success") process.exitCode = 1;
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;
31879
32221
  }
31880
32222
 
31881
32223
  //#endregion
@@ -31957,8 +32299,9 @@ function createProgram() {
31957
32299
  program.command("list").description("List synthesizers").action(async function() {
31958
32300
  await runEngineListCommand(resolveRuntimePaths(this));
31959
32301
  });
31960
- 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) {
31961
- await runEngineStatusCommand(synthesizerName, resolveRuntimePaths(this));
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));
31962
32305
  });
31963
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) {
31964
32307
  await runEngineLogsCommand(synthesizerName, options, resolveRuntimePaths(this));
@@ -31976,14 +32319,14 @@ function createProgram() {
31976
32319
  yes: options.yes ?? false
31977
32320
  });
31978
32321
  });
31979
- 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. Exits non-zero on a failed or timed-out run.").action(async function(synthesizerName, options) {
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) {
31980
32323
  await runRunCommand({
31981
32324
  databaseUrl: options.databaseUrl,
31982
32325
  paths: resolveRuntimePaths(this),
31983
32326
  synthesizerName
31984
32327
  });
31985
32328
  });
31986
- 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 now. The same loop the daemon runs, without the sleep. Streams each slice's run record; prints a summary; exits non-zero only if a slice fails.").action(async function(synthesizerName, options) {
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) {
31987
32330
  await runBackfillCommand({
31988
32331
  databaseUrl: options.databaseUrl,
31989
32332
  paths: resolveRuntimePaths(this),
@@ -32019,4 +32362,4 @@ runCli().catch((error) => {
32019
32362
  //#endregion
32020
32363
  export { createProgram, resolveRepoContext, resolveRuntimePaths, runCli };
32021
32364
  //# sourceMappingURL=cli.mjs.map
32022
- //# debugId=1a858cd0-cb9a-550b-a3f9-5ca9387cf7df
32365
+ //# debugId=ee0e5987-2fbc-50ed-9038-a0c4541b7548