@kontextmind/kxm 0.7.79 → 0.7.81

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.79",
14
+ "version": "0.7.81",
15
15
  "category": "development",
16
16
  "tags": ["kxm", "multi-agent", "workflows", "mcp"]
17
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextmind/kxm",
3
- "version": "0.7.79",
3
+ "version": "0.7.81",
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.79",
5
+ "version": "0.7.81",
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",
@@ -23980,20 +23980,30 @@ function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVers
23980
23980
  integrity: "ok"
23981
23981
  };
23982
23982
  }
23983
+ var KXM_BACKUP_CEILINGS = {
23984
+ "hub-store": 5,
23985
+ registry: 1,
23986
+ "binding-store": 1,
23987
+ events: 7
23988
+ };
23989
+ function kxmBackupCeiling(storeId) {
23990
+ if (storeId.startsWith("events:")) return KXM_BACKUP_CEILINGS.events;
23991
+ return KXM_BACKUP_CEILINGS[storeId] ?? KXM_BACKUP_CEILINGS["hub-store"];
23992
+ }
23983
23993
  function discoverProjectStores(projectRoot, options = {}) {
23984
23994
  const root = resolve5(projectRoot);
23985
23995
  const stores = [];
23986
23996
  const hubPath = options.hubDataPath ? resolve5(options.hubDataPath) : join8(root, ".kxm", "state", "kxm.db");
23987
23997
  if (existsSync8(hubPath)) {
23988
- stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: 5 });
23998
+ stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: kxmBackupCeiling("hub-store") });
23989
23999
  }
23990
24000
  const registryPath = join8(root, ".kxm", "runtime", "registry.db");
23991
24001
  if (existsSync8(registryPath)) {
23992
- stores.push({ storeId: "registry", sourcePath: registryPath, maxSupportedVersion: 1 });
24002
+ stores.push({ storeId: "registry", sourcePath: registryPath, maxSupportedVersion: kxmBackupCeiling("registry") });
23993
24003
  }
23994
24004
  const bindingsPath = join8(root, ".kxm", "runtime", "bindings.db");
23995
24005
  if (existsSync8(bindingsPath)) {
23996
- stores.push({ storeId: "binding-store", sourcePath: bindingsPath, maxSupportedVersion: 1 });
24006
+ stores.push({ storeId: "binding-store", sourcePath: bindingsPath, maxSupportedVersion: kxmBackupCeiling("binding-store") });
23997
24007
  }
23998
24008
  const eventsDir = join8(root, ".kxm", "runtime", "events");
23999
24009
  if (existsSync8(eventsDir)) {
@@ -24004,7 +24014,7 @@ function discoverProjectStores(projectRoot, options = {}) {
24004
24014
  stores.push({
24005
24015
  storeId: `events:${key}`,
24006
24016
  sourcePath: join8(eventsDir, entry.name),
24007
- maxSupportedVersion: 6
24017
+ maxSupportedVersion: kxmBackupCeiling(`events:${key}`)
24008
24018
  });
24009
24019
  }
24010
24020
  }
@@ -24091,12 +24101,7 @@ function restoreBackup(manifestPathOrDir, options = {}) {
24091
24101
  `backup file ${store.backupFile} sha256 ${actualSha256} does not match manifest hash ${store.sha256}`
24092
24102
  );
24093
24103
  }
24094
- let maxSupported = 5;
24095
- if (store.storeId === "registry" || store.storeId === "binding-store") {
24096
- maxSupported = 1;
24097
- } else if (store.storeId.startsWith("events:")) {
24098
- maxSupported = 7;
24099
- }
24104
+ const maxSupported = kxmBackupCeiling(store.storeId);
24100
24105
  let targetPath = store.sourcePath;
24101
24106
  if (options.projectRoot && manifest.projectRoot && targetPath.startsWith(manifest.projectRoot)) {
24102
24107
  const rel = targetPath.slice(manifest.projectRoot.length).replace(/^[\\/]+/, "");
@@ -32775,7 +32780,7 @@ async function cmdKxmRuntime(runtime, action) {
32775
32780
  const sync = status.running ? await readKxmSupervisorSync(runtime) : void 0;
32776
32781
  print(runtime.io, runtime.json, { ok: true, command: "runtime status", ...status, ...sync ? { sync } : {} }, [
32777
32782
  status.running ? `runtime supervisor running: ${status.runtimeId} pid ${status.pid} on 127.0.0.1:${status.port}` : "runtime supervisor is not running",
32778
- ...formatKxmSyncStatus(sync)
32783
+ ...formatKxmSyncStatus(sync, status.running)
32779
32784
  ].join("\n"));
32780
32785
  return status.running ? 0 : 1;
32781
32786
  }
@@ -32834,8 +32839,9 @@ async function readKxmSupervisorSync(runtime) {
32834
32839
  return void 0;
32835
32840
  }
32836
32841
  }
32837
- function formatKxmSyncStatus(sync) {
32838
- if (sync === void 0) return ["sync: the supervisor did not answer /v1/sync/status"];
32842
+ function formatKxmSyncStatus(sync, running) {
32843
+ if (!running) return [];
32844
+ if (sync === void 0) return ["sync: the supervisor is running but did not answer /v1/sync/status"];
32839
32845
  if (sync.length === 0) return ["sync: no project registered with this Runtime yet"];
32840
32846
  return sync.map((project) => {
32841
32847
  const codes = project.outbox.refusals.map((refusal) => `${refusal.code} x${refusal.count}`).join(", ");
@@ -17182,7 +17182,7 @@ async function deliverInboxNotification(messageId, delivered, notify) {
17182
17182
  }
17183
17183
 
17184
17184
  // plugins/kxm/src/mcp-server.ts
17185
- var VERSION = "0.7.79";
17185
+ var VERSION = "0.7.81";
17186
17186
  var inbox = /* @__PURE__ */ new Map();
17187
17187
  var notifiedInbox = /* @__PURE__ */ new Set();
17188
17188
  var meshClient;
@@ -18326,20 +18326,30 @@ function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVers
18326
18326
  integrity: "ok"
18327
18327
  };
18328
18328
  }
18329
+ var KXM_BACKUP_CEILINGS = {
18330
+ "hub-store": 5,
18331
+ registry: 1,
18332
+ "binding-store": 1,
18333
+ events: 7
18334
+ };
18335
+ function kxmBackupCeiling(storeId) {
18336
+ if (storeId.startsWith("events:")) return KXM_BACKUP_CEILINGS.events;
18337
+ return KXM_BACKUP_CEILINGS[storeId] ?? KXM_BACKUP_CEILINGS["hub-store"];
18338
+ }
18329
18339
  function discoverProjectStores(projectRoot, options = {}) {
18330
18340
  const root = resolve3(projectRoot);
18331
18341
  const stores = [];
18332
18342
  const hubPath = options.hubDataPath ? resolve3(options.hubDataPath) : join4(root, ".kxm", "state", "kxm.db");
18333
18343
  if (existsSync4(hubPath)) {
18334
- stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: 5 });
18344
+ stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: kxmBackupCeiling("hub-store") });
18335
18345
  }
18336
18346
  const registryPath = join4(root, ".kxm", "runtime", "registry.db");
18337
18347
  if (existsSync4(registryPath)) {
18338
- stores.push({ storeId: "registry", sourcePath: registryPath, maxSupportedVersion: 1 });
18348
+ stores.push({ storeId: "registry", sourcePath: registryPath, maxSupportedVersion: kxmBackupCeiling("registry") });
18339
18349
  }
18340
18350
  const bindingsPath = join4(root, ".kxm", "runtime", "bindings.db");
18341
18351
  if (existsSync4(bindingsPath)) {
18342
- stores.push({ storeId: "binding-store", sourcePath: bindingsPath, maxSupportedVersion: 1 });
18352
+ stores.push({ storeId: "binding-store", sourcePath: bindingsPath, maxSupportedVersion: kxmBackupCeiling("binding-store") });
18343
18353
  }
18344
18354
  const eventsDir = join4(root, ".kxm", "runtime", "events");
18345
18355
  if (existsSync4(eventsDir)) {
@@ -18350,7 +18360,7 @@ function discoverProjectStores(projectRoot, options = {}) {
18350
18360
  stores.push({
18351
18361
  storeId: `events:${key}`,
18352
18362
  sourcePath: join4(eventsDir, entry.name),
18353
- maxSupportedVersion: 6
18363
+ maxSupportedVersion: kxmBackupCeiling(`events:${key}`)
18354
18364
  });
18355
18365
  }
18356
18366
  }
@@ -18437,12 +18447,7 @@ function restoreBackup(manifestPathOrDir, options = {}) {
18437
18447
  `backup file ${store.backupFile} sha256 ${actualSha256} does not match manifest hash ${store.sha256}`
18438
18448
  );
18439
18449
  }
18440
- let maxSupported = 5;
18441
- if (store.storeId === "registry" || store.storeId === "binding-store") {
18442
- maxSupported = 1;
18443
- } else if (store.storeId.startsWith("events:")) {
18444
- maxSupported = 7;
18445
- }
18450
+ const maxSupported = kxmBackupCeiling(store.storeId);
18446
18451
  let targetPath = store.sourcePath;
18447
18452
  if (options.projectRoot && manifest.projectRoot && targetPath.startsWith(manifest.projectRoot)) {
18448
18453
  const rel = targetPath.slice(manifest.projectRoot.length).replace(/^[\\/]+/, "");
@@ -31288,6 +31293,7 @@ export {
31288
31293
  IMPROVEMENT_REPORT_SCHEMA,
31289
31294
  IMPROVEMENT_REPORT_V1_SCHEMA,
31290
31295
  KXM_ABSENT_MEMORY_REVISION,
31296
+ KXM_BACKUP_CEILINGS,
31291
31297
  KXM_DRIVE_RECEIPT_SCHEMA,
31292
31298
  KXM_EVENT_STORE_SCHEMA_VERSION,
31293
31299
  KXM_EVENT_STORE_TABLE_NAMES,
@@ -31366,6 +31372,7 @@ export {
31366
31372
  isKxmRuntimeContextClosed,
31367
31373
  isTransactionContention,
31368
31374
  isWindowsHarnessShim,
31375
+ kxmBackupCeiling,
31369
31376
  kxmDeclaredExecutorIds,
31370
31377
  kxmDeclaredRepositoryIds,
31371
31378
  kxmEventBase,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-plugin",
3
- "version": "0.7.79",
3
+ "version": "0.7.81",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "engines": {
@@ -758,7 +758,7 @@ export async function cmdKxmRuntime(runtime: Runtime, action: string): Promise<n
758
758
  status.running
759
759
  ? `runtime supervisor running: ${status.runtimeId} pid ${status.pid} on 127.0.0.1:${status.port}`
760
760
  : "runtime supervisor is not running",
761
- ...formatKxmSyncStatus(sync),
761
+ ...formatKxmSyncStatus(sync, status.running),
762
762
  ].join("\n"));
763
763
  return status.running ? 0 : 1;
764
764
  }
@@ -820,8 +820,11 @@ async function readKxmSupervisorSync(runtime: Runtime): Promise<KxmProjectSyncSt
820
820
  }
821
821
  }
822
822
 
823
- function formatKxmSyncStatus(sync: KxmProjectSyncStatus[] | undefined): string[] {
824
- if (sync === undefined) return ["sync: the supervisor did not answer /v1/sync/status"];
823
+ function formatKxmSyncStatus(sync: KxmProjectSyncStatus[] | undefined, running: boolean): string[] {
824
+ // Nothing was asked, so nothing failed to answer. Saying "did not answer" here
825
+ // would blame a supervisor that was never up.
826
+ if (!running) return [];
827
+ if (sync === undefined) return ["sync: the supervisor is running but did not answer /v1/sync/status"];
825
828
  if (sync.length === 0) return ["sync: no project registered with this Runtime yet"];
826
829
  return sync.map((project) => {
827
830
  const codes = project.outbox.refusals.map((refusal) => `${refusal.code} x${refusal.count}`).join(", ");
@@ -585,25 +585,50 @@ export function restoreDatabaseFile(
585
585
  };
586
586
  }
587
587
 
588
+ /**
589
+ * Per-store restore ceilings, held in **one** table read by both backup discovery
590
+ * and restore. Two copies of these numbers drifted once already: a schema bump
591
+ * raised the restore ceiling and left the discovery ceiling behind, and nothing
592
+ * caught it because nothing read the stale copy.
593
+ *
594
+ * Each value MUST track the version its store declares — `HUB_STORE_SCHEMA_VERSION`
595
+ * in `store.ts`, `KXM_REGISTRY_SCHEMA_VERSION` and `KXM_EVENT_STORE_SCHEMA_VERSION`
596
+ * in `runtime-store.ts`. Those modules import this one, so the constants cannot be
597
+ * named here; the gate is the named test
598
+ * `restore ceilings track every store's own schema version` in
599
+ * `test/core/e6-backup-restore-migrations.test.ts`, which is what the deleted
600
+ * "must track" comments were only pretending to be.
601
+ */
602
+ export const KXM_BACKUP_CEILINGS = {
603
+ "hub-store": 5,
604
+ registry: 1,
605
+ "binding-store": 1,
606
+ events: 7,
607
+ } as const;
608
+
609
+ export function kxmBackupCeiling(storeId: string): number {
610
+ if (storeId.startsWith("events:")) return KXM_BACKUP_CEILINGS.events;
611
+ // An id this build does not know keeps the ceiling restore has always defaulted to.
612
+ return KXM_BACKUP_CEILINGS[storeId as keyof typeof KXM_BACKUP_CEILINGS] ?? KXM_BACKUP_CEILINGS["hub-store"];
613
+ }
614
+
588
615
  export function discoverProjectStores(projectRoot: string, options: { hubDataPath?: string } = {}): Array<{ storeId: string; sourcePath: string; maxSupportedVersion: number }> {
589
616
  const root = resolve(projectRoot);
590
617
  const stores: Array<{ storeId: string; sourcePath: string; maxSupportedVersion: number }> = [];
591
618
 
592
619
  const hubPath = options.hubDataPath ? resolve(options.hubDataPath) : join(root, ".kxm", "state", "kxm.db");
593
620
  if (existsSync(hubPath)) {
594
- // Must track HUB_STORE_SCHEMA_VERSION in store.ts: the hub's own fresh backup is
595
- // restored through this ceiling, so a bump left behind here refuses it.
596
- stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: 5 });
621
+ stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: kxmBackupCeiling("hub-store") });
597
622
  }
598
623
 
599
624
  const registryPath = join(root, ".kxm", "runtime", "registry.db");
600
625
  if (existsSync(registryPath)) {
601
- stores.push({ storeId: "registry", sourcePath: registryPath, maxSupportedVersion: 1 });
626
+ stores.push({ storeId: "registry", sourcePath: registryPath, maxSupportedVersion: kxmBackupCeiling("registry") });
602
627
  }
603
628
 
604
629
  const bindingsPath = join(root, ".kxm", "runtime", "bindings.db");
605
630
  if (existsSync(bindingsPath)) {
606
- stores.push({ storeId: "binding-store", sourcePath: bindingsPath, maxSupportedVersion: 1 });
631
+ stores.push({ storeId: "binding-store", sourcePath: bindingsPath, maxSupportedVersion: kxmBackupCeiling("binding-store") });
607
632
  }
608
633
 
609
634
  const eventsDir = join(root, ".kxm", "runtime", "events");
@@ -615,7 +640,7 @@ export function discoverProjectStores(projectRoot: string, options: { hubDataPat
615
640
  stores.push({
616
641
  storeId: `events:${key}`,
617
642
  sourcePath: join(eventsDir, entry.name),
618
- maxSupportedVersion: 6,
643
+ maxSupportedVersion: kxmBackupCeiling(`events:${key}`),
619
644
  });
620
645
  }
621
646
  }
@@ -729,17 +754,7 @@ export function restoreBackup(
729
754
  );
730
755
  }
731
756
 
732
- // The hub-store ceiling. Must track HUB_STORE_SCHEMA_VERSION in store.ts for the
733
- // same reason as the events ceiling below.
734
- let maxSupported = 5;
735
- if (store.storeId === "registry" || store.storeId === "binding-store") {
736
- maxSupported = 1;
737
- } else if (store.storeId.startsWith("events:")) {
738
- // Must track KXM_EVENT_STORE_SCHEMA_VERSION in runtime-store.ts. The pin is
739
- // the e6 backup/restore round-trip test: bump one without the other and it
740
- // refuses its own fresh backup.
741
- maxSupported = 7;
742
- }
757
+ const maxSupported = kxmBackupCeiling(store.storeId);
743
758
 
744
759
  let targetPath = store.sourcePath;
745
760
  if (options.projectRoot && manifest.projectRoot && targetPath.startsWith(manifest.projectRoot)) {
@@ -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.79";
11
+ const VERSION = "0.7.81";
12
12
  const inbox = new Map<string, MessageRecord>();
13
13
  const notifiedInbox = new Set<string>();
14
14
  let meshClient: HubClient | undefined;