@kontextmind/kxm 0.7.167 → 0.7.169

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.
Files changed (35) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +30 -0
  3. package/docs/contributing/ci-and-release.md +6 -1
  4. package/docs/operations/runtime-sync.md +2 -1
  5. package/docs/operations/troubleshooting.md +4 -0
  6. package/docs/operations/upgrade.md +18 -3
  7. package/docs/operations.md +70 -7
  8. package/docs/reference/cli-reference.md +21 -6
  9. package/docs/reference/config-reference.md +28 -13
  10. package/docs/start/install.md +1 -1
  11. package/package.json +1 -1
  12. package/plugins/kxm/.claude-plugin/plugin.json +1 -1
  13. package/plugins/kxm/dist/claude-hook.js +170 -36
  14. package/plugins/kxm/dist/cli.js +451 -132
  15. package/plugins/kxm/dist/extension.js +184 -53
  16. package/plugins/kxm/dist/mcp-server.js +97 -40
  17. package/plugins/kxm/dist/runtime-supervisor.js +240 -47
  18. package/plugins/kxm/dist/runtime.js +240 -47
  19. package/plugins/kxm/dist/server.js +9 -0
  20. package/plugins/kxm/package.json +1 -1
  21. package/plugins/kxm/skills/kxm-definitions/SKILL.md +3 -2
  22. package/plugins/kxm/skills/kxm-harness-auth/SKILL.md +4 -2
  23. package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +9 -4
  24. package/plugins/kxm/src/cli/hub.ts +42 -7
  25. package/plugins/kxm/src/cli/system.ts +3 -1
  26. package/plugins/kxm/src/cli/types.ts +5 -3
  27. package/plugins/kxm/src/cli.ts +2 -1
  28. package/plugins/kxm/src/engine.ts +105 -8
  29. package/plugins/kxm/src/hub-binding.ts +301 -55
  30. package/plugins/kxm/src/hub-identity.ts +17 -9
  31. package/plugins/kxm/src/kxm-update.ts +29 -6
  32. package/plugins/kxm/src/mcp-server.ts +1 -1
  33. package/plugins/kxm/src/project-config.ts +63 -1
  34. package/plugins/kxm/src/runtime-supervisor.ts +22 -4
  35. package/scripts/kxm-publish-npm.mjs +47 -1
@@ -16349,6 +16349,9 @@ function resolveUserStateRoot(env) {
16349
16349
  function hubBindingFile(env = process.env) {
16350
16350
  return join3(resolveUserStateRoot(env), "hub-binding.json");
16351
16351
  }
16352
+ function hubBindingCloudFile(env = process.env) {
16353
+ return join3(resolveUserStateRoot(env), "hub-binding.cloud.json");
16354
+ }
16352
16355
  function validateHubUrl(raw) {
16353
16356
  let parsed;
16354
16357
  try {
@@ -16463,33 +16466,37 @@ function isAbortError(error2) {
16463
16466
  error2 && typeof error2 === "object" && ("name" in error2 && error2.name === "AbortError" || "code" in error2 && error2.code === "ABORT_ERR")
16464
16467
  );
16465
16468
  }
16466
- function readHubBinding(env = process.env) {
16467
- const file = hubBindingFile(env);
16468
- if (!existsSync3(file)) return void 0;
16469
+ var LEGACY_BINDING_KEYS = ["schema", "url", "boundAt"];
16470
+ var BINDING_KEYS = /* @__PURE__ */ new Set([...LEGACY_BINDING_KEYS, "cloud", "tokenEnv", "tokenCommand"]);
16471
+ function bindingFallbackWarning(file, reason) {
16472
+ return `hub binding at ${file} ${reason}; falling back to the local hub. Restart the Runtime supervisor, the hub, and workers after upgrading and before a cloud bind.`;
16473
+ }
16474
+ function writeBindingJson(file, value) {
16475
+ mkdirSync3(dirname3(file), { recursive: true, mode: 448 });
16476
+ const temporary = join3(dirname3(file), `.${file.endsWith("cloud.json") ? "hub-binding-cloud" : "hub-binding"}-${process.pid}.tmp`);
16477
+ try {
16478
+ writeFileSync3(temporary, `${JSON.stringify(value, null, 2)}
16479
+ `, { encoding: "utf8", mode: 384 });
16480
+ renameSync(temporary, file);
16481
+ } finally {
16482
+ rmSync(temporary, { force: true });
16483
+ }
16484
+ }
16485
+ function parseBindingObject(file) {
16486
+ if (!existsSync3(file)) return new HubBindingError(`missing hub binding at ${file}`);
16469
16487
  let parsed;
16470
16488
  try {
16471
16489
  parsed = JSON.parse(readFileSync3(file, "utf8"));
16472
16490
  } catch {
16473
- throw new HubBindingError(`malformed hub binding at ${file}`);
16491
+ return new HubBindingError(`malformed hub binding at ${file}`);
16474
16492
  }
16475
16493
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
16476
- throw new HubBindingError(`malformed hub binding at ${file}`);
16494
+ return new HubBindingError(`malformed hub binding at ${file}`);
16477
16495
  }
16478
- const row = parsed;
16479
- const keys = Object.keys(row);
16480
- const allowed = /* @__PURE__ */ new Set(["schema", "url", "boundAt", "cloud", "tokenEnv", "tokenCommand"]);
16481
- const cloudish = keys.some((key) => key === "cloud" || key === "tokenEnv" || key === "tokenCommand");
16482
- if (keys.some((key) => !allowed.has(key)) || !cloudish && keys.length !== 3 || row.schema !== HUB_BINDING_SCHEMA || typeof row.url !== "string" || typeof row.boundAt !== "string" || !isIsoTimestamp(row.boundAt)) {
16483
- throw new HubBindingError(`malformed hub binding at ${file}`);
16484
- }
16485
- let url;
16486
- try {
16487
- url = validateHubUrl(row.url);
16488
- } catch {
16489
- throw new HubBindingError(`malformed hub binding at ${file}`);
16490
- }
16491
- if (!cloudish) return { schema: HUB_BINDING_SCHEMA, url, boundAt: row.boundAt };
16492
- if (row.cloud !== true) throw new HubBindingError(`malformed hub binding at ${file}`);
16496
+ return parsed;
16497
+ }
16498
+ function cloudRecordFromRow(file, row, url, boundAt) {
16499
+ if (row.cloud !== true) return void 0;
16493
16500
  let tokenEnv;
16494
16501
  let tokenCommand;
16495
16502
  if (row.tokenEnv !== void 0) {
@@ -16511,31 +16518,158 @@ function readHubBinding(env = process.env) {
16511
16518
  return {
16512
16519
  schema: HUB_BINDING_SCHEMA,
16513
16520
  url,
16514
- boundAt: row.boundAt,
16521
+ boundAt,
16515
16522
  cloud: true,
16516
16523
  ...tokenEnv ? { tokenEnv } : {},
16517
16524
  ...tokenCommand ? { tokenCommand } : {}
16518
16525
  };
16519
16526
  }
16527
+ function interpretBindingFile(file) {
16528
+ if (!existsSync3(file)) return {};
16529
+ const parsed = parseBindingObject(file);
16530
+ if (parsed instanceof HubBindingError) throw parsed;
16531
+ const keys = Object.keys(parsed);
16532
+ const unknown2 = keys.filter((key) => !BINDING_KEYS.has(key));
16533
+ if (parsed.schema !== HUB_BINDING_SCHEMA || unknown2.length > 0) {
16534
+ return { warning: bindingFallbackWarning(file, `is newer than this build understands (${String(parsed.schema)})`) };
16535
+ }
16536
+ if (typeof parsed.url !== "string" || typeof parsed.boundAt !== "string" || !isIsoTimestamp(parsed.boundAt)) {
16537
+ throw new HubBindingError(`malformed hub binding at ${file}`);
16538
+ }
16539
+ let url;
16540
+ try {
16541
+ url = validateHubUrl(parsed.url);
16542
+ } catch {
16543
+ throw new HubBindingError(`malformed hub binding at ${file}`);
16544
+ }
16545
+ const cloudish = keys.some((key) => key === "cloud" || key === "tokenEnv" || key === "tokenCommand");
16546
+ if (!cloudish) {
16547
+ if (keys.length !== 3) throw new HubBindingError(`malformed hub binding at ${file}`);
16548
+ return { record: { schema: HUB_BINDING_SCHEMA, url, boundAt: parsed.boundAt } };
16549
+ }
16550
+ const record2 = cloudRecordFromRow(file, parsed, url, parsed.boundAt);
16551
+ if (!record2) throw new HubBindingError(`malformed hub binding at ${file}`);
16552
+ return { record: record2, legacyCloud: true };
16553
+ }
16554
+ function loadHubBinding(env = process.env) {
16555
+ const cloudFile = hubBindingCloudFile(env);
16556
+ const cloud = interpretBindingFile(cloudFile);
16557
+ if (cloud.warning && !cloud.record) {
16558
+ const local = existsSync3(hubBindingFile(env)) ? interpretBindingFile(hubBindingFile(env)) : {};
16559
+ if (local.record && !local.record.cloud) return { record: local.record, warning: cloud.warning };
16560
+ return { warning: cloud.warning };
16561
+ }
16562
+ if (cloud.record?.cloud) return { record: cloud.record, ...cloud.warning ? { warning: cloud.warning } : {} };
16563
+ const main = interpretBindingFile(hubBindingFile(env));
16564
+ if (main.legacyCloud && main.record) {
16565
+ writeBindingJson(cloudFile, main.record);
16566
+ rmSync(hubBindingFile(env), { force: true });
16567
+ return {
16568
+ record: main.record,
16569
+ warning: bindingFallbackWarning(
16570
+ hubBindingFile(env),
16571
+ "stored a cloud bind in the pre-0.7.160 file"
16572
+ )
16573
+ };
16574
+ }
16575
+ return { ...main.record ? { record: main.record } : {}, ...main.warning ? { warning: main.warning } : {} };
16576
+ }
16577
+ function readHubBinding(env = process.env) {
16578
+ return loadHubBinding(env).record;
16579
+ }
16580
+ function contentTypeBase(header) {
16581
+ return (header ?? "").split(";")[0].trim().toLowerCase();
16582
+ }
16583
+ function looksLikeHtml(contentType, body) {
16584
+ if (contentType === "text/html" || contentType === "application/xhtml+xml") return true;
16585
+ const sample = body.slice(0, 800).trim().toLowerCase();
16586
+ return sample.startsWith("<!doctype html") || sample.startsWith("<html") || sample.includes("<form") && (sample.includes("login") || sample.includes("authentik") || sample.includes("password"));
16587
+ }
16588
+ function jsonObject(text) {
16589
+ try {
16590
+ const parsed = JSON.parse(text);
16591
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
16592
+ return parsed;
16593
+ } catch {
16594
+ return void 0;
16595
+ }
16596
+ }
16597
+ function hubEndpointShape(role, body) {
16598
+ if (role === "health") return body.ok === true && typeof body.agents === "number";
16599
+ return body.ok === true && (body.storage === "sqlite" || body.storage === "memory");
16600
+ }
16601
+ function classifyHubResponse(input) {
16602
+ const contentType = contentTypeBase(input.contentType);
16603
+ if (input.status >= 300 && input.status < 400) {
16604
+ return {
16605
+ ok: false,
16606
+ status: input.status,
16607
+ kind: "redirect",
16608
+ detail: `HTTP ${input.status} redirect; this looks like an auth proxy or a redirect, not a kxm hub`,
16609
+ body: { error: "auth_proxy", detail: `HTTP ${input.status} redirect` }
16610
+ };
16611
+ }
16612
+ if (looksLikeHtml(contentType, input.bodyText)) {
16613
+ return {
16614
+ ok: false,
16615
+ status: input.status,
16616
+ kind: "auth_proxy",
16617
+ detail: `HTTP ${input.status} returned an HTML login page${contentType ? ` (${contentType})` : ""}; this looks like an auth proxy, not a kxm hub`,
16618
+ body: { error: "auth_proxy", detail: "HTML login page" }
16619
+ };
16620
+ }
16621
+ const jsonType = contentType === "application/json" || contentType === "text/plain" || contentType === "";
16622
+ const body = jsonType ? jsonObject(input.bodyText) : void 0;
16623
+ if (body && hubEndpointShape(input.role, body) && input.status >= 200 && input.status < 300) {
16624
+ if (contentType !== "" && contentType !== "application/json" && contentType !== "text/plain") {
16625
+ return {
16626
+ ok: false,
16627
+ status: input.status,
16628
+ kind: "not_hub",
16629
+ detail: `HTTP ${input.status} content-type ${contentType} is not application/json`,
16630
+ body: { error: "not_hub", detail: contentType }
16631
+ };
16632
+ }
16633
+ return { ok: true, status: input.status, kind: "hub", detail: "kxm hub", body };
16634
+ }
16635
+ const typeNote = contentType && contentType !== "application/json" ? ` content-type ${contentType}` : "";
16636
+ return {
16637
+ ok: false,
16638
+ status: input.status,
16639
+ kind: "not_hub",
16640
+ detail: `HTTP ${input.status}${typeNote} is not a kxm hub ${input.role} response`,
16641
+ body: { error: "not_hub", detail: `HTTP ${input.status}${typeNote}` }
16642
+ };
16643
+ }
16644
+ async function readHubEndpoint(url, role, fetchImpl, init = {}) {
16645
+ try {
16646
+ const response = await fetchImpl(`${url}/${role}`, {
16647
+ ...init.headers ? { headers: init.headers } : {},
16648
+ ...init.signal ? { signal: init.signal } : {},
16649
+ redirect: "manual"
16650
+ });
16651
+ const bodyText = await response.text();
16652
+ return classifyHubResponse({
16653
+ role,
16654
+ status: response.status,
16655
+ contentType: response.headers.get("content-type"),
16656
+ bodyText
16657
+ });
16658
+ } catch (error2) {
16659
+ if (isAbortError(error2)) {
16660
+ return { ok: false, status: 0, kind: "timeout", detail: "no reply within the probe budget", body: { error: "hub_unreachable" } };
16661
+ }
16662
+ return { ok: false, status: 0, kind: "unreachable", detail: "nothing answered", body: { error: "hub_unreachable" } };
16663
+ }
16664
+ }
16520
16665
  async function probeHubHealth(url, fetchImpl, timeoutMs = HUB_HEALTH_PROBE_MS) {
16521
16666
  const started = Date.now();
16522
16667
  const controller = new AbortController();
16523
16668
  const timer = setTimeout(() => controller.abort(), timeoutMs);
16524
16669
  try {
16525
- const response = await fetchImpl(`${url}/health`, { signal: controller.signal });
16526
- if (!response.ok) return { health: "unknown", probeMs: Date.now() - started };
16527
- let body;
16528
- try {
16529
- body = await response.json();
16530
- } catch {
16531
- return { health: "unknown", probeMs: Date.now() - started };
16532
- }
16533
- if (body && typeof body === "object" && body.ok === true) {
16534
- return { health: "on", probeMs: Date.now() - started };
16535
- }
16536
- return { health: "unknown", probeMs: Date.now() - started };
16537
- } catch (error2) {
16538
- return { health: isAbortError(error2) ? "unknown" : "off", probeMs: Date.now() - started };
16670
+ const verdict = await readHubEndpoint(url, "health", fetchImpl, { signal: controller.signal });
16671
+ const health = verdict.kind === "hub" ? "on" : verdict.kind === "unreachable" ? "off" : "unknown";
16672
+ return { health, probeMs: Date.now() - started, kind: verdict.kind, detail: verdict.detail, status: verdict.status };
16539
16673
  } finally {
16540
16674
  clearTimeout(timer);
16541
16675
  }
@@ -16610,15 +16744,6 @@ function resolveProjectIdentity(cwd, env = process.env, explicit) {
16610
16744
  if (fromPackage) return { project: fromPackage, source: "package.json", sourceLabel: "package.json name" };
16611
16745
  return { project: basename(cwd), source: "directory", sourceLabel: "directory name" };
16612
16746
  }
16613
- function opReferenceFromTokenCommand(command) {
16614
- try {
16615
- const args = splitTokenCommand(command);
16616
- if (args[0] === "op" && args[1] === "read" && args[2] && isHubOpReference(args[2])) return args[2];
16617
- } catch {
16618
- return void 0;
16619
- }
16620
- return void 0;
16621
- }
16622
16747
  function defaultOpRead(reference, env) {
16623
16748
  if (!isHubOpReference(reference)) {
16624
16749
  throw new CloudTokenError("cloud_token_command_invalid", `refusing to resolve ${reference}; an op:// reference is required`);
@@ -16663,18 +16788,24 @@ function resolveKeyReference(ref, env, opRead = defaultOpRead) {
16663
16788
  }
16664
16789
  function keySourceFor(input) {
16665
16790
  const ref = input.endpoint?.key;
16666
- if (input.mode === "local" && input.env.KXM_AUTH_TOKEN?.trim()) return "env:KXM_AUTH_TOKEN";
16667
- if (ref?.env && input.env[ref.env]?.trim()) return `env:${ref.env}`;
16668
- if (ref?.op) return `op:${ref.op}`;
16669
- if (ref?.env) return `env:${ref.env}`;
16791
+ const envName = (name) => {
16792
+ if (!name) return void 0;
16793
+ return input.env[name]?.trim() ? `env:${name}` : void 0;
16794
+ };
16670
16795
  if (input.mode === "cloud") {
16671
- if (input.binding?.tokenEnv) return `env:${input.binding.tokenEnv}`;
16672
- if (input.binding?.tokenCommand) {
16673
- const op = opReferenceFromTokenCommand(input.binding.tokenCommand);
16674
- return op ? `op:${op}` : "command";
16675
- }
16796
+ const fromEnv2 = envName(ref?.env);
16797
+ if (fromEnv2) return fromEnv2;
16798
+ if (ref?.op) return `op:${ref.op}`;
16799
+ const fromBindingEnv = envName(input.binding?.tokenEnv);
16800
+ if (fromBindingEnv) return fromBindingEnv;
16801
+ if (input.binding?.tokenCommand) return "token-command";
16676
16802
  return "missing";
16677
16803
  }
16804
+ const fromAuth = envName("KXM_AUTH_TOKEN");
16805
+ if (fromAuth) return fromAuth;
16806
+ const fromEnv = envName(ref?.env);
16807
+ if (fromEnv) return fromEnv;
16808
+ if (ref?.op) return `op:${ref.op}`;
16678
16809
  if (input.hasSavedProjectToken?.(input.project)) return "hub-env";
16679
16810
  return "missing";
16680
16811
  }
@@ -24015,6 +24015,9 @@ function resolveUserStateRoot(env) {
24015
24015
  function hubBindingFile(env = process.env) {
24016
24016
  return join2(resolveUserStateRoot(env), "hub-binding.json");
24017
24017
  }
24018
+ function hubBindingCloudFile(env = process.env) {
24019
+ return join2(resolveUserStateRoot(env), "hub-binding.cloud.json");
24020
+ }
24018
24021
  function validateHubUrl(raw) {
24019
24022
  let parsed;
24020
24023
  try {
@@ -24124,33 +24127,37 @@ function isIsoTimestamp(value) {
24124
24127
  if (Number.isNaN(Date.parse(value))) return false;
24125
24128
  return value === new Date(value).toISOString();
24126
24129
  }
24127
- function readHubBinding(env = process.env) {
24128
- const file = hubBindingFile(env);
24129
- if (!existsSync2(file)) return void 0;
24130
+ var LEGACY_BINDING_KEYS = ["schema", "url", "boundAt"];
24131
+ var BINDING_KEYS = /* @__PURE__ */ new Set([...LEGACY_BINDING_KEYS, "cloud", "tokenEnv", "tokenCommand"]);
24132
+ function bindingFallbackWarning(file, reason) {
24133
+ return `hub binding at ${file} ${reason}; falling back to the local hub. Restart the Runtime supervisor, the hub, and workers after upgrading and before a cloud bind.`;
24134
+ }
24135
+ function writeBindingJson(file, value) {
24136
+ mkdirSync2(dirname2(file), { recursive: true, mode: 448 });
24137
+ const temporary = join2(dirname2(file), `.${file.endsWith("cloud.json") ? "hub-binding-cloud" : "hub-binding"}-${process.pid}.tmp`);
24138
+ try {
24139
+ writeFileSync2(temporary, `${JSON.stringify(value, null, 2)}
24140
+ `, { encoding: "utf8", mode: 384 });
24141
+ renameSync(temporary, file);
24142
+ } finally {
24143
+ rmSync(temporary, { force: true });
24144
+ }
24145
+ }
24146
+ function parseBindingObject(file) {
24147
+ if (!existsSync2(file)) return new HubBindingError(`missing hub binding at ${file}`);
24130
24148
  let parsed;
24131
24149
  try {
24132
24150
  parsed = JSON.parse(readFileSync2(file, "utf8"));
24133
24151
  } catch {
24134
- throw new HubBindingError(`malformed hub binding at ${file}`);
24152
+ return new HubBindingError(`malformed hub binding at ${file}`);
24135
24153
  }
24136
24154
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
24137
- throw new HubBindingError(`malformed hub binding at ${file}`);
24138
- }
24139
- const row = parsed;
24140
- const keys = Object.keys(row);
24141
- const allowed = /* @__PURE__ */ new Set(["schema", "url", "boundAt", "cloud", "tokenEnv", "tokenCommand"]);
24142
- const cloudish = keys.some((key) => key === "cloud" || key === "tokenEnv" || key === "tokenCommand");
24143
- if (keys.some((key) => !allowed.has(key)) || !cloudish && keys.length !== 3 || row.schema !== HUB_BINDING_SCHEMA || typeof row.url !== "string" || typeof row.boundAt !== "string" || !isIsoTimestamp(row.boundAt)) {
24144
- throw new HubBindingError(`malformed hub binding at ${file}`);
24145
- }
24146
- let url;
24147
- try {
24148
- url = validateHubUrl(row.url);
24149
- } catch {
24150
- throw new HubBindingError(`malformed hub binding at ${file}`);
24155
+ return new HubBindingError(`malformed hub binding at ${file}`);
24151
24156
  }
24152
- if (!cloudish) return { schema: HUB_BINDING_SCHEMA, url, boundAt: row.boundAt };
24153
- if (row.cloud !== true) throw new HubBindingError(`malformed hub binding at ${file}`);
24157
+ return parsed;
24158
+ }
24159
+ function cloudRecordFromRow(file, row, url, boundAt) {
24160
+ if (row.cloud !== true) return void 0;
24154
24161
  let tokenEnv;
24155
24162
  let tokenCommand;
24156
24163
  if (row.tokenEnv !== void 0) {
@@ -24172,12 +24179,65 @@ function readHubBinding(env = process.env) {
24172
24179
  return {
24173
24180
  schema: HUB_BINDING_SCHEMA,
24174
24181
  url,
24175
- boundAt: row.boundAt,
24182
+ boundAt,
24176
24183
  cloud: true,
24177
24184
  ...tokenEnv ? { tokenEnv } : {},
24178
24185
  ...tokenCommand ? { tokenCommand } : {}
24179
24186
  };
24180
24187
  }
24188
+ function interpretBindingFile(file) {
24189
+ if (!existsSync2(file)) return {};
24190
+ const parsed = parseBindingObject(file);
24191
+ if (parsed instanceof HubBindingError) throw parsed;
24192
+ const keys = Object.keys(parsed);
24193
+ const unknown2 = keys.filter((key) => !BINDING_KEYS.has(key));
24194
+ if (parsed.schema !== HUB_BINDING_SCHEMA || unknown2.length > 0) {
24195
+ return { warning: bindingFallbackWarning(file, `is newer than this build understands (${String(parsed.schema)})`) };
24196
+ }
24197
+ if (typeof parsed.url !== "string" || typeof parsed.boundAt !== "string" || !isIsoTimestamp(parsed.boundAt)) {
24198
+ throw new HubBindingError(`malformed hub binding at ${file}`);
24199
+ }
24200
+ let url;
24201
+ try {
24202
+ url = validateHubUrl(parsed.url);
24203
+ } catch {
24204
+ throw new HubBindingError(`malformed hub binding at ${file}`);
24205
+ }
24206
+ const cloudish = keys.some((key) => key === "cloud" || key === "tokenEnv" || key === "tokenCommand");
24207
+ if (!cloudish) {
24208
+ if (keys.length !== 3) throw new HubBindingError(`malformed hub binding at ${file}`);
24209
+ return { record: { schema: HUB_BINDING_SCHEMA, url, boundAt: parsed.boundAt } };
24210
+ }
24211
+ const record2 = cloudRecordFromRow(file, parsed, url, parsed.boundAt);
24212
+ if (!record2) throw new HubBindingError(`malformed hub binding at ${file}`);
24213
+ return { record: record2, legacyCloud: true };
24214
+ }
24215
+ function loadHubBinding(env = process.env) {
24216
+ const cloudFile = hubBindingCloudFile(env);
24217
+ const cloud = interpretBindingFile(cloudFile);
24218
+ if (cloud.warning && !cloud.record) {
24219
+ const local = existsSync2(hubBindingFile(env)) ? interpretBindingFile(hubBindingFile(env)) : {};
24220
+ if (local.record && !local.record.cloud) return { record: local.record, warning: cloud.warning };
24221
+ return { warning: cloud.warning };
24222
+ }
24223
+ if (cloud.record?.cloud) return { record: cloud.record, ...cloud.warning ? { warning: cloud.warning } : {} };
24224
+ const main = interpretBindingFile(hubBindingFile(env));
24225
+ if (main.legacyCloud && main.record) {
24226
+ writeBindingJson(cloudFile, main.record);
24227
+ rmSync(hubBindingFile(env), { force: true });
24228
+ return {
24229
+ record: main.record,
24230
+ warning: bindingFallbackWarning(
24231
+ hubBindingFile(env),
24232
+ "stored a cloud bind in the pre-0.7.160 file"
24233
+ )
24234
+ };
24235
+ }
24236
+ return { ...main.record ? { record: main.record } : {}, ...main.warning ? { warning: main.warning } : {} };
24237
+ }
24238
+ function readHubBinding(env = process.env) {
24239
+ return loadHubBinding(env).record;
24240
+ }
24181
24241
 
24182
24242
  // plugins/kxm/src/hub-identity.ts
24183
24243
  var OP_TIMEOUT_MS = 15e3;
@@ -24244,15 +24304,6 @@ function resolveProjectIdentity(cwd, env = process.env, explicit) {
24244
24304
  if (fromPackage) return { project: fromPackage, source: "package.json", sourceLabel: "package.json name" };
24245
24305
  return { project: basename(cwd), source: "directory", sourceLabel: "directory name" };
24246
24306
  }
24247
- function opReferenceFromTokenCommand(command) {
24248
- try {
24249
- const args = splitTokenCommand(command);
24250
- if (args[0] === "op" && args[1] === "read" && args[2] && isHubOpReference(args[2])) return args[2];
24251
- } catch {
24252
- return void 0;
24253
- }
24254
- return void 0;
24255
- }
24256
24307
  function defaultOpRead(reference, env) {
24257
24308
  if (!isHubOpReference(reference)) {
24258
24309
  throw new CloudTokenError("cloud_token_command_invalid", `refusing to resolve ${reference}; an op:// reference is required`);
@@ -24297,18 +24348,24 @@ function resolveKeyReference(ref, env, opRead = defaultOpRead) {
24297
24348
  }
24298
24349
  function keySourceFor(input) {
24299
24350
  const ref = input.endpoint?.key;
24300
- if (input.mode === "local" && input.env.KXM_AUTH_TOKEN?.trim()) return "env:KXM_AUTH_TOKEN";
24301
- if (ref?.env && input.env[ref.env]?.trim()) return `env:${ref.env}`;
24302
- if (ref?.op) return `op:${ref.op}`;
24303
- if (ref?.env) return `env:${ref.env}`;
24351
+ const envName = (name) => {
24352
+ if (!name) return void 0;
24353
+ return input.env[name]?.trim() ? `env:${name}` : void 0;
24354
+ };
24304
24355
  if (input.mode === "cloud") {
24305
- if (input.binding?.tokenEnv) return `env:${input.binding.tokenEnv}`;
24306
- if (input.binding?.tokenCommand) {
24307
- const op = opReferenceFromTokenCommand(input.binding.tokenCommand);
24308
- return op ? `op:${op}` : "command";
24309
- }
24356
+ const fromEnv2 = envName(ref?.env);
24357
+ if (fromEnv2) return fromEnv2;
24358
+ if (ref?.op) return `op:${ref.op}`;
24359
+ const fromBindingEnv = envName(input.binding?.tokenEnv);
24360
+ if (fromBindingEnv) return fromBindingEnv;
24361
+ if (input.binding?.tokenCommand) return "token-command";
24310
24362
  return "missing";
24311
24363
  }
24364
+ const fromAuth = envName("KXM_AUTH_TOKEN");
24365
+ if (fromAuth) return fromAuth;
24366
+ const fromEnv = envName(ref?.env);
24367
+ if (fromEnv) return fromEnv;
24368
+ if (ref?.op) return `op:${ref.op}`;
24312
24369
  if (input.hasSavedProjectToken?.(input.project)) return "hub-env";
24313
24370
  return "missing";
24314
24371
  }
@@ -25381,7 +25438,7 @@ function sessionTokenFixHint(policy) {
25381
25438
  }
25382
25439
 
25383
25440
  // plugins/kxm/src/mcp-server.ts
25384
- var VERSION = "0.7.167";
25441
+ var VERSION = "0.7.169";
25385
25442
  var CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
25386
25443
  var inbox = /* @__PURE__ */ new Map();
25387
25444
  var notifiedInbox = /* @__PURE__ */ new Set();