@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
@@ -5,65 +5,65 @@ import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep }
5
5
  import { Ajv2020, type ErrorObject, type ValidateFunction } from "ajv/dist/2020.js";
6
6
  import {
7
7
  RestrictedYamlError,
8
- VNEXT_YAML_LIMITS,
8
+ KXM_YAML_LIMITS,
9
9
  parseRestrictedYaml as parseRestrictedYamlShared,
10
- type VnextYamlLimits,
10
+ type KxmYamlLimits,
11
11
  } from "./restricted-yaml.mjs";
12
- import { resolveVnextTemplateBaseline } from "./vnext-template.ts";
12
+ import { resolveKxmTemplateBaseline } from "./template.ts";
13
13
  import { findKxmRepoRoot } from "./repo-root.ts";
14
- import { BUILTIN_HARNESS_IDS, DEFAULT_HARNESS, validateHarnessModelPair } from "./vnext-harness.ts";
14
+ import { BUILTIN_HARNESS_IDS, DEFAULT_HARNESS, validateHarnessModelPair } from "./harness.ts";
15
15
 
16
16
  export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue };
17
17
  export type JsonObject = { [key: string]: JsonValue };
18
- export type { VnextYamlLimits };
19
- export { VNEXT_YAML_LIMITS };
18
+ export type { KxmYamlLimits };
19
+ export { KXM_YAML_LIMITS };
20
20
 
21
- export type VnextValidationPhase = "discovery" | "parse" | "schema" | "path" | "reference" | "semantic";
21
+ export type KxmValidationPhase = "discovery" | "parse" | "schema" | "path" | "reference" | "semantic";
22
22
 
23
- export interface VnextConfigIssue {
24
- phase: VnextValidationPhase;
23
+ export interface KxmConfigIssue {
24
+ phase: KxmValidationPhase;
25
25
  code: string;
26
26
  file: string;
27
27
  message: string;
28
28
  }
29
29
 
30
- export class VnextConfigError extends Error {
31
- readonly issues: readonly VnextConfigIssue[];
30
+ export class KxmConfigError extends Error {
31
+ readonly issues: readonly KxmConfigIssue[];
32
32
 
33
- constructor(issues: readonly VnextConfigIssue[]) {
33
+ constructor(issues: readonly KxmConfigIssue[]) {
34
34
  const sorted = sortIssues(issues);
35
35
  super(sorted.map((issue) => `${issue.file}: ${issue.code}: ${issue.message}`).join("\n"));
36
- this.name = "VnextConfigError";
36
+ this.name = "KxmConfigError";
37
37
  this.issues = sorted;
38
38
  }
39
39
  }
40
40
 
41
- export type VnextResourceKind = "project" | "repository" | "agent" | "model" | "environment" | "workflow" | "gate-registry";
41
+ export type KxmResourceKind = "project" | "repository" | "agent" | "model" | "environment" | "workflow" | "gate-registry";
42
42
 
43
- export interface VnextResource {
44
- kind: VnextResourceKind;
43
+ export interface KxmResource {
44
+ kind: KxmResourceKind;
45
45
  id?: string;
46
46
  file: string;
47
47
  logicalPath: string;
48
48
  value: JsonObject;
49
49
  }
50
50
 
51
- export interface VnextProjectBundle {
51
+ export interface KxmProjectBundle {
52
52
  projectRoot: string;
53
- project: VnextResource;
54
- repositories: ReadonlyMap<string, VnextResource>;
55
- agents: ReadonlyMap<string, VnextResource>;
56
- models: ReadonlyMap<string, VnextResource>;
57
- workflows: ReadonlyMap<string, VnextResource>;
58
- environments: readonly VnextResource[];
59
- gateRegistry?: VnextResource;
53
+ project: KxmResource;
54
+ repositories: ReadonlyMap<string, KxmResource>;
55
+ agents: ReadonlyMap<string, KxmResource>;
56
+ models: ReadonlyMap<string, KxmResource>;
57
+ workflows: ReadonlyMap<string, KxmResource>;
58
+ environments: readonly KxmResource[];
59
+ gateRegistry?: KxmResource;
60
60
  templateProvenance?: JsonObject;
61
61
  migrationReceipt?: JsonObject;
62
- resources: readonly VnextResource[];
62
+ resources: readonly KxmResource[];
63
63
  configRevision: string;
64
64
  }
65
65
 
66
- export interface VnextConfigOptions {
66
+ export interface KxmConfigOptions {
67
67
  schemasDir?: string;
68
68
  repositoryBindings?: Readonly<Record<string, string>>;
69
69
  registeredExecutors?: Iterable<string>;
@@ -73,24 +73,24 @@ export interface VnextConfigOptions {
73
73
  allowUnreceiptedLegacyConfig?: boolean;
74
74
  }
75
75
 
76
- export type VnextInitializationMode = "create" | "migrate" | "repair" | "ready";
76
+ export type KxmInitializationMode = "create" | "migrate" | "repair" | "ready";
77
77
 
78
- export interface VnextInitializationPlan {
79
- mode: VnextInitializationMode;
78
+ export interface KxmInitializationPlan {
79
+ mode: KxmInitializationMode;
80
80
  inspectedFrom: string;
81
81
  projectRoot?: string;
82
82
  legacyRoot?: string;
83
83
  changesRequired: boolean;
84
- issues: readonly VnextConfigIssue[];
84
+ issues: readonly KxmConfigIssue[];
85
85
  legacyInputs: readonly string[];
86
86
  configRevision?: string;
87
87
  }
88
88
 
89
- function defaultVnextSchemaDir(): string {
90
- return join(findKxmRepoRoot(import.meta.url), "schemas", "vnext");
89
+ function defaultKxmSchemaDir(): string {
90
+ return join(findKxmRepoRoot(import.meta.url), "schemas");
91
91
  }
92
- const DEFAULT_SCHEMA_DIR = defaultVnextSchemaDir();
93
- const RESOURCE_SCHEMA: Readonly<Record<VnextResourceKind, { identity: string; file: string }>> = Object.freeze({
92
+ const DEFAULT_SCHEMA_DIR = defaultKxmSchemaDir();
93
+ const RESOURCE_SCHEMA: Readonly<Record<KxmResourceKind, { identity: string; file: string }>> = Object.freeze({
94
94
  project: { identity: "kxm.project.v1", file: "project.schema.json" },
95
95
  repository: { identity: "kxm.repository.v1", file: "repository.schema.json" },
96
96
  agent: { identity: "kxm.agent.v1", file: "agent.schema.json" },
@@ -115,35 +115,35 @@ function compareCodeUnits(left: string, right: string): number {
115
115
  return left < right ? -1 : left > right ? 1 : 0;
116
116
  }
117
117
 
118
- function sortIssues(issues: readonly VnextConfigIssue[]): VnextConfigIssue[] {
118
+ function sortIssues(issues: readonly KxmConfigIssue[]): KxmConfigIssue[] {
119
119
  return [...issues].sort((left, right) => compareCodeUnits(left.file, right.file)
120
120
  || compareCodeUnits(left.phase, right.phase)
121
121
  || compareCodeUnits(left.code, right.code)
122
122
  || compareCodeUnits(left.message, right.message));
123
123
  }
124
124
 
125
- function issue(phase: VnextValidationPhase, code: string, file: string, message: string): VnextConfigIssue {
125
+ function issue(phase: KxmValidationPhase, code: string, file: string, message: string): KxmConfigIssue {
126
126
  return { phase, code, file, message };
127
127
  }
128
128
 
129
- function fail(phase: VnextValidationPhase, code: string, file: string, message: string): never {
130
- throw new VnextConfigError([issue(phase, code, file, message)]);
129
+ function fail(phase: KxmValidationPhase, code: string, file: string, message: string): never {
130
+ throw new KxmConfigError([issue(phase, code, file, message)]);
131
131
  }
132
132
 
133
133
  function isJsonObject(value: JsonValue): value is JsonObject {
134
134
  return value !== null && typeof value === "object" && !Array.isArray(value);
135
135
  }
136
136
 
137
- /** Parse the restricted, JSON-compatible YAML profile used by all vNext configuration. */
137
+ /** Parse the restricted, JSON-compatible YAML profile used by all KXM configuration. */
138
138
  export function parseRestrictedYaml(
139
139
  input: string | Uint8Array,
140
140
  label = "<yaml>",
141
- limits: Readonly<VnextYamlLimits> = VNEXT_YAML_LIMITS,
141
+ limits: Readonly<KxmYamlLimits> = KXM_YAML_LIMITS,
142
142
  ): JsonObject {
143
143
  try {
144
144
  return parseRestrictedYamlShared(input, label, limits);
145
145
  } catch (error) {
146
- if (error instanceof RestrictedYamlError) throw new VnextConfigError(error.issues);
146
+ if (error instanceof RestrictedYamlError) throw new KxmConfigError(error.issues);
147
147
  throw error;
148
148
  }
149
149
  }
@@ -154,10 +154,10 @@ function readJsonObject(file: string): Record<string, unknown> {
154
154
  return parsed as Record<string, unknown>;
155
155
  }
156
156
 
157
- export class VnextSchemaRegistry {
157
+ export class KxmSchemaRegistry {
158
158
  readonly schemasDir: string;
159
159
  readonly ajv: Ajv2020;
160
- readonly validators = new Map<VnextResourceKind, ValidateFunction>();
160
+ readonly validators = new Map<KxmResourceKind, ValidateFunction>();
161
161
  readonly localBindingsValidator: ValidateFunction;
162
162
  readonly templateProvenanceValidator: ValidateFunction;
163
163
  readonly initOperationValidator: ValidateFunction;
@@ -194,20 +194,20 @@ export class VnextSchemaRegistry {
194
194
  this.ajv.addSchema(readJsonObject(join(this.schemasDir, permissionDiffFile)));
195
195
  this.ajv.addSchema(readJsonObject(join(this.schemasDir, runEventFile)));
196
196
  this.ajv.addSchema(readJsonObject(join(this.schemasDir, driveReceiptFile)));
197
- for (const [kind, definition] of Object.entries(RESOURCE_SCHEMA) as [VnextResourceKind, { identity: string; file: string }][]) {
198
- const validator = this.ajv.getSchema(`https://schemas.kxm.dev/vnext/${definition.file}`);
197
+ for (const [kind, definition] of Object.entries(RESOURCE_SCHEMA) as [KxmResourceKind, { identity: string; file: string }][]) {
198
+ const validator = this.ajv.getSchema(`https://schemas.kxm.dev/${definition.file}`);
199
199
  if (!validator) throw new Error(`schema did not compile: ${definition.file}`);
200
200
  this.validators.set(kind, validator);
201
201
  }
202
- const localBindingsValidator = this.ajv.getSchema(`https://schemas.kxm.dev/vnext/${localBindingsFile}`);
203
- const templateProvenanceValidator = this.ajv.getSchema(`https://schemas.kxm.dev/vnext/${templateProvenanceFile}`);
204
- const initOperationValidator = this.ajv.getSchema(`https://schemas.kxm.dev/vnext/${initOperationFile}`);
205
- const migrationPlanValidator = this.ajv.getSchema(`https://schemas.kxm.dev/vnext/${migrationPlanFile}`);
206
- const migrationDecisionValidator = this.ajv.getSchema(`https://schemas.kxm.dev/vnext/${migrationDecisionFile}`);
207
- const migrationReceiptValidator = this.ajv.getSchema(`https://schemas.kxm.dev/vnext/${migrationReceiptFile}`);
208
- const permissionDiffValidator = this.ajv.getSchema(`https://schemas.kxm.dev/vnext/${permissionDiffFile}`);
209
- const runEventValidator = this.ajv.getSchema(`https://schemas.kxm.dev/vnext/${runEventFile}`);
210
- const driveReceiptValidator = this.ajv.getSchema(`https://schemas.kxm.dev/vnext/${driveReceiptFile}`);
202
+ const localBindingsValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${localBindingsFile}`);
203
+ const templateProvenanceValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${templateProvenanceFile}`);
204
+ const initOperationValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${initOperationFile}`);
205
+ const migrationPlanValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${migrationPlanFile}`);
206
+ const migrationDecisionValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${migrationDecisionFile}`);
207
+ const migrationReceiptValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${migrationReceiptFile}`);
208
+ const permissionDiffValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${permissionDiffFile}`);
209
+ const runEventValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${runEventFile}`);
210
+ const driveReceiptValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${driveReceiptFile}`);
211
211
  if (!localBindingsValidator) throw new Error(`schema did not compile: ${localBindingsFile}`);
212
212
  if (!templateProvenanceValidator) throw new Error(`schema did not compile: ${templateProvenanceFile}`);
213
213
  if (!initOperationValidator) throw new Error(`schema did not compile: ${initOperationFile}`);
@@ -228,50 +228,50 @@ export class VnextSchemaRegistry {
228
228
  this.driveReceiptValidator = driveReceiptValidator;
229
229
  }
230
230
 
231
- validate(kind: VnextResourceKind, value: JsonObject, file: string): VnextConfigIssue[] {
231
+ validate(kind: KxmResourceKind, value: JsonObject, file: string): KxmConfigIssue[] {
232
232
  const definition = RESOURCE_SCHEMA[kind];
233
233
  if (value.schema !== definition.identity) {
234
234
  return [issue("schema", "schema_identity_mismatch", file, `expected ${definition.identity}, received ${String(value.schema)}`)];
235
235
  }
236
236
  const validator = this.validators.get(kind);
237
- if (!validator) throw new Error(`missing vNext validator for ${kind}`);
237
+ if (!validator) throw new Error(`missing KXM validator for ${kind}`);
238
238
  if (validator(value)) return [];
239
239
  return (validator.errors ?? []).map((error) => schemaIssue(file, error));
240
240
  }
241
241
 
242
- validateLocalBindings(value: JsonObject, file: string): VnextConfigIssue[] {
242
+ validateLocalBindings(value: JsonObject, file: string): KxmConfigIssue[] {
243
243
  return this.validateAuxiliary(value, file, "kxm.local-repository-bindings.v1", this.localBindingsValidator);
244
244
  }
245
245
 
246
- validateTemplateProvenance(value: JsonObject, file: string): VnextConfigIssue[] {
246
+ validateTemplateProvenance(value: JsonObject, file: string): KxmConfigIssue[] {
247
247
  return this.validateAuxiliary(value, file, "kxm.template-provenance.v1", this.templateProvenanceValidator);
248
248
  }
249
249
 
250
- validateInitOperation(value: JsonObject, file: string): VnextConfigIssue[] {
250
+ validateInitOperation(value: JsonObject, file: string): KxmConfigIssue[] {
251
251
  return this.validateAuxiliary(value, file, "kxm.init-operation.v1", this.initOperationValidator);
252
252
  }
253
253
 
254
- validateMigrationPlan(value: JsonObject, file: string): VnextConfigIssue[] {
254
+ validateMigrationPlan(value: JsonObject, file: string): KxmConfigIssue[] {
255
255
  return this.validateAuxiliary(value, file, "kxm.migration-plan.v1", this.migrationPlanValidator);
256
256
  }
257
257
 
258
- validateMigrationDecision(value: JsonObject, file: string): VnextConfigIssue[] {
258
+ validateMigrationDecision(value: JsonObject, file: string): KxmConfigIssue[] {
259
259
  return this.validateAuxiliary(value, file, "kxm.migration-decision.v1", this.migrationDecisionValidator);
260
260
  }
261
261
 
262
- validateMigrationReceipt(value: JsonObject, file: string): VnextConfigIssue[] {
262
+ validateMigrationReceipt(value: JsonObject, file: string): KxmConfigIssue[] {
263
263
  return this.validateAuxiliary(value, file, "kxm.migration-receipt.v1", this.migrationReceiptValidator);
264
264
  }
265
265
 
266
- validatePermissionDiff(value: JsonObject, file: string): VnextConfigIssue[] {
266
+ validatePermissionDiff(value: JsonObject, file: string): KxmConfigIssue[] {
267
267
  return this.validateAuxiliary(value, file, "kxm.permission-diff.v1", this.permissionDiffValidator);
268
268
  }
269
269
 
270
- validateDriveReceipt(value: JsonObject, file: string): VnextConfigIssue[] {
270
+ validateDriveReceipt(value: JsonObject, file: string): KxmConfigIssue[] {
271
271
  return this.validateAuxiliary(value, file, "kxm.drive-receipt.v1", this.driveReceiptValidator);
272
272
  }
273
273
 
274
- private validateAuxiliary(value: JsonObject, file: string, identity: string, validator: ValidateFunction): VnextConfigIssue[] {
274
+ private validateAuxiliary(value: JsonObject, file: string, identity: string, validator: ValidateFunction): KxmConfigIssue[] {
275
275
  if (value.schema !== identity) {
276
276
  return [issue("schema", "schema_identity_mismatch", file, `expected ${identity}, received ${String(value.schema)}`)];
277
277
  }
@@ -280,13 +280,13 @@ export class VnextSchemaRegistry {
280
280
  }
281
281
  }
282
282
 
283
- let cachedRunEventRegistry: VnextSchemaRegistry | undefined;
283
+ let cachedRunEventRegistry: KxmSchemaRegistry | undefined;
284
284
 
285
285
  /** Validate a local run event against `kxm.run-event.v1`. Throws `run_event_invalid`. */
286
286
  export function validateRunEvent(value: unknown, file: string): void {
287
- const registry = (cachedRunEventRegistry ??= new VnextSchemaRegistry());
287
+ const registry = (cachedRunEventRegistry ??= new KxmSchemaRegistry());
288
288
  if (!registry.runEventValidator(value)) {
289
- throw new VnextConfigError([issue(
289
+ throw new KxmConfigError([issue(
290
290
  "schema",
291
291
  "run_event_invalid",
292
292
  file,
@@ -297,9 +297,9 @@ export function validateRunEvent(value: unknown, file: string): void {
297
297
 
298
298
  /** Validate a drive receipt against `kxm.drive-receipt.v1`. Throws `drive_receipt_invalid`. */
299
299
  export function validateDriveReceipt(value: unknown, file: string): void {
300
- const registry = (cachedRunEventRegistry ??= new VnextSchemaRegistry());
300
+ const registry = (cachedRunEventRegistry ??= new KxmSchemaRegistry());
301
301
  if (!value || typeof value !== "object" || Array.isArray(value) || (value as JsonObject).schema !== "kxm.drive-receipt.v1") {
302
- throw new VnextConfigError([issue(
302
+ throw new KxmConfigError([issue(
303
303
  "schema",
304
304
  "drive_receipt_invalid",
305
305
  file,
@@ -307,7 +307,7 @@ export function validateDriveReceipt(value: unknown, file: string): void {
307
307
  )]);
308
308
  }
309
309
  if (!registry.driveReceiptValidator(value)) {
310
- throw new VnextConfigError([issue(
310
+ throw new KxmConfigError([issue(
311
311
  "schema",
312
312
  "drive_receipt_invalid",
313
313
  file,
@@ -316,7 +316,7 @@ export function validateDriveReceipt(value: unknown, file: string): void {
316
316
  }
317
317
  }
318
318
 
319
- function schemaIssue(file: string, error: ErrorObject): VnextConfigIssue {
319
+ function schemaIssue(file: string, error: ErrorObject): KxmConfigIssue {
320
320
  const location = error.instancePath || "/";
321
321
  const suffix = error.params && "additionalProperty" in error.params
322
322
  ? ` (${String(error.params.additionalProperty)})`
@@ -346,7 +346,7 @@ function containedHostPath(root: string, candidate: string): boolean {
346
346
  return path === "" || (!isAbsolute(path) && path !== ".." && !path.startsWith(`..${sep}`));
347
347
  }
348
348
 
349
- function portableBindingIssue(root: string, pathHint: string, repositoryId: string): VnextConfigIssue | undefined {
349
+ function portableBindingIssue(root: string, pathHint: string, repositoryId: string): KxmConfigIssue | undefined {
350
350
  let current = root;
351
351
  for (const segment of pathHint === "." ? [] : pathHint.split("/")) {
352
352
  current = join(current, segment);
@@ -368,7 +368,7 @@ function portableBindingIssue(root: string, pathHint: string, repositoryId: stri
368
368
  }
369
369
 
370
370
  /** The portable relative-path rule every project-owned pathHint must satisfy. */
371
- export function vnextPortablePath(path: string): boolean {
371
+ export function kxmPortablePath(path: string): boolean {
372
372
  return portablePath(path);
373
373
  }
374
374
 
@@ -386,12 +386,12 @@ function portablePath(path: string): boolean {
386
386
  }
387
387
 
388
388
  /** The identifier rule every path-derived resource identity must satisfy. */
389
- export function vnextResourceIdentifier(id: string): boolean {
389
+ export function kxmResourceIdentifier(id: string): boolean {
390
390
  return id.length <= 64 && IDENTIFIER.test(id) && !WINDOWS_RESERVED.test(id);
391
391
  }
392
392
 
393
393
  function resourceIdentifier(id: string): boolean {
394
- return vnextResourceIdentifier(id);
394
+ return kxmResourceIdentifier(id);
395
395
  }
396
396
 
397
397
  function displayPath(root: string, file: string): string {
@@ -400,14 +400,14 @@ function displayPath(root: string, file: string): string {
400
400
  }
401
401
 
402
402
  function readResource(
403
- registry: VnextSchemaRegistry,
403
+ registry: KxmSchemaRegistry,
404
404
  root: string,
405
405
  file: string,
406
406
  logicalPath: string,
407
- kind: VnextResourceKind,
407
+ kind: KxmResourceKind,
408
408
  id?: string,
409
409
  containmentRoot = root,
410
- ): VnextResource {
410
+ ): KxmResource {
411
411
  const label = displayPath(root, file);
412
412
  let stat;
413
413
  try {
@@ -429,11 +429,11 @@ function readResource(
429
429
  if (!stat.isFile()) fail("path", "resource_not_file", label, "configuration resource must be a regular file");
430
430
  const value = parseRestrictedYaml(readFileSync(file), label);
431
431
  const issues = registry.validate(kind, value, label);
432
- if (issues.length > 0) throw new VnextConfigError(issues);
432
+ if (issues.length > 0) throw new KxmConfigError(issues);
433
433
  return { kind, ...(id === undefined ? {} : { id }), file, logicalPath, value };
434
434
  }
435
435
 
436
- function readTemplateProvenance(registry: VnextSchemaRegistry, root: string): JsonObject | undefined {
436
+ function readTemplateProvenance(registry: KxmSchemaRegistry, root: string): JsonObject | undefined {
437
437
  const file = join(root, ".kxm", "template-provenance.yaml");
438
438
  if (!existsSync(file)) return undefined;
439
439
  const label = ".kxm/template-provenance.yaml";
@@ -453,8 +453,8 @@ function readTemplateProvenance(registry: VnextSchemaRegistry, root: string): Js
453
453
  }
454
454
  const value = parseRestrictedYaml(readFileSync(file), label);
455
455
  const issues = registry.validateTemplateProvenance(value, label);
456
- if (issues.length > 0) throw new VnextConfigError(issues);
457
- if (!resolveVnextTemplateBaseline(value)) {
456
+ if (issues.length > 0) throw new KxmConfigError(issues);
457
+ if (!resolveKxmTemplateBaseline(value)) {
458
458
  fail("semantic", "template_provenance_revision_invalid", label, "template provenance does not exactly match a supported built-in baseline");
459
459
  }
460
460
  const files = Array.isArray(value.files) ? value.files : [];
@@ -482,19 +482,19 @@ function readTemplateProvenance(registry: VnextSchemaRegistry, root: string): Js
482
482
  }
483
483
 
484
484
  function listNamedResources(
485
- registry: VnextSchemaRegistry,
485
+ registry: KxmSchemaRegistry,
486
486
  root: string,
487
487
  directory: string,
488
488
  logicalDirectory: string,
489
489
  kind: "agent" | "model" | "workflow",
490
- ): Map<string, VnextResource> {
491
- const resources = new Map<string, VnextResource>();
490
+ ): Map<string, KxmResource> {
491
+ const resources = new Map<string, KxmResource>();
492
492
  if (!existsSync(directory)) return resources;
493
493
  const stat = lstatSync(directory);
494
494
  if (stat.isSymbolicLink() || !stat.isDirectory()) {
495
495
  fail("path", "resource_directory_invalid", displayPath(root, directory), "resource directory must be a regular directory");
496
496
  }
497
- const issues: VnextConfigIssue[] = [];
497
+ const issues: KxmConfigIssue[] = [];
498
498
  const entries = readdirSync(directory, { withFileTypes: true }).sort((left, right) => compareCodeUnits(left.name, right.name));
499
499
  for (const entry of entries) {
500
500
  if (entry.isDirectory()) {
@@ -521,11 +521,11 @@ function listNamedResources(
521
521
  const resource = readResource(registry, root, join(directory, entry.name), `${logicalDirectory}/${id}.yaml`, kind, id);
522
522
  resources.set(id, resource);
523
523
  } catch (error) {
524
- if (error instanceof VnextConfigError) issues.push(...error.issues);
524
+ if (error instanceof KxmConfigError) issues.push(...error.issues);
525
525
  else throw error;
526
526
  }
527
527
  }
528
- if (issues.length > 0) throw new VnextConfigError(issues);
528
+ if (issues.length > 0) throw new KxmConfigError(issues);
529
529
  return resources;
530
530
  }
531
531
 
@@ -550,7 +550,7 @@ function names(value: JsonValue | undefined): string[] {
550
550
  return Array.isArray(value) ? value.filter((candidate): candidate is string => typeof candidate === "string") : [];
551
551
  }
552
552
 
553
- function mapResource(resource: VnextResource, map: Map<string, VnextResource>, issues: VnextConfigIssue[]): void {
553
+ function mapResource(resource: KxmResource, map: Map<string, KxmResource>, issues: KxmConfigIssue[]): void {
554
554
  const id = resource.id;
555
555
  if (!id) return;
556
556
  const collision = [...map.keys()].find((candidate) => candidate.toLocaleLowerCase("en-US") === id.toLocaleLowerCase("en-US"));
@@ -561,7 +561,7 @@ function mapResource(resource: VnextResource, map: Map<string, VnextResource>, i
561
561
  map.set(id, resource);
562
562
  }
563
563
 
564
- function validatePortablePaths(resource: VnextResource, issues: VnextConfigIssue[]): void {
564
+ function validatePortablePaths(resource: KxmResource, issues: KxmConfigIssue[]): void {
565
565
  const candidates: { path: string; label: string }[] = [];
566
566
  if (resource.kind === "project") {
567
567
  for (const candidate of valuesOf(resource.value, "repositories")) {
@@ -587,11 +587,11 @@ function validatePortablePaths(resource: VnextResource, issues: VnextConfigIssue
587
587
 
588
588
  function selectorCandidates(
589
589
  selectorValue: JsonValue | undefined,
590
- models: ReadonlyMap<string, VnextResource>,
590
+ models: ReadonlyMap<string, KxmResource>,
591
591
  file: string,
592
592
  label: string,
593
- issues: VnextConfigIssue[],
594
- ): VnextResource[] {
593
+ issues: KxmConfigIssue[],
594
+ ): KxmResource[] {
595
595
  const selector = objectValue(selectorValue);
596
596
  if (!selector) return [];
597
597
  const profile = stringValue(selector.profile);
@@ -616,7 +616,7 @@ interface ModelCandidate {
616
616
  model?: string;
617
617
  }
618
618
 
619
- function modelCandidates(selectorValue: JsonValue | undefined, models: ReadonlyMap<string, VnextResource>): ModelCandidate[] {
619
+ function modelCandidates(selectorValue: JsonValue | undefined, models: ReadonlyMap<string, KxmResource>): ModelCandidate[] {
620
620
  const selector = objectValue(selectorValue);
621
621
  if (!selector) return [];
622
622
  const profile = stringValue(selector.profile);
@@ -656,8 +656,8 @@ function compatibleModel(left: ModelCandidate, right: ModelCandidate): boolean {
656
656
  function diversityCandidates(
657
657
  stepSelector: JsonValue | undefined,
658
658
  allowedAgents: readonly string[],
659
- agents: ReadonlyMap<string, VnextResource>,
660
- models: ReadonlyMap<string, VnextResource>,
659
+ agents: ReadonlyMap<string, KxmResource>,
660
+ models: ReadonlyMap<string, KxmResource>,
661
661
  ): ModelCandidate[] {
662
662
  const stepCandidates = modelCandidates(stepSelector, models);
663
663
  const resolved: ModelCandidate[] = [];
@@ -672,7 +672,7 @@ function diversityCandidates(
672
672
  return [...new Map(resolved.map((candidate) => [candidate.key, candidate])).values()];
673
673
  }
674
674
 
675
- function validateEnvironment(resource: VnextResource, issues: VnextConfigIssue[]): void {
675
+ function validateEnvironment(resource: KxmResource, issues: KxmConfigIssue[]): void {
676
676
  const values = objectValue(resource.value.values) ?? {};
677
677
  const secretNames = new Set<string>();
678
678
  for (const candidate of valuesOf(resource.value, "secrets")) {
@@ -694,7 +694,7 @@ function accessRank(value: JsonValue | undefined): number {
694
694
  return value === "write" ? 2 : value === "read" ? 1 : 0;
695
695
  }
696
696
 
697
- function validateToolScope(agent: VnextResource, step: JsonObject, file: string, stepId: string, issues: VnextConfigIssue[]): void {
697
+ function validateToolScope(agent: KxmResource, step: JsonObject, file: string, stepId: string, issues: KxmConfigIssue[]): void {
698
698
  const requested = objectValue(step.tools);
699
699
  if (!requested) return;
700
700
  const ceiling = objectValue(agent.value.tools);
@@ -718,7 +718,7 @@ function validateToolScope(agent: VnextResource, step: JsonObject, file: string,
718
718
  }
719
719
  }
720
720
 
721
- function validateToolPolicy(resource: VnextResource, policy: JsonObject | undefined, label: string, issues: VnextConfigIssue[]): void {
721
+ function validateToolPolicy(resource: KxmResource, policy: JsonObject | undefined, label: string, issues: KxmConfigIssue[]): void {
722
722
  if (!policy) return;
723
723
  const allowed = new Set(names(policy.allow));
724
724
  for (const tool of names(policy.deny)) {
@@ -727,11 +727,11 @@ function validateToolPolicy(resource: VnextResource, policy: JsonObject | undefi
727
727
  }
728
728
 
729
729
  /** Validate an in-memory resource set with the same semantic rules as a loaded project. */
730
- export function validateVnextResources(
731
- resources: ReadonlyMap<string, { kind: VnextResourceKind; id?: string; value: JsonObject }>,
732
- options: VnextConfigOptions = {},
733
- ): VnextConfigIssue[] {
734
- const make = (logicalPath: string, kind: VnextResourceKind, id: string | undefined, value: JsonObject): VnextResource => ({
730
+ export function validateKxmResources(
731
+ resources: ReadonlyMap<string, { kind: KxmResourceKind; id?: string; value: JsonObject }>,
732
+ options: KxmConfigOptions = {},
733
+ ): KxmConfigIssue[] {
734
+ const make = (logicalPath: string, kind: KxmResourceKind, id: string | undefined, value: JsonObject): KxmResource => ({
735
735
  kind,
736
736
  ...(id === undefined ? {} : { id }),
737
737
  file: logicalPath,
@@ -739,13 +739,13 @@ export function validateVnextResources(
739
739
  value,
740
740
  });
741
741
  assertNoRegisteredGates(options);
742
- let gateRegistry: VnextResource | undefined;
743
- let project: VnextResource | undefined;
744
- const repositories = new Map<string, VnextResource>();
745
- const agents = new Map<string, VnextResource>();
746
- const models = new Map<string, VnextResource>();
747
- const workflows = new Map<string, VnextResource>();
748
- const environments: VnextResource[] = [];
742
+ let gateRegistry: KxmResource | undefined;
743
+ let project: KxmResource | undefined;
744
+ const repositories = new Map<string, KxmResource>();
745
+ const agents = new Map<string, KxmResource>();
746
+ const models = new Map<string, KxmResource>();
747
+ const workflows = new Map<string, KxmResource>();
748
+ const environments: KxmResource[] = [];
749
749
  for (const [logicalPath, resource] of resources) {
750
750
  const made = make(logicalPath, resource.kind, resource.id, resource.value);
751
751
  if (resource.kind === "project") project = made;
@@ -761,12 +761,12 @@ export function validateVnextResources(
761
761
  }
762
762
 
763
763
  function validateAgentScope(
764
- agent: VnextResource,
764
+ agent: KxmResource,
765
765
  step: JsonObject,
766
766
  repositories: ReadonlySet<string>,
767
767
  file: string,
768
768
  stepId: string,
769
- issues: VnextConfigIssue[],
769
+ issues: KxmConfigIssue[],
770
770
  ): void {
771
771
  validateToolScope(agent, step, file, stepId, issues);
772
772
  const agentRepositories = objectValue(agent.value.repositories) ?? {};
@@ -800,12 +800,12 @@ function transition(value: JsonValue): { target?: string; maxTransitions?: numbe
800
800
  }
801
801
 
802
802
  function validateWorkflow(
803
- workflow: VnextResource,
804
- agents: ReadonlyMap<string, VnextResource>,
805
- models: ReadonlyMap<string, VnextResource>,
803
+ workflow: KxmResource,
804
+ agents: ReadonlyMap<string, KxmResource>,
805
+ models: ReadonlyMap<string, KxmResource>,
806
806
  repositories: ReadonlySet<string>,
807
807
  gates: ReadonlySet<string> | undefined,
808
- issues: VnextConfigIssue[],
808
+ issues: KxmConfigIssue[],
809
809
  ): void {
810
810
  const file = workflow.logicalPath;
811
811
  const coordinator = stringValue(workflow.value.coordinator) ?? "coordinator";
@@ -1029,7 +1029,7 @@ function validateWorkflow(
1029
1029
  }
1030
1030
  }
1031
1031
 
1032
- function validateModelReferences(models: ReadonlyMap<string, VnextResource>, issues: VnextConfigIssue[]): void {
1032
+ function validateModelReferences(models: ReadonlyMap<string, KxmResource>, issues: KxmConfigIssue[]): void {
1033
1033
  for (const model of models.values()) {
1034
1034
  for (const [index, fallback] of valuesOf(model.value, "fallbacks").entries()) {
1035
1035
  selectorCandidates(fallback, models, model.logicalPath, `fallbacks[${index}]`, issues);
@@ -1058,17 +1058,17 @@ function validateModelReferences(models: ReadonlyMap<string, VnextResource>, iss
1058
1058
  }
1059
1059
 
1060
1060
  function validateBundle(
1061
- project: VnextResource,
1062
- repositories: ReadonlyMap<string, VnextResource>,
1063
- agents: ReadonlyMap<string, VnextResource>,
1064
- models: ReadonlyMap<string, VnextResource>,
1065
- workflows: ReadonlyMap<string, VnextResource>,
1066
- environments: readonly VnextResource[],
1067
- options: VnextConfigOptions,
1068
- gateRegistry?: VnextResource,
1061
+ project: KxmResource,
1062
+ repositories: ReadonlyMap<string, KxmResource>,
1063
+ agents: ReadonlyMap<string, KxmResource>,
1064
+ models: ReadonlyMap<string, KxmResource>,
1065
+ workflows: ReadonlyMap<string, KxmResource>,
1066
+ environments: readonly KxmResource[],
1067
+ options: KxmConfigOptions,
1068
+ gateRegistry?: KxmResource,
1069
1069
  projectRoot?: string,
1070
- ): VnextConfigIssue[] {
1071
- const issues: VnextConfigIssue[] = [];
1070
+ ): KxmConfigIssue[] {
1071
+ const issues: KxmConfigIssue[] = [];
1072
1072
  const entries = valuesOf(project.value, "repositories").map((candidate) => objectValue(candidate)).filter((candidate): candidate is JsonObject => Boolean(candidate));
1073
1073
  const repositoryIds = new Set<string>();
1074
1074
  const foldedRepositories = new Map<string, string>();
@@ -1168,7 +1168,7 @@ function validateBundle(
1168
1168
  }
1169
1169
  }
1170
1170
  } catch (error) {
1171
- if (error instanceof VnextConfigError) {
1171
+ if (error instanceof KxmConfigError) {
1172
1172
  issues.push(...error.issues);
1173
1173
  }
1174
1174
  }
@@ -1178,17 +1178,17 @@ function validateBundle(
1178
1178
  return sortIssues(issues);
1179
1179
  }
1180
1180
 
1181
- export function vnextCanonicalJson(value: JsonValue): string {
1181
+ export function kxmCanonicalJson(value: JsonValue): string {
1182
1182
  if (value === null || typeof value !== "object") return JSON.stringify(value);
1183
- if (Array.isArray(value)) return `[${value.map((candidate) => vnextCanonicalJson(candidate)).join(",")}]`;
1184
- return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${vnextCanonicalJson(value[key] as JsonValue)}`).join(",")}}`;
1183
+ if (Array.isArray(value)) return `[${value.map((candidate) => kxmCanonicalJson(candidate)).join(",")}]`;
1184
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${kxmCanonicalJson(value[key] as JsonValue)}`).join(",")}}`;
1185
1185
  }
1186
1186
 
1187
1187
  function canonicalize(value: JsonValue): string {
1188
- return vnextCanonicalJson(value);
1188
+ return kxmCanonicalJson(value);
1189
1189
  }
1190
1190
 
1191
- function bundleRevision(resources: readonly VnextResource[]): string {
1191
+ function bundleRevision(resources: readonly KxmResource[]): string {
1192
1192
  const hash = createHash("sha256");
1193
1193
  for (const resource of [...resources].sort((left, right) => compareCodeUnits(left.logicalPath, right.logicalPath))) {
1194
1194
  hash.update(resource.logicalPath, "utf8");
@@ -1218,8 +1218,8 @@ export function discoverGitRoot(start = process.cwd()): string | undefined {
1218
1218
  return existsSync(root) && lstatSync(root).isDirectory() ? root : undefined;
1219
1219
  }
1220
1220
 
1221
- /** Find the authoritative vNext project only at the nearest Git worktree root. */
1222
- export function discoverVnextProjectRoot(start = process.cwd()): string | undefined {
1221
+ /** Find the authoritative KXM project only at the nearest Git worktree root. */
1222
+ export function discoverKxmProjectRoot(start = process.cwd()): string | undefined {
1223
1223
  const gitRoot = discoverGitRoot(start);
1224
1224
  return gitRoot && existsSync(join(gitRoot, ".kxm", "project.yaml")) ? gitRoot : undefined;
1225
1225
  }
@@ -1227,23 +1227,23 @@ export function discoverVnextProjectRoot(start = process.cwd()): string | undefi
1227
1227
  /** The former caller-supplied gate allowlist cannot substitute for reviewed YAML. */
1228
1228
  export function assertNoRegisteredGates(options: object): void {
1229
1229
  if ("registeredGates" in options) {
1230
- throw new VnextConfigError([issue("semantic", "registered_gates_removed", ".kxm/gates.yaml", "registeredGates was removed; declare gates in .kxm/gates.yaml")]);
1230
+ throw new KxmConfigError([issue("semantic", "registered_gates_removed", ".kxm/gates.yaml", "registeredGates was removed; declare gates in .kxm/gates.yaml")]);
1231
1231
  }
1232
1232
  }
1233
1233
 
1234
- /** Load and semantically validate one complete, path-derived vNext configuration bundle. */
1235
- export function loadVnextProject(projectRoot: string, options: VnextConfigOptions = {}): VnextProjectBundle {
1234
+ /** Load and semantically validate one complete, path-derived KXM configuration bundle. */
1235
+ export function loadKxmProject(projectRoot: string, options: KxmConfigOptions = {}): KxmProjectBundle {
1236
1236
  assertNoRegisteredGates(options);
1237
1237
  const root = resolve(projectRoot);
1238
1238
  let migrationReceipt: JsonObject | undefined;
1239
1239
  if (legacyConfigFilesAt(root).length > 0 && options.allowUnreceiptedLegacyConfig !== true) {
1240
- const receiptCheck = readVnextMigrationReceipt(root, options);
1241
- if (receiptCheck.issues.length > 0) throw new VnextConfigError(receiptCheck.issues);
1240
+ const receiptCheck = readKxmMigrationReceipt(root, options);
1241
+ if (receiptCheck.issues.length > 0) throw new KxmConfigError(receiptCheck.issues);
1242
1242
  migrationReceipt = receiptCheck.receipt;
1243
1243
  }
1244
- const registry = new VnextSchemaRegistry(options.schemasDir);
1244
+ const registry = new KxmSchemaRegistry(options.schemasDir);
1245
1245
  const project = readResource(registry, root, join(root, ".kxm", "project.yaml"), ".kxm/project.yaml", "project");
1246
- const earlyIssues: VnextConfigIssue[] = [];
1246
+ const earlyIssues: KxmConfigIssue[] = [];
1247
1247
  validatePortablePaths(project, earlyIssues);
1248
1248
  const templateProvenance = readTemplateProvenance(registry, root);
1249
1249
  if (templateProvenance && templateProvenance.inputs && typeof templateProvenance.inputs === "object" && !Array.isArray(templateProvenance.inputs)) {
@@ -1253,7 +1253,7 @@ export function loadVnextProject(projectRoot: string, options: VnextConfigOption
1253
1253
  }
1254
1254
  }
1255
1255
  if (migrationReceipt && stringValue(migrationReceipt.projectId) !== stringValue(project.value.id)) {
1256
- earlyIssues.push(issue("semantic", "migration_project_mismatch", VNEXT_MIGRATION_RECEIPT_PATH, "migration receipt belongs to a different project identity"));
1256
+ earlyIssues.push(issue("semantic", "migration_project_mismatch", KXM_MIGRATION_RECEIPT_PATH, "migration receipt belongs to a different project identity"));
1257
1257
  }
1258
1258
  const declaredRepositoryIds = new Set(valuesOf(project.value, "repositories")
1259
1259
  .map((candidate) => stringValue(objectValue(candidate)?.id))
@@ -1265,21 +1265,21 @@ export function loadVnextProject(projectRoot: string, options: VnextConfigOption
1265
1265
  earlyIssues.push(issue("reference", "repository_binding_unknown", ".kxm/project.yaml", `host-local binding references unknown repository ${repositoryId}`));
1266
1266
  }
1267
1267
  }
1268
- if (earlyIssues.length > 0) throw new VnextConfigError(earlyIssues);
1268
+ if (earlyIssues.length > 0) throw new KxmConfigError(earlyIssues);
1269
1269
 
1270
1270
  const agents = listNamedResources(registry, root, join(root, ".kxm", "agents"), ".kxm/agents", "agent");
1271
1271
  const models = listNamedResources(registry, root, join(root, ".kxm", "models"), ".kxm/models", "model");
1272
1272
  const workflows = listNamedResources(registry, root, join(root, ".kxm", "workflows"), ".kxm/workflows", "workflow");
1273
1273
  const gatePath = join(root, ".kxm", "gates.yaml");
1274
1274
  const gateRegistry = existsSync(gatePath) ? readResource(registry, root, gatePath, ".kxm/gates.yaml", "gate-registry") : undefined;
1275
- const environments: VnextResource[] = [];
1276
- const repositories = new Map<string, VnextResource>();
1277
- const loadIssues: VnextConfigIssue[] = [];
1275
+ const environments: KxmResource[] = [];
1276
+ const repositories = new Map<string, KxmResource>();
1277
+ const loadIssues: KxmConfigIssue[] = [];
1278
1278
 
1279
1279
  const projectEnvironment = join(root, ".kxm", "project", "env.yaml");
1280
1280
  if (existsSync(projectEnvironment)) {
1281
1281
  try { environments.push(readResource(registry, root, projectEnvironment, ".kxm/project/env.yaml", "environment")); }
1282
- catch (error) { if (error instanceof VnextConfigError) loadIssues.push(...error.issues); else throw error; }
1282
+ catch (error) { if (error instanceof KxmConfigError) loadIssues.push(...error.issues); else throw error; }
1283
1283
  }
1284
1284
 
1285
1285
  const seenBindings = new Map<string, string>();
@@ -1358,7 +1358,7 @@ export function loadVnextProject(projectRoot: string, options: VnextConfigOption
1358
1358
  definitionValidated = repositories.get(repositoryId) === resource;
1359
1359
  }
1360
1360
  } catch (error) {
1361
- if (error instanceof VnextConfigError) loadIssues.push(...error.issues);
1361
+ if (error instanceof KxmConfigError) loadIssues.push(...error.issues);
1362
1362
  else throw error;
1363
1363
  }
1364
1364
  } else if (required || hasLocalBinding) {
@@ -1370,14 +1370,14 @@ export function loadVnextProject(projectRoot: string, options: VnextConfigOption
1370
1370
  loadIssues.push(issue("reference", "repository_environment_without_definition", `.kxm/repositories/${repositoryId}/env.yaml`, `repository ${repositoryId} environment requires a validated matching repo.yaml`));
1371
1371
  } else {
1372
1372
  try { environments.push(readResource(registry, root, environmentFile, `.kxm/repositories/${repositoryId}/env.yaml`, "environment", undefined, binding)); }
1373
- catch (error) { if (error instanceof VnextConfigError) loadIssues.push(...error.issues); else throw error; }
1373
+ catch (error) { if (error instanceof KxmConfigError) loadIssues.push(...error.issues); else throw error; }
1374
1374
  }
1375
1375
  }
1376
1376
  }
1377
- if (loadIssues.length > 0) throw new VnextConfigError(loadIssues);
1377
+ if (loadIssues.length > 0) throw new KxmConfigError(loadIssues);
1378
1378
 
1379
1379
  const issues = validateBundle(project, repositories, agents, models, workflows, environments, options, gateRegistry, root);
1380
- if (issues.length > 0) throw new VnextConfigError(issues);
1380
+ if (issues.length > 0) throw new KxmConfigError(issues);
1381
1381
  const resources = [project, ...repositories.values(), ...agents.values(), ...models.values(), ...workflows.values(), ...environments, ...(gateRegistry ? [gateRegistry] : [])]
1382
1382
  .sort((left, right) => compareCodeUnits(left.logicalPath, right.logicalPath));
1383
1383
  return {
@@ -1401,15 +1401,15 @@ export function loadVnextProject(projectRoot: string, options: VnextConfigOption
1401
1401
  * revision and per-resource bytes. Load-time coexistence only pins the
1402
1402
  * legacy sources; this stricter check backs `kxm migrate verify`.
1403
1403
  */
1404
- export function verifyVnextMigrationReceiptTarget(
1404
+ export function verifyKxmMigrationReceiptTarget(
1405
1405
  root: string,
1406
1406
  receipt: JsonObject,
1407
- resources: readonly VnextResource[],
1407
+ resources: readonly KxmResource[],
1408
1408
  configRevision: string,
1409
- ): VnextConfigIssue[] {
1410
- const issues: VnextConfigIssue[] = [];
1409
+ ): KxmConfigIssue[] {
1410
+ const issues: KxmConfigIssue[] = [];
1411
1411
  if (receipt.configRevision !== configRevision) {
1412
- issues.push(issue("semantic", "migration_target_changed", VNEXT_MIGRATION_RECEIPT_PATH, "target configuration revision no longer matches the migration receipt"));
1412
+ issues.push(issue("semantic", "migration_target_changed", KXM_MIGRATION_RECEIPT_PATH, "target configuration revision no longer matches the migration receipt"));
1413
1413
  }
1414
1414
  const declared = new Map<string, JsonObject>();
1415
1415
  for (const candidate of Array.isArray(receipt.resources) ? receipt.resources : []) {
@@ -1459,7 +1459,7 @@ function legacyInputsAt(root: string): string[] {
1459
1459
  return candidates.filter((candidate) => existsSync(join(root, ...candidate.split("/"))));
1460
1460
  }
1461
1461
 
1462
- export const VNEXT_MIGRATION_RECEIPT_PATH = ".kxm/migration-receipt.yaml";
1462
+ export const KXM_MIGRATION_RECEIPT_PATH = ".kxm/migration-receipt.yaml";
1463
1463
  const LEGACY_CONFIG_FILES = [".kxm/config/agents.json", ".kxm/config/gates.json"] as const;
1464
1464
 
1465
1465
  /** Individual legacy configuration files (not directories, not runtime state) that a migration receipt must cover. */
@@ -1496,9 +1496,9 @@ export function legacyConfigFilesAt(root: string): string[] {
1496
1496
  return files;
1497
1497
  }
1498
1498
 
1499
- export interface VnextMigrationReceiptCheck {
1499
+ export interface KxmMigrationReceiptCheck {
1500
1500
  receipt?: JsonObject;
1501
- issues: VnextConfigIssue[];
1501
+ issues: KxmConfigIssue[];
1502
1502
  }
1503
1503
 
1504
1504
  function hashFileRecord(root: string, relativePath: string): { path: string; sha256: string; bytes: number } | undefined {
@@ -1514,7 +1514,7 @@ function hashFileRecord(root: string, relativePath: string): { path: string; sha
1514
1514
 
1515
1515
  export function migrationReceiptSelfHash(receipt: JsonObject): string {
1516
1516
  const { receiptSha256: _ignored, ...unsigned } = receipt;
1517
- return `sha256:${createHash("sha256").update(vnextCanonicalJson(unsigned as JsonObject), "utf8").digest("hex")}`;
1517
+ return `sha256:${createHash("sha256").update(kxmCanonicalJson(unsigned as JsonObject), "utf8").digest("hex")}`;
1518
1518
  }
1519
1519
 
1520
1520
  /**
@@ -1522,36 +1522,36 @@ export function migrationReceiptSelfHash(receipt: JsonObject): string {
1522
1522
  * exact coverage of the legacy configuration files still present. Does not
1523
1523
  * compare the target configuration revision (computed by the caller).
1524
1524
  */
1525
- export function readVnextMigrationReceipt(root: string, options: VnextConfigOptions = {}): VnextMigrationReceiptCheck {
1526
- const receiptPath = join(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
1525
+ export function readKxmMigrationReceipt(root: string, options: KxmConfigOptions = {}): KxmMigrationReceiptCheck {
1526
+ const receiptPath = join(root, ...KXM_MIGRATION_RECEIPT_PATH.split("/"));
1527
1527
  const legacyFiles = legacyConfigFilesAt(root);
1528
1528
  if (!existsSync(receiptPath)) {
1529
1529
  return {
1530
- issues: legacyFiles.map((file) => issue("semantic", "legacy_vnext_conflict", file, "legacy and vNext configuration cannot coexist before an accepted migration receipt")),
1530
+ issues: legacyFiles.map((file) => issue("semantic", "legacy_kxm_conflict", file, "legacy and KXM configuration cannot coexist before an accepted migration receipt")),
1531
1531
  };
1532
1532
  }
1533
1533
  const receiptStat = lstatSync(receiptPath);
1534
1534
  if (receiptStat.isSymbolicLink() || !receiptStat.isFile()) {
1535
- return { issues: [issue("path", "migration_receipt_invalid", VNEXT_MIGRATION_RECEIPT_PATH, "migration receipt must be a regular file, not a link")] };
1535
+ return { issues: [issue("path", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "migration receipt must be a regular file, not a link")] };
1536
1536
  }
1537
1537
  let receipt: JsonObject;
1538
1538
  try {
1539
- receipt = parseRestrictedYaml(readFileSync(receiptPath), VNEXT_MIGRATION_RECEIPT_PATH);
1539
+ receipt = parseRestrictedYaml(readFileSync(receiptPath), KXM_MIGRATION_RECEIPT_PATH);
1540
1540
  } catch (error) {
1541
- if (error instanceof VnextConfigError) return { issues: [...error.issues] };
1541
+ if (error instanceof KxmConfigError) return { issues: [...error.issues] };
1542
1542
  throw error;
1543
1543
  }
1544
- const registry = new VnextSchemaRegistry(options.schemasDir);
1545
- const schemaIssues = registry.validateMigrationReceipt(receipt, VNEXT_MIGRATION_RECEIPT_PATH);
1544
+ const registry = new KxmSchemaRegistry(options.schemasDir);
1545
+ const schemaIssues = registry.validateMigrationReceipt(receipt, KXM_MIGRATION_RECEIPT_PATH);
1546
1546
  if (schemaIssues.length > 0) return { issues: schemaIssues };
1547
1547
  if (receipt.receiptSha256 !== migrationReceiptSelfHash(receipt)) {
1548
- return { issues: [issue("semantic", "migration_receipt_hash_mismatch", VNEXT_MIGRATION_RECEIPT_PATH, "receipt self-hash does not match its content")] };
1548
+ return { issues: [issue("semantic", "migration_receipt_hash_mismatch", KXM_MIGRATION_RECEIPT_PATH, "receipt self-hash does not match its content")] };
1549
1549
  }
1550
1550
  const sources = (Array.isArray(receipt.sources) ? receipt.sources : [])
1551
1551
  .map((candidate) => (candidate && typeof candidate === "object" && !Array.isArray(candidate) ? (candidate as JsonObject).path : undefined))
1552
1552
  .filter((candidate): candidate is string => typeof candidate === "string")
1553
1553
  .sort(compareCodeUnits);
1554
- const issues: VnextConfigIssue[] = [];
1554
+ const issues: KxmConfigIssue[] = [];
1555
1555
  const declared = new Set(sources);
1556
1556
  for (const file of legacyFiles) {
1557
1557
  if (!declared.has(file)) {
@@ -1585,15 +1585,15 @@ function discoverLegacyRoot(start: string): { root: string; inputs: string[] } |
1585
1585
  }
1586
1586
 
1587
1587
  /** Classify init without changing files. Applying create/repair/migration is a separate, explicit operation. */
1588
- export function planVnextInitialization(start = process.cwd(), options: VnextConfigOptions = {}): VnextInitializationPlan {
1588
+ export function planKxmInitialization(start = process.cwd(), options: KxmConfigOptions = {}): KxmInitializationPlan {
1589
1589
  const inspectedFrom = resolve(start);
1590
- const projectRoot = discoverVnextProjectRoot(inspectedFrom);
1590
+ const projectRoot = discoverKxmProjectRoot(inspectedFrom);
1591
1591
  if (projectRoot) {
1592
1592
  try {
1593
- const bundle = loadVnextProject(projectRoot, options);
1593
+ const bundle = loadKxmProject(projectRoot, options);
1594
1594
  return { mode: "ready", inspectedFrom, projectRoot, changesRequired: false, issues: [], legacyInputs: [], configRevision: bundle.configRevision };
1595
1595
  } catch (error) {
1596
- if (!(error instanceof VnextConfigError)) throw error;
1596
+ if (!(error instanceof KxmConfigError)) throw error;
1597
1597
  const legacyInputs = legacyInputsAt(projectRoot);
1598
1598
  if (legacyInputs.length > 0) {
1599
1599
  return { mode: "migrate", inspectedFrom, projectRoot, legacyRoot: projectRoot, changesRequired: true, issues: error.issues, legacyInputs };