@kontextmind/kxm 0.7.25 → 0.7.27

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.
@@ -11,7 +11,7 @@
11
11
  "name": "kxm",
12
12
  "source": "./plugins/kxm",
13
13
  "description": "Durable workflows, peer agents, and kxm tui",
14
- "version": "0.7.25",
14
+ "version": "0.7.27",
15
15
  "category": "development",
16
16
  "tags": ["kxm", "multi-agent", "workflows", "mcp"]
17
17
  }
@@ -1,16 +1,23 @@
1
1
  schema: kxm.producers.v1
2
- updatedAt: 2026-09-10T17:30:00.000Z
2
+ updatedAt: 2026-09-16T14:55:00.000Z
3
3
  promoted:
4
4
  - anthropic/fable
5
5
  - openai/gpt-5.6-sol
6
6
  - xai/grok-4.6
7
7
  - openrouter/qwen/qwen3-coder-plus
8
+ # Qualified 2026-09-16 from the refreshed catalog (.kxm/models/inventory.yaml,
9
+ # fetchedAt 2026-09-16T14:54:53Z). Quality evidence (side-by-side runs) is
10
+ # queued — pending OpenRouter auth; not in any role rotation yet.
11
+ - openrouter/qwen/qwen3.8-flash # 1M ctx, thinking; $0.15/M in, $0.47/M out
12
+ - openrouter/z-ai/glm-5.3-flash # 1.31M ctx, thinking; $0.09/M in, $0.30/M out
8
13
  demoted: []
9
14
  enabled:
10
15
  - anthropic/fable
11
16
  - openai/gpt-5.6-sol
12
17
  - xai/grok-4.6
13
18
  - openrouter/qwen/qwen3-coder-plus
19
+ - openrouter/qwen/qwen3.8-flash
20
+ - openrouter/z-ai/glm-5.3-flash
14
21
  disabled: []
15
22
  roles:
16
23
  implementer:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextmind/kxm",
3
- "version": "0.7.25",
3
+ "version": "0.7.27",
4
4
  "description": "KXM local-first multi-agent orchestration and operator dashboard",
5
5
  "type": "module",
6
6
  "author": "KontextMind",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "kxm",
4
4
  "displayName": "KXM",
5
- "version": "0.7.25",
5
+ "version": "0.7.27",
6
6
  "description": "Headless multi-agent orchestration, durable workflows, and a live operator dashboard for Pi and Claude Code",
7
7
  "author": {
8
8
  "name": "KontextMind",
@@ -33705,7 +33705,21 @@ ${driveLine}` : ""}`
33705
33705
  return 1;
33706
33706
  }
33707
33707
  }
33708
- async function cmdVnextRunDrive(runtime, runId, simulated) {
33708
+ var DEFAULT_DRIVE_WAIT_MS = 6e4;
33709
+ var MAX_DRIVE_WAIT_MS = 6e5;
33710
+ function parseDriveWaitTimeoutMs(raw) {
33711
+ if (raw === void 0) return DEFAULT_DRIVE_WAIT_MS;
33712
+ const value = typeof raw === "number" ? raw : Number(typeof raw === "string" ? raw.trim() : raw);
33713
+ if (!Number.isInteger(value) || value < 1 || value > MAX_DRIVE_WAIT_MS) return void 0;
33714
+ return value;
33715
+ }
33716
+ function sleepMs(ms) {
33717
+ return new Promise((resolve31) => setTimeout(resolve31, ms));
33718
+ }
33719
+ function driveWaitCompleted(drive) {
33720
+ return drive?.verified === true && drive.receipt?.settlement?.kind === "terminal" && drive.receipt.settlement.status === "completed";
33721
+ }
33722
+ async function cmdVnextRunDrive(runtime, runId, simulated, options = {}) {
33709
33723
  try {
33710
33724
  const projectRoot = discoverVnextProjectRoot(runtime.cwd);
33711
33725
  if (!projectRoot) {
@@ -33717,8 +33731,19 @@ async function cmdVnextRunDrive(runtime, runId, simulated) {
33717
33731
  print(runtime.io, runtime.json, { ok: true, command: "runs drive", dryRun: true, runId, mode }, `drive plan: run ${runId} in ${mode} mode (no events written)`);
33718
33732
  return 0;
33719
33733
  }
33734
+ const timeoutMs = options.wait === true ? parseDriveWaitTimeoutMs(options.timeoutMs) : DEFAULT_DRIVE_WAIT_MS;
33735
+ if (options.wait === true && timeoutMs === void 0) {
33736
+ print(
33737
+ runtime.io,
33738
+ runtime.json,
33739
+ { ok: false, command: "runs drive", error: "run_drive_timeout_invalid" },
33740
+ `run drive --wait --timeout-ms must be an integer between 1 and ${MAX_DRIVE_WAIT_MS}`
33741
+ );
33742
+ return 1;
33743
+ }
33720
33744
  const supervisor = await (vnextDriveCliSeams.ensureSupervisor ?? ensureVnextSupervisor)({ env: runtime.env });
33721
- const result = await (vnextDriveCliSeams.runtimeRequest ?? vnextRuntimeRequest)(supervisor, "POST", `/v1/runs/${encodeURIComponent(runId)}/drive?projectRoot=${encodeURIComponent(projectRoot)}`, { mode });
33745
+ const request = vnextDriveCliSeams.runtimeRequest ?? vnextRuntimeRequest;
33746
+ const result = await request(supervisor, "POST", `/v1/runs/${encodeURIComponent(runId)}/drive?projectRoot=${encodeURIComponent(projectRoot)}`, { mode });
33722
33747
  const driveId = result.driveId;
33723
33748
  const poll = result.poll;
33724
33749
  const status = result.status;
@@ -33726,13 +33751,36 @@ async function cmdVnextRunDrive(runtime, runId, simulated) {
33726
33751
  print(runtime.io, runtime.json, { ok: false, command: "runs drive", error: "run_drive_io_failed" }, "run drive failed because a local operation did not complete");
33727
33752
  return 1;
33728
33753
  }
33729
- print(
33730
- runtime.io,
33731
- runtime.json,
33732
- { ok: true, command: "runs drive", runId, driveId, poll, mode, status },
33733
- `drive ${driveId}: accepted (poll ${poll})`
33734
- );
33735
- return 0;
33754
+ if (options.wait !== true) {
33755
+ print(
33756
+ runtime.io,
33757
+ runtime.json,
33758
+ { ok: true, command: "runs drive", runId, driveId, poll, mode, status },
33759
+ `drive ${driveId}: accepted (poll ${poll})`
33760
+ );
33761
+ return 0;
33762
+ }
33763
+ const deadline = Date.now() + timeoutMs;
33764
+ let interval = 25;
33765
+ while (true) {
33766
+ const stateResult = await request(supervisor, "GET", `/v1/runs/${encodeURIComponent(runId)}?projectRoot=${encodeURIComponent(projectRoot)}`);
33767
+ const drive = stateResult.drive;
33768
+ if (drive?.receipt) {
33769
+ print(
33770
+ runtime.io,
33771
+ runtime.json,
33772
+ { ok: driveWaitCompleted(drive), command: "runs drive", receipt: drive.receipt, verified: drive.verified === true },
33773
+ JSON.stringify(drive.receipt, null, 2)
33774
+ );
33775
+ return driveWaitCompleted(drive) ? 0 : 1;
33776
+ }
33777
+ const remaining = deadline - Date.now();
33778
+ if (remaining <= 0) break;
33779
+ await sleepMs(Math.min(interval, remaining));
33780
+ interval = Math.min(Math.floor(interval * 1.5), 250);
33781
+ }
33782
+ print(runtime.io, runtime.json, { ok: false, command: "runs drive", error: "timeout" }, "drive wait timed out");
33783
+ return 1;
33736
33784
  } catch (error) {
33737
33785
  if (error instanceof VnextConfigError) {
33738
33786
  print(runtime.io, runtime.json, { ok: false, command: "runs drive", error: "run_drive_failed", issues: error.issues }, `run drive failed: ${error.message}`);
@@ -33920,6 +33968,45 @@ async function cmdVnextRuntime(runtime, action) {
33920
33968
  return 1;
33921
33969
  }
33922
33970
  }
33971
+ async function cmdVnextRunReceipt(runtime, runId, options = {}) {
33972
+ try {
33973
+ const projectRoot = discoverVnextProjectRoot(runtime.cwd);
33974
+ if (!projectRoot) {
33975
+ print(runtime.io, runtime.json, { ok: false, command: "runs receipt", error: "project_required" }, "kxm runs receipt requires a vNext project (run kxm init first)");
33976
+ return 1;
33977
+ }
33978
+ const supervisor = await (vnextDriveCliSeams.ensureSupervisor ?? ensureVnextSupervisor)({ env: runtime.env });
33979
+ const result = await (vnextDriveCliSeams.runtimeRequest ?? vnextRuntimeRequest)(
33980
+ supervisor,
33981
+ "GET",
33982
+ `/v1/runs/${encodeURIComponent(runId)}/drive?projectRoot=${encodeURIComponent(projectRoot)}`
33983
+ );
33984
+ if (!Array.isArray(result.receipts)) {
33985
+ print(runtime.io, runtime.json, { ok: false, command: "runs receipt", error: "run_receipt_io_failed" }, "run receipt failed because a local operation did not complete");
33986
+ return 1;
33987
+ }
33988
+ const receipts = result.receipts;
33989
+ if (receipts.length === 0) {
33990
+ print(runtime.io, runtime.json, { ok: false, command: "runs receipt", error: "no_receipts" }, `run ${runId} has no drive receipts`);
33991
+ return 1;
33992
+ }
33993
+ if (options.all === true) {
33994
+ print(runtime.io, runtime.json, { ok: true, command: "runs receipt", receipts }, JSON.stringify(receipts, null, 2));
33995
+ return 0;
33996
+ }
33997
+ const latest = receipts[0];
33998
+ const settlement = latest && typeof latest === "object" && "settlement" in latest ? latest.settlement : latest;
33999
+ print(runtime.io, runtime.json, { ok: true, command: "runs receipt", receipt: latest }, JSON.stringify(settlement, null, 2));
34000
+ return 0;
34001
+ } catch (error) {
34002
+ if (error instanceof VnextConfigError) {
34003
+ print(runtime.io, runtime.json, { ok: false, command: "runs receipt", error: "run_receipt_failed", issues: error.issues }, `run receipt failed: ${error.message}`);
34004
+ return 1;
34005
+ }
34006
+ print(runtime.io, runtime.json, { ok: false, command: "runs receipt", error: "run_receipt_io_failed" }, "run receipt failed because a local operation did not complete");
34007
+ return 1;
34008
+ }
34009
+ }
33923
34010
 
33924
34011
  // plugins/kxm/src/cli/tasks.ts
33925
34012
  async function cmdSuggest(runtime, promptParts) {
@@ -48695,8 +48782,14 @@ function createProgram(ctx, result) {
48695
48782
  addGlobalOptions(runCmd.command("status").description("Show the projected status of a run, including durable drive receipt state (open / receipt verified / unsettled / orphaned)")).argument("<runId>", "Run id").action(async function runStatusAction(runId) {
48696
48783
  result.code = await cmdVnextRunStatus(runtimeFrom(ctx, this), runId);
48697
48784
  });
48698
- addGlobalOptions(runCmd.command("drive").description("Drive a run with an explicit model-free simulation")).argument("<runId>", "Run id").option("--simulated", "Use the model-free simulation producer").action(async function runDriveAction(runId, options) {
48699
- result.code = await cmdVnextRunDrive(runtimeFrom(ctx, this), runId, options.simulated === true);
48785
+ addGlobalOptions(runCmd.command("drive").description("Drive a run with an explicit model-free simulation")).argument("<runId>", "Run id").option("--simulated", "Use the model-free simulation producer").option("--wait", "Wait until a drive receipt is recorded; exits 0 only for a VERIFIED COMPLETED settlement").option("--timeout-ms <n>", "Wait timeout in milliseconds (default 60000, max 600000)").action(async function runDriveAction(runId, options) {
48786
+ result.code = await cmdVnextRunDrive(runtimeFrom(ctx, this), runId, options.simulated === true, {
48787
+ wait: options.wait === true,
48788
+ ...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {}
48789
+ });
48790
+ });
48791
+ addGlobalOptions(runCmd.command("receipt").description("Print the newest drive receipt for a run")).argument("<runId>", "Run id").option("--all", "Print the capped receipt list for the run").action(async function runReceiptAction(runId, options) {
48792
+ result.code = await cmdVnextRunReceipt(runtimeFrom(ctx, this), runId, { all: options.all === true });
48700
48793
  });
48701
48794
  addGlobalOptions(runCmd.command("cancel").description("Durably request cancellation of a run")).argument("<runId>", "Run id").action(async function runCancelAction(runId) {
48702
48795
  result.code = await cmdVnextRunCancel(runtimeFrom(ctx, this), runId);
@@ -17121,7 +17121,7 @@ async function deliverInboxNotification(messageId, delivered, notify) {
17121
17121
  }
17122
17122
 
17123
17123
  // plugins/kxm/src/mcp-server.ts
17124
- var VERSION = "0.7.25";
17124
+ var VERSION = "0.7.27";
17125
17125
  var inbox = /* @__PURE__ */ new Map();
17126
17126
  var notifiedInbox = /* @__PURE__ */ new Set();
17127
17127
  var meshClient;
@@ -18764,9 +18764,15 @@ var VnextRunEventStore = class {
18764
18764
  }
18765
18765
  driveReceiptsForRun(runId, limit = 20) {
18766
18766
  const rows = this.database.prepare(`
18767
- SELECT receipt FROM drive_receipts WHERE run_id = ? ORDER BY closed_at DESC, drive_id DESC LIMIT ?
18767
+ SELECT drive_id, receipt FROM drive_receipts WHERE run_id = ? ORDER BY closed_at DESC, drive_id DESC LIMIT ?
18768
18768
  `).all(runId, limit);
18769
- return rows.map((row) => parseDriveReceipt(row.receipt));
18769
+ return rows.map((row) => {
18770
+ try {
18771
+ return parseDriveReceipt(row.receipt);
18772
+ } catch {
18773
+ return { driveId: row.drive_id, divergence: "receipt unreadable" };
18774
+ }
18775
+ });
18770
18776
  }
18771
18777
  insertCapability(row) {
18772
18778
  this.database.prepare(`
@@ -22103,6 +22109,9 @@ function clearVnextDriveSession(storePath, runId, token) {
22103
22109
  if (!current || current.token !== token) return;
22104
22110
  delete current.driveSession;
22105
22111
  }
22112
+ function vnextDriveSession(storePath, runId) {
22113
+ return owners.get(storePath)?.admitted.get(runId)?.driveSession;
22114
+ }
22106
22115
  function vnextOpenDriveSessions(storePath) {
22107
22116
  const owner = owners.get(storePath);
22108
22117
  if (!owner) return [];
@@ -27388,6 +27397,20 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
27388
27397
  sendJson(response, 200, { ok: true, events });
27389
27398
  return;
27390
27399
  }
27400
+ if (request.method === "GET" && sub === "drive") {
27401
+ const run = context.eventStore.run(runId);
27402
+ if (!run) throw runtimeError("run_unknown", runId, "run not found");
27403
+ const activeSession = vnextDriveSession(context.eventStore.path, runId);
27404
+ const session = activeSession ? {
27405
+ driveId: activeSession.driveId,
27406
+ mode: activeSession.mode,
27407
+ openedAt: activeSession.openedAt,
27408
+ deadlineAt: activeSession.deadlineAt ?? null
27409
+ } : null;
27410
+ const receipts = context.eventStore.driveReceiptsForRun(runId, 20);
27411
+ sendJson(response, 200, { ok: true, session, receipts });
27412
+ return;
27413
+ }
27391
27414
  if (request.method === "POST" && sub === "cancel") {
27392
27415
  const body = await readJsonBody(request);
27393
27416
  const result = cancelVnextRun(context, runId, {
@@ -27421,6 +27444,43 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
27421
27444
  return;
27422
27445
  }
27423
27446
  }
27447
+ const driveMatch = /^\/v1\/drives\/([A-Za-z0-9_-]+)$/.exec(url.pathname);
27448
+ if (request.method === "GET" && driveMatch) {
27449
+ const driveId = driveMatch[1];
27450
+ const projectRoot = url.searchParams.get("projectRoot") ?? "";
27451
+ if (!projectRoot) {
27452
+ sendJson(response, 400, { ok: false, error: "runtime_request_invalid", message: "projectRoot query parameter is required" });
27453
+ return;
27454
+ }
27455
+ const context = contextFor(projectRoot);
27456
+ let receipt;
27457
+ try {
27458
+ receipt = context.eventStore.driveReceipt(driveId);
27459
+ } catch {
27460
+ sendJson(response, 200, { ok: true, receipt: null, verified: false, divergence: "receipt unreadable" });
27461
+ return;
27462
+ }
27463
+ if (!receipt) {
27464
+ sendJson(response, 404, { ok: false, error: "drive_receipt_missing", message: "receipt not found" });
27465
+ return;
27466
+ }
27467
+ const runId = receipt.runId;
27468
+ const stored = context.eventStore.run(runId);
27469
+ if (!stored) {
27470
+ sendJson(response, 200, { ok: true, receipt, verified: false, divergence: "run missing" });
27471
+ return;
27472
+ }
27473
+ const state = foldStoredVnextRun(context, stored);
27474
+ const events = context.eventStore.events(runId, 0, 1e6);
27475
+ const checked = verifyVnextDriveReceipt(receipt, events, state.status, { runId, driveId });
27476
+ sendJson(response, 200, {
27477
+ ok: true,
27478
+ receipt,
27479
+ verified: checked.verified,
27480
+ ...checked.divergence !== void 0 ? { divergence: checked.divergence } : {}
27481
+ });
27482
+ return;
27483
+ }
27424
27484
  const projectRunsMatch = /^\/v1\/projects\/(prj_[A-Za-z0-9_-]+)\/runs$/.exec(url.pathname);
27425
27485
  if (request.method === "GET" && projectRunsMatch) {
27426
27486
  const projectRoot = url.searchParams.get("projectRoot") ?? "";
@@ -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(`
@@ -21668,6 +21674,9 @@ function clearVnextDriveSession(storePath, runId, token) {
21668
21674
  if (!current || current.token !== token) return;
21669
21675
  delete current.driveSession;
21670
21676
  }
21677
+ function vnextDriveSession(storePath, runId) {
21678
+ return owners.get(storePath)?.admitted.get(runId)?.driveSession;
21679
+ }
21671
21680
  function vnextOpenDriveSessions(storePath) {
21672
21681
  const owner = owners.get(storePath);
21673
21682
  if (!owner) return [];
@@ -26902,6 +26911,20 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
26902
26911
  sendJson(response, 200, { ok: true, events });
26903
26912
  return;
26904
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
+ }
26905
26928
  if (request.method === "POST" && sub === "cancel") {
26906
26929
  const body = await readJsonBody(request);
26907
26930
  const result = cancelVnextRun(context, runId, {
@@ -26935,6 +26958,43 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
26935
26958
  return;
26936
26959
  }
26937
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
+ }
26938
26998
  const projectRunsMatch = /^\/v1\/projects\/(prj_[A-Za-z0-9_-]+)\/runs$/.exec(url.pathname);
26939
26999
  if (request.method === "GET" && projectRunsMatch) {
26940
27000
  const projectRoot = url.searchParams.get("projectRoot") ?? "";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kxm-claude-plugin",
3
- "version": "0.7.25",
3
+ "version": "0.7.27",
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
 
@@ -557,7 +557,32 @@ export async function cmdVnextRunStatus(runtime: Runtime, runId: string): Promis
557
557
  }
558
558
  }
559
559
 
560
- export async function cmdVnextRunDrive(runtime: Runtime, runId: string, simulated: boolean): Promise<number> {
560
+ const DEFAULT_DRIVE_WAIT_MS = 60_000;
561
+ const MAX_DRIVE_WAIT_MS = 600_000;
562
+
563
+ function parseDriveWaitTimeoutMs(raw: number | string | undefined): number | undefined {
564
+ if (raw === undefined) return DEFAULT_DRIVE_WAIT_MS;
565
+ const value = typeof raw === "number" ? raw : Number(typeof raw === "string" ? raw.trim() : raw);
566
+ if (!Number.isInteger(value) || value < 1 || value > MAX_DRIVE_WAIT_MS) return undefined;
567
+ return value;
568
+ }
569
+
570
+ function sleepMs(ms: number): Promise<void> {
571
+ return new Promise((resolve) => setTimeout(resolve, ms));
572
+ }
573
+
574
+ function driveWaitCompleted(drive: VnextStatusDrive | undefined): boolean {
575
+ return drive?.verified === true
576
+ && drive.receipt?.settlement?.kind === "terminal"
577
+ && drive.receipt.settlement.status === "completed";
578
+ }
579
+
580
+ export async function cmdVnextRunDrive(
581
+ runtime: Runtime,
582
+ runId: string,
583
+ simulated: boolean,
584
+ options: { wait?: boolean; timeoutMs?: number | string } = {},
585
+ ): Promise<number> {
561
586
  try {
562
587
  const projectRoot = discoverVnextProjectRoot(runtime.cwd);
563
588
  if (!projectRoot) {
@@ -569,8 +594,19 @@ export async function cmdVnextRunDrive(runtime: Runtime, runId: string, simulate
569
594
  print(runtime.io, runtime.json, { ok: true, command: "runs drive", dryRun: true, runId, mode }, `drive plan: run ${runId} in ${mode} mode (no events written)`);
570
595
  return 0;
571
596
  }
597
+ const timeoutMs = options.wait === true ? parseDriveWaitTimeoutMs(options.timeoutMs) : DEFAULT_DRIVE_WAIT_MS;
598
+ if (options.wait === true && timeoutMs === undefined) {
599
+ print(
600
+ runtime.io,
601
+ runtime.json,
602
+ { ok: false, command: "runs drive", error: "run_drive_timeout_invalid" },
603
+ `run drive --wait --timeout-ms must be an integer between 1 and ${MAX_DRIVE_WAIT_MS}`,
604
+ );
605
+ return 1;
606
+ }
572
607
  const supervisor = await (vnextDriveCliSeams.ensureSupervisor ?? ensureVnextSupervisor)({ env: runtime.env });
573
- const result = await (vnextDriveCliSeams.runtimeRequest ?? vnextRuntimeRequest)(supervisor, "POST", `/v1/runs/${encodeURIComponent(runId)}/drive?projectRoot=${encodeURIComponent(projectRoot)}`, { mode });
608
+ const request = vnextDriveCliSeams.runtimeRequest ?? vnextRuntimeRequest;
609
+ const result = await request(supervisor, "POST", `/v1/runs/${encodeURIComponent(runId)}/drive?projectRoot=${encodeURIComponent(projectRoot)}`, { mode });
574
610
  const driveId = result.driveId;
575
611
  const poll = result.poll;
576
612
  const status = result.status;
@@ -578,13 +614,39 @@ export async function cmdVnextRunDrive(runtime: Runtime, runId: string, simulate
578
614
  print(runtime.io, runtime.json, { ok: false, command: "runs drive", error: "run_drive_io_failed" }, "run drive failed because a local operation did not complete");
579
615
  return 1;
580
616
  }
581
- print(
582
- runtime.io,
583
- runtime.json,
584
- { ok: true, command: "runs drive", runId, driveId, poll, mode, status },
585
- `drive ${driveId}: accepted (poll ${poll})`,
586
- );
587
- return 0;
617
+
618
+ if (options.wait !== true) {
619
+ print(
620
+ runtime.io,
621
+ runtime.json,
622
+ { ok: true, command: "runs drive", runId, driveId, poll, mode, status },
623
+ `drive ${driveId}: accepted (poll ${poll})`,
624
+ );
625
+ return 0;
626
+ }
627
+
628
+ const deadline = Date.now() + timeoutMs!;
629
+ let interval = 25;
630
+ while (true) {
631
+ const stateResult = await request(supervisor, "GET", `/v1/runs/${encodeURIComponent(runId)}?projectRoot=${encodeURIComponent(projectRoot)}`);
632
+ const drive = stateResult.drive as VnextStatusDrive | undefined;
633
+ if (drive?.receipt) {
634
+ print(
635
+ runtime.io,
636
+ runtime.json,
637
+ { ok: driveWaitCompleted(drive), command: "runs drive", receipt: drive.receipt, verified: drive.verified === true },
638
+ JSON.stringify(drive.receipt, null, 2),
639
+ );
640
+ return driveWaitCompleted(drive) ? 0 : 1;
641
+ }
642
+ const remaining = deadline - Date.now();
643
+ if (remaining <= 0) break;
644
+ await sleepMs(Math.min(interval, remaining));
645
+ interval = Math.min(Math.floor(interval * 1.5), 250);
646
+ }
647
+
648
+ print(runtime.io, runtime.json, { ok: false, command: "runs drive", error: "timeout" }, "drive wait timed out");
649
+ return 1;
588
650
  } catch (error) {
589
651
  if (error instanceof VnextConfigError) {
590
652
  print(runtime.io, runtime.json, { ok: false, command: "runs drive", error: "run_drive_failed", issues: error.issues }, `run drive failed: ${error.message}`);
@@ -772,3 +834,45 @@ export async function cmdVnextRuntime(runtime: Runtime, action: string): Promise
772
834
  return 1;
773
835
  }
774
836
  }
837
+
838
+ export async function cmdVnextRunReceipt(runtime: Runtime, runId: string, options: { all?: boolean } = {}): Promise<number> {
839
+ try {
840
+ const projectRoot = discoverVnextProjectRoot(runtime.cwd);
841
+ if (!projectRoot) {
842
+ print(runtime.io, runtime.json, { ok: false, command: "runs receipt", error: "project_required" }, "kxm runs receipt requires a vNext project (run kxm init first)");
843
+ return 1;
844
+ }
845
+ const supervisor = await (vnextDriveCliSeams.ensureSupervisor ?? ensureVnextSupervisor)({ env: runtime.env });
846
+ const result = await (vnextDriveCliSeams.runtimeRequest ?? vnextRuntimeRequest)(
847
+ supervisor,
848
+ "GET",
849
+ `/v1/runs/${encodeURIComponent(runId)}/drive?projectRoot=${encodeURIComponent(projectRoot)}`,
850
+ );
851
+ if (!Array.isArray(result.receipts)) {
852
+ print(runtime.io, runtime.json, { ok: false, command: "runs receipt", error: "run_receipt_io_failed" }, "run receipt failed because a local operation did not complete");
853
+ return 1;
854
+ }
855
+ const receipts = result.receipts as unknown[];
856
+ if (receipts.length === 0) {
857
+ print(runtime.io, runtime.json, { ok: false, command: "runs receipt", error: "no_receipts" }, `run ${runId} has no drive receipts`);
858
+ return 1;
859
+ }
860
+ if (options.all === true) {
861
+ print(runtime.io, runtime.json, { ok: true, command: "runs receipt", receipts }, JSON.stringify(receipts, null, 2));
862
+ return 0;
863
+ }
864
+ const latest = receipts[0];
865
+ const settlement = latest && typeof latest === "object" && "settlement" in latest
866
+ ? (latest as { settlement: unknown }).settlement
867
+ : latest;
868
+ print(runtime.io, runtime.json, { ok: true, command: "runs receipt", receipt: latest }, JSON.stringify(settlement, null, 2));
869
+ return 0;
870
+ } catch (error) {
871
+ if (error instanceof VnextConfigError) {
872
+ print(runtime.io, runtime.json, { ok: false, command: "runs receipt", error: "run_receipt_failed", issues: error.issues }, `run receipt failed: ${error.message}`);
873
+ return 1;
874
+ }
875
+ print(runtime.io, runtime.json, { ok: false, command: "runs receipt", error: "run_receipt_io_failed" }, "run receipt failed because a local operation did not complete");
876
+ return 1;
877
+ }
878
+ }
@@ -107,6 +107,7 @@ import {
107
107
  cmdVnextRun,
108
108
  cmdVnextRunStatus,
109
109
  cmdVnextRunDrive,
110
+ cmdVnextRunReceipt,
110
111
  cmdVnextRunCancel,
111
112
  cmdVnextRunList,
112
113
  cmdHarnessList,
@@ -390,8 +391,19 @@ function createProgram(ctx: CliContext, result: { code: number }): Command {
390
391
  addGlobalOptions(runCmd.command("drive").description("Drive a run with an explicit model-free simulation"))
391
392
  .argument("<runId>", "Run id")
392
393
  .option("--simulated", "Use the model-free simulation producer")
393
- .action(async function runDriveAction(this: Command, runId: string, options: { simulated?: boolean }) {
394
- result.code = await cmdVnextRunDrive(runtimeFrom(ctx, this), runId, options.simulated === true);
394
+ .option("--wait", "Wait until a drive receipt is recorded; exits 0 only for a VERIFIED COMPLETED settlement")
395
+ .option("--timeout-ms <n>", "Wait timeout in milliseconds (default 60000, max 600000)")
396
+ .action(async function runDriveAction(this: Command, runId: string, options: { simulated?: boolean; wait?: boolean; timeoutMs?: string }) {
397
+ result.code = await cmdVnextRunDrive(runtimeFrom(ctx, this), runId, options.simulated === true, {
398
+ wait: options.wait === true,
399
+ ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),
400
+ });
401
+ });
402
+ addGlobalOptions(runCmd.command("receipt").description("Print the newest drive receipt for a run"))
403
+ .argument("<runId>", "Run id")
404
+ .option("--all", "Print the capped receipt list for the run")
405
+ .action(async function runReceiptAction(this: Command, runId: string, options: { all?: boolean }) {
406
+ result.code = await cmdVnextRunReceipt(runtimeFrom(ctx, this), runId, { all: options.all === true });
395
407
  });
396
408
  addGlobalOptions(runCmd.command("cancel").description("Durably request cancellation of a run"))
397
409
  .argument("<runId>", "Run id")
@@ -8,7 +8,7 @@ import { AGENT_COMMANDS_MAP, enforceToolPolicy, getMcpTools, reconcileInbox } fr
8
8
  import { deliverInboxNotification } from "./inbox.ts";
9
9
  import type { HubEvent, MessageRecord } from "./protocol.ts";
10
10
 
11
- const VERSION = "0.7.25";
11
+ const VERSION = "0.7.27";
12
12
  const inbox = new Map<string, MessageRecord>();
13
13
  const notifiedInbox = new Set<string>();
14
14
  let meshClient: HubClient | undefined;
@@ -396,6 +396,10 @@ export interface VnextDriveReceipt {
396
396
  producer: { id: string; closed: boolean };
397
397
  }
398
398
 
399
+ export type VnextDriveReceiptListItem =
400
+ | VnextDriveReceipt
401
+ | { readonly driveId: string; readonly divergence: string };
402
+
399
403
  export interface VnextDriveReceiptBudget {
400
404
  budgetMs: number;
401
405
  source: "workflow" | "project" | "both";
@@ -1014,11 +1018,17 @@ export class VnextRunEventStore {
1014
1018
  return row ? parseDriveReceipt(row.receipt) : undefined;
1015
1019
  }
1016
1020
 
1017
- driveReceiptsForRun(runId: string, limit = 20): VnextDriveReceipt[] {
1021
+ driveReceiptsForRun(runId: string, limit = 20): VnextDriveReceiptListItem[] {
1018
1022
  const rows = this.database.prepare(`
1019
- SELECT receipt FROM drive_receipts WHERE run_id = ? ORDER BY closed_at DESC, drive_id DESC LIMIT ?
1020
- `).all(runId, limit) as Array<{ receipt: string }>;
1021
- return rows.map((row) => parseDriveReceipt(row.receipt));
1023
+ SELECT drive_id, receipt FROM drive_receipts WHERE run_id = ? ORDER BY closed_at DESC, drive_id DESC LIMIT ?
1024
+ `).all(runId, limit) as Array<{ drive_id: string; receipt: string }>;
1025
+ return rows.map((row) => {
1026
+ try {
1027
+ return parseDriveReceipt(row.receipt);
1028
+ } catch {
1029
+ return { driveId: row.drive_id, divergence: "receipt unreadable" };
1030
+ }
1031
+ });
1022
1032
  }
1023
1033
 
1024
1034
  insertCapability(row: VnextAttemptCapabilityRow): void {
@@ -9,6 +9,7 @@ import {
9
9
  VnextRuntimeRegistry,
10
10
  projectRuntimeKey,
11
11
  runtimeError,
12
+ verifyVnextDriveReceipt,
12
13
  vnextRuntimePaths,
13
14
  type VnextRuntimePaths,
14
15
  } from "./vnext-runtime-store.ts";
@@ -24,7 +25,7 @@ import {
24
25
  import { createVnextOneShotProducer } from "./vnext-oneshot-producer.ts";
25
26
  import { isProducerAdmitted } from "./producers.ts";
26
27
  import { VnextRunScheduler, createVnextSimulatedProducer, recordDriveReceipt, recoverVnextRun, vnextDrivePollProjection } from "./vnext-engine.ts";
27
- import { vnextOpenDriveSessions } from "./vnext-runtime-owner.ts";
28
+ import { vnextDriveSession, vnextOpenDriveSessions } from "./vnext-runtime-owner.ts";
28
29
 
29
30
  /* ------------------------------------------------------------------ *
30
31
  * Token management
@@ -551,6 +552,24 @@ async function startVnextRuntimeSupervisorInner(
551
552
  sendJson(response, 200, { ok: true, events });
552
553
  return;
553
554
  }
555
+
556
+ if (request.method === "GET" && sub === "drive") {
557
+ const run = context.eventStore.run(runId);
558
+ if (!run) throw runtimeError("run_unknown", runId, "run not found");
559
+
560
+ const activeSession = vnextDriveSession(context.eventStore.path, runId);
561
+ const session = activeSession
562
+ ? {
563
+ driveId: activeSession.driveId,
564
+ mode: activeSession.mode,
565
+ openedAt: activeSession.openedAt,
566
+ deadlineAt: activeSession.deadlineAt ?? null,
567
+ }
568
+ : null;
569
+ const receipts = context.eventStore.driveReceiptsForRun(runId, 20);
570
+ sendJson(response, 200, { ok: true, session, receipts });
571
+ return;
572
+ }
554
573
  if (request.method === "POST" && sub === "cancel") {
555
574
  const body = await readJsonBody(request);
556
575
  const result = cancelVnextRun(context, runId, {
@@ -585,6 +604,47 @@ async function startVnextRuntimeSupervisorInner(
585
604
  }
586
605
  }
587
606
 
607
+ const driveMatch = /^\/v1\/drives\/([A-Za-z0-9_-]+)$/.exec(url.pathname);
608
+ if (request.method === "GET" && driveMatch) {
609
+ const driveId = driveMatch[1] as string;
610
+ const projectRoot = url.searchParams.get("projectRoot") ?? "";
611
+ if (!projectRoot) {
612
+ sendJson(response, 400, { ok: false, error: "runtime_request_invalid", message: "projectRoot query parameter is required" });
613
+ return;
614
+ }
615
+ const context = contextFor(projectRoot);
616
+
617
+ let receipt;
618
+ try {
619
+ receipt = context.eventStore.driveReceipt(driveId);
620
+ } catch {
621
+ sendJson(response, 200, { ok: true, receipt: null, verified: false, divergence: "receipt unreadable" });
622
+ return;
623
+ }
624
+
625
+ if (!receipt) {
626
+ sendJson(response, 404, { ok: false, error: "drive_receipt_missing", message: "receipt not found" });
627
+ return;
628
+ }
629
+
630
+ const runId = receipt.runId;
631
+ const stored = context.eventStore.run(runId);
632
+ if (!stored) {
633
+ sendJson(response, 200, { ok: true, receipt, verified: false, divergence: "run missing" });
634
+ return;
635
+ }
636
+ const state = foldStoredVnextRun(context, stored);
637
+ const events = context.eventStore.events(runId, 0, 1_000_000);
638
+ const checked = verifyVnextDriveReceipt(receipt, events, state.status, { runId, driveId });
639
+ sendJson(response, 200, {
640
+ ok: true,
641
+ receipt,
642
+ verified: checked.verified,
643
+ ...(checked.divergence !== undefined ? { divergence: checked.divergence } : {}),
644
+ });
645
+ return;
646
+ }
647
+
588
648
  const projectRunsMatch = /^\/v1\/projects\/(prj_[A-Za-z0-9_-]+)\/runs$/.exec(url.pathname);
589
649
  if (request.method === "GET" && projectRunsMatch) {
590
650
  const projectRoot = url.searchParams.get("projectRoot") ?? "";