@kontextmind/kxm 0.7.19 → 0.7.21

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kxm-claude-plugin",
3
- "version": "0.7.19",
3
+ "version": "0.7.21",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "engines": {
@@ -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 { dirname, join, resolve } from "node:path";
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(repoRoot);
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 { fileURLToPath } from "node:url";
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(repoRoot, "scripts", scriptName)], {
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 { dirname, join, resolve } from "node:path";
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,
@@ -16,6 +16,7 @@ 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";
20
21
  import { defaultProjectName } from "./project-name.ts";
21
22
  import {
@@ -155,7 +156,6 @@ export type { CliIo, CliSpawnResult };
155
156
  export { hubContextPost };
156
157
 
157
158
  const CLI_NAME = "kxm";
158
- const repoRoot = resolve(fileURLToPath(new URL("../../../", import.meta.url)));
159
159
 
160
160
  const USAGE_ERROR_CODES = new Set([
161
161
  "commander.help",
@@ -321,7 +321,7 @@ function createProgram(ctx: CliContext, result: { code: number }): Command {
321
321
  const program = new Command(CLI_NAME);
322
322
  program
323
323
  .description("KontextMind local-first orchestration CLI")
324
- .version(readInstalledKxmVersion(repoRoot), "-V, --version", "Print the installed kxm version")
324
+ .version(readInstalledKxmVersion(findKxmRepoRoot(import.meta.url)), "-V, --version", "Print the installed kxm version")
325
325
  .exitOverride()
326
326
  .configureOutput({
327
327
  writeOut: (text) => ctx.io.stdout(text),
@@ -1,9 +1,9 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { closeSync, mkdirSync, openSync, readFileSync } from "node:fs";
3
- import { dirname, join, resolve } from "node:path";
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 next to the checked-out KXM repo. The extension and
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 resolve(dirname(fileURLToPath(moduleUrl)), "../../../scripts/kxm-hub.mjs");
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.19";
10
+ const VERSION = "0.7.21";
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
- const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../../..");
90
- const DEFAULT_SCHEMA_DIR = join(PACKAGE_ROOT, "schemas", "vnext");
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, resolve } from "node:path";
6
- import { fileURLToPath } from "node:url";
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(repoRoot, "scripts", "kxm-runtime-supervisor.mjs");
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,