@kontextmind/kxm 0.7.24 → 0.7.26

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.
@@ -18324,9 +18324,15 @@ var VnextRunEventStore = class {
18324
18324
  }
18325
18325
  driveReceiptsForRun(runId, limit = 20) {
18326
18326
  const rows = this.database.prepare(`
18327
- SELECT receipt FROM drive_receipts WHERE run_id = ? ORDER BY closed_at DESC, drive_id DESC LIMIT ?
18327
+ SELECT drive_id, receipt FROM drive_receipts WHERE run_id = ? ORDER BY closed_at DESC, drive_id DESC LIMIT ?
18328
18328
  `).all(runId, limit);
18329
- return rows.map((row) => parseDriveReceipt(row.receipt));
18329
+ return rows.map((row) => {
18330
+ try {
18331
+ return parseDriveReceipt(row.receipt);
18332
+ } catch {
18333
+ return { driveId: row.drive_id, divergence: "receipt unreadable" };
18334
+ }
18335
+ });
18330
18336
  }
18331
18337
  insertCapability(row) {
18332
18338
  this.database.prepare(`
@@ -18962,6 +18968,16 @@ var ATTEMPT_EDGES = {
18962
18968
  executing: /* @__PURE__ */ new Set(["settling"]),
18963
18969
  settling: /* @__PURE__ */ new Set(["terminal"])
18964
18970
  };
18971
+ function effectiveRunDurationBudget(planLimits, projectLimits) {
18972
+ const workflow = planLimits?.maxRunDurationMs;
18973
+ const project = projectLimits?.maxRunDurationMs;
18974
+ if (workflow === void 0 && project === void 0) return void 0;
18975
+ if (workflow !== void 0 && project !== void 0) {
18976
+ return { budgetMs: Math.min(workflow, project), source: "both" };
18977
+ }
18978
+ if (workflow !== void 0) return { budgetMs: workflow, source: "workflow" };
18979
+ return { budgetMs: project, source: "project" };
18980
+ }
18965
18981
  function emptyPanel() {
18966
18982
  return { order: [], assignments: /* @__PURE__ */ Object.create(null) };
18967
18983
  }
@@ -19193,7 +19209,7 @@ function foldVnextRunState(run, plan, events, options = {}) {
19193
19209
  foldRunStatus(state, plan, event);
19194
19210
  break;
19195
19211
  case "run.cancel_requested":
19196
- foldCancelRequested(state, event);
19212
+ foldCancelRequested(state, event, plan, options);
19197
19213
  break;
19198
19214
  case "run.drive_opened":
19199
19215
  foldDriveOpened(state, event);
@@ -19322,6 +19338,9 @@ function foldRunStatus(state, plan, event) {
19322
19338
  if ((status === "running" || status === "cancelling") && !plan) {
19323
19339
  throw runtimeError("run_plan_missing", state.runId, `status ${status} requires a pinned run plan`);
19324
19340
  }
19341
+ if (status === "running" && state.runningSince === void 0) {
19342
+ state.runningSince = event.occurredAt;
19343
+ }
19325
19344
  if (TERMINAL_RUN.has(status)) {
19326
19345
  assertTerminalRunStatus(state, plan, status, event);
19327
19346
  if (typeof event.payload.reason === "string") state.terminalReason = event.payload.reason;
@@ -19420,10 +19439,36 @@ function foldDriveOpened(state, event) {
19420
19439
  }
19421
19440
  state.drive = { driveId, mode, openedSequence: event.sequence };
19422
19441
  }
19423
- function foldCancelRequested(state, event) {
19442
+ function foldCancelRequested(state, event, plan, options) {
19424
19443
  if (state.cancelRequested || TERMINAL_RUN.has(state.status)) {
19425
19444
  throw runtimeError("run_events_illegal", state.runId, "duplicate run.cancel_requested is not legal");
19426
19445
  }
19446
+ if (event.payload.reason === "budget_run_duration") {
19447
+ const budget = event.payload.budget;
19448
+ if (!budget || typeof budget !== "object" || Array.isArray(budget)) {
19449
+ throw runtimeError("run_events_illegal", state.runId, "budget_run_duration requires a budget payload");
19450
+ }
19451
+ const body = budget;
19452
+ const budgetMs = body.budgetMs;
19453
+ const elapsedMs = body.elapsedMs;
19454
+ const source = body.source;
19455
+ if (typeof budgetMs !== "number" || !Number.isInteger(budgetMs) || budgetMs < 0) {
19456
+ throw runtimeError("run_events_illegal", state.runId, "budget_run_duration budgetMs is invalid");
19457
+ }
19458
+ if (typeof elapsedMs !== "number" || !Number.isInteger(elapsedMs) || elapsedMs < 0) {
19459
+ throw runtimeError("run_events_illegal", state.runId, "budget_run_duration elapsedMs is invalid");
19460
+ }
19461
+ if (source !== "workflow" && source !== "project" && source !== "both") {
19462
+ throw runtimeError("run_events_illegal", state.runId, "budget_run_duration source is invalid");
19463
+ }
19464
+ const expected = effectiveRunDurationBudget(plan?.limits, options.projectLimits);
19465
+ if (!expected || expected.budgetMs !== budgetMs || expected.source !== source) {
19466
+ throw runtimeError("run_events_illegal", state.runId, "budget_run_duration budgetMs does not match the plan");
19467
+ }
19468
+ if (elapsedMs < budgetMs) {
19469
+ throw runtimeError("run_events_illegal", state.runId, "budget_run_duration elapsedMs is below budgetMs");
19470
+ }
19471
+ }
19427
19472
  state.cancelRequested = true;
19428
19473
  if (event.commandId) state.cancelCommandId = event.commandId;
19429
19474
  }
@@ -20069,7 +20114,8 @@ function freezeState(state) {
20069
20114
  cancelRequested: state.cancelRequested,
20070
20115
  ...state.terminalReason !== void 0 ? { terminalReason: state.terminalReason } : {},
20071
20116
  ...state.terminalReason !== void 0 && state.status === "failed" ? { failureReason: state.terminalReason } : {},
20072
- ...state.drive !== void 0 ? { drive: Object.freeze({ ...state.drive }) } : {}
20117
+ ...state.drive !== void 0 ? { drive: Object.freeze({ ...state.drive }) } : {},
20118
+ ...state.runningSince !== void 0 ? { runningSince: state.runningSince } : {}
20073
20119
  };
20074
20120
  return Object.freeze(frozen);
20075
20121
  }
@@ -21628,6 +21674,9 @@ function clearVnextDriveSession(storePath, runId, token) {
21628
21674
  if (!current || current.token !== token) return;
21629
21675
  delete current.driveSession;
21630
21676
  }
21677
+ function vnextDriveSession(storePath, runId) {
21678
+ return owners.get(storePath)?.admitted.get(runId)?.driveSession;
21679
+ }
21631
21680
  function vnextOpenDriveSessions(storePath) {
21632
21681
  const owner = owners.get(storePath);
21633
21682
  if (!owner) return [];
@@ -21959,7 +22008,8 @@ function foldStoredVnextRun(context, run) {
21959
22008
  const step = envelope.plan.steps[stepId];
21960
22009
  if (!step || step.kind !== "gate") return void 0;
21961
22010
  return envelope.gates.definitions[step.gate]?.kind;
21962
- }
22011
+ },
22012
+ projectLimits: envelope.projectLimits
21963
22013
  } : {});
21964
22014
  if (envelope) verifyVnextGateEvidence(context.eventStore, run, envelope, events, state);
21965
22015
  assertStoredProjection(context, run);
@@ -22066,10 +22116,17 @@ function cancelVnextRun(context, runId, options = {}) {
22066
22116
  };
22067
22117
  const cancelReason = options.reason ?? "operator_cancel";
22068
22118
  const activeAttempt = Boolean(folded.currentStep?.attemptId) || vnextFoldPanelAttemptIds(folded.currentStep).length > 0;
22069
- push("run.cancel_requested", {
22119
+ const cancelPayload = {
22070
22120
  actor: { kind: "runtime", id: context.homeRuntimeId },
22071
22121
  reason: cancelReason
22072
- });
22122
+ };
22123
+ if (cancelReason === "budget_run_duration") {
22124
+ if (!options.budget) {
22125
+ throw runtimeError("run_events_illegal", runId, "budget_run_duration requires a budget payload");
22126
+ }
22127
+ cancelPayload.budget = options.budget;
22128
+ }
22129
+ push("run.cancel_requested", cancelPayload);
22073
22130
  let status = "cancelled";
22074
22131
  if (folded.status === "running" && activeAttempt) {
22075
22132
  status = "cancelling";
@@ -23406,7 +23463,7 @@ function recordGateNoStartInTransaction(context, run, envelope, stepId, observat
23406
23463
  const cancelled = observation.stopCause === "cancel";
23407
23464
  const now = (/* @__PURE__ */ new Date()).toISOString();
23408
23465
  const seq = sequencer(context, run, now);
23409
- if (cancelled) ensureOperatorCancel(seq, ids.state, run);
23466
+ const cancelReason = cancelled ? ensureOperatorCancel(seq, ids.state, run, context) : void 0;
23410
23467
  const observationId = newVnextObservationId();
23411
23468
  const observed = seq.push("effect.observed", {
23412
23469
  effect: { id: ids.effectId, policy: { class: ids.gateKind === "artifacts-exist" ? "read-only" : "unknown", sharedMutable: false } },
@@ -23438,7 +23495,7 @@ function recordGateNoStartInTransaction(context, run, envelope, stepId, observat
23438
23495
  seq.push("attempt.status_changed", { attemptId: ids.attemptId, status: "terminal" });
23439
23496
  seq.push("assignment.terminal", { assignmentId: ids.assignmentId, outcome: "cancelled", status: "terminal" });
23440
23497
  seq.push("step.status_changed", { stepId, status: "cancelled", previousStatus: "running" });
23441
- seq.push("run.status_changed", { status: "cancelled", reason: "operator_cancel", stepId });
23498
+ seq.push("run.status_changed", { status: "cancelled", reason: cancelReason ?? "operator_cancel", stepId });
23442
23499
  } else {
23443
23500
  seq.push("assignment.result_recorded", { assignmentId: ids.assignmentId, resultClass: "producer_rejected", status: "result_recorded" });
23444
23501
  seq.push("attempt.status_changed", { attemptId: ids.attemptId, status: "terminal" });
@@ -23492,7 +23549,7 @@ function recordGateCancelObservedInTransaction(context, run, envelope, stepId, o
23492
23549
  }
23493
23550
  const now = (/* @__PURE__ */ new Date()).toISOString();
23494
23551
  const seq = sequencer(context, run, now);
23495
- ensureOperatorCancel(seq, ids.state, run);
23552
+ const cancelReason = ensureOperatorCancel(seq, ids.state, run, context);
23496
23553
  if (ids.gateKind === "artifacts-exist") {
23497
23554
  seq.push("assignment.executing", { assignmentId: ids.assignmentId, stepId, stepAttempt: ids.stepAttempt, attemptId: ids.attemptId, status: "executing" });
23498
23555
  seq.push("attempt.status_changed", { attemptId: ids.attemptId, assignmentId: ids.assignmentId, stepId, stepAttempt: ids.stepAttempt, status: "executing" });
@@ -23535,7 +23592,7 @@ function recordGateCancelObservedInTransaction(context, run, envelope, stepId, o
23535
23592
  seq.push("attempt.status_changed", { attemptId: ids.attemptId, status: "terminal" });
23536
23593
  seq.push("assignment.terminal", { assignmentId: ids.assignmentId, outcome: "cancelled", status: "terminal" });
23537
23594
  seq.push("step.status_changed", { stepId, status: "cancelled", previousStatus: "running" });
23538
- seq.push("run.status_changed", { status: "cancelled", reason: "operator_cancel", stepId });
23595
+ seq.push("run.status_changed", { status: "cancelled", reason: cancelReason, stepId });
23539
23596
  for (const event of seq.events) context.eventStore.appendEvent(event);
23540
23597
  context.eventStore.insertGateObservation(observationRow);
23541
23598
  context.eventStore.settleCapability(ids.attemptId, "settled");
@@ -23620,8 +23677,8 @@ function requireIntent(context, run, envelope, stepId) {
23620
23677
  state: folded
23621
23678
  };
23622
23679
  }
23623
- function ensureOperatorCancel(seq, state, run) {
23624
- if (state.status === "cancelling") return;
23680
+ function ensureOperatorCancel(seq, state, run, context) {
23681
+ if (state.status === "cancelling") return cancelReasonFromLog(context, run.runId);
23625
23682
  if (state.status !== "running") {
23626
23683
  throw runtimeError("run_events_illegal", run.runId, "cancelled gate proof requires a running or cancelling run");
23627
23684
  }
@@ -23630,6 +23687,17 @@ function ensureOperatorCancel(seq, state, run) {
23630
23687
  reason: "operator_cancel"
23631
23688
  });
23632
23689
  seq.push("run.status_changed", { status: "cancelling", reason: "operator_cancel" });
23690
+ return "operator_cancel";
23691
+ }
23692
+ function cancelReasonFromLog(context, runId) {
23693
+ const events = context.eventStore.events(runId, 0, 1e6);
23694
+ for (let index = events.length - 1; index >= 0; index -= 1) {
23695
+ const event = events[index];
23696
+ if (event.eventType === "run.cancel_requested" && typeof event.payload.reason === "string") {
23697
+ return event.payload.reason;
23698
+ }
23699
+ }
23700
+ return "operator_cancel";
23633
23701
  }
23634
23702
  function sequencer(context, run, now) {
23635
23703
  let sequence = context.eventStore.nextSequence(run.runId);
@@ -23968,6 +24036,8 @@ async function driveAdmitted(context, runId, producer, token, options = {}) {
23968
24036
  }
23969
24037
  let latest = { state: foldStoredVnextRun(context, requireRun(context, runId)) };
23970
24038
  while (latest.state.status === "running") {
24039
+ const overBudget = cancelRunDurationIfExceeded(context, runId);
24040
+ if (overBudget) return overBudget;
23971
24041
  const before = context.eventStore.runState(runId)?.lastSequence;
23972
24042
  latest = await stepLocked(context, runId, producer, token);
23973
24043
  if (latest.handoff) return latest;
@@ -24027,6 +24097,7 @@ function recordDriveReceipt(context, session, closeInfo) {
24027
24097
  const last = events[events.length - 1];
24028
24098
  const openedSequence = opened?.openedSequence ?? openedEvent?.sequence;
24029
24099
  if (openedSequence === void 0) return;
24100
+ const closedAt = (/* @__PURE__ */ new Date()).toISOString();
24030
24101
  const receipt = {
24031
24102
  schema: VNEXT_DRIVE_RECEIPT_SCHEMA,
24032
24103
  driveId: session.driveId,
@@ -24036,7 +24107,7 @@ function recordDriveReceipt(context, session, closeInfo) {
24036
24107
  mode: session.mode,
24037
24108
  openedAt: openedEvent?.occurredAt ?? session.openedAt,
24038
24109
  openedSequence,
24039
- closedAt: (/* @__PURE__ */ new Date()).toISOString(),
24110
+ closedAt,
24040
24111
  lastSequence: last.sequence,
24041
24112
  logHash: hashVnextDriveLog(events.filter((event) => event.sequence >= 1 && event.sequence <= last.sequence)),
24042
24113
  settlement: {
@@ -24046,7 +24117,7 @@ function recordDriveReceipt(context, session, closeInfo) {
24046
24117
  ...closeInfo.kind === "handoff" && closeInfo.handoff ? { handoff: receiptHandoff(closeInfo.handoff) } : {},
24047
24118
  ...closeInfo.error !== void 0 ? { error: closeInfo.error } : {}
24048
24119
  },
24049
- budget: null,
24120
+ budget: driveReceiptBudget(context, run.runId, state, events, closedAt),
24050
24121
  producer: { id: closeInfo.producerId, closed: closeInfo.producerClosed }
24051
24122
  };
24052
24123
  context.eventStore.insertDriveReceipt(receipt);
@@ -24235,6 +24306,8 @@ var VnextRunScheduler = class _VnextRunScheduler {
24235
24306
  }
24236
24307
  const driveId = newDriveId(runId, token, this.context.homeRuntimeId, vnextMonotonicNs());
24237
24308
  const openedMeta = appendDriveOpened(this.context, runId, driveId, options.mode);
24309
+ const startedState = foldStoredVnextRun(this.context, requireRun(this.context, runId));
24310
+ const deadlineAt = driveDeadlineAt(this.context, runId, startedState);
24238
24311
  const session = {
24239
24312
  driveId,
24240
24313
  runId,
@@ -24244,7 +24317,8 @@ var VnextRunScheduler = class _VnextRunScheduler {
24244
24317
  openedAt: openedMeta.occurredAt,
24245
24318
  producerId: producer.id,
24246
24319
  controller: new AbortController(),
24247
- settled
24320
+ settled,
24321
+ ...deadlineAt !== void 0 ? { deadlineAt } : {}
24248
24322
  };
24249
24323
  attachVnextDriveSession(this.context.eventStore.path, runId, token, session);
24250
24324
  opened = true;
@@ -24323,11 +24397,13 @@ async function stepLocked(context, runId, producer, token) {
24323
24397
  throw runtimeError("run_events_illegal", prepared.run.runId, "prepared gate is not artifacts-exist");
24324
24398
  }
24325
24399
  registerVnextAttemptController(context.eventStore.path, runId, { attemptId: prepared.attemptId, controller: prepared.controller });
24400
+ const clearBudget = armRunDurationBudgetTimer(context, runId);
24326
24401
  try {
24327
24402
  const observation = evaluateArtifactsGate(context, definition);
24328
24403
  vnextGateDispatchSeams.afterEvaluate?.(prepared);
24329
24404
  return context.eventStore.transaction(() => settlePreparedGate(context, prepared, observation));
24330
24405
  } finally {
24406
+ clearBudget();
24331
24407
  unregisterVnextAttemptController(context.eventStore.path, runId, prepared.attemptId);
24332
24408
  }
24333
24409
  }
@@ -24358,6 +24434,7 @@ async function runPreparedCommandGate(context, prepared, definition, token) {
24358
24434
  });
24359
24435
  armVnextGateHold(storePath, prepared.run.runId, token, prepared.attemptId, () => observer.requestStop("cancel"));
24360
24436
  registerVnextAttemptController(storePath, prepared.run.runId, { attemptId: prepared.attemptId, controller: prepared.controller });
24437
+ const clearBudget = armRunDurationBudgetTimer(context, prepared.run.runId);
24361
24438
  const unhookClose = registerVnextRuntimeCloseHook(context, () => {
24362
24439
  try {
24363
24440
  markVnextGateHoldUnsettled(storePath, prepared.run.runId, token, prepared.attemptId);
@@ -24398,6 +24475,7 @@ async function runPreparedCommandGate(context, prepared, definition, token) {
24398
24475
  return commitCommandUncertainty(context, prepared, token, outcome.reason, outcome.observation);
24399
24476
  } finally {
24400
24477
  unhookClose();
24478
+ clearBudget();
24401
24479
  unregisterVnextAttemptController(storePath, prepared.run.runId, prepared.attemptId);
24402
24480
  }
24403
24481
  }
@@ -25023,8 +25101,10 @@ async function drivePanel(context, panel, producer) {
25023
25101
  const pending = /* @__PURE__ */ new Map();
25024
25102
  let stopBirths = false;
25025
25103
  let settlementFailed = false;
25104
+ const budgetClears = /* @__PURE__ */ new Map();
25026
25105
  const register = (member) => {
25027
25106
  registerVnextAttemptController(context.eventStore.path, runId, { attemptId: member.attemptId, controller: member.controller });
25107
+ budgetClears.set(member.attemptId, armRunDurationBudgetTimer(context, runId));
25028
25108
  owned.set(member.attemptId, member);
25029
25109
  };
25030
25110
  const abortOwned = () => {
@@ -25207,6 +25287,7 @@ async function drivePanel(context, panel, producer) {
25207
25287
  throw error;
25208
25288
  } finally {
25209
25289
  for (const attemptId of owned.keys()) {
25290
+ budgetClears.get(attemptId)?.();
25210
25291
  unregisterVnextAttemptController(context.eventStore.path, runId, attemptId);
25211
25292
  }
25212
25293
  }
@@ -25386,7 +25467,7 @@ function joinPanel(context, panel) {
25386
25467
  };
25387
25468
  const cancelRun = () => {
25388
25469
  push("step.status_changed", { stepId: panel.stepId, status: "cancelled", previousStatus: "running" });
25389
- push("run.status_changed", { status: "cancelled", reason: "operator_cancel" });
25470
+ push("run.status_changed", { status: "cancelled", reason: cancelReasonFromLog2(context, run.runId) });
25390
25471
  for (const event of events) context.eventStore.appendEvent(event);
25391
25472
  const next2 = foldStoredVnextRun(context, run);
25392
25473
  persistVnextRunState(context, run.runId, next2, events[events.length - 1].sequence);
@@ -25493,16 +25574,124 @@ function transitionBudgetFailure(plan, state, fromStepId, outcome) {
25493
25574
  }
25494
25575
  return void 0;
25495
25576
  }
25496
- function unsupportedLimit(envelope) {
25497
- if (envelope.plan.limits.maxRunDurationMs !== void 0) {
25498
- return { reason: "limit_unsupported", field: "limits.maxRunDurationMs", detail: "duration budget enforcement is not available in this slice" };
25577
+ var MAX_TIMER_DELAY_MS = 2147483647;
25578
+ function elapsedMsBetween(fromIso, toIso) {
25579
+ const from = Date.parse(fromIso);
25580
+ const to = Date.parse(toIso);
25581
+ if (!Number.isFinite(from) || !Number.isFinite(to)) return 0;
25582
+ return Math.max(0, Math.trunc(to - from));
25583
+ }
25584
+ function declaredRunDurationBudget(context, runId) {
25585
+ const run = context.eventStore.run(runId);
25586
+ if (!run) return void 0;
25587
+ try {
25588
+ const envelope = loadVnextRunPlanEnvelope(context.eventStore, run);
25589
+ return effectiveRunDurationBudget(envelope.plan.limits, envelope.projectLimits);
25590
+ } catch {
25591
+ return void 0;
25592
+ }
25593
+ }
25594
+ function runDurationOverrunPayload(context, runId, nowIso = (/* @__PURE__ */ new Date()).toISOString()) {
25595
+ const declared = declaredRunDurationBudget(context, runId);
25596
+ if (!declared) return void 0;
25597
+ const run = context.eventStore.run(runId);
25598
+ if (!run) return void 0;
25599
+ const state = foldStoredVnextRun(context, run);
25600
+ if (!state.runningSince) return void 0;
25601
+ if (isTerminalRunStatus(state.status) || state.status === "cancelling") return void 0;
25602
+ const elapsedMs = elapsedMsBetween(state.runningSince, nowIso);
25603
+ if (elapsedMs < declared.budgetMs) return void 0;
25604
+ return { budgetMs: declared.budgetMs, elapsedMs, source: declared.source };
25605
+ }
25606
+ function cancelRunDurationIfExceeded(context, runId) {
25607
+ if (isVnextRuntimeContextClosed(context)) return void 0;
25608
+ const payload = runDurationOverrunPayload(context, runId);
25609
+ if (!payload) return void 0;
25610
+ cancelVnextRun(context, runId, { reason: "budget_run_duration", budget: payload });
25611
+ return { state: foldStoredVnextRun(context, requireRun(context, runId)) };
25612
+ }
25613
+ function driveDeadlineAt(context, runId, state) {
25614
+ const declared = declaredRunDurationBudget(context, runId);
25615
+ if (!declared || !state.runningSince) return void 0;
25616
+ const start = Date.parse(state.runningSince);
25617
+ if (!Number.isFinite(start)) return void 0;
25618
+ return new Date(start + declared.budgetMs).toISOString();
25619
+ }
25620
+ function driveReceiptBudget(context, runId, state, events, closedAt) {
25621
+ const declared = declaredRunDurationBudget(context, runId);
25622
+ if (!declared) return null;
25623
+ const elapsedMs = state.runningSince ? elapsedMsBetween(state.runningSince, closedAt) : 0;
25624
+ const overrun = events.some((event) => event.eventType === "run.cancel_requested" && event.payload.reason === "budget_run_duration");
25625
+ return {
25626
+ budgetMs: declared.budgetMs,
25627
+ source: declared.source,
25628
+ elapsedMs,
25629
+ overrun
25630
+ };
25631
+ }
25632
+ function cancelReasonFromLog2(context, runId) {
25633
+ const events = context.eventStore.events(runId, 0, 1e6);
25634
+ for (let index = events.length - 1; index >= 0; index -= 1) {
25635
+ const event = events[index];
25636
+ if (event.eventType === "run.cancel_requested" && typeof event.payload.reason === "string") {
25637
+ return event.payload.reason;
25638
+ }
25499
25639
  }
25640
+ return "operator_cancel";
25641
+ }
25642
+ function armRunDurationBudgetTimer(context, runId) {
25643
+ const declared = declaredRunDurationBudget(context, runId);
25644
+ if (!declared) return () => void 0;
25645
+ const run = context.eventStore.run(runId);
25646
+ if (!run) return () => void 0;
25647
+ const state = foldStoredVnextRun(context, run);
25648
+ if (!state.runningSince) return () => void 0;
25649
+ const startMs = Date.parse(state.runningSince);
25650
+ if (!Number.isFinite(startMs)) return () => void 0;
25651
+ const deadlineMs = startMs + declared.budgetMs;
25652
+ let timer;
25653
+ let cleared = false;
25654
+ const fire = () => {
25655
+ timer = void 0;
25656
+ if (cleared || isVnextRuntimeContextClosed(context)) return;
25657
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
25658
+ const elapsedMs = elapsedMsBetween(state.runningSince, nowIso);
25659
+ if (elapsedMs < declared.budgetMs) {
25660
+ arm(declared.budgetMs - elapsedMs);
25661
+ return;
25662
+ }
25663
+ try {
25664
+ cancelVnextRun(context, runId, {
25665
+ reason: "budget_run_duration",
25666
+ budget: { budgetMs: declared.budgetMs, elapsedMs, source: declared.source }
25667
+ });
25668
+ } catch {
25669
+ }
25670
+ };
25671
+ const arm = (remaining) => {
25672
+ if (cleared) return;
25673
+ const delay = Math.min(Math.max(0, remaining), MAX_TIMER_DELAY_MS);
25674
+ timer = setTimeout(fire, delay);
25675
+ timer.unref();
25676
+ };
25677
+ const unhook = registerVnextRuntimeCloseHook(context, () => {
25678
+ cleared = true;
25679
+ if (timer !== void 0) clearTimeout(timer);
25680
+ timer = void 0;
25681
+ });
25682
+ arm(deadlineMs - Date.now());
25683
+ return () => {
25684
+ if (cleared) return;
25685
+ cleared = true;
25686
+ if (timer !== void 0) clearTimeout(timer);
25687
+ timer = void 0;
25688
+ unhook();
25689
+ };
25690
+ }
25691
+ function unsupportedLimit(envelope) {
25500
25692
  if (envelope.plan.limits.maxAgentTimeMs !== void 0) {
25501
25693
  return { reason: "limit_unsupported", field: "limits.maxAgentTimeMs", detail: "agent-time budget enforcement is not available in this slice" };
25502
25694
  }
25503
- if (envelope.projectLimits.maxRunDurationMs !== void 0) {
25504
- return { reason: "limit_unsupported", field: "project.limits.maxRunDurationMs", detail: "duration budget enforcement is not available in this slice" };
25505
- }
25506
25695
  if (envelope.projectLimits.maxAgentTimeMs !== void 0) {
25507
25696
  return { reason: "limit_unsupported", field: "project.limits.maxAgentTimeMs", detail: "agent-time budget enforcement is not available in this slice" };
25508
25697
  }
@@ -26679,7 +26868,7 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
26679
26868
  const scheduler = VnextRunScheduler.for(context, bundle);
26680
26869
  const opening = scheduler.openDriveSession(runId, {
26681
26870
  mode: body.mode,
26682
- allowLimits: true,
26871
+ allowLimits: false,
26683
26872
  liveMode: body.mode === "live",
26684
26873
  createProducer
26685
26874
  });
@@ -26722,6 +26911,20 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
26722
26911
  sendJson(response, 200, { ok: true, events });
26723
26912
  return;
26724
26913
  }
26914
+ if (request.method === "GET" && sub === "drive") {
26915
+ const run = context.eventStore.run(runId);
26916
+ if (!run) throw runtimeError("run_unknown", runId, "run not found");
26917
+ const activeSession = vnextDriveSession(context.eventStore.path, runId);
26918
+ const session = activeSession ? {
26919
+ driveId: activeSession.driveId,
26920
+ mode: activeSession.mode,
26921
+ openedAt: activeSession.openedAt,
26922
+ deadlineAt: activeSession.deadlineAt ?? null
26923
+ } : null;
26924
+ const receipts = context.eventStore.driveReceiptsForRun(runId, 20);
26925
+ sendJson(response, 200, { ok: true, session, receipts });
26926
+ return;
26927
+ }
26725
26928
  if (request.method === "POST" && sub === "cancel") {
26726
26929
  const body = await readJsonBody(request);
26727
26930
  const result = cancelVnextRun(context, runId, {
@@ -26755,6 +26958,43 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
26755
26958
  return;
26756
26959
  }
26757
26960
  }
26961
+ const driveMatch = /^\/v1\/drives\/([A-Za-z0-9_-]+)$/.exec(url.pathname);
26962
+ if (request.method === "GET" && driveMatch) {
26963
+ const driveId = driveMatch[1];
26964
+ const projectRoot = url.searchParams.get("projectRoot") ?? "";
26965
+ if (!projectRoot) {
26966
+ sendJson(response, 400, { ok: false, error: "runtime_request_invalid", message: "projectRoot query parameter is required" });
26967
+ return;
26968
+ }
26969
+ const context = contextFor(projectRoot);
26970
+ let receipt;
26971
+ try {
26972
+ receipt = context.eventStore.driveReceipt(driveId);
26973
+ } catch {
26974
+ sendJson(response, 200, { ok: true, receipt: null, verified: false, divergence: "receipt unreadable" });
26975
+ return;
26976
+ }
26977
+ if (!receipt) {
26978
+ sendJson(response, 404, { ok: false, error: "drive_receipt_missing", message: "receipt not found" });
26979
+ return;
26980
+ }
26981
+ const runId = receipt.runId;
26982
+ const stored = context.eventStore.run(runId);
26983
+ if (!stored) {
26984
+ sendJson(response, 200, { ok: true, receipt, verified: false, divergence: "run missing" });
26985
+ return;
26986
+ }
26987
+ const state = foldStoredVnextRun(context, stored);
26988
+ const events = context.eventStore.events(runId, 0, 1e6);
26989
+ const checked = verifyVnextDriveReceipt(receipt, events, state.status, { runId, driveId });
26990
+ sendJson(response, 200, {
26991
+ ok: true,
26992
+ receipt,
26993
+ verified: checked.verified,
26994
+ ...checked.divergence !== void 0 ? { divergence: checked.divergence } : {}
26995
+ });
26996
+ return;
26997
+ }
26758
26998
  const projectRunsMatch = /^\/v1\/projects\/(prj_[A-Za-z0-9_-]+)\/runs$/.exec(url.pathname);
26759
26999
  if (request.method === "GET" && projectRunsMatch) {
26760
27000
  const projectRoot = url.searchParams.get("projectRoot") ?? "";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kxm-claude-plugin",
3
- "version": "0.7.24",
3
+ "version": "0.7.26",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "engines": {
@@ -16,12 +16,16 @@ verbs under `runs`.
16
16
  | `kxm run [workflow] [prompt...]` | Create a vNext run (prompt is hashed, never stored raw) | `--json` |
17
17
  | `kxm runs list` | List recent runs for the current project | `--json` |
18
18
  | `kxm runs status <runId>` | Show projected run status | `--json` |
19
+ | `kxm runs receipt <runId>` | Print the newest drive receipt for a run | `--json`, `--all` |
20
+ | `kxm runs drive <runId> --wait` | Drive a run, then wait for a receipt; exits 0 only for a VERIFIED COMPLETED settlement | `--json`, `--simulated`, `--timeout-ms` (default 60000, max 600000) |
19
21
  | `kxm runs cancel <runId>` | Durably request cancellation | `--json` |
20
22
 
21
23
  ```bash
22
24
  kxm run default "implement the bounded slice" --json
23
25
  kxm runs list --json
24
26
  kxm runs status run_12345 --json
27
+ kxm runs receipt run_12345 --json
28
+ kxm runs drive run_12345 --simulated --wait --timeout-ms 60000 --json
25
29
  kxm runs cancel run_12345 --json
26
30
  ```
27
31