@kontextmind/kxm 0.7.165 → 0.7.167

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 (41) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +16 -0
  3. package/docs/README.md +1 -0
  4. package/docs/architecture/hosted-direction.md +9 -4
  5. package/docs/architecture/inventory.md +1 -0
  6. package/docs/concepts/trust-model.md +1 -1
  7. package/docs/contributing/decisions.md +153 -0
  8. package/docs/contributing/learnings.md +54 -53
  9. package/docs/contributing/operating-rules.md +19 -6
  10. package/docs/glossary.md +2 -2
  11. package/docs/operations/troubleshooting.md +2 -2
  12. package/docs/operations.md +62 -8
  13. package/docs/reference/cli-reference.md +11 -11
  14. package/docs/reference/config-reference.md +36 -11
  15. package/docs/reference/configuration.md +2 -2
  16. package/docs/reference/tools.md +1 -1
  17. package/docs/start/quickstart-claude-code.md +2 -2
  18. package/package.json +1 -1
  19. package/plugins/kxm/.claude-plugin/plugin.json +1 -1
  20. package/plugins/kxm/README.md +3 -3
  21. package/plugins/kxm/dist/claude-hook.js +417 -66
  22. package/plugins/kxm/dist/cli.js +1399 -900
  23. package/plugins/kxm/dist/extension.js +399 -64
  24. package/plugins/kxm/dist/mcp-server.js +622 -135
  25. package/plugins/kxm/dist/runtime-supervisor.js +668 -166
  26. package/plugins/kxm/dist/runtime.js +713 -211
  27. package/plugins/kxm/dist/server.js +466 -58
  28. package/plugins/kxm/package.json +1 -1
  29. package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +15 -7
  30. package/plugins/kxm/src/cli/hub.ts +80 -21
  31. package/plugins/kxm/src/cli/types.ts +8 -1
  32. package/plugins/kxm/src/cli.ts +41 -7
  33. package/plugins/kxm/src/config.ts +246 -3
  34. package/plugins/kxm/src/extension.ts +8 -7
  35. package/plugins/kxm/src/hub-autostart.ts +20 -0
  36. package/plugins/kxm/src/hub-env.ts +83 -31
  37. package/plugins/kxm/src/hub-identity.ts +337 -0
  38. package/plugins/kxm/src/mcp-server.ts +17 -15
  39. package/plugins/kxm/src/project-name.ts +6 -47
  40. package/plugins/kxm/src/server.ts +22 -4
  41. package/scripts/kxm-hub.mjs +5 -0
@@ -2987,7 +2987,7 @@ var require_compile = __commonJS({
2987
2987
  const schOrFunc = root.refs[ref];
2988
2988
  if (schOrFunc)
2989
2989
  return schOrFunc;
2990
- let _sch = resolve11.call(this, root, ref);
2990
+ let _sch = resolve13.call(this, root, ref);
2991
2991
  if (_sch === void 0) {
2992
2992
  const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
2993
2993
  const { schemaId } = this.opts;
@@ -3014,7 +3014,7 @@ var require_compile = __commonJS({
3014
3014
  function sameSchemaEnv(s1, s2) {
3015
3015
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
3016
3016
  }
3017
- function resolve11(root, ref) {
3017
+ function resolve13(root, ref) {
3018
3018
  let sch;
3019
3019
  while (typeof (sch = this.refs[ref]) == "string")
3020
3020
  ref = sch;
@@ -3839,7 +3839,7 @@ var require_fast_uri = __commonJS({
3839
3839
  }
3840
3840
  return uri;
3841
3841
  }
3842
- function resolve11(baseURI, relativeURI, options) {
3842
+ function resolve13(baseURI, relativeURI, options) {
3843
3843
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
3844
3844
  const {
3845
3845
  parsed: baseParsed,
@@ -4201,7 +4201,7 @@ var require_fast_uri = __commonJS({
4201
4201
  var fastUri = {
4202
4202
  SCHEMES,
4203
4203
  normalize,
4204
- resolve: resolve11,
4204
+ resolve: resolve13,
4205
4205
  resolveComponent,
4206
4206
  equal,
4207
4207
  serialize,
@@ -14781,9 +14781,9 @@ var require_dist = __commonJS({
14781
14781
  // plugins/kxm/src/runtime-supervisor.ts
14782
14782
  import { spawn as spawn3 } from "node:child_process";
14783
14783
  import { createHash as createHash15, createHmac, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
14784
- import { chmodSync as chmodSync2, existsSync as existsSync18, lstatSync as lstatSync6, mkdirSync as mkdirSync9, readFileSync as readFileSync15, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "node:fs";
14784
+ import { chmodSync as chmodSync2, existsSync as existsSync20, lstatSync as lstatSync6, mkdirSync as mkdirSync10, readFileSync as readFileSync17, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync10 } from "node:fs";
14785
14785
  import { createServer } from "node:http";
14786
- import { dirname as dirname11, isAbsolute as isAbsolute8, join as join20 } from "node:path";
14786
+ import { dirname as dirname13, isAbsolute as isAbsolute8, join as join22 } from "node:path";
14787
14787
 
14788
14788
  // plugins/kxm/src/repo-root.ts
14789
14789
  import { existsSync } from "node:fs";
@@ -16097,7 +16097,7 @@ function defaultSpawn(command, args, options) {
16097
16097
  if (options.signal?.aborted) {
16098
16098
  return Promise.resolve({ stdout: "", stderr: "", code: null, started: false, observedChildExit: false, error: new Error("process_aborted") });
16099
16099
  }
16100
- return new Promise((resolve11) => {
16100
+ return new Promise((resolve13) => {
16101
16101
  const stdout = [];
16102
16102
  const stderr = [];
16103
16103
  let outputBytes = 0;
@@ -16128,7 +16128,7 @@ function defaultSpawn(command, args, options) {
16128
16128
  const started = Boolean(child?.pid);
16129
16129
  if (started && !observedChildExit) error ??= new Error("process_exit_unobserved");
16130
16130
  const unverifiedDescendants = stopping || started && !observedChildExit;
16131
- resolve11({
16131
+ resolve13({
16132
16132
  stdout: Buffer.concat(stdout).toString("utf8"),
16133
16133
  stderr: Buffer.concat(stderr).toString("utf8"),
16134
16134
  code,
@@ -17976,8 +17976,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
17976
17976
  const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
17977
17977
  if (maxWriteRepositories > writable) issues.push(issue3("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
17978
17978
  }
17979
- const join21 = objectValue(step.join);
17980
- const minimumPassed = join21 && typeof join21.minimumPassed === "number" ? join21.minimumPassed : void 0;
17979
+ const join23 = objectValue(step.join);
17980
+ const minimumPassed = join23 && typeof join23.minimumPassed === "number" ? join23.minimumPassed : void 0;
17981
17981
  if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue3("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
17982
17982
  const distinctBy = names(assignment?.distinctBy);
17983
17983
  if (distinctBy.length > 0) {
@@ -22557,7 +22557,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
22557
22557
  const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
22558
22558
  const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
22559
22559
  const assignments = compileAssignments(step, id, agent, sink);
22560
- const join21 = compileJoin(step, id, sink);
22560
+ const join23 = compileJoin(step, id, sink);
22561
22561
  const requiredEvidence = compileEvidence(step, id, sink);
22562
22562
  const transitions = compileTransitions(step, id, index, stepIndex, sink);
22563
22563
  const outcomes = Object.keys(transitions).sort(compareCodeUnits5);
@@ -22585,7 +22585,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
22585
22585
  transitions: orderedTransitions,
22586
22586
  requiresPlanHash: requirePlanHash.includes(id),
22587
22587
  assignments,
22588
- join: join21
22588
+ join: join23
22589
22589
  };
22590
22590
  if (kind === "agent" || kind === "moa") {
22591
22591
  if (!agent) return void 0;
@@ -22635,15 +22635,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
22635
22635
  };
22636
22636
  }
22637
22637
  function compileJoin(step, stepId, sink) {
22638
- const join21 = objectValue2(step.join);
22639
- if (!join21) return { strategy: "all" };
22640
- const declared = stringValue2(join21.strategy);
22638
+ const join23 = objectValue2(step.join);
22639
+ if (!join23) return { strategy: "all" };
22640
+ const declared = stringValue2(join23.strategy);
22641
22641
  const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
22642
- const minimumPassed = compileOptionalCount(join21.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
22642
+ const minimumPassed = compileOptionalCount(join23.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
22643
22643
  const compiled = {
22644
22644
  strategy,
22645
22645
  ...minimumPassed !== void 0 ? { minimumPassed } : {},
22646
- ...typeof join21.cancelRemaining === "boolean" ? { cancelRemaining: join21.cancelRemaining } : {}
22646
+ ...typeof join23.cancelRemaining === "boolean" ? { cancelRemaining: join23.cancelRemaining } : {}
22647
22647
  };
22648
22648
  return compiled;
22649
22649
  }
@@ -23996,12 +23996,12 @@ function enqueueKxmScheduledRun(storePath, runId, configRevision, bound, start)
23996
23996
  if (owner.admitted.has(runId) || owner.queue.some((item) => item.runId === runId)) {
23997
23997
  return Promise.reject(runtimeError("run_busy", runId, `run ${runId} is already admitted or queued`));
23998
23998
  }
23999
- return new Promise((resolve11, reject) => {
23999
+ return new Promise((resolve13, reject) => {
24000
24000
  owner.queue.push({
24001
24001
  runId,
24002
24002
  configRevision,
24003
24003
  bound,
24004
- start: (token) => start(token).then(resolve11, reject),
24004
+ start: (token) => start(token).then(resolve13, reject),
24005
24005
  fail: (error) => reject(error)
24006
24006
  });
24007
24007
  pump(storePath, owner);
@@ -24794,38 +24794,344 @@ function loadPriceCatalog(rootOrPath) {
24794
24794
  // plugins/kxm/src/engine.ts
24795
24795
  var import_yaml11 = __toESM(require_dist(), 1);
24796
24796
  import { createHash as createHash14, randomBytes, timingSafeEqual } from "node:crypto";
24797
- import { existsSync as existsSync14, readFileSync as readFileSync12 } from "node:fs";
24798
- import { join as join17 } from "node:path";
24797
+ import { existsSync as existsSync15, readFileSync as readFileSync13 } from "node:fs";
24798
+ import { join as join18 } from "node:path";
24799
24799
 
24800
24800
  // plugins/kxm/src/routes.ts
24801
24801
  var import_yaml7 = __toESM(require_dist(), 1);
24802
- import { existsSync as existsSync10, readFileSync as readFileSync8, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, readdirSync as readdirSync6 } from "node:fs";
24803
- import { join as join11 } from "node:path";
24802
+ import { existsSync as existsSync11, readFileSync as readFileSync9, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, readdirSync as readdirSync6 } from "node:fs";
24803
+ import { join as join12 } from "node:path";
24804
24804
 
24805
24805
  // plugins/kxm/src/role.ts
24806
24806
  var import_yaml6 = __toESM(require_dist(), 1);
24807
24807
 
24808
24808
  // plugins/kxm/src/config.ts
24809
24809
  var import_yaml5 = __toESM(require_dist(), 1);
24810
+ import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "node:fs";
24811
+ import { tmpdir, homedir as homedir2 } from "node:os";
24812
+ import { dirname as dirname6, join as join11, resolve as resolve7 } from "node:path";
24813
+ var KXM_CONFIG_SCHEMA = "kxm.config.v1";
24814
+ var KxmHubConfigError = class extends Error {
24815
+ code = "hub_config_invalid";
24816
+ constructor(message) {
24817
+ super(message);
24818
+ this.name = "KxmHubConfigError";
24819
+ }
24820
+ };
24821
+ var HUB_ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
24822
+ var HUB_OP_REF = /^op:\/\/\S+\/\S+\/\S+$/;
24823
+ var LITERAL_SECRET_KEY = /^(token|secret|password|authToken|auth_token|apiKey|api_key|api_token|bearer|credential|access_token)$/i;
24824
+ function isHubKeyEnvName(value) {
24825
+ return HUB_ENV_NAME.test(value);
24826
+ }
24827
+ function isHubOpReference(value) {
24828
+ return HUB_OP_REF.test(value);
24829
+ }
24830
+ var IMPROVEMENT_PROMOTION_POLICIES = ["manual_pr", "critic_quorum", "auto_threshold"];
24831
+ var DEFAULT_KXM_CONFIG = {
24832
+ schema: KXM_CONFIG_SCHEMA,
24833
+ user: {
24834
+ theme: "dark",
24835
+ preferredCritics: ["reviewer-arch", "reviewer-cli"],
24836
+ tokenBudget: 16e3
24837
+ },
24838
+ defaults: {
24839
+ workflow: "software-engineering/feature-implementation",
24840
+ harness: "pi"
24841
+ },
24842
+ dash: {
24843
+ defaultScreen: "agents",
24844
+ refreshIntervalMs: 1e3,
24845
+ autoOpen: false
24846
+ },
24847
+ sync: {
24848
+ defaultTracker: "none"
24849
+ },
24850
+ hub: {
24851
+ autoStart: "background"
24852
+ },
24853
+ improvement: {
24854
+ promotionPolicy: "manual_pr",
24855
+ telemetryHalfLifeDays: 14,
24856
+ autoThreshold: {
24857
+ minRuns: 10,
24858
+ minPassRate: 0.95,
24859
+ minCostSavings: 0.5
24860
+ }
24861
+ },
24862
+ routing: {
24863
+ shadowExecution: {
24864
+ enabled: false,
24865
+ sampleRate: 0.05,
24866
+ candidateModels: []
24867
+ },
24868
+ circuitBreaker: {
24869
+ mode: "soft_demotion",
24870
+ failureThreshold: 3,
24871
+ windowSeconds: 3600,
24872
+ cooldownSeconds: 1800,
24873
+ penaltyMultiplier: 5
24874
+ }
24875
+ },
24876
+ telemetry: {
24877
+ federated: true,
24878
+ anonymize: true
24879
+ }
24880
+ };
24881
+ function userConfigDirectory(overrideDir) {
24882
+ if (overrideDir) return resolve7(overrideDir);
24883
+ return resolve7(process.env.KXM_USER_CONFIG_DIR?.trim() || join11(homedir2(), ".config", "kxm"));
24884
+ }
24885
+ function repoConfigDirectory(repoRoot) {
24886
+ return resolve7(repoRoot, ".kxm");
24887
+ }
24888
+ function deepMerge(target, source) {
24889
+ const result = { ...target };
24890
+ for (const [key, val] of Object.entries(source)) {
24891
+ if (val && typeof val === "object" && !Array.isArray(val)) {
24892
+ const existing = result[key] && typeof result[key] === "object" && !Array.isArray(result[key]) ? result[key] : {};
24893
+ result[key] = deepMerge(existing, val);
24894
+ } else if (val !== void 0) {
24895
+ result[key] = val;
24896
+ }
24897
+ }
24898
+ return result;
24899
+ }
24900
+ function literalSecretMessage(path) {
24901
+ return `refusing literal hub token at ${path}: store an op:// reference (key.op) or an environment variable name (key.env), never the token`;
24902
+ }
24903
+ function rejectLiteralHubSecrets(value, path) {
24904
+ if (Array.isArray(value)) {
24905
+ value.forEach((item, index) => rejectLiteralHubSecrets(item, `${path}[${index}]`));
24906
+ return;
24907
+ }
24908
+ if (!value || typeof value !== "object") return;
24909
+ for (const [key, child] of Object.entries(value)) {
24910
+ const childPath = `${path}.${key}`;
24911
+ if (typeof child === "string" && (key === "key" || LITERAL_SECRET_KEY.test(key))) {
24912
+ throw new KxmHubConfigError(literalSecretMessage(childPath));
24913
+ }
24914
+ if (child && typeof child === "object") rejectLiteralHubSecrets(child, childPath);
24915
+ }
24916
+ }
24917
+ function parseKeyRef(raw, path) {
24918
+ if (raw === void 0) return void 0;
24919
+ if (typeof raw === "string") throw new KxmHubConfigError(literalSecretMessage(path));
24920
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
24921
+ throw new KxmHubConfigError(`${path} must be a key reference with op and/or env, never a token`);
24922
+ }
24923
+ const row = raw;
24924
+ for (const key of Object.keys(row)) {
24925
+ if (key !== "op" && key !== "env") {
24926
+ throw new KxmHubConfigError(literalSecretMessage(`${path}.${key}`));
24927
+ }
24928
+ }
24929
+ const ref = {};
24930
+ if (row.op !== void 0) {
24931
+ if (typeof row.op !== "string" || !isHubOpReference(row.op)) {
24932
+ throw new KxmHubConfigError(`${path}.op must be an op://vault/item/field reference, not a token`);
24933
+ }
24934
+ ref.op = row.op;
24935
+ }
24936
+ if (row.env !== void 0) {
24937
+ if (typeof row.env !== "string" || !isHubKeyEnvName(row.env)) {
24938
+ throw new KxmHubConfigError(`${path}.env must be an environment variable name, not a token`);
24939
+ }
24940
+ ref.env = row.env;
24941
+ }
24942
+ if (!ref.op && !ref.env) throw new KxmHubConfigError(`${path} needs key.op, key.env, or both`);
24943
+ return ref;
24944
+ }
24945
+ function parseEndpoint(raw, path) {
24946
+ if (raw === void 0) return void 0;
24947
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
24948
+ throw new KxmHubConfigError(`${path} must be an object with url, project, and key`);
24949
+ }
24950
+ const row = raw;
24951
+ const endpoint = {};
24952
+ if (row.url !== void 0) {
24953
+ if (typeof row.url !== "string" || !isHubUrl(row.url)) {
24954
+ throw new KxmHubConfigError(`${path}.url must be an http or https URL without credentials, query, or fragment`);
24955
+ }
24956
+ endpoint.url = row.url.replace(/\/$/, "");
24957
+ }
24958
+ if (row.project !== void 0) {
24959
+ if (typeof row.project !== "string" || !isHubProjectId(row.project)) {
24960
+ throw new KxmHubConfigError(`${path}.project must be a single-line project id, not a token`);
24961
+ }
24962
+ endpoint.project = row.project.trim();
24963
+ }
24964
+ const key = parseKeyRef(row.key, `${path}.key`);
24965
+ if (key) endpoint.key = key;
24966
+ for (const name of Object.keys(row)) {
24967
+ if (name !== "url" && name !== "project" && name !== "key") {
24968
+ if (typeof row[name] === "string") throw new KxmHubConfigError(literalSecretMessage(`${path}.${name}`));
24969
+ throw new KxmHubConfigError(`${path}.${name} is not a hub endpoint field`);
24970
+ }
24971
+ }
24972
+ return endpoint;
24973
+ }
24974
+ function isHubUrl(raw) {
24975
+ try {
24976
+ const parsed = new URL(raw);
24977
+ return (parsed.protocol === "http:" || parsed.protocol === "https:") && parsed.username === "" && parsed.password === "" && parsed.search === "" && parsed.hash === "" && !raw.includes("?") && !raw.includes("#");
24978
+ } catch {
24979
+ return false;
24980
+ }
24981
+ }
24982
+ function isHubProjectId(raw) {
24983
+ const value = raw.trim();
24984
+ return value.length > 0 && value.length <= 200 && !/[\s\r\n]/.test(value);
24985
+ }
24986
+ function parseProjectMap(raw) {
24987
+ if (raw === void 0) return void 0;
24988
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
24989
+ throw new KxmHubConfigError("hub.projects must be a map of project id to key reference, never a token");
24990
+ }
24991
+ const projects = {};
24992
+ for (const [project, value] of Object.entries(raw)) {
24993
+ if (!isHubProjectId(project)) {
24994
+ throw new KxmHubConfigError(`hub.projects key ${JSON.stringify(project)} must be a project id, not a token`);
24995
+ }
24996
+ const ref = parseKeyRef(value, `hub.projects.${project}`);
24997
+ if (!ref) throw new KxmHubConfigError(`hub.projects.${project} needs an op:// reference or an environment variable name`);
24998
+ projects[project.trim()] = ref;
24999
+ }
25000
+ return projects;
25001
+ }
25002
+ function normalizeHubConfig(raw) {
25003
+ const autoStart = raw?.autoStart;
25004
+ const hub = {
25005
+ autoStart: autoStart === "off" || autoStart === "background" ? autoStart : DEFAULT_KXM_CONFIG.hub.autoStart
25006
+ };
25007
+ if (raw === void 0) return hub;
25008
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
25009
+ throw new KxmHubConfigError("hub must be an object");
25010
+ }
25011
+ rejectLiteralHubSecrets(raw, "hub");
25012
+ const row = raw;
25013
+ if (row.mode !== void 0) {
25014
+ if (row.mode !== "local" && row.mode !== "cloud") {
25015
+ throw new KxmHubConfigError("hub.mode must be local or cloud");
25016
+ }
25017
+ hub.mode = row.mode;
25018
+ }
25019
+ const local = parseEndpoint(row.local, "hub.local");
25020
+ const cloud = parseEndpoint(row.cloud, "hub.cloud");
25021
+ const projects = parseProjectMap(row.projects);
25022
+ if (local) hub.local = local;
25023
+ if (cloud) hub.cloud = cloud;
25024
+ if (projects && Object.keys(projects).length > 0) hub.projects = projects;
25025
+ return hub;
25026
+ }
25027
+ function findConfigRoot(start) {
25028
+ let dir = resolve7(start);
25029
+ for (; ; ) {
25030
+ if (existsSync10(join11(dir, ".kxm", "project.yaml")) || existsSync10(join11(dir, ".kxm", "config.yaml"))) return dir;
25031
+ const parent = dirname6(dir);
25032
+ if (parent === dir) return resolve7(start);
25033
+ dir = parent;
25034
+ }
25035
+ }
25036
+ function userConfigDirForEnv(env) {
25037
+ const explicit = env.KXM_USER_CONFIG_DIR?.trim();
25038
+ if (explicit) return explicit;
25039
+ if (env === process.env) return void 0;
25040
+ return join11(tmpdir(), "kxm-no-user-config");
25041
+ }
25042
+ function loadHubSettings(start, env = process.env) {
25043
+ const userConfigDir = userConfigDirForEnv(env);
25044
+ return loadKxmConfig(findConfigRoot(start), userConfigDir === void 0 ? {} : { userConfigDir }).hub;
25045
+ }
25046
+ function recordOf(raw) {
25047
+ return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
25048
+ }
25049
+ function finiteNumber(value) {
25050
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
25051
+ }
25052
+ function normalizeImprovementConfig(raw) {
25053
+ const value = recordOf(raw);
25054
+ const threshold = recordOf(value.autoThreshold);
25055
+ const policy = value.promotionPolicy;
25056
+ const halfLife = finiteNumber(value.telemetryHalfLifeDays);
25057
+ const minRuns = finiteNumber(threshold.minRuns);
25058
+ const minPassRate = finiteNumber(threshold.minPassRate);
25059
+ const minCostSavings = finiteNumber(threshold.minCostSavings);
25060
+ return {
25061
+ promotionPolicy: IMPROVEMENT_PROMOTION_POLICIES.includes(policy) ? policy : "manual_pr",
25062
+ telemetryHalfLifeDays: halfLife !== void 0 && halfLife > 0 && halfLife <= 3650 ? halfLife : 14,
25063
+ autoThreshold: {
25064
+ minRuns: minRuns !== void 0 && Number.isInteger(minRuns) && minRuns >= 1 && minRuns <= 1e6 ? minRuns : 10,
25065
+ minPassRate: minPassRate !== void 0 && minPassRate >= 0 && minPassRate <= 1 ? minPassRate : 0.95,
25066
+ minCostSavings: minCostSavings !== void 0 && minCostSavings >= 0 ? minCostSavings : 0.5
25067
+ }
25068
+ };
25069
+ }
25070
+ function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
25071
+ const userDir = userConfigDirectory(options.userConfigDir);
25072
+ const userConfigFile = join11(userDir, "config.yaml");
25073
+ const repoDir = repoConfigDirectory(repoRoot);
25074
+ const repoConfigFile = join11(repoDir, "config.yaml");
25075
+ let userRaw = {};
25076
+ let userLoadedPath;
25077
+ if (existsSync10(userConfigFile)) {
25078
+ try {
25079
+ const text = readFileSync8(userConfigFile, "utf8");
25080
+ userRaw = (0, import_yaml5.parse)(text) ?? {};
25081
+ userLoadedPath = userConfigFile;
25082
+ } catch (error) {
25083
+ throw new Error(`invalid user config YAML at ${userConfigFile}`, { cause: error });
25084
+ }
25085
+ }
25086
+ let repoRaw = {};
25087
+ let repoLoadedPath;
25088
+ if (existsSync10(repoConfigFile)) {
25089
+ try {
25090
+ const text = readFileSync8(repoConfigFile, "utf8");
25091
+ repoRaw = (0, import_yaml5.parse)(text) ?? {};
25092
+ repoLoadedPath = repoConfigFile;
25093
+ } catch (error) {
25094
+ throw new Error(`invalid project config YAML at ${repoConfigFile}`, { cause: error });
25095
+ }
25096
+ }
25097
+ const baseCopy = JSON.parse(JSON.stringify(DEFAULT_KXM_CONFIG));
25098
+ const mergedUser = deepMerge(baseCopy, userRaw);
25099
+ const mergedAll = deepMerge(mergedUser, repoRaw);
25100
+ return {
25101
+ schema: KXM_CONFIG_SCHEMA,
25102
+ user: mergedAll.user ?? {},
25103
+ defaults: mergedAll.defaults ?? {},
25104
+ dash: mergedAll.dash ?? {},
25105
+ sync: mergedAll.sync ?? {},
25106
+ hub: normalizeHubConfig(mergedAll.hub),
25107
+ improvement: normalizeImprovementConfig(mergedAll.improvement),
25108
+ routing: mergedAll.routing ?? DEFAULT_KXM_CONFIG.routing,
25109
+ telemetry: mergedAll.telemetry ?? DEFAULT_KXM_CONFIG.telemetry,
25110
+ loadedFrom: {
25111
+ userConfigPath: userLoadedPath,
25112
+ repoConfigPath: repoLoadedPath
25113
+ }
25114
+ };
25115
+ }
24810
25116
 
24811
25117
  // plugins/kxm/src/routes.ts
24812
25118
  var RETIRED_POLICY = ".kxm/producers.yaml";
24813
25119
  var empty = () => ({ schema: "kxm.routes.v2", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), admitted: [], disabled: [] });
24814
25120
  function loadRoutePolicy(root) {
24815
- if (existsSync10(join11(root, RETIRED_POLICY))) throw new Error(`retired ${RETIRED_POLICY} present; use .kxm/routes.yaml (kxm.routes.v2)`);
24816
- const path = join11(root, ".kxm", "routes.yaml");
24817
- if (!existsSync10(path)) return empty();
24818
- const value = (0, import_yaml7.parse)(readFileSync8(path, "utf8"));
25121
+ if (existsSync11(join12(root, RETIRED_POLICY))) throw new Error(`retired ${RETIRED_POLICY} present; use .kxm/routes.yaml (kxm.routes.v2)`);
25122
+ const path = join12(root, ".kxm", "routes.yaml");
25123
+ if (!existsSync11(path)) return empty();
25124
+ const value = (0, import_yaml7.parse)(readFileSync9(path, "utf8"));
24819
25125
  if (value?.schema !== "kxm.routes.v2" || !Array.isArray(value.admitted)) throw new Error("invalid .kxm/routes.yaml");
24820
25126
  return { schema: "kxm.routes.v2", updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : (/* @__PURE__ */ new Date()).toISOString(), admitted: value.admitted.filter((x) => typeof x === "string"), disabled: Array.isArray(value.disabled) ? value.disabled.filter((x) => typeof x === "string") : [] };
24821
25127
  }
24822
25128
  function listRoleBindings(root) {
24823
- const dir = join11(root, ".kxm", "roles");
25129
+ const dir = join12(root, ".kxm", "roles");
24824
25130
  const result = {};
24825
- if (!existsSync10(dir)) return result;
25131
+ if (!existsSync11(dir)) return result;
24826
25132
  for (const file of readdirSync6(dir).filter((name) => name.endsWith(".yaml"))) {
24827
25133
  const role = file.slice(0, -5);
24828
- const value = (0, import_yaml7.parse)(readFileSync8(join11(dir, file), "utf8"));
25134
+ const value = (0, import_yaml7.parse)(readFileSync9(join12(dir, file), "utf8"));
24829
25135
  result[role] = (value.roster ?? []).map((entry) => entry.route).filter((route) => typeof route === "string");
24830
25136
  }
24831
25137
  return result;
@@ -24833,8 +25139,8 @@ function listRoleBindings(root) {
24833
25139
 
24834
25140
  // plugins/kxm/src/route-fallback.ts
24835
25141
  var import_yaml8 = __toESM(require_dist(), 1);
24836
- import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as readFileSync9 } from "node:fs";
24837
- import { join as join12 } from "node:path";
25142
+ import { existsSync as existsSync12, readdirSync as readdirSync7, readFileSync as readFileSync10 } from "node:fs";
25143
+ import { join as join13 } from "node:path";
24838
25144
 
24839
25145
  // plugins/kxm/src/route-switch.ts
24840
25146
  var WALKABLE_CLASSES = ["rate_limit", "transport", "provider_unavailable", "context_overflow"];
@@ -25034,9 +25340,9 @@ ${lines.join("\n")}`;
25034
25340
  ${block}`;
25035
25341
  }
25036
25342
  function readYaml(file) {
25037
- if (!existsSync11(file)) return void 0;
25343
+ if (!existsSync12(file)) return void 0;
25038
25344
  try {
25039
- const parsed = (0, import_yaml8.parse)(readFileSync9(file, "utf8"));
25345
+ const parsed = (0, import_yaml8.parse)(readFileSync10(file, "utf8"));
25040
25346
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
25041
25347
  return parsed;
25042
25348
  } catch {
@@ -25048,7 +25354,7 @@ function stringList(value) {
25048
25354
  }
25049
25355
  function readSelectors(projectRoot, value) {
25050
25356
  if (!Array.isArray(value)) return [];
25051
- const modelsDir = join12(projectRoot, ".kxm", "models");
25357
+ const modelsDir = join13(projectRoot, ".kxm", "models");
25052
25358
  const selectors = [];
25053
25359
  for (const item of value) {
25054
25360
  if (!item || typeof item !== "object" || Array.isArray(item)) continue;
@@ -25067,9 +25373,9 @@ function readSelectors(projectRoot, value) {
25067
25373
  return selectors;
25068
25374
  }
25069
25375
  function loadChainModel(projectRoot, routeId2, writerIds) {
25070
- const modelsDir = join12(projectRoot, ".kxm", "models");
25376
+ const modelsDir = join13(projectRoot, ".kxm", "models");
25071
25377
  const fileId = findYamlBasename(modelsDir, routeId2, "route") ?? routeId2;
25072
- const doc = readYaml(join12(modelsDir, `${fileId}.yaml`));
25378
+ const doc = readYaml(join13(modelsDir, `${fileId}.yaml`));
25073
25379
  if (!doc || doc.schema !== "kxm.model.v2") return void 0;
25074
25380
  const harness = typeof doc.harness === "string" ? doc.harness : "";
25075
25381
  const model = typeof doc.model === "string" ? doc.model : "";
@@ -25096,7 +25402,7 @@ function loadChainModel(projectRoot, routeId2, writerIds) {
25096
25402
  };
25097
25403
  }
25098
25404
  function canonicalRoster(projectRoot, entries) {
25099
- const modelsDir = join12(projectRoot, ".kxm", "models");
25405
+ const modelsDir = join13(projectRoot, ".kxm", "models");
25100
25406
  return entries.map((entry) => {
25101
25407
  const route = findYamlBasename(modelsDir, entry.route, "route") ?? entry.route;
25102
25408
  return entry.effort ? { route, effort: entry.effort } : { route };
@@ -25115,10 +25421,10 @@ function rosterEntries(doc) {
25115
25421
  return entries;
25116
25422
  }
25117
25423
  function loadModelsFor(projectRoot, roster, writerIds) {
25118
- const modelsDir = join12(projectRoot, ".kxm", "models");
25424
+ const modelsDir = join13(projectRoot, ".kxm", "models");
25119
25425
  const wanted = /* @__PURE__ */ new Set();
25120
25426
  for (const entry of roster) wanted.add(entry.route);
25121
- if (existsSync11(modelsDir)) {
25427
+ if (existsSync12(modelsDir)) {
25122
25428
  for (const name of readdirSync7(modelsDir)) {
25123
25429
  if (!name.endsWith(".yaml") || name === "inventory.yaml") continue;
25124
25430
  wanted.add(name.slice(0, -5));
@@ -25135,12 +25441,12 @@ function loadModelsFor(projectRoot, roster, writerIds) {
25135
25441
  return models;
25136
25442
  }
25137
25443
  function criticVendors(projectRoot, writerIds) {
25138
- const dir = join12(projectRoot, ".kxm", "roles");
25139
- if (!existsSync11(dir)) return [];
25444
+ const dir = join13(projectRoot, ".kxm", "roles");
25445
+ if (!existsSync12(dir)) return [];
25140
25446
  const vendors = [];
25141
25447
  for (const name of readdirSync7(dir)) {
25142
25448
  if (!name.endsWith(".yaml")) continue;
25143
- const doc = readYaml(join12(dir, name));
25449
+ const doc = readYaml(join13(dir, name));
25144
25450
  const purpose = doc?.purpose;
25145
25451
  if (purpose !== "reviewer-arch" && purpose !== "reviewer-cli") continue;
25146
25452
  const first = rosterEntries(doc)[0];
@@ -25151,12 +25457,12 @@ function criticVendors(projectRoot, writerIds) {
25151
25457
  return vendors;
25152
25458
  }
25153
25459
  function loadAgentFallback(projectRoot, agentId, options) {
25154
- const agentsDir = join12(projectRoot, ".kxm", "agents");
25460
+ const agentsDir = join13(projectRoot, ".kxm", "agents");
25155
25461
  const agentFile = findYamlBasename(agentsDir, agentId, "agent") ?? agentId;
25156
- const agent = readYaml(join12(agentsDir, `${agentFile}.yaml`));
25462
+ const agent = readYaml(join13(agentsDir, `${agentFile}.yaml`));
25157
25463
  const roleId = typeof agent?.role === "string" ? agent.role : "";
25158
25464
  if (!roleId) return void 0;
25159
- const role = readYaml(join12(projectRoot, ".kxm", "roles", `${roleId}.yaml`));
25465
+ const role = readYaml(join13(projectRoot, ".kxm", "roles", `${roleId}.yaml`));
25160
25466
  if (!role) return void 0;
25161
25467
  const policyRecord = role.policy && typeof role.policy === "object" ? role.policy.fallback : void 0;
25162
25468
  const policy = parseFallbackPolicy(policyRecord);
@@ -25167,7 +25473,7 @@ function loadAgentFallback(projectRoot, agentId, options) {
25167
25473
  let cursor = typeof role.extends === "string" ? role.extends : "";
25168
25474
  while (cursor && !seenRoles.has(cursor)) {
25169
25475
  seenRoles.add(cursor);
25170
- const parent = readYaml(join12(projectRoot, ".kxm", "roles", `${cursor}.yaml`));
25476
+ const parent = readYaml(join13(projectRoot, ".kxm", "roles", `${cursor}.yaml`));
25171
25477
  extendsRoster = extendsRoster.concat(canonicalRoster(projectRoot, rosterEntries(parent)));
25172
25478
  cursor = typeof parent?.extends === "string" ? parent.extends : "";
25173
25479
  }
@@ -25515,7 +25821,7 @@ function pruneContextPacket(packet, tokenBudget) {
25515
25821
  // plugins/kxm/src/dispatch-context.ts
25516
25822
  import { spawnSync as spawnSync5 } from "node:child_process";
25517
25823
  import { readdirSync as readdirSync10 } from "node:fs";
25518
- import { extname as extname3, join as join15 } from "node:path";
25824
+ import { extname as extname3, join as join16 } from "node:path";
25519
25825
 
25520
25826
  // plugins/kxm/src/protocol.ts
25521
25827
  var DEFAULT_MESSAGE_TTL_MS = 24 * 60 * 6e4;
@@ -26144,8 +26450,8 @@ function memoryRecordToContextItem(record2, project) {
26144
26450
 
26145
26451
  // plugins/kxm/src/memory.ts
26146
26452
  var import_yaml9 = __toESM(require_dist(), 1);
26147
- import { existsSync as existsSync12, mkdirSync as mkdirSync4, readdirSync as readdirSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "node:fs";
26148
- import { extname as extname2, join as join13, resolve as resolve7 } from "node:path";
26453
+ import { existsSync as existsSync13, mkdirSync as mkdirSync5, readdirSync as readdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "node:fs";
26454
+ import { extname as extname2, join as join14, resolve as resolve8 } from "node:path";
26149
26455
  var MEMORY_SCHEMA = "kxm.memory.v1";
26150
26456
  var VALID_SCOPES = /* @__PURE__ */ new Set(["agent", "project", "run", "operator"]);
26151
26457
  var VALID_AUTHORITIES = /* @__PURE__ */ new Set(["instruction", "evidence", "promoted"]);
@@ -26243,21 +26549,21 @@ function parseMemoryRecord(raw, filename = "memory.md") {
26243
26549
  };
26244
26550
  }
26245
26551
  function memoryDirectories(repoRoot) {
26246
- const root = resolve7(repoRoot);
26247
- const memoryDir = join13(root, ".kxm", "memory");
26248
- const candidatesDir = join13(memoryDir, "candidates");
26552
+ const root = resolve8(repoRoot);
26553
+ const memoryDir = join14(root, ".kxm", "memory");
26554
+ const candidatesDir = join14(memoryDir, "candidates");
26249
26555
  return { memoryDir, candidatesDir };
26250
26556
  }
26251
26557
  function loadAuthoredMemory(repoRoot) {
26252
26558
  const { memoryDir } = memoryDirectories(repoRoot);
26253
- if (!existsSync12(memoryDir)) return [];
26559
+ if (!existsSync13(memoryDir)) return [];
26254
26560
  const records = [];
26255
26561
  const entries = readdirSync8(memoryDir, { withFileTypes: true });
26256
26562
  for (const entry of entries) {
26257
26563
  if (entry.isFile() && extname2(entry.name) === ".md") {
26258
- const fullPath = join13(memoryDir, entry.name);
26564
+ const fullPath = join14(memoryDir, entry.name);
26259
26565
  try {
26260
- const text = readFileSync10(fullPath, "utf8");
26566
+ const text = readFileSync11(fullPath, "utf8");
26261
26567
  const record2 = parseMemoryRecord(text, entry.name);
26262
26568
  if (record2.lifecycle === "active") {
26263
26569
  records.push(record2);
@@ -26273,8 +26579,8 @@ function loadAuthoredMemory(repoRoot) {
26273
26579
  // plugins/kxm/src/skills.ts
26274
26580
  var import_yaml10 = __toESM(require_dist(), 1);
26275
26581
  import { createHash as createHash11 } from "node:crypto";
26276
- import { existsSync as existsSync13, mkdirSync as mkdirSync5, readdirSync as readdirSync9, readFileSync as readFileSync11, renameSync, rmSync, statSync as statSync3, writeFileSync as writeFileSync6 } from "node:fs";
26277
- import { dirname as dirname7, join as join14 } from "node:path";
26582
+ import { existsSync as existsSync14, mkdirSync as mkdirSync6, readdirSync as readdirSync9, readFileSync as readFileSync12, renameSync, rmSync, statSync as statSync3, writeFileSync as writeFileSync7 } from "node:fs";
26583
+ import { dirname as dirname8, join as join15 } from "node:path";
26278
26584
  var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
26279
26585
  var SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
26280
26586
  var SKILL_DECISION_SCHEMA = "kxm.skill-decision.v1";
@@ -26376,24 +26682,24 @@ var SkillLifecycle = class {
26376
26682
  this.planned.push({ action: "write", target: file });
26377
26683
  return;
26378
26684
  }
26379
- mkdirSync5(dirname7(file), { recursive: true });
26380
- writeFileSync6(file, content);
26685
+ mkdirSync6(dirname8(file), { recursive: true });
26686
+ writeFileSync7(file, content);
26381
26687
  }
26382
26688
  dir(state) {
26383
- return join14(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
26689
+ return join15(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
26384
26690
  }
26385
26691
  historyFile(id) {
26386
- return join14(this.root, "history", `${id}.jsonl`);
26692
+ return join15(this.root, "history", `${id}.jsonl`);
26387
26693
  }
26388
26694
  paths(state, id) {
26389
- const dir = join14(this.dir(state), id);
26390
- return { dir, metadata: join14(dir, "metadata.json"), skill: join14(dir, "SKILL.md") };
26695
+ const dir = join15(this.dir(state), id);
26696
+ return { dir, metadata: join15(dir, "metadata.json"), skill: join15(dir, "SKILL.md") };
26391
26697
  }
26392
26698
  appendHistory(id, record2) {
26393
26699
  const line = `${JSON.stringify(record2)}
26394
26700
  `;
26395
- if (existsSync13(this.historyFile(id))) {
26396
- const existing = readFileSync11(this.historyFile(id), "utf8");
26701
+ if (existsSync14(this.historyFile(id))) {
26702
+ const existing = readFileSync12(this.historyFile(id), "utf8");
26397
26703
  const lines = existing.split("\n").filter((entry) => entry.trim());
26398
26704
  this.write(this.historyFile(id), [...lines.slice(-499), line.trim()].join("\n") + "\n");
26399
26705
  } else {
@@ -26402,28 +26708,28 @@ var SkillLifecycle = class {
26402
26708
  }
26403
26709
  history(id) {
26404
26710
  const file = this.historyFile(id);
26405
- if (!existsSync13(file)) return [];
26406
- return readFileSync11(file, "utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
26711
+ if (!existsSync14(file)) return [];
26712
+ return readFileSync12(file, "utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
26407
26713
  }
26408
26714
  readMetadata(state, id) {
26409
26715
  const { metadata } = this.paths(state, id);
26410
- if (!existsSync13(metadata)) {
26716
+ if (!existsSync14(metadata)) {
26411
26717
  throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${state}`);
26412
26718
  }
26413
- return JSON.parse(readFileSync11(metadata, "utf8"));
26719
+ return JSON.parse(readFileSync12(metadata, "utf8"));
26414
26720
  }
26415
26721
  move(from, to, id) {
26416
- const fromDir = join14(this.dir(from), id);
26417
- const toDir = join14(this.dir(to), id);
26418
- if (!existsSync13(fromDir)) {
26722
+ const fromDir = join15(this.dir(from), id);
26723
+ const toDir = join15(this.dir(to), id);
26724
+ if (!existsSync14(fromDir)) {
26419
26725
  throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${from}`);
26420
26726
  }
26421
26727
  if (this.dryRun) {
26422
26728
  this.planned.push({ action: "move", target: `${fromDir} -> ${toDir}` });
26423
26729
  return;
26424
26730
  }
26425
- mkdirSync5(this.dir(to), { recursive: true });
26426
- if (existsSync13(toDir)) rmSync(toDir, { recursive: true, force: true });
26731
+ mkdirSync6(this.dir(to), { recursive: true });
26732
+ if (existsSync14(toDir)) rmSync(toDir, { recursive: true, force: true });
26427
26733
  renameSync(fromDir, toDir);
26428
26734
  }
26429
26735
  /** Submit a new skill candidate. Content is redacted of secret material at
@@ -26466,7 +26772,7 @@ var SkillLifecycle = class {
26466
26772
  const contentSha256 = skillContentSha256(content);
26467
26773
  const id = skillIdFor(name, contentSha256);
26468
26774
  const { metadata, skill } = this.paths("candidate", id);
26469
- if (existsSync13(metadata)) {
26775
+ if (existsSync14(metadata)) {
26470
26776
  throw new SkillLifecycleError(
26471
26777
  "skill_candidate_exists",
26472
26778
  `identical candidate ${id} already exists; changed behavior requires changed content`
@@ -26575,11 +26881,11 @@ var SkillLifecycle = class {
26575
26881
  };
26576
26882
  const candidatePaths = this.paths("candidate", candidateId);
26577
26883
  const promotedPaths = this.paths("promoted", candidateId);
26578
- const skillContent = readFileSync11(candidatePaths.skill, "utf8");
26579
- const metadataContent = readFileSync11(candidatePaths.metadata, "utf8");
26884
+ const skillContent = readFileSync12(candidatePaths.skill, "utf8");
26885
+ const metadataContent = readFileSync12(candidatePaths.metadata, "utf8");
26580
26886
  this.write(promotedPaths.skill, skillContent);
26581
26887
  this.write(promotedPaths.metadata, metadataContent);
26582
- const patchPath = join14(this.root, "patches", `${candidateId}.patch`);
26888
+ const patchPath = join15(this.root, "patches", `${candidateId}.patch`);
26583
26889
  const relSkillPath = `.kxm/skills/promoted/${candidateId}/SKILL.md`;
26584
26890
  const relMetaPath = `.kxm/skills/promoted/${candidateId}/metadata.json`;
26585
26891
  const patch = `${createUnifiedPatch(relSkillPath, skillContent)}${createUnifiedPatch(relMetaPath, metadataContent)}`;
@@ -26607,7 +26913,7 @@ var SkillLifecycle = class {
26607
26913
  verify(state, id) {
26608
26914
  const metadata = this.readMetadata(state, id);
26609
26915
  const { skill } = this.paths(state, id);
26610
- const content = readFileSync11(skill, "utf8");
26916
+ const content = readFileSync12(skill, "utf8");
26611
26917
  if (skillContentSha256(content) !== metadata.contentSha256) {
26612
26918
  throw new SkillLifecycleError(
26613
26919
  "skill_integrity_violation",
@@ -26625,7 +26931,7 @@ var SkillLifecycle = class {
26625
26931
  }
26626
26932
  list(state) {
26627
26933
  const dir = this.dir(state);
26628
- if (!existsSync13(dir)) return [];
26934
+ if (!existsSync14(dir)) return [];
26629
26935
  const ids = readdirSorted(dir);
26630
26936
  return ids.map((id) => {
26631
26937
  try {
@@ -26638,7 +26944,7 @@ var SkillLifecycle = class {
26638
26944
  read(state, id) {
26639
26945
  const metadata = this.readMetadata(state, id);
26640
26946
  const { skill } = this.paths(state, id);
26641
- return { metadata, content: readFileSync11(skill, "utf8") };
26947
+ return { metadata, content: readFileSync12(skill, "utf8") };
26642
26948
  }
26643
26949
  };
26644
26950
  function boundedList(value, field) {
@@ -26653,7 +26959,7 @@ function boundedList(value, field) {
26653
26959
  return [...new Set(refs)];
26654
26960
  }
26655
26961
  function readdirSorted(dir) {
26656
- return readdirSync9(dir).filter((entry) => statSync3(join14(dir, entry)).isDirectory()).sort();
26962
+ return readdirSync9(dir).filter((entry) => statSync3(join15(dir, entry)).isDirectory()).sort();
26657
26963
  }
26658
26964
 
26659
26965
  // plugins/kxm/src/dispatch-context.ts
@@ -26694,7 +27000,7 @@ function contextRoleForAgent(agentId) {
26694
27000
  return agentId;
26695
27001
  }
26696
27002
  function dispatchContextPresent(projectRoot) {
26697
- return hasTopLevelMarkdown(join15(projectRoot, ".kxm", "memory")) || hasAnyEntry(join15(projectRoot, ".kxm", "skills", "promoted"));
27003
+ return hasTopLevelMarkdown(join16(projectRoot, ".kxm", "memory")) || hasAnyEntry(join16(projectRoot, ".kxm", "skills", "promoted"));
26698
27004
  }
26699
27005
  function hasTopLevelMarkdown(dir) {
26700
27006
  try {
@@ -26770,7 +27076,7 @@ function loadDispatchContextSources(input) {
26770
27076
  }
26771
27077
  const promoted = [];
26772
27078
  try {
26773
- const lifecycle = new SkillLifecycle(join15(projectRoot, ".kxm", "skills"));
27079
+ const lifecycle = new SkillLifecycle(join16(projectRoot, ".kxm", "skills"));
26774
27080
  for (const metadata of lifecycle.list("promoted")) {
26775
27081
  try {
26776
27082
  promoted.push(lifecycle.verify("promoted", metadata.id));
@@ -26853,18 +27159,18 @@ function assembleDispatchContext(sources, input) {
26853
27159
  }
26854
27160
 
26855
27161
  // plugins/kxm/src/engine-artifacts.ts
26856
- import { join as join16 } from "node:path";
27162
+ import { join as join17 } from "node:path";
26857
27163
 
26858
27164
  // plugins/kxm/src/artifacts-exist.ts
26859
27165
  import { lstatSync as lstatSync5, realpathSync as realpathSync4, statSync as statSync4 } from "node:fs";
26860
- import { isAbsolute as isAbsolute5, relative as relative4, resolve as resolve8 } from "node:path";
27166
+ import { isAbsolute as isAbsolute5, relative as relative4, resolve as resolve9 } from "node:path";
26861
27167
  function staysUnder(root, candidate) {
26862
27168
  const child = relative4(root, candidate);
26863
27169
  return child === "" || !isAbsolute5(child) && child !== ".." && !child.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`);
26864
27170
  }
26865
27171
  function verifyArtifactExists(rootInput, pathInput) {
26866
- const lexicalRoot = resolve8(rootInput);
26867
- const lexicalPath = resolve8(pathInput);
27172
+ const lexicalRoot = resolve9(rootInput);
27173
+ const lexicalPath = resolve9(pathInput);
26868
27174
  if (!staysUnder(lexicalRoot, lexicalPath)) {
26869
27175
  return { ok: false, error: "artifact_outside_workspace_assets", path: lexicalPath };
26870
27176
  }
@@ -26900,14 +27206,14 @@ function verifyArtifactExists(rootInput, pathInput) {
26900
27206
  // plugins/kxm/src/engine-artifacts.ts
26901
27207
  var kxmArtifactsGateSeams = {};
26902
27208
  function evaluateArtifactsGate(context, definition) {
26903
- const root = join16(context.projectRoot, ".kxm", "assets");
27209
+ const root = join17(context.projectRoot, ".kxm", "assets");
26904
27210
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
26905
27211
  const startTime = process.hrtime.bigint();
26906
27212
  let checkedCount = 0;
26907
27213
  let failedCount = 0;
26908
27214
  for (const [index, path] of definition.paths.entries()) {
26909
27215
  checkedCount += 1;
26910
- const result = verifyArtifactExists(root, join16(root, path));
27216
+ const result = verifyArtifactExists(root, join17(root, path));
26911
27217
  if (!result.ok) failedCount += 1;
26912
27218
  kxmArtifactsGateSeams.afterPathChecked?.({ path, index, checkedCount, failedCount });
26913
27219
  }
@@ -27052,8 +27358,8 @@ var CommandObserver = class {
27052
27358
  this.requestStop("error", "lost-close");
27053
27359
  }
27054
27360
  run() {
27055
- return new Promise((resolve11) => {
27056
- this.resolveOutcome = resolve11;
27361
+ return new Promise((resolve13) => {
27362
+ this.resolveOutcome = resolve13;
27057
27363
  try {
27058
27364
  this.start();
27059
27365
  } catch (error) {
@@ -28380,8 +28686,8 @@ var KxmRunScheduler = class _KxmRunScheduler {
28380
28686
  resolve: (_value) => void 0,
28381
28687
  reject: (_error) => void 0
28382
28688
  };
28383
- const settled = new Promise((resolve11, reject) => {
28384
- pending.resolve = resolve11;
28689
+ const settled = new Promise((resolve13, reject) => {
28690
+ pending.resolve = resolve13;
28385
28691
  pending.reject = reject;
28386
28692
  });
28387
28693
  void settled.then(void 0, () => void 0);
@@ -28920,9 +29226,9 @@ function readYamlFile(file) {
28920
29226
  return readModelDocument(file);
28921
29227
  }
28922
29228
  function readModelDocument(file) {
28923
- if (!existsSync14(file)) return void 0;
29229
+ if (!existsSync15(file)) return void 0;
28924
29230
  try {
28925
- const parsed = (0, import_yaml11.parse)(readFileSync12(file, "utf8"));
29231
+ const parsed = (0, import_yaml11.parse)(readFileSync13(file, "utf8"));
28926
29232
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
28927
29233
  return parsed;
28928
29234
  } catch {
@@ -28953,8 +29259,8 @@ function resolveProducerRoute(projectRoot, step, agentId) {
28953
29259
  }
28954
29260
  };
28955
29261
  }
28956
- const agentFile = findYamlBasename(join17(projectRoot, ".kxm", "agents"), agentId, "agent") ?? agentId;
28957
- const agent = readYamlFile(join17(projectRoot, ".kxm", "agents", `${agentFile}.yaml`));
29262
+ const agentFile = findYamlBasename(join18(projectRoot, ".kxm", "agents"), agentId, "agent") ?? agentId;
29263
+ const agent = readYamlFile(join18(projectRoot, ".kxm", "agents", `${agentFile}.yaml`));
28958
29264
  const role = typeof agent?.role === "string" ? agent.role : "";
28959
29265
  if (!role) {
28960
29266
  return {
@@ -28965,7 +29271,7 @@ function resolveProducerRoute(projectRoot, step, agentId) {
28965
29271
  }
28966
29272
  };
28967
29273
  }
28968
- const roleDoc = readYamlFile(join17(projectRoot, ".kxm", "roles", `${role}.yaml`));
29274
+ const roleDoc = readYamlFile(join18(projectRoot, ".kxm", "roles", `${role}.yaml`));
28969
29275
  const roster = Array.isArray(roleDoc?.roster) ? roleDoc.roster : void 0;
28970
29276
  if (!roster) {
28971
29277
  return {
@@ -28981,8 +29287,8 @@ function resolveProducerRoute(projectRoot, step, agentId) {
28981
29287
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
28982
29288
  const record2 = entry;
28983
29289
  if (typeof record2.route !== "string" || record2.route.length === 0) continue;
28984
- const routeFile = findYamlBasename(join17(projectRoot, ".kxm", "models"), record2.route, "route") ?? record2.route;
28985
- const modelPath = join17(projectRoot, ".kxm", "models", `${routeFile}.yaml`);
29290
+ const routeFile = findYamlBasename(join18(projectRoot, ".kxm", "models"), record2.route, "route") ?? record2.route;
29291
+ const modelPath = join18(projectRoot, ".kxm", "models", `${routeFile}.yaml`);
28986
29292
  const doc = readModelDocument(modelPath);
28987
29293
  if (!doc) {
28988
29294
  return {
@@ -31322,9 +31628,9 @@ var RuntimeHubClient = class {
31322
31628
 
31323
31629
  // plugins/kxm/src/hub-binding.ts
31324
31630
  import { spawnSync as spawnSync6 } from "node:child_process";
31325
- import { existsSync as existsSync15, mkdirSync as mkdirSync6, readFileSync as readFileSync13, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
31326
- import { homedir as homedir2 } from "node:os";
31327
- import { dirname as dirname8, isAbsolute as isAbsolute6, join as join18, resolve as resolve9 } from "node:path";
31631
+ import { existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync14, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync8 } from "node:fs";
31632
+ import { homedir as homedir3 } from "node:os";
31633
+ import { dirname as dirname9, isAbsolute as isAbsolute6, join as join19, resolve as resolve10 } from "node:path";
31328
31634
  var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
31329
31635
  var CloudTokenError = class extends Error {
31330
31636
  code;
@@ -31347,20 +31653,20 @@ function resolveUserStateRoot(env) {
31347
31653
  const explicit = env.KXM_STATE_HOME?.trim();
31348
31654
  if (explicit) {
31349
31655
  if (!isAbsolute6(explicit)) throw new HubBindingError("local_state_root_not_absolute");
31350
- return resolve9(explicit);
31656
+ return resolve10(explicit);
31351
31657
  }
31352
31658
  if (process.platform === "win32") {
31353
31659
  const localAppData = env.LOCALAPPDATA?.trim();
31354
- const base2 = localAppData && isAbsolute6(localAppData) ? localAppData : join18(homedir2(), "AppData", "Local");
31355
- return resolve9(base2, "KXM");
31660
+ const base2 = localAppData && isAbsolute6(localAppData) ? localAppData : join19(homedir3(), "AppData", "Local");
31661
+ return resolve10(base2, "KXM");
31356
31662
  }
31357
- if (process.platform === "darwin") return resolve9(homedir2(), "Library", "Application Support", "KXM");
31663
+ if (process.platform === "darwin") return resolve10(homedir3(), "Library", "Application Support", "KXM");
31358
31664
  const xdgState = env.XDG_STATE_HOME?.trim();
31359
- const base = xdgState && isAbsolute6(xdgState) ? xdgState : join18(homedir2(), ".local", "state");
31360
- return resolve9(base, "kxm");
31665
+ const base = xdgState && isAbsolute6(xdgState) ? xdgState : join19(homedir3(), ".local", "state");
31666
+ return resolve10(base, "kxm");
31361
31667
  }
31362
31668
  function hubBindingFile(env = process.env) {
31363
- return join18(resolveUserStateRoot(env), "hub-binding.json");
31669
+ return join19(resolveUserStateRoot(env), "hub-binding.json");
31364
31670
  }
31365
31671
  function validateHubUrl(raw) {
31366
31672
  let parsed;
@@ -31456,16 +31762,27 @@ function runTokenCommand(command, env) {
31456
31762
  }
31457
31763
  return stdout.trim();
31458
31764
  }
31765
+ function hubBindingScope(url) {
31766
+ let host;
31767
+ try {
31768
+ host = new URL(url).hostname.toLowerCase();
31769
+ } catch {
31770
+ return "remote";
31771
+ }
31772
+ if (host === "localhost" || host === "::1" || host === "[::1]" || host.endsWith(".localhost")) return "loopback";
31773
+ const v4 = /^127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/.exec(host);
31774
+ return v4 && [v4[1], v4[2], v4[3]].every((part) => Number(part) <= 255) ? "loopback" : "remote";
31775
+ }
31459
31776
  function isIsoTimestamp(value) {
31460
31777
  if (Number.isNaN(Date.parse(value))) return false;
31461
31778
  return value === new Date(value).toISOString();
31462
31779
  }
31463
31780
  function readHubBinding(env = process.env) {
31464
31781
  const file = hubBindingFile(env);
31465
- if (!existsSync15(file)) return void 0;
31782
+ if (!existsSync16(file)) return void 0;
31466
31783
  let parsed;
31467
31784
  try {
31468
- parsed = JSON.parse(readFileSync13(file, "utf8"));
31785
+ parsed = JSON.parse(readFileSync14(file, "utf8"));
31469
31786
  } catch {
31470
31787
  throw new HubBindingError(`malformed hub binding at ${file}`);
31471
31788
  }
@@ -31516,12 +31833,197 @@ function readHubBinding(env = process.env) {
31516
31833
  }
31517
31834
 
31518
31835
  // plugins/kxm/src/hub-env.ts
31519
- import { existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync14, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
31520
- import { homedir as homedir3 } from "node:os";
31521
- import { dirname as dirname9, isAbsolute as isAbsolute7, join as join19, resolve as resolve10 } from "node:path";
31836
+ import { existsSync as existsSync18, mkdirSync as mkdirSync8, readFileSync as readFileSync16, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync9 } from "node:fs";
31837
+ import { homedir as homedir4 } from "node:os";
31838
+ import { dirname as dirname11, isAbsolute as isAbsolute7, join as join21, resolve as resolve12 } from "node:path";
31522
31839
 
31523
- // plugins/kxm/src/project-name.ts
31840
+ // plugins/kxm/src/hub-identity.ts
31524
31841
  var import_yaml12 = __toESM(require_dist(), 1);
31842
+ import { spawnSync as spawnSync7 } from "node:child_process";
31843
+ import { existsSync as existsSync17, readFileSync as readFileSync15 } from "node:fs";
31844
+ import { basename as basename4, dirname as dirname10, join as join20, resolve as resolve11 } from "node:path";
31845
+ var OP_TIMEOUT_MS = 15e3;
31846
+ var OP_MAX_BUFFER = 4096;
31847
+ function normalizeUrl(raw) {
31848
+ try {
31849
+ return validateHubUrl(raw);
31850
+ } catch {
31851
+ return void 0;
31852
+ }
31853
+ }
31854
+ function projectYamlId(start) {
31855
+ let dir = resolve11(start);
31856
+ for (; ; ) {
31857
+ const file = join20(dir, ".kxm", "project.yaml");
31858
+ if (existsSync17(file)) {
31859
+ try {
31860
+ const doc = (0, import_yaml12.parse)(readFileSync15(file, "utf8"));
31861
+ if (doc && typeof doc === "object" && !Array.isArray(doc) && typeof doc.id === "string" && doc.id.trim()) {
31862
+ return doc.id.trim();
31863
+ }
31864
+ } catch {
31865
+ }
31866
+ return void 0;
31867
+ }
31868
+ const parent = dirname10(dir);
31869
+ if (parent === dir) return void 0;
31870
+ dir = parent;
31871
+ }
31872
+ }
31873
+ function packageName(cwd) {
31874
+ try {
31875
+ const pkg = JSON.parse(readFileSync15(join20(cwd, "package.json"), "utf8"));
31876
+ if (typeof pkg.name === "string" && pkg.name.trim().length > 0) return pkg.name.trim();
31877
+ } catch {
31878
+ }
31879
+ return void 0;
31880
+ }
31881
+ function activeBinding(env) {
31882
+ try {
31883
+ return readHubBinding(env);
31884
+ } catch (error) {
31885
+ if (error instanceof HubBindingError) return void 0;
31886
+ throw error;
31887
+ }
31888
+ }
31889
+ function endpointFor(mode, settings) {
31890
+ return mode === "cloud" ? settings.cloud : settings.local;
31891
+ }
31892
+ function resolveProjectIdentity(cwd, env = process.env, explicit) {
31893
+ const fromExplicit = explicit?.trim();
31894
+ if (fromExplicit) return { project: fromExplicit, source: "flag", sourceLabel: "--project" };
31895
+ const fromEnv = env.KXM_PROJECT?.trim();
31896
+ if (fromEnv) return { project: fromEnv, source: "env", sourceLabel: "KXM_PROJECT" };
31897
+ const settings = loadHubSettings(cwd, env);
31898
+ const mode = settings.mode ?? (activeBinding(env)?.cloud ? "cloud" : "local");
31899
+ const fromConfig = endpointFor(mode, settings)?.project?.trim();
31900
+ if (fromConfig) {
31901
+ return { project: fromConfig, source: "config", sourceLabel: `.kxm/config.yaml hub.${mode}.project` };
31902
+ }
31903
+ const fromProject = projectYamlId(cwd);
31904
+ if (fromProject) return { project: fromProject, source: "project.yaml", sourceLabel: ".kxm/project.yaml id" };
31905
+ const fromPackage = packageName(cwd);
31906
+ if (fromPackage) return { project: fromPackage, source: "package.json", sourceLabel: "package.json name" };
31907
+ return { project: basename4(cwd), source: "directory", sourceLabel: "directory name" };
31908
+ }
31909
+ function opReferenceFromTokenCommand(command) {
31910
+ try {
31911
+ const args = splitTokenCommand(command);
31912
+ if (args[0] === "op" && args[1] === "read" && args[2] && isHubOpReference(args[2])) return args[2];
31913
+ } catch {
31914
+ return void 0;
31915
+ }
31916
+ return void 0;
31917
+ }
31918
+ function defaultOpRead(reference, env) {
31919
+ if (!isHubOpReference(reference)) {
31920
+ throw new CloudTokenError("cloud_token_command_invalid", `refusing to resolve ${reference}; an op:// reference is required`);
31921
+ }
31922
+ const result = spawnSync7("op", ["read", reference], {
31923
+ encoding: "utf8",
31924
+ shell: false,
31925
+ timeout: OP_TIMEOUT_MS,
31926
+ maxBuffer: OP_MAX_BUFFER,
31927
+ env,
31928
+ windowsHide: true
31929
+ });
31930
+ if (result.error || result.status !== 0) {
31931
+ throw new CloudTokenError(
31932
+ "cloud_token_command_failed",
31933
+ `op read failed for ${reference}; the token was not saved`
31934
+ );
31935
+ }
31936
+ const line = (result.stdout ?? "").trim();
31937
+ if (!line || line.split(/\r?\n/).length !== 1) {
31938
+ throw new CloudTokenError(
31939
+ "cloud_token_command_failed",
31940
+ `op read did not print a single token for ${reference}; the token was not saved`
31941
+ );
31942
+ }
31943
+ return line;
31944
+ }
31945
+ function resolveKeyReference(ref, env, opRead = defaultOpRead) {
31946
+ if (!ref) return void 0;
31947
+ if (ref.env) {
31948
+ const value = env[ref.env]?.trim();
31949
+ if (value) return { value, source: `env:${ref.env}` };
31950
+ }
31951
+ if (ref.op) {
31952
+ const value = opRead(ref.op, env).trim();
31953
+ if (!value || value.split(/\r?\n/).length !== 1) {
31954
+ throw new CloudTokenError("cloud_token_command_failed", `op read did not print a single token for ${ref.op}`);
31955
+ }
31956
+ return { value, source: `op:${ref.op}` };
31957
+ }
31958
+ return void 0;
31959
+ }
31960
+ function keySourceFor(input) {
31961
+ const ref = input.endpoint?.key;
31962
+ if (input.mode === "local" && input.env.KXM_AUTH_TOKEN?.trim()) return "env:KXM_AUTH_TOKEN";
31963
+ if (ref?.env && input.env[ref.env]?.trim()) return `env:${ref.env}`;
31964
+ if (ref?.op) return `op:${ref.op}`;
31965
+ if (ref?.env) return `env:${ref.env}`;
31966
+ if (input.mode === "cloud") {
31967
+ if (input.binding?.tokenEnv) return `env:${input.binding.tokenEnv}`;
31968
+ if (input.binding?.tokenCommand) {
31969
+ const op = opReferenceFromTokenCommand(input.binding.tokenCommand);
31970
+ return op ? `op:${op}` : "command";
31971
+ }
31972
+ return "missing";
31973
+ }
31974
+ if (input.hasSavedProjectToken?.(input.project)) return "hub-env";
31975
+ return "missing";
31976
+ }
31977
+ function describeHubConnection(cwd, env = process.env, hooks = {}) {
31978
+ const settings = loadHubSettings(cwd, env);
31979
+ const binding = activeBinding(env);
31980
+ const mode = settings.mode ?? (binding?.cloud ? "cloud" : "local");
31981
+ const modeSource = settings.mode ? "config" : binding?.cloud ? "binding" : "default";
31982
+ const endpoint = endpointFor(mode, settings);
31983
+ const fromEnv = env.KXM_SERVER_URL?.trim();
31984
+ const fromConfig = endpoint?.url?.trim();
31985
+ const fromBinding = binding?.url;
31986
+ let url = "http://127.0.0.1:7331";
31987
+ let urlSource = "default";
31988
+ if (fromEnv) {
31989
+ url = fromEnv.replace(/\/$/, "");
31990
+ urlSource = "env";
31991
+ } else if (fromConfig) {
31992
+ url = fromConfig.replace(/\/$/, "");
31993
+ urlSource = "config";
31994
+ } else if (fromBinding) {
31995
+ url = fromBinding;
31996
+ urlSource = "binding";
31997
+ }
31998
+ const identity = resolveProjectIdentity(cwd, env, hooks.explicitProject);
31999
+ const configuredCloudUrl = settings.cloud?.url ?? (binding?.cloud ? binding.url : void 0);
32000
+ let scope;
32001
+ if (mode === "cloud") {
32002
+ const override = fromEnv ? normalizeUrl(fromEnv) : void 0;
32003
+ const named = configuredCloudUrl ? normalizeUrl(configuredCloudUrl) : void 0;
32004
+ scope = override && named && override !== named ? hubBindingScope(url) : "remote";
32005
+ } else {
32006
+ scope = hubBindingScope(url);
32007
+ }
32008
+ return {
32009
+ ...identity,
32010
+ mode,
32011
+ modeSource,
32012
+ url,
32013
+ urlSource,
32014
+ scope,
32015
+ ...endpoint ? { endpoint } : {},
32016
+ ...binding ? { binding } : {},
32017
+ keySource: keySourceFor({
32018
+ mode,
32019
+ env,
32020
+ ...endpoint ? { endpoint } : {},
32021
+ ...binding ? { binding } : {},
32022
+ project: identity.project,
32023
+ ...hooks.hasSavedProjectToken ? { hasSavedProjectToken: hooks.hasSavedProjectToken } : {}
32024
+ })
32025
+ };
32026
+ }
31525
32027
 
31526
32028
  // plugins/kxm/src/hub-env.ts
31527
32029
  var HUB_ENV_SCHEMA = "kxm.hub-env.v1";
@@ -31535,27 +32037,27 @@ function resolveUserStateRoot2(env) {
31535
32037
  const explicit = env.KXM_STATE_HOME?.trim();
31536
32038
  if (explicit) {
31537
32039
  if (!isAbsolute7(explicit)) throw new HubEnvError("local_state_root_not_absolute");
31538
- return resolve10(explicit);
32040
+ return resolve12(explicit);
31539
32041
  }
31540
32042
  if (process.platform === "win32") {
31541
32043
  const localAppData = env.LOCALAPPDATA?.trim();
31542
- const base2 = localAppData && isAbsolute7(localAppData) ? localAppData : join19(homedir3(), "AppData", "Local");
31543
- return resolve10(base2, "KXM");
32044
+ const base2 = localAppData && isAbsolute7(localAppData) ? localAppData : join21(homedir4(), "AppData", "Local");
32045
+ return resolve12(base2, "KXM");
31544
32046
  }
31545
- if (process.platform === "darwin") return resolve10(homedir3(), "Library", "Application Support", "KXM");
32047
+ if (process.platform === "darwin") return resolve12(homedir4(), "Library", "Application Support", "KXM");
31546
32048
  const xdgState = env.XDG_STATE_HOME?.trim();
31547
- const base = xdgState && isAbsolute7(xdgState) ? xdgState : join19(homedir3(), ".local", "state");
31548
- return resolve10(base, "kxm");
32049
+ const base = xdgState && isAbsolute7(xdgState) ? xdgState : join21(homedir4(), ".local", "state");
32050
+ return resolve12(base, "kxm");
31549
32051
  }
31550
32052
  function hubEnvFile(env = process.env) {
31551
- return join19(resolveUserStateRoot2(env), "hub-env.json");
32053
+ return join21(resolveUserStateRoot2(env), "hub-env.json");
31552
32054
  }
31553
32055
  function readHubEnvRecord(env = process.env) {
31554
32056
  const file = hubEnvFile(env);
31555
- if (!existsSync16(file)) return void 0;
32057
+ if (!existsSync18(file)) return void 0;
31556
32058
  let parsed;
31557
32059
  try {
31558
- parsed = JSON.parse(readFileSync14(file, "utf8"));
32060
+ parsed = JSON.parse(readFileSync16(file, "utf8"));
31559
32061
  } catch (error) {
31560
32062
  throw new HubEnvError(`hub env file is malformed at ${file}: ${error instanceof Error ? error.message : String(error)}`);
31561
32063
  }
@@ -31587,31 +32089,31 @@ function readHubEnvRecord(env = process.env) {
31587
32089
  ...record2.projectTokens !== void 0 ? { projectTokens: record2.projectTokens } : {}
31588
32090
  };
31589
32091
  }
31590
- function activeCloudBinding(env) {
31591
- try {
31592
- const binding = readHubBinding(env);
31593
- return binding?.cloud ? binding : void 0;
31594
- } catch (error) {
31595
- if (error instanceof HubBindingError) {
31596
- throw new HubEnvError(
31597
- `${error.message}; refusing to guess a credential \u2014 repair or remove ${hubBindingFile(env)}`
31598
- );
31599
- }
31600
- throw error;
31601
- }
32092
+ function cloudModeToken(cwd, env, explicitProject, opRead) {
32093
+ const connection = describeHubConnection(cwd, env, explicitProject === void 0 ? {} : { explicitProject });
32094
+ if (connection.mode !== "cloud") return void 0;
32095
+ const fromConfig = resolveKeyReference(connection.endpoint?.key, env, opRead);
32096
+ if (fromConfig) return fromConfig.value;
32097
+ if (connection.binding?.cloud) return resolveCloudHubToken(connection.binding, env);
32098
+ throw new CloudTokenError(
32099
+ "cloud_token_missing",
32100
+ "cloud hub token is missing; the local hub-env token was not used"
32101
+ );
31602
32102
  }
31603
- function resolveClientHubAuthToken(env, project) {
31604
- const cloud = activeCloudBinding(env);
31605
- if (cloud) return resolveCloudHubToken(cloud, env);
32103
+ function resolveClientHubAuthToken(env, project, cwd = process.cwd(), opRead) {
32104
+ const cloud = cloudModeToken(cwd, env, void 0, opRead);
32105
+ if (cloud) return cloud;
31606
32106
  const envToken = env.KXM_AUTH_TOKEN?.trim();
31607
32107
  if (envToken) return envToken;
32108
+ const fromConfig = resolveKeyReference(describeHubConnection(cwd, env).endpoint?.key, env, opRead);
32109
+ if (fromConfig) return fromConfig.value;
31608
32110
  const record2 = readHubEnvRecord(env);
31609
32111
  return record2?.projectTokens?.[project]?.trim() || record2?.authToken?.trim() || void 0;
31610
32112
  }
31611
32113
 
31612
32114
  // plugins/kxm/src/logger.ts
31613
- import { appendFileSync, existsSync as existsSync17, mkdirSync as mkdirSync8, renameSync as renameSync4, statSync as statSync5, unlinkSync as unlinkSync2 } from "node:fs";
31614
- import { dirname as dirname10 } from "node:path";
32115
+ import { appendFileSync, existsSync as existsSync19, mkdirSync as mkdirSync9, renameSync as renameSync4, statSync as statSync5, unlinkSync as unlinkSync2 } from "node:fs";
32116
+ import { dirname as dirname12 } from "node:path";
31615
32117
  var LOG_LEVEL_PRIORITY = {
31616
32118
  debug: 10,
31617
32119
  info: 20,
@@ -31648,7 +32150,7 @@ function redactLogValue(val, key) {
31648
32150
  function rotateLogFiles(filePath, maxFiles) {
31649
32151
  for (let i = maxFiles; i >= 1; i--) {
31650
32152
  const current = `${filePath}.${i}`;
31651
- if (existsSync17(current)) {
32153
+ if (existsSync19(current)) {
31652
32154
  if (i >= maxFiles) {
31653
32155
  try {
31654
32156
  unlinkSync2(current);
@@ -31662,7 +32164,7 @@ function rotateLogFiles(filePath, maxFiles) {
31662
32164
  }
31663
32165
  }
31664
32166
  }
31665
- if (existsSync17(filePath)) {
32167
+ if (existsSync19(filePath)) {
31666
32168
  try {
31667
32169
  renameSync4(filePath, `${filePath}.1`);
31668
32170
  } catch {
@@ -31679,7 +32181,7 @@ function createLogger(options) {
31679
32181
  const shouldStdout = options.stdout ?? !isDaemon;
31680
32182
  const correlationDefaults = options.correlation ?? {};
31681
32183
  let currentSize = 0;
31682
- if (filePath && existsSync17(filePath)) {
32184
+ if (filePath && existsSync19(filePath)) {
31683
32185
  try {
31684
32186
  currentSize = statSync5(filePath).size;
31685
32187
  } catch {
@@ -31717,7 +32219,7 @@ function createLogger(options) {
31717
32219
  currentSize = 0;
31718
32220
  }
31719
32221
  try {
31720
- mkdirSync8(dirname10(filePath), { recursive: true });
32222
+ mkdirSync9(dirname12(filePath), { recursive: true });
31721
32223
  appendFileSync(filePath, line, { encoding: "utf8", mode: 384 });
31722
32224
  currentSize += lineBytes;
31723
32225
  } catch {
@@ -31760,13 +32262,13 @@ function createLogger(options) {
31760
32262
 
31761
32263
  // plugins/kxm/src/runtime-supervisor.ts
31762
32264
  function kxmSupervisorTokenFile(paths) {
31763
- return join20(paths.runtimeDir, "supervisor.token");
32265
+ return join22(paths.runtimeDir, "supervisor.token");
31764
32266
  }
31765
32267
  function publishKxmSupervisorToken(paths, token) {
31766
32268
  const file = kxmSupervisorTokenFile(paths);
31767
- mkdirSync9(dirname11(file), { recursive: true, mode: 448 });
32269
+ mkdirSync10(dirname13(file), { recursive: true, mode: 448 });
31768
32270
  const temp = `${file}.${process.pid}.tmp`;
31769
- writeFileSync9(temp, `${token}
32271
+ writeFileSync10(temp, `${token}
31770
32272
  `, { encoding: "utf8", mode: 384 });
31771
32273
  try {
31772
32274
  chmodSync2(temp, 384);
@@ -31788,7 +32290,7 @@ function readKxmSupervisorToken(paths) {
31788
32290
  if (stat.isSymbolicLink() || !stat.isFile()) {
31789
32291
  throw runtimeError("runtime_path_invalid", file, "supervisor token file must be a regular file, not a link");
31790
32292
  }
31791
- const token = readFileSync15(file, "utf8").trim();
32293
+ const token = readFileSync17(file, "utf8").trim();
31792
32294
  return token.length >= 32 ? token : void 0;
31793
32295
  }
31794
32296
  function processAlive(pid) {
@@ -31802,16 +32304,16 @@ function processAlive(pid) {
31802
32304
  var HEARTBEAT_STALE_MS = 15e3;
31803
32305
  var SUPERVISOR_ERROR_MAX_AGE_MS = 3e4;
31804
32306
  function supervisorErrorFile(paths) {
31805
- return join20(paths.runtimeDir, "supervisor.error");
32307
+ return join22(paths.runtimeDir, "supervisor.error");
31806
32308
  }
31807
32309
  function clearSupervisorError(paths) {
31808
32310
  const file = supervisorErrorFile(paths);
31809
- if (existsSync18(file)) rmSync4(file, { force: true });
32311
+ if (existsSync20(file)) rmSync4(file, { force: true });
31810
32312
  }
31811
32313
  function recordSupervisorError(paths, message) {
31812
32314
  try {
31813
- mkdirSync9(paths.runtimeDir, { recursive: true, mode: 448 });
31814
- writeFileSync9(supervisorErrorFile(paths), `${message}
32315
+ mkdirSync10(paths.runtimeDir, { recursive: true, mode: 448 });
32316
+ writeFileSync10(supervisorErrorFile(paths), `${message}
31815
32317
  `, { encoding: "utf8", mode: 384 });
31816
32318
  } catch {
31817
32319
  }
@@ -31823,7 +32325,7 @@ function readRecentSupervisorError(paths) {
31823
32325
  const ageMs = Date.now() - stat.mtimeMs;
31824
32326
  if (ageMs > SUPERVISOR_ERROR_MAX_AGE_MS) return void 0;
31825
32327
  try {
31826
- return readFileSync15(file, "utf8").trim();
32328
+ return readFileSync17(file, "utf8").trim();
31827
32329
  } catch {
31828
32330
  return void 0;
31829
32331
  }
@@ -31862,7 +32364,7 @@ function supervisorStatusOf(record2) {
31862
32364
  };
31863
32365
  }
31864
32366
  function kxmSupervisorStatus(paths, options = {}) {
31865
- if (!existsSync18(paths.registryDb)) return { running: false };
32367
+ if (!existsSync20(paths.registryDb)) return { running: false };
31866
32368
  if (options.readOnly) {
31867
32369
  const database = openReadOnlyDatabase(paths.registryDb);
31868
32370
  try {
@@ -31928,7 +32430,7 @@ async function ensureKxmSupervisor(options = {}) {
31928
32430
  throw runtimeError("runtime_supervisor_unreachable", paths.registryDb, `runtime supervisor pid ${status.pid} is registered as running but cannot be probed`);
31929
32431
  }
31930
32432
  clearSupervisorError(paths);
31931
- const scriptPath = join20(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
32433
+ const scriptPath = join22(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
31932
32434
  const spawnImpl = options.spawnImpl ?? ((script, env) => {
31933
32435
  const child = spawn3(process.execPath, [script], {
31934
32436
  detached: true,
@@ -32013,8 +32515,8 @@ async function waitForDriveSessions(settled, graceMs) {
32013
32515
  try {
32014
32516
  await Promise.race([
32015
32517
  Promise.allSettled(settled),
32016
- new Promise((resolve11) => {
32017
- timeout = setTimeout(resolve11, graceMs);
32518
+ new Promise((resolve13) => {
32519
+ timeout = setTimeout(resolve13, graceMs);
32018
32520
  timeout.unref?.();
32019
32521
  })
32020
32522
  ]);
@@ -32151,7 +32653,7 @@ function syncFailureText(error) {
32151
32653
  return `${code ? `${code}: ` : ""}${message}`.replace(/(kxm_[A-Za-z0-9_]+|[A-Za-z0-9._-]{40,})/g, "[redacted]").slice(0, 300);
32152
32654
  }
32153
32655
  function runtimeSupervisorLogFile(paths) {
32154
- return join20(paths.runtimeDir, "logs", "kxm-runtime.jsonl");
32656
+ return join22(paths.runtimeDir, "logs", "kxm-runtime.jsonl");
32155
32657
  }
32156
32658
  async function startKxmRuntimeSupervisor(options = {}) {
32157
32659
  const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
@@ -32167,8 +32669,8 @@ async function startKxmRuntimeSupervisor(options = {}) {
32167
32669
  }
32168
32670
  }
32169
32671
  async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now, env) {
32170
- mkdirSync9(paths.runtimeDir, { recursive: true, mode: 448 });
32171
- mkdirSync9(paths.projectsDir, { recursive: true, mode: 448 });
32672
+ mkdirSync10(paths.runtimeDir, { recursive: true, mode: 448 });
32673
+ mkdirSync10(paths.projectsDir, { recursive: true, mode: 448 });
32172
32674
  const logger = createLogger({
32173
32675
  component: "runtime",
32174
32676
  path: runtimeSupervisorLogFile(paths),
@@ -32280,8 +32782,8 @@ async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now, e
32280
32782
  openRunIds = unsettledRunIds(existing2);
32281
32783
  } else {
32282
32784
  const registration = registry.projectByRoot(projectRoot);
32283
- const eventsPath = join20(paths.projectsDir, registration?.projectKey ?? projectRuntimeKey(projectRoot), "run-events.db");
32284
- if (registration && existsSync18(eventsPath)) {
32785
+ const eventsPath = join22(paths.projectsDir, registration?.projectKey ?? projectRuntimeKey(projectRoot), "run-events.db");
32786
+ if (registration && existsSync20(eventsPath)) {
32285
32787
  const store = new KxmRunEventStore(eventsPath);
32286
32788
  try {
32287
32789
  openRunIds = store.runsForProject(registration.projectId, 1e4).filter((run) => !SETTLED_RUN_STATUS.has(run.status)).map((run) => run.runId);