@kontextmind/kxm 0.7.108 → 0.7.110
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.
- package/.claude-plugin/marketplace.json +1 -1
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +1 -1
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/cli/project.ts +5 -1
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/scripts/check-generated.mjs +60 -1
package/package.json
CHANGED
|
@@ -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.
|
|
5
|
+
"version": "0.7.110",
|
|
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",
|
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -35052,7 +35052,7 @@ function formatKxmSyncStatus(sync, running) {
|
|
|
35052
35052
|
return sync.map((project) => {
|
|
35053
35053
|
const codes = project.outbox.refusals.map((refusal) => `${refusal.code} x${refusal.count}`).join(", ");
|
|
35054
35054
|
if (project.storeReadable === false) {
|
|
35055
|
-
return `sync ${project.projectId}: blocked (
|
|
35055
|
+
return `sync ${project.projectId}: blocked (this build cannot open the project) \u2014 ${project.lastError ?? "unknown reason"}`;
|
|
35056
35056
|
}
|
|
35057
35057
|
const counts = `pending ${project.outbox.pending}, acked ${project.outbox.acked}, refused ${project.outbox.refused}`;
|
|
35058
35058
|
const tail = project.state === "refusing" ? ` (${codes || "see log"}) \u2014 fix the hub, then: kxm runtime sync-retry` : project.state === "blocked" ? ` \u2014 last error: ${project.lastError ?? "unreachable"}${project.nextAttemptAt ? `; next attempt ${project.nextAttemptAt}` : ""}` : "";
|
|
@@ -17313,7 +17313,7 @@ function sessionTokenFixHint(policy) {
|
|
|
17313
17313
|
}
|
|
17314
17314
|
|
|
17315
17315
|
// plugins/kxm/src/mcp-server.ts
|
|
17316
|
-
var VERSION = "0.7.
|
|
17316
|
+
var VERSION = "0.7.110";
|
|
17317
17317
|
var CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
|
|
17318
17318
|
var inbox = /* @__PURE__ */ new Map();
|
|
17319
17319
|
var notifiedInbox = /* @__PURE__ */ new Set();
|
package/plugins/kxm/package.json
CHANGED
|
@@ -1003,7 +1003,11 @@ function formatKxmSyncStatus(sync: KxmProjectSyncStatus[] | undefined, running:
|
|
|
1003
1003
|
// empty outbox. Saying "pending 0" there would send the operator looking
|
|
1004
1004
|
// somewhere else while every row in the project sits unreachable.
|
|
1005
1005
|
if (project.storeReadable === false) {
|
|
1006
|
-
|
|
1006
|
+
// "cannot open this project", not "its store is unreadable": what the
|
|
1007
|
+
// supervisor actually sees is whatever `openKxmRuntimeContext` refused —
|
|
1008
|
+
// an out-of-date event store *or* a project config a newer brake rejects.
|
|
1009
|
+
// Witnessed on kxm-dev-svr on 0.7.94, where it was the workflow config.
|
|
1010
|
+
return `sync ${project.projectId}: blocked (this build cannot open the project) — ${project.lastError ?? "unknown reason"}`;
|
|
1007
1011
|
}
|
|
1008
1012
|
const counts = `pending ${project.outbox.pending}, acked ${project.outbox.acked}, refused ${project.outbox.refused}`;
|
|
1009
1013
|
const tail = project.state === "refusing"
|
|
@@ -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.
|
|
14
|
+
const VERSION = "0.7.110";
|
|
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(", ")}`);
|