@kontextmind/kxm 0.7.43 → 0.7.44

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.43",
14
+ "version": "0.7.44",
15
15
  "category": "development",
16
16
  "tags": ["kxm", "multi-agent", "workflows", "mcp"]
17
17
  }
package/CHANGELOG.md CHANGED
@@ -38,6 +38,10 @@ All notable user-facing changes are documented here. The project follows [Semant
38
38
  happens to share the product's version is left alone, and a workspace package
39
39
  with no lock entry fails loudly instead of releasing half-bumped.
40
40
 
41
+ - **`kxm hub start` no longer generates and persists an admin token when it is
42
+ about to refuse** because another hub already owns the claim. A refused start
43
+ used to leave behind credentials the running hub never issued.
44
+
41
45
  ## 0.7.0 - 2026-09-11
42
46
 
43
47
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextmind/kxm",
3
- "version": "0.7.43",
3
+ "version": "0.7.44",
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.43",
5
+ "version": "0.7.44",
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",
@@ -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.43";
17124
+ var VERSION = "0.7.44";
17125
17125
  var inbox = /* @__PURE__ */ new Map();
17126
17126
  var notifiedInbox = /* @__PURE__ */ new Set();
17127
17127
  var meshClient;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-plugin",
3
- "version": "0.7.43",
3
+ "version": "0.7.44",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "engines": {
@@ -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.43";
11
+ const VERSION = "0.7.44";
12
12
  const inbox = new Map<string, MessageRecord>();
13
13
  const notifiedInbox = new Set<string>();
14
14
  let meshClient: HubClient | undefined;
@@ -39,6 +39,29 @@ function processExists(pid) {
39
39
  }
40
40
  }
41
41
 
42
+ /**
43
+ * Live hub claim, if any. Read-only: returns the pid of a well-formed
44
+ * `hub.pid` claim whose wrapper is still alive, otherwise null.
45
+ *
46
+ * Claims that are missing, malformed, dead, or stale return null so the
47
+ * atomic `claimPidFile()` below keeps sole authority over those cases — it is
48
+ * the real single-instance guard and fails closed on them. This exists only so
49
+ * a start that is certainly going to be refused can refuse *before* it
50
+ * persists credentials.
51
+ */
52
+ function liveHubClaimPid() {
53
+ let existing;
54
+ try {
55
+ existing = JSON.parse(readFileSync(pidPath, "utf8"));
56
+ } catch {
57
+ return null;
58
+ }
59
+ if (existing?.version === 1 && existing.role === "hub" && Number.isInteger(existing.pid) && processExists(existing.pid)) {
60
+ return existing.pid;
61
+ }
62
+ return null;
63
+ }
64
+
42
65
  function parseHubEnvFile() {
43
66
  const file = join(resolveUserStateRoot(), "hub-env.json");
44
67
  let raw;
@@ -122,6 +145,19 @@ function resolveCredentials() {
122
145
  return { authToken, authTokenSource, projectTokens, projectTokensSource, file };
123
146
  }
124
147
 
148
+ // Pre-flight: refuse a start that a live hub already owns before
149
+ // resolveCredentials() can generate and persist an admin token that the
150
+ // running hub never issued. `kxm hub start` used to mint the credential at
151
+ // module load and only then report "already managed by PID <n>", leaving a
152
+ // hub-env.json whose token no process trusts.
153
+ try {
154
+ const livePid = liveHubClaimPid();
155
+ if (livePid) {
156
+ process.stderr.write(`kxm hub: KXM hub is already managed by PID ${livePid}. Run kxm hub stop before starting another hub.\n`);
157
+ process.exit(1);
158
+ }
159
+ } catch { /* the atomic claim below still guards startup */ }
160
+
125
161
  let credentials;
126
162
  try {
127
163
  credentials = resolveCredentials();