@kontextmind/kxm 0.7.82 → 0.7.84
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 +49 -12
- package/plugins/kxm/dist/extension.js +6 -1
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/runtime-supervisor.js +6 -1
- package/plugins/kxm/dist/runtime.js +6 -1
- package/plugins/kxm/dist/server.js +6 -1
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/cli/hub.ts +47 -5
- package/plugins/kxm/src/cli/system.ts +13 -6
- package/plugins/kxm/src/kxm-update.ts +15 -0
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/repo-root.ts +12 -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.84",
|
|
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
|
@@ -18176,6 +18176,13 @@ function readInstalledKxmVersion(root) {
|
|
|
18176
18176
|
}
|
|
18177
18177
|
return pkg.version;
|
|
18178
18178
|
}
|
|
18179
|
+
function installedKxmVersion(root) {
|
|
18180
|
+
try {
|
|
18181
|
+
return readInstalledKxmVersion(root);
|
|
18182
|
+
} catch {
|
|
18183
|
+
return void 0;
|
|
18184
|
+
}
|
|
18185
|
+
}
|
|
18179
18186
|
function parseSemver(value) {
|
|
18180
18187
|
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(value.trim());
|
|
18181
18188
|
if (!match) return void 0;
|
|
@@ -18335,7 +18342,7 @@ import { dirname, join as join2 } from "node:path";
|
|
|
18335
18342
|
import { fileURLToPath } from "node:url";
|
|
18336
18343
|
var ROOT_MARKERS = ["scripts/kxm-hub.mjs", "scripts/kxm.mjs"];
|
|
18337
18344
|
var MAX_WALK_DEPTH = 10;
|
|
18338
|
-
function
|
|
18345
|
+
function tryFindKxmRepoRoot(fromUrl = import.meta.url) {
|
|
18339
18346
|
let dir = dirname(fileURLToPath(fromUrl));
|
|
18340
18347
|
for (let depth = 0; depth < MAX_WALK_DEPTH; depth += 1) {
|
|
18341
18348
|
if (ROOT_MARKERS.some((marker) => existsSync2(join2(dir, marker)))) return dir;
|
|
@@ -18343,6 +18350,11 @@ function findKxmRepoRoot(fromUrl = import.meta.url) {
|
|
|
18343
18350
|
if (parent === dir) break;
|
|
18344
18351
|
dir = parent;
|
|
18345
18352
|
}
|
|
18353
|
+
return void 0;
|
|
18354
|
+
}
|
|
18355
|
+
function findKxmRepoRoot(fromUrl = import.meta.url) {
|
|
18356
|
+
const found = tryFindKxmRepoRoot(fromUrl);
|
|
18357
|
+
if (found !== void 0) return found;
|
|
18346
18358
|
throw new Error(
|
|
18347
18359
|
`kxm: cannot locate the KXM repo root from ${fileURLToPath(fromUrl)} (walked ${MAX_WALK_DEPTH} levels looking for ${ROOT_MARKERS[0]})`
|
|
18348
18360
|
);
|
|
@@ -44588,14 +44600,30 @@ async function hubGet(url, fetchImpl) {
|
|
|
44588
44600
|
}
|
|
44589
44601
|
function installProbeFrom(runtime) {
|
|
44590
44602
|
const partial = runtime.io.installProbe ?? {};
|
|
44603
|
+
const moduleDir = partial.moduleDir ?? dirname20(fileURLToPath3(import.meta.url));
|
|
44591
44604
|
return {
|
|
44592
|
-
moduleDir
|
|
44593
|
-
|
|
44605
|
+
moduleDir,
|
|
44606
|
+
// Classify the install that is **running**, never the directory the caller
|
|
44607
|
+
// happens to be standing in. Deriving this from cwd made `kxm update --kxm`
|
|
44608
|
+
// answer "kxm is running from source at <cwd>; update it with git pull there"
|
|
44609
|
+
// on an npm-global install whenever the operator ran it inside a kxm
|
|
44610
|
+
// checkout — and a git pull there deploys nothing, because the services exec
|
|
44611
|
+
// the installed copy. An unrecognisable layout falls back to the module
|
|
44612
|
+
// directory, which classifies as `unknown` ("update it the way it was
|
|
44613
|
+
// installed") rather than inventing a source install.
|
|
44614
|
+
repoRoot: partial.repoRoot ?? tryFindKxmRepoRoot(import.meta.url) ?? moduleDir,
|
|
44594
44615
|
homeDir: partial.homeDir ?? homedir7(),
|
|
44595
44616
|
platform: partial.platform ?? process.platform,
|
|
44596
44617
|
env: partial.env ?? runtime.env
|
|
44597
44618
|
};
|
|
44598
44619
|
}
|
|
44620
|
+
function moduleInstallRoot() {
|
|
44621
|
+
try {
|
|
44622
|
+
return findKxmRepoRoot(import.meta.url);
|
|
44623
|
+
} catch {
|
|
44624
|
+
return dirname20(fileURLToPath3(import.meta.url));
|
|
44625
|
+
}
|
|
44626
|
+
}
|
|
44599
44627
|
function warnIgnoredProjectUpdateYaml(runtime) {
|
|
44600
44628
|
const projectFile = join41(runtime.dirs.workspace, "update.yaml");
|
|
44601
44629
|
if (!existsSync31(projectFile)) return;
|
|
@@ -44603,11 +44631,20 @@ function warnIgnoredProjectUpdateYaml(runtime) {
|
|
|
44603
44631
|
runtime.io.stderr(`kxm: ignoring .kxm/update.yaml in ${runtime.dirs.workdir}; update settings are read only from ${userFile}
|
|
44604
44632
|
`);
|
|
44605
44633
|
}
|
|
44606
|
-
async function refreshKxmUpdateNotice(runtime, config) {
|
|
44634
|
+
async function refreshKxmUpdateNotice(runtime, config, current) {
|
|
44607
44635
|
const resolved = config ?? loadKxmUpdateConfig(runtime.env);
|
|
44608
|
-
const
|
|
44636
|
+
const installed = current ?? installedKxmVersion(findKxmRepoRoot(import.meta.url)) ?? installedKxmVersion(moduleInstallRoot());
|
|
44637
|
+
if (installed === void 0) {
|
|
44638
|
+
return {
|
|
44639
|
+
current: "unknown",
|
|
44640
|
+
available: false,
|
|
44641
|
+
auto: false,
|
|
44642
|
+
source: resolved.source,
|
|
44643
|
+
message: `kxm update check skipped: the installed version is unreadable at ${moduleInstallRoot()}`
|
|
44644
|
+
};
|
|
44645
|
+
}
|
|
44609
44646
|
const fetched = await fetchLatestKxmVersion(resolved.source, runtime.env, runtime.fetchImpl);
|
|
44610
|
-
const notice = noticeFromVersions(
|
|
44647
|
+
const notice = noticeFromVersions(installed, fetched.latest, resolved, fetched.error, fetched.asset);
|
|
44611
44648
|
writeUpdateCache(runtime.dirs.state, notice);
|
|
44612
44649
|
return notice;
|
|
44613
44650
|
}
|
|
@@ -47128,16 +47165,16 @@ async function cmdUpdate(runtime, harness, options) {
|
|
|
47128
47165
|
warnIgnoredProjectUpdateYaml(runtime);
|
|
47129
47166
|
const probe = installProbeFrom(runtime);
|
|
47130
47167
|
const classified = classifyInstallRoot(probe);
|
|
47131
|
-
const current =
|
|
47168
|
+
const current = installedKxmVersion(classified.root) ?? installedKxmVersion(findKxmRepoRoot(import.meta.url));
|
|
47132
47169
|
let notice;
|
|
47133
47170
|
let kindReport = classified;
|
|
47134
47171
|
if (classified.kind === "source") {
|
|
47135
47172
|
if (options.check) {
|
|
47136
|
-
const message = `kxm ${current} (running from source at ${classified.root})`;
|
|
47173
|
+
const message = `kxm ${current ?? "unknown"} (running from source at ${classified.root})`;
|
|
47137
47174
|
print(runtime.io, runtime.json, {
|
|
47138
47175
|
ok: true,
|
|
47139
47176
|
command: "update check",
|
|
47140
|
-
current,
|
|
47177
|
+
current: current ?? "unknown",
|
|
47141
47178
|
available: false,
|
|
47142
47179
|
auto: false,
|
|
47143
47180
|
source: "github",
|
|
@@ -47159,15 +47196,15 @@ async function cmdUpdate(runtime, harness, options) {
|
|
|
47159
47196
|
return 2;
|
|
47160
47197
|
}
|
|
47161
47198
|
notice = {
|
|
47162
|
-
current,
|
|
47199
|
+
current: current ?? "unknown",
|
|
47163
47200
|
available: false,
|
|
47164
47201
|
auto: false,
|
|
47165
47202
|
source: "github",
|
|
47166
|
-
message: `kxm ${current} (running from source)`
|
|
47203
|
+
message: `kxm ${current ?? "unknown"} (running from source)`
|
|
47167
47204
|
};
|
|
47168
47205
|
} else {
|
|
47169
47206
|
try {
|
|
47170
|
-
notice = await refreshKxmUpdateNotice(runtime);
|
|
47207
|
+
notice = await refreshKxmUpdateNotice(runtime, void 0, current);
|
|
47171
47208
|
} catch (error) {
|
|
47172
47209
|
if (error instanceof KxmUpdateConfigError) {
|
|
47173
47210
|
print(runtime.io, runtime.json, { ok: false, command: "update", error: error.code, ...installKindPayload(classified) }, error.message);
|
|
@@ -16238,7 +16238,7 @@ import { dirname as dirname5, join as join5 } from "node:path";
|
|
|
16238
16238
|
import { fileURLToPath } from "node:url";
|
|
16239
16239
|
var ROOT_MARKERS = ["scripts/kxm-hub.mjs", "scripts/kxm.mjs"];
|
|
16240
16240
|
var MAX_WALK_DEPTH = 10;
|
|
16241
|
-
function
|
|
16241
|
+
function tryFindKxmRepoRoot(fromUrl = import.meta.url) {
|
|
16242
16242
|
let dir = dirname5(fileURLToPath(fromUrl));
|
|
16243
16243
|
for (let depth = 0; depth < MAX_WALK_DEPTH; depth += 1) {
|
|
16244
16244
|
if (ROOT_MARKERS.some((marker) => existsSync5(join5(dir, marker)))) return dir;
|
|
@@ -16246,6 +16246,11 @@ function findKxmRepoRoot(fromUrl = import.meta.url) {
|
|
|
16246
16246
|
if (parent === dir) break;
|
|
16247
16247
|
dir = parent;
|
|
16248
16248
|
}
|
|
16249
|
+
return void 0;
|
|
16250
|
+
}
|
|
16251
|
+
function findKxmRepoRoot(fromUrl = import.meta.url) {
|
|
16252
|
+
const found = tryFindKxmRepoRoot(fromUrl);
|
|
16253
|
+
if (found !== void 0) return found;
|
|
16249
16254
|
throw new Error(
|
|
16250
16255
|
`kxm: cannot locate the KXM repo root from ${fileURLToPath(fromUrl)} (walked ${MAX_WALK_DEPTH} levels looking for ${ROOT_MARKERS[0]})`
|
|
16251
16256
|
);
|
|
@@ -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.
|
|
17185
|
+
var VERSION = "0.7.84";
|
|
17186
17186
|
var inbox = /* @__PURE__ */ new Map();
|
|
17187
17187
|
var notifiedInbox = /* @__PURE__ */ new Set();
|
|
17188
17188
|
var meshClient;
|
|
@@ -14791,7 +14791,7 @@ import { dirname, join } from "node:path";
|
|
|
14791
14791
|
import { fileURLToPath } from "node:url";
|
|
14792
14792
|
var ROOT_MARKERS = ["scripts/kxm-hub.mjs", "scripts/kxm.mjs"];
|
|
14793
14793
|
var MAX_WALK_DEPTH = 10;
|
|
14794
|
-
function
|
|
14794
|
+
function tryFindKxmRepoRoot(fromUrl = import.meta.url) {
|
|
14795
14795
|
let dir = dirname(fileURLToPath(fromUrl));
|
|
14796
14796
|
for (let depth = 0; depth < MAX_WALK_DEPTH; depth += 1) {
|
|
14797
14797
|
if (ROOT_MARKERS.some((marker) => existsSync(join(dir, marker)))) return dir;
|
|
@@ -14799,6 +14799,11 @@ function findKxmRepoRoot(fromUrl = import.meta.url) {
|
|
|
14799
14799
|
if (parent === dir) break;
|
|
14800
14800
|
dir = parent;
|
|
14801
14801
|
}
|
|
14802
|
+
return void 0;
|
|
14803
|
+
}
|
|
14804
|
+
function findKxmRepoRoot(fromUrl = import.meta.url) {
|
|
14805
|
+
const found = tryFindKxmRepoRoot(fromUrl);
|
|
14806
|
+
if (found !== void 0) return found;
|
|
14802
14807
|
throw new Error(
|
|
14803
14808
|
`kxm: cannot locate the KXM repo root from ${fileURLToPath(fromUrl)} (walked ${MAX_WALK_DEPTH} levels looking for ${ROOT_MARKERS[0]})`
|
|
14804
14809
|
);
|
|
@@ -15119,7 +15119,7 @@ import { dirname, join } from "node:path";
|
|
|
15119
15119
|
import { fileURLToPath } from "node:url";
|
|
15120
15120
|
var ROOT_MARKERS = ["scripts/kxm-hub.mjs", "scripts/kxm.mjs"];
|
|
15121
15121
|
var MAX_WALK_DEPTH = 10;
|
|
15122
|
-
function
|
|
15122
|
+
function tryFindKxmRepoRoot(fromUrl = import.meta.url) {
|
|
15123
15123
|
let dir = dirname(fileURLToPath(fromUrl));
|
|
15124
15124
|
for (let depth = 0; depth < MAX_WALK_DEPTH; depth += 1) {
|
|
15125
15125
|
if (ROOT_MARKERS.some((marker) => existsSync(join(dir, marker)))) return dir;
|
|
@@ -15127,6 +15127,11 @@ function findKxmRepoRoot(fromUrl = import.meta.url) {
|
|
|
15127
15127
|
if (parent === dir) break;
|
|
15128
15128
|
dir = parent;
|
|
15129
15129
|
}
|
|
15130
|
+
return void 0;
|
|
15131
|
+
}
|
|
15132
|
+
function findKxmRepoRoot(fromUrl = import.meta.url) {
|
|
15133
|
+
const found = tryFindKxmRepoRoot(fromUrl);
|
|
15134
|
+
if (found !== void 0) return found;
|
|
15130
15135
|
throw new Error(
|
|
15131
15136
|
`kxm: cannot locate the KXM repo root from ${fileURLToPath(fromUrl)} (walked ${MAX_WALK_DEPTH} levels looking for ${ROOT_MARKERS[0]})`
|
|
15132
15137
|
);
|
|
@@ -14943,7 +14943,7 @@ import { dirname, join } from "node:path";
|
|
|
14943
14943
|
import { fileURLToPath } from "node:url";
|
|
14944
14944
|
var ROOT_MARKERS = ["scripts/kxm-hub.mjs", "scripts/kxm.mjs"];
|
|
14945
14945
|
var MAX_WALK_DEPTH = 10;
|
|
14946
|
-
function
|
|
14946
|
+
function tryFindKxmRepoRoot(fromUrl = import.meta.url) {
|
|
14947
14947
|
let dir = dirname(fileURLToPath(fromUrl));
|
|
14948
14948
|
for (let depth = 0; depth < MAX_WALK_DEPTH; depth += 1) {
|
|
14949
14949
|
if (ROOT_MARKERS.some((marker) => existsSync(join(dir, marker)))) return dir;
|
|
@@ -14951,6 +14951,11 @@ function findKxmRepoRoot(fromUrl = import.meta.url) {
|
|
|
14951
14951
|
if (parent === dir) break;
|
|
14952
14952
|
dir = parent;
|
|
14953
14953
|
}
|
|
14954
|
+
return void 0;
|
|
14955
|
+
}
|
|
14956
|
+
function findKxmRepoRoot(fromUrl = import.meta.url) {
|
|
14957
|
+
const found = tryFindKxmRepoRoot(fromUrl);
|
|
14958
|
+
if (found !== void 0) return found;
|
|
14954
14959
|
throw new Error(
|
|
14955
14960
|
`kxm: cannot locate the KXM repo root from ${fileURLToPath(fromUrl)} (walked ${MAX_WALK_DEPTH} levels looking for ${ROOT_MARKERS[0]})`
|
|
14956
14961
|
);
|
package/plugins/kxm/package.json
CHANGED
|
@@ -73,9 +73,18 @@ export async function hubGet(url: string, fetchImpl: typeof fetch): Promise<{ ok
|
|
|
73
73
|
|
|
74
74
|
export function installProbeFrom(runtime: Runtime): InstallProbe {
|
|
75
75
|
const partial = runtime.io.installProbe ?? {};
|
|
76
|
+
const moduleDir = partial.moduleDir ?? dirname(fileURLToPath(import.meta.url));
|
|
76
77
|
return {
|
|
77
|
-
moduleDir
|
|
78
|
-
|
|
78
|
+
moduleDir,
|
|
79
|
+
// Classify the install that is **running**, never the directory the caller
|
|
80
|
+
// happens to be standing in. Deriving this from cwd made `kxm update --kxm`
|
|
81
|
+
// answer "kxm is running from source at <cwd>; update it with git pull there"
|
|
82
|
+
// on an npm-global install whenever the operator ran it inside a kxm
|
|
83
|
+
// checkout — and a git pull there deploys nothing, because the services exec
|
|
84
|
+
// the installed copy. An unrecognisable layout falls back to the module
|
|
85
|
+
// directory, which classifies as `unknown` ("update it the way it was
|
|
86
|
+
// installed") rather than inventing a source install.
|
|
87
|
+
repoRoot: partial.repoRoot ?? tryFindKxmRepoRoot(import.meta.url) ?? moduleDir,
|
|
79
88
|
homeDir: partial.homeDir ?? homedir(),
|
|
80
89
|
platform: partial.platform ?? process.platform,
|
|
81
90
|
env: partial.env ?? runtime.env,
|
|
@@ -84,6 +93,17 @@ export function installProbeFrom(runtime: Runtime): InstallProbe {
|
|
|
84
93
|
|
|
85
94
|
import { fileURLToPath } from "node:url";
|
|
86
95
|
import { dirname } from "node:path";
|
|
96
|
+
import { findKxmRepoRoot, tryFindKxmRepoRoot } from "../repo-root.ts";
|
|
97
|
+
import { installedKxmVersion } from "../kxm-update.ts";
|
|
98
|
+
|
|
99
|
+
/** The install root derived from the loaded module; `unknown` never crashes a caller. */
|
|
100
|
+
function moduleInstallRoot(): string {
|
|
101
|
+
try {
|
|
102
|
+
return findKxmRepoRoot(import.meta.url);
|
|
103
|
+
} catch {
|
|
104
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
87
107
|
import { homedir } from "node:os";
|
|
88
108
|
|
|
89
109
|
export function warnIgnoredProjectUpdateYaml(runtime: Runtime): void {
|
|
@@ -93,11 +113,33 @@ export function warnIgnoredProjectUpdateYaml(runtime: Runtime): void {
|
|
|
93
113
|
runtime.io.stderr(`kxm: ignoring .kxm/update.yaml in ${runtime.dirs.workdir}; update settings are read only from ${userFile}\n`);
|
|
94
114
|
}
|
|
95
115
|
|
|
96
|
-
export async function refreshKxmUpdateNotice(
|
|
116
|
+
export async function refreshKxmUpdateNotice(
|
|
117
|
+
runtime: Runtime,
|
|
118
|
+
config?: KxmUpdateConfig,
|
|
119
|
+
current?: string,
|
|
120
|
+
): Promise<KxmUpdateNotice> {
|
|
97
121
|
const resolved = config ?? loadKxmUpdateConfig(runtime.env);
|
|
98
|
-
|
|
122
|
+
// The version being compared is the one **running**, taken from the install
|
|
123
|
+
// root. Reading it from the caller's directory made `cd ~ && kxm update --kxm`
|
|
124
|
+
// die with a raw ENOENT on `$HOME/package.json` — and silently compared a
|
|
125
|
+
// stranger's version wherever the operator happened to stand and a
|
|
126
|
+
// package.json did exist. Callers that already resolved it pass it in.
|
|
127
|
+
const installed = current
|
|
128
|
+
?? installedKxmVersion(findKxmRepoRoot(import.meta.url))
|
|
129
|
+
?? installedKxmVersion(moduleInstallRoot());
|
|
130
|
+
if (installed === undefined) {
|
|
131
|
+
// No version to compare against: say nothing rather than crash a hub start
|
|
132
|
+
// over an update notice.
|
|
133
|
+
return {
|
|
134
|
+
current: "unknown",
|
|
135
|
+
available: false,
|
|
136
|
+
auto: false,
|
|
137
|
+
source: resolved.source,
|
|
138
|
+
message: `kxm update check skipped: the installed version is unreadable at ${moduleInstallRoot()}`,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
99
141
|
const fetched = await fetchLatestKxmVersion(resolved.source, runtime.env, runtime.fetchImpl);
|
|
100
|
-
const notice = noticeFromVersions(
|
|
142
|
+
const notice = noticeFromVersions(installed, fetched.latest, resolved, fetched.error, fetched.asset);
|
|
101
143
|
writeUpdateCache(runtime.dirs.state, notice);
|
|
102
144
|
return notice;
|
|
103
145
|
}
|
|
@@ -63,6 +63,7 @@ import {
|
|
|
63
63
|
type InstallProbe,
|
|
64
64
|
} from "../kxm-install-kind.ts";
|
|
65
65
|
import {
|
|
66
|
+
installedKxmVersion,
|
|
66
67
|
fetchLatestKxmVersion,
|
|
67
68
|
kxmReleaseAssetName,
|
|
68
69
|
noticeFromVersions,
|
|
@@ -296,16 +297,22 @@ export async function cmdUpdate(runtime: Runtime, harness: string | undefined, o
|
|
|
296
297
|
warnIgnoredProjectUpdateYaml(runtime);
|
|
297
298
|
const probe = installProbeFrom(runtime);
|
|
298
299
|
const classified = classifyInstallRoot(probe);
|
|
299
|
-
|
|
300
|
+
// The version of the install being updated, taken from the root that was just
|
|
301
|
+
// classified — not from whichever directory the operator stood in. A
|
|
302
|
+
// `readInstalledKxmVersion(resolve("."))` in the notice path turned
|
|
303
|
+
// `cd ~ && kxm update --kxm` into an uncaught ENOENT on `$HOME/package.json`,
|
|
304
|
+
// and would happily compare a stranger project's version wherever one did
|
|
305
|
+
// exist. Unreadable is now a stated refusal.
|
|
306
|
+
const current = installedKxmVersion(classified.root) ?? installedKxmVersion(findKxmRepoRoot(import.meta.url));
|
|
300
307
|
let notice: KxmUpdateNotice;
|
|
301
308
|
let kindReport = classified;
|
|
302
309
|
if (classified.kind === "source") {
|
|
303
310
|
if (options.check) {
|
|
304
|
-
const message = `kxm ${current} (running from source at ${classified.root})`;
|
|
311
|
+
const message = `kxm ${current ?? "unknown"} (running from source at ${classified.root})`;
|
|
305
312
|
print(runtime.io, runtime.json, {
|
|
306
313
|
ok: true,
|
|
307
314
|
command: "update check",
|
|
308
|
-
current,
|
|
315
|
+
current: current ?? "unknown",
|
|
309
316
|
available: false,
|
|
310
317
|
auto: false,
|
|
311
318
|
source: "github",
|
|
@@ -327,15 +334,15 @@ export async function cmdUpdate(runtime: Runtime, harness: string | undefined, o
|
|
|
327
334
|
return 2;
|
|
328
335
|
}
|
|
329
336
|
notice = {
|
|
330
|
-
current,
|
|
337
|
+
current: current ?? "unknown",
|
|
331
338
|
available: false,
|
|
332
339
|
auto: false,
|
|
333
340
|
source: "github",
|
|
334
|
-
message: `kxm ${current} (running from source)`,
|
|
341
|
+
message: `kxm ${current ?? "unknown"} (running from source)`,
|
|
335
342
|
};
|
|
336
343
|
} else {
|
|
337
344
|
try {
|
|
338
|
-
notice = await refreshKxmUpdateNotice(runtime);
|
|
345
|
+
notice = await refreshKxmUpdateNotice(runtime, undefined, current);
|
|
339
346
|
} catch (error) {
|
|
340
347
|
if (error instanceof KxmUpdateConfigError) {
|
|
341
348
|
print(runtime.io, runtime.json, { ok: false, command: "update", error: error.code, ...installKindPayload(classified) }, error.message);
|
|
@@ -51,6 +51,21 @@ export function readInstalledKxmVersion(root: string): string {
|
|
|
51
51
|
return pkg.version;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* `readInstalledKxmVersion` without the raw filesystem failure. The installed
|
|
56
|
+
* version is read to decide whether a candidate is an upgrade, a downgrade or
|
|
57
|
+
* the same thing — so a directory that has no readable `package.json` must come
|
|
58
|
+
* back as "unknown" and be refused in words, not surface as an uncaught ENOENT
|
|
59
|
+
* stack from `kxm update`.
|
|
60
|
+
*/
|
|
61
|
+
export function installedKxmVersion(root: string): string | undefined {
|
|
62
|
+
try {
|
|
63
|
+
return readInstalledKxmVersion(root);
|
|
64
|
+
} catch {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
54
69
|
export function parseSemver(value: string): [number, number, number] | undefined {
|
|
55
70
|
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(value.trim());
|
|
56
71
|
if (!match) return undefined;
|
|
@@ -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.
|
|
11
|
+
const VERSION = "0.7.84";
|
|
12
12
|
const inbox = new Map<string, MessageRecord>();
|
|
13
13
|
const notifiedInbox = new Set<string>();
|
|
14
14
|
let meshClient: HubClient | undefined;
|
|
@@ -14,7 +14,12 @@ const MAX_WALK_DEPTH = 10;
|
|
|
14
14
|
* layout; marker discovery is correct in both, and in npm-installed
|
|
15
15
|
* layouts, which also ship `scripts/`.
|
|
16
16
|
*/
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* The repo/package root this module was loaded from, or `undefined` when the
|
|
19
|
+
* layout is not recognisable. For callers that must degrade to "cannot tell how
|
|
20
|
+
* it was installed" instead of throwing — install classification, mostly.
|
|
21
|
+
*/
|
|
22
|
+
export function tryFindKxmRepoRoot(fromUrl: string = import.meta.url): string | undefined {
|
|
18
23
|
let dir = dirname(fileURLToPath(fromUrl));
|
|
19
24
|
for (let depth = 0; depth < MAX_WALK_DEPTH; depth += 1) {
|
|
20
25
|
if (ROOT_MARKERS.some((marker) => existsSync(join(dir, marker)))) return dir;
|
|
@@ -22,6 +27,12 @@ export function findKxmRepoRoot(fromUrl: string = import.meta.url): string {
|
|
|
22
27
|
if (parent === dir) break;
|
|
23
28
|
dir = parent;
|
|
24
29
|
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function findKxmRepoRoot(fromUrl: string = import.meta.url): string {
|
|
34
|
+
const found = tryFindKxmRepoRoot(fromUrl);
|
|
35
|
+
if (found !== undefined) return found;
|
|
25
36
|
throw new Error(
|
|
26
37
|
`kxm: cannot locate the KXM repo root from ${fileURLToPath(fromUrl)} ` +
|
|
27
38
|
`(walked ${MAX_WALK_DEPTH} levels looking for ${ROOT_MARKERS[0]})`,
|