@kontextmind/kxm 0.7.40 → 0.7.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +45 -7
  3. package/docs/README.md +5 -3
  4. package/docs/agent-skills.md +1 -1
  5. package/docs/architecture.md +1 -1
  6. package/docs/configuration.md +28 -5
  7. package/docs/{vnext → contracts}/README.md +7 -7
  8. package/docs/{vnext → contracts}/architecture.md +2 -2
  9. package/docs/{vnext → contracts}/migration.md +25 -25
  10. package/docs/{vnext → contracts}/routing.md +2 -2
  11. package/docs/{vnext → contracts}/synchronization.md +1 -1
  12. package/docs/{vnext → contracts}/validation.md +7 -7
  13. package/docs/getting-started.md +1 -1
  14. package/docs/kb/qa-authentik-authentication.md +47 -0
  15. package/docs/kb/qa-extension-install-and-hub-bootstrap.md +68 -0
  16. package/docs/kb/qa-hub-on-a-public-host.md +31 -0
  17. package/docs/kb/qa-sqlite-vs-duckdb.md +18 -0
  18. package/docs/kb/qa-what-the-hub-stores.md +47 -0
  19. package/docs/packages.md +91 -0
  20. package/docs/templates/architecture.md +1 -1
  21. package/docs/test-matrix.md +6 -6
  22. package/docs/tui-components.md +131 -0
  23. package/examples/README.md +2 -2
  24. package/examples/{vnext → project}/.kxm/agents/critic-3.yaml +1 -1
  25. package/examples/{vnext → project}/README.md +4 -4
  26. package/package.json +18 -8
  27. package/packages/core/tui/CHANGELOG.md +19 -0
  28. package/packages/core/tui/LICENSE +21 -0
  29. package/packages/core/tui/README.md +45 -0
  30. package/packages/core/tui/dist/index.js +1439 -0
  31. package/packages/core/tui/src/adapters/pi.ts +73 -0
  32. package/packages/core/tui/src/adapters/terminal.ts +106 -0
  33. package/packages/core/tui/src/exports/index.ts +30 -0
  34. package/packages/core/tui/src/services/registry.ts +274 -0
  35. package/packages/core/tui/src/tui/keys.ts +130 -0
  36. package/packages/core/tui/src/tui/layout.ts +117 -0
  37. package/packages/core/tui/src/tui/panel.ts +435 -0
  38. package/packages/core/tui/src/tui/panelComponent.ts +208 -0
  39. package/packages/core/tui/src/tui/render.ts +309 -0
  40. package/packages/core/tui/src/tui/theme.ts +145 -0
  41. package/packages/core/tui/src/types/surface.ts +407 -0
  42. package/plugins/kxm/.claude-plugin/plugin.json +1 -1
  43. package/plugins/kxm/dist/cli.js +681 -553
  44. package/plugins/kxm/dist/extension.js +18 -18
  45. package/plugins/kxm/dist/mcp-server.js +1 -1
  46. package/plugins/kxm/dist/{vnext-runtime-supervisor.js → runtime-supervisor.js} +553 -553
  47. package/plugins/kxm/dist/runtime.js +608 -608
  48. package/plugins/kxm/dist/server.js +13 -13
  49. package/plugins/kxm/package.json +2 -2
  50. package/plugins/kxm/skills/kxm-project-setup/SKILL.md +2 -2
  51. package/plugins/kxm/skills/kxm-runs/SKILL.md +3 -3
  52. package/plugins/kxm/skills/kxm-session/SKILL.md +1 -1
  53. package/plugins/kxm/skills/kxm-workflow/SKILL.md +1 -1
  54. package/plugins/kxm/src/autocomplete.ts +4 -4
  55. package/plugins/kxm/src/{vnext-bindings.ts → bindings.ts} +48 -48
  56. package/plugins/kxm/src/cli/hub.ts +3 -3
  57. package/plugins/kxm/src/cli/{vnext.ts → project.ts} +106 -106
  58. package/plugins/kxm/src/cli/roles.ts +9 -9
  59. package/plugins/kxm/src/cli/system.ts +2 -2
  60. package/plugins/kxm/src/cli/tasks.ts +8 -8
  61. package/plugins/kxm/src/cli/workflows.ts +8 -8
  62. package/plugins/kxm/src/cli.ts +47 -47
  63. package/plugins/kxm/src/config.ts +69 -14
  64. package/plugins/kxm/src/database.ts +4 -4
  65. package/plugins/kxm/src/{vnext-engine-artifacts.ts → engine-artifacts.ts} +7 -7
  66. package/plugins/kxm/src/{vnext-engine-command.ts → engine-command.ts} +40 -40
  67. package/plugins/kxm/src/{vnext-engine-compile.ts → engine-compile.ts} +64 -64
  68. package/plugins/kxm/src/{vnext-engine-evidence.ts → engine-evidence.ts} +26 -26
  69. package/plugins/kxm/src/{vnext-engine-fold.ts → engine-fold.ts} +99 -99
  70. package/plugins/kxm/src/{vnext-engine-gate-records.ts → engine-gate-records.ts} +105 -105
  71. package/plugins/kxm/src/{vnext-engine-plan.ts → engine-plan.ts} +69 -69
  72. package/plugins/kxm/src/{vnext-engine.ts → engine.ts} +502 -502
  73. package/plugins/kxm/src/gate-hash.ts +10 -0
  74. package/plugins/kxm/src/{vnext-harness.ts → harness.ts} +1 -1
  75. package/plugins/kxm/src/hub.ts +1 -1
  76. package/plugins/kxm/src/init-guide-setup.ts +3 -3
  77. package/plugins/kxm/src/{vnext-init.ts → init.ts} +93 -93
  78. package/plugins/kxm/src/kxm-install-kind.ts +1 -1
  79. package/plugins/kxm/src/kxm-update-config.ts +2 -2
  80. package/plugins/kxm/src/local-snapshot.ts +23 -23
  81. package/plugins/kxm/src/mcp-server.ts +1 -1
  82. package/plugins/kxm/src/{vnext-migrate.ts → migrate.ts} +123 -123
  83. package/plugins/kxm/src/model-inventory.ts +1 -1
  84. package/plugins/kxm/src/{vnext-oneshot-evidence.ts → oneshot-evidence.ts} +2 -2
  85. package/plugins/kxm/src/{vnext-oneshot-process.ts → oneshot-process.ts} +4 -4
  86. package/plugins/kxm/src/{vnext-oneshot-producer.ts → oneshot-producer.ts} +24 -24
  87. package/plugins/kxm/src/{vnext-permission.ts → permission.ts} +86 -86
  88. package/plugins/kxm/src/{vnext-pi-producer.ts → pi-producer.ts} +13 -13
  89. package/plugins/kxm/src/{vnext-config.ts → project-config.ts} +177 -177
  90. package/plugins/kxm/src/{vnext-repair.ts → repair.ts} +159 -159
  91. package/plugins/kxm/src/restricted-yaml.d.mts +3 -3
  92. package/plugins/kxm/src/restricted-yaml.mjs +4 -4
  93. package/plugins/kxm/src/{vnext-runtime-owner.ts → runtime-owner.ts} +35 -35
  94. package/plugins/kxm/src/{vnext-runtime.ts → runtime-service.ts} +136 -136
  95. package/plugins/kxm/src/{vnext-runtime-store.ts → runtime-store.ts} +145 -145
  96. package/plugins/kxm/src/{vnext-runtime-supervisor.ts → runtime-supervisor.ts} +80 -80
  97. package/plugins/kxm/src/runtime.ts +6 -6
  98. package/plugins/kxm/src/session-work.ts +3 -3
  99. package/plugins/kxm/src/studio-layout.ts +6 -6
  100. package/plugins/kxm/src/{vnext-template.ts → template.ts} +33 -33
  101. package/plugins/kxm/src/tui.ts +10 -24
  102. package/schemas/{vnext/README.md → README.md} +3 -3
  103. package/schemas/{vnext/agent.schema.json → agent.schema.json} +1 -1
  104. package/schemas/{vnext/assignment-result.schema.json → assignment-result.schema.json} +1 -1
  105. package/schemas/{vnext/backup-manifest.schema.json → backup-manifest.schema.json} +1 -1
  106. package/schemas/{vnext/candidate.schema.json → candidate.schema.json} +1 -1
  107. package/schemas/{vnext/common.schema.json → common.schema.json} +2 -2
  108. package/schemas/{vnext/context-candidate.schema.json → context-candidate.schema.json} +1 -1
  109. package/schemas/{vnext/context-packet.schema.json → context-packet.schema.json} +1 -1
  110. package/schemas/{vnext/delivery-manifest.schema.json → delivery-manifest.schema.json} +1 -1
  111. package/schemas/{vnext/drive-receipt.schema.json → drive-receipt.schema.json} +2 -2
  112. package/schemas/{vnext/environment.schema.json → environment.schema.json} +1 -1
  113. package/schemas/{vnext/gate-registry.schema.json → gate-registry.schema.json} +1 -1
  114. package/schemas/{vnext/handoff-manifest.schema.json → handoff-manifest.schema.json} +1 -1
  115. package/schemas/{vnext/init-operation.schema.json → init-operation.schema.json} +1 -1
  116. package/schemas/{vnext/local-repository-bindings.schema.json → local-repository-bindings.schema.json} +1 -1
  117. package/schemas/{vnext/memory-record.schema.json → memory-record.schema.json} +1 -1
  118. package/schemas/{vnext/migration-decision.schema.json → migration-decision.schema.json} +1 -1
  119. package/schemas/{vnext/migration-plan.schema.json → migration-plan.schema.json} +1 -1
  120. package/schemas/{vnext/migration-receipt.schema.json → migration-receipt.schema.json} +1 -1
  121. package/schemas/{vnext/model.schema.json → model.schema.json} +1 -1
  122. package/schemas/{vnext/modes.schema.json → modes.schema.json} +1 -1
  123. package/schemas/{vnext/permission-diff.schema.json → permission-diff.schema.json} +1 -1
  124. package/schemas/policy-draft/README.md +2 -2
  125. package/schemas/{vnext/prices.schema.json → prices.schema.json} +1 -1
  126. package/schemas/{vnext/project.schema.json → project.schema.json} +1 -1
  127. package/schemas/{vnext/repository.schema.json → repository.schema.json} +1 -1
  128. package/schemas/{vnext/role.schema.json → role.schema.json} +1 -1
  129. package/schemas/{vnext/run-event.schema.json → run-event.schema.json} +1 -1
  130. package/schemas/{vnext/session-brief.schema.json → session-brief.schema.json} +2 -2
  131. package/schemas/{vnext/sync-event.schema.json → sync-event.schema.json} +1 -1
  132. package/schemas/{vnext/template-provenance.schema.json → template-provenance.schema.json} +1 -1
  133. package/schemas/{vnext/workflow.schema.json → workflow.schema.json} +1 -1
  134. package/scripts/build-package.mjs +59 -0
  135. package/scripts/build-runtime.mjs +3 -2
  136. package/scripts/check-generated.mjs +2 -1
  137. package/scripts/check-versions.mjs +12 -1
  138. package/scripts/docker-install-smoke.mjs +268 -0
  139. package/scripts/emit-codex-artifacts.mjs +1 -1
  140. package/scripts/kxm-bump-version.mjs +53 -3
  141. package/scripts/kxm-hub.mjs +36 -0
  142. package/scripts/kxm-runtime-supervisor.mjs +3 -3
  143. package/scripts/package-surfaces.mjs +39 -0
  144. package/plugins/kxm/src/vnext-gate-hash.ts +0 -10
  145. /package/docs/{vnext → contracts}/effects-and-recovery.md +0 -0
  146. /package/docs/{vnext → contracts}/lifecycles.md +0 -0
  147. /package/docs/{vnext → contracts}/terminology.md +0 -0
  148. /package/examples/{vnext → project}/.kxm/agents/coordinator.yaml +0 -0
  149. /package/examples/{vnext → project}/.kxm/agents/critic-1.yaml +0 -0
  150. /package/examples/{vnext → project}/.kxm/agents/critic-2.yaml +0 -0
  151. /package/examples/{vnext → project}/.kxm/agents/implementer.yaml +0 -0
  152. /package/examples/{vnext → project}/.kxm/agents/planner.yaml +0 -0
  153. /package/examples/{vnext → project}/.kxm/agents/reproducer.yaml +0 -0
  154. /package/examples/{vnext → project}/.kxm/agents/reviewer.yaml +0 -0
  155. /package/examples/{vnext → project}/.kxm/gates.yaml +0 -0
  156. /package/examples/{vnext → project}/.kxm/models/critic-claude.yaml +0 -0
  157. /package/examples/{vnext → project}/.kxm/models/critic-gemini.yaml +0 -0
  158. /package/examples/{vnext → project}/.kxm/models/critic-grok.yaml +0 -0
  159. /package/examples/{vnext → project}/.kxm/models/implementation.yaml +0 -0
  160. /package/examples/{vnext → project}/.kxm/models/primary.yaml +0 -0
  161. /package/examples/{vnext → project}/.kxm/prices.yaml +0 -0
  162. /package/examples/{vnext → project}/.kxm/project/env.yaml +0 -0
  163. /package/examples/{vnext → project}/.kxm/project.yaml +0 -0
  164. /package/examples/{vnext → project}/.kxm/repo/repo.yaml +0 -0
  165. /package/examples/{vnext → project}/.kxm/workflows/default.yaml +0 -0
  166. /package/examples/{vnext → project}/.kxm/workflows/fix.yaml +0 -0
  167. /package/examples/{vnext → project}/.kxm/workflows/improve.yaml +0 -0
  168. /package/examples/{vnext → project}/records/assignment-result-recorded.json +0 -0
  169. /package/examples/{vnext → project}/records/assignment-result.json +0 -0
  170. /package/examples/{vnext → project}/records/context-candidate.json +0 -0
  171. /package/examples/{vnext → project}/records/delivery-manifest.json +0 -0
  172. /package/examples/{vnext → project}/records/effect-uncertainty-resolved-sync.json +0 -0
  173. /package/examples/{vnext → project}/records/effect-uncertainty-resolved.json +0 -0
  174. /package/examples/{vnext → project}/records/run-created.json +0 -0
  175. /package/examples/{vnext → project}/records/sync-event.json +0 -0
  176. /package/examples/{vnext → project}/repositories/api/.kxm/repo/env.yaml +0 -0
  177. /package/examples/{vnext → project}/repositories/api/.kxm/repo/repo.yaml +0 -0
  178. /package/examples/{vnext → project}/repositories/web/.kxm/repo/repo.yaml +0 -0
@@ -4,26 +4,26 @@ import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync
4
4
  import { tmpdir } from "node:os";
5
5
  import { dirname, join, resolve, sep } from "node:path";
6
6
  import {
7
- VnextConfigError,
8
- loadVnextProject,
7
+ KxmConfigError,
8
+ loadKxmProject,
9
9
  parseRestrictedYaml,
10
- vnextCanonicalJson,
11
- vnextPortablePath,
12
- vnextResourceIdentifier,
10
+ kxmCanonicalJson,
11
+ kxmPortablePath,
12
+ kxmResourceIdentifier,
13
13
  type JsonObject,
14
14
  type JsonValue,
15
- type VnextConfigIssue,
16
- type VnextConfigOptions,
17
- type VnextProjectBundle,
18
- type VnextResource,
19
- type VnextResourceKind,
20
- } from "./vnext-config.ts";
15
+ type KxmConfigIssue,
16
+ type KxmConfigOptions,
17
+ type KxmProjectBundle,
18
+ type KxmResource,
19
+ type KxmResourceKind,
20
+ } from "./project-config.ts";
21
21
 
22
22
  /* ------------------------------------------------------------------ *
23
23
  * Structured authority projections
24
24
  * ------------------------------------------------------------------ */
25
25
 
26
- export type VnextPermissionField =
26
+ export type KxmPermissionField =
27
27
  | "repository-access"
28
28
  | "tools"
29
29
  | "secrets"
@@ -41,17 +41,17 @@ export type VnextPermissionField =
41
41
  | "gate"
42
42
  | "delivery";
43
43
 
44
- export type VnextPermissionDirection = "expansion" | "narrowing" | "neutral";
44
+ export type KxmPermissionDirection = "expansion" | "narrowing" | "neutral";
45
45
 
46
- export interface VnextAuthorityEntry {
46
+ export interface KxmAuthorityEntry {
47
47
  /** Resource-relative pointer, e.g. /repositories/api or /steps/3/tools/preset. */
48
48
  path: string;
49
- field: VnextPermissionField;
49
+ field: KxmPermissionField;
50
50
  /** Canonical JSON of the comparable value (never secret material). */
51
51
  value: string;
52
52
  }
53
53
 
54
- const PROSE_FIELDS: Readonly<Record<VnextResourceKind, ReadonlySet<string>>> = {
54
+ const PROSE_FIELDS: Readonly<Record<KxmResourceKind, ReadonlySet<string>>> = {
55
55
  project: new Set(["name", "description"]),
56
56
  repository: new Set(["description"]),
57
57
  agent: new Set(["purpose", "instructions"]),
@@ -66,7 +66,7 @@ const NETWORK_RANK: Readonly<Record<string, number>> = { none: 0, "provider-only
66
66
  const UNTRACKED_RANK: Readonly<Record<string, number>> = { "tracked-only": 0, ask: 1, bounded: 2 };
67
67
 
68
68
  function canonical(value: JsonValue | undefined): string {
69
- return vnextCanonicalJson(value === undefined ? null : value);
69
+ return kxmCanonicalJson(value === undefined ? null : value);
70
70
  }
71
71
 
72
72
  function asObject(value: JsonValue | undefined): JsonObject | undefined {
@@ -101,9 +101,9 @@ function secretGrantKeys(grants: JsonValue[]): Map<number, string> {
101
101
  }
102
102
 
103
103
  /** Extract the authority-bearing fields of one resource as comparable entries. */
104
- export function vnextAuthorityEntries(resource: { kind: VnextResourceKind; id?: string; value: JsonObject }): VnextAuthorityEntry[] {
105
- const entries: VnextAuthorityEntry[] = [];
106
- const push = (path: string, field: VnextPermissionField, value: JsonValue | undefined): void => {
104
+ export function kxmAuthorityEntries(resource: { kind: KxmResourceKind; id?: string; value: JsonObject }): KxmAuthorityEntry[] {
105
+ const entries: KxmAuthorityEntry[] = [];
106
+ const push = (path: string, field: KxmPermissionField, value: JsonValue | undefined): void => {
107
107
  entries.push({ path, field, value: canonical(value) });
108
108
  };
109
109
  const value = resource.value;
@@ -252,7 +252,7 @@ export function vnextAuthorityEntries(resource: { kind: VnextResourceKind; id?:
252
252
  }
253
253
 
254
254
  /** Prose/non-authority fields, surfaced separately so reviewers see them as neutral. */
255
- export function vnextProseEntries(resource: { kind: VnextResourceKind; value: JsonObject }): Map<string, string> {
255
+ export function kxmProseEntries(resource: { kind: KxmResourceKind; value: JsonObject }): Map<string, string> {
256
256
  const entries = new Map<string, string>();
257
257
  for (const field of PROSE_FIELDS[resource.kind]) {
258
258
  if (resource.value[field] !== undefined) entries.set(`/${field}`, canonical(resource.value[field]));
@@ -273,24 +273,24 @@ export function vnextProseEntries(resource: { kind: VnextResourceKind; value: Js
273
273
  * Diff
274
274
  * ------------------------------------------------------------------ */
275
275
 
276
- export interface VnextPermissionChange {
276
+ export interface KxmPermissionChange {
277
277
  resource: string;
278
278
  path: string;
279
- field: VnextPermissionField;
280
- direction: VnextPermissionDirection;
279
+ field: KxmPermissionField;
280
+ direction: KxmPermissionDirection;
281
281
  summary: string;
282
282
  baseValueSha256?: string;
283
283
  candidateValueSha256?: string;
284
284
  }
285
285
 
286
- export interface VnextPermissionDiff {
286
+ export interface KxmPermissionDiff {
287
287
  schema: "kxm.permission-diff.v1";
288
288
  baseRevision: string;
289
289
  candidateRevision: string;
290
- changes: VnextPermissionChange[];
291
- expansions: VnextPermissionChange[];
292
- narrowings: VnextPermissionChange[];
293
- neutralChanges: VnextPermissionChange[];
290
+ changes: KxmPermissionChange[];
291
+ expansions: KxmPermissionChange[];
292
+ narrowings: KxmPermissionChange[];
293
+ neutralChanges: KxmPermissionChange[];
294
294
  requiresReview: boolean;
295
295
  }
296
296
 
@@ -298,7 +298,7 @@ function valueHash(canonicalValue: string): string {
298
298
  return `sha256:${createHash("sha256").update(canonicalValue, "utf8").digest("hex")}`;
299
299
  }
300
300
 
301
- function rankDirection(rank: Readonly<Record<string, number>>, baseValue: string, candidateValue: string): VnextPermissionDirection {
301
+ function rankDirection(rank: Readonly<Record<string, number>>, baseValue: string, candidateValue: string): KxmPermissionDirection {
302
302
  const base = JSON.parse(baseValue) as unknown;
303
303
  const candidate = JSON.parse(candidateValue) as unknown;
304
304
  const baseRank = typeof base === "string" && base in rank ? rank[base] as number : undefined;
@@ -310,7 +310,7 @@ function rankDirection(rank: Readonly<Record<string, number>>, baseValue: string
310
310
  }
311
311
 
312
312
  /** Direction for a numeric bound: raising limits is expansion. */
313
- function numericBoundDirection(baseValue: string, candidateValue: string): VnextPermissionDirection {
313
+ function numericBoundDirection(baseValue: string, candidateValue: string): KxmPermissionDirection {
314
314
  const base = JSON.parse(baseValue) as unknown;
315
315
  const candidate = JSON.parse(candidateValue) as unknown;
316
316
  if (typeof base !== "number" || typeof candidate !== "number") return "expansion";
@@ -319,7 +319,7 @@ function numericBoundDirection(baseValue: string, candidateValue: string): Vnext
319
319
  return "neutral";
320
320
  }
321
321
 
322
- function budgetDirection(baseValue: string, candidateValue: string): VnextPermissionDirection {
322
+ function budgetDirection(baseValue: string, candidateValue: string): KxmPermissionDirection {
323
323
  const base = asObject(JSON.parse(baseValue) as JsonValue);
324
324
  const candidate = asObject(JSON.parse(candidateValue) as JsonValue);
325
325
  if (!base || !candidate) return "expansion";
@@ -335,7 +335,7 @@ function budgetDirection(baseValue: string, candidateValue: string): VnextPermis
335
335
  return sawNarrowing ? "narrowing" : "neutral";
336
336
  }
337
337
 
338
- function quorumDirection(baseValue: string, candidateValue: string): VnextPermissionDirection {
338
+ function quorumDirection(baseValue: string, candidateValue: string): KxmPermissionDirection {
339
339
  const base = asObject(JSON.parse(baseValue) as JsonValue);
340
340
  const candidate = asObject(JSON.parse(candidateValue) as JsonValue);
341
341
  if (!base || !candidate) return "expansion";
@@ -376,7 +376,7 @@ function quorumDirection(baseValue: string, candidateValue: string): VnextPermis
376
376
  };
377
377
  // Residual fail-closed check runs BEFORE any narrowing return: unknown or
378
378
  // future fields always expand, even alongside an ordered narrowing.
379
- if (vnextCanonicalJson(residualOf(baseValue)) !== vnextCanonicalJson(residualOf(candidateValue))) return "expansion";
379
+ if (kxmCanonicalJson(residualOf(baseValue)) !== kxmCanonicalJson(residualOf(candidateValue))) return "expansion";
380
380
  const basePolicy = asObject(base.producerPolicy as JsonValue | undefined);
381
381
  const candidatePolicy = asObject(candidate.producerPolicy as JsonValue | undefined);
382
382
  if (!basePolicy && !candidatePolicy) return sawNarrowing ? "narrowing" : "neutral";
@@ -404,7 +404,7 @@ function quorumDirection(baseValue: string, candidateValue: string): VnextPermis
404
404
  return sawNarrowing ? "narrowing" : "neutral";
405
405
  }
406
406
 
407
- function snapshotDirection(baseValue: string, candidateValue: string): VnextPermissionDirection {
407
+ function snapshotDirection(baseValue: string, candidateValue: string): KxmPermissionDirection {
408
408
  const base = asObject(JSON.parse(baseValue) as JsonValue);
409
409
  const candidate = asObject(JSON.parse(candidateValue) as JsonValue);
410
410
  if (!base || !candidate) return "expansion";
@@ -426,16 +426,16 @@ function snapshotDirection(baseValue: string, candidateValue: string): VnextPerm
426
426
  // Residual fail-closed check: unknown future snapshot keys expand.
427
427
  const CLASSIFIED_SNAPSHOT = new Set(["untracked", "maxUntrackedFileBytes", "maxUntrackedTotalBytes", "dirtySubmodules"]);
428
428
  const residualOf = (snapshot: JsonObject): JsonValue => Object.fromEntries(Object.entries(snapshot).filter(([key]) => !CLASSIFIED_SNAPSHOT.has(key)));
429
- if (vnextCanonicalJson(residualOf(baseSnapshot)) !== vnextCanonicalJson(residualOf(candidateSnapshot))) return "expansion";
429
+ if (kxmCanonicalJson(residualOf(baseSnapshot)) !== kxmCanonicalJson(residualOf(candidateSnapshot))) return "expansion";
430
430
  return bounds === "narrowing" || untracked === "narrowing" ? "narrowing" : "neutral";
431
431
  }
432
432
 
433
433
  function classifyChange(
434
- field: VnextPermissionField,
434
+ field: KxmPermissionField,
435
435
  baseValue: string | undefined,
436
436
  candidateValue: string | undefined,
437
437
  context?: { fallbackRank?: number; baseFallbackRank?: number },
438
- ): VnextPermissionDirection {
438
+ ): KxmPermissionDirection {
439
439
  if (baseValue === candidateValue) return "neutral";
440
440
  if (baseValue === undefined || candidateValue === undefined) {
441
441
  if (candidateValue === undefined) {
@@ -489,7 +489,7 @@ function classifyChange(
489
489
  // review-required expansion; then order by required (default true).
490
490
  const { required: _b, ...baseRest } = base;
491
491
  const { required: _c, ...candidateRest } = candidate;
492
- if (vnextCanonicalJson(baseRest as JsonValue) !== vnextCanonicalJson(candidateRest as JsonValue)) return "expansion";
492
+ if (kxmCanonicalJson(baseRest as JsonValue) !== kxmCanonicalJson(candidateRest as JsonValue)) return "expansion";
493
493
  const baseRequired = (base.required ?? true) === true;
494
494
  const candidateRequired = (candidate.required ?? true) === true;
495
495
  if (baseRequired && !candidateRequired) return "narrowing";
@@ -506,14 +506,14 @@ function classifyChange(
506
506
  }
507
507
  }
508
508
 
509
- function summarize(resource: string, path: string, field: VnextPermissionField, direction: VnextPermissionDirection, baseValue: string | undefined, candidateValue: string | undefined): string {
509
+ function summarize(resource: string, path: string, field: KxmPermissionField, direction: KxmPermissionDirection, baseValue: string | undefined, candidateValue: string | undefined): string {
510
510
  const verb = baseValue === undefined ? "added" : candidateValue === undefined ? "removed" : "changed";
511
511
  return `${resource} ${path} ${field} ${verb} (${direction})`;
512
512
  }
513
513
 
514
514
  /** Diff two complete bundles into a deterministic, classified permission report. */
515
- export function computeVnextPermissionDiff(base: VnextProjectBundle, candidate: VnextProjectBundle): VnextPermissionDiff {
516
- const changes: VnextPermissionChange[] = [];
515
+ export function computeKxmPermissionDiff(base: KxmProjectBundle, candidate: KxmProjectBundle): KxmPermissionDiff {
516
+ const changes: KxmPermissionChange[] = [];
517
517
  const baseByPath = new Map(base.resources.map((resource) => [resource.logicalPath, resource]));
518
518
  const candidateByPath = new Map(candidate.resources.map((resource) => [resource.logicalPath, resource]));
519
519
 
@@ -528,8 +528,8 @@ export function computeVnextPermissionDiff(base: VnextProjectBundle, candidate:
528
528
  // Resource added or removed: shape change. Added resources expand
529
529
  // authority; removed resources narrow it — except models: removing one
530
530
  // can retarget tag-based consumers onto another profile (an expansion).
531
- const resource = candidateResource ?? baseResource as VnextResource;
532
- const direction: VnextPermissionDirection = candidateResource
531
+ const resource = candidateResource ?? baseResource as KxmResource;
532
+ const direction: KxmPermissionDirection = candidateResource
533
533
  ? "expansion"
534
534
  : ((resource.kind === "model" || resource.kind === "gate-registry") ? "expansion" : "narrowing");
535
535
  changes.push({
@@ -560,27 +560,27 @@ export function computeVnextPermissionDiff(base: VnextProjectBundle, candidate:
560
560
  }
561
561
 
562
562
  /** Diff two values of one resource kind (e.g. template baseline vs target). */
563
- export function computeVnextResourcePermissionDiff(
564
- kind: VnextResourceKind,
563
+ export function computeKxmResourcePermissionDiff(
564
+ kind: KxmResourceKind,
565
565
  resourcePath: string,
566
566
  baseValue: JsonObject,
567
567
  candidateValue: JsonObject,
568
- ): VnextPermissionChange[] {
569
- const changes: VnextPermissionChange[] = [];
570
- const base: VnextResource = { kind, file: resourcePath, logicalPath: resourcePath, value: baseValue };
571
- const candidate: VnextResource = { kind, file: resourcePath, logicalPath: resourcePath, value: candidateValue };
568
+ ): KxmPermissionChange[] {
569
+ const changes: KxmPermissionChange[] = [];
570
+ const base: KxmResource = { kind, file: resourcePath, logicalPath: resourcePath, value: baseValue };
571
+ const candidate: KxmResource = { kind, file: resourcePath, logicalPath: resourcePath, value: candidateValue };
572
572
  diffResource(resourcePath, base, candidate, changes);
573
573
  return changes.sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
574
574
  }
575
575
 
576
- function diffResource(logicalPath: string, base: VnextResource, candidate: VnextResource, changes: VnextPermissionChange[]): void {
577
- const baseEntries = new Map(vnextAuthorityEntries(base).map((entry) => [entry.path, entry]));
578
- const candidateEntries = new Map(vnextAuthorityEntries(candidate).map((entry) => [entry.path, entry]));
576
+ function diffResource(logicalPath: string, base: KxmResource, candidate: KxmResource, changes: KxmPermissionChange[]): void {
577
+ const baseEntries = new Map(kxmAuthorityEntries(base).map((entry) => [entry.path, entry]));
578
+ const candidateEntries = new Map(kxmAuthorityEntries(candidate).map((entry) => [entry.path, entry]));
579
579
  const paths = [...new Set([...baseEntries.keys(), ...candidateEntries.keys()])].sort();
580
580
  for (const path of paths) {
581
581
  const baseEntry = baseEntries.get(path);
582
582
  const candidateEntry = candidateEntries.get(path);
583
- const field = (candidateEntry ?? baseEntry as VnextAuthorityEntry).field;
583
+ const field = (candidateEntry ?? baseEntry as KxmAuthorityEntry).field;
584
584
  // For per-repository overrides, the effective fallback is the resource-
585
585
  // level defaultRepositoryAccess (the loader's ceiling rule). Removal
586
586
  // compares against the candidate's default; addition against the base's.
@@ -609,8 +609,8 @@ function diffResource(logicalPath: string, base: VnextResource, candidate: Vnext
609
609
  });
610
610
  }
611
611
  // Prose changes are surfaced as neutral for reviewer visibility.
612
- const baseProse = vnextProseEntries(base);
613
- const candidateProse = vnextProseEntries(candidate);
612
+ const baseProse = kxmProseEntries(base);
613
+ const candidateProse = kxmProseEntries(candidate);
614
614
  for (const path of [...new Set([...baseProse.keys(), ...candidateProse.keys()])].sort()) {
615
615
  if (baseProse.get(path) === candidateProse.get(path)) continue;
616
616
  changes.push({
@@ -642,7 +642,7 @@ function git(root: string, args: string[]): string {
642
642
  maxBuffer: 64 * 1024 * 1024,
643
643
  });
644
644
  if (result.status !== 0 || result.error) {
645
- throw new VnextConfigError([{
645
+ throw new KxmConfigError([{
646
646
  phase: "discovery",
647
647
  code: "git_base_unavailable",
648
648
  file: args[0] ?? "<git>",
@@ -660,7 +660,7 @@ function gitBuffer(root: string, args: string[]): Buffer {
660
660
  maxBuffer: 256 * 1024 * 1024,
661
661
  });
662
662
  if (result.status !== 0 || result.error) {
663
- throw new VnextConfigError([{
663
+ throw new KxmConfigError([{
664
664
  phase: "discovery",
665
665
  code: "git_base_unavailable",
666
666
  file: args[0] ?? "<git>",
@@ -673,7 +673,7 @@ function gitBuffer(root: string, args: string[]): Buffer {
673
673
  /** Resolve a revision to its tree SHA once so a moving ref cannot mix bases. */
674
674
  function resolveTreeRevision(root: string, revision: string): string {
675
675
  if (!/^[A-Za-z0-9._/^~-]+$/.test(revision) || revision.includes("..") || revision.startsWith("-")) {
676
- throw new VnextConfigError([{
676
+ throw new KxmConfigError([{
677
677
  phase: "discovery",
678
678
  code: "git_revision_invalid",
679
679
  file: revision,
@@ -684,7 +684,7 @@ function resolveTreeRevision(root: string, revision: string): string {
684
684
  }
685
685
 
686
686
  /** Load the bundle as of a Git revision by materializing tracked files into a temporary shadow root. */
687
- export function loadVnextProjectAtRevision(root: string, revision: string, options: VnextConfigOptions = {}): VnextProjectBundle {
687
+ export function loadKxmProjectAtRevision(root: string, revision: string, options: KxmConfigOptions = {}): KxmProjectBundle {
688
688
  const tree = resolveTreeRevision(root, revision);
689
689
  const listing = gitBuffer(root, ["ls-tree", "-r", "-z", "--name-only", tree]).toString("utf8");
690
690
  const paths = listing
@@ -697,7 +697,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
697
697
  for (const path of paths) {
698
698
  const segments = path.split("/");
699
699
  if (segments.some((segment) => segment === "" || segment === "." || segment === ".." || /[\\:]/.test(segment))) {
700
- throw new VnextConfigError([{
700
+ throw new KxmConfigError([{
701
701
  phase: "path",
702
702
  code: "git_tree_path_invalid",
703
703
  file: path,
@@ -707,7 +707,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
707
707
  const absolute = join(shadowResolved, ...segments);
708
708
  const resolved = resolve(absolute);
709
709
  if (!resolved.startsWith(`${shadowResolved}${sep}`)) {
710
- throw new VnextConfigError([{
710
+ throw new KxmConfigError([{
711
711
  phase: "path",
712
712
  code: "git_tree_path_invalid",
713
713
  file: path,
@@ -733,16 +733,16 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
733
733
  try {
734
734
  baseProject = loadBaseProjectDeclarations(baseProjectFile);
735
735
  } catch (error) {
736
- if (error instanceof VnextConfigError) {
737
- throw new VnextConfigError(error.issues.map((entry) => ({ ...entry, message: `base ${revision}: ${entry.message}` })));
736
+ if (error instanceof KxmConfigError) {
737
+ throw new KxmConfigError(error.issues.map((entry) => ({ ...entry, message: `base ${revision}: ${entry.message}` })));
738
738
  }
739
739
  throw error;
740
740
  }
741
741
  const shadowBindings: Record<string, string> = {};
742
742
  for (const member of baseProject) {
743
743
  if (member.role !== "member") continue;
744
- if (!vnextResourceIdentifier(member.repositoryId)) {
745
- throw new VnextConfigError([{
744
+ if (!kxmResourceIdentifier(member.repositoryId)) {
745
+ throw new KxmConfigError([{
746
746
  phase: "path",
747
747
  code: "git_tree_path_invalid",
748
748
  file: ".kxm/project.yaml",
@@ -750,7 +750,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
750
750
  }]);
751
751
  }
752
752
  if (member.pathHint !== undefined && !portableMemberPathHint(member.pathHint)) {
753
- throw new VnextConfigError([{
753
+ throw new KxmConfigError([{
754
754
  phase: "path",
755
755
  code: "git_tree_path_invalid",
756
756
  file: ".kxm/project.yaml",
@@ -767,7 +767,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
767
767
  : undefined;
768
768
  if (!memberWorktree || !existsSync(memberWorktree)) {
769
769
  if (member.required === false) continue; // optional member absent on this host (loader tolerates it)
770
- throw new VnextConfigError([{
770
+ throw new KxmConfigError([{
771
771
  phase: "discovery",
772
772
  code: "trust_scope_unsupported",
773
773
  file: ".kxm/project.yaml",
@@ -781,7 +781,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
781
781
  if (gitlink.length > 0) {
782
782
  const match = /^160000 commit ([0-9a-f]{40,64})\t/.exec(gitlink);
783
783
  if (!match) {
784
- throw new VnextConfigError([{
784
+ throw new KxmConfigError([{
785
785
  phase: "discovery",
786
786
  code: "trust_scope_unsupported",
787
787
  file: ".kxm/project.yaml",
@@ -794,7 +794,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
794
794
  // the only reviewable base is the member's own HEAD commit.
795
795
  pinnedCommit = git(memberWorktree, ["rev-parse", "--verify", "--quiet", "HEAD^{commit}"]).trim();
796
796
  } else {
797
- throw new VnextConfigError([{
797
+ throw new KxmConfigError([{
798
798
  phase: "discovery",
799
799
  code: "trust_scope_unsupported",
800
800
  file: ".kxm/project.yaml",
@@ -807,7 +807,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
807
807
  pinnedCommit = git(memberWorktree, ["rev-parse", "--verify", "--quiet", "HEAD^{commit}"]).trim();
808
808
  }
809
809
  if (!pinnedCommit) {
810
- throw new VnextConfigError([{
810
+ throw new KxmConfigError([{
811
811
  phase: "discovery",
812
812
  code: "trust_scope_unsupported",
813
813
  file: ".kxm/project.yaml",
@@ -819,7 +819,7 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
819
819
  const memberPaths = memberListing.split("\u0000").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
820
820
  const memberShadowRoot = join(shadowResolved, shadowMembersDir, member.repositoryId);
821
821
  if (!resolve(memberShadowRoot).startsWith(`${resolve(shadowResolved, shadowMembersDir)}${sep}`)) {
822
- throw new VnextConfigError([{
822
+ throw new KxmConfigError([{
823
823
  phase: "path",
824
824
  code: "git_tree_path_invalid",
825
825
  file: ".kxm/project.yaml",
@@ -829,12 +829,12 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
829
829
  for (const path of memberPaths) {
830
830
  const segments = path.split("/");
831
831
  if (segments.some((segment) => segment === "" || segment === "." || segment === ".." || /[\\:]/.test(segment))) {
832
- throw new VnextConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path, message: "member Git tree entry contains a traversal or non-portable segment" }]);
832
+ throw new KxmConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path, message: "member Git tree entry contains a traversal or non-portable segment" }]);
833
833
  }
834
834
  const absolute = join(memberShadowRoot, ...segments);
835
835
  const resolved = resolve(absolute);
836
836
  if (!resolved.startsWith(`${resolve(memberShadowRoot)}${sep}`)) {
837
- throw new VnextConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path, message: "member Git tree entry escapes the shadow root" }]);
837
+ throw new KxmConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path, message: "member Git tree entry escapes the shadow root" }]);
838
838
  }
839
839
  const content = gitBuffer(memberWorktree, ["cat-file", "blob", `${memberTree}:${path}`]);
840
840
  mkdirSync(dirname(absolute), { recursive: true });
@@ -844,10 +844,10 @@ export function loadVnextProjectAtRevision(root: string, revision: string, optio
844
844
  shadowBindings[member.repositoryId] = memberShadowRoot;
845
845
  }
846
846
  try {
847
- return loadVnextProject(shadowResolved, { ...options, repositoryBindings: shadowBindings });
847
+ return loadKxmProject(shadowResolved, { ...options, repositoryBindings: shadowBindings });
848
848
  } catch (error) {
849
- if (error instanceof VnextConfigError) {
850
- throw new VnextConfigError(error.issues.map((entry) => ({ ...entry, message: `base ${revision}: ${entry.message}` })));
849
+ if (error instanceof KxmConfigError) {
850
+ throw new KxmConfigError(error.issues.map((entry) => ({ ...entry, message: `base ${revision}: ${entry.message}` })));
851
851
  }
852
852
  throw error;
853
853
  }
@@ -865,7 +865,7 @@ interface BaseProjectMember {
865
865
 
866
866
  /** Portable member pathHint predicate (mirrors the loader's portable path rules; "." is never a member). */
867
867
  function portableMemberPathHint(pathHint: string): boolean {
868
- return pathHint !== "." && vnextPortablePath(pathHint);
868
+ return pathHint !== "." && kxmPortablePath(pathHint);
869
869
  }
870
870
 
871
871
 
@@ -898,7 +898,7 @@ function initShadowGitRoot(directory: string): void {
898
898
  windowsHide: true,
899
899
  });
900
900
  if (result.status !== 0 || result.error) {
901
- throw new VnextConfigError([{
901
+ throw new KxmConfigError([{
902
902
  phase: "discovery",
903
903
  code: "git_base_unavailable",
904
904
  file: directory,
@@ -908,18 +908,18 @@ function initShadowGitRoot(directory: string): void {
908
908
  }
909
909
 
910
910
  /** Diff the working tree against a Git revision. */
911
- export function diffVnextProjectAgainstRevision(
911
+ export function diffKxmProjectAgainstRevision(
912
912
  root: string,
913
913
  revision: string,
914
- options: VnextConfigOptions = {},
915
- ): VnextPermissionDiff {
916
- const base = loadVnextProjectAtRevision(root, revision, options);
917
- const candidate = loadVnextProject(root, options);
918
- return computeVnextPermissionDiff(base, candidate);
914
+ options: KxmConfigOptions = {},
915
+ ): KxmPermissionDiff {
916
+ const base = loadKxmProjectAtRevision(root, revision, options);
917
+ const candidate = loadKxmProject(root, options);
918
+ return computeKxmPermissionDiff(base, candidate);
919
919
  }
920
920
 
921
921
  /** Human-readable report lines for the CLI. */
922
- export function formatVnextPermissionDiff(diff: VnextPermissionDiff): string {
922
+ export function formatKxmPermissionDiff(diff: KxmPermissionDiff): string {
923
923
  const lines: string[] = [];
924
924
  lines.push(`permission diff: ${diff.baseRevision.slice(0, 19)}… -> ${diff.candidateRevision.slice(0, 19)}…`);
925
925
  if (diff.changes.length === 0) {
@@ -3,16 +3,16 @@ import { join } from "node:path";
3
3
  import { StringDecoder } from "node:string_decoder";
4
4
  import {
5
5
  registerTrustedProducer,
6
- type VnextProducer,
7
- type VnextProducerRequest,
8
- type VnextProducerResult,
9
- } from "./vnext-engine.ts";
6
+ type KxmProducer,
7
+ type KxmProducerRequest,
8
+ type KxmProducerResult,
9
+ } from "./engine.ts";
10
10
  import {
11
11
  probeHarnessAssignmentAsync,
12
12
  type HarnessAssignmentProbeOptions,
13
13
  type HarnessInventory,
14
14
  type HarnessStatus,
15
- } from "./vnext-harness.ts";
15
+ } from "./harness.ts";
16
16
  import {
17
17
  calculateModelCost,
18
18
  loadPriceCatalogForEstimate,
@@ -380,7 +380,7 @@ export class PiSession {
380
380
  }
381
381
  }
382
382
 
383
- export interface VnextPiProducerOptions {
383
+ export interface KxmPiProducerOptions {
384
384
  projectRoot?: string | undefined;
385
385
  sessionDir?: string | undefined;
386
386
  piCommand?: string | undefined;
@@ -394,15 +394,15 @@ export interface VnextPiProducerOptions {
394
394
  defaultProvider?: string | undefined;
395
395
  }
396
396
 
397
- export interface VnextPiProducer extends VnextProducer {
397
+ export interface KxmPiProducer extends KxmProducer {
398
398
  readonly id: "pi";
399
399
  readonly sessions: ReadonlyMap<string, PiSession>;
400
- produce(request: VnextProducerRequest): Promise<VnextProducerResult>;
400
+ produce(request: KxmProducerRequest): Promise<KxmProducerResult>;
401
401
  close(): Promise<void>;
402
402
  closeRun(runId: string): Promise<void>;
403
403
  }
404
404
 
405
- export function createVnextPiProducer(options: VnextPiProducerOptions = {}): VnextPiProducer {
405
+ export function createKxmPiProducer(options: KxmPiProducerOptions = {}): KxmPiProducer {
406
406
  const sessions = new Map<string, PiSession>();
407
407
  const defaultModel = options.defaultModel ?? "xai/grok-4.6";
408
408
  const defaultProvider = options.defaultProvider ?? "xai";
@@ -416,7 +416,7 @@ export function createVnextPiProducer(options: VnextPiProducerOptions = {}): Vne
416
416
  return { provider: defaultProvider, model: trimmed };
417
417
  }
418
418
 
419
- function resolveModelForRequest(request: VnextProducerRequest): { provider: string; model: string; thinking?: string | undefined } {
419
+ function resolveModelForRequest(request: KxmProducerRequest): { provider: string; model: string; thinking?: string | undefined } {
420
420
  if (request.model) {
421
421
  const parsed = parseModelString(request.model);
422
422
  return {
@@ -466,7 +466,7 @@ export function createVnextPiProducer(options: VnextPiProducerOptions = {}): Vne
466
466
  }
467
467
  }
468
468
 
469
- async function getOrCreateSession(request: VnextProducerRequest, model: string): Promise<PiSession> {
469
+ async function getOrCreateSession(request: KxmProducerRequest, model: string): Promise<PiSession> {
470
470
  const key = formatPiSessionKey({
471
471
  runId: request.runId,
472
472
  agentId: request.agentId,
@@ -532,13 +532,13 @@ export function createVnextPiProducer(options: VnextPiProducerOptions = {}): Vne
532
532
  return session;
533
533
  }
534
534
 
535
- const producer: VnextPiProducer = {
535
+ const producer: KxmPiProducer = {
536
536
  id: "pi",
537
537
  get sessions(): ReadonlyMap<string, PiSession> {
538
538
  return sessions;
539
539
  },
540
540
 
541
- async produce(request: VnextProducerRequest): Promise<VnextProducerResult> {
541
+ async produce(request: KxmProducerRequest): Promise<KxmProducerResult> {
542
542
  const startTime = Date.now();
543
543
  const resolved = resolveModelForRequest(request);
544
544