@kontextmind/kxm 0.7.20 → 0.7.22
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 +958 -872
- package/plugins/kxm/dist/client.js +2 -2
- package/plugins/kxm/dist/extension.js +85 -67
- package/plugins/kxm/dist/mcp-server.js +3 -3
- package/plugins/kxm/dist/runtime.js +212 -194
- package/plugins/kxm/dist/server.js +46 -26
- package/plugins/kxm/dist/vnext-runtime-supervisor.js +155 -137
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/cli/system.ts +3 -4
- package/plugins/kxm/src/cli/types.ts +2 -4
- package/plugins/kxm/src/cli/vnext.ts +1 -4
- package/plugins/kxm/src/cli.ts +15 -3
- package/plugins/kxm/src/client.ts +4 -2
- package/plugins/kxm/src/hub-autostart.ts +4 -4
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/repo-root.ts +29 -0
- package/plugins/kxm/src/vnext-config.ts +5 -3
- package/plugins/kxm/src/vnext-runtime-supervisor.ts +3 -4
package/plugins/kxm/package.json
CHANGED
|
@@ -2,9 +2,8 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { homedir, tmpdir } from "node:os";
|
|
5
|
-
import {
|
|
5
|
+
import { join, resolve } from "node:path";
|
|
6
6
|
import { createInterface } from "node:readline";
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
7
|
import { verifyArtifactExists } from "../artifacts-exist.ts";
|
|
9
8
|
import { parseWorkflowDefinitions } from "../workflow.ts";
|
|
10
9
|
import { redactSecrets } from "../redact.ts";
|
|
@@ -99,8 +98,8 @@ import {
|
|
|
99
98
|
warnIgnoredProjectUpdateYaml,
|
|
100
99
|
refreshKxmUpdateNotice,
|
|
101
100
|
} from "./hub.ts";
|
|
101
|
+
import { findKxmRepoRoot } from "../repo-root.ts";
|
|
102
102
|
|
|
103
|
-
const repoRoot = resolve(fileURLToPath(new URL("../../../../", import.meta.url)));
|
|
104
103
|
|
|
105
104
|
export function cliSpawn(runtime: Runtime, command: string, args: readonly string[], extra?: { timeout?: number }): CliSpawnResult {
|
|
106
105
|
if (runtime.io.spawnSync) return runtime.io.spawnSync(command, args);
|
|
@@ -297,7 +296,7 @@ export async function cmdUpdate(runtime: Runtime, harness: string | undefined, o
|
|
|
297
296
|
warnIgnoredProjectUpdateYaml(runtime);
|
|
298
297
|
const probe = installProbeFrom(runtime);
|
|
299
298
|
const classified = classifyInstallRoot(probe);
|
|
300
|
-
const current = readInstalledKxmVersion(
|
|
299
|
+
const current = readInstalledKxmVersion(findKxmRepoRoot(import.meta.url));
|
|
301
300
|
let notice: KxmUpdateNotice;
|
|
302
301
|
let kindReport = classified;
|
|
303
302
|
if (classified.kind === "source") {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { findKxmRepoRoot } from "../repo-root.ts";
|
|
4
4
|
import type { Command } from "commander";
|
|
5
5
|
import { redactSecrets } from "../redact.ts";
|
|
6
6
|
import { appendTelemetry, inferImprovementTarget, makeTelemetryEvent, telemetryPath } from "../telemetry.ts";
|
|
@@ -61,11 +61,9 @@ export interface Runtime extends CliContext, Required<Pick<GlobalOpts, "json" |
|
|
|
61
61
|
fetchImpl: typeof fetch;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
const repoRoot = resolve(fileURLToPath(new URL("../../../../", import.meta.url)));
|
|
65
|
-
|
|
66
64
|
export function spawnScript(scriptName: string, extraEnv: NodeJS.ProcessEnv = {}): Promise<number> {
|
|
67
65
|
return new Promise((resolveExit) => {
|
|
68
|
-
const child = spawn(process.execPath, [join(
|
|
66
|
+
const child = spawn(process.execPath, [join(findKxmRepoRoot(import.meta.url), "scripts", scriptName)], {
|
|
69
67
|
stdio: "inherit",
|
|
70
68
|
env: { ...process.env, ...extraEnv },
|
|
71
69
|
});
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
3
3
|
import { homedir, tmpdir } from "node:os";
|
|
4
|
-
import {
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
5
|
import { createInterface } from "node:readline";
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
7
6
|
import { createBackup, restoreBackup } from "../database.ts";
|
|
8
7
|
import { refreshModelInventory } from "../model-inventory.ts";
|
|
9
8
|
import { listInventoryModels, listRoleBindings, loadProducerPolicy, setModelState, updateProducer } from "../producers.ts";
|
|
@@ -48,8 +47,6 @@ export const vnextDriveCliSeams: {
|
|
|
48
47
|
runtimeRequest?: typeof vnextRuntimeRequest;
|
|
49
48
|
} = {};
|
|
50
49
|
|
|
51
|
-
const repoRoot = resolve(fileURLToPath(new URL("../../../../", import.meta.url)));
|
|
52
|
-
|
|
53
50
|
export function initPlanPayload(plan: VnextInitializationPlan): Record<string, unknown> {
|
|
54
51
|
return {
|
|
55
52
|
mode: plan.mode,
|
package/plugins/kxm/src/cli.ts
CHANGED
|
@@ -16,7 +16,9 @@ import { dirname, join, resolve } from "node:path";
|
|
|
16
16
|
import { fileURLToPath } from "node:url";
|
|
17
17
|
import { Command, CommanderError } from "commander";
|
|
18
18
|
import { readInstalledKxmVersion } from "./kxm-update.ts";
|
|
19
|
+
import { findKxmRepoRoot } from "./repo-root.ts";
|
|
19
20
|
import { HubClient } from "./client.ts";
|
|
21
|
+
import { readHubEnvRecord } from "./hub-env.ts";
|
|
20
22
|
import { defaultProjectName } from "./project-name.ts";
|
|
21
23
|
import {
|
|
22
24
|
AGENT_COMMANDS_MAP,
|
|
@@ -155,7 +157,16 @@ export type { CliIo, CliSpawnResult };
|
|
|
155
157
|
export { hubContextPost };
|
|
156
158
|
|
|
157
159
|
const CLI_NAME = "kxm";
|
|
158
|
-
|
|
160
|
+
|
|
161
|
+
/** Authenticate CLI hub clients: explicit KXM_AUTH_TOKEN first, then the
|
|
162
|
+
* persisted hub env record (project token for this project, then the admin
|
|
163
|
+
* token), matching the credential precedence `kxm hub start` prints. */
|
|
164
|
+
function resolveCliAuthToken(runtime: Runtime, project: string): string | undefined {
|
|
165
|
+
const envToken = runtime.env.KXM_AUTH_TOKEN?.trim();
|
|
166
|
+
if (envToken) return envToken;
|
|
167
|
+
const record = readHubEnvRecord(runtime.env);
|
|
168
|
+
return record?.projectTokens?.[project]?.trim() || record?.authToken?.trim() || undefined;
|
|
169
|
+
}
|
|
159
170
|
|
|
160
171
|
const USAGE_ERROR_CODES = new Set([
|
|
161
172
|
"commander.help",
|
|
@@ -183,12 +194,13 @@ async function ensureCliClient(runtime: Runtime): Promise<HubClient> {
|
|
|
183
194
|
const project = defaultProjectName(runtime.cwd, runtime.env);
|
|
184
195
|
const name = runtime.env.KXM_AGENT_NAME?.trim() || `cli-${process.pid}`;
|
|
185
196
|
const purpose = runtime.env.KXM_AGENT_PURPOSE?.trim() || "CLI agent client";
|
|
186
|
-
const authToken = runtime
|
|
197
|
+
const authToken = resolveCliAuthToken(runtime, project);
|
|
187
198
|
const client = new HubClient({
|
|
188
199
|
serverUrl,
|
|
189
200
|
name,
|
|
190
201
|
project,
|
|
191
202
|
purpose,
|
|
203
|
+
fetchImpl: runtime.fetchImpl,
|
|
192
204
|
...(authToken ? { authToken } : {}),
|
|
193
205
|
});
|
|
194
206
|
await client.start(() => {});
|
|
@@ -321,7 +333,7 @@ function createProgram(ctx: CliContext, result: { code: number }): Command {
|
|
|
321
333
|
const program = new Command(CLI_NAME);
|
|
322
334
|
program
|
|
323
335
|
.description("KontextMind local-first orchestration CLI")
|
|
324
|
-
.version(readInstalledKxmVersion(
|
|
336
|
+
.version(readInstalledKxmVersion(findKxmRepoRoot(import.meta.url)), "-V, --version", "Print the installed kxm version")
|
|
325
337
|
.exitOverride()
|
|
326
338
|
.configureOutput({
|
|
327
339
|
writeOut: (text) => ctx.io.stdout(text),
|
|
@@ -55,6 +55,8 @@ export interface HubClientOptions {
|
|
|
55
55
|
heartbeatMs?: number;
|
|
56
56
|
reconnectMs?: number;
|
|
57
57
|
requestTimeoutMs?: number;
|
|
58
|
+
/** Injectable fetch for CLI/tests; defaults to global fetch. */
|
|
59
|
+
fetchImpl?: typeof fetch;
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
export interface SendOptions {
|
|
@@ -493,7 +495,7 @@ export class HubClient {
|
|
|
493
495
|
while (!this.stopped && this.agent) {
|
|
494
496
|
this.eventsAbort = new AbortController();
|
|
495
497
|
try {
|
|
496
|
-
const response = await fetch(
|
|
498
|
+
const response = await (this.options.fetchImpl ?? fetch)(
|
|
497
499
|
`${this.options.serverUrl.replace(/\/$/, "")}/v1/events?agentId=${encodeURIComponent(this.agent.id)}`,
|
|
498
500
|
{
|
|
499
501
|
headers: this.headers(),
|
|
@@ -578,7 +580,7 @@ export class HubClient {
|
|
|
578
580
|
const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
|
|
579
581
|
let response: Response;
|
|
580
582
|
try {
|
|
581
|
-
response = await fetch(`${this.options.serverUrl.replace(/\/$/, "")}${path}`, {
|
|
583
|
+
response = await (this.options.fetchImpl ?? fetch)(`${this.options.serverUrl.replace(/\/$/, "")}${path}`, {
|
|
582
584
|
...init,
|
|
583
585
|
signal,
|
|
584
586
|
headers: { ...this.headers(includeIdentity), ...(init.headers ?? {}) },
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { closeSync, mkdirSync, openSync, readFileSync } from "node:fs";
|
|
3
|
-
import {
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
5
4
|
import { probeHubHealth, readHubBinding } from "./hub-binding.ts";
|
|
6
5
|
import { resolveHubCredentials } from "./hub-env.ts";
|
|
6
|
+
import { findKxmRepoRoot } from "./repo-root.ts";
|
|
7
7
|
import { redactSecrets } from "./redact.ts";
|
|
8
8
|
|
|
9
9
|
/** Background hub auto-start for harness extensions (Pi TUI, one-shot CLIs).
|
|
@@ -99,11 +99,11 @@ export function readLiveHubClaim(stateDir: string, processExists: (pid: number)
|
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
/** The hub wrapper script
|
|
102
|
+
/** The hub wrapper script at the KXM repo/package root. The extension and
|
|
103
103
|
* the CLI both resolve the same path so auto-start launches the identical
|
|
104
104
|
* supervision wrapper as `kxm hub start`. */
|
|
105
105
|
export function defaultHubWrapperScriptPath(moduleUrl: string = import.meta.url): string {
|
|
106
|
-
return
|
|
106
|
+
return join(findKxmRepoRoot(moduleUrl), "scripts", "kxm-hub.mjs");
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
function defaultHubSpawner(command: string, args: readonly string[], options: HubSpawnOptions): HubSpawned {
|
|
@@ -7,7 +7,7 @@ import { AGENT_COMMANDS_MAP, enforceToolPolicy, getMcpTools, reconcileInbox } fr
|
|
|
7
7
|
import { deliverInboxNotification } from "./inbox.ts";
|
|
8
8
|
import type { HubEvent, MessageRecord } from "./protocol.ts";
|
|
9
9
|
|
|
10
|
-
const VERSION = "0.7.
|
|
10
|
+
const VERSION = "0.7.22";
|
|
11
11
|
const inbox = new Map<string, MessageRecord>();
|
|
12
12
|
const notifiedInbox = new Set<string>();
|
|
13
13
|
let meshClient: HubClient | undefined;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
/** Files that only exist at the KXM repo/package root. */
|
|
6
|
+
const ROOT_MARKERS = ["scripts/kxm-hub.mjs", "scripts/kxm.mjs"] as const;
|
|
7
|
+
const MAX_WALK_DEPTH = 10;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Locate the KXM repo/package root by walking up from `fromUrl` until a
|
|
11
|
+
* directory contains a root marker. Fixed-depth `../..` resolution breaks
|
|
12
|
+
* because the same module runs from both the source tree
|
|
13
|
+
* (`plugins/kxm/src/...`) and the flat bundled `plugins/kxm/dist/...`
|
|
14
|
+
* layout; marker discovery is correct in both, and in npm-installed
|
|
15
|
+
* layouts, which also ship `scripts/`.
|
|
16
|
+
*/
|
|
17
|
+
export function findKxmRepoRoot(fromUrl: string = import.meta.url): string {
|
|
18
|
+
let dir = dirname(fileURLToPath(fromUrl));
|
|
19
|
+
for (let depth = 0; depth < MAX_WALK_DEPTH; depth += 1) {
|
|
20
|
+
if (ROOT_MARKERS.some((marker) => existsSync(join(dir, marker)))) return dir;
|
|
21
|
+
const parent = dirname(dir);
|
|
22
|
+
if (parent === dir) break;
|
|
23
|
+
dir = parent;
|
|
24
|
+
}
|
|
25
|
+
throw new Error(
|
|
26
|
+
`kxm: cannot locate the KXM repo root from ${fileURLToPath(fromUrl)} ` +
|
|
27
|
+
`(walked ${MAX_WALK_DEPTH} levels looking for ${ROOT_MARKERS[0]})`,
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -2,7 +2,6 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { existsSync, lstatSync, readFileSync, readdirSync, realpathSync } from "node:fs";
|
|
4
4
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
5
|
import { Ajv2020, type ErrorObject, type ValidateFunction } from "ajv/dist/2020.js";
|
|
7
6
|
import {
|
|
8
7
|
RestrictedYamlError,
|
|
@@ -11,6 +10,7 @@ import {
|
|
|
11
10
|
type VnextYamlLimits,
|
|
12
11
|
} from "./restricted-yaml.mjs";
|
|
13
12
|
import { resolveVnextTemplateBaseline } from "./vnext-template.ts";
|
|
13
|
+
import { findKxmRepoRoot } from "./repo-root.ts";
|
|
14
14
|
import { BUILTIN_HARNESS_IDS, DEFAULT_HARNESS, validateHarnessModelPair } from "./vnext-harness.ts";
|
|
15
15
|
|
|
16
16
|
export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue };
|
|
@@ -86,8 +86,10 @@ export interface VnextInitializationPlan {
|
|
|
86
86
|
configRevision?: string;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
function defaultVnextSchemaDir(): string {
|
|
90
|
+
return join(findKxmRepoRoot(import.meta.url), "schemas", "vnext");
|
|
91
|
+
}
|
|
92
|
+
const DEFAULT_SCHEMA_DIR = defaultVnextSchemaDir();
|
|
91
93
|
const RESOURCE_SCHEMA: Readonly<Record<VnextResourceKind, { identity: string; file: string }>> = Object.freeze({
|
|
92
94
|
project: { identity: "kxm.project.v1", file: "project.schema.json" },
|
|
93
95
|
repository: { identity: "kxm.repository.v1", file: "repository.schema.json" },
|
|
@@ -2,10 +2,9 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { createHash, createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
3
3
|
import { chmodSync, existsSync, lstatSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { createServer, type IncomingMessage, type Server, type ServerResponse } from "node:http";
|
|
5
|
-
import { dirname, isAbsolute, join
|
|
6
|
-
import {
|
|
5
|
+
import { dirname, isAbsolute, join } from "node:path";
|
|
6
|
+
import { findKxmRepoRoot } from "./repo-root.ts";
|
|
7
7
|
import { loadVnextProject, VnextConfigError, type VnextConfigOptions } from "./vnext-config.ts";
|
|
8
|
-
const repoRoot = resolve(fileURLToPath(new URL("../../../", import.meta.url)));
|
|
9
8
|
import {
|
|
10
9
|
VnextRuntimeRegistry,
|
|
11
10
|
projectRuntimeKey,
|
|
@@ -201,7 +200,7 @@ export async function ensureVnextSupervisor(
|
|
|
201
200
|
|
|
202
201
|
// Auto-start: claim the singleton, spawn detached, wait for readiness.
|
|
203
202
|
clearSupervisorError(paths);
|
|
204
|
-
const scriptPath = join(
|
|
203
|
+
const scriptPath = join(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
|
|
205
204
|
const spawnImpl = options.spawnImpl ?? ((script: string, env: NodeJS.ProcessEnv): number => {
|
|
206
205
|
const child = spawn(process.execPath, [script], {
|
|
207
206
|
detached: true,
|