@kontextmind/kxm 0.7.149 → 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.
@@ -5567,7 +5567,7 @@ var require_fast_uri = __commonJS({
5567
5567
  normalizeString(uri, options);
5568
5568
  } else if (typeof uri === "object") {
5569
5569
  uri = /** @type {T} */
5570
- parse11(serialize(uri, options), options);
5570
+ parse12(serialize(uri, options), options);
5571
5571
  }
5572
5572
  return uri;
5573
5573
  }
@@ -5607,8 +5607,8 @@ var require_fast_uri = __commonJS({
5607
5607
  function resolveComponent(base, relative8, options, skipNormalization) {
5608
5608
  const target = {};
5609
5609
  if (!skipNormalization) {
5610
- base = parse11(serialize(base, options), options);
5611
- relative8 = parse11(serialize(relative8, options), options);
5610
+ base = parse12(serialize(base, options), options);
5611
+ relative8 = parse12(serialize(relative8, options), options);
5612
5612
  }
5613
5613
  options = options || {};
5614
5614
  if (!options.tolerant && relative8.scheme) {
@@ -5900,7 +5900,7 @@ var require_fast_uri = __commonJS({
5900
5900
  }
5901
5901
  return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
5902
5902
  }
5903
- function parse11(uri, opts) {
5903
+ function parse12(uri, opts) {
5904
5904
  return parseWithStatus(uri, opts).parsed;
5905
5905
  }
5906
5906
  function normalizeString(uri, opts) {
@@ -5937,7 +5937,7 @@ var require_fast_uri = __commonJS({
5937
5937
  resolveComponent,
5938
5938
  equal,
5939
5939
  serialize,
5940
- parse: parse11
5940
+ parse: parse12
5941
5941
  };
5942
5942
  module.exports = fastUri;
5943
5943
  module.exports.default = fastUri;
@@ -16410,7 +16410,7 @@ var require_public_api = __commonJS({
16410
16410
  }
16411
16411
  return doc;
16412
16412
  }
16413
- function parse11(src, reviver, options) {
16413
+ function parse12(src, reviver, options) {
16414
16414
  let _reviver = void 0;
16415
16415
  if (typeof reviver === "function") {
16416
16416
  _reviver = reviver;
@@ -16451,7 +16451,7 @@ var require_public_api = __commonJS({
16451
16451
  return value.toString(options);
16452
16452
  return new Document.Document(value, _replacer, options).toString(options);
16453
16453
  }
16454
- exports.parse = parse11;
16454
+ exports.parse = parse12;
16455
16455
  exports.parseAllDocuments = parseAllDocuments;
16456
16456
  exports.parseDocument = parseDocument3;
16457
16457
  exports.stringify = stringify12;
@@ -16968,7 +16968,7 @@ function validateRoleShape(document, id, label, issues) {
16968
16968
  if (!closedObject(fallback, FALLBACK_KEYS, path4, issues)) return;
16969
16969
  if (fallback.onError !== void 0) {
16970
16970
  if (!Array.isArray(fallback.onError) || new Set(fallback.onError).size !== fallback.onError.length || fallback.onError.some((item) => !FALLBACK_ERRORS.includes(item))) {
16971
- issues.push(issue2("schema", "schema_enum", path4, "onError must be unique rate_limit, transport, or provider_unavailable values"));
16971
+ issues.push(issue2("schema", "schema_enum", path4, "onError must be unique rate_limit, transport, provider_unavailable, or context_overflow values"));
16972
16972
  }
16973
16973
  }
16974
16974
  if (fallback.maxSwitches !== void 0 && (!Number.isInteger(fallback.maxSwitches) || fallback.maxSwitches < 0)) {
@@ -17226,7 +17226,7 @@ var init_policy_draft = __esm({
17226
17226
  TEMPLATE_KEYS = Object.freeze(["template", "schema"]);
17227
17227
  POLICY_KEYS = Object.freeze(["vendorIndependenceRequired", "maxTransitions", "requiresGateVerification", "fallback"]);
17228
17228
  FALLBACK_KEYS = Object.freeze(["onError", "maxSwitches", "revert"]);
17229
- FALLBACK_ERRORS = Object.freeze(["rate_limit", "transport", "provider_unavailable"]);
17229
+ FALLBACK_ERRORS = Object.freeze(["rate_limit", "transport", "provider_unavailable", "context_overflow"]);
17230
17230
  FALLBACK_REVERT = Object.freeze(["next_run", "never"]);
17231
17231
  ROSTER_ENTRY_KEYS = Object.freeze(["route", "effort", "mode"]);
17232
17232
  CRITIC_PURPOSES = Object.freeze(["reviewer-arch", "reviewer-cli"]);
@@ -25145,6 +25145,54 @@ var init_routes = __esm({
25145
25145
  }
25146
25146
  });
25147
25147
 
25148
+ // plugins/kxm/src/route-switch.ts
25149
+ function parseRouteSwitchRecord(payload, identity = {}) {
25150
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) return void 0;
25151
+ const routeSwitch = payload.routeSwitch;
25152
+ if (!routeSwitch || typeof routeSwitch !== "object" || Array.isArray(routeSwitch)) return void 0;
25153
+ const record = routeSwitch;
25154
+ const from = record.from;
25155
+ const to = record.to;
25156
+ const reason = record.reason;
25157
+ if (typeof from !== "string" || typeof to !== "string" || typeof reason !== "string") return void 0;
25158
+ if (!WALKABLE_CLASSES.includes(reason)) return void 0;
25159
+ const attemptId = typeof identity.attemptId === "string" ? identity.attemptId : typeof payload.attemptId === "string" ? payload.attemptId : "";
25160
+ const stepId = typeof identity.stepId === "string" ? identity.stepId : typeof payload.stepId === "string" ? payload.stepId : "";
25161
+ if (!attemptId || !stepId) return void 0;
25162
+ const effort = typeof record.effort === "string" && EFFORTS2.has(record.effort) ? record.effort : void 0;
25163
+ return {
25164
+ from,
25165
+ to,
25166
+ reason,
25167
+ attemptId,
25168
+ stepId,
25169
+ ...effort ? { effort } : {},
25170
+ ...identity.runId ? { runId: identity.runId } : {}
25171
+ };
25172
+ }
25173
+ var WALKABLE_CLASSES, EFFORTS2;
25174
+ var init_route_switch = __esm({
25175
+ "plugins/kxm/src/route-switch.ts"() {
25176
+ "use strict";
25177
+ WALKABLE_CLASSES = ["rate_limit", "transport", "provider_unavailable", "context_overflow"];
25178
+ EFFORTS2 = /* @__PURE__ */ new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
25179
+ }
25180
+ });
25181
+
25182
+ // plugins/kxm/src/route-fallback.ts
25183
+ var import_yaml8;
25184
+ var init_route_fallback = __esm({
25185
+ "plugins/kxm/src/route-fallback.ts"() {
25186
+ "use strict";
25187
+ import_yaml8 = __toESM(require_dist(), 1);
25188
+ init_harness();
25189
+ init_routes();
25190
+ init_route_switch();
25191
+ init_workforce_names();
25192
+ init_route_switch();
25193
+ }
25194
+ });
25195
+
25148
25196
  // plugins/kxm/src/worktree-witness.ts
25149
25197
  var init_worktree_witness = __esm({
25150
25198
  "plugins/kxm/src/worktree-witness.ts"() {
@@ -25191,7 +25239,7 @@ function parseFrontmatter(content) {
25191
25239
  }
25192
25240
  function parseMemoryRecord(raw, filename = "memory.md") {
25193
25241
  const { frontmatter, body } = parseFrontmatter(raw);
25194
- const data = (0, import_yaml8.parse)(frontmatter);
25242
+ const data = (0, import_yaml9.parse)(frontmatter);
25195
25243
  if (!data || typeof data !== "object" || Array.isArray(data)) {
25196
25244
  throw new Error(`invalid YAML frontmatter in ${filename}`);
25197
25245
  }
@@ -25271,7 +25319,7 @@ function formatMemoryRecord(record) {
25271
25319
  lifecycle: record.lifecycle,
25272
25320
  evidenceRefs: record.evidenceRefs
25273
25321
  };
25274
- const yamlText = (0, import_yaml8.stringify)(frontmatter).trim();
25322
+ const yamlText = (0, import_yaml9.stringify)(frontmatter).trim();
25275
25323
  const bodyText = record.body?.trim() ?? "";
25276
25324
  return bodyText ? `---
25277
25325
  ${yamlText}
@@ -25428,11 +25476,11 @@ function syncHarnessMemory(repoRoot, options = {}) {
25428
25476
  }
25429
25477
  return { updated, unchanged, missing };
25430
25478
  }
25431
- var import_yaml8, MEMORY_SCHEMA, MEMORY_BRIEF_SCHEMA, MEMORY_MARKER_START, MEMORY_MARKER_END, VALID_SCOPES, VALID_AUTHORITIES, VALID_CONFIDENCES, VALID_LIFECYCLES, BANNED_CONTROL_PLANE_FIELDS, HARNESS_INSTRUCTION_FILES;
25479
+ var import_yaml9, MEMORY_SCHEMA, MEMORY_BRIEF_SCHEMA, MEMORY_MARKER_START, MEMORY_MARKER_END, VALID_SCOPES, VALID_AUTHORITIES, VALID_CONFIDENCES, VALID_LIFECYCLES, BANNED_CONTROL_PLANE_FIELDS, HARNESS_INSTRUCTION_FILES;
25432
25480
  var init_memory = __esm({
25433
25481
  "plugins/kxm/src/memory.ts"() {
25434
25482
  "use strict";
25435
- import_yaml8 = __toESM(require_dist(), 1);
25483
+ import_yaml9 = __toESM(require_dist(), 1);
25436
25484
  init_redact();
25437
25485
  MEMORY_SCHEMA = "kxm.memory.v1";
25438
25486
  MEMORY_BRIEF_SCHEMA = "kxm.memory-brief.v1";
@@ -25484,7 +25532,7 @@ function parseSkillFrontmatter(content) {
25484
25532
  return { frontmatter: null, body: content };
25485
25533
  }
25486
25534
  try {
25487
- const parsed = (0, import_yaml9.parse)(rawFm);
25535
+ const parsed = (0, import_yaml10.parse)(rawFm);
25488
25536
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
25489
25537
  return { frontmatter: parsed, body: rawBody };
25490
25538
  }
@@ -25541,11 +25589,11 @@ function boundedList(value, field) {
25541
25589
  function readdirSorted(dir) {
25542
25590
  return readdirSync7(dir).filter((entry) => statSync3(join17(dir, entry)).isDirectory()).sort();
25543
25591
  }
25544
- var import_yaml9, SKILL_CANDIDATE_SCHEMA, SKILL_EVALUATION_SCHEMA, SKILL_DECISION_SCHEMA, MAX_SKILL_NAME_CHARS, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_EVIDENCE_REFS, MAX_SKILL_MODELS, PROMOTION_REQUIRED_EVALUATIONS, SkillLifecycleError, SkillLifecycle;
25592
+ var import_yaml10, SKILL_CANDIDATE_SCHEMA, SKILL_EVALUATION_SCHEMA, SKILL_DECISION_SCHEMA, MAX_SKILL_NAME_CHARS, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_EVIDENCE_REFS, MAX_SKILL_MODELS, PROMOTION_REQUIRED_EVALUATIONS, SkillLifecycleError, SkillLifecycle;
25545
25593
  var init_skills = __esm({
25546
25594
  "plugins/kxm/src/skills.ts"() {
25547
25595
  "use strict";
25548
- import_yaml9 = __toESM(require_dist(), 1);
25596
+ import_yaml10 = __toESM(require_dist(), 1);
25549
25597
  init_redact();
25550
25598
  SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
25551
25599
  SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
@@ -26318,12 +26366,14 @@ function computeDecayedWeight(recordedAt, halfLifeDays = 14, now = Date.now()) {
26318
26366
  }
26319
26367
  function generateRoutingReport(records, options = {}) {
26320
26368
  const generatedAt = options.now ? options.now() : (/* @__PURE__ */ new Date()).toISOString();
26369
+ const routeSwitches = options.routeSwitches?.filter((item) => item.from && item.to) ?? [];
26321
26370
  if (records.length === 0) {
26322
26371
  return {
26323
26372
  schema: ROUTING_REPORT_SCHEMA,
26324
26373
  generatedAt,
26325
26374
  totalAttempts: 0,
26326
- rows: []
26375
+ rows: [],
26376
+ ...routeSwitches.length > 0 ? { routeSwitches: [...routeSwitches] } : {}
26327
26377
  };
26328
26378
  }
26329
26379
  const groups = /* @__PURE__ */ new Map();
@@ -26487,13 +26537,22 @@ function generateRoutingReport(records, options = {}) {
26487
26537
  schema: ROUTING_REPORT_SCHEMA,
26488
26538
  generatedAt,
26489
26539
  totalAttempts: records.length,
26490
- rows
26540
+ rows,
26541
+ ...routeSwitches.length > 0 ? { routeSwitches: [...routeSwitches] } : {}
26491
26542
  };
26492
26543
  }
26493
26544
  function formatRoutingReport(report2, options = {}) {
26494
- if (report2.rows.length === 0) {
26545
+ if (report2.rows.length === 0 && (!report2.routeSwitches || report2.routeSwitches.length === 0)) {
26495
26546
  return "no routing records to report";
26496
26547
  }
26548
+ if (report2.rows.length === 0) {
26549
+ const lines2 = ["no routing records to report", "", `Route switches (${report2.routeSwitches.length})`];
26550
+ for (const item of report2.routeSwitches) {
26551
+ const effort = item.effort ? ` effort ${item.effort}` : "";
26552
+ lines2.push(` ${item.from} -> ${item.to} (${item.reason}${effort}) step ${item.stepId}`);
26553
+ }
26554
+ return lines2.join("\n");
26555
+ }
26497
26556
  const showListCost = Boolean(options.equivalentListCost);
26498
26557
  const headers = [
26499
26558
  "Harness".padEnd(10),
@@ -26549,6 +26608,14 @@ function formatRoutingReport(report2, options = {}) {
26549
26608
  if (report2.rows.some((r) => r.flagged)) {
26550
26609
  lines.push("* = unknown-cost attempts present (never ranked cheapest)");
26551
26610
  }
26611
+ if (report2.routeSwitches && report2.routeSwitches.length > 0) {
26612
+ lines.push("");
26613
+ lines.push(`Route switches (${report2.routeSwitches.length})`);
26614
+ for (const item of report2.routeSwitches) {
26615
+ const effort = item.effort ? ` effort ${item.effort}` : "";
26616
+ lines.push(` ${item.from} -> ${item.to} (${item.reason}${effort}) step ${item.stepId}`);
26617
+ }
26618
+ }
26552
26619
  return lines.join("\n");
26553
26620
  }
26554
26621
  var ROUTING_RECORD_SCHEMA, ROUTING_RECORD_V2_SCHEMA, BEHAVIORAL_HASH_VERSION, MAX_CONTEXT_ITEM_IDS, MAX_SKILL_REFS, MAX_PROVIDER_METADATA_FIELDS, ROUTING_REPORT_SCHEMA;
@@ -26575,7 +26642,7 @@ function readYamlFile(file) {
26575
26642
  function readModelDocument(file) {
26576
26643
  if (!existsSync18(file)) return void 0;
26577
26644
  try {
26578
- const parsed = (0, import_yaml10.parse)(readFileSync16(file, "utf8"));
26645
+ const parsed = (0, import_yaml11.parse)(readFileSync16(file, "utf8"));
26579
26646
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
26580
26647
  return parsed;
26581
26648
  } catch {
@@ -26999,12 +27066,13 @@ function pinnedGatesForCompiledPlan(plan, bundle, projectRoot) {
26999
27066
  controlRoot: { repositoryId: "control", projectKey: projectRuntimeKey(projectRoot) }
27000
27067
  };
27001
27068
  }
27002
- var import_yaml10, ENGINE_ROUTING_METADATA_KEYS, MAX_PRODUCER_ROUTING_METADATA_FIELDS;
27069
+ var import_yaml11, ENGINE_ROUTING_METADATA_KEYS, MAX_PRODUCER_ROUTING_METADATA_FIELDS;
27003
27070
  var init_engine = __esm({
27004
27071
  "plugins/kxm/src/engine.ts"() {
27005
27072
  "use strict";
27006
- import_yaml10 = __toESM(require_dist(), 1);
27073
+ import_yaml11 = __toESM(require_dist(), 1);
27007
27074
  init_routes();
27075
+ init_route_fallback();
27008
27076
  init_workforce_names();
27009
27077
  init_worktree_witness();
27010
27078
  init_context_packet();
@@ -27839,14 +27907,14 @@ async function refreshModelInventory(options) {
27839
27907
  for (const item of nous.data) add(item, "nous", "discount");
27840
27908
  const inventory = { schema: "kxm.model-inventory.v1", fetchedAt, currency: "USD", sources, models: [...byId.values()].sort((a, b2) => a.id.localeCompare(b2.id)) };
27841
27909
  mkdirSync19(join28(options.outputRoot, ".kxm", "models"), { recursive: true });
27842
- writeFileSync18(join28(options.outputRoot, ".kxm", "models", "inventory.yaml"), (0, import_yaml15.stringify)(inventory), "utf8");
27910
+ writeFileSync18(join28(options.outputRoot, ".kxm", "models", "inventory.yaml"), (0, import_yaml16.stringify)(inventory), "utf8");
27843
27911
  return inventory;
27844
27912
  }
27845
- var import_yaml15, OR_URL, NOUS_URL;
27913
+ var import_yaml16, OR_URL, NOUS_URL;
27846
27914
  var init_model_inventory = __esm({
27847
27915
  "plugins/kxm/src/model-inventory.ts"() {
27848
27916
  "use strict";
27849
- import_yaml15 = __toESM(require_dist(), 1);
27917
+ import_yaml16 = __toESM(require_dist(), 1);
27850
27918
  init_oneshot_process();
27851
27919
  OR_URL = "https://openrouter.ai/api/v1/models";
27852
27920
  NOUS_URL = "https://inference-api.nousresearch.com/v1/models";
@@ -35606,7 +35674,7 @@ init_runtime_store();
35606
35674
  init_types();
35607
35675
 
35608
35676
  // plugins/kxm/src/cli/roles.ts
35609
- var import_yaml11 = __toESM(require_dist(), 1);
35677
+ var import_yaml12 = __toESM(require_dist(), 1);
35610
35678
  init_sqlite();
35611
35679
  init_role();
35612
35680
  init_project_config();
@@ -35707,7 +35775,7 @@ async function cmdRoleGet(runtime, roleId, options) {
35707
35775
  runtime.io,
35708
35776
  runtime.json,
35709
35777
  { ok: true, command: "role get", roleId, scope: result.scope, filePath: result.filePath, role: result.role },
35710
- (0, import_yaml11.stringify)(result.role)
35778
+ (0, import_yaml12.stringify)(result.role)
35711
35779
  );
35712
35780
  return 0;
35713
35781
  }
@@ -35756,7 +35824,7 @@ async function cmdRoleAdd(runtime, roleId, options) {
35756
35824
  if (options.file) {
35757
35825
  const filePath = resolve14(runtime.cwd, options.file);
35758
35826
  const content = readFileSync20(filePath, "utf8");
35759
- roleDef = (0, import_yaml11.parse)(content);
35827
+ roleDef = (0, import_yaml12.parse)(content);
35760
35828
  roleDef.id = roleId;
35761
35829
  roleDef.schema = "kxm.role.v2";
35762
35830
  roleDef.purpose ??= rolePurposeForId(roleDef.id);
@@ -35795,7 +35863,7 @@ async function cmdRoleAdd(runtime, roleId, options) {
35795
35863
  );
35796
35864
  return 2;
35797
35865
  }
35798
- const issues = kxmRoleWriteIssues(projectRoot2, roleDef.id, (0, import_yaml11.stringify)(roleDef));
35866
+ const issues = kxmRoleWriteIssues(projectRoot2, roleDef.id, (0, import_yaml12.stringify)(roleDef));
35799
35867
  if (issues.length > 0) {
35800
35868
  print(
35801
35869
  runtime.io,
@@ -36091,7 +36159,7 @@ async function cmdRoleResume(runtime, runId, ruling) {
36091
36159
  }
36092
36160
 
36093
36161
  // plugins/kxm/src/cli/workflows.ts
36094
- var import_yaml13 = __toESM(require_dist(), 1);
36162
+ var import_yaml14 = __toESM(require_dist(), 1);
36095
36163
  init_sqlite();
36096
36164
  import { randomUUID as randomUUID8 } from "node:crypto";
36097
36165
  import { existsSync as existsSync23, readFileSync as readFileSync22 } from "node:fs";
@@ -36528,7 +36596,7 @@ async function watchGithubChecks(input) {
36528
36596
  }
36529
36597
 
36530
36598
  // plugins/kxm/src/workflow-manager.ts
36531
- var import_yaml12 = __toESM(require_dist(), 1);
36599
+ var import_yaml13 = __toESM(require_dist(), 1);
36532
36600
  init_config();
36533
36601
  init_engine_compile();
36534
36602
  init_project_config();
@@ -36541,7 +36609,7 @@ function assertWorkflowId(workflowId) {
36541
36609
  }
36542
36610
  var workflowSchemaRegistry;
36543
36611
  function workflowPayload(workflowId, content, filePath) {
36544
- const payload = typeof content === "string" ? content : (0, import_yaml12.stringify)(content);
36612
+ const payload = typeof content === "string" ? content : (0, import_yaml13.stringify)(content);
36545
36613
  const value = parseRestrictedYaml2(payload, filePath);
36546
36614
  const issues = (workflowSchemaRegistry ??= new KxmSchemaRegistry()).validate("workflow", value, filePath);
36547
36615
  if (issues.length > 0) throw new KxmConfigError(issues);
@@ -37036,7 +37104,7 @@ async function cmdWorkflowAdd(runtime, workflowId, options) {
37036
37104
  } else if (!content) {
37037
37105
  content = scaffoldWorkflowDefinition(options.description || `Workflow ${workflowId}`);
37038
37106
  }
37039
- const document = typeof content === "string" ? content : (0, import_yaml13.stringify)(content);
37107
+ const document = typeof content === "string" ? content : (0, import_yaml14.stringify)(content);
37040
37108
  let repoRoot = runtime.cwd;
37041
37109
  if (scope === "local") {
37042
37110
  const projectRoot = discoverKxmProjectRoot(runtime.cwd);
@@ -37480,7 +37548,7 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
37480
37548
  }
37481
37549
 
37482
37550
  // plugins/kxm/src/cli/tasks.ts
37483
- var import_yaml16 = __toESM(require_dist(), 1);
37551
+ var import_yaml17 = __toESM(require_dist(), 1);
37484
37552
  init_harness();
37485
37553
  import { existsSync as existsSync30, readFileSync as readFileSync28, readdirSync as readdirSync11 } from "node:fs";
37486
37554
  import { basename as basename7, join as join33, resolve as resolve22 } from "node:path";
@@ -37634,7 +37702,7 @@ function suggestWorkflowAndRoles(prompt, options = {}) {
37634
37702
  }
37635
37703
 
37636
37704
  // plugins/kxm/src/task-manager.ts
37637
- var import_yaml14 = __toESM(require_dist(), 1);
37705
+ var import_yaml15 = __toESM(require_dist(), 1);
37638
37706
  import { randomUUID as randomUUID9 } from "node:crypto";
37639
37707
  import { existsSync as existsSync24, mkdirSync as mkdirSync17, readFileSync as readFileSync23, readdirSync as readdirSync9, writeFileSync as writeFileSync17 } from "node:fs";
37640
37708
  import { join as join26, resolve as resolve17 } from "node:path";
@@ -37668,7 +37736,7 @@ function createGoal(repoRoot, input, options = {}) {
37668
37736
  };
37669
37737
  if (options.dryRun) return record;
37670
37738
  mkdirSync17(goalsDirectory(repoRoot), { recursive: true });
37671
- writeFileSync17(goalFilePath(repoRoot, id), (0, import_yaml14.stringify)(record).trim() + "\n", "utf8");
37739
+ writeFileSync17(goalFilePath(repoRoot, id), (0, import_yaml15.stringify)(record).trim() + "\n", "utf8");
37672
37740
  return record;
37673
37741
  }
37674
37742
  function listGoals(repoRoot) {
@@ -37680,7 +37748,7 @@ function listGoals(repoRoot) {
37680
37748
  if (entry.isFile() && (entry.name.endsWith(".yaml") || entry.name.endsWith(".yml"))) {
37681
37749
  try {
37682
37750
  const text = readFileSync23(join26(dir, entry.name), "utf8");
37683
- const doc = (0, import_yaml14.parse)(text);
37751
+ const doc = (0, import_yaml15.parse)(text);
37684
37752
  if (doc && doc.schema === GOAL_SCHEMA) goals.push(doc);
37685
37753
  } catch {
37686
37754
  }
@@ -37712,7 +37780,7 @@ function createTask(repoRoot, input, options = {}) {
37712
37780
  };
37713
37781
  if (options.dryRun) return record;
37714
37782
  mkdirSync17(tasksDirectory(repoRoot), { recursive: true });
37715
- writeFileSync17(taskFilePath(repoRoot, id), (0, import_yaml14.stringify)(record).trim() + "\n", "utf8");
37783
+ writeFileSync17(taskFilePath(repoRoot, id), (0, import_yaml15.stringify)(record).trim() + "\n", "utf8");
37716
37784
  return record;
37717
37785
  }
37718
37786
  function listTasks(repoRoot, options = {}) {
@@ -37724,7 +37792,7 @@ function listTasks(repoRoot, options = {}) {
37724
37792
  if (entry.isFile() && (entry.name.endsWith(".yaml") || entry.name.endsWith(".yml"))) {
37725
37793
  try {
37726
37794
  const text = readFileSync23(join26(dir, entry.name), "utf8");
37727
- const doc = (0, import_yaml14.parse)(text);
37795
+ const doc = (0, import_yaml15.parse)(text);
37728
37796
  if (doc && doc.schema === TASK_SCHEMA) {
37729
37797
  if (options.goalId && doc.goalId !== options.goalId) continue;
37730
37798
  if (options.status && doc.status !== options.status) continue;
@@ -37742,7 +37810,7 @@ function getTask(repoRoot, taskId) {
37742
37810
  if (!existsSync24(filePath)) return void 0;
37743
37811
  try {
37744
37812
  const text = readFileSync23(filePath, "utf8");
37745
- const doc = (0, import_yaml14.parse)(text);
37813
+ const doc = (0, import_yaml15.parse)(text);
37746
37814
  return doc && doc.schema === TASK_SCHEMA ? doc : void 0;
37747
37815
  } catch {
37748
37816
  return void 0;
@@ -37760,7 +37828,7 @@ function syncTaskWithTracker(repoRoot, taskId, options = {}) {
37760
37828
  task.trackerSync.syncStatus = "synced";
37761
37829
  task.trackerSync.lastSyncedAt = now;
37762
37830
  task.updatedAt = now;
37763
- if (!options.dryRun) writeFileSync17(taskFilePath(repoRoot, taskId), (0, import_yaml14.stringify)(task).trim() + "\n", "utf8");
37831
+ if (!options.dryRun) writeFileSync17(taskFilePath(repoRoot, taskId), (0, import_yaml15.stringify)(task).trim() + "\n", "utf8");
37764
37832
  return task;
37765
37833
  }
37766
37834
 
@@ -38803,7 +38871,7 @@ steps:
38803
38871
  maxTransitions: 2
38804
38872
  `;
38805
38873
  }
38806
- const parsedYaml = (0, import_yaml16.parse)(yamlContent);
38874
+ const parsedYaml = (0, import_yaml17.parse)(yamlContent);
38807
38875
  const plan = compileKxmWorkflow({ id: workflowId, value: parsedYaml });
38808
38876
  const layout = generateStudioLayout(plan);
38809
38877
  print(runtime.io, runtime.json, { ok: true, command: "studio layout", layout }, JSON.stringify(layout, null, 2));
@@ -38845,7 +38913,7 @@ async function cmdStudioServe(runtime, options) {
38845
38913
  }
38846
38914
  if (targetPath && existsSync30(targetPath)) {
38847
38915
  const raw = readFileSync28(targetPath, "utf8");
38848
- const parsed = (0, import_yaml16.parse)(raw);
38916
+ const parsed = (0, import_yaml17.parse)(raw);
38849
38917
  const wfId = basename7(targetPath).replace(/\.(yaml|yml)$/, "");
38850
38918
  return compileKxmWorkflow({ id: wfId, value: parsed });
38851
38919
  }
@@ -50478,7 +50546,7 @@ function resolveInstallKind(probe, npmGlobalRoot) {
50478
50546
  init_bindings();
50479
50547
 
50480
50548
  // plugins/kxm/src/kxm-update-config.ts
50481
- var import_yaml17 = __toESM(require_dist(), 1);
50549
+ var import_yaml18 = __toESM(require_dist(), 1);
50482
50550
  import { existsSync as existsSync37, readFileSync as readFileSync34 } from "node:fs";
50483
50551
  import { join as join47 } from "node:path";
50484
50552
  init_bindings();
@@ -50487,7 +50555,7 @@ function loadKxmUpdateConfig(env = process.env) {
50487
50555
  if (!existsSync37(path4)) return { schema: KXM_UPDATE_SCHEMA, auto: false, source: "github" };
50488
50556
  let parsed;
50489
50557
  try {
50490
- parsed = (0, import_yaml17.parse)(readFileSync34(path4, "utf8"));
50558
+ parsed = (0, import_yaml18.parse)(readFileSync34(path4, "utf8"));
50491
50559
  } catch {
50492
50560
  throw new KxmUpdateConfigError("update.yaml is not valid YAML");
50493
50561
  }
@@ -51635,6 +51703,7 @@ function buildImprovementReport(records, options = {}) {
51635
51703
  })
51636
51704
  });
51637
51705
  }
51706
+ const routeSwitches = options.routeSwitches?.filter((item) => item.from && item.to) ?? [];
51638
51707
  return {
51639
51708
  schema: IMPROVEMENT_REPORT_SCHEMA,
51640
51709
  createdAt: nowIso(),
@@ -51643,7 +51712,8 @@ function buildImprovementReport(records, options = {}) {
51643
51712
  groups,
51644
51713
  candidates,
51645
51714
  promotionPolicy,
51646
- promotion
51715
+ promotion,
51716
+ ...routeSwitches.length > 0 ? { routeSwitches: [...routeSwitches] } : {}
51647
51717
  };
51648
51718
  }
51649
51719
  function writeImprovementReport(improvementsDir, report2, dryRun = false) {
@@ -51679,6 +51749,14 @@ function formatImprovementReport(report2) {
51679
51749
  const cand = g.isCandidate ? `yes (${g.candidateKind})` : g.excludedReason !== void 0 ? `no (${g.excludedReason})` : "no";
51680
51750
  lines.push(`${wf} ${step} ${role} ${prompt} ${rec} ${runs} ${asks} ${weighted} ${cost} ${lat} ${accepted} ${rework} ${cand}`);
51681
51751
  }
51752
+ if (report2.routeSwitches && report2.routeSwitches.length > 0) {
51753
+ lines.push("");
51754
+ lines.push(`Route switches (${report2.routeSwitches.length}):`);
51755
+ for (const item of report2.routeSwitches) {
51756
+ const effort = item.effort ? ` effort ${item.effort}` : "";
51757
+ lines.push(` - ${item.from} -> ${item.to} (${item.reason}${effort}) on ${item.stepId}`);
51758
+ }
51759
+ }
51682
51760
  if (report2.candidates.length > 0) {
51683
51761
  const readiness = new Map(report2.promotion.map((entry) => [entry.candidateId, entry]));
51684
51762
  lines.push("");
@@ -51730,11 +51808,12 @@ function evaluatePromotionPolicy(candidate, policy = "manual_pr", options = {})
51730
51808
  init_sqlite();
51731
51809
  init_project_config();
51732
51810
  init_runtime_store();
51811
+ init_route_switch();
51733
51812
  init_routing();
51734
51813
  init_telemetry();
51735
51814
  import { existsSync as existsSync41 } from "node:fs";
51736
51815
  import { resolve as resolve29 } from "node:path";
51737
- var ENGINE_EVENTS_SQL = "SELECT run_id, sequence, event_type, payload FROM events WHERE event_type IN ('routing.attempt.recorded','step.entered','run.status_changed') ORDER BY run_id, sequence";
51816
+ var ENGINE_EVENTS_SQL = "SELECT run_id, sequence, event_type, payload FROM events WHERE event_type IN ('routing.attempt.recorded','routing.route_switched','step.entered','run.status_changed') ORDER BY run_id, sequence";
51738
51817
  var SIMULATED_HARNESS = "driver-simulated";
51739
51818
  function parsePayload(text) {
51740
51819
  try {
@@ -51755,7 +51834,7 @@ function readEngineRoutingRecords(path4) {
51755
51834
  undecided: 0,
51756
51835
  duplicatesDropped: 0
51757
51836
  };
51758
- if (!existsSync41(path4)) return { records: [], source };
51837
+ if (!existsSync41(path4)) return { records: [], source, routeSwitches: [] };
51759
51838
  source.exists = true;
51760
51839
  let rows;
51761
51840
  let database;
@@ -51773,6 +51852,7 @@ function readEngineRoutingRecords(path4) {
51773
51852
  }
51774
51853
  }
51775
51854
  const runs = /* @__PURE__ */ new Map();
51855
+ const routeSwitches = [];
51776
51856
  for (const row of rows) {
51777
51857
  const runId = String(row.run_id);
51778
51858
  const sequence = Number(row.sequence);
@@ -51785,6 +51865,14 @@ function readEngineRoutingRecords(path4) {
51785
51865
  }
51786
51866
  if (eventType === "routing.attempt.recorded") {
51787
51867
  run.routing.push({ sequence, payload });
51868
+ } else if (eventType === "routing.route_switched") {
51869
+ const parsed = parsePayload(payload);
51870
+ const record = parseRouteSwitchRecord(parsed, {
51871
+ attemptId: typeof parsed?.attemptId === "string" ? parsed.attemptId : void 0,
51872
+ stepId: typeof parsed?.stepId === "string" ? parsed.stepId : void 0,
51873
+ runId
51874
+ });
51875
+ if (record) routeSwitches.push(record);
51788
51876
  } else if (eventType === "step.entered") {
51789
51877
  const stepId = parsePayload(payload)?.stepId;
51790
51878
  if (typeof stepId === "string") run.lastEntered.set(stepId, sequence);
@@ -51827,6 +51915,7 @@ function readEngineRoutingRecords(path4) {
51827
51915
  }
51828
51916
  return {
51829
51917
  records,
51918
+ routeSwitches,
51830
51919
  source: { ...source, records: records.length, skippedInvalid, excludedSimulated, undecided }
51831
51920
  };
51832
51921
  }
@@ -51869,12 +51958,13 @@ function loadRoutingSources(options) {
51869
51958
  return {
51870
51959
  ...projectRoot !== void 0 ? { projectRoot } : {},
51871
51960
  records,
51872
- sources: reads.map((read) => read.source)
51961
+ sources: reads.map((read) => read.source),
51962
+ routeSwitches: reads.flatMap((read) => read.routeSwitches ?? [])
51873
51963
  };
51874
51964
  }
51875
51965
 
51876
51966
  // plugins/kxm/src/modes.ts
51877
- var import_yaml18 = __toESM(require_dist(), 1);
51967
+ var import_yaml19 = __toESM(require_dist(), 1);
51878
51968
  init_prices();
51879
51969
  import { existsSync as existsSync42, readFileSync as readFileSync38 } from "node:fs";
51880
51970
  import { join as join51 } from "node:path";
@@ -51946,7 +52036,7 @@ function loadModesConfig(projectRoot) {
51946
52036
  }
51947
52037
  try {
51948
52038
  const raw = readFileSync38(modesPath, "utf8");
51949
- const parsed = (0, import_yaml18.parse)(raw);
52039
+ const parsed = (0, import_yaml19.parse)(raw);
51950
52040
  if (parsed && parsed.schema === "kxm.modes.v1" && parsed.majorModes) {
51951
52041
  return {
51952
52042
  schema: "kxm.modes.v1",
@@ -52941,7 +53031,7 @@ ${line}
52941
53031
  }
52942
53032
 
52943
53033
  // plugins/kxm/src/init-guide-setup.ts
52944
- var import_yaml19 = __toESM(require_dist(), 1);
53034
+ var import_yaml20 = __toESM(require_dist(), 1);
52945
53035
  init_routes();
52946
53036
  import { existsSync as existsSync45, mkdirSync as mkdirSync32, writeFileSync as writeFileSync28 } from "node:fs";
52947
53037
  import { dirname as dirname24, join as join54 } from "node:path";
@@ -53376,7 +53466,7 @@ function renderGuideSetupFiles(projectRoot, plan) {
53376
53466
  if (binding.harness === "pi" && !piMatch) {
53377
53467
  files.push({
53378
53468
  path: join54(projectRoot, ".kxm", "agents", `${role}.yaml`),
53379
- content: (0, import_yaml19.stringify)(agentDocument(role, stage))
53469
+ content: (0, import_yaml20.stringify)(agentDocument(role, stage))
53380
53470
  });
53381
53471
  continue;
53382
53472
  }
@@ -53401,15 +53491,15 @@ function renderGuideSetupFiles(projectRoot, plan) {
53401
53491
  }
53402
53492
  files.push({
53403
53493
  path: join54(projectRoot, ".kxm", "agents", `${role}.yaml`),
53404
- content: (0, import_yaml19.stringify)(agentDocument(role, stage))
53494
+ content: (0, import_yaml20.stringify)(agentDocument(role, stage))
53405
53495
  });
53406
53496
  files.push({
53407
53497
  path: join54(projectRoot, ".kxm", "models", `${routeId2}.yaml`),
53408
- content: (0, import_yaml19.stringify)(modelDocument)
53498
+ content: (0, import_yaml20.stringify)(modelDocument)
53409
53499
  });
53410
53500
  files.push({
53411
53501
  path: join54(projectRoot, ".kxm", "roles", `${role}.yaml`),
53412
- content: (0, import_yaml19.stringify)({
53502
+ content: (0, import_yaml20.stringify)({
53413
53503
  schema: "kxm.role.v2",
53414
53504
  id: role,
53415
53505
  purpose: writer ? "writer" : "experiment",
@@ -53422,7 +53512,7 @@ function renderGuideSetupFiles(projectRoot, plan) {
53422
53512
  for (const workflow of plan.workflows) {
53423
53513
  files.push({
53424
53514
  path: join54(projectRoot, ".kxm", "workflows", `${workflow.slug}.yaml`),
53425
- content: (0, import_yaml19.stringify)(workflowDocument(workflow))
53515
+ content: (0, import_yaml20.stringify)(workflowDocument(workflow))
53426
53516
  });
53427
53517
  }
53428
53518
  return files;
@@ -53440,7 +53530,7 @@ function mergeGuideRouteAdmission(projectRoot, plan) {
53440
53530
  policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
53441
53531
  const path4 = join54(projectRoot, ".kxm", "routes.yaml");
53442
53532
  mkdirSync32(dirname24(path4), { recursive: true });
53443
- writeFileSync28(path4, (0, import_yaml19.stringify)(policy), "utf8");
53533
+ writeFileSync28(path4, (0, import_yaml20.stringify)(policy), "utf8");
53444
53534
  return added;
53445
53535
  }
53446
53536
  function writeGuideSetupFiles(files) {
@@ -53912,7 +54002,8 @@ async function cmdImprove(runtime, options = {}) {
53912
54002
  dryRun: runtime.dryRun,
53913
54003
  promotionPolicy: config.improvement.promotionPolicy,
53914
54004
  autoThreshold: config.improvement.autoThreshold,
53915
- halfLifeDays: config.improvement.telemetryHalfLifeDays
54005
+ halfLifeDays: config.improvement.telemetryHalfLifeDays,
54006
+ routeSwitches: loaded.routeSwitches
53916
54007
  });
53917
54008
  const reportDir = join55(runtime.dirs.assets, "improvements");
53918
54009
  const reportPath = writeImprovementReport(reportDir, report2, runtime.dryRun);
@@ -54209,6 +54300,7 @@ async function cmdRoutingReport(runtime, options) {
54209
54300
  let file;
54210
54301
  let records;
54211
54302
  let sources;
54303
+ let routeSwitches = [];
54212
54304
  if (options.file !== void 0) {
54213
54305
  file = options.file;
54214
54306
  records = readRoutingRecords(file).map((entry) => entry.routing);
@@ -54218,6 +54310,7 @@ async function cmdRoutingReport(runtime, options) {
54218
54310
  file = telemetryPath(runtime.dirs.logs);
54219
54311
  records = loaded.records;
54220
54312
  sources = loaded.sources;
54313
+ routeSwitches = loaded.routeSwitches;
54221
54314
  }
54222
54315
  const includeEquivalentListCost = Boolean(options.equivalentListCost || options.listPrices);
54223
54316
  let catalog;
@@ -54228,7 +54321,7 @@ async function cmdRoutingReport(runtime, options) {
54228
54321
  } catch {
54229
54322
  }
54230
54323
  }
54231
- const report2 = generateRoutingReport(records, { catalog, includeEquivalentListCost });
54324
+ const report2 = generateRoutingReport(records, { catalog, includeEquivalentListCost, routeSwitches });
54232
54325
  if (records.length === 0) {
54233
54326
  print(runtime.io, runtime.json, { ok: true, command: "routing report", file, ...sources ? { sources } : {}, configurations: [], report: report2 }, "no routing records in telemetry");
54234
54327
  return 0;