@kontextmind/kxm 0.7.40 → 0.7.43

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 (177) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +41 -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-runtime-supervisor.mjs +3 -3
  142. package/scripts/package-surfaces.mjs +39 -0
  143. package/plugins/kxm/src/vnext-gate-hash.ts +0 -10
  144. /package/docs/{vnext → contracts}/effects-and-recovery.md +0 -0
  145. /package/docs/{vnext → contracts}/lifecycles.md +0 -0
  146. /package/docs/{vnext → contracts}/terminology.md +0 -0
  147. /package/examples/{vnext → project}/.kxm/agents/coordinator.yaml +0 -0
  148. /package/examples/{vnext → project}/.kxm/agents/critic-1.yaml +0 -0
  149. /package/examples/{vnext → project}/.kxm/agents/critic-2.yaml +0 -0
  150. /package/examples/{vnext → project}/.kxm/agents/implementer.yaml +0 -0
  151. /package/examples/{vnext → project}/.kxm/agents/planner.yaml +0 -0
  152. /package/examples/{vnext → project}/.kxm/agents/reproducer.yaml +0 -0
  153. /package/examples/{vnext → project}/.kxm/agents/reviewer.yaml +0 -0
  154. /package/examples/{vnext → project}/.kxm/gates.yaml +0 -0
  155. /package/examples/{vnext → project}/.kxm/models/critic-claude.yaml +0 -0
  156. /package/examples/{vnext → project}/.kxm/models/critic-gemini.yaml +0 -0
  157. /package/examples/{vnext → project}/.kxm/models/critic-grok.yaml +0 -0
  158. /package/examples/{vnext → project}/.kxm/models/implementation.yaml +0 -0
  159. /package/examples/{vnext → project}/.kxm/models/primary.yaml +0 -0
  160. /package/examples/{vnext → project}/.kxm/prices.yaml +0 -0
  161. /package/examples/{vnext → project}/.kxm/project/env.yaml +0 -0
  162. /package/examples/{vnext → project}/.kxm/project.yaml +0 -0
  163. /package/examples/{vnext → project}/.kxm/repo/repo.yaml +0 -0
  164. /package/examples/{vnext → project}/.kxm/workflows/default.yaml +0 -0
  165. /package/examples/{vnext → project}/.kxm/workflows/fix.yaml +0 -0
  166. /package/examples/{vnext → project}/.kxm/workflows/improve.yaml +0 -0
  167. /package/examples/{vnext → project}/records/assignment-result-recorded.json +0 -0
  168. /package/examples/{vnext → project}/records/assignment-result.json +0 -0
  169. /package/examples/{vnext → project}/records/context-candidate.json +0 -0
  170. /package/examples/{vnext → project}/records/delivery-manifest.json +0 -0
  171. /package/examples/{vnext → project}/records/effect-uncertainty-resolved-sync.json +0 -0
  172. /package/examples/{vnext → project}/records/effect-uncertainty-resolved.json +0 -0
  173. /package/examples/{vnext → project}/records/run-created.json +0 -0
  174. /package/examples/{vnext → project}/records/sync-event.json +0 -0
  175. /package/examples/{vnext → project}/repositories/api/.kxm/repo/env.yaml +0 -0
  176. /package/examples/{vnext → project}/repositories/api/.kxm/repo/repo.yaml +0 -0
  177. /package/examples/{vnext → project}/repositories/web/.kxm/repo/repo.yaml +0 -0
@@ -3,25 +3,25 @@ import { chmodSync, closeSync, existsSync, fsyncSync, lstatSync, mkdirSync, open
3
3
  import { join, resolve } from "node:path";
4
4
  import { stringify } from "yaml";
5
5
  import {
6
- VnextConfigError,
7
- VnextSchemaRegistry,
6
+ KxmConfigError,
7
+ KxmSchemaRegistry,
8
8
  discoverGitRoot,
9
9
  legacyConfigFilesAt,
10
- loadVnextProject,
10
+ loadKxmProject,
11
11
  migrationReceiptSelfHash,
12
12
  parseRestrictedYaml,
13
- readVnextMigrationReceipt,
14
- validateVnextResources,
15
- verifyVnextMigrationReceiptTarget,
16
- vnextCanonicalJson,
17
- VNEXT_MIGRATION_RECEIPT_PATH,
13
+ readKxmMigrationReceipt,
14
+ validateKxmResources,
15
+ verifyKxmMigrationReceiptTarget,
16
+ kxmCanonicalJson,
17
+ KXM_MIGRATION_RECEIPT_PATH,
18
18
  type JsonObject,
19
19
  type JsonValue,
20
- type VnextConfigIssue,
21
- type VnextConfigOptions,
22
- type VnextResourceKind,
23
- } from "./vnext-config.ts";
24
- import { withVnextLocalBindingLock, type VnextLocalBindingLock, type VnextLocalBindingStoreOptions } from "./vnext-bindings.ts";
20
+ type KxmConfigIssue,
21
+ type KxmConfigOptions,
22
+ type KxmResourceKind,
23
+ } from "./project-config.ts";
24
+ import { withKxmLocalBindingLock, type KxmLocalBindingLock, type KxmLocalBindingStoreOptions } from "./bindings.ts";
25
25
 
26
26
  /* ------------------------------------------------------------------ *
27
27
  * Bounded legacy JSON reading (duplicate keys rejected, depth bounded)
@@ -32,12 +32,12 @@ const MAX_LEGACY_JSON_DEPTH = 32;
32
32
  const MAX_LEGACY_JSON_NODES = 32_768;
33
33
  const MAX_LEGACY_SOURCES = 64;
34
34
 
35
- function migrateIssue(phase: VnextConfigIssue["phase"], code: string, file: string, message: string): VnextConfigIssue {
35
+ function migrateIssue(phase: KxmConfigIssue["phase"], code: string, file: string, message: string): KxmConfigIssue {
36
36
  return { phase, code, file, message };
37
37
  }
38
38
 
39
39
  function migrateFail(code: string, file: string, message: string): never {
40
- throw new VnextConfigError([migrateIssue("parse", code, file, message)]);
40
+ throw new KxmConfigError([migrateIssue("parse", code, file, message)]);
41
41
  }
42
42
 
43
43
  /** JSON.parse with duplicate-key rejection and structural bounds. */
@@ -168,7 +168,7 @@ function detectDuplicateKeys(text: string, label: string): void {
168
168
  * Legacy source model
169
169
  * ------------------------------------------------------------------ */
170
170
 
171
- export interface VnextLegacySource {
171
+ export interface KxmLegacySource {
172
172
  path: string;
173
173
  sha256: string;
174
174
  bytes: number;
@@ -180,23 +180,23 @@ function sha256Of(input: string | Uint8Array): string {
180
180
  }
181
181
 
182
182
  /** Read every legacy configuration file with bounds and exact duplicate-key rejection. */
183
- export function readVnextLegacySources(root: string): VnextLegacySource[] {
183
+ export function readKxmLegacySources(root: string): KxmLegacySource[] {
184
184
  const files = legacyConfigFilesAt(root);
185
185
  if (files.length > MAX_LEGACY_SOURCES) {
186
- throw new VnextConfigError([migrateIssue("discovery", "legacy_source_limit", ".kxm/config", `legacy configuration exceeds ${MAX_LEGACY_SOURCES} files`)]);
186
+ throw new KxmConfigError([migrateIssue("discovery", "legacy_source_limit", ".kxm/config", `legacy configuration exceeds ${MAX_LEGACY_SOURCES} files`)]);
187
187
  }
188
188
  return files.map((path) => {
189
189
  const absolute = join(root, ...path.split("/"));
190
190
  const stat = lstatSync(absolute);
191
191
  if (stat.isSymbolicLink() || !stat.isFile()) {
192
- throw new VnextConfigError([migrateIssue("path", "legacy_source_invalid", path, "legacy configuration must be a regular file, not a link")]);
192
+ throw new KxmConfigError([migrateIssue("path", "legacy_source_invalid", path, "legacy configuration must be a regular file, not a link")]);
193
193
  }
194
194
  const buffer = readFileSync(absolute);
195
195
  let text: string;
196
196
  try {
197
197
  text = new TextDecoder("utf-8", { fatal: true }).decode(buffer);
198
198
  } catch {
199
- throw new VnextConfigError([migrateIssue("parse", "invalid_utf8", path, "document is not valid UTF-8")]);
199
+ throw new KxmConfigError([migrateIssue("parse", "invalid_utf8", path, "document is not valid UTF-8")]);
200
200
  }
201
201
  return {
202
202
  path,
@@ -207,8 +207,8 @@ export function readVnextLegacySources(root: string): VnextLegacySource[] {
207
207
  });
208
208
  }
209
209
 
210
- export function legacySourceDigest(sources: readonly VnextLegacySource[]): string {
211
- return sha256Of(vnextCanonicalJson(sources.map((source) => ({ path: source.path, sha256: source.sha256, bytes: source.bytes }))));
210
+ export function legacySourceDigest(sources: readonly KxmLegacySource[]): string {
211
+ return sha256Of(kxmCanonicalJson(sources.map((source) => ({ path: source.path, sha256: source.sha256, bytes: source.bytes }))));
212
212
  }
213
213
 
214
214
  /* ------------------------------------------------------------------ *
@@ -227,7 +227,7 @@ const KNOWN_STAGE_FIELDS = new Set(["id", "label", "instructions", "requiredEvid
227
227
  const KNOWN_POLICY_FIELDS = new Set(["kind", "minProducers", "eligibleAgents", "acceptedStatuses", "degradation"]);
228
228
  const KNOWN_TRANSITION_FIELDS = new Set(["target", "maxTransitions"]);
229
229
 
230
- export interface VnextMigrationAmbiguity {
230
+ export interface KxmMigrationAmbiguity {
231
231
  key: string;
232
232
  category: "unsupported" | "identity" | "step-kind" | "terminal-status" | "transition-budget" | "evidence-policy" | "permission" | "secret-reference";
233
233
  sourcePath: string;
@@ -235,20 +235,20 @@ export interface VnextMigrationAmbiguity {
235
235
  allowedValues: readonly (string | number)[];
236
236
  }
237
237
 
238
- export interface VnextMigrationUnmapped {
238
+ export interface KxmMigrationUnmapped {
239
239
  sourcePath: string;
240
240
  jsonPointer: string;
241
241
  valueSha256: string;
242
242
  sensitive: boolean;
243
243
  }
244
244
 
245
- export interface VnextMigrationRename {
245
+ export interface KxmMigrationRename {
246
246
  from: string;
247
247
  to: string;
248
248
  kind: "agent" | "model" | "workflow" | "step" | "evidence" | "outcome";
249
249
  }
250
250
 
251
- export interface VnextMigrationPermissionChange {
251
+ export interface KxmMigrationPermissionChange {
252
252
  sourcePath: string;
253
253
  targetPath: string;
254
254
  direction: "narrowing" | "expansion" | "unknown";
@@ -257,13 +257,13 @@ export interface VnextMigrationPermissionChange {
257
257
  }
258
258
 
259
259
  interface MutablePlan {
260
- ambiguities: VnextMigrationAmbiguity[];
260
+ ambiguities: KxmMigrationAmbiguity[];
261
261
  invalidDecisions: string[];
262
262
  decisionKeys: Set<string>;
263
263
  decisionAllowedValues: Map<string, readonly (string | number)[]>;
264
- unmapped: VnextMigrationUnmapped[];
265
- renames: VnextMigrationRename[];
266
- permissionChanges: VnextMigrationPermissionChange[];
264
+ unmapped: KxmMigrationUnmapped[];
265
+ renames: KxmMigrationRename[];
266
+ permissionChanges: KxmMigrationPermissionChange[];
267
267
  }
268
268
 
269
269
  function compareCodeUnits(left: string, right: string): number {
@@ -317,12 +317,12 @@ function recordUnmapped(plan: MutablePlan, sourcePath: string, pointer: string,
317
317
  // not be recoverable by offline guessing against a committed plan. Record
318
318
  // only the serialized byte length as proof something was dropped.
319
319
  const digestInput = sensitive
320
- ? { redacted: true, bytes: Buffer.byteLength(vnextCanonicalJson(value === undefined ? null : value), "utf8") }
320
+ ? { redacted: true, bytes: Buffer.byteLength(kxmCanonicalJson(value === undefined ? null : value), "utf8") }
321
321
  : (value === undefined ? null : value);
322
322
  plan.unmapped.push({
323
323
  sourcePath,
324
324
  jsonPointer: pointer,
325
- valueSha256: sha256Of(vnextCanonicalJson(digestInput)),
325
+ valueSha256: sha256Of(kxmCanonicalJson(digestInput)),
326
326
  sensitive,
327
327
  });
328
328
  }
@@ -348,7 +348,7 @@ function mapIdentity(
348
348
  plan: MutablePlan,
349
349
  sourcePath: string,
350
350
  raw: string,
351
- kind: VnextMigrationRename["kind"],
351
+ kind: KxmMigrationRename["kind"],
352
352
  taken: Map<string, string>,
353
353
  decisions: Readonly<Record<string, JsonValue>>,
354
354
  dropPointer?: string,
@@ -387,7 +387,7 @@ function mapIdentity(
387
387
  `identity:${kind}:${keyFragment(raw)}`,
388
388
  "identity",
389
389
  sourcePath,
390
- `${kind} name ${JSON.stringify(elide(raw, 200))} cannot be normalized to a vNext identifier; supply a decision with the target identifier`,
390
+ `${kind} name ${JSON.stringify(elide(raw, 200))} cannot be normalized to a KXM identifier; supply a decision with the target identifier`,
391
391
  ["<identifier>"],
392
392
  decisions,
393
393
  );
@@ -474,7 +474,7 @@ function decisionValueAllowed(key: string, value: JsonValue | undefined, allowed
474
474
  function resolveDecision(
475
475
  plan: MutablePlan,
476
476
  key: string,
477
- category: VnextMigrationAmbiguity["category"],
477
+ category: KxmMigrationAmbiguity["category"],
478
478
  sourcePath: string,
479
479
  message: string,
480
480
  allowedValues: readonly (string | number)[],
@@ -510,7 +510,7 @@ interface ConvertedAgents {
510
510
 
511
511
  function convertAgentsRoster(
512
512
  plan: MutablePlan,
513
- source: VnextLegacySource,
513
+ source: KxmLegacySource,
514
514
  decisions: Readonly<Record<string, JsonValue>>,
515
515
  agentNames: Map<string, string>,
516
516
  ): ConvertedAgents {
@@ -618,7 +618,7 @@ function convertAgentsRoster(
618
618
  }
619
619
  const thinking = asString(record.thinking);
620
620
  if (thinking) {
621
- // vNext agents select models; thinking belongs to a model profile. Emit
621
+ // KXM agents select models; thinking belongs to a model profile. Emit
622
622
  // a per-agent profile when the model mapped cleanly.
623
623
  const selector = asObject(agent.model as JsonValue | undefined);
624
624
  if (selector && typeof selector.profile !== "string") {
@@ -662,7 +662,7 @@ const IMPLEMENTED_GATES = new Set(["test", "scm-delivery"]);
662
662
 
663
663
  function convertGatesRoster(
664
664
  plan: MutablePlan,
665
- source: VnextLegacySource,
665
+ source: KxmLegacySource,
666
666
  decisions: Readonly<Record<string, JsonValue>>,
667
667
  ): void {
668
668
  const root = asObject(source.value);
@@ -696,7 +696,7 @@ function convertGatesRoster(
696
696
  `gate:${keyFragment(name)}`,
697
697
  "unsupported",
698
698
  source.path,
699
- `gate ${JSON.stringify(elide(name, 200))} has no registered deterministic runner in vNext; it is preserved in the migration report only`,
699
+ `gate ${JSON.stringify(elide(name, 200))} has no registered deterministic runner in KXM; it is preserved in the migration report only`,
700
700
  ["report-only"],
701
701
  decisions,
702
702
  );
@@ -721,7 +721,7 @@ function mapStageRef(context: StageContext, raw: string): string {
721
721
 
722
722
  function convertTransition(
723
723
  plan: MutablePlan,
724
- source: VnextLegacySource,
724
+ source: KxmLegacySource,
725
725
  context: StageContext,
726
726
  stageId: string,
727
727
  stageKey: string,
@@ -746,13 +746,13 @@ function convertTransition(
746
746
  const sourceIndex = context.stageIds.indexOf(stageId);
747
747
  if (target === "$terminal") {
748
748
  // Legacy $terminal always completes the run successfully regardless of
749
- // outcome; vNext requires an explicit terminal status.
749
+ // outcome; KXM requires an explicit terminal status.
750
750
  const chosen = resolveDecision(
751
751
  plan,
752
752
  `terminal:${context.workflowKey}:${stageKey}:${outcome}`,
753
753
  "terminal-status",
754
754
  source.path,
755
- `legacy transition ${context.workflowId}/${stageId} outcome ${outcome} ends the run; choose the vNext terminal status (legacy semantics completed the run even on failure outcomes)`,
755
+ `legacy transition ${context.workflowId}/${stageId} outcome ${outcome} ends the run; choose the KXM terminal status (legacy semantics completed the run even on failure outcomes)`,
756
756
  outcome === "passed" ? ["completed"] : ["completed", "failed", "cancelled"],
757
757
  decisions,
758
758
  );
@@ -803,7 +803,7 @@ function convertTransition(
803
803
  `backedge:${context.workflowKey}:${stageKey}:${outcome}`,
804
804
  "transition-budget",
805
805
  source.path,
806
- `back-edge ${context.workflowId}/${stageId} -> ${targetId} (outcome ${outcome}) has no per-edge budget in legacy; vNext requires maxTransitions (1-100)`,
806
+ `back-edge ${context.workflowId}/${stageId} -> ${targetId} (outcome ${outcome}) has no per-edge budget in legacy; KXM requires maxTransitions (1-100)`,
807
807
  [2, 3, 4, 5],
808
808
  decisions,
809
809
  );
@@ -816,7 +816,7 @@ function convertTransition(
816
816
 
817
817
  function convertWorkflowFile(
818
818
  plan: MutablePlan,
819
- source: VnextLegacySource,
819
+ source: KxmLegacySource,
820
820
  decisions: Readonly<Record<string, JsonValue>>,
821
821
  agentIds: ReadonlyMap<string, JsonObject>,
822
822
  agentRawNames: ReadonlyMap<string, string>,
@@ -847,7 +847,7 @@ function convertWorkflowFile(
847
847
  : `preview-${(normalizeIdentifier(rawId) || "unnamed").slice(0, 46).replace(/[-_]+$/u, "")}-${createHash("sha256").update(`${rawId}#${source.path}#${definitionIndex}`, "utf8").digest("hex").slice(0, 8)}`;
848
848
  const workflowKey = keyFragment(rawId);
849
849
 
850
- // Hub/webhook-specific fields have no vNext workflow equivalent; the
850
+ // Hub/webhook-specific fields have no KXM workflow equivalent; the
851
851
  // trigger surface is a later phase. Record them (secrets hashed).
852
852
  for (const field of ["source", "project", "event", "filter", "delivery", "ttlMs", "promptTemplate"] as const) {
853
853
  if (definition[field] !== undefined) recordUnmapped(plan, source.path, `${basePointer}/${field}`, definition[field], false);
@@ -860,7 +860,7 @@ function convertWorkflowFile(
860
860
  `secret:${workflowKey}:${field}`,
861
861
  "secret-reference",
862
862
  source.path,
863
- `workflow ${workflowId} field ${field} configures a webhook secret; vNext workflows never embed secrets — confirm the field is dropped and re-granted through scoped secret references when the trigger surface lands`,
863
+ `workflow ${workflowId} field ${field} configures a webhook secret; KXM workflows never embed secrets — confirm the field is dropped and re-granted through scoped secret references when the trigger surface lands`,
864
864
  ["drop"],
865
865
  decisions,
866
866
  );
@@ -986,7 +986,7 @@ function convertWorkflowFile(
986
986
  `instructions:${workflowKey}:${stepKey}`,
987
987
  "unsupported",
988
988
  source.path,
989
- `stage ${stepId} has no instructions; vNext agent steps require executable instructions — confirm the stage is dropped`,
989
+ `stage ${stepId} has no instructions; KXM agent steps require executable instructions — confirm the stage is dropped`,
990
990
  ["drop"],
991
991
  decisions,
992
992
  );
@@ -1161,8 +1161,8 @@ function convertWorkflowFile(
1161
1161
  "evidence-policy",
1162
1162
  source.path,
1163
1163
  acceptedStatusesMalformed
1164
- ? `evidence policy ${policyKey} acceptedStatuses is malformed (not an array) and was preserved in the report; confirm mapping the policy to vNext 'passed'`
1165
- : `evidence policy ${policyKey} accepted statuses ${JSON.stringify(elide(accepted.map((candidate) => String(candidate)).join(","), 200))} cannot map losslessly; confirm mapping to vNext 'passed'`,
1164
+ ? `evidence policy ${policyKey} acceptedStatuses is malformed (not an array) and was preserved in the report; confirm mapping the policy to KXM 'passed'`
1165
+ : `evidence policy ${policyKey} accepted statuses ${JSON.stringify(elide(accepted.map((candidate) => String(candidate)).join(","), 200))} cannot map losslessly; confirm mapping to KXM 'passed'`,
1166
1166
  ["passed"],
1167
1167
  decisions,
1168
1168
  );
@@ -1183,7 +1183,7 @@ function convertWorkflowFile(
1183
1183
  sourcePath: source.path,
1184
1184
  targetPath: `.kxm/workflows/${workflowId}.yaml`,
1185
1185
  direction: "expansion",
1186
- summary: `step ${stepId}: assignment pool widens from the single legacy coordinator to coordinator plus evidence producers so vNext producer evidence stays in scope`,
1186
+ summary: `step ${stepId}: assignment pool widens from the single legacy coordinator to coordinator plus evidence producers so KXM producer evidence stays in scope`,
1187
1187
  decisionKey: `evidence:${workflowKey}:${stepKey}:${policyKey}`,
1188
1188
  });
1189
1189
  resolveDecision(
@@ -1223,7 +1223,7 @@ function convertWorkflowFile(
1223
1223
  }
1224
1224
  if (requiredEvidence.length > 0) step.requiredEvidence = requiredEvidence;
1225
1225
  if (policyProducers.size > 0) {
1226
- // vNext evidence producers must execute within the step assignment
1226
+ // KXM evidence producers must execute within the step assignment
1227
1227
  // pool: widen it beyond the legacy single-coordinator shape.
1228
1228
  const pool = [stepAgent, ...[...policyProducers].filter((candidate) => candidate !== stepAgent).sort(compareCodeUnits)];
1229
1229
  step.assignments = {
@@ -1246,7 +1246,7 @@ function convertWorkflowFile(
1246
1246
  continue;
1247
1247
  }
1248
1248
  if (seenOutcomes.has(outcome)) {
1249
- // Two legacy outcome keys normalize to the same vNext outcome;
1249
+ // Two legacy outcome keys normalize to the same KXM outcome;
1250
1250
  // never merge their edges last-wins.
1251
1251
  recordUnmapped(plan, source.path, `${pointer}/on/${pointerEscape(rawOutcome)}`, rawTransition, false);
1252
1252
  continue;
@@ -1270,7 +1270,7 @@ function convertWorkflowFile(
1270
1270
  }
1271
1271
  step.on = transitions;
1272
1272
  if (typeof stage.maxTransitions === "number") {
1273
- // Legacy per-stage transition budgets have no vNext equivalent;
1273
+ // Legacy per-stage transition budgets have no KXM equivalent;
1274
1274
  // per-edge budgets and the global limit cover the same bound.
1275
1275
  recordUnmapped(plan, source.path, `${pointer}/maxTransitions`, stage.maxTransitions, false);
1276
1276
  }
@@ -1302,7 +1302,7 @@ function convertWorkflowFile(
1302
1302
  recordUnmapped(plan, source.path, `${basePointer}/maxTransitions`, definition.maxTransitions, false);
1303
1303
  }
1304
1304
  if (workflow.limits === undefined) {
1305
- // vNext requires a global budget whenever any back-edge exists.
1305
+ // KXM requires a global budget whenever any back-edge exists.
1306
1306
  const hasBackEdge = steps.some((step) => Object.values(asObject(step.on as JsonValue) ?? {}).some((rule) => {
1307
1307
  const target = typeof rule === "string" ? rule : asObject(rule)?.target;
1308
1308
  return typeof target === "string" && target !== "$terminal" && stageIds.indexOf(target) <= stageIds.indexOf(String(step.id));
@@ -1313,7 +1313,7 @@ function convertWorkflowFile(
1313
1313
  `budget:${workflowKey}`,
1314
1314
  "transition-budget",
1315
1315
  source.path,
1316
- `workflow ${workflowId} has back-edges but no legacy global maxTransitions; vNext requires limits.maxTransitions (1-1000)`,
1316
+ `workflow ${workflowId} has back-edges but no legacy global maxTransitions; KXM requires limits.maxTransitions (1-1000)`,
1317
1317
  [28],
1318
1318
  decisions,
1319
1319
  );
@@ -1368,18 +1368,18 @@ function convertWorkflowFile(
1368
1368
 
1369
1369
  /* ------------------------- plan assembly -------------------------- */
1370
1370
 
1371
- export interface VnextMigrationPlanResult {
1371
+ export interface KxmMigrationPlanResult {
1372
1372
  plan: JsonObject;
1373
1373
  resources: Map<string, JsonObject>;
1374
- ambiguities: readonly VnextMigrationAmbiguity[];
1374
+ ambiguities: readonly KxmMigrationAmbiguity[];
1375
1375
  decisionKeys: ReadonlySet<string>;
1376
1376
  decisionAllowedValues: ReadonlyMap<string, readonly (string | number)[]>;
1377
1377
  invalidDecisions: readonly string[];
1378
1378
  decisions: Readonly<Record<string, JsonValue>>;
1379
- sources: readonly VnextLegacySource[];
1379
+ sources: readonly KxmLegacySource[];
1380
1380
  }
1381
1381
 
1382
- export interface VnextMigrationOptions extends VnextConfigOptions {
1382
+ export interface KxmMigrationOptions extends KxmConfigOptions {
1383
1383
  decisions?: Readonly<Record<string, JsonValue>>;
1384
1384
  projectId?: string;
1385
1385
  projectName?: string;
@@ -1395,18 +1395,18 @@ function sortedRecord<T>(map: ReadonlyMap<string, T>, prefix: string): Map<strin
1395
1395
  function migrationGitRoot(start: string): string {
1396
1396
  const root = discoverGitRoot(start);
1397
1397
  if (!root) {
1398
- throw new VnextConfigError([migrateIssue("discovery", "git_root_required", ".", "kxm migrate must run inside the authoritative Git worktree")]);
1398
+ throw new KxmConfigError([migrateIssue("discovery", "git_root_required", ".", "kxm migrate must run inside the authoritative Git worktree")]);
1399
1399
  }
1400
1400
  return root;
1401
1401
  }
1402
1402
 
1403
1403
  /** Convert legacy configuration into a deterministic, schema-shaped migration plan. */
1404
- export function planVnextMigration(projectRoot: string, options: VnextMigrationOptions = {}): VnextMigrationPlanResult {
1404
+ export function planKxmMigration(projectRoot: string, options: KxmMigrationOptions = {}): KxmMigrationPlanResult {
1405
1405
  const root = migrationGitRoot(projectRoot);
1406
- const registry = new VnextSchemaRegistry(options.schemasDir);
1407
- const sources = readVnextLegacySources(root);
1406
+ const registry = new KxmSchemaRegistry(options.schemasDir);
1407
+ const sources = readKxmLegacySources(root);
1408
1408
  if (sources.length === 0) {
1409
- throw new VnextConfigError([migrateIssue("discovery", "legacy_sources_missing", ".kxm/config", "no legacy configuration files found to migrate")]);
1409
+ throw new KxmConfigError([migrateIssue("discovery", "legacy_sources_missing", ".kxm/config", "no legacy configuration files found to migrate")]);
1410
1410
  }
1411
1411
  const decisions = options.decisions ?? {};
1412
1412
  const plan: MutablePlan = { ambiguities: [], invalidDecisions: [], decisionKeys: new Set(), decisionAllowedValues: new Map(), unmapped: [], renames: [], permissionChanges: [] };
@@ -1449,11 +1449,11 @@ export function planVnextMigration(projectRoot: string, options: VnextMigrationO
1449
1449
 
1450
1450
  const projectId = options.projectId ?? `prj_mig${sha256Of(legacySourceDigest(sources)).slice(7, 39)}`;
1451
1451
  if (!PROJECT_ID.test(projectId)) {
1452
- throw new VnextConfigError([migrateIssue("semantic", "project_id_invalid", ".kxm/project.yaml", "project ID must satisfy the kxm.project.v1 opaque ID grammar and use the prj_ prefix")]);
1452
+ throw new KxmConfigError([migrateIssue("semantic", "project_id_invalid", ".kxm/project.yaml", "project ID must satisfy the kxm.project.v1 opaque ID grammar and use the prj_ prefix")]);
1453
1453
  }
1454
1454
  const projectName = options.projectName ?? "Migrated legacy project";
1455
1455
  if (projectName.length < 1 || projectName.length > 120 || /[\u0000\r\n]/.test(projectName)) {
1456
- throw new VnextConfigError([migrateIssue("semantic", "project_name_invalid", ".kxm/project.yaml", "project name must contain 1-120 characters on one line")]);
1456
+ throw new KxmConfigError([migrateIssue("semantic", "project_name_invalid", ".kxm/project.yaml", "project name must contain 1-120 characters on one line")]);
1457
1457
  }
1458
1458
 
1459
1459
  const resources = new Map<string, JsonObject>();
@@ -1484,8 +1484,8 @@ export function planVnextMigration(projectRoot: string, options: VnextMigrationO
1484
1484
 
1485
1485
  // Validate every converted resource against its exact schema before the
1486
1486
  // plan is considered applicable.
1487
- const schemaIssues: VnextConfigIssue[] = [];
1488
- const kindOf = (path: string): VnextResourceKind => path === ".kxm/project.yaml" ? "project"
1487
+ const schemaIssues: KxmConfigIssue[] = [];
1488
+ const kindOf = (path: string): KxmResourceKind => path === ".kxm/project.yaml" ? "project"
1489
1489
  : path.endsWith("repo.yaml") ? "repository"
1490
1490
  : path.startsWith(".kxm/agents/") ? "agent"
1491
1491
  : path.startsWith(".kxm/models/") ? "model"
@@ -1493,14 +1493,14 @@ export function planVnextMigration(projectRoot: string, options: VnextMigrationO
1493
1493
  const idOf = (path: string): string | undefined => path === ".kxm/project.yaml" || path.endsWith("repo.yaml")
1494
1494
  ? undefined
1495
1495
  : path.slice(path.lastIndexOf("/") + 1, -".yaml".length);
1496
- const semanticResources = new Map<string, { kind: VnextResourceKind; id?: string; value: JsonObject }>();
1496
+ const semanticResources = new Map<string, { kind: KxmResourceKind; id?: string; value: JsonObject }>();
1497
1497
  for (const [path, value] of [...resources.entries()].sort(([left], [right]) => compareCodeUnits(left, right))) {
1498
1498
  const kind = kindOf(path);
1499
1499
  schemaIssues.push(...registry.validate(kind, value, path));
1500
1500
  const id = idOf(path);
1501
1501
  semanticResources.set(path, kind === "repository" ? { kind, id: "control", value } : { kind, ...(id === undefined ? {} : { id }), value });
1502
1502
  }
1503
- if (schemaIssues.length > 0) throw new VnextConfigError(schemaIssues);
1503
+ if (schemaIssues.length > 0) throw new KxmConfigError(schemaIssues);
1504
1504
  // Full semantic validation gates a resolved plan: while ambiguities remain,
1505
1505
  // the intermediate resource set may legitimately be incomplete (for example
1506
1506
  // a workflow whose coordinator decision is still pending), and the operator
@@ -1508,8 +1508,8 @@ export function planVnextMigration(projectRoot: string, options: VnextMigrationO
1508
1508
  // Apply always re-plans and requires zero ambiguities, so this check still
1509
1509
  // runs before any write.
1510
1510
  if (plan.ambiguities.length === 0) {
1511
- const semanticIssues = validateVnextResources(semanticResources, options);
1512
- if (semanticIssues.length > 0) throw new VnextConfigError(semanticIssues);
1511
+ const semanticIssues = validateKxmResources(semanticResources, options);
1512
+ if (semanticIssues.length > 0) throw new KxmConfigError(semanticIssues);
1513
1513
  }
1514
1514
 
1515
1515
  const planRecord: JsonObject = {
@@ -1537,7 +1537,7 @@ export function planVnextMigration(projectRoot: string, options: VnextMigrationO
1537
1537
  canApply: plan.ambiguities.length === 0,
1538
1538
  };
1539
1539
  const planIssues = registry.validateMigrationPlan(planRecord, "kxm.migration-plan.v1");
1540
- if (planIssues.length > 0) throw new VnextConfigError(planIssues);
1540
+ if (planIssues.length > 0) throw new KxmConfigError(planIssues);
1541
1541
 
1542
1542
  return {
1543
1543
  plan: planRecord,
@@ -1553,14 +1553,14 @@ export function planVnextMigration(projectRoot: string, options: VnextMigrationO
1553
1553
 
1554
1554
  /* ------------------------- decisions file -------------------------- */
1555
1555
 
1556
- export function readVnextMigrationDecisions(path: string, schemasDir?: string): JsonObject {
1556
+ export function readKxmMigrationDecisions(path: string, schemasDir?: string): JsonObject {
1557
1557
  if (!existsSync(path)) {
1558
- throw new VnextConfigError([migrateIssue("discovery", "decisions_missing", path, "migration decisions file does not exist")]);
1558
+ throw new KxmConfigError([migrateIssue("discovery", "decisions_missing", path, "migration decisions file does not exist")]);
1559
1559
  }
1560
- const registry = new VnextSchemaRegistry(schemasDir);
1560
+ const registry = new KxmSchemaRegistry(schemasDir);
1561
1561
  const value = parseRestrictedYaml(readFileSync(path), path);
1562
1562
  const issues = registry.validateMigrationDecision(value, path);
1563
- if (issues.length > 0) throw new VnextConfigError(issues);
1563
+ if (issues.length > 0) throw new KxmConfigError(issues);
1564
1564
  return value;
1565
1565
  }
1566
1566
 
@@ -1572,7 +1572,7 @@ function resolutionsOf(decisions: JsonObject): Record<string, JsonValue> {
1572
1572
 
1573
1573
  /* ------------------------- apply / verify -------------------------- */
1574
1574
 
1575
- export interface VnextMigrationApplyResult {
1575
+ export interface KxmMigrationApplyResult {
1576
1576
  action: "applied" | "planned" | "already-migrated";
1577
1577
  projectRoot: string;
1578
1578
  receiptPath?: string;
@@ -1581,7 +1581,7 @@ export interface VnextMigrationApplyResult {
1581
1581
  plan?: JsonObject;
1582
1582
  }
1583
1583
 
1584
- export interface VnextMigrationApplyOptions extends VnextMigrationOptions {
1584
+ export interface KxmMigrationApplyOptions extends KxmMigrationOptions {
1585
1585
  dryRun?: boolean;
1586
1586
  decisionsFile?: string;
1587
1587
  localStateRoot?: string;
@@ -1621,34 +1621,34 @@ function writeDurable(path: string, content: Buffer): void {
1621
1621
  }
1622
1622
 
1623
1623
  /** Apply a reviewed migration: stage, validate the complete target, install, and receipt. */
1624
- export function applyVnextMigration(projectRoot: string, options: VnextMigrationApplyOptions = {}): VnextMigrationApplyResult {
1624
+ export function applyKxmMigration(projectRoot: string, options: KxmMigrationApplyOptions = {}): KxmMigrationApplyResult {
1625
1625
  const root = migrationGitRoot(projectRoot);
1626
- const storeOptions: VnextLocalBindingStoreOptions = {
1626
+ const storeOptions: KxmLocalBindingStoreOptions = {
1627
1627
  ...(options.localStateRoot === undefined ? {} : { stateRoot: options.localStateRoot }),
1628
1628
  ...(options.schemasDir === undefined ? {} : { schemasDir: options.schemasDir }),
1629
1629
  };
1630
1630
 
1631
- const execute = (lock: VnextLocalBindingLock | undefined): VnextMigrationApplyResult => {
1632
- const receiptAbsolute = join(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
1631
+ const execute = (lock: KxmLocalBindingLock | undefined): KxmMigrationApplyResult => {
1632
+ const receiptAbsolute = join(root, ...KXM_MIGRATION_RECEIPT_PATH.split("/"));
1633
1633
  // Already-migrated detection precedes planning and decision checks: a
1634
1634
  // validated receipt makes re-apply an idempotent no-op even when legacy
1635
1635
  // sources were later removed or no decisions are supplied.
1636
1636
  if (existsSync(receiptAbsolute)) {
1637
1637
  const stat = lstatSync(receiptAbsolute);
1638
1638
  if (stat.isSymbolicLink() || !stat.isFile()) {
1639
- throw new VnextConfigError([migrateIssue("path", "migration_receipt_invalid", VNEXT_MIGRATION_RECEIPT_PATH, "migration receipt must be a regular file, not a link")]);
1639
+ throw new KxmConfigError([migrateIssue("path", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "migration receipt must be a regular file, not a link")]);
1640
1640
  }
1641
- const existing = loadVnextProject(root, options);
1641
+ const existing = loadKxmProject(root, options);
1642
1642
  return {
1643
1643
  action: "already-migrated",
1644
1644
  projectRoot: root,
1645
- receiptPath: VNEXT_MIGRATION_RECEIPT_PATH,
1645
+ receiptPath: KXM_MIGRATION_RECEIPT_PATH,
1646
1646
  configRevision: existing.configRevision,
1647
1647
  files: [],
1648
1648
  };
1649
1649
  }
1650
1650
 
1651
- const decisionsRecord = options.decisionsFile ? readVnextMigrationDecisions(options.decisionsFile, options.schemasDir) : undefined;
1651
+ const decisionsRecord = options.decisionsFile ? readKxmMigrationDecisions(options.decisionsFile, options.schemasDir) : undefined;
1652
1652
  const decisions = decisionsRecord ? resolutionsOf(decisionsRecord) : (options.decisions ?? {});
1653
1653
  // Plan once with the real decisions: resolveDecision validates every
1654
1654
  // supplied value inline, so an invalid value can never masquerade as a
@@ -1656,16 +1656,16 @@ export function applyVnextMigration(projectRoot: string, options: VnextMigration
1656
1656
  // universe the operator reviewed; decision keys are accepted from the
1657
1657
  // union of both plans because binding decisions (coordinator, identities)
1658
1658
  // can make plan-1 keys unnecessary without invalidating the review.
1659
- const first = planVnextMigration(root, { ...options, decisions });
1659
+ const first = planKxmMigration(root, { ...options, decisions });
1660
1660
  if (decisionsRecord) {
1661
1661
  if (decisionsRecord.projectId !== first.plan.projectId) {
1662
- throw new VnextConfigError([migrateIssue("semantic", "decision_project_mismatch", options.decisionsFile ?? "<decisions>", "decisions file projectId does not match the recomputed plan")]);
1662
+ throw new KxmConfigError([migrateIssue("semantic", "decision_project_mismatch", options.decisionsFile ?? "<decisions>", "decisions file projectId does not match the recomputed plan")]);
1663
1663
  }
1664
1664
  if (decisionsRecord.projectName !== first.plan.projectName) {
1665
- throw new VnextConfigError([migrateIssue("semantic", "decision_project_mismatch", options.decisionsFile ?? "<decisions>", "decisions file projectName does not match the recomputed plan")]);
1665
+ throw new KxmConfigError([migrateIssue("semantic", "decision_project_mismatch", options.decisionsFile ?? "<decisions>", "decisions file projectName does not match the recomputed plan")]);
1666
1666
  }
1667
1667
  if (decisionsRecord.sourceDigest !== first.plan.sourceDigest) {
1668
- throw new VnextConfigError([migrateIssue("semantic", "decision_source_changed", options.decisionsFile ?? "<decisions>", "legacy sources changed after the decisions file was reviewed")]);
1668
+ throw new KxmConfigError([migrateIssue("semantic", "decision_source_changed", options.decisionsFile ?? "<decisions>", "legacy sources changed after the decisions file was reviewed")]);
1669
1669
  }
1670
1670
  }
1671
1671
  if (Object.keys(decisions).length > 0) {
@@ -1674,7 +1674,7 @@ export function applyVnextMigration(projectRoot: string, options: VnextMigration
1674
1674
  // e.g. a coordinator choice superseded by a raw-name binding) are
1675
1675
  // validated against the universe's allowed values here. Anything else
1676
1676
  // was never part of any review.
1677
- const universe = planVnextMigration(root, { ...options, decisions: {} });
1677
+ const universe = planKxmMigration(root, { ...options, decisions: {} });
1678
1678
  const unknown: string[] = [];
1679
1679
  const invalid: string[] = [];
1680
1680
  for (const [key, value] of Object.entries(decisions)) {
@@ -1687,11 +1687,11 @@ export function applyVnextMigration(projectRoot: string, options: VnextMigration
1687
1687
  }
1688
1688
  }
1689
1689
  if (unknown.length > 0) {
1690
- throw new VnextConfigError(unknown.sort(compareCodeUnits).map((key) => migrateIssue("semantic", "decision_unknown", key, "decision key does not match any current ambiguity")));
1690
+ throw new KxmConfigError(unknown.sort(compareCodeUnits).map((key) => migrateIssue("semantic", "decision_unknown", key, "decision key does not match any current ambiguity")));
1691
1691
  }
1692
1692
  const allInvalid = [...new Set([...invalid, ...first.invalidDecisions])].sort(compareCodeUnits);
1693
1693
  if (allInvalid.length > 0) {
1694
- throw new VnextConfigError(allInvalid.map((key) => migrateIssue("semantic", "decision_value_invalid", key, "decision value is not one of the plan's allowed values")));
1694
+ throw new KxmConfigError(allInvalid.map((key) => migrateIssue("semantic", "decision_value_invalid", key, "decision value is not one of the plan's allowed values")));
1695
1695
  }
1696
1696
  }
1697
1697
  if (first.ambiguities.length > 0) {
@@ -1700,14 +1700,14 @@ export function applyVnextMigration(projectRoot: string, options: VnextMigration
1700
1700
 
1701
1701
  const files = [...first.resources.entries()].sort(([left], [right]) => compareCodeUnits(left, right))
1702
1702
  .map(([path, value]) => ({ path, bytes: Buffer.from(stringify(value, { lineWidth: 0 }), "utf8") }));
1703
- // Refuse to overwrite any existing vNext state or legacy inputs.
1703
+ // Refuse to overwrite any existing KXM state or legacy inputs.
1704
1704
  const collisions = files.filter((file) => existsSync(join(root, ...file.path.split("/"))));
1705
1705
  if (collisions.length > 0) {
1706
- throw new VnextConfigError(collisions.map((file) => migrateIssue("semantic", "migration_target_exists", file.path, "target resource already exists; refusing to overwrite")));
1706
+ throw new KxmConfigError(collisions.map((file) => migrateIssue("semantic", "migration_target_exists", file.path, "target resource already exists; refusing to overwrite")));
1707
1707
  }
1708
1708
  // Never write through a linked or non-directory parent component: walk
1709
1709
  // every target parent from the project root before the first write.
1710
- const parentIssues: VnextConfigIssue[] = [];
1710
+ const parentIssues: KxmConfigIssue[] = [];
1711
1711
  for (const file of files) {
1712
1712
  const segments = file.path.split("/");
1713
1713
  let current = root;
@@ -1721,7 +1721,7 @@ export function applyVnextMigration(projectRoot: string, options: VnextMigration
1721
1721
  }
1722
1722
  }
1723
1723
  }
1724
- if (parentIssues.length > 0) throw new VnextConfigError(parentIssues);
1724
+ if (parentIssues.length > 0) throw new KxmConfigError(parentIssues);
1725
1725
 
1726
1726
  if (options.dryRun) {
1727
1727
  // Preflight is complete (decisions, collisions, linked parents); a
@@ -1741,29 +1741,29 @@ export function applyVnextMigration(projectRoot: string, options: VnextMigration
1741
1741
  writeDurable(absolute, file.bytes);
1742
1742
  }
1743
1743
  // Validate the complete installed bundle before issuing the receipt.
1744
- const bundle = loadVnextProject(root, { ...options, allowUnreceiptedLegacyConfig: true });
1744
+ const bundle = loadKxmProject(root, { ...options, allowUnreceiptedLegacyConfig: true });
1745
1745
  const receipt: JsonObject = {
1746
1746
  schema: "kxm.migration-receipt.v1",
1747
1747
  migrationId: `mig_${sha256Of(`${first.plan.sourceDigest}\n${bundle.configRevision}`).slice(7, 39)}`,
1748
1748
  projectId: String(first.plan.projectId),
1749
1749
  sourceDigest: String(first.plan.sourceDigest),
1750
- decisionDigest: sha256Of(vnextCanonicalJson((decisionsRecord ?? { schema: "kxm.migration-decision.v1", projectId: first.plan.projectId, projectName: first.plan.projectName, sourceDigest: first.plan.sourceDigest, resolutions: decisions }) as JsonObject)),
1750
+ decisionDigest: sha256Of(kxmCanonicalJson((decisionsRecord ?? { schema: "kxm.migration-decision.v1", projectId: first.plan.projectId, projectName: first.plan.projectName, sourceDigest: first.plan.sourceDigest, resolutions: decisions }) as JsonObject)),
1751
1751
  configRevision: bundle.configRevision,
1752
1752
  sources: first.plan.sources as JsonValue,
1753
1753
  resources: files.map((file) => ({ path: file.path, sha256: sha256Of(file.bytes), bytes: file.bytes.byteLength })),
1754
1754
  };
1755
1755
  receipt.receiptSha256 = migrationReceiptSelfHash(receipt);
1756
- const registry = new VnextSchemaRegistry(options.schemasDir);
1757
- const receiptIssues = registry.validateMigrationReceipt(receipt, VNEXT_MIGRATION_RECEIPT_PATH);
1758
- if (receiptIssues.length > 0) throw new VnextConfigError(receiptIssues);
1756
+ const registry = new KxmSchemaRegistry(options.schemasDir);
1757
+ const receiptIssues = registry.validateMigrationReceipt(receipt, KXM_MIGRATION_RECEIPT_PATH);
1758
+ if (receiptIssues.length > 0) throw new KxmConfigError(receiptIssues);
1759
1759
  written.push(receiptAbsolute);
1760
1760
  writeDurable(receiptAbsolute, Buffer.from(stringify(receipt, { lineWidth: 0 }), "utf8"));
1761
1761
  // The receipt must make the mixed tree loadable.
1762
- const verified = loadVnextProject(root, options);
1762
+ const verified = loadKxmProject(root, options);
1763
1763
  return {
1764
1764
  action: "applied",
1765
1765
  projectRoot: root,
1766
- receiptPath: VNEXT_MIGRATION_RECEIPT_PATH,
1766
+ receiptPath: KXM_MIGRATION_RECEIPT_PATH,
1767
1767
  configRevision: verified.configRevision,
1768
1768
  files: files.map((file) => file.path),
1769
1769
  plan: first.plan,
@@ -1780,67 +1780,67 @@ export function applyVnextMigration(projectRoot: string, options: VnextMigration
1780
1780
  };
1781
1781
 
1782
1782
  if (options.dryRun) return execute(undefined);
1783
- return withVnextLocalBindingLock(root, storeOptions, (lock) => execute(lock));
1783
+ return withKxmLocalBindingLock(root, storeOptions, (lock) => execute(lock));
1784
1784
  }
1785
1785
 
1786
1786
  /* ------------------------- verify ---------------------------------- */
1787
1787
 
1788
- export interface VnextMigrationVerifyResult {
1788
+ export interface KxmMigrationVerifyResult {
1789
1789
  ok: boolean;
1790
1790
  projectRoot: string;
1791
1791
  receiptPath: string;
1792
1792
  configRevision?: string;
1793
- issues: readonly VnextConfigIssue[];
1793
+ issues: readonly KxmConfigIssue[];
1794
1794
  }
1795
1795
 
1796
1796
  /** Re-check a migration receipt against current legacy sources and the target bundle. No writes. */
1797
- export function verifyVnextMigration(projectRoot: string, options: VnextConfigOptions = {}): VnextMigrationVerifyResult {
1797
+ export function verifyKxmMigration(projectRoot: string, options: KxmConfigOptions = {}): KxmMigrationVerifyResult {
1798
1798
  const root = migrationGitRoot(projectRoot);
1799
- const receiptAbsolute = join(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
1799
+ const receiptAbsolute = join(root, ...KXM_MIGRATION_RECEIPT_PATH.split("/"));
1800
1800
  if (!existsSync(receiptAbsolute)) {
1801
1801
  return {
1802
1802
  ok: false,
1803
1803
  projectRoot: root,
1804
- receiptPath: VNEXT_MIGRATION_RECEIPT_PATH,
1805
- issues: [migrateIssue("discovery", "migration_receipt_missing", VNEXT_MIGRATION_RECEIPT_PATH, "no migration receipt exists")],
1804
+ receiptPath: KXM_MIGRATION_RECEIPT_PATH,
1805
+ issues: [migrateIssue("discovery", "migration_receipt_missing", KXM_MIGRATION_RECEIPT_PATH, "no migration receipt exists")],
1806
1806
  };
1807
1807
  }
1808
1808
  try {
1809
- const bundle = loadVnextProject(root, options);
1809
+ const bundle = loadKxmProject(root, options);
1810
1810
  const receipt = bundle.migrationReceipt;
1811
1811
  if (!receipt) {
1812
1812
  if (legacyConfigFilesAt(root).length === 0) {
1813
1813
  // Every legacy source was removed after migration: the receipt was
1814
- // never consulted at load. Read it directly; readVnextMigrationReceipt
1814
+ // never consulted at load. Read it directly; readKxmMigrationReceipt
1815
1815
  // surfaces one migration_source_missing issue per declared source.
1816
- const direct = readVnextMigrationReceipt(root, options);
1816
+ const direct = readKxmMigrationReceipt(root, options);
1817
1817
  return {
1818
1818
  ok: false,
1819
1819
  projectRoot: root,
1820
- receiptPath: VNEXT_MIGRATION_RECEIPT_PATH,
1820
+ receiptPath: KXM_MIGRATION_RECEIPT_PATH,
1821
1821
  configRevision: bundle.configRevision,
1822
- issues: direct.issues.length > 0 ? direct.issues : [migrateIssue("semantic", "migration_receipt_invalid", VNEXT_MIGRATION_RECEIPT_PATH, "receipt did not validate")],
1822
+ issues: direct.issues.length > 0 ? direct.issues : [migrateIssue("semantic", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "receipt did not validate")],
1823
1823
  };
1824
1824
  }
1825
1825
  return {
1826
1826
  ok: false,
1827
1827
  projectRoot: root,
1828
- receiptPath: VNEXT_MIGRATION_RECEIPT_PATH,
1828
+ receiptPath: KXM_MIGRATION_RECEIPT_PATH,
1829
1829
  configRevision: bundle.configRevision,
1830
- issues: [migrateIssue("semantic", "migration_receipt_invalid", VNEXT_MIGRATION_RECEIPT_PATH, "receipt did not validate during project load")],
1830
+ issues: [migrateIssue("semantic", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "receipt did not validate during project load")],
1831
1831
  };
1832
1832
  }
1833
- const targetIssues = verifyVnextMigrationReceiptTarget(root, receipt, bundle.resources, bundle.configRevision);
1833
+ const targetIssues = verifyKxmMigrationReceiptTarget(root, receipt, bundle.resources, bundle.configRevision);
1834
1834
  return {
1835
1835
  ok: targetIssues.length === 0,
1836
1836
  projectRoot: root,
1837
- receiptPath: VNEXT_MIGRATION_RECEIPT_PATH,
1837
+ receiptPath: KXM_MIGRATION_RECEIPT_PATH,
1838
1838
  configRevision: bundle.configRevision,
1839
1839
  issues: targetIssues,
1840
1840
  };
1841
1841
  } catch (error) {
1842
- if (error instanceof VnextConfigError) {
1843
- return { ok: false, projectRoot: root, receiptPath: VNEXT_MIGRATION_RECEIPT_PATH, issues: error.issues };
1842
+ if (error instanceof KxmConfigError) {
1843
+ return { ok: false, projectRoot: root, receiptPath: KXM_MIGRATION_RECEIPT_PATH, issues: error.issues };
1844
1844
  }
1845
1845
  throw error;
1846
1846
  }