@kontextmind/kxm 0.7.30 → 0.7.35

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.
@@ -11,7 +11,7 @@
11
11
  "name": "kxm",
12
12
  "source": "./plugins/kxm",
13
13
  "description": "Durable workflows, peer agents, and kxm tui",
14
- "version": "0.7.30",
14
+ "version": "0.7.35",
15
15
  "category": "development",
16
16
  "tags": ["kxm", "multi-agent", "workflows", "mcp"]
17
17
  }
@@ -0,0 +1,10 @@
1
+ schema: kxm.role.v1
2
+ id: planner
3
+ # fable primary (proven planning); qwen3.8-max failover (admitted, planning-unproven)
4
+ roster:
5
+ - model: anthropic/fable
6
+ effort: medium
7
+ enabled: true
8
+ - model: qwen-token-plan/qwen3.8-max
9
+ effort: medium
10
+ enabled: true
@@ -0,0 +1,10 @@
1
+ schema: kxm.role.v1
2
+ id: reviewer-arch
3
+ # fable is the required arch critic; glm-5.3 failover (admitted, review-unproven)
4
+ roster:
5
+ - model: anthropic/fable
6
+ effort: medium
7
+ enabled: true
8
+ - model: zai-coding-cn/glm-5.3
9
+ effort: medium
10
+ enabled: true
@@ -0,0 +1,10 @@
1
+ schema: kxm.role.v1
2
+ id: reviewer-cli
3
+ # sol is the required cli critic; glm-5.3-flash failover (fast tier, review-unproven)
4
+ roster:
5
+ - model: openai/gpt-5.6-sol
6
+ effort: low
7
+ enabled: true
8
+ - model: zai-coding-cn/glm-5.3-flash
9
+ effort: low
10
+ enabled: true
@@ -1,7 +1,21 @@
1
1
  schema: kxm.role.v1
2
2
  id: writer
3
+ # Rotation priority = order. Primaries first; subscription/unmetered models
4
+ # act as failover (verified edit probes 2026-09-16; see routes.yaml).
5
+ # Effort default: medium for implementation (AGENTS.md). agy ids bake in the
6
+ # effort tier, so those entries carry no effort field.
3
7
  roster:
4
8
  - model: xai/grok-4.6
9
+ effort: medium
5
10
  enabled: true
6
11
  - model: openrouter/qwen/qwen3-coder-plus
12
+ effort: medium
13
+ enabled: true
14
+ - model: zai-coding-cn/glm-5.3-flash
15
+ effort: medium
16
+ enabled: true
17
+ - model: qwen-token-plan/qwen3.8-flash
18
+ effort: medium
19
+ enabled: true
20
+ - model: google/gemini-3.8-flash-high
7
21
  enabled: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextmind/kxm",
3
- "version": "0.7.30",
3
+ "version": "0.7.35",
4
4
  "description": "KXM local-first multi-agent orchestration and operator dashboard",
5
5
  "type": "module",
6
6
  "author": "KontextMind",
@@ -48,6 +48,7 @@
48
48
  "verify": "npm test && npm run check && npm run check:generated",
49
49
  "validate:claude": "claude plugin validate . --strict && claude plugin validate plugins/kxm --strict",
50
50
  "validate:ci": "npm run test:coverage && npm run check && npm pack --dry-run",
51
+ "validate:pr": "npm run test:core && npm run check && npm run check:generated",
51
52
  "validate": "npm run validate:ci && npm run validate:claude"
52
53
  },
53
54
  "bin": {
@@ -70,7 +71,7 @@
70
71
  ]
71
72
  },
72
73
  "dependencies": {
73
- "@anthropic-ai/claude-agent-sdk": "0.2.141",
74
+ "@anthropic-ai/claude-agent-sdk": "0.3.270",
74
75
  "@earendil-works/pi-tui": "0.85.1",
75
76
  "@modelcontextprotocol/sdk": "1.30.0",
76
77
  "yaml": "^2.9.0"
@@ -90,13 +91,13 @@
90
91
  "devDependencies": {
91
92
  "@earendil-works/pi-coding-agent": "0.85.1",
92
93
  "@modelcontextprotocol/sdk": "1.30.0",
93
- "@types/node": "26.4.1",
94
+ "@types/node": "26.5.1",
94
95
  "ajv": "8.20.0",
95
96
  "commander": "15.0.0",
96
97
  "esbuild": "0.28.2",
97
98
  "markdownlint-cli2": "0.23.2",
98
99
  "tsx": "^4.23.13",
99
- "typebox": "1.3.28",
100
+ "typebox": "1.3.30",
100
101
  "typescript": "7.0.2"
101
102
  },
102
103
  "files": [
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "kxm",
4
4
  "displayName": "KXM",
5
- "version": "0.7.30",
5
+ "version": "0.7.35",
6
6
  "description": "Headless multi-agent orchestration, durable workflows, and a live operator dashboard for Pi and Claude Code",
7
7
  "author": {
8
8
  "name": "KontextMind",
@@ -24951,33 +24951,29 @@ function loadPriceCatalogForEstimate(options) {
24951
24951
  // plugins/kxm/src/vnext-engine.ts
24952
24952
  var import_yaml5 = __toESM(require_dist(), 1);
24953
24953
 
24954
- // plugins/kxm/src/producers.ts
24954
+ // plugins/kxm/src/routes.ts
24955
24955
  var import_yaml4 = __toESM(require_dist(), 1);
24956
24956
  import { existsSync as existsSync11, readFileSync as readFileSync10, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7, readdirSync as readdirSync3 } from "node:fs";
24957
24957
  import { join as join11 } from "node:path";
24958
- var empty = () => ({ schema: "kxm.producers.v1", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), promoted: [], demoted: [], enabled: [], disabled: [], roles: {} });
24959
- function loadProducerPolicy(root) {
24960
- const path4 = join11(root, ".kxm", "producers.yaml");
24958
+ var RETIRED_POLICY = ".kxm/producers.yaml";
24959
+ var empty = () => ({ schema: "kxm.routes.v2", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), admitted: [], disabled: [], roles: {} });
24960
+ function loadRoutePolicy(root) {
24961
+ if (existsSync11(join11(root, RETIRED_POLICY))) throw new Error(`retired ${RETIRED_POLICY} present; use .kxm/routes.yaml (kxm.routes.v2)`);
24962
+ const path4 = join11(root, ".kxm", "routes.yaml");
24961
24963
  if (!existsSync11(path4)) return empty();
24962
24964
  const value = (0, import_yaml4.parse)(readFileSync10(path4, "utf8"));
24963
- if (value?.schema !== "kxm.producers.v1" || !Array.isArray(value.promoted) || !Array.isArray(value.demoted)) throw new Error("invalid .kxm/producers.yaml");
24964
- return { schema: "kxm.producers.v1", updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : (/* @__PURE__ */ new Date()).toISOString(), promoted: value.promoted.filter((x2) => typeof x2 === "string"), demoted: value.demoted.filter((x2) => typeof x2 === "string"), enabled: Array.isArray(value.enabled) ? value.enabled.filter((x2) => typeof x2 === "string") : [], disabled: Array.isArray(value.disabled) ? value.disabled.filter((x2) => typeof x2 === "string") : [], roles: value.roles && typeof value.roles === "object" ? Object.fromEntries(Object.entries(value.roles).filter(([, v2]) => Array.isArray(v2)).map(([k, v2]) => [k, v2.filter((x2) => typeof x2 === "string")])) : {} };
24965
- }
24966
- function updateProducer(root, model, status) {
24967
- const policy = loadProducerPolicy(root);
24968
- policy.promoted = policy.promoted.filter((x2) => x2 !== model);
24969
- policy.demoted = policy.demoted.filter((x2) => x2 !== model);
24970
- policy[status].push(model);
24971
- policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
24972
- mkdirSync7(join11(root, ".kxm"), { recursive: true });
24973
- writeFileSync7(join11(root, ".kxm", "producers.yaml"), (0, import_yaml4.stringify)(policy), "utf8");
24974
- return policy;
24965
+ if (value?.schema !== "kxm.routes.v2" || !Array.isArray(value.admitted)) throw new Error("invalid .kxm/routes.yaml");
24966
+ return { schema: "kxm.routes.v2", updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : (/* @__PURE__ */ new Date()).toISOString(), admitted: value.admitted.filter((x2) => typeof x2 === "string"), disabled: Array.isArray(value.disabled) ? value.disabled.filter((x2) => typeof x2 === "string") : [], roles: value.roles && typeof value.roles === "object" ? Object.fromEntries(Object.entries(value.roles).filter(([, v2]) => Array.isArray(v2)).map(([k, v2]) => [k, v2.filter((x2) => typeof x2 === "string")])) : {} };
24967
+ }
24968
+ function updateRouteState(root, model, state) {
24969
+ return setRouteState(root, model, state);
24975
24970
  }
24976
- function setModelState(root, model, state, role, removeRole2 = false) {
24977
- const policy = loadProducerPolicy(root);
24978
- policy.enabled = policy.enabled.filter((x2) => x2 !== model);
24971
+ function setRouteState(root, model, state, role, removeRole2 = false) {
24972
+ const policy = loadRoutePolicy(root);
24973
+ policy.admitted = policy.admitted.filter((x2) => x2 !== model);
24979
24974
  policy.disabled = policy.disabled.filter((x2) => x2 !== model);
24980
- policy[state].push(model);
24975
+ if (state === "admitted") policy.admitted.push(model);
24976
+ else policy.disabled.push(model);
24981
24977
  if (role) {
24982
24978
  if (!/^[a-z][a-z0-9_-]{0,63}$/i.test(role)) throw new Error("invalid role id");
24983
24979
  const rolePath = join11(root, ".kxm", "roles", `${role}.yaml`);
@@ -24999,7 +24995,7 @@ function setModelState(root, model, state, role, removeRole2 = false) {
24999
24995
  }
25000
24996
  policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
25001
24997
  mkdirSync7(join11(root, ".kxm"), { recursive: true });
25002
- writeFileSync7(join11(root, ".kxm", "producers.yaml"), (0, import_yaml4.stringify)(policy), "utf8");
24998
+ writeFileSync7(join11(root, ".kxm", "routes.yaml"), (0, import_yaml4.stringify)(policy), "utf8");
25003
24999
  return policy;
25004
25000
  }
25005
25001
  function listRoleBindings(root) {
@@ -33853,7 +33849,7 @@ async function cmdHarnessList(runtime) {
33853
33849
  print(runtime.io, runtime.json, { ok: true, command: "harness list", ...inventory }, formatHarnessInventory(inventory));
33854
33850
  return 0;
33855
33851
  }
33856
- async function selectProducerModel(runtime, requested) {
33852
+ async function selectInventoryModel(runtime, requested) {
33857
33853
  const models = listInventoryModels(runtime.dirs.workdir);
33858
33854
  if (requested) return models.find((model) => model.toLowerCase() === requested.toLowerCase());
33859
33855
  if (runtime.json || !process.stdin.isTTY || models.length === 0) return void 0;
@@ -33864,18 +33860,18 @@ async function selectProducerModel(runtime, requested) {
33864
33860
  const index = Number.parseInt(answer.trim(), 10) - 1;
33865
33861
  return Number.isInteger(index) && index >= 0 && index < models.length ? models[index] : void 0;
33866
33862
  }
33867
- async function cmdProducerChange(runtime, status, requested) {
33868
- const model = await selectProducerModel(runtime, requested);
33863
+ async function cmdRouteChange(runtime, status, requested) {
33864
+ const model = await selectInventoryModel(runtime, requested);
33869
33865
  if (!model) {
33870
- print(runtime.io, runtime.json, { ok: false, command: `producers ${status}`, error: "model_selection_required" }, "select a model from the refreshed inventory");
33866
+ print(runtime.io, runtime.json, { ok: false, command: `routes ${status}`, error: "model_selection_required" }, "select a model from the refreshed inventory");
33871
33867
  return 2;
33872
33868
  }
33873
33869
  if (runtime.dryRun) {
33874
- print(runtime.io, runtime.json, { ok: true, command: `producers ${status}`, model, dryRun: true }, `would ${status} ${model}`);
33870
+ print(runtime.io, runtime.json, { ok: true, command: `routes ${status}`, model, dryRun: true }, `would ${status === "admitted" ? "admit" : "disable"} ${model}`);
33875
33871
  return 0;
33876
33872
  }
33877
- const policy = updateProducer(runtime.dirs.workdir, model, status);
33878
- print(runtime.io, runtime.json, { ok: true, command: `producers ${status}`, model, policy }, `${status} ${model}`);
33873
+ const policy = updateRouteState(runtime.dirs.workdir, model, status);
33874
+ print(runtime.io, runtime.json, { ok: true, command: `routes ${status}`, model, policy }, `${status} ${model}`);
33879
33875
  return 0;
33880
33876
  }
33881
33877
  async function cmdModelsScreen(runtime) {
@@ -33888,25 +33884,24 @@ async function cmdModelsScreen(runtime) {
33888
33884
  const ask = (q2) => new Promise((resolve31) => rl.question(q2, resolve31));
33889
33885
  try {
33890
33886
  while (true) {
33891
- const policy = loadProducerPolicy(runtime.dirs.workdir);
33887
+ const policy = loadRoutePolicy(runtime.dirs.workdir);
33892
33888
  const roleBindings = listRoleBindings(runtime.dirs.workdir);
33893
- runtime.io.stdout(models.map((m2, i) => `${i + 1}. ${m2} [${policy.enabled.includes(m2) ? "enabled" : policy.disabled.includes(m2) ? "disabled" : "unset"}] [${policy.promoted.includes(m2) ? "producer" : policy.demoted.includes(m2) ? "demoted" : "not producer"}] roles:${Object.entries(roleBindings).filter(([, xs]) => xs.includes(m2)).map(([r]) => r).join(",") || "-"}`).join("\n") + "\n");
33894
- const command = (await ask("[e]nable [d]isable [p]romote [x]demote [a]dd-role [r]emove-role [q]uit: ")).trim().toLowerCase();
33889
+ runtime.io.stdout(models.map((m2, i) => `${i + 1}. ${m2} [${policy.admitted.includes(m2) ? "admitted" : policy.disabled.includes(m2) ? "disabled" : "unset"}] roles:${Object.entries(roleBindings).filter(([, xs]) => xs.includes(m2)).map(([r]) => r).join(",") || "-"}`).join("\n") + "\n");
33890
+ const command = (await ask("[a]dmit [d]isable [r]ole-add [x]ole-remove [q]uit: ")).trim().toLowerCase();
33895
33891
  if (command === "q" || command === "quit") return 0;
33896
33892
  const index = Number.parseInt((await ask("model number: ")).trim(), 10) - 1;
33897
33893
  if (!Number.isInteger(index) || !models[index]) continue;
33898
33894
  const model = models[index];
33899
- if (command === "p" || command === "x") updateProducer(runtime.dirs.workdir, model, command === "p" ? "promoted" : "demoted");
33900
- else if (command === "e" || command === "d") setModelState(runtime.dirs.workdir, model, command === "e" ? "enabled" : "disabled");
33901
- else if (command === "a" || command === "r") setModelState(runtime.dirs.workdir, model, "enabled", (await ask("role: ")).trim(), command === "r");
33895
+ if (command === "a" || command === "d") setRouteState(runtime.dirs.workdir, model, command === "a" ? "admitted" : "disabled");
33896
+ else if (command === "r" || command === "x") setRouteState(runtime.dirs.workdir, model, "admitted", (await ask("role: ")).trim(), command === "x");
33902
33897
  }
33903
33898
  } finally {
33904
33899
  rl.close();
33905
33900
  }
33906
33901
  }
33907
- async function cmdProducerList(runtime) {
33908
- const policy = loadProducerPolicy(runtime.dirs.workdir);
33909
- print(runtime.io, runtime.json, { ok: true, command: "producers list", policy }, [...policy.promoted.map((x2) => `promoted ${x2}`), ...policy.demoted.map((x2) => `demoted ${x2}`)].join("\n") || "no producer decisions");
33902
+ async function cmdRouteList(runtime) {
33903
+ const policy = loadRoutePolicy(runtime.dirs.workdir);
33904
+ print(runtime.io, runtime.json, { ok: true, command: "routes list", policy }, [...policy.admitted.map((x2) => `admitted ${x2}`), ...policy.disabled.map((x2) => `disabled ${x2}`)].join("\n") || "no route decisions");
33910
33905
  return 0;
33911
33906
  }
33912
33907
  async function cmdModelInventoryRefresh(runtime) {
@@ -48797,7 +48792,7 @@ function createProgram(ctx, result) {
48797
48792
  addGlobalOptions(runCmd.command("list").description("List recent runs for the current project")).action(async function runListAction() {
48798
48793
  result.code = await cmdVnextRunList(runtimeFrom(ctx, this));
48799
48794
  });
48800
- const modelsCmd = addGlobalOptions(program2.command("models").description("Manage model catalogs, roles, and producer state"));
48795
+ const modelsCmd = addGlobalOptions(program2.command("models").description("Manage model catalogs, roles, and route state"));
48801
48796
  modelsCmd.action(async function modelsScreenAction() {
48802
48797
  result.code = await cmdModelsScreen(runtimeFrom(ctx, this));
48803
48798
  });
@@ -48805,14 +48800,14 @@ function createProgram(ctx, result) {
48805
48800
  addGlobalOptions(modelsCmd.command("inventory-refresh").alias("refresh").description("Refresh the YAML model inventory with standard and Nous/OpenRouter prices")).action(async function modelInventoryRefreshAction() {
48806
48801
  result.code = await cmdModelInventoryRefresh(runtimeFrom(ctx, this));
48807
48802
  });
48808
- const producersCmd = addGlobalOptions(program2.command("producers").description("Promote or demote verified producer models"));
48809
- producersCmd.helpCommand("help", "Show producers help");
48810
- addGlobalOptions(producersCmd.command("list").description("List producer decisions")).action(async function producersListAction() {
48811
- result.code = await cmdProducerList(runtimeFrom(ctx, this));
48803
+ const routesCmd = addGlobalOptions(program2.command("routes").description("Admit or disable verified model routes"));
48804
+ routesCmd.helpCommand("help", "Show routes help");
48805
+ addGlobalOptions(routesCmd.command("list").description("List route decisions")).action(async function routesListAction() {
48806
+ result.code = await cmdRouteList(runtimeFrom(ctx, this));
48812
48807
  });
48813
- for (const status of ["promote", "demote"]) {
48814
- addGlobalOptions(producersCmd.command(status).description(`${status} a model from the inventory`)).option("--model <id>", "Exact model id; omit to choose interactively").action(async function producerChangeAction(options) {
48815
- result.code = await cmdProducerChange(runtimeFrom(ctx, this), status === "promote" ? "promoted" : "demoted", options.model);
48808
+ for (const status of ["admit", "disable"]) {
48809
+ addGlobalOptions(routesCmd.command(status).description(`${status === "admit" ? "Admit" : "Disable"} a model route from the inventory`)).option("--model <id>", "Exact model id; omit to choose interactively").action(async function routeChangeAction(options) {
48810
+ result.code = await cmdRouteChange(runtimeFrom(ctx, this), status === "admit" ? "admitted" : "disabled", options.model);
48816
48811
  });
48817
48812
  }
48818
48813
  const harnessCmd = addGlobalOptions(program2.command("harness").description("Detect coding-agent harnesses and authentication"));
@@ -17121,7 +17121,7 @@ async function deliverInboxNotification(messageId, delivered, notify) {
17121
17121
  }
17122
17122
 
17123
17123
  // plugins/kxm/src/mcp-server.ts
17124
- var VERSION = "0.7.30";
17124
+ var VERSION = "0.7.35";
17125
17125
  var inbox = /* @__PURE__ */ new Map();
17126
17126
  var notifiedInbox = /* @__PURE__ */ new Set();
17127
17127
  var meshClient;
@@ -22945,17 +22945,19 @@ import { createHash as createHash11, randomBytes as randomBytes2, timingSafeEqua
22945
22945
  import { existsSync as existsSync9, readFileSync as readFileSync7 } from "node:fs";
22946
22946
  import { join as join11 } from "node:path";
22947
22947
 
22948
- // plugins/kxm/src/producers.ts
22948
+ // plugins/kxm/src/routes.ts
22949
22949
  var import_yaml4 = __toESM(require_dist(), 1);
22950
22950
  import { existsSync as existsSync8, readFileSync as readFileSync6, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3, readdirSync as readdirSync4 } from "node:fs";
22951
22951
  import { join as join9 } from "node:path";
22952
- var empty = () => ({ schema: "kxm.producers.v1", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), promoted: [], demoted: [], enabled: [], disabled: [], roles: {} });
22953
- function loadProducerPolicy(root) {
22954
- const path = join9(root, ".kxm", "producers.yaml");
22952
+ var RETIRED_POLICY = ".kxm/producers.yaml";
22953
+ var empty = () => ({ schema: "kxm.routes.v2", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), admitted: [], disabled: [], roles: {} });
22954
+ function loadRoutePolicy(root) {
22955
+ if (existsSync8(join9(root, RETIRED_POLICY))) throw new Error(`retired ${RETIRED_POLICY} present; use .kxm/routes.yaml (kxm.routes.v2)`);
22956
+ const path = join9(root, ".kxm", "routes.yaml");
22955
22957
  if (!existsSync8(path)) return empty();
22956
22958
  const value = (0, import_yaml4.parse)(readFileSync6(path, "utf8"));
22957
- if (value?.schema !== "kxm.producers.v1" || !Array.isArray(value.promoted) || !Array.isArray(value.demoted)) throw new Error("invalid .kxm/producers.yaml");
22958
- return { schema: "kxm.producers.v1", updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : (/* @__PURE__ */ new Date()).toISOString(), promoted: value.promoted.filter((x) => typeof x === "string"), demoted: value.demoted.filter((x) => typeof x === "string"), enabled: Array.isArray(value.enabled) ? value.enabled.filter((x) => typeof x === "string") : [], disabled: Array.isArray(value.disabled) ? value.disabled.filter((x) => typeof x === "string") : [], roles: value.roles && typeof value.roles === "object" ? Object.fromEntries(Object.entries(value.roles).filter(([, v]) => Array.isArray(v)).map(([k, v]) => [k, v.filter((x) => typeof x === "string")])) : {} };
22959
+ if (value?.schema !== "kxm.routes.v2" || !Array.isArray(value.admitted)) throw new Error("invalid .kxm/routes.yaml");
22960
+ return { schema: "kxm.routes.v2", updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : (/* @__PURE__ */ new Date()).toISOString(), admitted: value.admitted.filter((x) => typeof x === "string"), disabled: Array.isArray(value.disabled) ? value.disabled.filter((x) => typeof x === "string") : [], roles: value.roles && typeof value.roles === "object" ? Object.fromEntries(Object.entries(value.roles).filter(([, v]) => Array.isArray(v)).map(([k, v]) => [k, v.filter((x) => typeof x === "string")])) : {} };
22959
22961
  }
22960
22962
  function listRoleBindings(root) {
22961
22963
  const dir = join9(root, ".kxm", "roles");
@@ -22968,9 +22970,9 @@ function listRoleBindings(root) {
22968
22970
  }
22969
22971
  return result;
22970
22972
  }
22971
- function isProducerAdmitted(root, modelId) {
22972
- const policy = loadProducerPolicy(root);
22973
- return policy.enabled.includes(modelId) && policy.promoted.includes(modelId) && !policy.disabled.includes(modelId) && !policy.demoted.includes(modelId);
22973
+ function isRouteAdmitted(root, modelId) {
22974
+ const policy = loadRoutePolicy(root);
22975
+ return policy.admitted.includes(modelId) && !policy.disabled.includes(modelId);
22974
22976
  }
22975
22977
 
22976
22978
  // plugins/kxm/src/context-packet.ts
@@ -25164,7 +25166,7 @@ function resolveProducerRoute(projectRoot, step, agentId) {
25164
25166
  }
25165
25167
  };
25166
25168
  }
25167
- if (!isProducerAdmitted(projectRoot, selector)) {
25169
+ if (!isRouteAdmitted(projectRoot, selector)) {
25168
25170
  return {
25169
25171
  error: {
25170
25172
  reason: "step_unsupported",
@@ -27337,7 +27339,7 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
27337
27339
  const value = model;
27338
27340
  const provider = typeof value.provider === "string" ? value.provider : void 0;
27339
27341
  const modelName = typeof value.model === "string" ? value.model : void 0;
27340
- if (!provider || !modelName || !isProducerAdmitted(projectRoot, `${provider}/${modelName}`)) {
27342
+ if (!provider || !modelName || !isRouteAdmitted(projectRoot, `${provider}/${modelName}`)) {
27341
27343
  throw new Error("producer_route_not_admitted");
27342
27344
  }
27343
27345
  return { provider, model: modelName };
@@ -22470,17 +22470,19 @@ import { createHash as createHash10, randomBytes, timingSafeEqual } from "node:c
22470
22470
  import { existsSync as existsSync9, readFileSync as readFileSync7 } from "node:fs";
22471
22471
  import { join as join11 } from "node:path";
22472
22472
 
22473
- // plugins/kxm/src/producers.ts
22473
+ // plugins/kxm/src/routes.ts
22474
22474
  var import_yaml4 = __toESM(require_dist(), 1);
22475
22475
  import { existsSync as existsSync8, readFileSync as readFileSync6, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3, readdirSync as readdirSync4 } from "node:fs";
22476
22476
  import { join as join9 } from "node:path";
22477
- var empty = () => ({ schema: "kxm.producers.v1", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), promoted: [], demoted: [], enabled: [], disabled: [], roles: {} });
22478
- function loadProducerPolicy(root) {
22479
- const path = join9(root, ".kxm", "producers.yaml");
22477
+ var RETIRED_POLICY = ".kxm/producers.yaml";
22478
+ var empty = () => ({ schema: "kxm.routes.v2", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), admitted: [], disabled: [], roles: {} });
22479
+ function loadRoutePolicy(root) {
22480
+ if (existsSync8(join9(root, RETIRED_POLICY))) throw new Error(`retired ${RETIRED_POLICY} present; use .kxm/routes.yaml (kxm.routes.v2)`);
22481
+ const path = join9(root, ".kxm", "routes.yaml");
22480
22482
  if (!existsSync8(path)) return empty();
22481
22483
  const value = (0, import_yaml4.parse)(readFileSync6(path, "utf8"));
22482
- if (value?.schema !== "kxm.producers.v1" || !Array.isArray(value.promoted) || !Array.isArray(value.demoted)) throw new Error("invalid .kxm/producers.yaml");
22483
- return { schema: "kxm.producers.v1", updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : (/* @__PURE__ */ new Date()).toISOString(), promoted: value.promoted.filter((x) => typeof x === "string"), demoted: value.demoted.filter((x) => typeof x === "string"), enabled: Array.isArray(value.enabled) ? value.enabled.filter((x) => typeof x === "string") : [], disabled: Array.isArray(value.disabled) ? value.disabled.filter((x) => typeof x === "string") : [], roles: value.roles && typeof value.roles === "object" ? Object.fromEntries(Object.entries(value.roles).filter(([, v]) => Array.isArray(v)).map(([k, v]) => [k, v.filter((x) => typeof x === "string")])) : {} };
22484
+ if (value?.schema !== "kxm.routes.v2" || !Array.isArray(value.admitted)) throw new Error("invalid .kxm/routes.yaml");
22485
+ return { schema: "kxm.routes.v2", updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : (/* @__PURE__ */ new Date()).toISOString(), admitted: value.admitted.filter((x) => typeof x === "string"), disabled: Array.isArray(value.disabled) ? value.disabled.filter((x) => typeof x === "string") : [], roles: value.roles && typeof value.roles === "object" ? Object.fromEntries(Object.entries(value.roles).filter(([, v]) => Array.isArray(v)).map(([k, v]) => [k, v.filter((x) => typeof x === "string")])) : {} };
22484
22486
  }
22485
22487
  function listRoleBindings(root) {
22486
22488
  const dir = join9(root, ".kxm", "roles");
@@ -22493,9 +22495,9 @@ function listRoleBindings(root) {
22493
22495
  }
22494
22496
  return result;
22495
22497
  }
22496
- function isProducerAdmitted(root, modelId) {
22497
- const policy = loadProducerPolicy(root);
22498
- return policy.enabled.includes(modelId) && policy.promoted.includes(modelId) && !policy.disabled.includes(modelId) && !policy.demoted.includes(modelId);
22498
+ function isRouteAdmitted(root, modelId) {
22499
+ const policy = loadRoutePolicy(root);
22500
+ return policy.admitted.includes(modelId) && !policy.disabled.includes(modelId);
22499
22501
  }
22500
22502
 
22501
22503
  // plugins/kxm/src/context-packet.ts
@@ -24678,7 +24680,7 @@ function resolveProducerRoute(projectRoot, step, agentId) {
24678
24680
  }
24679
24681
  };
24680
24682
  }
24681
- if (!isProducerAdmitted(projectRoot, selector)) {
24683
+ if (!isRouteAdmitted(projectRoot, selector)) {
24682
24684
  return {
24683
24685
  error: {
24684
24686
  reason: "step_unsupported",
@@ -26851,7 +26853,7 @@ async function startVnextRuntimeSupervisorInner(paths, requestedPortOption, now)
26851
26853
  const value = model;
26852
26854
  const provider = typeof value.provider === "string" ? value.provider : void 0;
26853
26855
  const modelName = typeof value.model === "string" ? value.model : void 0;
26854
- if (!provider || !modelName || !isProducerAdmitted(projectRoot, `${provider}/${modelName}`)) {
26856
+ if (!provider || !modelName || !isRouteAdmitted(projectRoot, `${provider}/${modelName}`)) {
26855
26857
  throw new Error("producer_route_not_admitted");
26856
26858
  }
26857
26859
  return { provider, model: modelName };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kxm-claude-plugin",
3
- "version": "0.7.30",
3
+ "version": "0.7.35",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "engines": {
@@ -5,7 +5,7 @@ import { join, resolve } from "node:path";
5
5
  import { createInterface } from "node:readline";
6
6
  import { createBackup, restoreBackup } from "../database.ts";
7
7
  import { refreshModelInventory } from "../model-inventory.ts";
8
- import { listInventoryModels, listRoleBindings, loadProducerPolicy, setModelState, updateProducer } from "../producers.ts";
8
+ import { listInventoryModels, listRoleBindings, loadRoutePolicy, setRouteState, updateRouteState } from "../routes.ts";
9
9
  import {
10
10
  VnextConfigError,
11
11
  discoverVnextProjectRoot,
@@ -723,7 +723,7 @@ export async function cmdHarnessList(runtime: Runtime): Promise<number> {
723
723
  return 0;
724
724
  }
725
725
 
726
- export async function selectProducerModel(runtime: Runtime, requested?: string | undefined): Promise<string | undefined> {
726
+ export async function selectInventoryModel(runtime: Runtime, requested?: string | undefined): Promise<string | undefined> {
727
727
  const models = listInventoryModels(runtime.dirs.workdir);
728
728
  if (requested) return models.find((model) => model.toLowerCase() === requested.toLowerCase());
729
729
  if (runtime.json || !process.stdin.isTTY || models.length === 0) return undefined;
@@ -735,12 +735,12 @@ export async function selectProducerModel(runtime: Runtime, requested?: string |
735
735
  return Number.isInteger(index) && index >= 0 && index < models.length ? models[index] : undefined;
736
736
  }
737
737
 
738
- export async function cmdProducerChange(runtime: Runtime, status: "promoted" | "demoted", requested?: string | undefined): Promise<number> {
739
- const model = await selectProducerModel(runtime, requested);
740
- if (!model) { print(runtime.io, runtime.json, { ok: false, command: `producers ${status}`, error: "model_selection_required" }, "select a model from the refreshed inventory"); return 2; }
741
- if (runtime.dryRun) { print(runtime.io, runtime.json, { ok: true, command: `producers ${status}`, model, dryRun: true }, `would ${status} ${model}`); return 0; }
742
- const policy = updateProducer(runtime.dirs.workdir, model, status);
743
- print(runtime.io, runtime.json, { ok: true, command: `producers ${status}`, model, policy }, `${status} ${model}`);
738
+ export async function cmdRouteChange(runtime: Runtime, status: "admitted" | "disabled", requested?: string | undefined): Promise<number> {
739
+ const model = await selectInventoryModel(runtime, requested);
740
+ if (!model) { print(runtime.io, runtime.json, { ok: false, command: `routes ${status}`, error: "model_selection_required" }, "select a model from the refreshed inventory"); return 2; }
741
+ if (runtime.dryRun) { print(runtime.io, runtime.json, { ok: true, command: `routes ${status}`, model, dryRun: true }, `would ${status === "admitted" ? "admit" : "disable"} ${model}`); return 0; }
742
+ const policy = updateRouteState(runtime.dirs.workdir, model, status);
743
+ print(runtime.io, runtime.json, { ok: true, command: `routes ${status}`, model, policy }, `${status} ${model}`);
744
744
  return 0;
745
745
  }
746
746
 
@@ -751,24 +751,23 @@ export async function cmdModelsScreen(runtime: Runtime): Promise<number> {
751
751
  const ask = (q: string) => new Promise<string>((resolve) => rl.question(q, resolve));
752
752
  try {
753
753
  while (true) {
754
- const policy = loadProducerPolicy(runtime.dirs.workdir);
754
+ const policy = loadRoutePolicy(runtime.dirs.workdir);
755
755
  const roleBindings = listRoleBindings(runtime.dirs.workdir);
756
- runtime.io.stdout(models.map((m, i) => `${i + 1}. ${m} [${policy.enabled.includes(m) ? "enabled" : policy.disabled.includes(m) ? "disabled" : "unset"}] [${policy.promoted.includes(m) ? "producer" : policy.demoted.includes(m) ? "demoted" : "not producer"}] roles:${Object.entries(roleBindings).filter(([, xs]) => xs.includes(m)).map(([r]) => r).join(",") || "-"}`).join("\n") + "\n");
757
- const command = (await ask("[e]nable [d]isable [p]romote [x]demote [a]dd-role [r]emove-role [q]uit: ")).trim().toLowerCase();
756
+ runtime.io.stdout(models.map((m, i) => `${i + 1}. ${m} [${policy.admitted.includes(m) ? "admitted" : policy.disabled.includes(m) ? "disabled" : "unset"}] roles:${Object.entries(roleBindings).filter(([, xs]) => xs.includes(m)).map(([r]) => r).join(",") || "-"}`).join("\n") + "\n");
757
+ const command = (await ask("[a]dmit [d]isable [r]ole-add [x]ole-remove [q]uit: ")).trim().toLowerCase();
758
758
  if (command === "q" || command === "quit") return 0;
759
759
  const index = Number.parseInt((await ask("model number: ")).trim(), 10) - 1;
760
760
  if (!Number.isInteger(index) || !models[index]) continue;
761
761
  const model = models[index];
762
- if (command === "p" || command === "x") updateProducer(runtime.dirs.workdir, model, command === "p" ? "promoted" : "demoted");
763
- else if (command === "e" || command === "d") setModelState(runtime.dirs.workdir, model, command === "e" ? "enabled" : "disabled");
764
- else if (command === "a" || command === "r") setModelState(runtime.dirs.workdir, model, "enabled", (await ask("role: ")).trim(), command === "r");
762
+ if (command === "a" || command === "d") setRouteState(runtime.dirs.workdir, model, command === "a" ? "admitted" : "disabled");
763
+ else if (command === "r" || command === "x") setRouteState(runtime.dirs.workdir, model, "admitted", (await ask("role: ")).trim(), command === "x");
765
764
  }
766
765
  } finally { rl.close(); }
767
766
  }
768
767
 
769
- export async function cmdProducerList(runtime: Runtime): Promise<number> {
770
- const policy = loadProducerPolicy(runtime.dirs.workdir);
771
- print(runtime.io, runtime.json, { ok: true, command: "producers list", policy }, [...policy.promoted.map((x) => `promoted ${x}`), ...policy.demoted.map((x) => `demoted ${x}`)].join("\n") || "no producer decisions");
768
+ export async function cmdRouteList(runtime: Runtime): Promise<number> {
769
+ const policy = loadRoutePolicy(runtime.dirs.workdir);
770
+ print(runtime.io, runtime.json, { ok: true, command: "routes list", policy }, [...policy.admitted.map((x) => `admitted ${x}`), ...policy.disabled.map((x) => `disabled ${x}`)].join("\n") || "no route decisions");
772
771
  return 0;
773
772
  }
774
773
 
@@ -111,9 +111,9 @@ import {
111
111
  cmdVnextRunCancel,
112
112
  cmdVnextRunList,
113
113
  cmdHarnessList,
114
- cmdProducerChange,
114
+ cmdRouteChange,
115
115
  cmdModelsScreen,
116
- cmdProducerList,
116
+ cmdRouteList,
117
117
  cmdModelInventoryRefresh,
118
118
  cmdVnextRuntime,
119
119
  } from "./cli/vnext.ts";
@@ -415,7 +415,7 @@ function createProgram(ctx: CliContext, result: { code: number }): Command {
415
415
  result.code = await cmdVnextRunList(runtimeFrom(ctx, this));
416
416
  });
417
417
 
418
- const modelsCmd = addGlobalOptions(program.command("models").description("Manage model catalogs, roles, and producer state"));
418
+ const modelsCmd = addGlobalOptions(program.command("models").description("Manage model catalogs, roles, and route state"));
419
419
  modelsCmd.action(async function modelsScreenAction(this: Command) { result.code = await cmdModelsScreen(runtimeFrom(ctx, this)); });
420
420
  modelsCmd.helpCommand("help", "Show models help");
421
421
  addGlobalOptions(modelsCmd.command("inventory-refresh").alias("refresh").description("Refresh the YAML model inventory with standard and Nous/OpenRouter prices"))
@@ -423,11 +423,11 @@ function createProgram(ctx: CliContext, result: { code: number }): Command {
423
423
  result.code = await cmdModelInventoryRefresh(runtimeFrom(ctx, this));
424
424
  });
425
425
 
426
- const producersCmd = addGlobalOptions(program.command("producers").description("Promote or demote verified producer models"));
427
- producersCmd.helpCommand("help", "Show producers help");
428
- addGlobalOptions(producersCmd.command("list").description("List producer decisions")).action(async function producersListAction(this: Command) { result.code = await cmdProducerList(runtimeFrom(ctx, this)); });
429
- for (const status of ["promote", "demote"] as const) {
430
- addGlobalOptions(producersCmd.command(status).description(`${status} a model from the inventory`)).option("--model <id>", "Exact model id; omit to choose interactively").action(async function producerChangeAction(this: Command, options: { model?: string }) { result.code = await cmdProducerChange(runtimeFrom(ctx, this), status === "promote" ? "promoted" : "demoted", options.model); });
426
+ const routesCmd = addGlobalOptions(program.command("routes").description("Admit or disable verified model routes"));
427
+ routesCmd.helpCommand("help", "Show routes help");
428
+ addGlobalOptions(routesCmd.command("list").description("List route decisions")).action(async function routesListAction(this: Command) { result.code = await cmdRouteList(runtimeFrom(ctx, this)); });
429
+ for (const status of ["admit", "disable"] as const) {
430
+ addGlobalOptions(routesCmd.command(status).description(`${status === "admit" ? "Admit" : "Disable"} a model route from the inventory`)).option("--model <id>", "Exact model id; omit to choose interactively").action(async function routeChangeAction(this: Command, options: { model?: string }) { result.code = await cmdRouteChange(runtimeFrom(ctx, this), status === "admit" ? "admitted" : "disabled", options.model); });
431
431
  }
432
432
 
433
433
  const harnessCmd = addGlobalOptions(program.command("harness").description("Detect coding-agent harnesses and authentication"));
@@ -8,7 +8,7 @@ import { AGENT_COMMANDS_MAP, enforceToolPolicy, getMcpTools, reconcileInbox } fr
8
8
  import { deliverInboxNotification } from "./inbox.ts";
9
9
  import type { HubEvent, MessageRecord } from "./protocol.ts";
10
10
 
11
- const VERSION = "0.7.30";
11
+ const VERSION = "0.7.35";
12
12
  const inbox = new Map<string, MessageRecord>();
13
13
  const notifiedInbox = new Set<string>();
14
14
  let meshClient: HubClient | undefined;
@@ -0,0 +1,68 @@
1
+ import { existsSync, readFileSync, mkdirSync, writeFileSync, readdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { parse, stringify } from "yaml";
4
+
5
+ const RETIRED_POLICY = ".kxm/producers.yaml";
6
+
7
+ export interface RoutePolicy { schema: "kxm.routes.v2"; updatedAt: string; admitted: string[]; disabled: string[]; roles: Record<string, string[]>; }
8
+ const empty = (): RoutePolicy => ({ schema: "kxm.routes.v2", updatedAt: new Date().toISOString(), admitted: [], disabled: [], roles: {} });
9
+ export function loadRoutePolicy(root: string): RoutePolicy {
10
+ if (existsSync(join(root, RETIRED_POLICY))) throw new Error(`retired ${RETIRED_POLICY} present; use .kxm/routes.yaml (kxm.routes.v2)`);
11
+ const path = join(root, ".kxm", "routes.yaml");
12
+ if (!existsSync(path)) return empty();
13
+ const value = parse(readFileSync(path, "utf8")) as Partial<RoutePolicy>;
14
+ if (value?.schema !== "kxm.routes.v2" || !Array.isArray(value.admitted)) throw new Error("invalid .kxm/routes.yaml");
15
+ return { schema: "kxm.routes.v2", updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : new Date().toISOString(), admitted: value.admitted.filter((x): x is string => typeof x === "string"), disabled: Array.isArray(value.disabled) ? value.disabled.filter((x): x is string => typeof x === "string") : [], roles: value.roles && typeof value.roles === "object" ? Object.fromEntries(Object.entries(value.roles).filter(([, v]) => Array.isArray(v)).map(([k, v]) => [k, (v as unknown[]).filter((x): x is string => typeof x === "string")])) : {} };
16
+ }
17
+ export function updateRouteState(root: string, model: string, state: "admitted" | "disabled"): RoutePolicy {
18
+ return setRouteState(root, model, state);
19
+ }
20
+ export function setRouteState(root: string, model: string, state: "admitted" | "disabled", role?: string, removeRole = false): RoutePolicy {
21
+ const policy = loadRoutePolicy(root);
22
+ policy.admitted = policy.admitted.filter((x) => x !== model);
23
+ policy.disabled = policy.disabled.filter((x) => x !== model);
24
+ if (state === "admitted") policy.admitted.push(model);
25
+ else policy.disabled.push(model);
26
+ if (role) {
27
+ if (!/^[a-z][a-z0-9_-]{0,63}$/i.test(role)) throw new Error("invalid role id");
28
+ const rolePath = join(root, ".kxm", "roles", `${role}.yaml`);
29
+ let roleFile: Record<string, unknown> = {};
30
+ if (existsSync(rolePath)) {
31
+ const parsed = parse(readFileSync(rolePath, "utf8"));
32
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) roleFile = parsed as Record<string, unknown>;
33
+ }
34
+ const roster = Array.isArray(roleFile.roster) ? roleFile.roster.filter((entry): entry is Record<string, unknown> => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)) : [];
35
+ const existing = roster.findIndex((entry) => entry.model === model);
36
+ if (removeRole) { if (existing >= 0) roster.splice(existing, 1); }
37
+ else if (existing < 0) roster.push({ model, enabled: true });
38
+ roleFile.schema ??= "kxm.role.v1"; roleFile.id ??= role; roleFile.roster = roster;
39
+ mkdirSync(join(root, ".kxm", "roles"), { recursive: true });
40
+ writeFileSync(rolePath, stringify(roleFile), "utf8");
41
+ }
42
+ policy.updatedAt = new Date().toISOString();
43
+ mkdirSync(join(root, ".kxm"), { recursive: true });
44
+ writeFileSync(join(root, ".kxm", "routes.yaml"), stringify(policy), "utf8");
45
+ return policy;
46
+ }
47
+
48
+ export function listRoleBindings(root: string): Record<string, string[]> {
49
+ const dir = join(root, ".kxm", "roles"); const result: Record<string, string[]> = {};
50
+ if (!existsSync(dir)) return result;
51
+ for (const file of readdirSync(dir).filter((name) => name.endsWith(".yaml"))) {
52
+ const role = file.slice(0, -5); const value = parse(readFileSync(join(dir, file), "utf8")) as { roster?: Array<{ model?: unknown }> };
53
+ result[role] = (value.roster ?? []).map((entry) => entry.model).filter((model): model is string => typeof model === "string");
54
+ }
55
+ return result;
56
+ }
57
+
58
+ export function isRouteAdmitted(root: string, modelId: string): boolean {
59
+ const policy = loadRoutePolicy(root);
60
+ return policy.admitted.includes(modelId) && !policy.disabled.includes(modelId);
61
+ }
62
+
63
+ export function listInventoryModels(root: string): string[] {
64
+ const path = join(root, ".kxm", "models", "inventory.yaml");
65
+ if (!existsSync(path)) return [];
66
+ const value = parse(readFileSync(path, "utf8")) as { models?: Array<{ id?: unknown }> };
67
+ return (value.models ?? []).map((m) => m.id).filter((id): id is string => typeof id === "string");
68
+ }
@@ -2,7 +2,7 @@ import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { parse } from "yaml";
5
- import { isProducerAdmitted, listRoleBindings } from "./producers.ts";
5
+ import { isRouteAdmitted, listRoleBindings } from "./routes.ts";
6
6
  import {
7
7
  buildFormalContextPacket,
8
8
  buildHandoffManifest,
@@ -1317,7 +1317,7 @@ function resolveProducerRoute(
1317
1317
  };
1318
1318
  }
1319
1319
 
1320
- if (!isProducerAdmitted(projectRoot, selector)) {
1320
+ if (!isRouteAdmitted(projectRoot, selector)) {
1321
1321
  return {
1322
1322
  error: {
1323
1323
  reason: "step_unsupported",
@@ -23,7 +23,7 @@ import {
23
23
  type VnextRuntimeContext,
24
24
  } from "./vnext-runtime.ts";
25
25
  import { createVnextOneShotProducer } from "./vnext-oneshot-producer.ts";
26
- import { isProducerAdmitted } from "./producers.ts";
26
+ import { isRouteAdmitted } from "./routes.ts";
27
27
  import { VnextRunScheduler, createVnextSimulatedProducer, recordDriveReceipt, recoverVnextRun, vnextDrivePollProjection } from "./vnext-engine.ts";
28
28
  import { vnextDriveSession, vnextOpenDriveSessions } from "./vnext-runtime-owner.ts";
29
29
 
@@ -487,7 +487,7 @@ async function startVnextRuntimeSupervisorInner(
487
487
  const value = model as Record<string, unknown>;
488
488
  const provider = typeof value.provider === "string" ? value.provider : undefined;
489
489
  const modelName = typeof value.model === "string" ? value.model : undefined;
490
- if (!provider || !modelName || !isProducerAdmitted(projectRoot, `${provider}/${modelName}`)) {
490
+ if (!provider || !modelName || !isRouteAdmitted(projectRoot, `${provider}/${modelName}`)) {
491
491
  throw new Error("producer_route_not_admitted");
492
492
  }
493
493
  return { provider, model: modelName };
@@ -1,53 +0,0 @@
1
- schema: kxm.producers.v1
2
- updatedAt: 2026-09-16T14:55:00.000Z
3
- promoted:
4
- - anthropic/fable
5
- - openai/gpt-5.6-sol
6
- - xai/grok-4.6
7
- - openrouter/qwen/qwen3-coder-plus
8
- # Qualified 2026-09-16 from the refreshed catalog (.kxm/models/inventory.yaml,
9
- # fetchedAt 2026-09-16T14:54:53Z). Quality evidence (side-by-side runs) is
10
- # queued — pending OpenRouter auth; not in any role rotation yet.
11
- - openrouter/qwen/qwen3.8-flash # 1M ctx, thinking; $0.15/M in, $0.47/M out
12
- - openrouter/z-ai/glm-5.3-flash # 1.31M ctx, thinking; $0.09/M in, $0.30/M out
13
- # Qualified 2026-09-16 via live probes on the native z.ai coding plan
14
- # (provider zai-coding-cn, subscription/unmetered): smoke + repo-shaped edit
15
- # probe + vision probe (screenshot color read) all passed. glm-5.3-highspeed
16
- # and glm-5v-turbo NOT admitted: plan returns 429 1311 (not in subscription).
17
- # glm-4.6v verified for vision but not admitted (superseded by 5.3-flash).
18
- - zai-coding-cn/glm-5.3 # 1M ctx, thinking; coding-plan subscription
19
- - zai-coding-cn/glm-5.3-flash # 1M ctx, thinking, vision; coding-plan subscription
20
- # Qualified 2026-09-16 via live probes (smoke; subscription/unmetered):
21
- # agy = Antigravity CLI (google sub, Gemini kebab ids bake in the effort tier;
22
- # harness default is flash-high). qwen-token-plan edit probe passed on
23
- # qwen3.8-flash. deepseek-v4.1-flash and glm-5.x on qwen-token-plan are
24
- # third-party models hosted by that plan.
25
- - google/gemini-3.8-flash-medium # agy harness, 1M ctx
26
- - google/gemini-3.8-flash-high # agy harness, 1M ctx; oneshot default for agy
27
- - qwen-token-plan/qwen3.8-flash # 1M ctx, thinking, vision; edit probe passed
28
- - qwen-token-plan/qwen3.8-max # 1M ctx, thinking, vision
29
- - qwen-token-plan/deepseek-v4.1-flash # 1M ctx, thinking, vision
30
- demoted: []
31
- enabled:
32
- - anthropic/fable
33
- - openai/gpt-5.6-sol
34
- - xai/grok-4.6
35
- - openrouter/qwen/qwen3-coder-plus
36
- - openrouter/qwen/qwen3.8-flash
37
- - openrouter/z-ai/glm-5.3-flash
38
- - zai-coding-cn/glm-5.3
39
- - zai-coding-cn/glm-5.3-flash
40
- - google/gemini-3.8-flash-medium
41
- - google/gemini-3.8-flash-high
42
- - qwen-token-plan/qwen3.8-flash
43
- - qwen-token-plan/qwen3.8-max
44
- - qwen-token-plan/deepseek-v4.1-flash
45
- disabled: []
46
- roles:
47
- implementer:
48
- - xai/grok-4.6
49
- - openrouter/qwen/qwen3-coder-plus
50
- critic-arch:
51
- - anthropic/fable
52
- critic-cli:
53
- - openai/gpt-5.6-sol
@@ -1,71 +0,0 @@
1
- import { existsSync, readFileSync, mkdirSync, writeFileSync, readdirSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { parse, stringify } from "yaml";
4
-
5
- export interface ProducerPolicy { schema: "kxm.producers.v1"; updatedAt: string; promoted: string[]; demoted: string[]; enabled: string[]; disabled: string[]; roles: Record<string, string[]>; }
6
- const empty = (): ProducerPolicy => ({ schema: "kxm.producers.v1", updatedAt: new Date().toISOString(), promoted: [], demoted: [], enabled: [], disabled: [], roles: {} });
7
- export function loadProducerPolicy(root: string): ProducerPolicy {
8
- const path = join(root, ".kxm", "producers.yaml");
9
- if (!existsSync(path)) return empty();
10
- const value = parse(readFileSync(path, "utf8")) as Partial<ProducerPolicy>;
11
- if (value?.schema !== "kxm.producers.v1" || !Array.isArray(value.promoted) || !Array.isArray(value.demoted)) throw new Error("invalid .kxm/producers.yaml");
12
- return { schema: "kxm.producers.v1", updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : new Date().toISOString(), promoted: value.promoted.filter((x): x is string => typeof x === "string"), demoted: value.demoted.filter((x): x is string => typeof x === "string"), enabled: Array.isArray(value.enabled) ? value.enabled.filter((x): x is string => typeof x === "string") : [], disabled: Array.isArray(value.disabled) ? value.disabled.filter((x): x is string => typeof x === "string") : [], roles: value.roles && typeof value.roles === "object" ? Object.fromEntries(Object.entries(value.roles).filter(([, v]) => Array.isArray(v)).map(([k, v]) => [k, (v as unknown[]).filter((x): x is string => typeof x === "string")])) : {} };
13
- }
14
- export function updateProducer(root: string, model: string, status: "promoted" | "demoted"): ProducerPolicy {
15
- const policy = loadProducerPolicy(root);
16
- policy.promoted = policy.promoted.filter((x) => x !== model);
17
- policy.demoted = policy.demoted.filter((x) => x !== model);
18
- policy[status].push(model);
19
- policy.updatedAt = new Date().toISOString();
20
- mkdirSync(join(root, ".kxm"), { recursive: true });
21
- writeFileSync(join(root, ".kxm", "producers.yaml"), stringify(policy), "utf8");
22
- return policy;
23
- }
24
- export function setModelState(root: string, model: string, state: "enabled" | "disabled", role?: string, removeRole = false): ProducerPolicy {
25
- const policy = loadProducerPolicy(root);
26
- policy.enabled = policy.enabled.filter((x) => x !== model);
27
- policy.disabled = policy.disabled.filter((x) => x !== model);
28
- policy[state].push(model);
29
- if (role) {
30
- if (!/^[a-z][a-z0-9_-]{0,63}$/i.test(role)) throw new Error("invalid role id");
31
- const rolePath = join(root, ".kxm", "roles", `${role}.yaml`);
32
- let roleFile: Record<string, unknown> = {};
33
- if (existsSync(rolePath)) {
34
- const parsed = parse(readFileSync(rolePath, "utf8"));
35
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) roleFile = parsed as Record<string, unknown>;
36
- }
37
- const roster = Array.isArray(roleFile.roster) ? roleFile.roster.filter((entry): entry is Record<string, unknown> => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)) : [];
38
- const existing = roster.findIndex((entry) => entry.model === model);
39
- if (removeRole) { if (existing >= 0) roster.splice(existing, 1); }
40
- else if (existing < 0) roster.push({ model, enabled: true });
41
- roleFile.schema ??= "kxm.role.v1"; roleFile.id ??= role; roleFile.roster = roster;
42
- mkdirSync(join(root, ".kxm", "roles"), { recursive: true });
43
- writeFileSync(rolePath, stringify(roleFile), "utf8");
44
- }
45
- policy.updatedAt = new Date().toISOString();
46
- mkdirSync(join(root, ".kxm"), { recursive: true });
47
- writeFileSync(join(root, ".kxm", "producers.yaml"), stringify(policy), "utf8");
48
- return policy;
49
- }
50
-
51
- export function listRoleBindings(root: string): Record<string, string[]> {
52
- const dir = join(root, ".kxm", "roles"); const result: Record<string, string[]> = {};
53
- if (!existsSync(dir)) return result;
54
- for (const file of readdirSync(dir).filter((name) => name.endsWith(".yaml"))) {
55
- const role = file.slice(0, -5); const value = parse(readFileSync(join(dir, file), "utf8")) as { roster?: Array<{ model?: unknown }> };
56
- result[role] = (value.roster ?? []).map((entry) => entry.model).filter((model): model is string => typeof model === "string");
57
- }
58
- return result;
59
- }
60
-
61
- export function isProducerAdmitted(root: string, modelId: string): boolean {
62
- const policy = loadProducerPolicy(root);
63
- return policy.enabled.includes(modelId) && policy.promoted.includes(modelId) && !policy.disabled.includes(modelId) && !policy.demoted.includes(modelId);
64
- }
65
-
66
- export function listInventoryModels(root: string): string[] {
67
- const path = join(root, ".kxm", "models", "inventory.yaml");
68
- if (!existsSync(path)) return [];
69
- const value = parse(readFileSync(path, "utf8")) as { models?: Array<{ id?: unknown }> };
70
- return (value.models ?? []).map((m) => m.id).filter((id): id is string => typeof id === "string");
71
- }