@kontextmind/kxm 0.7.150 → 0.7.151

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.
@@ -3835,7 +3835,7 @@ var require_fast_uri = __commonJS({
3835
3835
  normalizeString(uri, options);
3836
3836
  } else if (typeof uri === "object") {
3837
3837
  uri = /** @type {T} */
3838
- parse9(serialize(uri, options), options);
3838
+ parse10(serialize(uri, options), options);
3839
3839
  }
3840
3840
  return uri;
3841
3841
  }
@@ -3875,8 +3875,8 @@ var require_fast_uri = __commonJS({
3875
3875
  function resolveComponent(base, relative5, options, skipNormalization) {
3876
3876
  const target = {};
3877
3877
  if (!skipNormalization) {
3878
- base = parse9(serialize(base, options), options);
3879
- relative5 = parse9(serialize(relative5, options), options);
3878
+ base = parse10(serialize(base, options), options);
3879
+ relative5 = parse10(serialize(relative5, options), options);
3880
3880
  }
3881
3881
  options = options || {};
3882
3882
  if (!options.tolerant && relative5.scheme) {
@@ -4168,7 +4168,7 @@ var require_fast_uri = __commonJS({
4168
4168
  }
4169
4169
  return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
4170
4170
  }
4171
- function parse9(uri, opts) {
4171
+ function parse10(uri, opts) {
4172
4172
  return parseWithStatus(uri, opts).parsed;
4173
4173
  }
4174
4174
  function normalizeString(uri, opts) {
@@ -4205,7 +4205,7 @@ var require_fast_uri = __commonJS({
4205
4205
  resolveComponent,
4206
4206
  equal,
4207
4207
  serialize,
4208
- parse: parse9
4208
+ parse: parse10
4209
4209
  };
4210
4210
  module.exports = fastUri;
4211
4211
  module.exports.default = fastUri;
@@ -14678,7 +14678,7 @@ var require_public_api = __commonJS({
14678
14678
  }
14679
14679
  return doc;
14680
14680
  }
14681
- function parse9(src, reviver, options) {
14681
+ function parse10(src, reviver, options) {
14682
14682
  let _reviver = void 0;
14683
14683
  if (typeof reviver === "function") {
14684
14684
  _reviver = reviver;
@@ -14719,7 +14719,7 @@ var require_public_api = __commonJS({
14719
14719
  return value.toString(options);
14720
14720
  return new Document.Document(value, _replacer, options).toString(options);
14721
14721
  }
14722
- exports.parse = parse9;
14722
+ exports.parse = parse10;
14723
14723
  exports.parseAllDocuments = parseAllDocuments;
14724
14724
  exports.parseDocument = parseDocument3;
14725
14725
  exports.stringify = stringify7;
@@ -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 existsSync17, lstatSync as lstatSync6, mkdirSync as mkdirSync9, readFileSync as readFileSync14, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "node:fs";
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";
14785
14785
  import { createServer } from "node:http";
14786
- import { dirname as dirname11, isAbsolute as isAbsolute8, join as join19 } from "node:path";
14786
+ import { dirname as dirname11, isAbsolute as isAbsolute8, join as join20 } from "node:path";
14787
14787
 
14788
14788
  // plugins/kxm/src/repo-root.ts
14789
14789
  import { existsSync } from "node:fs";
@@ -15000,7 +15000,7 @@ var TOOL_KEYS = Object.freeze(["preset", "allow", "deny"]);
15000
15000
  var TEMPLATE_KEYS = Object.freeze(["template", "schema"]);
15001
15001
  var POLICY_KEYS = Object.freeze(["vendorIndependenceRequired", "maxTransitions", "requiresGateVerification", "fallback"]);
15002
15002
  var FALLBACK_KEYS = Object.freeze(["onError", "maxSwitches", "revert"]);
15003
- var FALLBACK_ERRORS = Object.freeze(["rate_limit", "transport", "provider_unavailable"]);
15003
+ var FALLBACK_ERRORS = Object.freeze(["rate_limit", "transport", "provider_unavailable", "context_overflow"]);
15004
15004
  var FALLBACK_REVERT = Object.freeze(["next_run", "never"]);
15005
15005
  var ROSTER_ENTRY_KEYS = Object.freeze(["route", "effort", "mode"]);
15006
15006
  var CRITIC_PURPOSES = Object.freeze(["reviewer-arch", "reviewer-cli"]);
@@ -15329,7 +15329,7 @@ function validateRoleShape(document, id, label, issues) {
15329
15329
  if (!closedObject(fallback, FALLBACK_KEYS, path, issues)) return;
15330
15330
  if (fallback.onError !== void 0) {
15331
15331
  if (!Array.isArray(fallback.onError) || new Set(fallback.onError).size !== fallback.onError.length || fallback.onError.some((item) => !FALLBACK_ERRORS.includes(item))) {
15332
- issues.push(issue2("schema", "schema_enum", path, "onError must be unique rate_limit, transport, or provider_unavailable values"));
15332
+ issues.push(issue2("schema", "schema_enum", path, "onError must be unique rate_limit, transport, provider_unavailable, or context_overflow values"));
15333
15333
  }
15334
15334
  }
15335
15335
  if (fallback.maxSwitches !== void 0 && (!Number.isInteger(fallback.maxSwitches) || fallback.maxSwitches < 0)) {
@@ -17969,8 +17969,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
17969
17969
  const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
17970
17970
  if (maxWriteRepositories > writable) issues.push(issue3("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
17971
17971
  }
17972
- const join20 = objectValue(step.join);
17973
- const minimumPassed = join20 && typeof join20.minimumPassed === "number" ? join20.minimumPassed : void 0;
17972
+ const join21 = objectValue(step.join);
17973
+ const minimumPassed = join21 && typeof join21.minimumPassed === "number" ? join21.minimumPassed : void 0;
17974
17974
  if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue3("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
17975
17975
  const distinctBy = names(assignment?.distinctBy);
17976
17976
  if (distinctBy.length > 0) {
@@ -17991,10 +17991,10 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
17991
17991
  }
17992
17992
  const policy = objectValue(requirement.producerPolicy);
17993
17993
  if (!policy) continue;
17994
- const eligible = names(policy.eligibleAgents);
17994
+ const eligible2 = names(policy.eligibleAgents);
17995
17995
  const producerMinimum = numberValue(policy.minimumProducers, 1);
17996
- if (producerMinimum > target || producerMinimum > eligible.length) issues.push(issue3("semantic", "producer_minimum_impossible", file, `${stepId}.${String(key)} producer minimum exceeds its eligible or target pool`));
17997
- for (const agentId of eligible) {
17996
+ if (producerMinimum > target || producerMinimum > eligible2.length) issues.push(issue3("semantic", "producer_minimum_impossible", file, `${stepId}.${String(key)} producer minimum exceeds its eligible or target pool`));
17997
+ for (const agentId of eligible2) {
17998
17998
  if (!lookupKxmResource(agents.values(), agentId, "agent")) issues.push(issue3("reference", "producer_agent_unknown", file, `${stepId}.${String(key)} references unknown producer ${agentId}`));
17999
17999
  if (allowedAgents.length > 0 && !allowedAgents.includes(agentId)) issues.push(issue3("semantic", "producer_agent_ineligible", file, `${stepId}.${String(key)} producer ${agentId} is outside allowedAgents`));
18000
18000
  }
@@ -21530,6 +21530,7 @@ function foldKxmRunState(run, plan, events, options = {}) {
21530
21530
  foldEffectUncertain(state, plan, event);
21531
21531
  break;
21532
21532
  case "routing.attempt.recorded":
21533
+ case "routing.route_switched":
21533
21534
  break;
21534
21535
  default:
21535
21536
  throw runtimeError("run_events_illegal", run.runId, `event type ${event.eventType} is not legal in this engine slice`);
@@ -22549,7 +22550,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
22549
22550
  const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
22550
22551
  const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
22551
22552
  const assignments = compileAssignments(step, id, agent, sink);
22552
- const join20 = compileJoin(step, id, sink);
22553
+ const join21 = compileJoin(step, id, sink);
22553
22554
  const requiredEvidence = compileEvidence(step, id, sink);
22554
22555
  const transitions = compileTransitions(step, id, index, stepIndex, sink);
22555
22556
  const outcomes = Object.keys(transitions).sort(compareCodeUnits5);
@@ -22577,7 +22578,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
22577
22578
  transitions: orderedTransitions,
22578
22579
  requiresPlanHash: requirePlanHash.includes(id),
22579
22580
  assignments,
22580
- join: join20
22581
+ join: join21
22581
22582
  };
22582
22583
  if (kind === "agent" || kind === "moa") {
22583
22584
  if (!agent) return void 0;
@@ -22627,15 +22628,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
22627
22628
  };
22628
22629
  }
22629
22630
  function compileJoin(step, stepId, sink) {
22630
- const join20 = objectValue2(step.join);
22631
- if (!join20) return { strategy: "all" };
22632
- const declared = stringValue2(join20.strategy);
22631
+ const join21 = objectValue2(step.join);
22632
+ if (!join21) return { strategy: "all" };
22633
+ const declared = stringValue2(join21.strategy);
22633
22634
  const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
22634
- const minimumPassed = compileOptionalCount(join20.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
22635
+ const minimumPassed = compileOptionalCount(join21.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
22635
22636
  const compiled = {
22636
22637
  strategy,
22637
22638
  ...minimumPassed !== void 0 ? { minimumPassed } : {},
22638
- ...typeof join20.cancelRemaining === "boolean" ? { cancelRemaining: join20.cancelRemaining } : {}
22639
+ ...typeof join21.cancelRemaining === "boolean" ? { cancelRemaining: join21.cancelRemaining } : {}
22639
22640
  };
22640
22641
  return compiled;
22641
22642
  }
@@ -24784,10 +24785,10 @@ function loadPriceCatalog(rootOrPath) {
24784
24785
  }
24785
24786
 
24786
24787
  // plugins/kxm/src/engine.ts
24787
- var import_yaml10 = __toESM(require_dist(), 1);
24788
+ var import_yaml11 = __toESM(require_dist(), 1);
24788
24789
  import { createHash as createHash14, randomBytes, timingSafeEqual } from "node:crypto";
24789
- import { existsSync as existsSync13, readFileSync as readFileSync11 } from "node:fs";
24790
- import { join as join16 } from "node:path";
24790
+ import { existsSync as existsSync14, readFileSync as readFileSync12 } from "node:fs";
24791
+ import { join as join17 } from "node:path";
24791
24792
 
24792
24793
  // plugins/kxm/src/routes.ts
24793
24794
  var import_yaml7 = __toESM(require_dist(), 1);
@@ -24823,6 +24824,363 @@ function listRoleBindings(root) {
24823
24824
  return result;
24824
24825
  }
24825
24826
 
24827
+ // plugins/kxm/src/route-fallback.ts
24828
+ var import_yaml8 = __toESM(require_dist(), 1);
24829
+ import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as readFileSync9 } from "node:fs";
24830
+ import { join as join12 } from "node:path";
24831
+
24832
+ // plugins/kxm/src/route-switch.ts
24833
+ var WALKABLE_CLASSES = ["rate_limit", "transport", "provider_unavailable", "context_overflow"];
24834
+ var EFFORTS2 = /* @__PURE__ */ new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
24835
+
24836
+ // plugins/kxm/src/route-fallback.ts
24837
+ var CARRY_ROLES = /* @__PURE__ */ new Set(["user", "assistant", "tool"]);
24838
+ var MAX_CARRY_MESSAGES = 8;
24839
+ var MAX_CARRY_TEXT = 2e3;
24840
+ var MAX_CARRY_TOTAL = 8e3;
24841
+ var DEFAULT_MAX_SWITCHES = 1;
24842
+ function classifyRouteFailure(input) {
24843
+ const code = (input.code ?? "").toLowerCase();
24844
+ const text = `${code} ${input.text ?? ""}`.toLowerCase();
24845
+ const name = (input.name ?? "").toLowerCase();
24846
+ const status = input.httpStatus;
24847
+ const result = (failureClass) => ({
24848
+ class: failureClass,
24849
+ walkable: WALKABLE_CLASSES.includes(failureClass)
24850
+ });
24851
+ if (name === "aborterror" || /\b(?:user_cancelled|cancelled|cancellation)\b/.test(text) || code === "process_aborted" || text.includes("abort")) {
24852
+ return result("cancelled");
24853
+ }
24854
+ if (/policy_refusal|content_policy|tool_policy|usage policy|safety/.test(text) || text.includes("policy refusal")) {
24855
+ return result("policy_refusal");
24856
+ }
24857
+ if (code.includes("not_authenticated") || /unauthori[sz]ed|authentication|invalid api key|auth_failed|\bauth\b/.test(text) || status === 401 || status === 403) {
24858
+ return result("auth");
24859
+ }
24860
+ if (/permission_profile_unaudited|writer_profile_unaudited|tool_policy/.test(text)) {
24861
+ return result("tool_policy");
24862
+ }
24863
+ if (/harness_unhosted_model|unhosted|does not host/.test(text)) {
24864
+ return result("unhosted_model");
24865
+ }
24866
+ if (code.startsWith("gate_") || text.includes("gate_unsupported") || text.includes("gate_failed")) {
24867
+ return result("gate");
24868
+ }
24869
+ if (code === "producer_route_not_admitted" || text.includes("not_admitted") || text.includes("not admitted")) {
24870
+ return result("admission");
24871
+ }
24872
+ if (status === 413 || /context_overflow|context length|context window|maximum context|token limit|prompt too long|context overflow/.test(text)) {
24873
+ return result("context_overflow");
24874
+ }
24875
+ if (status === 429 || /rate_limit|rate limit|ratelimit|too many requests/.test(text)) {
24876
+ return result("rate_limit");
24877
+ }
24878
+ if (status === 408 || status === 502 || status === 504 || code === "process_timeout" || /etimedout|econnreset|econnrefused|enotfound|eai_again|socket hang up|\btimeout\b|timed out|\btransport\b/.test(text)) {
24879
+ return result("transport");
24880
+ }
24881
+ if (status === 500 || status === 503 || /provider_unavailable|model unavailable|service unavailable|overloaded|model_not_found|no available model/.test(text)) {
24882
+ return result("provider_unavailable");
24883
+ }
24884
+ return result("unknown");
24885
+ }
24886
+ function parseFallbackPolicy(value) {
24887
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
24888
+ const record2 = value;
24889
+ const onErrorRaw = record2.onError;
24890
+ if (!Array.isArray(onErrorRaw) || onErrorRaw.length === 0) return void 0;
24891
+ if (new Set(onErrorRaw).size !== onErrorRaw.length) return void 0;
24892
+ const onError = [];
24893
+ for (const item of onErrorRaw) {
24894
+ if (typeof item !== "string" || !WALKABLE_CLASSES.includes(item)) return void 0;
24895
+ onError.push(item);
24896
+ }
24897
+ let maxSwitches = DEFAULT_MAX_SWITCHES;
24898
+ if (record2.maxSwitches !== void 0) {
24899
+ if (!Number.isInteger(record2.maxSwitches) || record2.maxSwitches < 0) return void 0;
24900
+ maxSwitches = record2.maxSwitches;
24901
+ }
24902
+ let revert = "next_run";
24903
+ if (record2.revert !== void 0) {
24904
+ if (record2.revert !== "next_run" && record2.revert !== "never") return void 0;
24905
+ revert = record2.revert;
24906
+ }
24907
+ return { onError, maxSwitches, revert };
24908
+ }
24909
+ function admittedSelector(model, admitted, disabled) {
24910
+ const candidates = [model.model, `${model.vendor}/${model.model}`, `${model.harness}/${model.model}`];
24911
+ const selector = candidates.find((candidate) => admitted.has(candidate));
24912
+ if (!selector || disabled.has(selector)) return void 0;
24913
+ return selector;
24914
+ }
24915
+ function splitSelector(selector) {
24916
+ const slash = selector.indexOf("/");
24917
+ if (slash <= 0 || slash === selector.length - 1) return void 0;
24918
+ return { provider: selector.slice(0, slash), model: selector.slice(slash + 1) };
24919
+ }
24920
+ function eligible(model, admitted, disabled, liveWrite) {
24921
+ if (model.status !== "admitted" || !model.hosted) return void 0;
24922
+ if (liveWrite && (!model.permissions.includes("edit") || !model.writerReady || !model.onWriterRoster)) return void 0;
24923
+ const selector = admittedSelector(model, admitted, disabled);
24924
+ if (!selector) return void 0;
24925
+ const parts = splitSelector(selector);
24926
+ if (!parts) return void 0;
24927
+ return {
24928
+ routeId: model.routeId,
24929
+ harness: model.harness,
24930
+ provider: parts.provider,
24931
+ model: parts.model,
24932
+ selector,
24933
+ vendor: model.vendor,
24934
+ permissions: model.permissions,
24935
+ priority: model.priority
24936
+ };
24937
+ }
24938
+ function selectorsFor2(fallback, models) {
24939
+ if (fallback.profile) {
24940
+ const model = models.find((item) => item.routeId === fallback.profile);
24941
+ return model ? [model] : [];
24942
+ }
24943
+ if (fallback.tag) {
24944
+ const required2 = new Set(fallback.capabilities ?? []);
24945
+ return models.filter((item) => item.tags.includes(fallback.tag) && [...required2].every((capability) => item.capabilities.includes(capability))).slice().sort((left, right) => right.priority - left.priority || left.routeId.localeCompare(right.routeId));
24946
+ }
24947
+ if (fallback.provider && fallback.model) {
24948
+ return models.filter((item) => item.vendor === fallback.provider && item.model === fallback.model);
24949
+ }
24950
+ return [];
24951
+ }
24952
+ function buildFallbackChain(input) {
24953
+ const admitted = new Set(input.admitted);
24954
+ const disabled = new Set(input.disabled);
24955
+ const critics = new Set(input.criticVendors ?? []);
24956
+ const byId = new Map(input.models.map((model) => [model.routeId, model]));
24957
+ const chain = [];
24958
+ const seen = /* @__PURE__ */ new Set();
24959
+ const entries = [...input.roster, ...input.extendsRoster ?? []];
24960
+ const push2 = (model, effort) => {
24961
+ if (!model || seen.has(model.routeId)) return;
24962
+ const candidate = eligible(model, admitted, disabled, input.liveWrite);
24963
+ if (!candidate) return;
24964
+ if (input.vendorIndependenceRequired && chain.length > 0 && critics.has(candidate.vendor)) return;
24965
+ seen.add(model.routeId);
24966
+ const resolvedEffort = effort && EFFORTS2.has(effort) ? effort : void 0;
24967
+ chain.push(resolvedEffort ? { ...candidate, effort: resolvedEffort } : candidate);
24968
+ };
24969
+ for (const entry of entries) {
24970
+ const model = byId.get(entry.route);
24971
+ push2(model, entry.effort);
24972
+ if (!model) continue;
24973
+ for (const fallback of model.fallbacks) {
24974
+ for (const resolved of selectorsFor2(fallback, input.models)) push2(resolved, entry.effort);
24975
+ }
24976
+ }
24977
+ return chain;
24978
+ }
24979
+ function decideRouteSwitch(input) {
24980
+ if (!input.policy || input.policy.onError.length === 0) return { action: "continue", cause: "disabled" };
24981
+ if (!input.failure.walkable) return { action: "continue", cause: "not_walkable" };
24982
+ if (!input.policy.onError.includes(input.failure.class)) {
24983
+ return { action: "continue", cause: "class_not_opted_in" };
24984
+ }
24985
+ if (input.switchesUsed >= input.policy.maxSwitches) return { action: "continue", cause: "budget" };
24986
+ const index = input.chain.findIndex((candidate) => candidate.routeId === input.currentRouteId);
24987
+ const next = index >= 0 ? input.chain[index + 1] : void 0;
24988
+ if (!next) return { action: "continue", cause: "no_candidate" };
24989
+ const effort = next.effort ?? (input.currentEffort && EFFORTS2.has(input.currentEffort) ? input.currentEffort : void 0);
24990
+ return {
24991
+ action: "switch",
24992
+ to: next,
24993
+ reason: input.failure.class,
24994
+ ...effort ? { effort } : {}
24995
+ };
24996
+ }
24997
+ function parseSessionCarry(value) {
24998
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
24999
+ const transcript = value.transcript;
25000
+ if (!Array.isArray(transcript) || transcript.length === 0) return void 0;
25001
+ const messages = [];
25002
+ let total = 0;
25003
+ for (const item of transcript) {
25004
+ if (messages.length >= MAX_CARRY_MESSAGES) break;
25005
+ if (!item || typeof item !== "object" || Array.isArray(item)) continue;
25006
+ const role = item.role;
25007
+ const text = item.text;
25008
+ if (typeof role !== "string" || !CARRY_ROLES.has(role) || typeof text !== "string" || text.length === 0) continue;
25009
+ const clipped = text.slice(0, MAX_CARRY_TEXT);
25010
+ if (total + clipped.length > MAX_CARRY_TOTAL) break;
25011
+ total += clipped.length;
25012
+ messages.push({ role, text: clipped });
25013
+ }
25014
+ return messages.length > 0 ? { transcript: messages } : void 0;
25015
+ }
25016
+ function mergeSessionCarry(left, right) {
25017
+ return parseSessionCarry({ transcript: [...left?.transcript ?? [], ...right?.transcript ?? []] });
25018
+ }
25019
+ function carryForwardPrompt(prompt, carry) {
25020
+ if (!carry || carry.transcript.length === 0) return prompt;
25021
+ const lines = carry.transcript.map((message) => `${message.role}: ${message.text}`);
25022
+ const block = `Prior attempt transcript:
25023
+ ${lines.join("\n")}`;
25024
+ if (!prompt || prompt.length === 0) return block;
25025
+ return `${prompt}
25026
+
25027
+ ${block}`;
25028
+ }
25029
+ function readYaml(file) {
25030
+ if (!existsSync11(file)) return void 0;
25031
+ try {
25032
+ const parsed = (0, import_yaml8.parse)(readFileSync9(file, "utf8"));
25033
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
25034
+ return parsed;
25035
+ } catch {
25036
+ return void 0;
25037
+ }
25038
+ }
25039
+ function stringList(value) {
25040
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
25041
+ }
25042
+ function readSelectors(projectRoot, value) {
25043
+ if (!Array.isArray(value)) return [];
25044
+ const modelsDir = join12(projectRoot, ".kxm", "models");
25045
+ const selectors = [];
25046
+ for (const item of value) {
25047
+ if (!item || typeof item !== "object" || Array.isArray(item)) continue;
25048
+ const record2 = item;
25049
+ if (typeof record2.profile === "string") {
25050
+ selectors.push({ profile: findYamlBasename(modelsDir, record2.profile, "route") ?? record2.profile });
25051
+ } else if (typeof record2.tag === "string") {
25052
+ selectors.push({
25053
+ tag: record2.tag,
25054
+ ...Array.isArray(record2.capabilities) ? { capabilities: stringList(record2.capabilities) } : {}
25055
+ });
25056
+ } else if (typeof record2.provider === "string" && typeof record2.model === "string") {
25057
+ selectors.push({ provider: record2.provider, model: record2.model });
25058
+ }
25059
+ }
25060
+ return selectors;
25061
+ }
25062
+ function loadChainModel(projectRoot, routeId2, writerIds) {
25063
+ const modelsDir = join12(projectRoot, ".kxm", "models");
25064
+ const fileId = findYamlBasename(modelsDir, routeId2, "route") ?? routeId2;
25065
+ const doc = readYaml(join12(modelsDir, `${fileId}.yaml`));
25066
+ if (!doc || doc.schema !== "kxm.model.v2") return void 0;
25067
+ const harness = typeof doc.harness === "string" ? doc.harness : "";
25068
+ const model = typeof doc.model === "string" ? doc.model : "";
25069
+ const vendor = typeof doc.vendor === "string" ? doc.vendor : "";
25070
+ if (!harness || !model || !vendor) return void 0;
25071
+ const permissions = stringList(doc.permissions);
25072
+ const selector = [model, `${vendor}/${model}`, `${harness}/${model}`].find((candidate) => candidate.includes("/")) ?? `${vendor}/${model}`;
25073
+ const parts = splitSelector(selector);
25074
+ const hosted = parts ? validateHarnessModelPair(harness, { provider: parts.provider, model: parts.model }).valid : false;
25075
+ return {
25076
+ routeId: fileId,
25077
+ harness,
25078
+ model,
25079
+ vendor,
25080
+ status: typeof doc.status === "string" ? doc.status : "",
25081
+ permissions,
25082
+ tags: stringList(doc.tags),
25083
+ capabilities: stringList(doc.capabilities),
25084
+ priority: typeof doc.priority === "number" ? doc.priority : 0,
25085
+ fallbacks: readSelectors(projectRoot, doc.fallbacks),
25086
+ hosted,
25087
+ writerReady: oneShotWriterArgs(harness) !== void 0,
25088
+ onWriterRoster: writerIds.has(fileId) || writerIds.has(routeId2)
25089
+ };
25090
+ }
25091
+ function canonicalRoster(projectRoot, entries) {
25092
+ const modelsDir = join12(projectRoot, ".kxm", "models");
25093
+ return entries.map((entry) => {
25094
+ const route = findYamlBasename(modelsDir, entry.route, "route") ?? entry.route;
25095
+ return entry.effort ? { route, effort: entry.effort } : { route };
25096
+ });
25097
+ }
25098
+ function rosterEntries(doc) {
25099
+ if (!Array.isArray(doc?.roster)) return [];
25100
+ const entries = [];
25101
+ for (const item of doc.roster) {
25102
+ if (!item || typeof item !== "object" || Array.isArray(item)) continue;
25103
+ const route = item.route;
25104
+ const effort = item.effort;
25105
+ if (typeof route !== "string" || route.length === 0) continue;
25106
+ entries.push(typeof effort === "string" ? { route, effort } : { route });
25107
+ }
25108
+ return entries;
25109
+ }
25110
+ function loadModelsFor(projectRoot, roster, writerIds) {
25111
+ const modelsDir = join12(projectRoot, ".kxm", "models");
25112
+ const wanted = /* @__PURE__ */ new Set();
25113
+ for (const entry of roster) wanted.add(entry.route);
25114
+ if (existsSync11(modelsDir)) {
25115
+ for (const name of readdirSync7(modelsDir)) {
25116
+ if (!name.endsWith(".yaml") || name === "inventory.yaml") continue;
25117
+ wanted.add(name.slice(0, -5));
25118
+ }
25119
+ }
25120
+ const models = [];
25121
+ const seen = /* @__PURE__ */ new Set();
25122
+ for (const routeId2 of wanted) {
25123
+ const model = loadChainModel(projectRoot, routeId2, writerIds);
25124
+ if (!model || seen.has(model.routeId)) continue;
25125
+ seen.add(model.routeId);
25126
+ models.push(model);
25127
+ }
25128
+ return models;
25129
+ }
25130
+ function criticVendors(projectRoot, writerIds) {
25131
+ const dir = join12(projectRoot, ".kxm", "roles");
25132
+ if (!existsSync11(dir)) return [];
25133
+ const vendors = [];
25134
+ for (const name of readdirSync7(dir)) {
25135
+ if (!name.endsWith(".yaml")) continue;
25136
+ const doc = readYaml(join12(dir, name));
25137
+ const purpose = doc?.purpose;
25138
+ if (purpose !== "reviewer-arch" && purpose !== "reviewer-cli") continue;
25139
+ const first = rosterEntries(doc)[0];
25140
+ if (!first) continue;
25141
+ const model = loadChainModel(projectRoot, first.route, writerIds);
25142
+ if (model?.status === "admitted") vendors.push(model.vendor);
25143
+ }
25144
+ return vendors;
25145
+ }
25146
+ function loadAgentFallback(projectRoot, agentId, options) {
25147
+ const agentsDir = join12(projectRoot, ".kxm", "agents");
25148
+ const agentFile = findYamlBasename(agentsDir, agentId, "agent") ?? agentId;
25149
+ const agent = readYaml(join12(agentsDir, `${agentFile}.yaml`));
25150
+ const roleId = typeof agent?.role === "string" ? agent.role : "";
25151
+ if (!roleId) return void 0;
25152
+ const role = readYaml(join12(projectRoot, ".kxm", "roles", `${roleId}.yaml`));
25153
+ if (!role) return void 0;
25154
+ const policyRecord = role.policy && typeof role.policy === "object" ? role.policy.fallback : void 0;
25155
+ const policy = parseFallbackPolicy(policyRecord);
25156
+ if (!policy) return void 0;
25157
+ const own2 = canonicalRoster(projectRoot, rosterEntries(role));
25158
+ const seenRoles = /* @__PURE__ */ new Set([roleId]);
25159
+ let extendsRoster = [];
25160
+ let cursor = typeof role.extends === "string" ? role.extends : "";
25161
+ while (cursor && !seenRoles.has(cursor)) {
25162
+ seenRoles.add(cursor);
25163
+ const parent = readYaml(join12(projectRoot, ".kxm", "roles", `${cursor}.yaml`));
25164
+ extendsRoster = extendsRoster.concat(canonicalRoster(projectRoot, rosterEntries(parent)));
25165
+ cursor = typeof parent?.extends === "string" ? parent.extends : "";
25166
+ }
25167
+ const writerIds = new Set(listRoleBindings(projectRoot).writer ?? []);
25168
+ const models = loadModelsFor(projectRoot, [...own2, ...extendsRoster], writerIds);
25169
+ const routePolicy = loadRoutePolicy(projectRoot);
25170
+ const independence = Boolean(role.policy && typeof role.policy === "object" && role.policy.vendorIndependenceRequired);
25171
+ const chain = buildFallbackChain({
25172
+ roster: own2,
25173
+ extendsRoster,
25174
+ models,
25175
+ admitted: routePolicy.admitted,
25176
+ disabled: routePolicy.disabled,
25177
+ liveWrite: options.liveWrite,
25178
+ criticVendors: independence ? criticVendors(projectRoot, writerIds) : [],
25179
+ vendorIndependenceRequired: independence
25180
+ });
25181
+ return { policy, chain, roleId };
25182
+ }
25183
+
24826
25184
  // plugins/kxm/src/worktree-witness.ts
24827
25185
  import { spawnSync as spawnSync4 } from "node:child_process";
24828
25186
  function gitText(cwd, args) {
@@ -25149,8 +25507,8 @@ function pruneContextPacket(packet, tokenBudget) {
25149
25507
 
25150
25508
  // plugins/kxm/src/dispatch-context.ts
25151
25509
  import { spawnSync as spawnSync5 } from "node:child_process";
25152
- import { readdirSync as readdirSync9 } from "node:fs";
25153
- import { extname as extname3, join as join14 } from "node:path";
25510
+ import { readdirSync as readdirSync10 } from "node:fs";
25511
+ import { extname as extname3, join as join15 } from "node:path";
25154
25512
 
25155
25513
  // plugins/kxm/src/protocol.ts
25156
25514
  var DEFAULT_MESSAGE_TTL_MS = 24 * 60 * 6e4;
@@ -25679,16 +26037,16 @@ function arbitrate(requestInput, pool, options = {}) {
25679
26037
  };
25680
26038
  const allowedKinds = new Set(requestedKinds);
25681
26039
  const inertProposal = (item) => item.kind === "state" && item.status !== void 0 && item.status !== "current" || item.kind === "skill" && item.status === "proposed";
25682
- const eligible = candidates.filter((item) => contradictions.has(item.id) || allowedKinds.has(item.kind) && !inertProposal(item));
25683
- const scoreList = scoreRelevance(request.task, eligible.map(contextItemRelevanceText));
26040
+ const eligible2 = candidates.filter((item) => contradictions.has(item.id) || allowedKinds.has(item.kind) && !inertProposal(item));
26041
+ const scoreList = scoreRelevance(request.task, eligible2.map(contextItemRelevanceText));
25684
26042
  const scores = /* @__PURE__ */ new Map();
25685
- eligible.forEach((item, index) => scores.set(item, scoreList[index] ?? 0));
26043
+ eligible2.forEach((item, index) => scores.set(item, scoreList[index] ?? 0));
25686
26044
  const scoreOf = (item) => scores.get(item) ?? 0;
25687
26045
  const when = (item) => {
25688
26046
  const parsed = Date.parse(item.observedAt ?? item.validFrom ?? "");
25689
26047
  return Number.isFinite(parsed) ? parsed : 0;
25690
26048
  };
25691
- const ordered = [...eligible].sort(
26049
+ const ordered = [...eligible2].sort(
25692
26050
  (left, right) => (contradictions.has(right.id) ? 1 : 0) - (contradictions.has(left.id) ? 1 : 0) || (left.project === request.project ? 0 : 1) - (right.project === request.project ? 0 : 1) || (scoreOf(right) > 0 ? 1 : 0) - (scoreOf(left) > 0 ? 1 : 0) || kindPreference(left) - kindPreference(right) || scoreOf(right) - scoreOf(left) || CONFIDENCE_RANK[right.confidence] - CONFIDENCE_RANK[left.confidence] || AUTHORITY_WEIGHT[right.authority] - AUTHORITY_WEIGHT[left.authority] || when(right) - when(left) || compareCodeUnitIds(left.id, right.id)
25693
26051
  );
25694
26052
  const selected = [];
@@ -25778,9 +26136,9 @@ function memoryRecordToContextItem(record2, project) {
25778
26136
  }
25779
26137
 
25780
26138
  // plugins/kxm/src/memory.ts
25781
- var import_yaml8 = __toESM(require_dist(), 1);
25782
- import { existsSync as existsSync11, mkdirSync as mkdirSync4, readdirSync as readdirSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "node:fs";
25783
- import { extname as extname2, join as join12, resolve as resolve7 } from "node:path";
26139
+ var import_yaml9 = __toESM(require_dist(), 1);
26140
+ import { existsSync as existsSync12, mkdirSync as mkdirSync4, readdirSync as readdirSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "node:fs";
26141
+ import { extname as extname2, join as join13, resolve as resolve7 } from "node:path";
25784
26142
  var MEMORY_SCHEMA = "kxm.memory.v1";
25785
26143
  var VALID_SCOPES = /* @__PURE__ */ new Set(["agent", "project", "run", "operator"]);
25786
26144
  var VALID_AUTHORITIES = /* @__PURE__ */ new Set(["instruction", "evidence", "promoted"]);
@@ -25810,7 +26168,7 @@ function parseFrontmatter(content) {
25810
26168
  }
25811
26169
  function parseMemoryRecord(raw, filename = "memory.md") {
25812
26170
  const { frontmatter, body } = parseFrontmatter(raw);
25813
- const data = (0, import_yaml8.parse)(frontmatter);
26171
+ const data = (0, import_yaml9.parse)(frontmatter);
25814
26172
  if (!data || typeof data !== "object" || Array.isArray(data)) {
25815
26173
  throw new Error(`invalid YAML frontmatter in ${filename}`);
25816
26174
  }
@@ -25879,20 +26237,20 @@ function parseMemoryRecord(raw, filename = "memory.md") {
25879
26237
  }
25880
26238
  function memoryDirectories(repoRoot) {
25881
26239
  const root = resolve7(repoRoot);
25882
- const memoryDir = join12(root, ".kxm", "memory");
25883
- const candidatesDir = join12(memoryDir, "candidates");
26240
+ const memoryDir = join13(root, ".kxm", "memory");
26241
+ const candidatesDir = join13(memoryDir, "candidates");
25884
26242
  return { memoryDir, candidatesDir };
25885
26243
  }
25886
26244
  function loadAuthoredMemory(repoRoot) {
25887
26245
  const { memoryDir } = memoryDirectories(repoRoot);
25888
- if (!existsSync11(memoryDir)) return [];
26246
+ if (!existsSync12(memoryDir)) return [];
25889
26247
  const records = [];
25890
- const entries = readdirSync7(memoryDir, { withFileTypes: true });
26248
+ const entries = readdirSync8(memoryDir, { withFileTypes: true });
25891
26249
  for (const entry of entries) {
25892
26250
  if (entry.isFile() && extname2(entry.name) === ".md") {
25893
- const fullPath = join12(memoryDir, entry.name);
26251
+ const fullPath = join13(memoryDir, entry.name);
25894
26252
  try {
25895
- const text = readFileSync9(fullPath, "utf8");
26253
+ const text = readFileSync10(fullPath, "utf8");
25896
26254
  const record2 = parseMemoryRecord(text, entry.name);
25897
26255
  if (record2.lifecycle === "active") {
25898
26256
  records.push(record2);
@@ -25906,10 +26264,10 @@ function loadAuthoredMemory(repoRoot) {
25906
26264
  }
25907
26265
 
25908
26266
  // plugins/kxm/src/skills.ts
25909
- var import_yaml9 = __toESM(require_dist(), 1);
26267
+ var import_yaml10 = __toESM(require_dist(), 1);
25910
26268
  import { createHash as createHash11 } from "node:crypto";
25911
- import { existsSync as existsSync12, mkdirSync as mkdirSync5, readdirSync as readdirSync8, readFileSync as readFileSync10, renameSync, rmSync, statSync as statSync3, writeFileSync as writeFileSync6 } from "node:fs";
25912
- import { dirname as dirname7, join as join13 } from "node:path";
26269
+ import { existsSync as existsSync13, mkdirSync as mkdirSync5, readdirSync as readdirSync9, readFileSync as readFileSync11, renameSync, rmSync, statSync as statSync3, writeFileSync as writeFileSync6 } from "node:fs";
26270
+ import { dirname as dirname7, join as join14 } from "node:path";
25913
26271
  var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
25914
26272
  var SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
25915
26273
  var SKILL_DECISION_SCHEMA = "kxm.skill-decision.v1";
@@ -25950,7 +26308,7 @@ function parseSkillFrontmatter(content) {
25950
26308
  return { frontmatter: null, body: content };
25951
26309
  }
25952
26310
  try {
25953
- const parsed = (0, import_yaml9.parse)(rawFm);
26311
+ const parsed = (0, import_yaml10.parse)(rawFm);
25954
26312
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
25955
26313
  return { frontmatter: parsed, body: rawBody };
25956
26314
  }
@@ -26015,20 +26373,20 @@ var SkillLifecycle = class {
26015
26373
  writeFileSync6(file, content);
26016
26374
  }
26017
26375
  dir(state) {
26018
- return join13(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
26376
+ return join14(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
26019
26377
  }
26020
26378
  historyFile(id) {
26021
- return join13(this.root, "history", `${id}.jsonl`);
26379
+ return join14(this.root, "history", `${id}.jsonl`);
26022
26380
  }
26023
26381
  paths(state, id) {
26024
- const dir = join13(this.dir(state), id);
26025
- return { dir, metadata: join13(dir, "metadata.json"), skill: join13(dir, "SKILL.md") };
26382
+ const dir = join14(this.dir(state), id);
26383
+ return { dir, metadata: join14(dir, "metadata.json"), skill: join14(dir, "SKILL.md") };
26026
26384
  }
26027
26385
  appendHistory(id, record2) {
26028
26386
  const line = `${JSON.stringify(record2)}
26029
26387
  `;
26030
- if (existsSync12(this.historyFile(id))) {
26031
- const existing = readFileSync10(this.historyFile(id), "utf8");
26388
+ if (existsSync13(this.historyFile(id))) {
26389
+ const existing = readFileSync11(this.historyFile(id), "utf8");
26032
26390
  const lines = existing.split("\n").filter((entry) => entry.trim());
26033
26391
  this.write(this.historyFile(id), [...lines.slice(-499), line.trim()].join("\n") + "\n");
26034
26392
  } else {
@@ -26037,20 +26395,20 @@ var SkillLifecycle = class {
26037
26395
  }
26038
26396
  history(id) {
26039
26397
  const file = this.historyFile(id);
26040
- if (!existsSync12(file)) return [];
26041
- return readFileSync10(file, "utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
26398
+ if (!existsSync13(file)) return [];
26399
+ return readFileSync11(file, "utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
26042
26400
  }
26043
26401
  readMetadata(state, id) {
26044
26402
  const { metadata } = this.paths(state, id);
26045
- if (!existsSync12(metadata)) {
26403
+ if (!existsSync13(metadata)) {
26046
26404
  throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${state}`);
26047
26405
  }
26048
- return JSON.parse(readFileSync10(metadata, "utf8"));
26406
+ return JSON.parse(readFileSync11(metadata, "utf8"));
26049
26407
  }
26050
26408
  move(from, to, id) {
26051
- const fromDir = join13(this.dir(from), id);
26052
- const toDir = join13(this.dir(to), id);
26053
- if (!existsSync12(fromDir)) {
26409
+ const fromDir = join14(this.dir(from), id);
26410
+ const toDir = join14(this.dir(to), id);
26411
+ if (!existsSync13(fromDir)) {
26054
26412
  throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${from}`);
26055
26413
  }
26056
26414
  if (this.dryRun) {
@@ -26058,7 +26416,7 @@ var SkillLifecycle = class {
26058
26416
  return;
26059
26417
  }
26060
26418
  mkdirSync5(this.dir(to), { recursive: true });
26061
- if (existsSync12(toDir)) rmSync(toDir, { recursive: true, force: true });
26419
+ if (existsSync13(toDir)) rmSync(toDir, { recursive: true, force: true });
26062
26420
  renameSync(fromDir, toDir);
26063
26421
  }
26064
26422
  /** Submit a new skill candidate. Content is redacted of secret material at
@@ -26101,7 +26459,7 @@ var SkillLifecycle = class {
26101
26459
  const contentSha256 = skillContentSha256(content);
26102
26460
  const id = skillIdFor(name, contentSha256);
26103
26461
  const { metadata, skill } = this.paths("candidate", id);
26104
- if (existsSync12(metadata)) {
26462
+ if (existsSync13(metadata)) {
26105
26463
  throw new SkillLifecycleError(
26106
26464
  "skill_candidate_exists",
26107
26465
  `identical candidate ${id} already exists; changed behavior requires changed content`
@@ -26210,11 +26568,11 @@ var SkillLifecycle = class {
26210
26568
  };
26211
26569
  const candidatePaths = this.paths("candidate", candidateId);
26212
26570
  const promotedPaths = this.paths("promoted", candidateId);
26213
- const skillContent = readFileSync10(candidatePaths.skill, "utf8");
26214
- const metadataContent = readFileSync10(candidatePaths.metadata, "utf8");
26571
+ const skillContent = readFileSync11(candidatePaths.skill, "utf8");
26572
+ const metadataContent = readFileSync11(candidatePaths.metadata, "utf8");
26215
26573
  this.write(promotedPaths.skill, skillContent);
26216
26574
  this.write(promotedPaths.metadata, metadataContent);
26217
- const patchPath = join13(this.root, "patches", `${candidateId}.patch`);
26575
+ const patchPath = join14(this.root, "patches", `${candidateId}.patch`);
26218
26576
  const relSkillPath = `.kxm/skills/promoted/${candidateId}/SKILL.md`;
26219
26577
  const relMetaPath = `.kxm/skills/promoted/${candidateId}/metadata.json`;
26220
26578
  const patch = `${createUnifiedPatch(relSkillPath, skillContent)}${createUnifiedPatch(relMetaPath, metadataContent)}`;
@@ -26242,7 +26600,7 @@ var SkillLifecycle = class {
26242
26600
  verify(state, id) {
26243
26601
  const metadata = this.readMetadata(state, id);
26244
26602
  const { skill } = this.paths(state, id);
26245
- const content = readFileSync10(skill, "utf8");
26603
+ const content = readFileSync11(skill, "utf8");
26246
26604
  if (skillContentSha256(content) !== metadata.contentSha256) {
26247
26605
  throw new SkillLifecycleError(
26248
26606
  "skill_integrity_violation",
@@ -26260,7 +26618,7 @@ var SkillLifecycle = class {
26260
26618
  }
26261
26619
  list(state) {
26262
26620
  const dir = this.dir(state);
26263
- if (!existsSync12(dir)) return [];
26621
+ if (!existsSync13(dir)) return [];
26264
26622
  const ids = readdirSorted(dir);
26265
26623
  return ids.map((id) => {
26266
26624
  try {
@@ -26273,7 +26631,7 @@ var SkillLifecycle = class {
26273
26631
  read(state, id) {
26274
26632
  const metadata = this.readMetadata(state, id);
26275
26633
  const { skill } = this.paths(state, id);
26276
- return { metadata, content: readFileSync10(skill, "utf8") };
26634
+ return { metadata, content: readFileSync11(skill, "utf8") };
26277
26635
  }
26278
26636
  };
26279
26637
  function boundedList(value, field) {
@@ -26288,7 +26646,7 @@ function boundedList(value, field) {
26288
26646
  return [...new Set(refs)];
26289
26647
  }
26290
26648
  function readdirSorted(dir) {
26291
- return readdirSync8(dir).filter((entry) => statSync3(join13(dir, entry)).isDirectory()).sort();
26649
+ return readdirSync9(dir).filter((entry) => statSync3(join14(dir, entry)).isDirectory()).sort();
26292
26650
  }
26293
26651
 
26294
26652
  // plugins/kxm/src/dispatch-context.ts
@@ -26329,18 +26687,18 @@ function contextRoleForAgent(agentId) {
26329
26687
  return agentId;
26330
26688
  }
26331
26689
  function dispatchContextPresent(projectRoot) {
26332
- return hasTopLevelMarkdown(join14(projectRoot, ".kxm", "memory")) || hasAnyEntry(join14(projectRoot, ".kxm", "skills", "promoted"));
26690
+ return hasTopLevelMarkdown(join15(projectRoot, ".kxm", "memory")) || hasAnyEntry(join15(projectRoot, ".kxm", "skills", "promoted"));
26333
26691
  }
26334
26692
  function hasTopLevelMarkdown(dir) {
26335
26693
  try {
26336
- return readdirSync9(dir, { withFileTypes: true }).some((entry) => entry.isFile() && extname3(entry.name) === ".md");
26694
+ return readdirSync10(dir, { withFileTypes: true }).some((entry) => entry.isFile() && extname3(entry.name) === ".md");
26337
26695
  } catch {
26338
26696
  return false;
26339
26697
  }
26340
26698
  }
26341
26699
  function hasAnyEntry(dir) {
26342
26700
  try {
26343
- return readdirSync9(dir).length > 0;
26701
+ return readdirSync10(dir).length > 0;
26344
26702
  } catch {
26345
26703
  return false;
26346
26704
  }
@@ -26405,7 +26763,7 @@ function loadDispatchContextSources(input) {
26405
26763
  }
26406
26764
  const promoted = [];
26407
26765
  try {
26408
- const lifecycle = new SkillLifecycle(join14(projectRoot, ".kxm", "skills"));
26766
+ const lifecycle = new SkillLifecycle(join15(projectRoot, ".kxm", "skills"));
26409
26767
  for (const metadata of lifecycle.list("promoted")) {
26410
26768
  try {
26411
26769
  promoted.push(lifecycle.verify("promoted", metadata.id));
@@ -26488,7 +26846,7 @@ function assembleDispatchContext(sources, input) {
26488
26846
  }
26489
26847
 
26490
26848
  // plugins/kxm/src/engine-artifacts.ts
26491
- import { join as join15 } from "node:path";
26849
+ import { join as join16 } from "node:path";
26492
26850
 
26493
26851
  // plugins/kxm/src/artifacts-exist.ts
26494
26852
  import { lstatSync as lstatSync5, realpathSync as realpathSync4, statSync as statSync4 } from "node:fs";
@@ -26535,14 +26893,14 @@ function verifyArtifactExists(rootInput, pathInput) {
26535
26893
  // plugins/kxm/src/engine-artifacts.ts
26536
26894
  var kxmArtifactsGateSeams = {};
26537
26895
  function evaluateArtifactsGate(context, definition) {
26538
- const root = join15(context.projectRoot, ".kxm", "assets");
26896
+ const root = join16(context.projectRoot, ".kxm", "assets");
26539
26897
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
26540
26898
  const startTime = process.hrtime.bigint();
26541
26899
  let checkedCount = 0;
26542
26900
  let failedCount = 0;
26543
26901
  for (const [index, path] of definition.paths.entries()) {
26544
26902
  checkedCount += 1;
26545
- const result = verifyArtifactExists(root, join15(root, path));
26903
+ const result = verifyArtifactExists(root, join16(root, path));
26546
26904
  if (!result.ok) failedCount += 1;
26547
26905
  kxmArtifactsGateSeams.afterPathChecked?.({ path, index, checkedCount, failedCount });
26548
26906
  }
@@ -28103,32 +28461,185 @@ var KxmRunScheduler = class _KxmRunScheduler {
28103
28461
  });
28104
28462
  }
28105
28463
  };
28464
+ var attemptFallback = /* @__PURE__ */ new Map();
28465
+ var runStickyRoute = /* @__PURE__ */ new Map();
28466
+ function observeProducerFailure(error, capability) {
28467
+ try {
28468
+ const raw = error instanceof Error ? error.message : error;
28469
+ const message = typeof raw === "string" ? raw : "";
28470
+ let text = message;
28471
+ if (capability) text = text.split(capability).join("[redacted]");
28472
+ text = text.replace(/kxmcap_[A-Za-z0-9_-]+/g, "[redacted]");
28473
+ const match = /^[a-z][a-z0-9]*(?:_[a-z0-9]+){1,3}/.exec(text);
28474
+ const extracted = match?.[0] ?? "";
28475
+ const code = extracted.length > 0 && extracted.length <= 64 ? extracted : "producer_error";
28476
+ const record2 = error && typeof error === "object" ? error : void 0;
28477
+ const statusValue = record2?.statusCode ?? record2?.status ?? record2?.httpStatus;
28478
+ const httpStatus = typeof statusValue === "number" && Number.isInteger(statusValue) ? statusValue : void 0;
28479
+ const name = error instanceof Error ? error.name : void 0;
28480
+ const sessionCarry = parseSessionCarry(record2?.sessionCarry);
28481
+ return {
28482
+ code,
28483
+ failure: {
28484
+ classified: classifyRouteFailure({ code, text: text.slice(0, 500), httpStatus, name }),
28485
+ ...sessionCarry ? { sessionCarry } : {}
28486
+ }
28487
+ };
28488
+ } catch {
28489
+ return { code: "producer_error", failure: { classified: classifyRouteFailure({ code: "producer_error" }) } };
28490
+ }
28491
+ }
28106
28492
  function invokeProducer(producer, request) {
28107
- const reason = (error) => {
28108
- try {
28109
- const raw = error instanceof Error ? error.message : error;
28110
- const message = typeof raw === "string" ? raw : "";
28111
- let text = message;
28112
- if (request.capability) text = text.split(request.capability).join("[redacted]");
28113
- text = text.replace(/kxmcap_[A-Za-z0-9_-]+/g, "[redacted]");
28114
- const match = /^[a-z][a-z0-9]*(?:_[a-z0-9]+){1,3}/.exec(text);
28115
- const code = match?.[0] ?? "";
28116
- return code.length > 0 && code.length <= 64 ? code : "producer_error";
28117
- } catch {
28118
- return "producer_error";
28119
- }
28120
- };
28121
28493
  let pending;
28122
28494
  try {
28123
28495
  pending = Promise.resolve(producer.produce(request));
28124
28496
  } catch (error) {
28125
- return Promise.resolve({ error: true, errorCode: reason(error) });
28497
+ const observed = observeProducerFailure(error, request.capability);
28498
+ return Promise.resolve({ error: true, errorCode: observed.code, failure: observed.failure });
28126
28499
  }
28127
28500
  return pending.then(
28128
28501
  (result) => ({ result, error: false }),
28129
- (error) => ({ error: true, errorCode: reason(error) })
28502
+ (error) => {
28503
+ const observed = observeProducerFailure(error, request.capability);
28504
+ return { error: true, errorCode: observed.code, failure: observed.failure };
28505
+ }
28130
28506
  );
28131
28507
  }
28508
+ function stickyRouteFromEvents(context, runId) {
28509
+ const remembered = runStickyRoute.get(runId);
28510
+ if (remembered) return remembered;
28511
+ let found;
28512
+ for (const event of context.eventStore.events(runId, 0, 1e5)) {
28513
+ if (event.eventType !== "routing.attempt.recorded") continue;
28514
+ const routing = event.payload.routing;
28515
+ const route = routing?.providerMetadata?.fallbackRoute;
28516
+ if (typeof route === "string" && route.length > 0) found = route;
28517
+ }
28518
+ return found;
28519
+ }
28520
+ function stickyWalkRoute(context, step, agentId, runId, liveWrite) {
28521
+ const loaded = loadAgentFallback(context.projectRoot, agentId, { liveWrite });
28522
+ if (!loaded || loaded.policy.revert !== "never") return void 0;
28523
+ const sticky = stickyRouteFromEvents(context, runId);
28524
+ if (!sticky) return void 0;
28525
+ const candidate = loaded.chain.find((item) => item.routeId === sticky);
28526
+ if (!candidate) return void 0;
28527
+ return candidateToRoute(candidate, loaded.roleId);
28528
+ }
28529
+ function candidateToRoute(candidate, role) {
28530
+ return {
28531
+ provider: candidate.provider,
28532
+ model: candidate.model,
28533
+ selector: candidate.selector,
28534
+ harness: candidate.harness,
28535
+ routeId: candidate.routeId,
28536
+ role,
28537
+ permissions: [...candidate.permissions],
28538
+ ...candidate.effort ? { effort: candidate.effort } : {}
28539
+ };
28540
+ }
28541
+ function rememberAttemptFallback(attemptId, loaded, index, basePrompt) {
28542
+ if (loaded.chain.length < 2 || loaded.policy.onError.length === 0 || loaded.policy.maxSwitches <= 0) return;
28543
+ if (index < 0 || index >= loaded.chain.length) return;
28544
+ attemptFallback.set(attemptId, {
28545
+ policy: loaded.policy,
28546
+ chain: loaded.chain,
28547
+ index,
28548
+ switches: 0,
28549
+ basePrompt
28550
+ });
28551
+ }
28552
+ function appendRouteSwitch(context, member, routeSwitch) {
28553
+ const run = requireRun(context, member.run.runId);
28554
+ const now = (/* @__PURE__ */ new Date()).toISOString();
28555
+ const sequence = context.eventStore.nextSequence(run.runId);
28556
+ const event = {
28557
+ ...kxmEventBase(context, run, now, kxmMonotonicNs()),
28558
+ eventId: newKxmEventId(),
28559
+ eventType: "routing.route_switched",
28560
+ sequence,
28561
+ payload: {
28562
+ attemptId: member.attemptId,
28563
+ stepId: member.stepId,
28564
+ routeSwitch: {
28565
+ from: routeSwitch.from,
28566
+ to: routeSwitch.to,
28567
+ reason: routeSwitch.reason,
28568
+ ...routeSwitch.effort ? { effort: routeSwitch.effort } : {}
28569
+ }
28570
+ }
28571
+ };
28572
+ context.eventStore.appendEvent(event);
28573
+ const next = foldStoredKxmRun(context, run);
28574
+ persistKxmRunState(context, run.runId, next, sequence);
28575
+ try {
28576
+ context.logger?.({
28577
+ event: "route_switch",
28578
+ runId: run.runId,
28579
+ attemptId: member.attemptId,
28580
+ stepId: member.stepId,
28581
+ from: routeSwitch.from,
28582
+ to: routeSwitch.to,
28583
+ reason: routeSwitch.reason,
28584
+ ...routeSwitch.effort ? { effort: routeSwitch.effort } : {}
28585
+ });
28586
+ } catch {
28587
+ }
28588
+ }
28589
+ async function produceWithRouteFallback(context, member, producer) {
28590
+ const session = attemptFallback.get(member.attemptId);
28591
+ let request = member.request;
28592
+ let produced = await invokeProducer(producer, request);
28593
+ if (!session) return producerOutcome(produced);
28594
+ let carry;
28595
+ while (produced.error) {
28596
+ const current = session.chain[session.index];
28597
+ if (!current) break;
28598
+ const failure = produced.failure?.classified ?? classifyRouteFailure({ code: produced.errorCode, text: produced.errorCode });
28599
+ const decision = decideRouteSwitch({
28600
+ policy: session.policy,
28601
+ chain: session.chain,
28602
+ currentRouteId: current.routeId,
28603
+ switchesUsed: session.switches,
28604
+ failure,
28605
+ ...current.effort || member.request.thinking ? { currentEffort: current.effort ?? member.request.thinking } : {}
28606
+ });
28607
+ if (decision.action !== "switch") break;
28608
+ appendRouteSwitch(context, member, {
28609
+ from: current.routeId,
28610
+ to: decision.to.routeId,
28611
+ reason: decision.reason,
28612
+ ...decision.effort ? { effort: decision.effort } : {}
28613
+ });
28614
+ session.switches += 1;
28615
+ session.index = session.chain.findIndex((candidate) => candidate.routeId === decision.to.routeId);
28616
+ carry = mergeSessionCarry(carry, produced.failure?.sessionCarry);
28617
+ request = {
28618
+ ...member.request,
28619
+ prompt: carryForwardPrompt(session.basePrompt, carry),
28620
+ model: decision.to.model,
28621
+ provider: decision.to.provider,
28622
+ harness: decision.to.harness,
28623
+ ...decision.effort ? { thinking: decision.effort } : {}
28624
+ };
28625
+ produced = await invokeProducer(producer, request);
28626
+ }
28627
+ if (!produced.error && session.switches > 0 && session.policy.revert === "never") {
28628
+ const route = session.chain[session.index];
28629
+ if (route) {
28630
+ session.stickyRouteId = route.routeId;
28631
+ runStickyRoute.set(member.run.runId, route.routeId);
28632
+ }
28633
+ }
28634
+ return producerOutcome(produced);
28635
+ }
28636
+ function producerOutcome(produced) {
28637
+ return {
28638
+ error: produced.error,
28639
+ ...produced.result !== void 0 ? { result: produced.result } : {},
28640
+ ...produced.errorCode !== void 0 ? { errorCode: produced.errorCode } : {}
28641
+ };
28642
+ }
28132
28643
  var kxmGateDispatchSeams = {};
28133
28644
  function peekDispatchContextSources(context, runId) {
28134
28645
  if (!dispatchContextPresent(context.projectRoot)) return EMPTY_DISPATCH_SOURCES;
@@ -28402,9 +28913,9 @@ function readYamlFile(file) {
28402
28913
  return readModelDocument(file);
28403
28914
  }
28404
28915
  function readModelDocument(file) {
28405
- if (!existsSync13(file)) return void 0;
28916
+ if (!existsSync14(file)) return void 0;
28406
28917
  try {
28407
- const parsed = (0, import_yaml10.parse)(readFileSync11(file, "utf8"));
28918
+ const parsed = (0, import_yaml11.parse)(readFileSync12(file, "utf8"));
28408
28919
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
28409
28920
  return parsed;
28410
28921
  } catch {
@@ -28435,8 +28946,8 @@ function resolveProducerRoute(projectRoot, step, agentId) {
28435
28946
  }
28436
28947
  };
28437
28948
  }
28438
- const agentFile = findYamlBasename(join16(projectRoot, ".kxm", "agents"), agentId, "agent") ?? agentId;
28439
- const agent = readYamlFile(join16(projectRoot, ".kxm", "agents", `${agentFile}.yaml`));
28949
+ const agentFile = findYamlBasename(join17(projectRoot, ".kxm", "agents"), agentId, "agent") ?? agentId;
28950
+ const agent = readYamlFile(join17(projectRoot, ".kxm", "agents", `${agentFile}.yaml`));
28440
28951
  const role = typeof agent?.role === "string" ? agent.role : "";
28441
28952
  if (!role) {
28442
28953
  return {
@@ -28447,7 +28958,7 @@ function resolveProducerRoute(projectRoot, step, agentId) {
28447
28958
  }
28448
28959
  };
28449
28960
  }
28450
- const roleDoc = readYamlFile(join16(projectRoot, ".kxm", "roles", `${role}.yaml`));
28961
+ const roleDoc = readYamlFile(join17(projectRoot, ".kxm", "roles", `${role}.yaml`));
28451
28962
  const roster = Array.isArray(roleDoc?.roster) ? roleDoc.roster : void 0;
28452
28963
  if (!roster) {
28453
28964
  return {
@@ -28463,8 +28974,8 @@ function resolveProducerRoute(projectRoot, step, agentId) {
28463
28974
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
28464
28975
  const record2 = entry;
28465
28976
  if (typeof record2.route !== "string" || record2.route.length === 0) continue;
28466
- const routeFile = findYamlBasename(join16(projectRoot, ".kxm", "models"), record2.route, "route") ?? record2.route;
28467
- const modelPath = join16(projectRoot, ".kxm", "models", `${routeFile}.yaml`);
28977
+ const routeFile = findYamlBasename(join17(projectRoot, ".kxm", "models"), record2.route, "route") ?? record2.route;
28978
+ const modelPath = join17(projectRoot, ".kxm", "models", `${routeFile}.yaml`);
28468
28979
  const doc = readModelDocument(modelPath);
28469
28980
  if (!doc) {
28470
28981
  return {
@@ -28481,9 +28992,9 @@ function resolveProducerRoute(projectRoot, step, agentId) {
28481
28992
  const harness = typeof doc.harness === "string" ? doc.harness : "";
28482
28993
  if (!modelName || !vendor || !harness) continue;
28483
28994
  const candidates = [modelName, `${vendor}/${modelName}`, `${harness}/${modelName}`];
28484
- const admittedSelector = candidates.find((candidate) => policy.admitted.includes(candidate));
28995
+ const admittedSelector2 = candidates.find((candidate) => policy.admitted.includes(candidate));
28485
28996
  const disabledSelector = candidates.find((candidate) => policy.disabled.includes(candidate));
28486
- if (!admittedSelector && disabledSelector) {
28997
+ if (!admittedSelector2 && disabledSelector) {
28487
28998
  return {
28488
28999
  error: {
28489
29000
  reason: "step_unsupported",
@@ -28492,7 +29003,7 @@ function resolveProducerRoute(projectRoot, step, agentId) {
28492
29003
  }
28493
29004
  };
28494
29005
  }
28495
- const selector = admittedSelector ?? (modelName.includes("/") ? modelName : `${vendor}/${modelName}`);
29006
+ const selector = admittedSelector2 ?? (modelName.includes("/") ? modelName : `${vendor}/${modelName}`);
28496
29007
  if (policy.disabled.includes(selector)) {
28497
29008
  return {
28498
29009
  error: {
@@ -28754,6 +29265,14 @@ function prepareDispatch(context, runId, producerId, dispatchSources) {
28754
29265
  return { kind: "return", state, handoff: { ...routeResult.error, stepId } };
28755
29266
  }
28756
29267
  resolvedRoute = routeResult;
29268
+ const stickyRoute = stickyWalkRoute(
29269
+ context,
29270
+ step,
29271
+ agentId,
29272
+ run.runId,
29273
+ Object.values(step.repositories).some((access) => access === "write")
29274
+ );
29275
+ if (stickyRoute && stickyRoute.routeId !== resolvedRoute.routeId) resolvedRoute = stickyRoute;
28757
29276
  const writeRefusal = unsupportedLiveWrite(
28758
29277
  context.projectRoot,
28759
29278
  step,
@@ -28868,6 +29387,27 @@ function birthMember(context, input) {
28868
29387
  }
28869
29388
  resolvedRoute = routeResult;
28870
29389
  }
29390
+ const liveProducer = Boolean(input.producerId && input.producerId !== "driver-simulated");
29391
+ const liveWrite = liveProducer && Object.values(input.step.repositories).some((access) => access === "write");
29392
+ const loadedFallback = loadAgentFallback(context.projectRoot, agentId, { liveWrite });
29393
+ let fallbackIndex = -1;
29394
+ if (loadedFallback && loadedFallback.chain.length > 1 && loadedFallback.policy.maxSwitches > 0) {
29395
+ const sticky = loadedFallback.policy.revert === "never" ? stickyRouteFromEvents(context, run.runId) : void 0;
29396
+ const stickyIndex = sticky ? loadedFallback.chain.findIndex((candidate) => candidate.routeId === sticky) : -1;
29397
+ if (!resolvedRoute) {
29398
+ fallbackIndex = stickyIndex > 0 ? stickyIndex : 0;
29399
+ const start = loadedFallback.chain[fallbackIndex];
29400
+ if (start) resolvedRoute = candidateToRoute(start, loadedFallback.roleId);
29401
+ } else if (stickyIndex > 0 && resolvedRoute.routeId !== loadedFallback.chain[stickyIndex]?.routeId) {
29402
+ const start = loadedFallback.chain[stickyIndex];
29403
+ if (start) {
29404
+ resolvedRoute = candidateToRoute(start, loadedFallback.roleId);
29405
+ fallbackIndex = stickyIndex;
29406
+ }
29407
+ } else {
29408
+ fallbackIndex = loadedFallback.chain.findIndex((candidate) => candidate.routeId === resolvedRoute?.routeId);
29409
+ }
29410
+ }
28871
29411
  const dispatchContext = assembleDispatchContext(input.dispatchSources, {
28872
29412
  projectId: run.projectId,
28873
29413
  runId: run.runId,
@@ -29002,6 +29542,9 @@ ${generatedPrompt}` : generatedPrompt,
29002
29542
  } catch {
29003
29543
  }
29004
29544
  }
29545
+ if (loadedFallback && fallbackIndex >= 0) {
29546
+ rememberAttemptFallback(attemptId, loadedFallback, fallbackIndex, member.request.prompt ?? "");
29547
+ }
29005
29548
  kxmPanelDispatchSeams.afterBirth?.(member);
29006
29549
  return member;
29007
29550
  }
@@ -29105,7 +29648,7 @@ async function drivePanel(context, panel, producer) {
29105
29648
  const live = member.producerId !== "driver-simulated";
29106
29649
  const writes = Object.values(member.step.repositories).some((access) => access === "write");
29107
29650
  const before = live ? captureWorktreeWitness(context.projectRoot) : void 0;
29108
- const produced = await invokeProducer(producer, member.request);
29651
+ const produced = await produceWithRouteFallback(context, member, producer);
29109
29652
  if (live && produced.result && before) {
29110
29653
  const after = captureWorktreeWitness(context.projectRoot);
29111
29654
  return {
@@ -29300,6 +29843,8 @@ function engineRoutingMetadata(dispatch, producer) {
29300
29843
  metadata.askSha256 = kxmStepAskSha256(dispatch.plan, dispatch.stepId, dispatch.agentId);
29301
29844
  metadata.objectiveSha256 = dispatch.run.promptSha256;
29302
29845
  metadata.stepWrites = Object.values(dispatch.step.repositories).some((access) => access === "write");
29846
+ const stickyRouteId = attemptFallback.get(dispatch.attemptId)?.stickyRouteId;
29847
+ if (stickyRouteId && Object.keys(metadata).length < MAX_PROVIDER_METADATA_FIELDS) metadata.fallbackRoute = stickyRouteId;
29303
29848
  return metadata;
29304
29849
  }
29305
29850
  function producerRoutingRecord(context, dispatch, result, now, finalOutcome) {
@@ -29458,6 +30003,7 @@ function settleMember(context, dispatch, result, produceError, produceErrorCode)
29458
30003
  }
29459
30004
  }
29460
30005
  context.eventStore.settleCapability(dispatch.attemptId, "settled");
30006
+ attemptFallback.delete(dispatch.attemptId);
29461
30007
  for (const event of events) context.eventStore.appendEvent(event);
29462
30008
  const next = foldStoredKxmRun(context, run);
29463
30009
  persistKxmRunState(context, run.runId, next, events[events.length - 1].sequence);
@@ -30718,9 +31264,9 @@ var RuntimeHubClient = class {
30718
31264
  };
30719
31265
 
30720
31266
  // plugins/kxm/src/hub-binding.ts
30721
- import { existsSync as existsSync14, mkdirSync as mkdirSync6, readFileSync as readFileSync12, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
31267
+ import { existsSync as existsSync15, mkdirSync as mkdirSync6, readFileSync as readFileSync13, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
30722
31268
  import { homedir as homedir2 } from "node:os";
30723
- import { dirname as dirname8, isAbsolute as isAbsolute6, join as join17, resolve as resolve9 } from "node:path";
31269
+ import { dirname as dirname8, isAbsolute as isAbsolute6, join as join18, resolve as resolve9 } from "node:path";
30724
31270
  var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
30725
31271
  var HubBindingError = class extends Error {
30726
31272
  constructor(message) {
@@ -30736,16 +31282,16 @@ function resolveUserStateRoot(env) {
30736
31282
  }
30737
31283
  if (process.platform === "win32") {
30738
31284
  const localAppData = env.LOCALAPPDATA?.trim();
30739
- const base2 = localAppData && isAbsolute6(localAppData) ? localAppData : join17(homedir2(), "AppData", "Local");
31285
+ const base2 = localAppData && isAbsolute6(localAppData) ? localAppData : join18(homedir2(), "AppData", "Local");
30740
31286
  return resolve9(base2, "KXM");
30741
31287
  }
30742
31288
  if (process.platform === "darwin") return resolve9(homedir2(), "Library", "Application Support", "KXM");
30743
31289
  const xdgState = env.XDG_STATE_HOME?.trim();
30744
- const base = xdgState && isAbsolute6(xdgState) ? xdgState : join17(homedir2(), ".local", "state");
31290
+ const base = xdgState && isAbsolute6(xdgState) ? xdgState : join18(homedir2(), ".local", "state");
30745
31291
  return resolve9(base, "kxm");
30746
31292
  }
30747
31293
  function hubBindingFile(env = process.env) {
30748
- return join17(resolveUserStateRoot(env), "hub-binding.json");
31294
+ return join18(resolveUserStateRoot(env), "hub-binding.json");
30749
31295
  }
30750
31296
  function validateHubUrl(raw) {
30751
31297
  let parsed;
@@ -30765,10 +31311,10 @@ function isIsoTimestamp(value) {
30765
31311
  }
30766
31312
  function readHubBinding(env = process.env) {
30767
31313
  const file = hubBindingFile(env);
30768
- if (!existsSync14(file)) return void 0;
31314
+ if (!existsSync15(file)) return void 0;
30769
31315
  let parsed;
30770
31316
  try {
30771
- parsed = JSON.parse(readFileSync12(file, "utf8"));
31317
+ parsed = JSON.parse(readFileSync13(file, "utf8"));
30772
31318
  } catch {
30773
31319
  throw new HubBindingError(`malformed hub binding at ${file}`);
30774
31320
  }
@@ -30790,9 +31336,9 @@ function readHubBinding(env = process.env) {
30790
31336
  }
30791
31337
 
30792
31338
  // plugins/kxm/src/hub-env.ts
30793
- import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync13, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
31339
+ import { existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync14, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
30794
31340
  import { homedir as homedir3 } from "node:os";
30795
- import { dirname as dirname9, isAbsolute as isAbsolute7, join as join18, resolve as resolve10 } from "node:path";
31341
+ import { dirname as dirname9, isAbsolute as isAbsolute7, join as join19, resolve as resolve10 } from "node:path";
30796
31342
  var HUB_ENV_SCHEMA = "kxm.hub-env.v1";
30797
31343
  var HubEnvError = class extends Error {
30798
31344
  constructor(message) {
@@ -30808,23 +31354,23 @@ function resolveUserStateRoot2(env) {
30808
31354
  }
30809
31355
  if (process.platform === "win32") {
30810
31356
  const localAppData = env.LOCALAPPDATA?.trim();
30811
- const base2 = localAppData && isAbsolute7(localAppData) ? localAppData : join18(homedir3(), "AppData", "Local");
31357
+ const base2 = localAppData && isAbsolute7(localAppData) ? localAppData : join19(homedir3(), "AppData", "Local");
30812
31358
  return resolve10(base2, "KXM");
30813
31359
  }
30814
31360
  if (process.platform === "darwin") return resolve10(homedir3(), "Library", "Application Support", "KXM");
30815
31361
  const xdgState = env.XDG_STATE_HOME?.trim();
30816
- const base = xdgState && isAbsolute7(xdgState) ? xdgState : join18(homedir3(), ".local", "state");
31362
+ const base = xdgState && isAbsolute7(xdgState) ? xdgState : join19(homedir3(), ".local", "state");
30817
31363
  return resolve10(base, "kxm");
30818
31364
  }
30819
31365
  function hubEnvFile(env = process.env) {
30820
- return join18(resolveUserStateRoot2(env), "hub-env.json");
31366
+ return join19(resolveUserStateRoot2(env), "hub-env.json");
30821
31367
  }
30822
31368
  function readHubEnvRecord(env = process.env) {
30823
31369
  const file = hubEnvFile(env);
30824
- if (!existsSync15(file)) return void 0;
31370
+ if (!existsSync16(file)) return void 0;
30825
31371
  let parsed;
30826
31372
  try {
30827
- parsed = JSON.parse(readFileSync13(file, "utf8"));
31373
+ parsed = JSON.parse(readFileSync14(file, "utf8"));
30828
31374
  } catch (error) {
30829
31375
  throw new HubEnvError(`hub env file is malformed at ${file}: ${error instanceof Error ? error.message : String(error)}`);
30830
31376
  }
@@ -30864,7 +31410,7 @@ function resolveClientHubAuthToken(env, project) {
30864
31410
  }
30865
31411
 
30866
31412
  // plugins/kxm/src/logger.ts
30867
- import { appendFileSync, existsSync as existsSync16, mkdirSync as mkdirSync8, renameSync as renameSync4, statSync as statSync5, unlinkSync as unlinkSync2 } from "node:fs";
31413
+ import { appendFileSync, existsSync as existsSync17, mkdirSync as mkdirSync8, renameSync as renameSync4, statSync as statSync5, unlinkSync as unlinkSync2 } from "node:fs";
30868
31414
  import { dirname as dirname10 } from "node:path";
30869
31415
  var LOG_LEVEL_PRIORITY = {
30870
31416
  debug: 10,
@@ -30902,7 +31448,7 @@ function redactLogValue(val, key) {
30902
31448
  function rotateLogFiles(filePath, maxFiles) {
30903
31449
  for (let i = maxFiles; i >= 1; i--) {
30904
31450
  const current = `${filePath}.${i}`;
30905
- if (existsSync16(current)) {
31451
+ if (existsSync17(current)) {
30906
31452
  if (i >= maxFiles) {
30907
31453
  try {
30908
31454
  unlinkSync2(current);
@@ -30916,7 +31462,7 @@ function rotateLogFiles(filePath, maxFiles) {
30916
31462
  }
30917
31463
  }
30918
31464
  }
30919
- if (existsSync16(filePath)) {
31465
+ if (existsSync17(filePath)) {
30920
31466
  try {
30921
31467
  renameSync4(filePath, `${filePath}.1`);
30922
31468
  } catch {
@@ -30933,7 +31479,7 @@ function createLogger(options) {
30933
31479
  const shouldStdout = options.stdout ?? !isDaemon;
30934
31480
  const correlationDefaults = options.correlation ?? {};
30935
31481
  let currentSize = 0;
30936
- if (filePath && existsSync16(filePath)) {
31482
+ if (filePath && existsSync17(filePath)) {
30937
31483
  try {
30938
31484
  currentSize = statSync5(filePath).size;
30939
31485
  } catch {
@@ -31014,7 +31560,7 @@ function createLogger(options) {
31014
31560
 
31015
31561
  // plugins/kxm/src/runtime-supervisor.ts
31016
31562
  function kxmSupervisorTokenFile(paths) {
31017
- return join19(paths.runtimeDir, "supervisor.token");
31563
+ return join20(paths.runtimeDir, "supervisor.token");
31018
31564
  }
31019
31565
  function publishKxmSupervisorToken(paths, token) {
31020
31566
  const file = kxmSupervisorTokenFile(paths);
@@ -31042,7 +31588,7 @@ function readKxmSupervisorToken(paths) {
31042
31588
  if (stat.isSymbolicLink() || !stat.isFile()) {
31043
31589
  throw runtimeError("runtime_path_invalid", file, "supervisor token file must be a regular file, not a link");
31044
31590
  }
31045
- const token = readFileSync14(file, "utf8").trim();
31591
+ const token = readFileSync15(file, "utf8").trim();
31046
31592
  return token.length >= 32 ? token : void 0;
31047
31593
  }
31048
31594
  function processAlive(pid) {
@@ -31056,11 +31602,11 @@ function processAlive(pid) {
31056
31602
  var HEARTBEAT_STALE_MS = 15e3;
31057
31603
  var SUPERVISOR_ERROR_MAX_AGE_MS = 3e4;
31058
31604
  function supervisorErrorFile(paths) {
31059
- return join19(paths.runtimeDir, "supervisor.error");
31605
+ return join20(paths.runtimeDir, "supervisor.error");
31060
31606
  }
31061
31607
  function clearSupervisorError(paths) {
31062
31608
  const file = supervisorErrorFile(paths);
31063
- if (existsSync17(file)) rmSync4(file, { force: true });
31609
+ if (existsSync18(file)) rmSync4(file, { force: true });
31064
31610
  }
31065
31611
  function recordSupervisorError(paths, message) {
31066
31612
  try {
@@ -31077,7 +31623,7 @@ function readRecentSupervisorError(paths) {
31077
31623
  const ageMs = Date.now() - stat.mtimeMs;
31078
31624
  if (ageMs > SUPERVISOR_ERROR_MAX_AGE_MS) return void 0;
31079
31625
  try {
31080
- return readFileSync14(file, "utf8").trim();
31626
+ return readFileSync15(file, "utf8").trim();
31081
31627
  } catch {
31082
31628
  return void 0;
31083
31629
  }
@@ -31116,7 +31662,7 @@ function supervisorStatusOf(record2) {
31116
31662
  };
31117
31663
  }
31118
31664
  function kxmSupervisorStatus(paths, options = {}) {
31119
- if (!existsSync17(paths.registryDb)) return { running: false };
31665
+ if (!existsSync18(paths.registryDb)) return { running: false };
31120
31666
  if (options.readOnly) {
31121
31667
  const database = openReadOnlyDatabase(paths.registryDb);
31122
31668
  try {
@@ -31182,7 +31728,7 @@ async function ensureKxmSupervisor(options = {}) {
31182
31728
  throw runtimeError("runtime_supervisor_unreachable", paths.registryDb, `runtime supervisor pid ${status.pid} is registered as running but cannot be probed`);
31183
31729
  }
31184
31730
  clearSupervisorError(paths);
31185
- const scriptPath = join19(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
31731
+ const scriptPath = join20(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
31186
31732
  const spawnImpl = options.spawnImpl ?? ((script, env) => {
31187
31733
  const child = spawn3(process.execPath, [script], {
31188
31734
  detached: true,
@@ -31405,7 +31951,7 @@ function syncFailureText(error) {
31405
31951
  return `${code ? `${code}: ` : ""}${message}`.replace(/(kxm_[A-Za-z0-9_]+|[A-Za-z0-9._-]{40,})/g, "[redacted]").slice(0, 300);
31406
31952
  }
31407
31953
  function runtimeSupervisorLogFile(paths) {
31408
- return join19(paths.runtimeDir, "logs", "kxm-runtime.jsonl");
31954
+ return join20(paths.runtimeDir, "logs", "kxm-runtime.jsonl");
31409
31955
  }
31410
31956
  async function startKxmRuntimeSupervisor(options = {}) {
31411
31957
  const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
@@ -31530,8 +32076,8 @@ async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now, e
31530
32076
  openRunIds = unsettledRunIds(existing2);
31531
32077
  } else {
31532
32078
  const registration = registry.projectByRoot(projectRoot);
31533
- const eventsPath = join19(paths.projectsDir, registration?.projectKey ?? projectRuntimeKey(projectRoot), "run-events.db");
31534
- if (registration && existsSync17(eventsPath)) {
32079
+ const eventsPath = join20(paths.projectsDir, registration?.projectKey ?? projectRuntimeKey(projectRoot), "run-events.db");
32080
+ if (registration && existsSync18(eventsPath)) {
31535
32081
  const store = new KxmRunEventStore(eventsPath);
31536
32082
  try {
31537
32083
  openRunIds = store.runsForProject(registration.projectId, 1e4).filter((run) => !SETTLED_RUN_STATUS.has(run.status)).map((run) => run.runId);