@kontextmind/kxm 0.7.72 → 0.7.74

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.
@@ -2987,7 +2987,7 @@ var require_compile = __commonJS({
2987
2987
  const schOrFunc = root.refs[ref];
2988
2988
  if (schOrFunc)
2989
2989
  return schOrFunc;
2990
- let _sch = resolve6.call(this, root, ref);
2990
+ let _sch = resolve8.call(this, root, ref);
2991
2991
  if (_sch === void 0) {
2992
2992
  const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
2993
2993
  const { schemaId } = this.opts;
@@ -3014,7 +3014,7 @@ var require_compile = __commonJS({
3014
3014
  function sameSchemaEnv(s1, s2) {
3015
3015
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
3016
3016
  }
3017
- function resolve6(root, ref) {
3017
+ function resolve8(root, ref) {
3018
3018
  let sch;
3019
3019
  while (typeof (sch = this.refs[ref]) == "string")
3020
3020
  ref = sch;
@@ -3839,7 +3839,7 @@ var require_fast_uri = __commonJS({
3839
3839
  }
3840
3840
  return uri;
3841
3841
  }
3842
- function resolve6(baseURI, relativeURI, options) {
3842
+ function resolve8(baseURI, relativeURI, options) {
3843
3843
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
3844
3844
  const {
3845
3845
  parsed: baseParsed,
@@ -4201,7 +4201,7 @@ var require_fast_uri = __commonJS({
4201
4201
  var fastUri = {
4202
4202
  SCHEMES,
4203
4203
  normalize,
4204
- resolve: resolve6,
4204
+ resolve: resolve8,
4205
4205
  resolveComponent,
4206
4206
  equal,
4207
4207
  serialize,
@@ -14780,10 +14780,10 @@ var require_dist = __commonJS({
14780
14780
 
14781
14781
  // plugins/kxm/src/runtime-supervisor.ts
14782
14782
  import { spawn as spawn3 } from "node:child_process";
14783
- import { createHash as createHash11, createHmac, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
14784
- import { chmodSync as chmodSync2, existsSync as existsSync10, lstatSync as lstatSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync, rmSync, writeFileSync as writeFileSync4 } from "node:fs";
14783
+ import { createHash as createHash12, createHmac, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
14784
+ import { chmodSync as chmodSync2, existsSync as existsSync12, lstatSync as lstatSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync11, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "node:fs";
14785
14785
  import { createServer } from "node:http";
14786
- import { dirname as dirname6, isAbsolute as isAbsolute4, join as join13 } from "node:path";
14786
+ import { dirname as dirname8, isAbsolute as isAbsolute6, join as join16 } from "node:path";
14787
14787
 
14788
14788
  // plugins/kxm/src/repo-root.ts
14789
14789
  import { existsSync } from "node:fs";
@@ -15163,7 +15163,7 @@ function defaultSpawn(command, args, options) {
15163
15163
  if (options.signal?.aborted) {
15164
15164
  return Promise.resolve({ stdout: "", stderr: "", code: null, started: false, observedChildExit: false, error: new Error("process_aborted") });
15165
15165
  }
15166
- return new Promise((resolve6) => {
15166
+ return new Promise((resolve8) => {
15167
15167
  const stdout = [];
15168
15168
  const stderr = [];
15169
15169
  let outputBytes = 0;
@@ -15194,7 +15194,7 @@ function defaultSpawn(command, args, options) {
15194
15194
  const started = Boolean(child?.pid);
15195
15195
  if (started && !observedChildExit) error ??= new Error("process_exit_unobserved");
15196
15196
  const unverifiedDescendants = stopping || started && !observedChildExit;
15197
- resolve6({
15197
+ resolve8({
15198
15198
  stdout: Buffer.concat(stdout).toString("utf8"),
15199
15199
  stderr: Buffer.concat(stderr).toString("utf8"),
15200
15200
  code,
@@ -16303,6 +16303,7 @@ var KxmSchemaRegistry = class {
16303
16303
  driveReceiptValidator;
16304
16304
  coordinatorValidator;
16305
16305
  intakeMessageValidator;
16306
+ syncEventValidator;
16306
16307
  constructor(schemasDir = DEFAULT_SCHEMA_DIR) {
16307
16308
  this.schemasDir = resolve(schemasDir);
16308
16309
  this.ajv = new import__.Ajv2020({ allErrors: true, strict: true, strictRequired: false });
@@ -16319,6 +16320,7 @@ var KxmSchemaRegistry = class {
16319
16320
  const driveReceiptFile = "drive-receipt.schema.json";
16320
16321
  const coordinatorFile = "coordinator.schema.json";
16321
16322
  const intakeMessageFile = "intake-message.schema.json";
16323
+ const syncEventFile = "sync-event.schema.json";
16322
16324
  this.ajv.addSchema(readJsonObject(join2(this.schemasDir, localBindingsFile)));
16323
16325
  this.ajv.addSchema(readJsonObject(join2(this.schemasDir, templateProvenanceFile)));
16324
16326
  this.ajv.addSchema(readJsonObject(join2(this.schemasDir, initOperationFile)));
@@ -16327,6 +16329,7 @@ var KxmSchemaRegistry = class {
16327
16329
  this.ajv.addSchema(readJsonObject(join2(this.schemasDir, driveReceiptFile)));
16328
16330
  this.ajv.addSchema(readJsonObject(join2(this.schemasDir, coordinatorFile)));
16329
16331
  this.ajv.addSchema(readJsonObject(join2(this.schemasDir, intakeMessageFile)));
16332
+ this.ajv.addSchema(readJsonObject(join2(this.schemasDir, syncEventFile)));
16330
16333
  for (const [kind, definition] of Object.entries(RESOURCE_SCHEMA)) {
16331
16334
  const validator = this.ajv.getSchema(`https://schemas.kxm.dev/${definition.file}`);
16332
16335
  if (!validator) throw new Error(`schema did not compile: ${definition.file}`);
@@ -16340,6 +16343,7 @@ var KxmSchemaRegistry = class {
16340
16343
  const driveReceiptValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${driveReceiptFile}`);
16341
16344
  const coordinatorValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${coordinatorFile}`);
16342
16345
  const intakeMessageValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${intakeMessageFile}`);
16346
+ const syncEventValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${syncEventFile}`);
16343
16347
  if (!localBindingsValidator) throw new Error(`schema did not compile: ${localBindingsFile}`);
16344
16348
  if (!templateProvenanceValidator) throw new Error(`schema did not compile: ${templateProvenanceFile}`);
16345
16349
  if (!initOperationValidator) throw new Error(`schema did not compile: ${initOperationFile}`);
@@ -16348,6 +16352,7 @@ var KxmSchemaRegistry = class {
16348
16352
  if (!driveReceiptValidator) throw new Error(`schema did not compile: ${driveReceiptFile}`);
16349
16353
  if (!coordinatorValidator) throw new Error(`schema did not compile: ${coordinatorFile}`);
16350
16354
  if (!intakeMessageValidator) throw new Error(`schema did not compile: ${intakeMessageFile}`);
16355
+ if (!syncEventValidator) throw new Error(`schema did not compile: ${syncEventFile}`);
16351
16356
  this.localBindingsValidator = localBindingsValidator;
16352
16357
  this.templateProvenanceValidator = templateProvenanceValidator;
16353
16358
  this.initOperationValidator = initOperationValidator;
@@ -16356,6 +16361,7 @@ var KxmSchemaRegistry = class {
16356
16361
  this.driveReceiptValidator = driveReceiptValidator;
16357
16362
  this.coordinatorValidator = coordinatorValidator;
16358
16363
  this.intakeMessageValidator = intakeMessageValidator;
16364
+ this.syncEventValidator = syncEventValidator;
16359
16365
  }
16360
16366
  validate(kind, value, file) {
16361
16367
  const definition = RESOURCE_SCHEMA[kind];
@@ -16402,6 +16408,11 @@ function validateRunEvent(value, file) {
16402
16408
  )]);
16403
16409
  }
16404
16410
  }
16411
+ function syncEventSchemaErrors(value) {
16412
+ const registry = cachedRunEventRegistry ??= new KxmSchemaRegistry();
16413
+ if (registry.syncEventValidator(value)) return void 0;
16414
+ return registry.ajv.errorsText(registry.syncEventValidator.errors, { separator: "; " });
16415
+ }
16405
16416
  function validateDriveReceipt(value, file) {
16406
16417
  const registry = cachedRunEventRegistry ??= new KxmSchemaRegistry();
16407
16418
  if (!value || typeof value !== "object" || Array.isArray(value) || value.schema !== "kxm.drive-receipt.v1") {
@@ -16908,8 +16919,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
16908
16919
  const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
16909
16920
  if (maxWriteRepositories > writable) issues.push(issue2("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
16910
16921
  }
16911
- const join14 = objectValue(step.join);
16912
- const minimumPassed = join14 && typeof join14.minimumPassed === "number" ? join14.minimumPassed : void 0;
16922
+ const join17 = objectValue(step.join);
16923
+ const minimumPassed = join17 && typeof join17.minimumPassed === "number" ? join17.minimumPassed : void 0;
16913
16924
  if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue2("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
16914
16925
  const distinctBy = names(assignment?.distinctBy);
16915
16926
  if (distinctBy.length > 0) {
@@ -17382,7 +17393,7 @@ function legacyConfigFilesAt(root) {
17382
17393
  }
17383
17394
 
17384
17395
  // plugins/kxm/src/runtime-store.ts
17385
- import { createHash as createHash3, randomUUID } from "node:crypto";
17396
+ import { createHash as createHash4, randomUUID } from "node:crypto";
17386
17397
  import { existsSync as existsSync5, lstatSync as lstatSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, realpathSync as realpathSync2, writeFileSync as writeFileSync2 } from "node:fs";
17387
17398
  import { dirname as dirname5, join as join5, resolve as resolve4 } from "node:path";
17388
17399
 
@@ -17458,6 +17469,337 @@ function kxmUserStateRoot(options = {}) {
17458
17469
  return resolve2(base, "kxm");
17459
17470
  }
17460
17471
 
17472
+ // plugins/kxm/src/sync-transform.ts
17473
+ import { createHash as createHash3 } from "node:crypto";
17474
+
17475
+ // plugins/kxm/src/redact.ts
17476
+ var SECRET_PATTERNS = [
17477
+ /\bsk-[A-Za-z0-9_-]{8,}\b/g,
17478
+ /\bsk-ant-[A-Za-z0-9_-]{8,}\b/g,
17479
+ /\bghp_[A-Za-z0-9_]{20,}\b/g,
17480
+ /\bgithub_pat_[A-Za-z0-9_]{20,}\b/g,
17481
+ /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/gi,
17482
+ /\bBearer\s+[A-Za-z0-9._~+/=-]+\b/gi,
17483
+ /\bya29\.[A-Za-z0-9._~+/-]+=*/g,
17484
+ /\b1\/\/[A-Za-z0-9_-]+/g,
17485
+ /\b1\/[A-Za-z0-9_-]{20,}/g,
17486
+ /("?(?:access_token|refresh_token|id_token|sessionKey|session_key|claude_oauth_token|anthropicApiKey)"?\s*[:=]\s*")[^"]*(")/gi,
17487
+ /\bKXM_[A-Z0-9_]*(TOKEN|SECRET|KEY)[A-Z0-9_]*=\S+/gi,
17488
+ /\b(GITHUB_TOKEN|GH_TOKEN|KXM_AUTH_TOKEN|KXM_WORKFLOW_SIGNAL_SECRET|ANTHROPIC_API_KEY|ANTHROPIC_AUTH_TOKEN|CLAUDE_API_KEY)=\S+/gi,
17489
+ /\b[A-Fa-f0-9]{64}\b/g
17490
+ ];
17491
+ function redactSecrets(value) {
17492
+ let result = value;
17493
+ for (const pattern of SECRET_PATTERNS) {
17494
+ result = result.replace(pattern, "[redacted]");
17495
+ }
17496
+ return result;
17497
+ }
17498
+
17499
+ // plugins/kxm/src/sync-transform.ts
17500
+ var KXM_SYNC_EVENT_SCHEMA = "kxm.sync-event.v1";
17501
+ var KXM_SYNC_REDACTOR_VERSION = "redactor-v1";
17502
+ var KXM_DEFAULT_SYNC_POLICY = Object.freeze({
17503
+ prompts: "title-only",
17504
+ results: "bounded-summary",
17505
+ evidence: "references",
17506
+ artifacts: "metadata",
17507
+ fileChanges: "paths-only",
17508
+ rawLogs: false,
17509
+ diffs: false,
17510
+ environmentValues: false
17511
+ });
17512
+ var KXM_DEFAULT_SYNC_POLICY_REVISION = `sha256:${createHash3("sha256").update(kxmCanonicalJson(KXM_DEFAULT_SYNC_POLICY), "utf8").digest("hex")}`;
17513
+ var MIN_REGISTERED_SECRET_CHARS = 4;
17514
+ var REDACTED = "[redacted]";
17515
+ var PATH_REDACTED = "[path]";
17516
+ var CREDENTIAL_SHAPES = [
17517
+ /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?(?:-----END [A-Z ]*PRIVATE KEY-----|$)/g,
17518
+ /\bssh-(?:rsa|ed25519|dss|ecdsa-[a-z0-9-]+) AAAA[0-9A-Za-z+/=]+/g,
17519
+ /\bAKIA[0-9A-Z]{16}\b/g,
17520
+ /\bgh[opsu]_[A-Za-z0-9]{20,}\b/g,
17521
+ /\b(?:api[_-]?key|token|secret|password|passwd)\s*[:=]\s*\S+/gi
17522
+ ];
17523
+ var URL_USERINFO = /\b([a-z][a-z0-9+.-]*:\/\/)[^\s/@]+@/gi;
17524
+ var ABSOLUTE_PATHS = [
17525
+ /\\\\[^\s\\"'`]+\\[^\s"'`]*/g,
17526
+ // UNC
17527
+ /\b[A-Za-z]:[\\/][^\s"'`]*/g,
17528
+ // Windows drive
17529
+ /(?<![\w.~:/-])~[\\/][^\s"'`]*/g,
17530
+ // home
17531
+ /(?<![\w.~:/-])\/(?:[\w.@%+-]+\/)*[\w.@%+-]+\/?/g
17532
+ // POSIX
17533
+ ];
17534
+ var CONTROL_CHARACTERS = /[\u0000-\u001F\u007F]/g;
17535
+ var KxmSyncRedactor = class {
17536
+ values = /* @__PURE__ */ new Set();
17537
+ register(value) {
17538
+ const trimmed = value.trim();
17539
+ if (trimmed.length >= MIN_REGISTERED_SECRET_CHARS) this.values.add(trimmed);
17540
+ }
17541
+ get size() {
17542
+ return this.values.size;
17543
+ }
17544
+ /** Scrub one free-text value; `replaced` counts every substitution. */
17545
+ scrub(input) {
17546
+ let replaced = 0;
17547
+ let text = input;
17548
+ for (const secret of [...this.values].sort((left, right) => right.length - left.length)) {
17549
+ const parts = text.split(secret);
17550
+ if (parts.length > 1) {
17551
+ replaced += parts.length - 1;
17552
+ text = parts.join(REDACTED);
17553
+ }
17554
+ }
17555
+ const substitute = (pattern, replacement) => {
17556
+ text = text.replace(pattern, (...args) => {
17557
+ replaced += 1;
17558
+ return typeof replacement === "string" ? replacement : replacement(...args);
17559
+ });
17560
+ };
17561
+ for (const pattern of CREDENTIAL_SHAPES) substitute(pattern, REDACTED);
17562
+ substitute(URL_USERINFO, (_match, scheme) => `${scheme}${REDACTED}@`);
17563
+ const shaped = redactSecrets(text);
17564
+ if (shaped !== text) {
17565
+ replaced += shaped.split(REDACTED).length - text.split(REDACTED).length;
17566
+ text = shaped;
17567
+ }
17568
+ for (const pattern of ABSOLUTE_PATHS) substitute(pattern, PATH_REDACTED);
17569
+ text = text.replace(CONTROL_CHARACTERS, " ").replace(/\s+/g, " ").trim();
17570
+ return { text, replaced };
17571
+ }
17572
+ };
17573
+ function isRecord(value) {
17574
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
17575
+ }
17576
+ function pickScalars(source, keys, redactor) {
17577
+ if (!isRecord(source)) return void 0;
17578
+ const result = {};
17579
+ for (const key of keys) {
17580
+ const value = source[key];
17581
+ if (typeof value === "number" || typeof value === "boolean") {
17582
+ result[key] = value;
17583
+ } else if (typeof value === "string") {
17584
+ if (redactor) {
17585
+ const scrubbed = redactor.scrub(value);
17586
+ if (scrubbed.text.length > 0) result[key] = scrubbed.text.slice(0, 200);
17587
+ } else {
17588
+ result[key] = value;
17589
+ }
17590
+ }
17591
+ }
17592
+ return Object.keys(result).length > 0 ? result : void 0;
17593
+ }
17594
+ var SyncPayloadBuilder = class {
17595
+ payload = {};
17596
+ omitted = /* @__PURE__ */ new Set();
17597
+ replaced = 0;
17598
+ redactor;
17599
+ constructor(redactor) {
17600
+ this.redactor = redactor;
17601
+ }
17602
+ /** Bounded, scrubbed free text; empty after scrubbing means absent. */
17603
+ text(value, max) {
17604
+ if (typeof value !== "string") return void 0;
17605
+ const { text, replaced } = this.redactor.scrub(value);
17606
+ this.replaced += replaced;
17607
+ if (text.length === 0) return void 0;
17608
+ return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
17609
+ }
17610
+ /** A nested record rebuilt key by key, with the named keys scrubbed as text. */
17611
+ record(source, keys, textKeys = {}) {
17612
+ const scalars = pickScalars(source, keys.filter((key) => !(key in textKeys)));
17613
+ const result = { ...scalars ?? {} };
17614
+ if (isRecord(source)) {
17615
+ for (const [key, max] of Object.entries(textKeys)) {
17616
+ const value = this.text(source[key], max);
17617
+ if (value !== void 0) result[key] = value;
17618
+ }
17619
+ }
17620
+ return Object.keys(result).length > 0 ? result : void 0;
17621
+ }
17622
+ set(key, value) {
17623
+ if (value !== void 0) this.payload[key] = value;
17624
+ }
17625
+ };
17626
+ var SCALAR_FIELDS = [
17627
+ "workflowId",
17628
+ "promptHash",
17629
+ "status",
17630
+ "previousStatus",
17631
+ "outcome",
17632
+ "stepId",
17633
+ "stepAttempt",
17634
+ "fromStepId",
17635
+ "toStepId",
17636
+ "assignmentId",
17637
+ "attemptId",
17638
+ "agentId",
17639
+ "instanceNo",
17640
+ "scopeEpoch",
17641
+ "resolutionAction"
17642
+ ];
17643
+ var REF_KEYS = ["id", "kind", "hash", "status", "producerId"];
17644
+ var ARTIFACT_KEYS = ["id", "kind", "hash", "size", "classification", "availability"];
17645
+ var LEASE_KEYS = ["id", "fencingToken", "acquiredAt", "expiresAt", "operation"];
17646
+ var MAX_REFS = 64;
17647
+ var CARRIED_FIELDS = /* @__PURE__ */ new Set([
17648
+ ...SCALAR_FIELDS,
17649
+ "displayTitle",
17650
+ "summary",
17651
+ "reason",
17652
+ "executor",
17653
+ "model",
17654
+ "timing",
17655
+ "usage",
17656
+ "evidenceRefs",
17657
+ "artifacts",
17658
+ "receipt",
17659
+ "error",
17660
+ "effect",
17661
+ "lease",
17662
+ "actor",
17663
+ "resolvedBy",
17664
+ "suppliedRefs",
17665
+ "counts"
17666
+ ]);
17667
+ var CONTROL_FIELDS = ["effect", "lease", "actor", "resolvedBy", "resolutionAction", "reason", "suppliedRefs", "outcome"];
17668
+ function buildPayload(source, builder) {
17669
+ for (const key of SCALAR_FIELDS) {
17670
+ const value = source[key];
17671
+ if (typeof value === "string" || typeof value === "number") builder.set(key, value);
17672
+ }
17673
+ builder.set("displayTitle", builder.text(source.displayTitle, 200));
17674
+ builder.set("summary", builder.text(source.summary, 1e3));
17675
+ if (source.reason !== void 0) {
17676
+ builder.set("reason", builder.text(source.reason, 1e3) ?? REDACTED);
17677
+ }
17678
+ builder.set("executor", builder.record(source.executor, ["id", "kind", "harness"], {
17679
+ executorVersion: 128,
17680
+ harnessVersion: 128,
17681
+ helperGeneration: 256
17682
+ }));
17683
+ const model = builder.record(source.model, ["profile", "provider"], { model: 200, thinking: 64 });
17684
+ if (model && isRecord(source.model) && Array.isArray(source.model.tags)) {
17685
+ model.tags = source.model.tags.filter((tag) => typeof tag === "string").slice(0, 32);
17686
+ }
17687
+ builder.set("model", model);
17688
+ builder.set("timing", builder.record(source.timing, ["startedAt", "finishedAt", "durationMs", "queueMs", "agentMs"]));
17689
+ builder.set("usage", builder.record(source.usage, [
17690
+ "inputTokens",
17691
+ "outputTokens",
17692
+ "cacheReadTokens",
17693
+ "cacheWriteTokens",
17694
+ "cost",
17695
+ "currency",
17696
+ "costKind"
17697
+ ]));
17698
+ const refs = (value, keys) => Array.isArray(value) ? value.slice(0, MAX_REFS).map((entry) => pickScalars(entry, keys)).filter((entry) => entry !== void 0) : void 0;
17699
+ builder.set("evidenceRefs", refs(source.evidenceRefs, REF_KEYS));
17700
+ builder.set("suppliedRefs", refs(source.suppliedRefs, REF_KEYS));
17701
+ builder.set("artifacts", refs(source.artifacts, ARTIFACT_KEYS));
17702
+ if (isRecord(source.receipt)) {
17703
+ const receipt = builder.record(source.receipt, ["provider", "kind", "hash", "observedAt"], { id: 512 });
17704
+ if (receipt) builder.set("receipts", [receipt]);
17705
+ if (source.receipt.url !== void 0) builder.omitted.add("receipt.url");
17706
+ }
17707
+ builder.set("error", builder.record(source.error, ["class", "retryable"], { component: 128 }));
17708
+ if (isRecord(source.effect)) {
17709
+ const effect = pickScalars(source.effect, ["id", "idempotencyKeyHash"], builder.redactor) ?? {};
17710
+ const policy = pickScalars(source.effect.policy, ["class", "sharedMutable", "idempotencyKey", "receiptQuery"], builder.redactor);
17711
+ if (policy) effect.policy = policy;
17712
+ builder.set("effect", effect);
17713
+ }
17714
+ builder.set("lease", pickScalars(source.lease, LEASE_KEYS, builder.redactor));
17715
+ builder.set("actor", builder.record(source.actor, ["kind"], { id: 200 }));
17716
+ builder.set("resolvedBy", builder.record(source.resolvedBy, ["kind"], { id: 200 }));
17717
+ if (isRecord(source.counts)) {
17718
+ const counts = Object.fromEntries(Object.entries(source.counts).filter((entry) => Number.isInteger(entry[1]) && entry[1] >= 0).slice(0, 32));
17719
+ builder.set("counts", counts);
17720
+ }
17721
+ }
17722
+ function envelope(event, policyRevision, payload, fieldsOmitted, valuesReplaced) {
17723
+ return {
17724
+ schema: KXM_SYNC_EVENT_SCHEMA,
17725
+ sourceEventId: event.eventId,
17726
+ eventType: event.eventType,
17727
+ projectId: event.projectId,
17728
+ runId: event.runId,
17729
+ homeRuntimeId: event.homeRuntimeId,
17730
+ sequence: event.sequence,
17731
+ occurredAt: event.occurredAt,
17732
+ configRevision: event.configRevision,
17733
+ memoryRevision: event.memoryRevision,
17734
+ executorPolicyRevision: event.executorPolicyRevision,
17735
+ toolPolicyRevision: event.toolPolicyRevision,
17736
+ syncPolicyRevision: policyRevision,
17737
+ redaction: {
17738
+ version: KXM_SYNC_REDACTOR_VERSION,
17739
+ fieldsOmitted: [...new Set(fieldsOmitted)].sort().slice(0, 128),
17740
+ valuesReplaced: Math.min(valuesReplaced, 1e5)
17741
+ },
17742
+ payload
17743
+ };
17744
+ }
17745
+ function deriveKxmSyncEvent(event, options = {}) {
17746
+ const redactor = options.redactor ?? new KxmSyncRedactor();
17747
+ const policyRevision = options.policyRevision ?? KXM_DEFAULT_SYNC_POLICY_REVISION;
17748
+ const source = isRecord(event.payload) ? event.payload : {};
17749
+ const builder = new SyncPayloadBuilder(redactor);
17750
+ buildPayload(source, builder);
17751
+ const omitted = new Set(builder.omitted);
17752
+ for (const key of Object.keys(source)) if (!CARRIED_FIELDS.has(key)) omitted.add(key);
17753
+ if (event.protectedPayload !== void 0) omitted.add("protectedPayload");
17754
+ const payload = Object.keys(builder.payload).length > 0 ? builder.payload : { counts: {} };
17755
+ const full = envelope(event, policyRevision, payload, omitted, builder.replaced);
17756
+ if (syncEventSchemaErrors(full) === void 0) return full;
17757
+ const degradedPayload = { degraded: true };
17758
+ for (const key of CONTROL_FIELDS) {
17759
+ const value = builder.payload[key];
17760
+ const restoreNested = (built, orig) => {
17761
+ if (!isRecord(orig)) return built !== void 0 ? built : "[redacted]";
17762
+ const result = {};
17763
+ const builtRecord = isRecord(built) ? built : {};
17764
+ for (const [k, v] of Object.entries(orig)) {
17765
+ const builtValue = builtRecord[k];
17766
+ if (builtValue === void 0 || typeof builtValue === "string" && builtValue.trim().length === 0) {
17767
+ result[k] = isRecord(v) ? restoreNested(void 0, v) : "[redacted]";
17768
+ } else {
17769
+ result[k] = builtValue;
17770
+ }
17771
+ }
17772
+ return result;
17773
+ };
17774
+ if (value === void 0) {
17775
+ const sourceValue = source[key];
17776
+ if (sourceValue !== void 0) {
17777
+ degradedPayload[key] = restoreNested(void 0, sourceValue);
17778
+ }
17779
+ } else if (typeof value === "string" && value.trim().length === 0) {
17780
+ degradedPayload[key] = "[redacted]";
17781
+ } else if (isRecord(value)) {
17782
+ degradedPayload[key] = restoreNested(value, source[key]);
17783
+ } else {
17784
+ degradedPayload[key] = value;
17785
+ }
17786
+ }
17787
+ const degradedOmitted = new Set(omitted);
17788
+ for (const key of Object.keys(builder.payload)) if (!(key in degradedPayload)) degradedOmitted.add(key);
17789
+ const degraded = envelope(event, policyRevision, degradedPayload, degradedOmitted, builder.replaced);
17790
+ const errors = syncEventSchemaErrors(degraded);
17791
+ if (errors === void 0) return degraded;
17792
+ throw new KxmConfigError([{
17793
+ phase: "schema",
17794
+ code: "sync_event_invalid",
17795
+ file: `${event.runId}#${event.sequence}`,
17796
+ message: `event cannot be derived into kxm.sync-event.v1: ${errors}`
17797
+ }]);
17798
+ }
17799
+ function kxmSyncEventBytes(event) {
17800
+ return kxmCanonicalJson(event);
17801
+ }
17802
+
17461
17803
  // plugins/kxm/src/database.ts
17462
17804
  import {
17463
17805
  chmodSync,
@@ -17708,7 +18050,7 @@ function projectRuntimeKey(projectRoot) {
17708
18050
  canonical = resolve4(projectRoot);
17709
18051
  }
17710
18052
  const folded = process.platform === "win32" ? canonical.toLocaleLowerCase("en-US") : canonical;
17711
- return createHash3("sha256").update(folded, "utf8").digest("hex").slice(0, 24);
18053
+ return createHash4("sha256").update(folded, "utf8").digest("hex").slice(0, 24);
17712
18054
  }
17713
18055
  var KXM_REGISTRY_SCHEMA_VERSION = 1;
17714
18056
  var REGISTRY_TABLES = {
@@ -17828,6 +18170,15 @@ var KxmRuntimeRegistry = class {
17828
18170
  return this.readSupervisorRow();
17829
18171
  }
17830
18172
  /** Register or revalidate a project's home binding. Home Runtime is immutable. */
18173
+ /** All projects registered to this Runtime, for restart recovery: the
18174
+ * supervisor needs to reopen their contexts so pending outbox rows resume
18175
+ * syncing and presence keeps beating. */
18176
+ projectsForRuntime(homeRuntimeId) {
18177
+ const rows = this.database.prepare(
18178
+ "SELECT project_root, project_id FROM projects WHERE home_runtime_id = ? ORDER BY registered_at"
18179
+ ).all(homeRuntimeId);
18180
+ return rows.map((row) => ({ projectRoot: row.project_root, projectId: row.project_id }));
18181
+ }
17831
18182
  registerProject(registration) {
17832
18183
  const projectRoot = resolve4(registration.projectRoot);
17833
18184
  const projectKey = projectRuntimeKey(projectRoot);
@@ -17904,7 +18255,7 @@ var KxmRuntimeRegistry = class {
17904
18255
  var KXM_RUN_EVENT_SCHEMA = "kxm.run-event.v1";
17905
18256
  function hashKxmDriveLog(events) {
17906
18257
  const body = events.map((event) => `${event.eventId}:${event.sequence}`).join("\n");
17907
- return `sha256:${createHash3("sha256").update(body, "utf8").digest("hex")}`;
18258
+ return `sha256:${createHash4("sha256").update(body, "utf8").digest("hex")}`;
17908
18259
  }
17909
18260
  function verifyKxmDriveReceipt(receipt, events, foldedStatus, binding) {
17910
18261
  const reasons = [];
@@ -17929,7 +18280,7 @@ function verifyKxmDriveReceipt(receipt, events, foldedStatus, binding) {
17929
18280
  if (reasons.length === 0) return { verified: true };
17930
18281
  return { verified: false, divergence: reasons.join("; ") };
17931
18282
  }
17932
- var KXM_EVENT_STORE_SCHEMA_VERSION = 5;
18283
+ var KXM_EVENT_STORE_SCHEMA_VERSION = 6;
17933
18284
  var KXM_DRIVE_RECEIPT_SCHEMA = "kxm.drive-receipt.v1";
17934
18285
  var DRIVE_RECEIPT_MAX_BYTES = 8 * 1024;
17935
18286
  var EVENT_STORE_TABLES = {
@@ -18034,7 +18385,8 @@ var EVENT_STORE_TABLES = {
18034
18385
  "schema",
18035
18386
  "record"
18036
18387
  ],
18037
- project_controls: ["project_id", "paused", "reason", "updated_at", "actor", "schema", "record"]
18388
+ project_controls: ["project_id", "paused", "reason", "updated_at", "actor", "schema", "record"],
18389
+ outbox: ["seq", "run_id", "sequence", "sync_event", "attempted_at", "acked_at"]
18038
18390
  };
18039
18391
  var KXM_EVENT_STORE_TABLE_NAMES = Object.keys(EVENT_STORE_TABLES).sort();
18040
18392
  var EVENT_STORE_SCHEMA = `
@@ -18222,9 +18574,22 @@ CREATE TABLE project_controls (
18222
18574
  schema TEXT NOT NULL,
18223
18575
  record TEXT NOT NULL
18224
18576
  ) STRICT;
18577
+ CREATE TABLE IF NOT EXISTS outbox (
18578
+ seq INTEGER PRIMARY KEY AUTOINCREMENT,
18579
+ run_id TEXT NOT NULL,
18580
+ sequence INTEGER NOT NULL,
18581
+ sync_event TEXT NOT NULL,
18582
+ attempted_at TEXT,
18583
+ acked_at TEXT,
18584
+ UNIQUE (run_id, sequence)
18585
+ ) STRICT;
18586
+ CREATE INDEX outbox_pending ON outbox(seq) WHERE acked_at IS NULL;
18225
18587
  `;
18226
18588
  var KxmRunEventStore = class {
18227
18589
  path;
18590
+ /** Secret values registered here are replaced in every sync object this
18591
+ * store derives. In memory only: they are never written anywhere. */
18592
+ syncRedactor = new KxmSyncRedactor();
18228
18593
  database;
18229
18594
  constructor(path) {
18230
18595
  this.path = resolve4(path);
@@ -18307,6 +18672,15 @@ var KxmRunEventStore = class {
18307
18672
  `).get(runId);
18308
18673
  return row ? runFromRow(row) : void 0;
18309
18674
  }
18675
+ /** All projects registered to this Runtime, for restart recovery: the
18676
+ * supervisor needs to reopen their contexts so pending outbox rows resume
18677
+ * syncing and presence keeps beating. */
18678
+ projectsForRuntime(homeRuntimeId) {
18679
+ const rows = this.database.prepare(
18680
+ "SELECT project_root, project_id FROM projects WHERE home_runtime_id = ? ORDER BY registered_at"
18681
+ ).all(homeRuntimeId);
18682
+ return rows.map((row) => ({ projectRoot: row.project_root, projectId: row.project_id }));
18683
+ }
18310
18684
  runsForProject(projectId, limit = 50) {
18311
18685
  const rows = this.database.prepare(`
18312
18686
  SELECT run_id, project_id, home_runtime_id, workflow_id, prompt_sha256, status, config_revision, memory_revision, executor_policy_revision, tool_policy_revision, created_at, updated_at
@@ -18346,6 +18720,39 @@ var KxmRunEventStore = class {
18346
18720
  event.schema,
18347
18721
  event.homeRuntimeId
18348
18722
  );
18723
+ const syncEvent = deriveKxmSyncEvent(event, { redactor: this.syncRedactor });
18724
+ this.database.prepare("INSERT INTO outbox (run_id, sequence, sync_event) VALUES (?, ?, ?)").run(event.runId, event.sequence, kxmSyncEventBytes(syncEvent));
18725
+ }
18726
+ /** Unacknowledged outbox rows after `afterSeq`, in outbox order, oldest first. */
18727
+ pendingOutbox(limit = 100, afterSeq = 0) {
18728
+ const rows = this.database.prepare(`
18729
+ SELECT seq, run_id, sequence, sync_event, attempted_at, acked_at
18730
+ FROM outbox WHERE acked_at IS NULL AND seq > ? ORDER BY seq ASC LIMIT ?
18731
+ `).all(afterSeq, limit);
18732
+ return rows.map(outboxFromRow);
18733
+ }
18734
+ /** Every outbox row of one run, acknowledged or not, in sequence order. */
18735
+ outboxForRun(runId) {
18736
+ const rows = this.database.prepare(`
18737
+ SELECT seq, run_id, sequence, sync_event, attempted_at, acked_at
18738
+ FROM outbox WHERE run_id = ? ORDER BY sequence ASC
18739
+ `).all(runId);
18740
+ return rows.map(outboxFromRow);
18741
+ }
18742
+ markOutboxAttempted(seqs, at) {
18743
+ const statement = this.database.prepare("UPDATE outbox SET attempted_at = ? WHERE seq = ? AND acked_at IS NULL");
18744
+ this.transaction(() => {
18745
+ for (const seq of seqs) statement.run(at, seq);
18746
+ });
18747
+ }
18748
+ /** Advance the cursor: the hub holds these rows now. Returns rows newly acked. */
18749
+ ackOutbox(seqs, at) {
18750
+ const statement = this.database.prepare("UPDATE outbox SET acked_at = ? WHERE seq = ? AND acked_at IS NULL");
18751
+ return this.transaction(() => {
18752
+ let changed = 0;
18753
+ for (const seq of seqs) changed += Number(statement.run(at, seq).changes);
18754
+ return changed;
18755
+ });
18349
18756
  }
18350
18757
  events(runId, afterSequence = 0, limit = 200) {
18351
18758
  const rows = this.database.prepare(`
@@ -18862,6 +19269,16 @@ function parseDriveReceipt(raw) {
18862
19269
  validateDriveReceipt(parsed, "drive-receipt");
18863
19270
  return parsed;
18864
19271
  }
19272
+ function outboxFromRow(row) {
19273
+ return {
19274
+ seq: row.seq,
19275
+ runId: row.run_id,
19276
+ sequence: row.sequence,
19277
+ syncEvent: row.sync_event,
19278
+ ...row.attempted_at !== null ? { attemptedAt: row.attempted_at } : {},
19279
+ ...row.acked_at !== null ? { ackedAt: row.acked_at } : {}
19280
+ };
19281
+ }
18865
19282
  function runFromRow(row) {
18866
19283
  if (typeof row.memory_revision !== "string" || row.memory_revision.length === 0) {
18867
19284
  throw runtimeError("runtime_schema_shape_invalid", row.run_id, "memory_revision is required");
@@ -18984,7 +19401,7 @@ function gateRowContentHash(table, row) {
18984
19401
  const copy = { ...row };
18985
19402
  delete copy.contentHash;
18986
19403
  void table;
18987
- return `sha256:${createHash3("sha256").update(kxmCanonicalJson(copy), "utf8").digest("hex")}`;
19404
+ return `sha256:${createHash4("sha256").update(kxmCanonicalJson(copy), "utf8").digest("hex")}`;
18988
19405
  }
18989
19406
  function assertClosedGateObservation(kind, row, id = "observation") {
18990
19407
  if (row.completeness === "incomplete") return;
@@ -19214,7 +19631,7 @@ function capabilityFromRow(row) {
19214
19631
  }
19215
19632
 
19216
19633
  // plugins/kxm/src/runtime-service.ts
19217
- import { createHash as createHash5 } from "node:crypto";
19634
+ import { createHash as createHash6 } from "node:crypto";
19218
19635
  import { existsSync as existsSync6, readdirSync as readdirSync3, readFileSync as readFileSync4 } from "node:fs";
19219
19636
  import { join as join6 } from "node:path";
19220
19637
 
@@ -20420,7 +20837,7 @@ function isTerminalRunStatus(status) {
20420
20837
  }
20421
20838
 
20422
20839
  // plugins/kxm/src/engine-plan.ts
20423
- import { createHash as createHash4 } from "node:crypto";
20840
+ import { createHash as createHash5 } from "node:crypto";
20424
20841
 
20425
20842
  // plugins/kxm/src/engine-compile.ts
20426
20843
  var KXM_COMPILED_WORKFLOW_SCHEMA = "kxm.compiled-workflow.v1";
@@ -20570,7 +20987,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
20570
20987
  const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
20571
20988
  const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
20572
20989
  const assignments = compileAssignments(step, id, agent, sink);
20573
- const join14 = compileJoin(step, id, sink);
20990
+ const join17 = compileJoin(step, id, sink);
20574
20991
  const requiredEvidence = compileEvidence(step, id, sink);
20575
20992
  const transitions = compileTransitions(step, id, index, stepIndex, sink);
20576
20993
  const outcomes = Object.keys(transitions).sort(compareCodeUnits4);
@@ -20598,7 +21015,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
20598
21015
  transitions: orderedTransitions,
20599
21016
  requiresPlanHash: requirePlanHash.includes(id),
20600
21017
  assignments,
20601
- join: join14
21018
+ join: join17
20602
21019
  };
20603
21020
  if (kind === "agent" || kind === "moa") {
20604
21021
  if (!agent) return void 0;
@@ -20648,15 +21065,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
20648
21065
  };
20649
21066
  }
20650
21067
  function compileJoin(step, stepId, sink) {
20651
- const join14 = objectValue2(step.join);
20652
- if (!join14) return { strategy: "all" };
20653
- const declared = stringValue2(join14.strategy);
21068
+ const join17 = objectValue2(step.join);
21069
+ if (!join17) return { strategy: "all" };
21070
+ const declared = stringValue2(join17.strategy);
20654
21071
  const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
20655
- const minimumPassed = compileOptionalCount(join14.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
21072
+ const minimumPassed = compileOptionalCount(join17.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
20656
21073
  const compiled = {
20657
21074
  strategy,
20658
21075
  ...minimumPassed !== void 0 ? { minimumPassed } : {},
20659
- ...typeof join14.cancelRemaining === "boolean" ? { cancelRemaining: join14.cancelRemaining } : {}
21076
+ ...typeof join17.cancelRemaining === "boolean" ? { cancelRemaining: join17.cancelRemaining } : {}
20660
21077
  };
20661
21078
  return compiled;
20662
21079
  }
@@ -20967,10 +21384,10 @@ var JOIN_OPTIONAL = ["minimumPassed", "cancelRemaining"];
20967
21384
  var EVIDENCE_REQUIRED = ["key", "kind", "minimum", "reusableAcrossAttempts"];
20968
21385
  var EVIDENCE_OPTIONAL = ["producerPolicy"];
20969
21386
  function kxmSha256(input) {
20970
- return `sha256:${createHash4("sha256").update(input, "utf8").digest("hex")}`;
21387
+ return `sha256:${createHash5("sha256").update(input, "utf8").digest("hex")}`;
20971
21388
  }
20972
- function hashKxmRunPlanEnvelope(envelope) {
20973
- return kxmSha256(kxmCanonicalJson(envelope));
21389
+ function hashKxmRunPlanEnvelope(envelope2) {
21390
+ return kxmSha256(kxmCanonicalJson(envelope2));
20974
21391
  }
20975
21392
  function freezeKxmCompiledPlan(plan) {
20976
21393
  const steps = /* @__PURE__ */ Object.create(null);
@@ -21017,12 +21434,12 @@ function parseKxmRunPlanEnvelope(raw, run, expectedHash) {
21017
21434
  } catch {
21018
21435
  throw runtimeError("run_plan_corrupt", run.runId, "run plan envelope is not JSON");
21019
21436
  }
21020
- const envelope = parseEnvelope(parsed, run);
21021
- const hash = hashKxmRunPlanEnvelope(envelope);
21437
+ const envelope2 = parseEnvelope(parsed, run);
21438
+ const hash = hashKxmRunPlanEnvelope(envelope2);
21022
21439
  if (hash !== expectedHash) {
21023
21440
  throw runtimeError("run_plan_corrupt", run.runId, "run plan envelope hash does not match");
21024
21441
  }
21025
- return envelope;
21442
+ return envelope2;
21026
21443
  }
21027
21444
  function rehydrateKxmCompiledPlanFromStore(store, run) {
21028
21445
  return loadPinnedEnvelope(store, run).plan;
@@ -21532,7 +21949,7 @@ function gateRegistryHash(registryValue) {
21532
21949
  }
21533
21950
 
21534
21951
  // plugins/kxm/src/engine-evidence.ts
21535
- function verifyKxmGateEvidence(store, run, envelope, events, state) {
21952
+ function verifyKxmGateEvidence(store, run, envelope2, events, state) {
21536
21953
  const attempts = store.gateAttemptsForRun(run.runId);
21537
21954
  const observations = store.gateObservationsForRun(run.runId);
21538
21955
  const evidence = store.gateEvidenceForRun(run.runId);
@@ -21550,7 +21967,7 @@ function verifyKxmGateEvidence(store, run, envelope, events, state) {
21550
21967
  const attemptId = stringField(event, "attemptId");
21551
21968
  const row = attemptById.get(attemptId);
21552
21969
  if (!row) throw runtimeError("gate_attempt_pin_mismatch", run.runId, `effect.intent_recorded ${event.eventId} has no gate_attempts row`);
21553
- assertAttemptMatchesEvent(run, envelope, state, event, row);
21970
+ assertAttemptMatchesEvent(run, envelope2, state, event, row);
21554
21971
  }
21555
21972
  for (const event of observedEvents) {
21556
21973
  const attemptId = stringField(event, "attemptId");
@@ -21613,7 +22030,7 @@ function verifyKxmGateEvidence(store, run, envelope, events, state) {
21613
22030
  if (row.outcome !== recomputed || event.payload.outcome !== recomputed) {
21614
22031
  throw runtimeError("gate_evidence_hash_mismatch", run.runId, "evidence outcome does not match the observation and expect");
21615
22032
  }
21616
- const step = envelope.plan.steps[row.stepId];
22033
+ const step = envelope2.plan.steps[row.stepId];
21617
22034
  const required = step?.requiredEvidence.filter((item) => item.kind === "gate") ?? [];
21618
22035
  const expectedKey = required.length === 1 ? required[0].key : null;
21619
22036
  if (row.evidenceKey !== expectedKey) {
@@ -21709,7 +22126,7 @@ function lastEffectByAttempt(events) {
21709
22126
  }
21710
22127
  return last;
21711
22128
  }
21712
- function assertAttemptMatchesEvent(run, envelope, state, event, row) {
22129
+ function assertAttemptMatchesEvent(run, envelope2, state, event, row) {
21713
22130
  const effectId = event.payload.effect?.id;
21714
22131
  if (row.effectId !== effectId || row.intentEventId !== event.eventId) {
21715
22132
  throw runtimeError("gate_attempt_pin_mismatch", run.runId, "intent event does not match the gate attempt");
@@ -21720,14 +22137,14 @@ function assertAttemptMatchesEvent(run, envelope, state, event, row) {
21720
22137
  if (row.stepId !== event.payload.stepId || row.stepAttempt !== event.payload.stepAttempt || row.assignmentId !== event.payload.assignmentId || row.attemptId !== event.payload.attemptId) {
21721
22138
  throw runtimeError("gate_attempt_pin_mismatch", run.runId, "gate attempt identity does not match the intent payload");
21722
22139
  }
21723
- const step = envelope.plan.steps[row.stepId];
22140
+ const step = envelope2.plan.steps[row.stepId];
21724
22141
  if (!step || step.kind !== "gate") {
21725
22142
  throw runtimeError("gate_attempt_pin_mismatch", run.runId, "gate attempt step is not a gate");
21726
22143
  }
21727
22144
  if (row.gateId !== step.gate || row.expect !== step.expect) {
21728
22145
  throw runtimeError("gate_attempt_pin_mismatch", run.runId, "gate attempt gate/expect do not match the plan");
21729
22146
  }
21730
- const definition = envelope.gates.definitions[step.gate];
22147
+ const definition = envelope2.gates.definitions[step.gate];
21731
22148
  if (!definition || definition.kind !== row.gateKind) {
21732
22149
  throw runtimeError("gate_attempt_pin_mismatch", run.runId, "gate attempt kind does not match the pinned definition");
21733
22150
  }
@@ -21735,14 +22152,14 @@ function assertAttemptMatchesEvent(run, envelope, state, event, row) {
21735
22152
  if (row.gateDefinitionHash !== expectedDefinitionHash) {
21736
22153
  throw runtimeError("gate_attempt_pin_mismatch", run.runId, "gate_definition_hash does not match the pinned definition");
21737
22154
  }
21738
- if (!envelope.gates.registry || row.registryHash !== envelope.gates.registry.hash) {
22155
+ if (!envelope2.gates.registry || row.registryHash !== envelope2.gates.registry.hash) {
21739
22156
  throw runtimeError("gate_attempt_pin_mismatch", run.runId, "registry_hash does not match the pinned registry");
21740
22157
  }
21741
- const planRowHash = envelope && state.runPlanHash;
22158
+ const planRowHash = envelope2 && state.runPlanHash;
21742
22159
  if (row.runPlanHash !== planRowHash) {
21743
22160
  throw runtimeError("gate_attempt_pin_mismatch", run.runId, "run_plan_hash does not match the pinned plan");
21744
22161
  }
21745
- if (row.controlProjectKey !== envelope.gates.controlRoot.projectKey) {
22162
+ if (row.controlProjectKey !== envelope2.gates.controlRoot.projectKey) {
21746
22163
  throw runtimeError("gate_attempt_pin_mismatch", run.runId, "control_project_key does not match the envelope");
21747
22164
  }
21748
22165
  }
@@ -21980,12 +22397,12 @@ function enqueueKxmScheduledRun(storePath, runId, configRevision, bound, start)
21980
22397
  if (owner.admitted.has(runId) || owner.queue.some((item) => item.runId === runId)) {
21981
22398
  return Promise.reject(runtimeError("run_busy", runId, `run ${runId} is already admitted or queued`));
21982
22399
  }
21983
- return new Promise((resolve6, reject) => {
22400
+ return new Promise((resolve8, reject) => {
21984
22401
  owner.queue.push({
21985
22402
  runId,
21986
22403
  configRevision,
21987
22404
  bound,
21988
- start: (token) => start(token).then(resolve6, reject),
22405
+ start: (token) => start(token).then(resolve8, reject),
21989
22406
  fail: (error) => reject(error)
21990
22407
  });
21991
22408
  pump(storePath, owner);
@@ -22014,7 +22431,7 @@ function compareCodeUnits5(left, right) {
22014
22431
  return left < right ? -1 : left > right ? 1 : 0;
22015
22432
  }
22016
22433
  function sha256Of(input) {
22017
- return `sha256:${createHash5("sha256").update(input, "utf8").digest("hex")}`;
22434
+ return `sha256:${createHash6("sha256").update(input, "utf8").digest("hex")}`;
22018
22435
  }
22019
22436
  function objectValue3(value) {
22020
22437
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
@@ -22062,7 +22479,7 @@ function collectMemoryFiles(dir, baseDir, ignoreSubdirs = /* @__PURE__ */ new Se
22062
22479
  return results;
22063
22480
  }
22064
22481
  function computeKxmMemoryRevision(bundle, options = {}) {
22065
- const hash = createHash5("sha256");
22482
+ const hash = createHash6("sha256");
22066
22483
  const memoryDir = options.memoryDir ?? join6(bundle.projectRoot, ".kxm", "memory");
22067
22484
  const memoryFiles = collectMemoryFiles(memoryDir, memoryDir, /* @__PURE__ */ new Set(["candidates"])).sort((left, right) => compareCodeUnits5(left.relPath, right.relPath));
22068
22485
  for (const file of memoryFiles) {
@@ -22213,7 +22630,7 @@ function acceptKxmRun(context, bundle, request, options = {}) {
22213
22630
  }
22214
22631
  const revisions = kxmPolicyRevisions(bundle, options);
22215
22632
  const memoryRevision = options.memoryRevision ?? revisions.memoryRevision;
22216
- const promptSha256 = `sha256:${createHash5("sha256").update(request.prompt, "utf8").digest("hex")}`;
22633
+ const promptSha256 = `sha256:${createHash6("sha256").update(request.prompt, "utf8").digest("hex")}`;
22217
22634
  return context.eventStore.transaction(() => {
22218
22635
  const prior = context.eventStore.command(commandId);
22219
22636
  if (prior) {
@@ -22288,21 +22705,21 @@ function foldStoredKxmRun(context, run) {
22288
22705
  if (!planRow && events.some((event) => event.eventType.startsWith("step.") || event.eventType.startsWith("effect.") || event.payload.status === "preparing" || event.payload.status === "running" || event.payload.status === "cancelling")) {
22289
22706
  throw runtimeError("run_plan_missing", run.runId, "run reached preparing or later without a pinned plan");
22290
22707
  }
22291
- const envelope = planRow ? loadKxmRunPlanEnvelope(context.eventStore, run) : void 0;
22292
- const state = foldKxmRunState(run, envelope?.plan, events, envelope ? {
22708
+ const envelope2 = planRow ? loadKxmRunPlanEnvelope(context.eventStore, run) : void 0;
22709
+ const state = foldKxmRunState(run, envelope2?.plan, events, envelope2 ? {
22293
22710
  observationLookup: (attemptId, observationId) => {
22294
22711
  const row = context.eventStore.gateObservationForAttempt(attemptId);
22295
22712
  if (!row || row.observationId !== observationId) return void 0;
22296
22713
  return { completeness: row.completeness };
22297
22714
  },
22298
22715
  gateKind: (stepId) => {
22299
- const step = envelope.plan.steps[stepId];
22716
+ const step = envelope2.plan.steps[stepId];
22300
22717
  if (!step || step.kind !== "gate") return void 0;
22301
- return envelope.gates.definitions[step.gate]?.kind;
22718
+ return envelope2.gates.definitions[step.gate]?.kind;
22302
22719
  },
22303
- projectLimits: envelope.projectLimits
22720
+ projectLimits: envelope2.projectLimits
22304
22721
  } : {});
22305
- if (envelope) verifyKxmGateEvidence(context.eventStore, run, envelope, events, state);
22722
+ if (envelope2) verifyKxmGateEvidence(context.eventStore, run, envelope2, events, state);
22306
22723
  assertStoredProjection(context, run);
22307
22724
  return state;
22308
22725
  }
@@ -22458,7 +22875,7 @@ function cancelKxmRun(context, runId, options = {}) {
22458
22875
  import { join as join12 } from "node:path";
22459
22876
 
22460
22877
  // plugins/kxm/src/oneshot-evidence.ts
22461
- import { createHash as createHash6, randomUUID as randomUUID3 } from "node:crypto";
22878
+ import { createHash as createHash7, randomUUID as randomUUID3 } from "node:crypto";
22462
22879
  import { lstat, mkdir, open, rename } from "node:fs/promises";
22463
22880
  import { join as join7 } from "node:path";
22464
22881
  var ONESHOT_EVIDENCE_SCHEMA = "kxm.oneshot-evidence.v2";
@@ -22466,7 +22883,7 @@ var RETIRED_ONESHOT_EVIDENCE_SCHEMAS = /* @__PURE__ */ new Set(["kxm.oneshot-evi
22466
22883
  var TEXT_LIMIT = 4 * 1024 * 1024;
22467
22884
  var ARGV_LIMIT = 64 * 1024;
22468
22885
  var RECORD_LIMIT = 16 * 1024 * 1024;
22469
- var digest = (value) => `sha256:${createHash6("sha256").update(value).digest("hex")}`;
22886
+ var digest = (value) => `sha256:${createHash7("sha256").update(value).digest("hex")}`;
22470
22887
  function parseOneShotEvidenceRecord(bytes) {
22471
22888
  let parsed;
22472
22889
  try {
@@ -22576,7 +22993,7 @@ async function beginOneShotEvidence(root, intent, sensitive) {
22576
22993
 
22577
22994
  // plugins/kxm/src/prices.ts
22578
22995
  var import_yaml3 = __toESM(require_dist(), 1);
22579
- import { createHash as createHash7 } from "node:crypto";
22996
+ import { createHash as createHash8 } from "node:crypto";
22580
22997
  import { existsSync as existsSync7, readFileSync as readFileSync5, statSync } from "node:fs";
22581
22998
  import { join as join8 } from "node:path";
22582
22999
 
@@ -22639,7 +23056,7 @@ function hashPriceCatalog(catalog) {
22639
23056
  }))
22640
23057
  })).sort((a, b) => a.id.localeCompare(b.id))
22641
23058
  };
22642
- return createHash7("sha256").update(JSON.stringify(canonical), "utf8").digest("hex");
23059
+ return createHash8("sha256").update(JSON.stringify(canonical), "utf8").digest("hex");
22643
23060
  }
22644
23061
  function parsePriceCatalog(text) {
22645
23062
  const parsed = (0, import_yaml3.parse)(text);
@@ -22740,7 +23157,7 @@ function loadPriceCatalog(rootOrPath) {
22740
23157
 
22741
23158
  // plugins/kxm/src/engine.ts
22742
23159
  var import_yaml5 = __toESM(require_dist(), 1);
22743
- import { createHash as createHash10, randomBytes, timingSafeEqual } from "node:crypto";
23160
+ import { createHash as createHash11, randomBytes, timingSafeEqual } from "node:crypto";
22744
23161
  import { existsSync as existsSync9, readFileSync as readFileSync7 } from "node:fs";
22745
23162
  import { join as join11 } from "node:path";
22746
23163
 
@@ -23122,7 +23539,7 @@ function evaluateArtifactsGate(context, definition) {
23122
23539
 
23123
23540
  // plugins/kxm/src/engine-command.ts
23124
23541
  import { spawn as spawn2 } from "node:child_process";
23125
- import { createHash as createHash8 } from "node:crypto";
23542
+ import { createHash as createHash9 } from "node:crypto";
23126
23543
 
23127
23544
  // plugins/kxm/src/safety-integrity.ts
23128
23545
  var DESTRUCTIVE_COMMAND_PATTERNS = Object.freeze([
@@ -23159,7 +23576,7 @@ function createCommandObserver(input) {
23159
23576
  return new CommandObserver(input);
23160
23577
  }
23161
23578
  var StreamDigest = class {
23162
- hash = createHash8("sha256");
23579
+ hash = createHash9("sha256");
23163
23580
  bytes = 0;
23164
23581
  complete = 0;
23165
23582
  digest() {
@@ -23234,8 +23651,8 @@ var CommandObserver = class {
23234
23651
  this.requestStop("error", "lost-close");
23235
23652
  }
23236
23653
  run() {
23237
- return new Promise((resolve6) => {
23238
- this.resolveOutcome = resolve6;
23654
+ return new Promise((resolve8) => {
23655
+ this.resolveOutcome = resolve8;
23239
23656
  try {
23240
23657
  this.start();
23241
23658
  } catch (error) {
@@ -23579,9 +23996,9 @@ function schedule(ms, fn) {
23579
23996
  }
23580
23997
 
23581
23998
  // plugins/kxm/src/engine-gate-records.ts
23582
- function recordGateIntentInTransaction(context, run, envelope, stepId) {
23583
- const step = requireGateStep(envelope, stepId, run.runId);
23584
- const definition = envelope.gates.definitions[step.gate];
23999
+ function recordGateIntentInTransaction(context, run, envelope2, stepId) {
24000
+ const step = requireGateStep(envelope2, stepId, run.runId);
24001
+ const definition = envelope2.gates.definitions[step.gate];
23585
24002
  if (!definition || definition.kind === "reserved") {
23586
24003
  throw runtimeError("gate_row_invalid", run.runId, "reserved gates cannot record intent in this slice");
23587
24004
  }
@@ -23634,9 +24051,9 @@ function recordGateIntentInTransaction(context, run, envelope, stepId) {
23634
24051
  gateKind: definition.kind,
23635
24052
  expect: step.expect,
23636
24053
  gateDefinitionHash: gateDefinitionHash(step.gate, definition),
23637
- registryHash: envelope.gates.registry.hash,
23638
- runPlanHash: envelope && folded.runPlanHash ? folded.runPlanHash : hashFromStore(context, run.runId),
23639
- controlProjectKey: envelope.gates.controlRoot.projectKey,
24054
+ registryHash: envelope2.gates.registry.hash,
24055
+ runPlanHash: envelope2 && folded.runPlanHash ? folded.runPlanHash : hashFromStore(context, run.runId),
24056
+ controlProjectKey: envelope2.gates.controlRoot.projectKey,
23640
24057
  producerId: "kxm-gate",
23641
24058
  intentEventId: intent.eventId,
23642
24059
  contentHash: ""
@@ -23646,8 +24063,8 @@ function recordGateIntentInTransaction(context, run, envelope, stepId) {
23646
24063
  context.eventStore.insertGateAttempt(withHash);
23647
24064
  return persist(context, run, now, seq.events.at(-1).sequence);
23648
24065
  }
23649
- function recordGateSpawnedInTransaction(context, run, envelope, stepId) {
23650
- const ids = requireIntent(context, run, envelope, stepId);
24066
+ function recordGateSpawnedInTransaction(context, run, envelope2, stepId) {
24067
+ const ids = requireIntent(context, run, envelope2, stepId);
23651
24068
  if (ids.gateKind !== "command") throw runtimeError("gate_row_invalid", run.runId, "effect.dispatched is command-only");
23652
24069
  const now = (/* @__PURE__ */ new Date()).toISOString();
23653
24070
  const seq = sequencer(context, run, now);
@@ -23663,8 +24080,8 @@ function recordGateSpawnedInTransaction(context, run, envelope, stepId) {
23663
24080
  for (const event of seq.events) context.eventStore.appendEvent(event);
23664
24081
  return persist(context, run, now, seq.events.at(-1).sequence);
23665
24082
  }
23666
- function recordGateSettlementInTransaction(context, run, envelope, stepId, observation) {
23667
- const ids = requireIntent(context, run, envelope, stepId);
24083
+ function recordGateSettlementInTransaction(context, run, envelope2, stepId, observation) {
24084
+ const ids = requireIntent(context, run, envelope2, stepId);
23668
24085
  assertClosedGateObservation(ids.gateKind, observation);
23669
24086
  const outcome = computeGateEvidenceOutcome(ids.gateKind, ids.expect, observation);
23670
24087
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -23704,7 +24121,7 @@ function recordGateSettlementInTransaction(context, run, envelope, stepId, obser
23704
24121
  stepAttempt: ids.stepAttempt,
23705
24122
  assignmentId: ids.assignmentId,
23706
24123
  effectId: ids.effectId,
23707
- evidenceKey: evidenceKeyFor(envelope, stepId),
24124
+ evidenceKey: evidenceKeyFor(envelope2, stepId),
23708
24125
  kind: "gate",
23709
24126
  expect: ids.expect,
23710
24127
  outcome,
@@ -23723,15 +24140,15 @@ function recordGateSettlementInTransaction(context, run, envelope, stepId, obser
23723
24140
  evidenceDraft.settledEventId = settled.eventId;
23724
24141
  evidenceDraft.contentHash = gateRowContentHash("gate_evidence", { ...evidenceDraft, contentHash: "" });
23725
24142
  settled.payload.evidenceRefs[0].hash = evidenceDraft.contentHash;
23726
- appendEvaluatedTail(seq, envelope, ids, stepId, outcome);
24143
+ appendEvaluatedTail(seq, envelope2, ids, stepId, outcome);
23727
24144
  for (const event of seq.events) context.eventStore.appendEvent(event);
23728
24145
  context.eventStore.insertGateObservation(observationRow);
23729
24146
  context.eventStore.insertGateEvidence(evidenceDraft);
23730
24147
  context.eventStore.settleCapability(ids.attemptId, "settled");
23731
24148
  return persist(context, run, now, seq.events.at(-1).sequence);
23732
24149
  }
23733
- function recordGateNoStartInTransaction(context, run, envelope, stepId, observation) {
23734
- const ids = requireIntent(context, run, envelope, stepId);
24150
+ function recordGateNoStartInTransaction(context, run, envelope2, stepId, observation) {
24151
+ const ids = requireIntent(context, run, envelope2, stepId);
23735
24152
  assertClosedGateObservation(ids.gateKind, observation);
23736
24153
  if (observation.completeness !== "no-start") {
23737
24154
  throw runtimeError("gate_row_invalid", run.runId, "no-start proof requires spawned 0 and completeness no-start");
@@ -23784,8 +24201,8 @@ function recordGateNoStartInTransaction(context, run, envelope, stepId, observat
23784
24201
  context.eventStore.settleCapability(ids.attemptId, "settled");
23785
24202
  return persist(context, run, now, seq.events.at(-1).sequence);
23786
24203
  }
23787
- function recordGateUncertainInTransaction(context, run, envelope, stepId, reason, observation) {
23788
- const ids = requireIntent(context, run, envelope, stepId);
24204
+ function recordGateUncertainInTransaction(context, run, envelope2, stepId, reason, observation) {
24205
+ const ids = requireIntent(context, run, envelope2, stepId);
23789
24206
  if (observation.completeness !== "incomplete") {
23790
24207
  throw runtimeError("gate_row_invalid", run.runId, "uncertainty observation must be incomplete");
23791
24208
  }
@@ -23814,8 +24231,8 @@ function recordGateUncertainInTransaction(context, run, envelope, stepId, reason
23814
24231
  context.eventStore.insertGateObservation(observationRow);
23815
24232
  return persist(context, run, now, seq.events.at(-1).sequence);
23816
24233
  }
23817
- function recordGateCancelObservedInTransaction(context, run, envelope, stepId, observation) {
23818
- const ids = requireIntent(context, run, envelope, stepId);
24234
+ function recordGateCancelObservedInTransaction(context, run, envelope2, stepId, observation) {
24235
+ const ids = requireIntent(context, run, envelope2, stepId);
23819
24236
  assertClosedGateObservation(ids.gateKind, observation);
23820
24237
  if (observation.completeness !== "complete") {
23821
24238
  throw runtimeError("gate_row_invalid", run.runId, "cancel-after-observation requires a complete observation");
@@ -23874,19 +24291,19 @@ function recordGateCancelObservedInTransaction(context, run, envelope, stepId, o
23874
24291
  context.eventStore.settleCapability(ids.attemptId, "settled");
23875
24292
  return persist(context, run, now, seq.events.at(-1).sequence);
23876
24293
  }
23877
- function appendEvaluatedTail(seq, envelope, ids, stepId, outcome) {
24294
+ function appendEvaluatedTail(seq, envelope2, ids, stepId, outcome) {
23878
24295
  const mapped = outcome === "passed" ? "passed" : outcome === "repro-missing" ? "failed" : "failed";
23879
24296
  seq.push("assignment.result_recorded", { assignmentId: ids.assignmentId, resultClass: "outcome", outcome, status: "result_recorded" });
23880
24297
  seq.push("attempt.status_changed", { attemptId: ids.attemptId, status: "terminal" });
23881
24298
  seq.push("assignment.terminal", { assignmentId: ids.assignmentId, outcome, status: "terminal" });
23882
24299
  seq.push("step.outcome_recorded", { stepId, stepAttempt: ids.stepAttempt, outcome });
23883
24300
  seq.push("step.status_changed", { stepId, status: mapped, previousStatus: "running" });
23884
- const selected = envelope.plan.steps[stepId].transitions[outcome];
24301
+ const selected = envelope2.plan.steps[stepId].transitions[outcome];
23885
24302
  if (!selected) {
23886
24303
  seq.push("run.status_changed", { status: "failed", reason: "outcome_unknown", stepId, outcome });
23887
24304
  return;
23888
24305
  }
23889
- const budget = kxmTransitionBudgetFailure(envelope.plan, ids.state, stepId, outcome);
24306
+ const budget = kxmTransitionBudgetFailure(envelope2.plan, ids.state, stepId, outcome);
23890
24307
  if (budget) {
23891
24308
  seq.push("run.status_changed", { status: "failed", reason: budget, stepId, outcome });
23892
24309
  return;
@@ -23898,8 +24315,8 @@ function appendEvaluatedTail(seq, envelope, ids, stepId, outcome) {
23898
24315
  seq.push("run.status_changed", { status: selected.terminalStatus });
23899
24316
  }
23900
24317
  }
23901
- function evidenceKeyFor(envelope, stepId) {
23902
- const required = envelope.plan.steps[stepId]?.requiredEvidence.filter((item) => item.kind === "gate") ?? [];
24318
+ function evidenceKeyFor(envelope2, stepId) {
24319
+ const required = envelope2.plan.steps[stepId]?.requiredEvidence.filter((item) => item.kind === "gate") ?? [];
23903
24320
  return required.length === 1 ? required[0].key : null;
23904
24321
  }
23905
24322
  function placeholderReceipt(observationId, kind, now) {
@@ -23932,13 +24349,13 @@ function buildObservation(ids, observation, observationId, recordedEventId) {
23932
24349
  };
23933
24350
  return { ...row, contentHash: gateRowContentHash("gate_observations", { ...row, contentHash: "" }) };
23934
24351
  }
23935
- function requireGateStep(envelope, stepId, runId) {
23936
- const step = envelope.plan.steps[stepId];
24352
+ function requireGateStep(envelope2, stepId, runId) {
24353
+ const step = envelope2.plan.steps[stepId];
23937
24354
  if (!step || step.kind !== "gate") throw runtimeError("run_events_illegal", runId, `step ${stepId} is not a gate`);
23938
24355
  return step;
23939
24356
  }
23940
- function requireIntent(context, run, envelope, stepId) {
23941
- const step = requireGateStep(envelope, stepId, run.runId);
24357
+ function requireIntent(context, run, envelope2, stepId) {
24358
+ const step = requireGateStep(envelope2, stepId, run.runId);
23942
24359
  const folded = foldStoredKxmRun(context, run);
23943
24360
  const attemptId = folded.currentStep?.attemptId;
23944
24361
  if (!attemptId || folded.currentStep?.stepId !== stepId) {
@@ -24006,7 +24423,7 @@ function hashFromStore(context, runId) {
24006
24423
  }
24007
24424
 
24008
24425
  // plugins/kxm/src/routing.ts
24009
- import { createHash as createHash9 } from "node:crypto";
24426
+ import { createHash as createHash10 } from "node:crypto";
24010
24427
  var ROUTING_RECORD_V2_SCHEMA = "kxm.routing-record.v2";
24011
24428
  var BEHAVIORAL_HASH_VERSION = 1;
24012
24429
  var MAX_PROVIDER_METADATA_FIELDS = 32;
@@ -24029,7 +24446,7 @@ function behavioralConfigHash(input) {
24029
24446
  workflowDefinitionSha256: input.workflowDefinitionSha256?.trim() ?? null,
24030
24447
  verifierConfigSha256: input.verifierConfigSha256?.trim() ?? null
24031
24448
  };
24032
- return createHash9("sha256").update(JSON.stringify(canonical), "utf8").digest("hex");
24449
+ return createHash10("sha256").update(JSON.stringify(canonical), "utf8").digest("hex");
24033
24450
  }
24034
24451
  function boundedInt(value, field) {
24035
24452
  if (value === void 0 || value === null) return void 0;
@@ -24198,7 +24615,7 @@ function requireTrustedProducer(producer) {
24198
24615
  }
24199
24616
  }
24200
24617
  function hashCapabilitySecret(secret) {
24201
- return `sha256:${createHash10("sha256").update(`${CAPABILITY_PREFIX}${secret}`, "utf8").digest("hex")}`;
24618
+ return `sha256:${createHash11("sha256").update(`${CAPABILITY_PREFIX}${secret}`, "utf8").digest("hex")}`;
24202
24619
  }
24203
24620
  function mintKxmCapabilitySecret() {
24204
24621
  const secret = `kxmcap_${randomBytes(32).toString("base64url")}`;
@@ -24227,7 +24644,7 @@ function pinKxmCompiledPlan(context, bundle, runId, options) {
24227
24644
  value: workflow.value,
24228
24645
  ...workflow.logicalPath !== void 0 ? { logicalPath: workflow.logicalPath } : {}
24229
24646
  }));
24230
- const envelope = {
24647
+ const envelope2 = {
24231
24648
  schema: KXM_RUN_PLAN_SCHEMA,
24232
24649
  runId: run.runId,
24233
24650
  projectId: run.projectId,
@@ -24243,7 +24660,7 @@ function pinKxmCompiledPlan(context, bundle, runId, options) {
24243
24660
  plan: compiled,
24244
24661
  gates: pinnedGatesForCompiledPlan(compiled, bundle, context.projectRoot)
24245
24662
  };
24246
- const runPlanHash = hashKxmRunPlanEnvelope(envelope);
24663
+ const runPlanHash = hashKxmRunPlanEnvelope(envelope2);
24247
24664
  const existing = context.eventStore.runPlan(runId);
24248
24665
  if (existing) {
24249
24666
  if (existing.runPlanHash !== runPlanHash) {
@@ -24266,7 +24683,7 @@ function pinKxmCompiledPlan(context, bundle, runId, options) {
24266
24683
  context.eventStore.insertRunPlan({
24267
24684
  runId,
24268
24685
  runPlanHash,
24269
- envelope: kxmCanonicalJson(envelope),
24686
+ envelope: kxmCanonicalJson(envelope2),
24270
24687
  pinnedSequence: sequence
24271
24688
  });
24272
24689
  context.eventStore.appendEvent(event);
@@ -24279,8 +24696,8 @@ function pinKxmCompiledPlan(context, bundle, runId, options) {
24279
24696
  function startKxmRun(context, runId, options = {}) {
24280
24697
  return context.eventStore.transaction(() => {
24281
24698
  const run = requireRun(context, runId);
24282
- const envelope = loadKxmRunPlanEnvelope(context.eventStore, run);
24283
- const unsupported = options.allowLimits ? void 0 : unsupportedLimit(envelope);
24699
+ const envelope2 = loadKxmRunPlanEnvelope(context.eventStore, run);
24700
+ const unsupported = options.allowLimits ? void 0 : unsupportedLimit(envelope2);
24284
24701
  const state = foldStoredKxmRun(context, run);
24285
24702
  if (unsupported) {
24286
24703
  return { state, handoff: unsupported };
@@ -24327,7 +24744,7 @@ async function driveAdmitted(context, runId, producer, token, options = {}) {
24327
24744
  return latest;
24328
24745
  }
24329
24746
  function newDriveId(runId, token, runtimeId, monotonicNs) {
24330
- return `drv_${createHash10("sha256").update(`${runId}\0${token}\0${runtimeId}\0${monotonicNs}`, "utf8").digest("hex").slice(0, 24)}`;
24747
+ return `drv_${createHash11("sha256").update(`${runId}\0${token}\0${runtimeId}\0${monotonicNs}`, "utf8").digest("hex").slice(0, 24)}`;
24331
24748
  }
24332
24749
  function driveErrorSummary(error) {
24333
24750
  const raw = error instanceof KxmConfigError ? error.issues[0]?.code : void 0;
@@ -24519,12 +24936,12 @@ var KxmRunScheduler = class _KxmRunScheduler {
24519
24936
  }
24520
24937
  try {
24521
24938
  const run = requireRun(this.context, runId);
24522
- const envelope = loadKxmRunPlanEnvelope(this.context.eventStore, run);
24939
+ const envelope2 = loadKxmRunPlanEnvelope(this.context.eventStore, run);
24523
24940
  return enqueueKxmScheduledRun(
24524
24941
  this.context.eventStore.path,
24525
24942
  runId,
24526
- envelope.revisions.config,
24527
- envelope.projectLimits.maxConcurrentRuns,
24943
+ envelope2.revisions.config,
24944
+ envelope2.projectLimits.maxConcurrentRuns,
24528
24945
  (token) => driveAdmitted(this.context, runId, producer, token, options)
24529
24946
  );
24530
24947
  } catch (error) {
@@ -24554,8 +24971,8 @@ var KxmRunScheduler = class _KxmRunScheduler {
24554
24971
  resolve: (_value) => void 0,
24555
24972
  reject: (_error) => void 0
24556
24973
  };
24557
- const settled = new Promise((resolve6, reject) => {
24558
- pending.resolve = resolve6;
24974
+ const settled = new Promise((resolve8, reject) => {
24975
+ pending.resolve = resolve8;
24559
24976
  pending.reject = reject;
24560
24977
  });
24561
24978
  void settled.then(void 0, () => void 0);
@@ -25094,10 +25511,10 @@ function prepareDispatch(context, runId, producerId) {
25094
25511
  return { kind: "return", ...failBudget(context, run, plan, state, "budget_unmetered_attempts", stepId) };
25095
25512
  }
25096
25513
  if (step.kind === "gate") {
25097
- const envelope = loadKxmRunPlanEnvelope(context.eventStore, run);
25098
- const unsupported2 = unsupportedGateStep(plan, step, envelope, context);
25514
+ const envelope2 = loadKxmRunPlanEnvelope(context.eventStore, run);
25515
+ const unsupported2 = unsupportedGateStep(plan, step, envelope2, context);
25099
25516
  if (unsupported2) return { kind: "return", state, handoff: { ...unsupported2, stepId } };
25100
- const definition = envelope.gates.definitions[step.gate];
25517
+ const definition = envelope2.gates.definitions[step.gate];
25101
25518
  if (definition?.kind === "command") {
25102
25519
  const preflightResult = gateRecoveryPreflight(context);
25103
25520
  const firstBlocking = preflightResult.blocking[0];
@@ -25113,7 +25530,7 @@ function prepareDispatch(context, runId, producerId) {
25113
25530
  };
25114
25531
  }
25115
25532
  }
25116
- const result = recordGateIntentInTransaction(context, run, envelope, stepId);
25533
+ const result = recordGateIntentInTransaction(context, run, envelope2, stepId);
25117
25534
  const current = result.state.currentStep;
25118
25535
  const attemptId = current?.attemptId;
25119
25536
  const assignmentId = current?.assignmentId;
@@ -25124,7 +25541,7 @@ function prepareDispatch(context, runId, producerId) {
25124
25541
  return {
25125
25542
  kind: "gate",
25126
25543
  run,
25127
- envelope,
25544
+ envelope: envelope2,
25128
25545
  stepId,
25129
25546
  stepAttempt: current.stepAttempt,
25130
25547
  assignmentId,
@@ -25230,7 +25647,7 @@ function birthMember(context, input) {
25230
25647
  if (promptText === void 0) {
25231
25648
  throw runtimeError("run_prompt_mismatch", run.runId, "prompt text missing from accepted run prompt store");
25232
25649
  }
25233
- const promptHash = createHash10("sha256").update(promptText, "utf8").digest("hex");
25650
+ const promptHash = createHash11("sha256").update(promptText, "utf8").digest("hex");
25234
25651
  const expectedHash = run.promptSha256.replace(/^sha256:/, "");
25235
25652
  if (promptHash !== expectedHash) {
25236
25653
  throw runtimeError("run_prompt_mismatch", run.runId, "prompt text does not match accepted promptSha256");
@@ -25608,12 +26025,12 @@ function producerRoutingRecord(context, dispatch, result, now) {
25608
26025
  if (result.costBasis === "metered" && (typeof result.costUsd !== "number" || !Number.isFinite(result.costUsd) || result.costUsd < 0)) {
25609
26026
  throw runtimeError("settle_invalid_cost", run.runId, "attempt settlement rejected: metered costBasis requires non-negative finite costUsd");
25610
26027
  }
25611
- const envelope = loadKxmRunPlanEnvelope(context.eventStore, run);
26028
+ const envelope2 = loadKxmRunPlanEnvelope(context.eventStore, run);
25612
26029
  const rawHash = result.behavioralSha256 ?? behavioralConfigHash({
25613
26030
  requestedModel: result.requestedModel ?? "simulated",
25614
26031
  effectiveModel: result.effectiveModel ?? result.requestedModel ?? "simulated",
25615
26032
  agentRole: dispatch.step.kind === "agent" || dispatch.step.kind === "moa" ? dispatch.step.agent : void 0,
25616
- toolPolicyVersion: envelope.revisions.toolPolicy
26033
+ toolPolicyVersion: envelope2.revisions.toolPolicy
25617
26034
  });
25618
26035
  const record2 = {
25619
26036
  schema: ROUTING_RECORD_V2_SCHEMA,
@@ -25674,12 +26091,12 @@ function settleMember(context, dispatch, result, produceError, produceErrorCode)
25674
26091
  push("attempt.status_changed", { attemptId: dispatch.attemptId, status: "terminal" });
25675
26092
  push("assignment.terminal", { assignmentId: dispatch.assignmentId, outcome: "cancelled", status: "terminal" });
25676
26093
  } else if (produceError) {
25677
- const envelope = loadKxmRunPlanEnvelope(context.eventStore, run);
26094
+ const envelope2 = loadKxmRunPlanEnvelope(context.eventStore, run);
25678
26095
  const rawHash = result?.behavioralSha256 ?? behavioralConfigHash({
25679
26096
  requestedModel: result?.requestedModel ?? "simulated",
25680
26097
  effectiveModel: result?.effectiveModel ?? result?.requestedModel ?? "simulated",
25681
26098
  agentRole: dispatch.step.kind === "agent" || dispatch.step.kind === "moa" ? dispatch.step.agent : void 0,
25682
- toolPolicyVersion: envelope.revisions.toolPolicy
26099
+ toolPolicyVersion: envelope2.revisions.toolPolicy
25683
26100
  });
25684
26101
  const behavioralSha256 = rawHash.startsWith("sha256:") ? rawHash : `sha256:${rawHash}`;
25685
26102
  const routingRecord = {
@@ -25894,8 +26311,8 @@ function declaredRunDurationBudget(context, runId) {
25894
26311
  const run = context.eventStore.run(runId);
25895
26312
  if (!run) return void 0;
25896
26313
  try {
25897
- const envelope = loadKxmRunPlanEnvelope(context.eventStore, run);
25898
- return effectiveRunDurationBudget(envelope.plan.limits, envelope.projectLimits);
26314
+ const envelope2 = loadKxmRunPlanEnvelope(context.eventStore, run);
26315
+ return effectiveRunDurationBudget(envelope2.plan.limits, envelope2.projectLimits);
25899
26316
  } catch {
25900
26317
  return void 0;
25901
26318
  }
@@ -26001,11 +26418,11 @@ function armRunDurationBudgetTimer(context, runId) {
26001
26418
  unhook();
26002
26419
  };
26003
26420
  }
26004
- function unsupportedLimit(envelope) {
26005
- if (envelope.plan.limits.maxAgentTimeMs !== void 0) {
26421
+ function unsupportedLimit(envelope2) {
26422
+ if (envelope2.plan.limits.maxAgentTimeMs !== void 0) {
26006
26423
  return { reason: "limit_unsupported", field: "limits.maxAgentTimeMs", detail: "agent-time budget enforcement is not available in this slice" };
26007
26424
  }
26008
- if (envelope.projectLimits.maxAgentTimeMs !== void 0) {
26425
+ if (envelope2.projectLimits.maxAgentTimeMs !== void 0) {
26009
26426
  return { reason: "limit_unsupported", field: "project.limits.maxAgentTimeMs", detail: "agent-time budget enforcement is not available in this slice" };
26010
26427
  }
26011
26428
  return void 0;
@@ -26058,12 +26475,12 @@ function unsupportedStep(plan, step, producerId) {
26058
26475
  }
26059
26476
  return void 0;
26060
26477
  }
26061
- function unsupportedGateStep(plan, step, envelope, context) {
26478
+ function unsupportedGateStep(plan, step, envelope2, context) {
26062
26479
  if (!step.gate) return { reason: "step_unsupported", field: "gate", detail: "gate step is missing gate id" };
26063
- if (envelope.gates.registry === null) {
26480
+ if (envelope2.gates.registry === null) {
26064
26481
  return { reason: "step_unsupported", field: "gate", detail: `step ${step.id} refers to a gate but registry is null` };
26065
26482
  }
26066
- const definition = envelope.gates.definitions[step.gate];
26483
+ const definition = envelope2.gates.definitions[step.gate];
26067
26484
  if (!definition) {
26068
26485
  return { reason: "step_unsupported", field: "gate", detail: `gate definition ${step.gate} not found in registry` };
26069
26486
  }
@@ -26169,7 +26586,7 @@ function unsupportedGateStep(plan, step, envelope, context) {
26169
26586
  return { reason: "gate_outcome_undeclared", field: "outcomes", detail: "step expects fail but missing required failure outcome; declare implementation-failure or failed" };
26170
26587
  }
26171
26588
  }
26172
- if (context && projectRuntimeKey(context.projectRoot) !== envelope.gates.controlRoot.projectKey) {
26589
+ if (context && projectRuntimeKey(context.projectRoot) !== envelope2.gates.controlRoot.projectKey) {
26173
26590
  throw runtimeError("run_owner_mismatch", plan.workflowId, `gate control root does not match project`);
26174
26591
  }
26175
26592
  if (definition.kind === "artifacts-exist" && step.expect === "fail") {
@@ -26808,28 +27225,290 @@ Return a final JSON object with an "outcome" field chosen from ${JSON.stringify(
26808
27225
  return producer;
26809
27226
  }
26810
27227
 
27228
+ // plugins/kxm/src/client.ts
27229
+ import { hostname } from "node:os";
27230
+
27231
+ // plugins/kxm/src/protocol.ts
27232
+ var DEFAULT_MESSAGE_TTL_MS = 24 * 60 * 6e4;
27233
+ var MAX_MESSAGE_TTL_MS = 7 * 24 * 60 * 6e4;
27234
+ var DEFAULT_MESSAGE_RETENTION_MS = 7 * 24 * 60 * 6e4;
27235
+ var MAX_BODY_BYTES = 256 * 1024;
27236
+ var MAX_AGENT_HOST_CHARS = 64;
27237
+ var MAX_LEASE_TTL_MS = 10 * 6e4;
27238
+ var DEFAULT_LEASE_TTL_MS = 5 * 6e4;
27239
+
27240
+ // plugins/kxm/src/client.ts
27241
+ function defaultHostLabel() {
27242
+ try {
27243
+ return hostname().trim().slice(0, MAX_AGENT_HOST_CHARS) || void 0;
27244
+ } catch {
27245
+ return void 0;
27246
+ }
27247
+ }
27248
+ var HubHttpError = class extends Error {
27249
+ statusCode;
27250
+ code;
27251
+ requestId;
27252
+ extras;
27253
+ constructor(statusCode, message, code, requestId, extras) {
27254
+ super(message);
27255
+ this.name = "HubHttpError";
27256
+ this.statusCode = statusCode;
27257
+ if (code) this.code = code;
27258
+ if (requestId) this.requestId = requestId;
27259
+ if (extras) this.extras = extras;
27260
+ }
27261
+ };
27262
+ async function hubJsonRequest(options, path, init, headers) {
27263
+ const requestTimeoutMs = options.requestTimeoutMs ?? 15e3;
27264
+ const timeoutSignal = AbortSignal.timeout(requestTimeoutMs);
27265
+ const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
27266
+ let response;
27267
+ try {
27268
+ response = await (options.fetchImpl ?? fetch)(`${options.serverUrl.replace(/\/$/, "")}${path}`, {
27269
+ ...init,
27270
+ signal,
27271
+ headers: { ...headers, ...init.headers ?? {} }
27272
+ });
27273
+ } catch (error) {
27274
+ if (timeoutSignal.aborted) throw new Error(`request timed out after ${requestTimeoutMs}ms`);
27275
+ throw error;
27276
+ }
27277
+ const text = await response.text();
27278
+ let body = {};
27279
+ if (text) {
27280
+ try {
27281
+ body = JSON.parse(text);
27282
+ } catch {
27283
+ throw new Error(`hub returned invalid JSON with HTTP ${response.status}`);
27284
+ }
27285
+ }
27286
+ if (!response.ok) {
27287
+ const extras = {};
27288
+ for (const key of ["operation", "nextAction", "assignedCoordinatorName"]) {
27289
+ if (typeof body[key] === "string") extras[key] = body[key];
27290
+ }
27291
+ if (body.lease && typeof body.lease === "object") extras.lease = body.lease;
27292
+ throw new HubHttpError(
27293
+ response.status,
27294
+ String(body.error ?? `HTTP ${response.status}`),
27295
+ typeof body.code === "string" ? body.code : void 0,
27296
+ response.headers.get("x-request-id") ?? void 0,
27297
+ Object.keys(extras).length > 0 ? extras : void 0
27298
+ );
27299
+ }
27300
+ return body;
27301
+ }
27302
+ var RuntimeHubClient = class {
27303
+ options;
27304
+ constructor(options) {
27305
+ this.options = options;
27306
+ }
27307
+ async heartbeat() {
27308
+ const result = await this.request("/v1/runtime/presence", {
27309
+ project: this.options.project,
27310
+ runtimeId: this.options.runtimeId,
27311
+ host: this.options.host ?? defaultHostLabel()
27312
+ });
27313
+ return result.presence;
27314
+ }
27315
+ /** Push already-derived `kxm.sync-event.v1` objects, in outbox order. */
27316
+ async pushSyncEvents(events) {
27317
+ return await this.request("/v1/sync/events", {
27318
+ project: this.options.project,
27319
+ runtimeId: this.options.runtimeId,
27320
+ events
27321
+ });
27322
+ }
27323
+ async request(path, body) {
27324
+ const headers = { "content-type": "application/json" };
27325
+ if (this.options.authToken) headers.authorization = `Bearer ${this.options.authToken}`;
27326
+ return await hubJsonRequest(this.options, path, { method: "POST", body: JSON.stringify(body) }, headers);
27327
+ }
27328
+ };
27329
+
27330
+ // plugins/kxm/src/hub-binding.ts
27331
+ import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync, rmSync, writeFileSync as writeFileSync4 } from "node:fs";
27332
+ import { homedir as homedir2 } from "node:os";
27333
+ import { dirname as dirname6, isAbsolute as isAbsolute4, join as join13, resolve as resolve6 } from "node:path";
27334
+ var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
27335
+ var HubBindingError = class extends Error {
27336
+ constructor(message) {
27337
+ super(message);
27338
+ this.name = "HubBindingError";
27339
+ }
27340
+ };
27341
+ function resolveUserStateRoot(env) {
27342
+ const explicit = env.KXM_STATE_HOME?.trim();
27343
+ if (explicit) {
27344
+ if (!isAbsolute4(explicit)) throw new HubBindingError("local_state_root_not_absolute");
27345
+ return resolve6(explicit);
27346
+ }
27347
+ if (process.platform === "win32") {
27348
+ const localAppData = env.LOCALAPPDATA?.trim();
27349
+ const base2 = localAppData && isAbsolute4(localAppData) ? localAppData : join13(homedir2(), "AppData", "Local");
27350
+ return resolve6(base2, "KXM");
27351
+ }
27352
+ if (process.platform === "darwin") return resolve6(homedir2(), "Library", "Application Support", "KXM");
27353
+ const xdgState = env.XDG_STATE_HOME?.trim();
27354
+ const base = xdgState && isAbsolute4(xdgState) ? xdgState : join13(homedir2(), ".local", "state");
27355
+ return resolve6(base, "kxm");
27356
+ }
27357
+ function hubBindingFile(env = process.env) {
27358
+ return join13(resolveUserStateRoot(env), "hub-binding.json");
27359
+ }
27360
+ function validateHubUrl(raw) {
27361
+ let parsed;
27362
+ try {
27363
+ parsed = new URL(raw);
27364
+ } catch {
27365
+ throw new HubBindingError("hub_url_invalid");
27366
+ }
27367
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "" || raw.includes("?") || raw.includes("#")) {
27368
+ throw new HubBindingError("hub_url_invalid");
27369
+ }
27370
+ return parsed.href.replace(/\/$/, "");
27371
+ }
27372
+ function isIsoTimestamp(value) {
27373
+ if (Number.isNaN(Date.parse(value))) return false;
27374
+ return value === new Date(value).toISOString();
27375
+ }
27376
+ function readHubBinding(env = process.env) {
27377
+ const file = hubBindingFile(env);
27378
+ if (!existsSync10(file)) return void 0;
27379
+ let parsed;
27380
+ try {
27381
+ parsed = JSON.parse(readFileSync8(file, "utf8"));
27382
+ } catch {
27383
+ throw new HubBindingError(`malformed hub binding at ${file}`);
27384
+ }
27385
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
27386
+ throw new HubBindingError(`malformed hub binding at ${file}`);
27387
+ }
27388
+ const row = parsed;
27389
+ const keys = Object.keys(row);
27390
+ if (keys.length !== 3 || row.schema !== HUB_BINDING_SCHEMA || typeof row.url !== "string" || typeof row.boundAt !== "string" || !isIsoTimestamp(row.boundAt)) {
27391
+ throw new HubBindingError(`malformed hub binding at ${file}`);
27392
+ }
27393
+ let url;
27394
+ try {
27395
+ url = validateHubUrl(row.url);
27396
+ } catch {
27397
+ throw new HubBindingError(`malformed hub binding at ${file}`);
27398
+ }
27399
+ return { schema: HUB_BINDING_SCHEMA, url, boundAt: row.boundAt };
27400
+ }
27401
+
27402
+ // plugins/kxm/src/hub-env.ts
27403
+ import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync9, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "node:fs";
27404
+ import { homedir as homedir3 } from "node:os";
27405
+ import { dirname as dirname7, isAbsolute as isAbsolute5, join as join14, resolve as resolve7 } from "node:path";
27406
+ var HUB_ENV_SCHEMA = "kxm.hub-env.v1";
27407
+ var HubEnvError = class extends Error {
27408
+ constructor(message) {
27409
+ super(message);
27410
+ this.name = "HubEnvError";
27411
+ }
27412
+ };
27413
+ function resolveUserStateRoot2(env) {
27414
+ const explicit = env.KXM_STATE_HOME?.trim();
27415
+ if (explicit) {
27416
+ if (!isAbsolute5(explicit)) throw new HubEnvError("local_state_root_not_absolute");
27417
+ return resolve7(explicit);
27418
+ }
27419
+ if (process.platform === "win32") {
27420
+ const localAppData = env.LOCALAPPDATA?.trim();
27421
+ const base2 = localAppData && isAbsolute5(localAppData) ? localAppData : join14(homedir3(), "AppData", "Local");
27422
+ return resolve7(base2, "KXM");
27423
+ }
27424
+ if (process.platform === "darwin") return resolve7(homedir3(), "Library", "Application Support", "KXM");
27425
+ const xdgState = env.XDG_STATE_HOME?.trim();
27426
+ const base = xdgState && isAbsolute5(xdgState) ? xdgState : join14(homedir3(), ".local", "state");
27427
+ return resolve7(base, "kxm");
27428
+ }
27429
+ function hubEnvFile(env = process.env) {
27430
+ return join14(resolveUserStateRoot2(env), "hub-env.json");
27431
+ }
27432
+ function readHubEnvRecord(env = process.env) {
27433
+ const file = hubEnvFile(env);
27434
+ if (!existsSync11(file)) return void 0;
27435
+ let parsed;
27436
+ try {
27437
+ parsed = JSON.parse(readFileSync9(file, "utf8"));
27438
+ } catch (error) {
27439
+ throw new HubEnvError(`hub env file is malformed at ${file}: ${error instanceof Error ? error.message : String(error)}`);
27440
+ }
27441
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
27442
+ throw new HubEnvError(`hub env file is malformed at ${file}: expected a JSON object`);
27443
+ }
27444
+ const record2 = parsed;
27445
+ if (record2.schema !== HUB_ENV_SCHEMA) {
27446
+ throw new HubEnvError(`hub env file at ${file} has unsupported schema ${String(record2.schema)}`);
27447
+ }
27448
+ if (record2.authToken !== void 0 && (typeof record2.authToken !== "string" || record2.authToken.trim().length === 0)) {
27449
+ throw new HubEnvError(`hub env file at ${file} has an invalid authToken`);
27450
+ }
27451
+ if (record2.projectTokens !== void 0) {
27452
+ const tokens = record2.projectTokens;
27453
+ if (!tokens || typeof tokens !== "object" || Array.isArray(tokens)) {
27454
+ throw new HubEnvError(`hub env file at ${file} has invalid projectTokens`);
27455
+ }
27456
+ for (const [project, token] of Object.entries(tokens)) {
27457
+ if (!project.trim() || typeof token !== "string" || !token.trim()) {
27458
+ throw new HubEnvError(`hub env file at ${file} has an empty project name or token`);
27459
+ }
27460
+ }
27461
+ }
27462
+ return {
27463
+ schema: HUB_ENV_SCHEMA,
27464
+ createdAt: typeof record2.createdAt === "string" ? record2.createdAt : "",
27465
+ ...record2.authToken !== void 0 ? { authToken: record2.authToken } : {},
27466
+ ...record2.projectTokens !== void 0 ? { projectTokens: record2.projectTokens } : {}
27467
+ };
27468
+ }
27469
+ function resolveClientHubAuthToken(env, project) {
27470
+ const envToken = env.KXM_AUTH_TOKEN?.trim();
27471
+ if (envToken) return envToken;
27472
+ const record2 = readHubEnvRecord(env);
27473
+ return record2?.projectTokens?.[project]?.trim() || record2?.authToken?.trim() || void 0;
27474
+ }
27475
+
27476
+ // plugins/kxm/src/project-name.ts
27477
+ import { readFileSync as readFileSync10 } from "node:fs";
27478
+ import { basename as basename3, join as join15 } from "node:path";
27479
+ function defaultProjectName(cwd, env = process.env) {
27480
+ const fromEnv = env.KXM_PROJECT?.trim();
27481
+ if (fromEnv) return fromEnv;
27482
+ try {
27483
+ const pkg = JSON.parse(readFileSync10(join15(cwd, "package.json"), "utf8"));
27484
+ if (typeof pkg.name === "string" && pkg.name.trim().length > 0) return pkg.name.trim();
27485
+ } catch {
27486
+ }
27487
+ return basename3(cwd);
27488
+ }
27489
+
26811
27490
  // plugins/kxm/src/runtime-supervisor.ts
26812
27491
  function kxmSupervisorTokenFile(paths) {
26813
- return join13(paths.runtimeDir, "supervisor.token");
27492
+ return join16(paths.runtimeDir, "supervisor.token");
26814
27493
  }
26815
27494
  function publishKxmSupervisorToken(paths, token) {
26816
27495
  const file = kxmSupervisorTokenFile(paths);
26817
- mkdirSync4(dirname6(file), { recursive: true, mode: 448 });
27496
+ mkdirSync6(dirname8(file), { recursive: true, mode: 448 });
26818
27497
  const temp = `${file}.${process.pid}.tmp`;
26819
- writeFileSync4(temp, `${token}
27498
+ writeFileSync6(temp, `${token}
26820
27499
  `, { encoding: "utf8", mode: 384 });
26821
27500
  try {
26822
27501
  chmodSync2(temp, 384);
26823
27502
  } catch {
26824
27503
  }
26825
- renameSync(temp, file);
27504
+ renameSync3(temp, file);
26826
27505
  try {
26827
27506
  chmodSync2(file, 384);
26828
27507
  } catch {
26829
27508
  }
26830
27509
  }
26831
27510
  function hashKxmSupervisorToken(token) {
26832
- return `sha256:${createHash11("sha256").update(`kxm-runtime-supervisor\0${token}`, "utf8").digest("hex")}`;
27511
+ return `sha256:${createHash12("sha256").update(`kxm-runtime-supervisor\0${token}`, "utf8").digest("hex")}`;
26833
27512
  }
26834
27513
  function readKxmSupervisorToken(paths) {
26835
27514
  const file = kxmSupervisorTokenFile(paths);
@@ -26838,7 +27517,7 @@ function readKxmSupervisorToken(paths) {
26838
27517
  if (stat.isSymbolicLink() || !stat.isFile()) {
26839
27518
  throw runtimeError("runtime_path_invalid", file, "supervisor token file must be a regular file, not a link");
26840
27519
  }
26841
- const token = readFileSync8(file, "utf8").trim();
27520
+ const token = readFileSync11(file, "utf8").trim();
26842
27521
  return token.length >= 32 ? token : void 0;
26843
27522
  }
26844
27523
  function processAlive(pid) {
@@ -26852,16 +27531,16 @@ function processAlive(pid) {
26852
27531
  var HEARTBEAT_STALE_MS = 15e3;
26853
27532
  var SUPERVISOR_ERROR_MAX_AGE_MS = 3e4;
26854
27533
  function supervisorErrorFile(paths) {
26855
- return join13(paths.runtimeDir, "supervisor.error");
27534
+ return join16(paths.runtimeDir, "supervisor.error");
26856
27535
  }
26857
27536
  function clearSupervisorError(paths) {
26858
27537
  const file = supervisorErrorFile(paths);
26859
- if (existsSync10(file)) rmSync(file, { force: true });
27538
+ if (existsSync12(file)) rmSync3(file, { force: true });
26860
27539
  }
26861
27540
  function recordSupervisorError(paths, message) {
26862
27541
  try {
26863
- mkdirSync4(paths.runtimeDir, { recursive: true, mode: 448 });
26864
- writeFileSync4(supervisorErrorFile(paths), `${message}
27542
+ mkdirSync6(paths.runtimeDir, { recursive: true, mode: 448 });
27543
+ writeFileSync6(supervisorErrorFile(paths), `${message}
26865
27544
  `, { encoding: "utf8", mode: 384 });
26866
27545
  } catch {
26867
27546
  }
@@ -26873,13 +27552,13 @@ function readRecentSupervisorError(paths) {
26873
27552
  const ageMs = Date.now() - stat.mtimeMs;
26874
27553
  if (ageMs > SUPERVISOR_ERROR_MAX_AGE_MS) return void 0;
26875
27554
  try {
26876
- return readFileSync8(file, "utf8").trim();
27555
+ return readFileSync11(file, "utf8").trim();
26877
27556
  } catch {
26878
27557
  return void 0;
26879
27558
  }
26880
27559
  }
26881
27560
  function kxmSupervisorStatus(paths) {
26882
- if (!existsSync10(paths.registryDb)) return { running: false };
27561
+ if (!existsSync12(paths.registryDb)) return { running: false };
26883
27562
  const registry = new KxmRuntimeRegistry(paths.registryDb);
26884
27563
  try {
26885
27564
  const record2 = registry.supervisor();
@@ -26949,7 +27628,7 @@ async function ensureKxmSupervisor(options = {}) {
26949
27628
  throw runtimeError("runtime_supervisor_unreachable", paths.registryDb, `runtime supervisor pid ${status.pid} is registered as running but cannot be probed`);
26950
27629
  }
26951
27630
  clearSupervisorError(paths);
26952
- const scriptPath = join13(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
27631
+ const scriptPath = join16(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
26953
27632
  const spawnImpl = options.spawnImpl ?? ((script, env) => {
26954
27633
  const child = spawn3(process.execPath, [script], {
26955
27634
  detached: true,
@@ -27034,8 +27713,8 @@ async function waitForDriveSessions(settled, graceMs) {
27034
27713
  try {
27035
27714
  await Promise.race([
27036
27715
  Promise.allSettled(settled),
27037
- new Promise((resolve6) => {
27038
- timeout = setTimeout(resolve6, graceMs);
27716
+ new Promise((resolve8) => {
27717
+ timeout = setTimeout(resolve8, graceMs);
27039
27718
  timeout.unref?.();
27040
27719
  })
27041
27720
  ]);
@@ -27056,6 +27735,63 @@ async function driveSessionStillPending(settled) {
27056
27735
  await Promise.resolve();
27057
27736
  return pending;
27058
27737
  }
27738
+ var DEFAULT_RUNTIME_SYNC_INTERVAL_MS = 1e4;
27739
+ var MIN_RUNTIME_SYNC_INTERVAL_MS = 250;
27740
+ var MAX_RUNTIME_SYNC_INTERVAL_MS = 6e4;
27741
+ var OUTBOX_PUSH_BATCH = 32;
27742
+ function runtimeSyncIntervalMs(env = process.env) {
27743
+ const raw = env.KXM_RUNTIME_SYNC_INTERVAL_MS?.trim();
27744
+ if (!raw) return DEFAULT_RUNTIME_SYNC_INTERVAL_MS;
27745
+ const parsed = Number(raw);
27746
+ if (!Number.isInteger(parsed)) return DEFAULT_RUNTIME_SYNC_INTERVAL_MS;
27747
+ return Math.min(MAX_RUNTIME_SYNC_INTERVAL_MS, Math.max(MIN_RUNTIME_SYNC_INTERVAL_MS, parsed));
27748
+ }
27749
+ async function syncKxmOutbox(eventStore, client, options = {}) {
27750
+ const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
27751
+ const batchSize = options.batchSize ?? OUTBOX_PUSH_BATCH;
27752
+ const result = { pushed: 0, acked: 0, conflicts: 0, rejected: 0 };
27753
+ let afterSeq = 0;
27754
+ for (; ; ) {
27755
+ const rows = eventStore.pendingOutbox(batchSize, afterSeq);
27756
+ if (rows.length === 0) return result;
27757
+ const MAX_BATCH_BYTES = 2e5;
27758
+ let byteBudget = MAX_BATCH_BYTES;
27759
+ let sendCount = 0;
27760
+ for (const row of rows) {
27761
+ const rowBytes = Buffer.byteLength(row.syncEvent, "utf8") + 64;
27762
+ if (sendCount > 0 && byteBudget - rowBytes < 0) break;
27763
+ byteBudget -= rowBytes;
27764
+ sendCount += 1;
27765
+ }
27766
+ const batch = rows.slice(0, sendCount);
27767
+ if (batch.length === 0) batch.push(rows[0]);
27768
+ afterSeq = batch[batch.length - 1].seq;
27769
+ eventStore.markOutboxAttempted(batch.map((row) => row.seq), now());
27770
+ const response = await client.pushSyncEvents(batch.map((row) => JSON.parse(row.syncEvent)));
27771
+ result.pushed += batch.length;
27772
+ const outcomes = new Map(response.results.map((entry) => [`${entry.runId}\0${entry.sequence}`, entry.outcome]));
27773
+ const acked = [];
27774
+ for (const row of batch) {
27775
+ const outcome = outcomes.get(`${row.runId}\0${row.sequence}`);
27776
+ if (outcome === "accepted" || outcome === "duplicate") acked.push(row.seq);
27777
+ else if (outcome === "conflict") result.conflicts += 1;
27778
+ else result.rejected += 1;
27779
+ }
27780
+ result.acked += eventStore.ackOutbox(acked, now());
27781
+ }
27782
+ }
27783
+ function runtimeHubClientFor(context, env) {
27784
+ const serverUrl = env.KXM_SERVER_URL?.trim() || readHubBinding(env)?.url;
27785
+ if (!serverUrl) return void 0;
27786
+ const project = defaultProjectName(context.projectRoot, env);
27787
+ const authToken = resolveClientHubAuthToken(env, project);
27788
+ return new RuntimeHubClient({
27789
+ serverUrl,
27790
+ project,
27791
+ runtimeId: context.homeRuntimeId,
27792
+ ...authToken ? { authToken } : {}
27793
+ });
27794
+ }
27059
27795
  async function startKxmRuntimeSupervisor(options = {}) {
27060
27796
  const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
27061
27797
  const paths = kxmRuntimePaths(options.stateRoot !== void 0 ? { stateRoot: options.stateRoot } : {});
@@ -27069,23 +27805,34 @@ async function startKxmRuntimeSupervisor(options = {}) {
27069
27805
  }
27070
27806
  }
27071
27807
  async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now) {
27072
- mkdirSync4(paths.runtimeDir, { recursive: true, mode: 448 });
27073
- mkdirSync4(paths.projectsDir, { recursive: true, mode: 448 });
27808
+ mkdirSync6(paths.runtimeDir, { recursive: true, mode: 448 });
27809
+ mkdirSync6(paths.projectsDir, { recursive: true, mode: 448 });
27074
27810
  const token = randomBytes2(32).toString("hex");
27075
27811
  const tokenHash = hashKxmSupervisorToken(token);
27076
27812
  const registry = new KxmRuntimeRegistry(paths.registryDb);
27077
- const runtimeId = `rtm_${createHash11("sha256").update(`${paths.stateRoot}\0${process.pid}\0${now()}\0${randomBytes2(16).toString("hex")}`, "utf8").digest("hex").slice(0, 24)}`;
27813
+ const runtimeId = `rtm_${createHash12("sha256").update(`${paths.stateRoot}\0${process.pid}\0${now()}\0${randomBytes2(16).toString("hex")}`, "utf8").digest("hex").slice(0, 24)}`;
27078
27814
  const requestedPort = requestedPortOption ?? 0;
27079
27815
  let activeRuntimeId = runtimeId;
27080
27816
  const contexts = /* @__PURE__ */ new Map();
27817
+ const registerSyncCredentials = (context) => {
27818
+ const hubToken = resolveClientHubAuthToken(process.env, defaultProjectName(context.projectRoot, process.env));
27819
+ if (hubToken) context.eventStore.syncRedactor.register(hubToken);
27820
+ for (const key of Object.keys(process.env)) {
27821
+ if (key.startsWith("KXM_") && (key.endsWith("_TOKEN") || key.endsWith("_KEY")) || key.endsWith("_API_KEY") || key.endsWith("_SECRET")) {
27822
+ const value = process.env[key]?.trim();
27823
+ if (value) context.eventStore.syncRedactor.register(value);
27824
+ }
27825
+ }
27826
+ };
27081
27827
  const contextFor = (projectRoot) => {
27082
- if (!isAbsolute4(projectRoot)) {
27828
+ if (!isAbsolute6(projectRoot)) {
27083
27829
  throw runtimeError("runtime_request_invalid", "projectRoot", "projectRoot must be an absolute path");
27084
27830
  }
27085
27831
  const key = projectRuntimeKey(projectRoot);
27086
27832
  const existing = contexts.get(key);
27087
27833
  if (existing) return existing;
27088
27834
  const context = openKxmRuntimeContext(projectRoot, { homeRuntimeId: activeRuntimeId, stateRoot: paths.stateRoot });
27835
+ registerSyncCredentials(context);
27089
27836
  contexts.set(key, context);
27090
27837
  return context;
27091
27838
  };
@@ -27417,11 +28164,37 @@ async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now) {
27417
28164
  }
27418
28165
  }, 1e3);
27419
28166
  heartbeat.unref();
28167
+ for (const reg of registry.projectsForRuntime(activeRuntimeId)) {
28168
+ try {
28169
+ contextFor(reg.projectRoot);
28170
+ } catch {
28171
+ }
28172
+ }
28173
+ let syncing = false;
28174
+ const syncTimer = setInterval(() => {
28175
+ if (syncing || stopping) return;
28176
+ syncing = true;
28177
+ void (async () => {
28178
+ for (const context of [...contexts.values()]) {
28179
+ try {
28180
+ const client = runtimeHubClientFor(context, process.env);
28181
+ if (!client) continue;
28182
+ await client.heartbeat();
28183
+ await syncKxmOutbox(context.eventStore, client, { now });
28184
+ } catch {
28185
+ }
28186
+ }
28187
+ })().finally(() => {
28188
+ syncing = false;
28189
+ });
28190
+ }, runtimeSyncIntervalMs());
28191
+ syncTimer.unref();
27420
28192
  let stopping = false;
27421
28193
  const stop = async () => {
27422
28194
  if (stopping) return;
27423
28195
  stopping = true;
27424
28196
  clearInterval(heartbeat);
28197
+ clearInterval(syncTimer);
27425
28198
  try {
27426
28199
  registry.markStopping(process.pid, now());
27427
28200
  } catch {
@@ -27485,6 +28258,7 @@ async function kxmRuntimeRequest(handle, method, path, body) {
27485
28258
  }
27486
28259
  export {
27487
28260
  DEFAULT_RUNTIME_STOP_GRACE_MS,
28261
+ DEFAULT_RUNTIME_SYNC_INTERVAL_MS,
27488
28262
  MAX_RUNTIME_STOP_GRACE_MS,
27489
28263
  attachKxmSupervisor,
27490
28264
  ensureKxmSupervisor,
@@ -27495,5 +28269,7 @@ export {
27495
28269
  kxmSupervisorTokenFile,
27496
28270
  readKxmSupervisorToken,
27497
28271
  runtimeStopGraceMs,
27498
- startKxmRuntimeSupervisor
28272
+ runtimeSyncIntervalMs,
28273
+ startKxmRuntimeSupervisor,
28274
+ syncKxmOutbox
27499
28275
  };