@kontextmind/kxm 0.7.109 → 0.7.111

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.109",
14
+ "version": "0.7.111",
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.109",
3
+ "version": "0.7.111",
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.109",
5
+ "version": "0.7.111",
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",
@@ -17313,7 +17313,7 @@ function sessionTokenFixHint(policy) {
17313
17313
  }
17314
17314
 
17315
17315
  // plugins/kxm/src/mcp-server.ts
17316
- var VERSION = "0.7.109";
17316
+ var VERSION = "0.7.111";
17317
17317
  var CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
17318
17318
  var inbox = /* @__PURE__ */ new Map();
17319
17319
  var notifiedInbox = /* @__PURE__ */ new Set();
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-plugin",
3
- "version": "0.7.109",
3
+ "version": "0.7.111",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "engines": {
@@ -11,7 +11,7 @@ import { deliverInboxNotification } from "./inbox.ts";
11
11
  import type { HubEvent, MessageRecord } from "./protocol.ts";
12
12
  import { sessionTokenFixHint } from "./session-token-hint.ts";
13
13
 
14
- const VERSION = "0.7.109";
14
+ const VERSION = "0.7.111";
15
15
  const CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
16
16
  const inbox = new Map<string, MessageRecord>();
17
17
  const notifiedInbox = new Set<string>();
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { existsSync } from "node:fs";
3
+ import { existsSync, readFileSync } from "node:fs";
4
4
  import { resolve } from "node:path";
5
5
  import { spawnSync } from "node:child_process";
6
6
  import { fileURLToPath } from "node:url";
@@ -22,6 +22,55 @@ export const STATIC_GENERATED_ARTIFACTS = Object.freeze([
22
22
  "GEMINI.md",
23
23
  ]);
24
24
 
25
+ /**
26
+ * Packages whose installed version differs from `package-lock.json`.
27
+ *
28
+ * The generated bundles embed dependency **bytes and paths**, so a
29
+ * `node_modules` that has drifted from the lock produces artifacts that pass
30
+ * this check locally and fail in CI — which installs from the lock on every
31
+ * leg. That asymmetry is worse than a broken build: it lets a machine ship a
32
+ * bundle nobody else can reproduce. Refuse before the build, naming the
33
+ * packages, instead of reporting a diff the developer cannot act on.
34
+ *
35
+ * @param {string} [repository]
36
+ * @returns {string[]}
37
+ */
38
+ export function findLockfileDrift(repository = process.cwd()) {
39
+ const root = resolve(repository);
40
+ if (!existsSync(resolve(root, "node_modules"))) return [];
41
+ const lockPath = resolve(root, "package-lock.json");
42
+ if (!existsSync(lockPath)) return [];
43
+ let lock;
44
+ try {
45
+ lock = JSON.parse(readFileSync(lockPath, "utf8"));
46
+ } catch {
47
+ return ["package-lock.json is unreadable"];
48
+ }
49
+ const packages = lock?.packages;
50
+ if (!packages || typeof packages !== "object") return [];
51
+ const drifted = [];
52
+ for (const [key, entry] of Object.entries(packages)) {
53
+ if (!key.startsWith("node_modules/")) continue; // the root importer and workspaces
54
+ if (entry?.link) continue; // a symlinked workspace, not an installed version
55
+ const name = key.split("node_modules/").pop();
56
+ const manifest = resolve(root, key, "package.json");
57
+ if (!existsSync(manifest)) {
58
+ if (!entry.optional) drifted.push(`${name}@${entry.version} is not installed`);
59
+ continue;
60
+ }
61
+ let installed;
62
+ try {
63
+ installed = JSON.parse(readFileSync(manifest, "utf8")).version;
64
+ } catch {
65
+ installed = undefined;
66
+ }
67
+ if (installed !== entry.version) {
68
+ drifted.push(`${name}: lock ${entry.version}, installed ${installed ?? "unreadable"}`);
69
+ }
70
+ }
71
+ return drifted;
72
+ }
73
+
25
74
  /**
26
75
  * Compute the generated artifact list from the committed suite manifest.
27
76
  * The manifest is required; missing or invalid manifests fail closed.
@@ -65,6 +114,16 @@ export function checkGeneratedArtifacts(repository = process.cwd()) {
65
114
  const root = resolve(topLevel);
66
115
  const artifacts = computeGeneratedArtifacts(root);
67
116
 
117
+ const drifted = findLockfileDrift(root);
118
+ if (drifted.length > 0) {
119
+ const shown = drifted.slice(0, 8).map((line) => ` ${line}`).join("\n");
120
+ throw new Error(
121
+ `node_modules does not match package-lock.json (${drifted.length} package(s)); `
122
+ + "the generated bundles embed dependency bytes, so CI — which runs npm ci — will rebuild them differently.\n"
123
+ + `${shown}${drifted.length > 8 ? "\n …" : ""}\nRun: npm ci`,
124
+ );
125
+ }
126
+
68
127
  const missing = artifacts.filter((path) => !existsSync(resolve(root, path)));
69
128
  if (missing.length > 0) {
70
129
  throw new Error(`generated artifacts are missing: ${missing.join(", ")}`);