@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.
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +41 -7
- package/docs/README.md +5 -3
- package/docs/agent-skills.md +1 -1
- package/docs/architecture.md +1 -1
- package/docs/configuration.md +28 -5
- package/docs/{vnext → contracts}/README.md +7 -7
- package/docs/{vnext → contracts}/architecture.md +2 -2
- package/docs/{vnext → contracts}/migration.md +25 -25
- package/docs/{vnext → contracts}/routing.md +2 -2
- package/docs/{vnext → contracts}/synchronization.md +1 -1
- package/docs/{vnext → contracts}/validation.md +7 -7
- package/docs/getting-started.md +1 -1
- package/docs/kb/qa-authentik-authentication.md +47 -0
- package/docs/kb/qa-extension-install-and-hub-bootstrap.md +68 -0
- package/docs/kb/qa-hub-on-a-public-host.md +31 -0
- package/docs/kb/qa-sqlite-vs-duckdb.md +18 -0
- package/docs/kb/qa-what-the-hub-stores.md +47 -0
- package/docs/packages.md +91 -0
- package/docs/templates/architecture.md +1 -1
- package/docs/test-matrix.md +6 -6
- package/docs/tui-components.md +131 -0
- package/examples/README.md +2 -2
- package/examples/{vnext → project}/.kxm/agents/critic-3.yaml +1 -1
- package/examples/{vnext → project}/README.md +4 -4
- package/package.json +18 -8
- package/packages/core/tui/CHANGELOG.md +19 -0
- package/packages/core/tui/LICENSE +21 -0
- package/packages/core/tui/README.md +45 -0
- package/packages/core/tui/dist/index.js +1439 -0
- package/packages/core/tui/src/adapters/pi.ts +73 -0
- package/packages/core/tui/src/adapters/terminal.ts +106 -0
- package/packages/core/tui/src/exports/index.ts +30 -0
- package/packages/core/tui/src/services/registry.ts +274 -0
- package/packages/core/tui/src/tui/keys.ts +130 -0
- package/packages/core/tui/src/tui/layout.ts +117 -0
- package/packages/core/tui/src/tui/panel.ts +435 -0
- package/packages/core/tui/src/tui/panelComponent.ts +208 -0
- package/packages/core/tui/src/tui/render.ts +309 -0
- package/packages/core/tui/src/tui/theme.ts +145 -0
- package/packages/core/tui/src/types/surface.ts +407 -0
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +681 -553
- package/plugins/kxm/dist/extension.js +18 -18
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/{vnext-runtime-supervisor.js → runtime-supervisor.js} +553 -553
- package/plugins/kxm/dist/runtime.js +608 -608
- package/plugins/kxm/dist/server.js +13 -13
- package/plugins/kxm/package.json +2 -2
- package/plugins/kxm/skills/kxm-project-setup/SKILL.md +2 -2
- package/plugins/kxm/skills/kxm-runs/SKILL.md +3 -3
- package/plugins/kxm/skills/kxm-session/SKILL.md +1 -1
- package/plugins/kxm/skills/kxm-workflow/SKILL.md +1 -1
- package/plugins/kxm/src/autocomplete.ts +4 -4
- package/plugins/kxm/src/{vnext-bindings.ts → bindings.ts} +48 -48
- package/plugins/kxm/src/cli/hub.ts +3 -3
- package/plugins/kxm/src/cli/{vnext.ts → project.ts} +106 -106
- package/plugins/kxm/src/cli/roles.ts +9 -9
- package/plugins/kxm/src/cli/system.ts +2 -2
- package/plugins/kxm/src/cli/tasks.ts +8 -8
- package/plugins/kxm/src/cli/workflows.ts +8 -8
- package/plugins/kxm/src/cli.ts +47 -47
- package/plugins/kxm/src/config.ts +69 -14
- package/plugins/kxm/src/database.ts +4 -4
- package/plugins/kxm/src/{vnext-engine-artifacts.ts → engine-artifacts.ts} +7 -7
- package/plugins/kxm/src/{vnext-engine-command.ts → engine-command.ts} +40 -40
- package/plugins/kxm/src/{vnext-engine-compile.ts → engine-compile.ts} +64 -64
- package/plugins/kxm/src/{vnext-engine-evidence.ts → engine-evidence.ts} +26 -26
- package/plugins/kxm/src/{vnext-engine-fold.ts → engine-fold.ts} +99 -99
- package/plugins/kxm/src/{vnext-engine-gate-records.ts → engine-gate-records.ts} +105 -105
- package/plugins/kxm/src/{vnext-engine-plan.ts → engine-plan.ts} +69 -69
- package/plugins/kxm/src/{vnext-engine.ts → engine.ts} +502 -502
- package/plugins/kxm/src/gate-hash.ts +10 -0
- package/plugins/kxm/src/{vnext-harness.ts → harness.ts} +1 -1
- package/plugins/kxm/src/hub.ts +1 -1
- package/plugins/kxm/src/init-guide-setup.ts +3 -3
- package/plugins/kxm/src/{vnext-init.ts → init.ts} +93 -93
- package/plugins/kxm/src/kxm-install-kind.ts +1 -1
- package/plugins/kxm/src/kxm-update-config.ts +2 -2
- package/plugins/kxm/src/local-snapshot.ts +23 -23
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/{vnext-migrate.ts → migrate.ts} +123 -123
- package/plugins/kxm/src/model-inventory.ts +1 -1
- package/plugins/kxm/src/{vnext-oneshot-evidence.ts → oneshot-evidence.ts} +2 -2
- package/plugins/kxm/src/{vnext-oneshot-process.ts → oneshot-process.ts} +4 -4
- package/plugins/kxm/src/{vnext-oneshot-producer.ts → oneshot-producer.ts} +24 -24
- package/plugins/kxm/src/{vnext-permission.ts → permission.ts} +86 -86
- package/plugins/kxm/src/{vnext-pi-producer.ts → pi-producer.ts} +13 -13
- package/plugins/kxm/src/{vnext-config.ts → project-config.ts} +177 -177
- package/plugins/kxm/src/{vnext-repair.ts → repair.ts} +159 -159
- package/plugins/kxm/src/restricted-yaml.d.mts +3 -3
- package/plugins/kxm/src/restricted-yaml.mjs +4 -4
- package/plugins/kxm/src/{vnext-runtime-owner.ts → runtime-owner.ts} +35 -35
- package/plugins/kxm/src/{vnext-runtime.ts → runtime-service.ts} +136 -136
- package/plugins/kxm/src/{vnext-runtime-store.ts → runtime-store.ts} +145 -145
- package/plugins/kxm/src/{vnext-runtime-supervisor.ts → runtime-supervisor.ts} +80 -80
- package/plugins/kxm/src/runtime.ts +6 -6
- package/plugins/kxm/src/session-work.ts +3 -3
- package/plugins/kxm/src/studio-layout.ts +6 -6
- package/plugins/kxm/src/{vnext-template.ts → template.ts} +33 -33
- package/plugins/kxm/src/tui.ts +10 -24
- package/schemas/{vnext/README.md → README.md} +3 -3
- package/schemas/{vnext/agent.schema.json → agent.schema.json} +1 -1
- package/schemas/{vnext/assignment-result.schema.json → assignment-result.schema.json} +1 -1
- package/schemas/{vnext/backup-manifest.schema.json → backup-manifest.schema.json} +1 -1
- package/schemas/{vnext/candidate.schema.json → candidate.schema.json} +1 -1
- package/schemas/{vnext/common.schema.json → common.schema.json} +2 -2
- package/schemas/{vnext/context-candidate.schema.json → context-candidate.schema.json} +1 -1
- package/schemas/{vnext/context-packet.schema.json → context-packet.schema.json} +1 -1
- package/schemas/{vnext/delivery-manifest.schema.json → delivery-manifest.schema.json} +1 -1
- package/schemas/{vnext/drive-receipt.schema.json → drive-receipt.schema.json} +2 -2
- package/schemas/{vnext/environment.schema.json → environment.schema.json} +1 -1
- package/schemas/{vnext/gate-registry.schema.json → gate-registry.schema.json} +1 -1
- package/schemas/{vnext/handoff-manifest.schema.json → handoff-manifest.schema.json} +1 -1
- package/schemas/{vnext/init-operation.schema.json → init-operation.schema.json} +1 -1
- package/schemas/{vnext/local-repository-bindings.schema.json → local-repository-bindings.schema.json} +1 -1
- package/schemas/{vnext/memory-record.schema.json → memory-record.schema.json} +1 -1
- package/schemas/{vnext/migration-decision.schema.json → migration-decision.schema.json} +1 -1
- package/schemas/{vnext/migration-plan.schema.json → migration-plan.schema.json} +1 -1
- package/schemas/{vnext/migration-receipt.schema.json → migration-receipt.schema.json} +1 -1
- package/schemas/{vnext/model.schema.json → model.schema.json} +1 -1
- package/schemas/{vnext/modes.schema.json → modes.schema.json} +1 -1
- package/schemas/{vnext/permission-diff.schema.json → permission-diff.schema.json} +1 -1
- package/schemas/policy-draft/README.md +2 -2
- package/schemas/{vnext/prices.schema.json → prices.schema.json} +1 -1
- package/schemas/{vnext/project.schema.json → project.schema.json} +1 -1
- package/schemas/{vnext/repository.schema.json → repository.schema.json} +1 -1
- package/schemas/{vnext/role.schema.json → role.schema.json} +1 -1
- package/schemas/{vnext/run-event.schema.json → run-event.schema.json} +1 -1
- package/schemas/{vnext/session-brief.schema.json → session-brief.schema.json} +2 -2
- package/schemas/{vnext/sync-event.schema.json → sync-event.schema.json} +1 -1
- package/schemas/{vnext/template-provenance.schema.json → template-provenance.schema.json} +1 -1
- package/schemas/{vnext/workflow.schema.json → workflow.schema.json} +1 -1
- package/scripts/build-package.mjs +59 -0
- package/scripts/build-runtime.mjs +3 -2
- package/scripts/check-generated.mjs +2 -1
- package/scripts/check-versions.mjs +12 -1
- package/scripts/docker-install-smoke.mjs +268 -0
- package/scripts/emit-codex-artifacts.mjs +1 -1
- package/scripts/kxm-bump-version.mjs +53 -3
- package/scripts/kxm-runtime-supervisor.mjs +3 -3
- package/scripts/package-surfaces.mjs +39 -0
- package/plugins/kxm/src/vnext-gate-hash.ts +0 -10
- /package/docs/{vnext → contracts}/effects-and-recovery.md +0 -0
- /package/docs/{vnext → contracts}/lifecycles.md +0 -0
- /package/docs/{vnext → contracts}/terminology.md +0 -0
- /package/examples/{vnext → project}/.kxm/agents/coordinator.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/agents/critic-1.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/agents/critic-2.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/agents/implementer.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/agents/planner.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/agents/reproducer.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/agents/reviewer.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/gates.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/models/critic-claude.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/models/critic-gemini.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/models/critic-grok.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/models/implementation.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/models/primary.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/prices.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/project/env.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/project.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/repo/repo.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/workflows/default.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/workflows/fix.yaml +0 -0
- /package/examples/{vnext → project}/.kxm/workflows/improve.yaml +0 -0
- /package/examples/{vnext → project}/records/assignment-result-recorded.json +0 -0
- /package/examples/{vnext → project}/records/assignment-result.json +0 -0
- /package/examples/{vnext → project}/records/context-candidate.json +0 -0
- /package/examples/{vnext → project}/records/delivery-manifest.json +0 -0
- /package/examples/{vnext → project}/records/effect-uncertainty-resolved-sync.json +0 -0
- /package/examples/{vnext → project}/records/effect-uncertainty-resolved.json +0 -0
- /package/examples/{vnext → project}/records/run-created.json +0 -0
- /package/examples/{vnext → project}/records/sync-event.json +0 -0
- /package/examples/{vnext → project}/repositories/api/.kxm/repo/env.yaml +0 -0
- /package/examples/{vnext → project}/repositories/api/.kxm/repo/repo.yaml +0 -0
- /package/examples/{vnext → project}/repositories/web/.kxm/repo/repo.yaml +0 -0
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -20586,7 +20586,7 @@ function enforceToolPolicy(commandName, env = process.env, options) {
|
|
|
20586
20586
|
return { allowed: true };
|
|
20587
20587
|
}
|
|
20588
20588
|
|
|
20589
|
-
// plugins/kxm/src/
|
|
20589
|
+
// plugins/kxm/src/project-config.ts
|
|
20590
20590
|
var import__ = __toESM(require__(), 1);
|
|
20591
20591
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
20592
20592
|
import { createHash as createHash6 } from "node:crypto";
|
|
@@ -20595,7 +20595,7 @@ import { basename as basename2, dirname as dirname4, extname, isAbsolute as isAb
|
|
|
20595
20595
|
|
|
20596
20596
|
// plugins/kxm/src/restricted-yaml.mjs
|
|
20597
20597
|
var import_yaml = __toESM(require_dist(), 1);
|
|
20598
|
-
var
|
|
20598
|
+
var KXM_YAML_LIMITS = Object.freeze({
|
|
20599
20599
|
maxDocumentBytes: 256 * 1024,
|
|
20600
20600
|
maxDepth: 32,
|
|
20601
20601
|
maxScalarBytes: 64 * 1024,
|
|
@@ -20666,7 +20666,7 @@ function assertJsonValue(value, label, path4 = "$", seen = /* @__PURE__ */ new S
|
|
|
20666
20666
|
}
|
|
20667
20667
|
seen.delete(value);
|
|
20668
20668
|
}
|
|
20669
|
-
function parseRestrictedYaml(input, label = "<yaml>", limits =
|
|
20669
|
+
function parseRestrictedYaml(input, label = "<yaml>", limits = KXM_YAML_LIMITS) {
|
|
20670
20670
|
const byteLength = typeof input === "string" ? Buffer.byteLength(input, "utf8") : input.byteLength;
|
|
20671
20671
|
if (byteLength > limits.maxDocumentBytes) {
|
|
20672
20672
|
fail("parse", "document_too_large", label, `document exceeds ${limits.maxDocumentBytes} bytes`);
|
|
@@ -20718,13 +20718,13 @@ function parseRestrictedYaml(input, label = "<yaml>", limits = VNEXT_YAML_LIMITS
|
|
|
20718
20718
|
return value;
|
|
20719
20719
|
}
|
|
20720
20720
|
|
|
20721
|
-
// plugins/kxm/src/
|
|
20721
|
+
// plugins/kxm/src/template.ts
|
|
20722
20722
|
var import_yaml2 = __toESM(require_dist(), 1);
|
|
20723
20723
|
import { createHash as createHash5 } from "node:crypto";
|
|
20724
|
-
var
|
|
20725
|
-
var
|
|
20726
|
-
var
|
|
20727
|
-
var
|
|
20724
|
+
var KXM_TEMPLATE_ID = "builtin-minimal";
|
|
20725
|
+
var KXM_TEMPLATE_PROVENANCE_PATH = ".kxm/template-provenance.yaml";
|
|
20726
|
+
var CURRENT_KXM_TEMPLATE_VARIANT = "v4-registry";
|
|
20727
|
+
var SUPPORTED_KXM_TEMPLATE_VARIANTS = ["v1", "v2", "v3-policy", "v4-registry"];
|
|
20728
20728
|
function compareCodeUnits2(left, right) {
|
|
20729
20729
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
20730
20730
|
}
|
|
@@ -20735,7 +20735,7 @@ function canonicalJson(value) {
|
|
|
20735
20735
|
if (Array.isArray(value)) return `[${value.map((candidate) => canonicalJson(candidate)).join(",")}]`;
|
|
20736
20736
|
return `{${Object.keys(value).sort(compareCodeUnits2).map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(",")}}`;
|
|
20737
20737
|
}
|
|
20738
|
-
function
|
|
20738
|
+
function kxmContentSha256(input) {
|
|
20739
20739
|
return `sha256:${createHash5("sha256").update(input).digest("hex")}`;
|
|
20740
20740
|
}
|
|
20741
20741
|
function authorityProjection(value) {
|
|
@@ -20746,8 +20746,8 @@ function authorityProjection(value) {
|
|
|
20746
20746
|
if (projected.schema === "kxm.workflow.v1") delete projected.description;
|
|
20747
20747
|
return projected;
|
|
20748
20748
|
}
|
|
20749
|
-
function
|
|
20750
|
-
return
|
|
20749
|
+
function kxmAuthoritySha256(value) {
|
|
20750
|
+
return kxmContentSha256(canonicalJson(authorityProjection(value)));
|
|
20751
20751
|
}
|
|
20752
20752
|
function coreTemplate(projectId, projectName, variant) {
|
|
20753
20753
|
const files = /* @__PURE__ */ new Map([
|
|
@@ -20863,14 +20863,14 @@ function coreTemplate(projectId, projectName, variant) {
|
|
|
20863
20863
|
return files;
|
|
20864
20864
|
}
|
|
20865
20865
|
function provenanceRevision(files) {
|
|
20866
|
-
return
|
|
20866
|
+
return kxmContentSha256(canonicalJson(files.map((file) => ({
|
|
20867
20867
|
path: file.path,
|
|
20868
20868
|
sha256: file.sha256,
|
|
20869
20869
|
authoritySha256: file.authoritySha256,
|
|
20870
20870
|
bytes: file.bytes
|
|
20871
20871
|
}))));
|
|
20872
20872
|
}
|
|
20873
|
-
function
|
|
20873
|
+
function renderKxmTemplate(projectId, projectName, variant = CURRENT_KXM_TEMPLATE_VARIANT) {
|
|
20874
20874
|
const values = coreTemplate(projectId, projectName, variant);
|
|
20875
20875
|
const coreFiles = /* @__PURE__ */ new Map();
|
|
20876
20876
|
const records = [...values.entries()].map(([path4, value]) => {
|
|
@@ -20878,22 +20878,22 @@ function renderVnextTemplate(projectId, projectName, variant = CURRENT_VNEXT_TEM
|
|
|
20878
20878
|
coreFiles.set(path4, bytes);
|
|
20879
20879
|
return {
|
|
20880
20880
|
path: path4,
|
|
20881
|
-
sha256:
|
|
20882
|
-
authoritySha256:
|
|
20881
|
+
sha256: kxmContentSha256(bytes),
|
|
20882
|
+
authoritySha256: kxmAuthoritySha256(value),
|
|
20883
20883
|
bytes: bytes.byteLength
|
|
20884
20884
|
};
|
|
20885
20885
|
}).sort((left, right) => compareCodeUnits2(left.path, right.path));
|
|
20886
20886
|
const templateRevision = provenanceRevision(records);
|
|
20887
20887
|
const provenance = {
|
|
20888
20888
|
schema: "kxm.template-provenance.v1",
|
|
20889
|
-
templateId:
|
|
20889
|
+
templateId: KXM_TEMPLATE_ID,
|
|
20890
20890
|
templateRevision,
|
|
20891
20891
|
inputs: { projectId, projectName },
|
|
20892
20892
|
files: records
|
|
20893
20893
|
};
|
|
20894
20894
|
const fileEntries = [...coreFiles.entries()];
|
|
20895
20895
|
fileEntries.push([
|
|
20896
|
-
|
|
20896
|
+
KXM_TEMPLATE_PROVENANCE_PATH,
|
|
20897
20897
|
Buffer.from((0, import_yaml2.stringify)(provenance, { lineWidth: 0 }), "utf8")
|
|
20898
20898
|
]);
|
|
20899
20899
|
fileEntries.sort(([left], [right]) => compareCodeUnits2(left, right));
|
|
@@ -20901,15 +20901,15 @@ function renderVnextTemplate(projectId, projectName, variant = CURRENT_VNEXT_TEM
|
|
|
20901
20901
|
return { projectId, projectName, templateRevision, provenance, files, values };
|
|
20902
20902
|
}
|
|
20903
20903
|
function validatedTemplateProvenance(value) {
|
|
20904
|
-
if (value.schema !== "kxm.template-provenance.v1" || value.templateId !==
|
|
20904
|
+
if (value.schema !== "kxm.template-provenance.v1" || value.templateId !== KXM_TEMPLATE_ID) return void 0;
|
|
20905
20905
|
const candidate = value;
|
|
20906
20906
|
return provenanceRevision(candidate.files) === candidate.templateRevision ? candidate : void 0;
|
|
20907
20907
|
}
|
|
20908
|
-
function
|
|
20908
|
+
function resolveKxmTemplateBaseline(value) {
|
|
20909
20909
|
const candidate = validatedTemplateProvenance(value);
|
|
20910
20910
|
if (!candidate) return void 0;
|
|
20911
|
-
for (const variant of
|
|
20912
|
-
const known =
|
|
20911
|
+
for (const variant of SUPPORTED_KXM_TEMPLATE_VARIANTS) {
|
|
20912
|
+
const known = renderKxmTemplate(candidate.inputs.projectId, candidate.inputs.projectName, variant).provenance;
|
|
20913
20913
|
if (known.templateRevision === candidate.templateRevision && canonicalJson(known) === canonicalJson(candidate)) {
|
|
20914
20914
|
return candidate;
|
|
20915
20915
|
}
|
|
@@ -20917,12 +20917,12 @@ function resolveVnextTemplateBaseline(value) {
|
|
|
20917
20917
|
return void 0;
|
|
20918
20918
|
}
|
|
20919
20919
|
|
|
20920
|
-
// plugins/kxm/src/
|
|
20920
|
+
// plugins/kxm/src/harness.ts
|
|
20921
20921
|
import { spawnSync } from "node:child_process";
|
|
20922
20922
|
import { existsSync as existsSync5 } from "node:fs";
|
|
20923
20923
|
import { win32 as win32Path } from "node:path";
|
|
20924
20924
|
|
|
20925
|
-
// plugins/kxm/src/
|
|
20925
|
+
// plugins/kxm/src/oneshot-process.ts
|
|
20926
20926
|
import { spawn } from "node:child_process";
|
|
20927
20927
|
var OUTPUT_LIMIT = 8 * 1024 * 1024;
|
|
20928
20928
|
var KILL_GRACE_MS = 250;
|
|
@@ -21075,7 +21075,7 @@ function defaultSpawn(command, args, options) {
|
|
|
21075
21075
|
});
|
|
21076
21076
|
}
|
|
21077
21077
|
|
|
21078
|
-
// plugins/kxm/src/
|
|
21078
|
+
// plugins/kxm/src/harness.ts
|
|
21079
21079
|
var DEFAULT_HARNESS = "pi";
|
|
21080
21080
|
var UNKNOWN_AUTH_HARNESSES = /* @__PURE__ */ new Set(["deepseek"]);
|
|
21081
21081
|
var GROK_LOGIN_LINE = "You are logged in with grok.com.";
|
|
@@ -21975,20 +21975,20 @@ function formatHarnessUpdate(steps) {
|
|
|
21975
21975
|
}).join("\n");
|
|
21976
21976
|
}
|
|
21977
21977
|
|
|
21978
|
-
// plugins/kxm/src/
|
|
21979
|
-
var
|
|
21978
|
+
// plugins/kxm/src/project-config.ts
|
|
21979
|
+
var KxmConfigError = class extends Error {
|
|
21980
21980
|
issues;
|
|
21981
21981
|
constructor(issues) {
|
|
21982
21982
|
const sorted = sortIssues2(issues);
|
|
21983
21983
|
super(sorted.map((issue3) => `${issue3.file}: ${issue3.code}: ${issue3.message}`).join("\n"));
|
|
21984
|
-
this.name = "
|
|
21984
|
+
this.name = "KxmConfigError";
|
|
21985
21985
|
this.issues = sorted;
|
|
21986
21986
|
}
|
|
21987
21987
|
};
|
|
21988
|
-
function
|
|
21989
|
-
return join6(findKxmRepoRoot(import.meta.url), "schemas"
|
|
21988
|
+
function defaultKxmSchemaDir() {
|
|
21989
|
+
return join6(findKxmRepoRoot(import.meta.url), "schemas");
|
|
21990
21990
|
}
|
|
21991
|
-
var DEFAULT_SCHEMA_DIR =
|
|
21991
|
+
var DEFAULT_SCHEMA_DIR = defaultKxmSchemaDir();
|
|
21992
21992
|
var RESOURCE_SCHEMA = Object.freeze({
|
|
21993
21993
|
project: { identity: "kxm.project.v1", file: "project.schema.json" },
|
|
21994
21994
|
repository: { identity: "kxm.repository.v1", file: "repository.schema.json" },
|
|
@@ -22020,16 +22020,16 @@ function issue2(phase, code, file, message) {
|
|
|
22020
22020
|
return { phase, code, file, message };
|
|
22021
22021
|
}
|
|
22022
22022
|
function fail2(phase, code, file, message) {
|
|
22023
|
-
throw new
|
|
22023
|
+
throw new KxmConfigError([issue2(phase, code, file, message)]);
|
|
22024
22024
|
}
|
|
22025
22025
|
function isJsonObject2(value) {
|
|
22026
22026
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
22027
22027
|
}
|
|
22028
|
-
function parseRestrictedYaml2(input, label = "<yaml>", limits =
|
|
22028
|
+
function parseRestrictedYaml2(input, label = "<yaml>", limits = KXM_YAML_LIMITS) {
|
|
22029
22029
|
try {
|
|
22030
22030
|
return parseRestrictedYaml(input, label, limits);
|
|
22031
22031
|
} catch (error) {
|
|
22032
|
-
if (error instanceof RestrictedYamlError) throw new
|
|
22032
|
+
if (error instanceof RestrictedYamlError) throw new KxmConfigError(error.issues);
|
|
22033
22033
|
throw error;
|
|
22034
22034
|
}
|
|
22035
22035
|
}
|
|
@@ -22038,7 +22038,7 @@ function readJsonObject(file) {
|
|
|
22038
22038
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`${file} is not a JSON object`);
|
|
22039
22039
|
return parsed;
|
|
22040
22040
|
}
|
|
22041
|
-
var
|
|
22041
|
+
var KxmSchemaRegistry = class {
|
|
22042
22042
|
schemasDir;
|
|
22043
22043
|
ajv;
|
|
22044
22044
|
validators = /* @__PURE__ */ new Map();
|
|
@@ -22078,19 +22078,19 @@ var VnextSchemaRegistry = class {
|
|
|
22078
22078
|
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, runEventFile)));
|
|
22079
22079
|
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, driveReceiptFile)));
|
|
22080
22080
|
for (const [kind, definition] of Object.entries(RESOURCE_SCHEMA)) {
|
|
22081
|
-
const validator = this.ajv.getSchema(`https://schemas.kxm.dev
|
|
22081
|
+
const validator = this.ajv.getSchema(`https://schemas.kxm.dev/${definition.file}`);
|
|
22082
22082
|
if (!validator) throw new Error(`schema did not compile: ${definition.file}`);
|
|
22083
22083
|
this.validators.set(kind, validator);
|
|
22084
22084
|
}
|
|
22085
|
-
const localBindingsValidator = this.ajv.getSchema(`https://schemas.kxm.dev
|
|
22086
|
-
const templateProvenanceValidator = this.ajv.getSchema(`https://schemas.kxm.dev
|
|
22087
|
-
const initOperationValidator = this.ajv.getSchema(`https://schemas.kxm.dev
|
|
22088
|
-
const migrationPlanValidator = this.ajv.getSchema(`https://schemas.kxm.dev
|
|
22089
|
-
const migrationDecisionValidator = this.ajv.getSchema(`https://schemas.kxm.dev
|
|
22090
|
-
const migrationReceiptValidator = this.ajv.getSchema(`https://schemas.kxm.dev
|
|
22091
|
-
const permissionDiffValidator = this.ajv.getSchema(`https://schemas.kxm.dev
|
|
22092
|
-
const runEventValidator = this.ajv.getSchema(`https://schemas.kxm.dev
|
|
22093
|
-
const driveReceiptValidator = this.ajv.getSchema(`https://schemas.kxm.dev
|
|
22085
|
+
const localBindingsValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${localBindingsFile}`);
|
|
22086
|
+
const templateProvenanceValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${templateProvenanceFile}`);
|
|
22087
|
+
const initOperationValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${initOperationFile}`);
|
|
22088
|
+
const migrationPlanValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${migrationPlanFile}`);
|
|
22089
|
+
const migrationDecisionValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${migrationDecisionFile}`);
|
|
22090
|
+
const migrationReceiptValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${migrationReceiptFile}`);
|
|
22091
|
+
const permissionDiffValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${permissionDiffFile}`);
|
|
22092
|
+
const runEventValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${runEventFile}`);
|
|
22093
|
+
const driveReceiptValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${driveReceiptFile}`);
|
|
22094
22094
|
if (!localBindingsValidator) throw new Error(`schema did not compile: ${localBindingsFile}`);
|
|
22095
22095
|
if (!templateProvenanceValidator) throw new Error(`schema did not compile: ${templateProvenanceFile}`);
|
|
22096
22096
|
if (!initOperationValidator) throw new Error(`schema did not compile: ${initOperationFile}`);
|
|
@@ -22116,7 +22116,7 @@ var VnextSchemaRegistry = class {
|
|
|
22116
22116
|
return [issue2("schema", "schema_identity_mismatch", file, `expected ${definition.identity}, received ${String(value.schema)}`)];
|
|
22117
22117
|
}
|
|
22118
22118
|
const validator = this.validators.get(kind);
|
|
22119
|
-
if (!validator) throw new Error(`missing
|
|
22119
|
+
if (!validator) throw new Error(`missing KXM validator for ${kind}`);
|
|
22120
22120
|
if (validator(value)) return [];
|
|
22121
22121
|
return (validator.errors ?? []).map((error) => schemaIssue(file, error));
|
|
22122
22122
|
}
|
|
@@ -22194,7 +22194,7 @@ function portableBindingIssue(root, pathHint, repositoryId) {
|
|
|
22194
22194
|
}
|
|
22195
22195
|
return void 0;
|
|
22196
22196
|
}
|
|
22197
|
-
function
|
|
22197
|
+
function kxmPortablePath(path4) {
|
|
22198
22198
|
return portablePath(path4);
|
|
22199
22199
|
}
|
|
22200
22200
|
function portablePath(path4) {
|
|
@@ -22203,11 +22203,11 @@ function portablePath(path4) {
|
|
|
22203
22203
|
const segments = path4.split("/");
|
|
22204
22204
|
return segments.every((segment) => segment.length > 0 && segment !== "." && segment !== ".." && !WINDOWS_RESERVED.test((segment.split(".")[0] ?? segment).replace(/[ .]+$/g, "")) && !segment.endsWith(".") && !segment.endsWith(" ") && !segment.includes(":"));
|
|
22205
22205
|
}
|
|
22206
|
-
function
|
|
22206
|
+
function kxmResourceIdentifier(id) {
|
|
22207
22207
|
return id.length <= 64 && IDENTIFIER.test(id) && !WINDOWS_RESERVED.test(id);
|
|
22208
22208
|
}
|
|
22209
22209
|
function resourceIdentifier(id) {
|
|
22210
|
-
return
|
|
22210
|
+
return kxmResourceIdentifier(id);
|
|
22211
22211
|
}
|
|
22212
22212
|
function displayPath(root, file) {
|
|
22213
22213
|
const candidate = relative(root, file).replaceAll("\\", "/");
|
|
@@ -22238,7 +22238,7 @@ function readResource(registry, root, file, logicalPath, kind, id, containmentRo
|
|
|
22238
22238
|
if (!stat.isFile()) fail2("path", "resource_not_file", label, "configuration resource must be a regular file");
|
|
22239
22239
|
const value = parseRestrictedYaml2(readFileSync5(file), label);
|
|
22240
22240
|
const issues = registry.validate(kind, value, label);
|
|
22241
|
-
if (issues.length > 0) throw new
|
|
22241
|
+
if (issues.length > 0) throw new KxmConfigError(issues);
|
|
22242
22242
|
return { kind, ...id === void 0 ? {} : { id }, file, logicalPath, value };
|
|
22243
22243
|
}
|
|
22244
22244
|
function readTemplateProvenance(registry, root) {
|
|
@@ -22261,8 +22261,8 @@ function readTemplateProvenance(registry, root) {
|
|
|
22261
22261
|
}
|
|
22262
22262
|
const value = parseRestrictedYaml2(readFileSync5(file), label);
|
|
22263
22263
|
const issues = registry.validateTemplateProvenance(value, label);
|
|
22264
|
-
if (issues.length > 0) throw new
|
|
22265
|
-
if (!
|
|
22264
|
+
if (issues.length > 0) throw new KxmConfigError(issues);
|
|
22265
|
+
if (!resolveKxmTemplateBaseline(value)) {
|
|
22266
22266
|
fail2("semantic", "template_provenance_revision_invalid", label, "template provenance does not exactly match a supported built-in baseline");
|
|
22267
22267
|
}
|
|
22268
22268
|
const files = Array.isArray(value.files) ? value.files : [];
|
|
@@ -22322,11 +22322,11 @@ function listNamedResources(registry, root, directory, logicalDirectory, kind) {
|
|
|
22322
22322
|
const resource = readResource(registry, root, join6(directory, entry.name), `${logicalDirectory}/${id}.yaml`, kind, id);
|
|
22323
22323
|
resources.set(id, resource);
|
|
22324
22324
|
} catch (error) {
|
|
22325
|
-
if (error instanceof
|
|
22325
|
+
if (error instanceof KxmConfigError) issues.push(...error.issues);
|
|
22326
22326
|
else throw error;
|
|
22327
22327
|
}
|
|
22328
22328
|
}
|
|
22329
|
-
if (issues.length > 0) throw new
|
|
22329
|
+
if (issues.length > 0) throw new KxmConfigError(issues);
|
|
22330
22330
|
return resources;
|
|
22331
22331
|
}
|
|
22332
22332
|
function valuesOf(object2, field) {
|
|
@@ -22489,7 +22489,7 @@ function validateToolPolicy(resource, policy, label, issues) {
|
|
|
22489
22489
|
if (allowed.has(tool)) issues.push(issue2("semantic", "tool_policy_contradiction", resource.logicalPath, `${label} both allows and denies ${tool}`));
|
|
22490
22490
|
}
|
|
22491
22491
|
}
|
|
22492
|
-
function
|
|
22492
|
+
function validateKxmResources(resources, options = {}) {
|
|
22493
22493
|
const make = (logicalPath, kind, id, value) => ({
|
|
22494
22494
|
kind,
|
|
22495
22495
|
...id === void 0 ? {} : { id },
|
|
@@ -22875,7 +22875,7 @@ function validateBundle(project, repositories, agents, models, workflows, enviro
|
|
|
22875
22875
|
}
|
|
22876
22876
|
}
|
|
22877
22877
|
} catch (error) {
|
|
22878
|
-
if (error instanceof
|
|
22878
|
+
if (error instanceof KxmConfigError) {
|
|
22879
22879
|
issues.push(...error.issues);
|
|
22880
22880
|
}
|
|
22881
22881
|
}
|
|
@@ -22883,13 +22883,13 @@ function validateBundle(project, repositories, agents, models, workflows, enviro
|
|
|
22883
22883
|
}
|
|
22884
22884
|
return sortIssues2(issues);
|
|
22885
22885
|
}
|
|
22886
|
-
function
|
|
22886
|
+
function kxmCanonicalJson(value) {
|
|
22887
22887
|
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
22888
|
-
if (Array.isArray(value)) return `[${value.map((candidate) =>
|
|
22889
|
-
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${
|
|
22888
|
+
if (Array.isArray(value)) return `[${value.map((candidate) => kxmCanonicalJson(candidate)).join(",")}]`;
|
|
22889
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${kxmCanonicalJson(value[key])}`).join(",")}}`;
|
|
22890
22890
|
}
|
|
22891
22891
|
function canonicalize(value) {
|
|
22892
|
-
return
|
|
22892
|
+
return kxmCanonicalJson(value);
|
|
22893
22893
|
}
|
|
22894
22894
|
function bundleRevision(resources) {
|
|
22895
22895
|
const hash = createHash6("sha256");
|
|
@@ -22917,25 +22917,25 @@ function discoverGitRoot(start = process.cwd()) {
|
|
|
22917
22917
|
const root = resolve3(result.stdout.trim());
|
|
22918
22918
|
return existsSync6(root) && lstatSync(root).isDirectory() ? root : void 0;
|
|
22919
22919
|
}
|
|
22920
|
-
function
|
|
22920
|
+
function discoverKxmProjectRoot(start = process.cwd()) {
|
|
22921
22921
|
const gitRoot = discoverGitRoot(start);
|
|
22922
22922
|
return gitRoot && existsSync6(join6(gitRoot, ".kxm", "project.yaml")) ? gitRoot : void 0;
|
|
22923
22923
|
}
|
|
22924
22924
|
function assertNoRegisteredGates(options) {
|
|
22925
22925
|
if ("registeredGates" in options) {
|
|
22926
|
-
throw new
|
|
22926
|
+
throw new KxmConfigError([issue2("semantic", "registered_gates_removed", ".kxm/gates.yaml", "registeredGates was removed; declare gates in .kxm/gates.yaml")]);
|
|
22927
22927
|
}
|
|
22928
22928
|
}
|
|
22929
|
-
function
|
|
22929
|
+
function loadKxmProject(projectRoot, options = {}) {
|
|
22930
22930
|
assertNoRegisteredGates(options);
|
|
22931
22931
|
const root = resolve3(projectRoot);
|
|
22932
22932
|
let migrationReceipt;
|
|
22933
22933
|
if (legacyConfigFilesAt(root).length > 0 && options.allowUnreceiptedLegacyConfig !== true) {
|
|
22934
|
-
const receiptCheck =
|
|
22935
|
-
if (receiptCheck.issues.length > 0) throw new
|
|
22934
|
+
const receiptCheck = readKxmMigrationReceipt(root, options);
|
|
22935
|
+
if (receiptCheck.issues.length > 0) throw new KxmConfigError(receiptCheck.issues);
|
|
22936
22936
|
migrationReceipt = receiptCheck.receipt;
|
|
22937
22937
|
}
|
|
22938
|
-
const registry = new
|
|
22938
|
+
const registry = new KxmSchemaRegistry(options.schemasDir);
|
|
22939
22939
|
const project = readResource(registry, root, join6(root, ".kxm", "project.yaml"), ".kxm/project.yaml", "project");
|
|
22940
22940
|
const earlyIssues = [];
|
|
22941
22941
|
validatePortablePaths(project, earlyIssues);
|
|
@@ -22947,7 +22947,7 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22947
22947
|
}
|
|
22948
22948
|
}
|
|
22949
22949
|
if (migrationReceipt && stringValue(migrationReceipt.projectId) !== stringValue(project.value.id)) {
|
|
22950
|
-
earlyIssues.push(issue2("semantic", "migration_project_mismatch",
|
|
22950
|
+
earlyIssues.push(issue2("semantic", "migration_project_mismatch", KXM_MIGRATION_RECEIPT_PATH, "migration receipt belongs to a different project identity"));
|
|
22951
22951
|
}
|
|
22952
22952
|
const declaredRepositoryIds = new Set(valuesOf(project.value, "repositories").map((candidate) => stringValue(objectValue(candidate)?.id)).filter((candidate) => candidate !== void 0));
|
|
22953
22953
|
for (const repositoryId of Object.keys(options.repositoryBindings ?? {}).sort(compareCodeUnits3)) {
|
|
@@ -22957,7 +22957,7 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22957
22957
|
earlyIssues.push(issue2("reference", "repository_binding_unknown", ".kxm/project.yaml", `host-local binding references unknown repository ${repositoryId}`));
|
|
22958
22958
|
}
|
|
22959
22959
|
}
|
|
22960
|
-
if (earlyIssues.length > 0) throw new
|
|
22960
|
+
if (earlyIssues.length > 0) throw new KxmConfigError(earlyIssues);
|
|
22961
22961
|
const agents = listNamedResources(registry, root, join6(root, ".kxm", "agents"), ".kxm/agents", "agent");
|
|
22962
22962
|
const models = listNamedResources(registry, root, join6(root, ".kxm", "models"), ".kxm/models", "model");
|
|
22963
22963
|
const workflows = listNamedResources(registry, root, join6(root, ".kxm", "workflows"), ".kxm/workflows", "workflow");
|
|
@@ -22971,7 +22971,7 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22971
22971
|
try {
|
|
22972
22972
|
environments.push(readResource(registry, root, projectEnvironment, ".kxm/project/env.yaml", "environment"));
|
|
22973
22973
|
} catch (error) {
|
|
22974
|
-
if (error instanceof
|
|
22974
|
+
if (error instanceof KxmConfigError) loadIssues.push(...error.issues);
|
|
22975
22975
|
else throw error;
|
|
22976
22976
|
}
|
|
22977
22977
|
}
|
|
@@ -23044,7 +23044,7 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
23044
23044
|
definitionValidated = repositories.get(repositoryId) === resource;
|
|
23045
23045
|
}
|
|
23046
23046
|
} catch (error) {
|
|
23047
|
-
if (error instanceof
|
|
23047
|
+
if (error instanceof KxmConfigError) loadIssues.push(...error.issues);
|
|
23048
23048
|
else throw error;
|
|
23049
23049
|
}
|
|
23050
23050
|
} else if (required || hasLocalBinding) {
|
|
@@ -23058,15 +23058,15 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
23058
23058
|
try {
|
|
23059
23059
|
environments.push(readResource(registry, root, environmentFile, `.kxm/repositories/${repositoryId}/env.yaml`, "environment", void 0, binding));
|
|
23060
23060
|
} catch (error) {
|
|
23061
|
-
if (error instanceof
|
|
23061
|
+
if (error instanceof KxmConfigError) loadIssues.push(...error.issues);
|
|
23062
23062
|
else throw error;
|
|
23063
23063
|
}
|
|
23064
23064
|
}
|
|
23065
23065
|
}
|
|
23066
23066
|
}
|
|
23067
|
-
if (loadIssues.length > 0) throw new
|
|
23067
|
+
if (loadIssues.length > 0) throw new KxmConfigError(loadIssues);
|
|
23068
23068
|
const issues = validateBundle(project, repositories, agents, models, workflows, environments, options, gateRegistry, root);
|
|
23069
|
-
if (issues.length > 0) throw new
|
|
23069
|
+
if (issues.length > 0) throw new KxmConfigError(issues);
|
|
23070
23070
|
const resources = [project, ...repositories.values(), ...agents.values(), ...models.values(), ...workflows.values(), ...environments, ...gateRegistry ? [gateRegistry] : []].sort((left, right) => compareCodeUnits3(left.logicalPath, right.logicalPath));
|
|
23071
23071
|
return {
|
|
23072
23072
|
projectRoot: root,
|
|
@@ -23083,10 +23083,10 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
23083
23083
|
configRevision: bundleRevision(resources)
|
|
23084
23084
|
};
|
|
23085
23085
|
}
|
|
23086
|
-
function
|
|
23086
|
+
function verifyKxmMigrationReceiptTarget(root, receipt, resources, configRevision) {
|
|
23087
23087
|
const issues = [];
|
|
23088
23088
|
if (receipt.configRevision !== configRevision) {
|
|
23089
|
-
issues.push(issue2("semantic", "migration_target_changed",
|
|
23089
|
+
issues.push(issue2("semantic", "migration_target_changed", KXM_MIGRATION_RECEIPT_PATH, "target configuration revision no longer matches the migration receipt"));
|
|
23090
23090
|
}
|
|
23091
23091
|
const declared = /* @__PURE__ */ new Map();
|
|
23092
23092
|
for (const candidate of Array.isArray(receipt.resources) ? receipt.resources : []) {
|
|
@@ -23131,7 +23131,7 @@ function legacyInputsAt(root) {
|
|
|
23131
23131
|
];
|
|
23132
23132
|
return candidates.filter((candidate) => existsSync6(join6(root, ...candidate.split("/"))));
|
|
23133
23133
|
}
|
|
23134
|
-
var
|
|
23134
|
+
var KXM_MIGRATION_RECEIPT_PATH = ".kxm/migration-receipt.yaml";
|
|
23135
23135
|
var LEGACY_CONFIG_FILES = [".kxm/config/agents.json", ".kxm/config/gates.json"];
|
|
23136
23136
|
function legacyConfigFilesAt(root) {
|
|
23137
23137
|
const files = [];
|
|
@@ -23169,32 +23169,32 @@ function hashFileRecord(root, relativePath) {
|
|
|
23169
23169
|
}
|
|
23170
23170
|
function migrationReceiptSelfHash(receipt) {
|
|
23171
23171
|
const { receiptSha256: _ignored, ...unsigned } = receipt;
|
|
23172
|
-
return `sha256:${createHash6("sha256").update(
|
|
23172
|
+
return `sha256:${createHash6("sha256").update(kxmCanonicalJson(unsigned), "utf8").digest("hex")}`;
|
|
23173
23173
|
}
|
|
23174
|
-
function
|
|
23175
|
-
const receiptPath = join6(root, ...
|
|
23174
|
+
function readKxmMigrationReceipt(root, options = {}) {
|
|
23175
|
+
const receiptPath = join6(root, ...KXM_MIGRATION_RECEIPT_PATH.split("/"));
|
|
23176
23176
|
const legacyFiles = legacyConfigFilesAt(root);
|
|
23177
23177
|
if (!existsSync6(receiptPath)) {
|
|
23178
23178
|
return {
|
|
23179
|
-
issues: legacyFiles.map((file) => issue2("semantic", "
|
|
23179
|
+
issues: legacyFiles.map((file) => issue2("semantic", "legacy_kxm_conflict", file, "legacy and KXM configuration cannot coexist before an accepted migration receipt"))
|
|
23180
23180
|
};
|
|
23181
23181
|
}
|
|
23182
23182
|
const receiptStat = lstatSync(receiptPath);
|
|
23183
23183
|
if (receiptStat.isSymbolicLink() || !receiptStat.isFile()) {
|
|
23184
|
-
return { issues: [issue2("path", "migration_receipt_invalid",
|
|
23184
|
+
return { issues: [issue2("path", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "migration receipt must be a regular file, not a link")] };
|
|
23185
23185
|
}
|
|
23186
23186
|
let receipt;
|
|
23187
23187
|
try {
|
|
23188
|
-
receipt = parseRestrictedYaml2(readFileSync5(receiptPath),
|
|
23188
|
+
receipt = parseRestrictedYaml2(readFileSync5(receiptPath), KXM_MIGRATION_RECEIPT_PATH);
|
|
23189
23189
|
} catch (error) {
|
|
23190
|
-
if (error instanceof
|
|
23190
|
+
if (error instanceof KxmConfigError) return { issues: [...error.issues] };
|
|
23191
23191
|
throw error;
|
|
23192
23192
|
}
|
|
23193
|
-
const registry = new
|
|
23194
|
-
const schemaIssues = registry.validateMigrationReceipt(receipt,
|
|
23193
|
+
const registry = new KxmSchemaRegistry(options.schemasDir);
|
|
23194
|
+
const schemaIssues = registry.validateMigrationReceipt(receipt, KXM_MIGRATION_RECEIPT_PATH);
|
|
23195
23195
|
if (schemaIssues.length > 0) return { issues: schemaIssues };
|
|
23196
23196
|
if (receipt.receiptSha256 !== migrationReceiptSelfHash(receipt)) {
|
|
23197
|
-
return { issues: [issue2("semantic", "migration_receipt_hash_mismatch",
|
|
23197
|
+
return { issues: [issue2("semantic", "migration_receipt_hash_mismatch", KXM_MIGRATION_RECEIPT_PATH, "receipt self-hash does not match its content")] };
|
|
23198
23198
|
}
|
|
23199
23199
|
const sources = (Array.isArray(receipt.sources) ? receipt.sources : []).map((candidate) => candidate && typeof candidate === "object" && !Array.isArray(candidate) ? candidate.path : void 0).filter((candidate) => typeof candidate === "string").sort(compareCodeUnits3);
|
|
23200
23200
|
const issues = [];
|
|
@@ -23224,15 +23224,15 @@ function discoverLegacyRoot(start) {
|
|
|
23224
23224
|
const inputs = legacyInputsAt(candidate);
|
|
23225
23225
|
return inputs.length > 0 ? { root: candidate, inputs } : void 0;
|
|
23226
23226
|
}
|
|
23227
|
-
function
|
|
23227
|
+
function planKxmInitialization(start = process.cwd(), options = {}) {
|
|
23228
23228
|
const inspectedFrom = resolve3(start);
|
|
23229
|
-
const projectRoot =
|
|
23229
|
+
const projectRoot = discoverKxmProjectRoot(inspectedFrom);
|
|
23230
23230
|
if (projectRoot) {
|
|
23231
23231
|
try {
|
|
23232
|
-
const bundle =
|
|
23232
|
+
const bundle = loadKxmProject(projectRoot, options);
|
|
23233
23233
|
return { mode: "ready", inspectedFrom, projectRoot, changesRequired: false, issues: [], legacyInputs: [], configRevision: bundle.configRevision };
|
|
23234
23234
|
} catch (error) {
|
|
23235
|
-
if (!(error instanceof
|
|
23235
|
+
if (!(error instanceof KxmConfigError)) throw error;
|
|
23236
23236
|
const legacyInputs = legacyInputsAt(projectRoot);
|
|
23237
23237
|
if (legacyInputs.length > 0) {
|
|
23238
23238
|
return { mode: "migrate", inspectedFrom, projectRoot, legacyRoot: projectRoot, changesRequired: true, issues: error.issues, legacyInputs };
|
|
@@ -23259,18 +23259,18 @@ function planVnextInitialization(start = process.cwd(), options = {}) {
|
|
|
23259
23259
|
return { mode: "create", inspectedFrom, projectRoot: candidateRoot, changesRequired: true, issues: [], legacyInputs: [] };
|
|
23260
23260
|
}
|
|
23261
23261
|
|
|
23262
|
-
// plugins/kxm/src/
|
|
23262
|
+
// plugins/kxm/src/runtime-supervisor.ts
|
|
23263
23263
|
import { spawn as spawn2 } from "node:child_process";
|
|
23264
23264
|
import { createHash as createHash11, createHmac, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
23265
23265
|
import { chmodSync as chmodSync4, existsSync as existsSync12, lstatSync as lstatSync6, mkdirSync as mkdirSync8, readFileSync as readFileSync11, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
|
|
23266
23266
|
import { dirname as dirname8, isAbsolute as isAbsolute5, join as join12 } from "node:path";
|
|
23267
23267
|
|
|
23268
|
-
// plugins/kxm/src/
|
|
23268
|
+
// plugins/kxm/src/runtime-store.ts
|
|
23269
23269
|
import { createHash as createHash9, randomUUID as randomUUID4 } from "node:crypto";
|
|
23270
23270
|
import { existsSync as existsSync9, lstatSync as lstatSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync8, realpathSync as realpathSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
23271
23271
|
import { dirname as dirname7, join as join9, resolve as resolve6 } from "node:path";
|
|
23272
23272
|
|
|
23273
|
-
// plugins/kxm/src/
|
|
23273
|
+
// plugins/kxm/src/bindings.ts
|
|
23274
23274
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
23275
23275
|
import { createHash as createHash7, randomUUID as randomUUID3 } from "node:crypto";
|
|
23276
23276
|
import {
|
|
@@ -23328,7 +23328,7 @@ var DatabaseSync = class {
|
|
|
23328
23328
|
}
|
|
23329
23329
|
};
|
|
23330
23330
|
|
|
23331
|
-
// plugins/kxm/src/
|
|
23331
|
+
// plugins/kxm/src/bindings.ts
|
|
23332
23332
|
import { dirname as dirname5, isAbsolute as isAbsolute3, join as join7, parse, relative as relative2, resolve as resolve4, sep as sep2 } from "node:path";
|
|
23333
23333
|
var MAX_BINDING_RECORD_BYTES = 256 * 1024;
|
|
23334
23334
|
var BINDING_LABEL = "Runtime-local repository bindings";
|
|
@@ -23337,7 +23337,7 @@ function bindingIssue(phase, code, message) {
|
|
|
23337
23337
|
return { phase, code, file: BINDING_LABEL, message };
|
|
23338
23338
|
}
|
|
23339
23339
|
function bindingError(phase, code, message) {
|
|
23340
|
-
throw new
|
|
23340
|
+
throw new KxmConfigError([bindingIssue(phase, code, message)]);
|
|
23341
23341
|
}
|
|
23342
23342
|
function canonicalHostPath2(path4) {
|
|
23343
23343
|
const absolute = resolve4(path4);
|
|
@@ -23352,7 +23352,7 @@ function sameHostPath2(left, right, platform = process.platform) {
|
|
|
23352
23352
|
const second = canonicalHostPath2(right);
|
|
23353
23353
|
return platform === "win32" ? first.toLocaleLowerCase("en-US") === second.toLocaleLowerCase("en-US") : first === second;
|
|
23354
23354
|
}
|
|
23355
|
-
function
|
|
23355
|
+
function kxmUserStateRoot(options = {}) {
|
|
23356
23356
|
const env = options.env ?? process.env;
|
|
23357
23357
|
const platform = options.platform ?? process.platform;
|
|
23358
23358
|
const home = options.homeDir ?? homedir3();
|
|
@@ -23376,8 +23376,8 @@ function projectBindingKey(projectRoot, platform = process.platform) {
|
|
|
23376
23376
|
const keyInput = platform === "win32" ? canonical2.toLocaleLowerCase("en-US") : canonical2;
|
|
23377
23377
|
return createHash7("sha256").update(keyInput, "utf8").digest("hex");
|
|
23378
23378
|
}
|
|
23379
|
-
function
|
|
23380
|
-
const stateRoot =
|
|
23379
|
+
function kxmLocalBindingFile(projectRoot, options = {}) {
|
|
23380
|
+
const stateRoot = kxmUserStateRoot(options);
|
|
23381
23381
|
return join7(stateRoot, "projects", projectBindingKey(projectRoot, options.platform), "repository-bindings.json");
|
|
23382
23382
|
}
|
|
23383
23383
|
function checkedDirectory(path4, description) {
|
|
@@ -23396,9 +23396,9 @@ function existingBindingDirectory(file, stateRoot) {
|
|
|
23396
23396
|
return checkedDirectory(project, "local project binding directory");
|
|
23397
23397
|
}
|
|
23398
23398
|
function asRecord2(value, file, projectRoot, schemasDir) {
|
|
23399
|
-
const registry = new
|
|
23399
|
+
const registry = new KxmSchemaRegistry(schemasDir);
|
|
23400
23400
|
const issues = registry.validateLocalBindings(value, BINDING_LABEL);
|
|
23401
|
-
if (issues.length > 0) throw new
|
|
23401
|
+
if (issues.length > 0) throw new KxmConfigError(issues);
|
|
23402
23402
|
const recordRoot = String(value.projectRoot);
|
|
23403
23403
|
if (!sameHostPath2(recordRoot, projectRoot)) {
|
|
23404
23404
|
bindingError("semantic", "local_binding_project_root_mismatch", "binding record belongs to a different control worktree");
|
|
@@ -23412,10 +23412,10 @@ function asRecord2(value, file, projectRoot, schemasDir) {
|
|
|
23412
23412
|
file
|
|
23413
23413
|
};
|
|
23414
23414
|
}
|
|
23415
|
-
function
|
|
23415
|
+
function readKxmLocalBindings(projectRoot, options = {}) {
|
|
23416
23416
|
const root = resolve4(projectRoot);
|
|
23417
|
-
const stateRoot =
|
|
23418
|
-
const file =
|
|
23417
|
+
const stateRoot = kxmUserStateRoot(options);
|
|
23418
|
+
const file = kxmLocalBindingFile(root, options);
|
|
23419
23419
|
if (!existingBindingDirectory(file, stateRoot) || !existsSync7(file)) return void 0;
|
|
23420
23420
|
const stat = lstatSync2(file);
|
|
23421
23421
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
@@ -23438,8 +23438,8 @@ function normalizedRecord(projectRoot, projectId, repositories, schemasDir) {
|
|
|
23438
23438
|
projectRoot: canonicalHostPath2(projectRoot),
|
|
23439
23439
|
repositories: normalizedRepositories
|
|
23440
23440
|
};
|
|
23441
|
-
const issues = new
|
|
23442
|
-
if (issues.length > 0) throw new
|
|
23441
|
+
const issues = new KxmSchemaRegistry(schemasDir).validateLocalBindings(value, BINDING_LABEL);
|
|
23442
|
+
if (issues.length > 0) throw new KxmConfigError(issues);
|
|
23443
23443
|
return value;
|
|
23444
23444
|
}
|
|
23445
23445
|
function recordsEqual(left, right) {
|
|
@@ -23544,7 +23544,7 @@ function projectOperationLockFile(projectRoot) {
|
|
|
23544
23544
|
}
|
|
23545
23545
|
return join7(lockDirectory, "project-operation-lock.sqlite");
|
|
23546
23546
|
}
|
|
23547
|
-
function
|
|
23547
|
+
function withKxmLocalBindingLock(projectRoot, options, callback) {
|
|
23548
23548
|
const root = resolve4(projectRoot);
|
|
23549
23549
|
const file = projectOperationLockFile(root);
|
|
23550
23550
|
if (existsSync7(file)) {
|
|
@@ -23579,28 +23579,28 @@ function withVnextLocalBindingLock(projectRoot, options, callback) {
|
|
|
23579
23579
|
database.close();
|
|
23580
23580
|
}
|
|
23581
23581
|
}
|
|
23582
|
-
function
|
|
23582
|
+
function planKxmLocalBindings(projectRoot, projectId, repositories, options = {}) {
|
|
23583
23583
|
const root = resolve4(projectRoot);
|
|
23584
|
-
const file =
|
|
23584
|
+
const file = kxmLocalBindingFile(root, options);
|
|
23585
23585
|
const record = normalizedRecord(root, projectId, repositories, options.schemasDir);
|
|
23586
|
-
const existing =
|
|
23586
|
+
const existing = readKxmLocalBindings(root, options);
|
|
23587
23587
|
if (existing?.projectId !== void 0 && existing.projectId !== projectId) {
|
|
23588
23588
|
bindingError("semantic", "local_binding_project_id_mismatch", "binding record belongs to a different project identity");
|
|
23589
23589
|
}
|
|
23590
23590
|
return { file, written: !existing || !recordsEqual(existing, record), record };
|
|
23591
23591
|
}
|
|
23592
|
-
function
|
|
23592
|
+
function writeKxmLocalBindings(projectRoot, projectId, repositories, options = {}, lock) {
|
|
23593
23593
|
const root = resolve4(projectRoot);
|
|
23594
23594
|
if (!lock) {
|
|
23595
|
-
return
|
|
23595
|
+
return withKxmLocalBindingLock(root, options, (acquired) => writeKxmLocalBindings(root, projectId, repositories, options, acquired));
|
|
23596
23596
|
}
|
|
23597
23597
|
if (!activeLocks.has(lock) || !sameHostPath2(lock.projectRoot, root)) {
|
|
23598
23598
|
bindingError("semantic", "local_binding_lock_invalid", "binding update does not hold the active project lock");
|
|
23599
23599
|
}
|
|
23600
|
-
const planned =
|
|
23600
|
+
const planned = planKxmLocalBindings(root, projectId, repositories, options);
|
|
23601
23601
|
const { file, record } = planned;
|
|
23602
23602
|
if (!planned.written) return planned;
|
|
23603
|
-
ensureBindingDirectory(file,
|
|
23603
|
+
ensureBindingDirectory(file, kxmUserStateRoot(options));
|
|
23604
23604
|
const temporary = join7(dirname5(file), `.repository-bindings-${process.pid}-${randomUUID3()}.tmp`);
|
|
23605
23605
|
let descriptor;
|
|
23606
23606
|
try {
|
|
@@ -23616,7 +23616,7 @@ function writeVnextLocalBindings(projectRoot, projectId, repositories, options =
|
|
|
23616
23616
|
if (descriptor !== void 0) closeSync(descriptor);
|
|
23617
23617
|
rmSync2(temporary, { force: true });
|
|
23618
23618
|
}
|
|
23619
|
-
const verified =
|
|
23619
|
+
const verified = readKxmLocalBindings(root, options);
|
|
23620
23620
|
if (!verified || !recordsEqual(verified, record)) {
|
|
23621
23621
|
bindingError("semantic", "local_binding_install_verification_failed", "installed binding record does not match the validated input");
|
|
23622
23622
|
}
|
|
@@ -23639,7 +23639,7 @@ import {
|
|
|
23639
23639
|
import { basename as basename3, dirname as dirname6, join as join8, resolve as resolve5 } from "node:path";
|
|
23640
23640
|
function databaseError(code, file, message) {
|
|
23641
23641
|
const issue3 = { phase: "semantic", code, file, message };
|
|
23642
|
-
return new
|
|
23642
|
+
return new KxmConfigError([issue3]);
|
|
23643
23643
|
}
|
|
23644
23644
|
function checkedParent(path4, description) {
|
|
23645
23645
|
const parent = dirname6(path4);
|
|
@@ -24041,9 +24041,9 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
24041
24041
|
};
|
|
24042
24042
|
}
|
|
24043
24043
|
|
|
24044
|
-
// plugins/kxm/src/
|
|
24045
|
-
function
|
|
24046
|
-
const stateRoot = options.stateRoot ? resolve6(options.stateRoot) :
|
|
24044
|
+
// plugins/kxm/src/runtime-store.ts
|
|
24045
|
+
function kxmRuntimePaths(options = {}) {
|
|
24046
|
+
const stateRoot = options.stateRoot ? resolve6(options.stateRoot) : kxmUserStateRoot({ ...options.env ? { env: options.env } : {}, ...options.homeDir ? { homeDir: options.homeDir } : {} });
|
|
24047
24047
|
const runtimeDir = join9(stateRoot, "runtime");
|
|
24048
24048
|
return {
|
|
24049
24049
|
stateRoot,
|
|
@@ -24056,7 +24056,7 @@ function runtimeIssue(phase, code, file, message) {
|
|
|
24056
24056
|
return { phase, code, file, message };
|
|
24057
24057
|
}
|
|
24058
24058
|
function runtimeError(code, file, message) {
|
|
24059
|
-
return new
|
|
24059
|
+
return new KxmConfigError([runtimeIssue("semantic", code, file, message)]);
|
|
24060
24060
|
}
|
|
24061
24061
|
function projectRuntimeKey(projectRoot) {
|
|
24062
24062
|
let canonical2;
|
|
@@ -24068,7 +24068,7 @@ function projectRuntimeKey(projectRoot) {
|
|
|
24068
24068
|
const folded = process.platform === "win32" ? canonical2.toLocaleLowerCase("en-US") : canonical2;
|
|
24069
24069
|
return createHash9("sha256").update(folded, "utf8").digest("hex").slice(0, 24);
|
|
24070
24070
|
}
|
|
24071
|
-
var
|
|
24071
|
+
var KXM_REGISTRY_SCHEMA_VERSION = 1;
|
|
24072
24072
|
var REGISTRY_TABLES = {
|
|
24073
24073
|
supervisor: ["singleton_id", "runtime_id", "pid", "port", "token_hash", "started_at", "heartbeat_at", "state"],
|
|
24074
24074
|
projects: ["project_id", "project_root", "project_key", "home_runtime_id", "config_revision", "registered_at"]
|
|
@@ -24093,14 +24093,14 @@ CREATE TABLE projects (
|
|
|
24093
24093
|
registered_at TEXT NOT NULL
|
|
24094
24094
|
) STRICT;
|
|
24095
24095
|
`;
|
|
24096
|
-
var
|
|
24096
|
+
var KxmRuntimeRegistry = class {
|
|
24097
24097
|
path;
|
|
24098
24098
|
database;
|
|
24099
24099
|
constructor(path4) {
|
|
24100
24100
|
this.path = resolve6(path4);
|
|
24101
24101
|
this.database = openDatabase(this.path, "runtime registry", {
|
|
24102
24102
|
schema: REGISTRY_SCHEMA,
|
|
24103
|
-
version:
|
|
24103
|
+
version: KXM_REGISTRY_SCHEMA_VERSION,
|
|
24104
24104
|
tables: REGISTRY_TABLES
|
|
24105
24105
|
});
|
|
24106
24106
|
}
|
|
@@ -24261,8 +24261,8 @@ var VnextRuntimeRegistry = class {
|
|
|
24261
24261
|
};
|
|
24262
24262
|
var DRIVE_RECEIPT_MAX_BYTES = 8 * 1024;
|
|
24263
24263
|
|
|
24264
|
-
// plugins/kxm/src/
|
|
24265
|
-
var
|
|
24264
|
+
// plugins/kxm/src/engine-compile.ts
|
|
24265
|
+
var KXM_COMPILED_WORKFLOW_SCHEMA = "kxm.compiled-workflow.v1";
|
|
24266
24266
|
var WORKFLOW_SCHEMA = "kxm.workflow.v1";
|
|
24267
24267
|
var STEP_ID_PATTERN = /^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/;
|
|
24268
24268
|
var SUPPORTED_STEP_KINDS = /* @__PURE__ */ new Set(["agent", "moa", "gate", "approval", "wait"]);
|
|
@@ -24272,16 +24272,16 @@ var EVIDENCE_KINDS = /* @__PURE__ */ new Set(["assignment-result", "gate", "rece
|
|
|
24272
24272
|
var REPOSITORY_ACCESS = /* @__PURE__ */ new Set(["none", "read", "write"]);
|
|
24273
24273
|
var DISTINCT_BY = /* @__PURE__ */ new Set(["provider", "model", "profile"]);
|
|
24274
24274
|
var BANNED_RUNTIME_HINT = "not yet supported";
|
|
24275
|
-
var
|
|
24275
|
+
var KxmEngineCompileError = class extends Error {
|
|
24276
24276
|
issues;
|
|
24277
24277
|
constructor(issues) {
|
|
24278
24278
|
const sorted = sortIssues3(issues);
|
|
24279
24279
|
super(sorted.map((issue3) => `${issue3.workflowId}: ${issue3.code}: ${issue3.message}`).join("\n"));
|
|
24280
|
-
this.name = "
|
|
24280
|
+
this.name = "KxmEngineCompileError";
|
|
24281
24281
|
this.issues = sorted;
|
|
24282
24282
|
}
|
|
24283
24283
|
};
|
|
24284
|
-
function
|
|
24284
|
+
function compileKxmWorkflow(input) {
|
|
24285
24285
|
const sink = { workflowId: input.id, issues: [] };
|
|
24286
24286
|
const value = input.value;
|
|
24287
24287
|
if (value.schema !== WORKFLOW_SCHEMA) {
|
|
@@ -24327,16 +24327,16 @@ function compileVnextWorkflow(input) {
|
|
|
24327
24327
|
pushIssue(sink, { code: "plan_hash_stage_unknown", message: `requirePlanHash references unknown stage ${stageId}` });
|
|
24328
24328
|
}
|
|
24329
24329
|
}
|
|
24330
|
-
if (sink.issues.length > 0) throw new
|
|
24330
|
+
if (sink.issues.length > 0) throw new KxmEngineCompileError(sink.issues);
|
|
24331
24331
|
const order = compiledSteps.map((step) => step.id);
|
|
24332
24332
|
const steps = /* @__PURE__ */ Object.create(null);
|
|
24333
24333
|
for (const step of compiledSteps) steps[step.id] = step;
|
|
24334
24334
|
const entryStepId = order[0];
|
|
24335
|
-
if (!entryStepId) throw new
|
|
24335
|
+
if (!entryStepId) throw new KxmEngineCompileError(sink.issues);
|
|
24336
24336
|
const coordinator = stringValue2(value.coordinator) ?? "coordinator";
|
|
24337
24337
|
const transitionBudget = limits.maxTransitions ?? order.length;
|
|
24338
24338
|
const plan = {
|
|
24339
|
-
schema:
|
|
24339
|
+
schema: KXM_COMPILED_WORKFLOW_SCHEMA,
|
|
24340
24340
|
workflowId: input.id,
|
|
24341
24341
|
...input.logicalPath !== void 0 ? { sourcePath: input.logicalPath } : {},
|
|
24342
24342
|
coordinator,
|
|
@@ -24764,10 +24764,10 @@ function pushIssue(sink, issue3) {
|
|
|
24764
24764
|
sink.issues.push({ workflowId: sink.workflowId, ...issue3 });
|
|
24765
24765
|
}
|
|
24766
24766
|
|
|
24767
|
-
// plugins/kxm/src/
|
|
24767
|
+
// plugins/kxm/src/runtime-service.ts
|
|
24768
24768
|
var RUNTIME_EPOCH_NS = process.hrtime.bigint();
|
|
24769
24769
|
|
|
24770
|
-
// plugins/kxm/src/
|
|
24770
|
+
// plugins/kxm/src/oneshot-evidence.ts
|
|
24771
24771
|
var TEXT_LIMIT = 4 * 1024 * 1024;
|
|
24772
24772
|
var ARGV_LIMIT = 64 * 1024;
|
|
24773
24773
|
var RECORD_LIMIT = 16 * 1024 * 1024;
|
|
@@ -24948,7 +24948,7 @@ function loadPriceCatalogForEstimate(options) {
|
|
|
24948
24948
|
return { catalog, unavailable: false, stale: false };
|
|
24949
24949
|
}
|
|
24950
24950
|
|
|
24951
|
-
// plugins/kxm/src/
|
|
24951
|
+
// plugins/kxm/src/engine.ts
|
|
24952
24952
|
var import_yaml5 = __toESM(require_dist(), 1);
|
|
24953
24953
|
|
|
24954
24954
|
// plugins/kxm/src/routes.ts
|
|
@@ -25643,12 +25643,12 @@ function formatRoutingReport(report2, options = {}) {
|
|
|
25643
25643
|
return lines.join("\n");
|
|
25644
25644
|
}
|
|
25645
25645
|
|
|
25646
|
-
// plugins/kxm/src/
|
|
25647
|
-
function
|
|
25646
|
+
// plugins/kxm/src/runtime-supervisor.ts
|
|
25647
|
+
function kxmSupervisorTokenFile(paths) {
|
|
25648
25648
|
return join12(paths.runtimeDir, "supervisor.token");
|
|
25649
25649
|
}
|
|
25650
|
-
function
|
|
25651
|
-
const file =
|
|
25650
|
+
function readKxmSupervisorToken(paths) {
|
|
25651
|
+
const file = kxmSupervisorTokenFile(paths);
|
|
25652
25652
|
const stat = lstatSync6(file, { throwIfNoEntry: false });
|
|
25653
25653
|
if (!stat) return void 0;
|
|
25654
25654
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
@@ -25686,9 +25686,9 @@ function readRecentSupervisorError(paths) {
|
|
|
25686
25686
|
return void 0;
|
|
25687
25687
|
}
|
|
25688
25688
|
}
|
|
25689
|
-
function
|
|
25689
|
+
function kxmSupervisorStatus(paths) {
|
|
25690
25690
|
if (!existsSync12(paths.registryDb)) return { running: false };
|
|
25691
|
-
const registry = new
|
|
25691
|
+
const registry = new KxmRuntimeRegistry(paths.registryDb);
|
|
25692
25692
|
try {
|
|
25693
25693
|
const record = registry.supervisor();
|
|
25694
25694
|
if (!record) return { running: false };
|
|
@@ -25723,7 +25723,7 @@ async function probeSupervisor(port, expectedRuntimeId, token, timeoutMs = 750)
|
|
|
25723
25723
|
const response = await fetch(`http://127.0.0.1:${port}/healthz?nonce=${nonce}`, { signal: controller.signal });
|
|
25724
25724
|
if (!response.ok) return false;
|
|
25725
25725
|
const payload = await response.json();
|
|
25726
|
-
const expectedProof =
|
|
25726
|
+
const expectedProof = hashKxmTokenProof(token, nonce);
|
|
25727
25727
|
return payload.runtimeId === expectedRuntimeId && payload.tokenProof === expectedProof;
|
|
25728
25728
|
} catch {
|
|
25729
25729
|
return false;
|
|
@@ -25731,15 +25731,15 @@ async function probeSupervisor(port, expectedRuntimeId, token, timeoutMs = 750)
|
|
|
25731
25731
|
clearTimeout(timeout);
|
|
25732
25732
|
}
|
|
25733
25733
|
}
|
|
25734
|
-
function
|
|
25734
|
+
function hashKxmTokenProof(token, nonce) {
|
|
25735
25735
|
return createHmac("sha256", token).update(`kxm-runtime-token-proof\0${nonce}`, "utf8").digest("hex");
|
|
25736
25736
|
}
|
|
25737
|
-
async function
|
|
25738
|
-
const paths =
|
|
25739
|
-
const status =
|
|
25737
|
+
async function ensureKxmSupervisor(options = {}) {
|
|
25738
|
+
const paths = kxmRuntimePaths(options.stateRoot !== void 0 ? { stateRoot: options.stateRoot } : { ...options.env ? { env: options.env } : {} });
|
|
25739
|
+
const status = kxmSupervisorStatus(paths);
|
|
25740
25740
|
if (status.running && status.port) {
|
|
25741
25741
|
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
25742
|
-
const token =
|
|
25742
|
+
const token = readKxmSupervisorToken(paths);
|
|
25743
25743
|
if (token && await probeSupervisorWithRetry(status.port, status.runtimeId, token)) {
|
|
25744
25744
|
return { runtimeId: status.runtimeId, port: status.port, token, started: false };
|
|
25745
25745
|
}
|
|
@@ -25767,9 +25767,9 @@ async function ensureVnextSupervisor(options = {}) {
|
|
|
25767
25767
|
const deadline = Date.now() + 1e4;
|
|
25768
25768
|
while (Date.now() < deadline) {
|
|
25769
25769
|
await new Promise((resolveWait) => setTimeout(resolveWait, 100));
|
|
25770
|
-
const next =
|
|
25770
|
+
const next = kxmSupervisorStatus(paths);
|
|
25771
25771
|
if (next.running && next.port) {
|
|
25772
|
-
const token =
|
|
25772
|
+
const token = readKxmSupervisorToken(paths);
|
|
25773
25773
|
if (token && await probeSupervisor(next.port, next.runtimeId, token)) {
|
|
25774
25774
|
return { runtimeId: next.runtimeId, port: next.port, token, started: true };
|
|
25775
25775
|
}
|
|
@@ -25781,7 +25781,7 @@ async function ensureVnextSupervisor(options = {}) {
|
|
|
25781
25781
|
}
|
|
25782
25782
|
throw runtimeError("runtime_supervisor_start_failed", scriptPath, `runtime supervisor (pid ${pid}) did not become ready in time`);
|
|
25783
25783
|
}
|
|
25784
|
-
async function
|
|
25784
|
+
async function kxmRuntimeRequest(handle, method, path4, body) {
|
|
25785
25785
|
const response = await fetch(`http://127.0.0.1:${handle.port}${path4}`, {
|
|
25786
25786
|
method,
|
|
25787
25787
|
headers: {
|
|
@@ -26369,10 +26369,17 @@ function getKxmConfigValue(config, keyPath) {
|
|
|
26369
26369
|
}
|
|
26370
26370
|
return current;
|
|
26371
26371
|
}
|
|
26372
|
-
function
|
|
26373
|
-
|
|
26374
|
-
|
|
26375
|
-
|
|
26372
|
+
function kxmConfigFileForScope(repoRoot, scope, userConfigDir) {
|
|
26373
|
+
return scope === "user" ? join16(userConfigDirectory(userConfigDir), "config.yaml") : join16(repoConfigDirectory(repoRoot), "config.yaml");
|
|
26374
|
+
}
|
|
26375
|
+
function configKeyParts(keyPath) {
|
|
26376
|
+
const parts = keyPath.split(".");
|
|
26377
|
+
if (parts.some((part) => !part || part === "__proto__" || part === "prototype" || part === "constructor")) {
|
|
26378
|
+
throw new Error("invalid config key path");
|
|
26379
|
+
}
|
|
26380
|
+
return parts;
|
|
26381
|
+
}
|
|
26382
|
+
function readConfigFile(targetFile2) {
|
|
26376
26383
|
let existing = {};
|
|
26377
26384
|
if (existsSync14(targetFile2)) {
|
|
26378
26385
|
try {
|
|
@@ -26381,10 +26388,16 @@ function setKxmConfigValue(repoRoot, keyPath, value, options = {}) {
|
|
|
26381
26388
|
existing = {};
|
|
26382
26389
|
}
|
|
26383
26390
|
}
|
|
26384
|
-
|
|
26385
|
-
|
|
26386
|
-
|
|
26387
|
-
}
|
|
26391
|
+
return existing;
|
|
26392
|
+
}
|
|
26393
|
+
function writeConfigFile(targetFile2, value) {
|
|
26394
|
+
mkdirSync11(dirname11(targetFile2), { recursive: true });
|
|
26395
|
+
writeFileSync10(targetFile2, (0, import_yaml6.stringify)(value).trim() + "\n", "utf8");
|
|
26396
|
+
}
|
|
26397
|
+
function setKxmConfigValue(repoRoot, keyPath, value, options = {}) {
|
|
26398
|
+
const targetFile2 = kxmConfigFileForScope(repoRoot, options.scope ?? "project", options.userConfigDir);
|
|
26399
|
+
const existing = readConfigFile(targetFile2);
|
|
26400
|
+
const parts = configKeyParts(keyPath);
|
|
26388
26401
|
let cursor2 = existing;
|
|
26389
26402
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
26390
26403
|
const p = parts[i];
|
|
@@ -26394,7 +26407,7 @@ function setKxmConfigValue(repoRoot, keyPath, value, options = {}) {
|
|
|
26394
26407
|
cursor2 = cursor2[p];
|
|
26395
26408
|
}
|
|
26396
26409
|
cursor2[parts[parts.length - 1]] = value;
|
|
26397
|
-
|
|
26410
|
+
writeConfigFile(targetFile2, existing);
|
|
26398
26411
|
}
|
|
26399
26412
|
function formatKxmConfig(config) {
|
|
26400
26413
|
const display = {
|
|
@@ -27283,15 +27296,15 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
27283
27296
|
return 1;
|
|
27284
27297
|
}
|
|
27285
27298
|
const effectiveRuling = ruling?.trim() || "operator_ruling: waived and resumed";
|
|
27286
|
-
const projectRoot =
|
|
27299
|
+
const projectRoot = discoverKxmProjectRoot(runtime.cwd);
|
|
27287
27300
|
if (projectRoot && /^run_[a-f0-9]{32}$/i.test(runId)) {
|
|
27288
27301
|
if (runtime.dryRun) {
|
|
27289
|
-
print(runtime.io, runtime.json, { ok: true, command: "role resume", runId, ruling: effectiveRuling }, `would resume
|
|
27302
|
+
print(runtime.io, runtime.json, { ok: true, command: "role resume", runId, ruling: effectiveRuling }, `would resume KXM run ${runId}`);
|
|
27290
27303
|
return 0;
|
|
27291
27304
|
}
|
|
27292
27305
|
try {
|
|
27293
|
-
const supervisor = await
|
|
27294
|
-
const posted = await
|
|
27306
|
+
const supervisor = await ensureKxmSupervisor({ env: runtime.env });
|
|
27307
|
+
const posted = await kxmRuntimeRequest(
|
|
27295
27308
|
supervisor,
|
|
27296
27309
|
"POST",
|
|
27297
27310
|
`/v1/runs/${encodeURIComponent(runId)}/signal?projectRoot=${encodeURIComponent(projectRoot)}`,
|
|
@@ -27306,13 +27319,13 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
27306
27319
|
runtime.io,
|
|
27307
27320
|
runtime.json,
|
|
27308
27321
|
{ ok: true, command: "role resume", runId, ruling: effectiveRuling, unblocked: posted.unblocked === true },
|
|
27309
|
-
`Resumed
|
|
27322
|
+
`Resumed KXM run ${runId} with ruling: ${effectiveRuling}
|
|
27310
27323
|
`
|
|
27311
27324
|
);
|
|
27312
27325
|
return 0;
|
|
27313
27326
|
} catch (error) {
|
|
27314
27327
|
const msg = error instanceof Error ? error.message : "resume_failed";
|
|
27315
|
-
print(runtime.io, runtime.json, { ok: false, command: "role resume", error: "resume_failed", detail: msg }, `resume
|
|
27328
|
+
print(runtime.io, runtime.json, { ok: false, command: "role resume", error: "resume_failed", detail: msg }, `resume KXM run failed: ${msg}
|
|
27316
27329
|
`);
|
|
27317
27330
|
return 1;
|
|
27318
27331
|
}
|
|
@@ -28529,26 +28542,26 @@ async function cmdSignal(runtime, runId, signalKey, status, summary, evidenceArg
|
|
|
28529
28542
|
return 2;
|
|
28530
28543
|
}
|
|
28531
28544
|
const worker = gateOf(runtime, "signal");
|
|
28532
|
-
const projectRoot =
|
|
28545
|
+
const projectRoot = discoverKxmProjectRoot(runtime.cwd);
|
|
28533
28546
|
if (projectRoot && /^run_[a-f0-9]{32}$/i.test(runId)) {
|
|
28534
28547
|
if (runtime.dryRun) {
|
|
28535
|
-
printWorker(runtime, worker, { ok: true, command: "signal", runId, signalKey, status, summary, evidence }, "would post signal to
|
|
28548
|
+
printWorker(runtime, worker, { ok: true, command: "signal", runId, signalKey, status, summary, evidence }, "would post signal to KXM run");
|
|
28536
28549
|
return 0;
|
|
28537
28550
|
}
|
|
28538
28551
|
const deliveryId2 = String(deliveryIdFlag || `cli-signal:${randomUUID7()}`);
|
|
28539
28552
|
try {
|
|
28540
|
-
const supervisor = await
|
|
28541
|
-
const posted = await
|
|
28553
|
+
const supervisor = await ensureKxmSupervisor({ env: runtime.env });
|
|
28554
|
+
const posted = await kxmRuntimeRequest(
|
|
28542
28555
|
supervisor,
|
|
28543
28556
|
"POST",
|
|
28544
28557
|
`/v1/runs/${encodeURIComponent(runId)}/signal?projectRoot=${encodeURIComponent(projectRoot)}`,
|
|
28545
28558
|
{ signalKey, status, summary, evidence, deliveryId: deliveryId2, ...recoveryAction ? { action: recoveryAction } : {} }
|
|
28546
28559
|
);
|
|
28547
|
-
printWorker(runtime, worker, { ok: true, command: "signal", runId, signalKey, status, unblocked: posted.unblocked === true, deliveryId: deliveryId2 }, "posted signal to
|
|
28560
|
+
printWorker(runtime, worker, { ok: true, command: "signal", runId, signalKey, status, unblocked: posted.unblocked === true, deliveryId: deliveryId2 }, "posted signal to KXM run");
|
|
28548
28561
|
return 0;
|
|
28549
28562
|
} catch (error) {
|
|
28550
28563
|
const msg = error instanceof Error ? error.message : "signal_failed";
|
|
28551
|
-
printWorker(runtime, worker, { ok: false, command: "signal", error: "signal_failed", detail: msg, deliveryId: deliveryId2 }, "signal to
|
|
28564
|
+
printWorker(runtime, worker, { ok: false, command: "signal", error: "signal_failed", detail: msg, deliveryId: deliveryId2 }, "signal to KXM run failed");
|
|
28552
28565
|
return 1;
|
|
28553
28566
|
}
|
|
28554
28567
|
}
|
|
@@ -29706,7 +29719,7 @@ function createStudioServer(options = {}) {
|
|
|
29706
29719
|
};
|
|
29707
29720
|
}
|
|
29708
29721
|
|
|
29709
|
-
// plugins/kxm/src/cli/
|
|
29722
|
+
// plugins/kxm/src/cli/project.ts
|
|
29710
29723
|
import { join as join27, resolve as resolve20 } from "node:path";
|
|
29711
29724
|
import { createInterface as createInterface2 } from "node:readline";
|
|
29712
29725
|
|
|
@@ -29804,12 +29817,12 @@ async function refreshModelInventory(options) {
|
|
|
29804
29817
|
return inventory;
|
|
29805
29818
|
}
|
|
29806
29819
|
|
|
29807
|
-
// plugins/kxm/src/
|
|
29820
|
+
// plugins/kxm/src/init.ts
|
|
29808
29821
|
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
29809
29822
|
import { existsSync as existsSync22 } from "node:fs";
|
|
29810
29823
|
import { basename as basename5, join as join25 } from "node:path";
|
|
29811
29824
|
|
|
29812
|
-
// plugins/kxm/src/
|
|
29825
|
+
// plugins/kxm/src/repair.ts
|
|
29813
29826
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
29814
29827
|
import {
|
|
29815
29828
|
chmodSync as chmodSync5,
|
|
@@ -29828,7 +29841,7 @@ import {
|
|
|
29828
29841
|
} from "node:fs";
|
|
29829
29842
|
import { dirname as dirname15, isAbsolute as isAbsolute7, join as join24, relative as relative4, resolve as resolve18 } from "node:path";
|
|
29830
29843
|
|
|
29831
|
-
// plugins/kxm/src/
|
|
29844
|
+
// plugins/kxm/src/permission.ts
|
|
29832
29845
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
29833
29846
|
import { createHash as createHash12 } from "node:crypto";
|
|
29834
29847
|
import { existsSync as existsSync20, mkdtempSync, mkdirSync as mkdirSync17, readFileSync as readFileSync20, rmSync as rmSync7, writeFileSync as writeFileSync16 } from "node:fs";
|
|
@@ -29847,7 +29860,7 @@ var ACCESS_RANK = { none: 0, read: 1, write: 2 };
|
|
|
29847
29860
|
var NETWORK_RANK = { none: 0, "provider-only": 1, restricted: 2, host: 3 };
|
|
29848
29861
|
var UNTRACKED_RANK = { "tracked-only": 0, ask: 1, bounded: 2 };
|
|
29849
29862
|
function canonical(value) {
|
|
29850
|
-
return
|
|
29863
|
+
return kxmCanonicalJson(value === void 0 ? null : value);
|
|
29851
29864
|
}
|
|
29852
29865
|
function asObject(value) {
|
|
29853
29866
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
@@ -29875,7 +29888,7 @@ function secretGrantKeys(grants) {
|
|
|
29875
29888
|
}
|
|
29876
29889
|
return keys;
|
|
29877
29890
|
}
|
|
29878
|
-
function
|
|
29891
|
+
function kxmAuthorityEntries(resource) {
|
|
29879
29892
|
const entries = [];
|
|
29880
29893
|
const push = (path4, field, value2) => {
|
|
29881
29894
|
entries.push({ path: path4, field, value: canonical(value2) });
|
|
@@ -30019,7 +30032,7 @@ function vnextAuthorityEntries(resource) {
|
|
|
30019
30032
|
}
|
|
30020
30033
|
return entries;
|
|
30021
30034
|
}
|
|
30022
|
-
function
|
|
30035
|
+
function kxmProseEntries(resource) {
|
|
30023
30036
|
const entries = /* @__PURE__ */ new Map();
|
|
30024
30037
|
for (const field of PROSE_FIELDS[resource.kind]) {
|
|
30025
30038
|
if (resource.value[field] !== void 0) entries.set(`/${field}`, canonical(resource.value[field]));
|
|
@@ -30104,7 +30117,7 @@ function quorumDirection(baseValue, candidateValue) {
|
|
|
30104
30117
|
}
|
|
30105
30118
|
return residual;
|
|
30106
30119
|
};
|
|
30107
|
-
if (
|
|
30120
|
+
if (kxmCanonicalJson(residualOf(baseValue)) !== kxmCanonicalJson(residualOf(candidateValue))) return "expansion";
|
|
30108
30121
|
const basePolicy = asObject(base.producerPolicy);
|
|
30109
30122
|
const candidatePolicy = asObject(candidate.producerPolicy);
|
|
30110
30123
|
if (!basePolicy && !candidatePolicy) return sawNarrowing ? "narrowing" : "neutral";
|
|
@@ -30146,7 +30159,7 @@ function snapshotDirection(baseValue, candidateValue) {
|
|
|
30146
30159
|
if (bounds === "expansion") return "expansion";
|
|
30147
30160
|
const CLASSIFIED_SNAPSHOT = /* @__PURE__ */ new Set(["untracked", "maxUntrackedFileBytes", "maxUntrackedTotalBytes", "dirtySubmodules"]);
|
|
30148
30161
|
const residualOf = (snapshot) => Object.fromEntries(Object.entries(snapshot).filter(([key]) => !CLASSIFIED_SNAPSHOT.has(key)));
|
|
30149
|
-
if (
|
|
30162
|
+
if (kxmCanonicalJson(residualOf(baseSnapshot)) !== kxmCanonicalJson(residualOf(candidateSnapshot))) return "expansion";
|
|
30150
30163
|
return bounds === "narrowing" || untracked === "narrowing" ? "narrowing" : "neutral";
|
|
30151
30164
|
}
|
|
30152
30165
|
function classifyChange(field, baseValue, candidateValue, context) {
|
|
@@ -30193,7 +30206,7 @@ function classifyChange(field, baseValue, candidateValue, context) {
|
|
|
30193
30206
|
if (base && candidate && base.ref === candidate.ref) {
|
|
30194
30207
|
const { required: _b, ...baseRest } = base;
|
|
30195
30208
|
const { required: _c, ...candidateRest } = candidate;
|
|
30196
|
-
if (
|
|
30209
|
+
if (kxmCanonicalJson(baseRest) !== kxmCanonicalJson(candidateRest)) return "expansion";
|
|
30197
30210
|
const baseRequired = (base.required ?? true) === true;
|
|
30198
30211
|
const candidateRequired = (candidate.required ?? true) === true;
|
|
30199
30212
|
if (baseRequired && !candidateRequired) return "narrowing";
|
|
@@ -30210,7 +30223,7 @@ function summarize(resource, path4, field, direction, baseValue, candidateValue)
|
|
|
30210
30223
|
const verb = baseValue === void 0 ? "added" : candidateValue === void 0 ? "removed" : "changed";
|
|
30211
30224
|
return `${resource} ${path4} ${field} ${verb} (${direction})`;
|
|
30212
30225
|
}
|
|
30213
|
-
function
|
|
30226
|
+
function computeKxmPermissionDiff(base, candidate) {
|
|
30214
30227
|
const changes = [];
|
|
30215
30228
|
const baseByPath = new Map(base.resources.map((resource) => [resource.logicalPath, resource]));
|
|
30216
30229
|
const candidateByPath = new Map(candidate.resources.map((resource) => [resource.logicalPath, resource]));
|
|
@@ -30249,7 +30262,7 @@ function computeVnextPermissionDiff(base, candidate) {
|
|
|
30249
30262
|
requiresReview: expansions.length > 0
|
|
30250
30263
|
};
|
|
30251
30264
|
}
|
|
30252
|
-
function
|
|
30265
|
+
function computeKxmResourcePermissionDiff(kind, resourcePath, baseValue, candidateValue) {
|
|
30253
30266
|
const changes = [];
|
|
30254
30267
|
const base = { kind, file: resourcePath, logicalPath: resourcePath, value: baseValue };
|
|
30255
30268
|
const candidate = { kind, file: resourcePath, logicalPath: resourcePath, value: candidateValue };
|
|
@@ -30257,8 +30270,8 @@ function computeVnextResourcePermissionDiff(kind, resourcePath, baseValue, candi
|
|
|
30257
30270
|
return changes.sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
|
|
30258
30271
|
}
|
|
30259
30272
|
function diffResource(logicalPath, base, candidate, changes) {
|
|
30260
|
-
const baseEntries = new Map(
|
|
30261
|
-
const candidateEntries = new Map(
|
|
30273
|
+
const baseEntries = new Map(kxmAuthorityEntries(base).map((entry) => [entry.path, entry]));
|
|
30274
|
+
const candidateEntries = new Map(kxmAuthorityEntries(candidate).map((entry) => [entry.path, entry]));
|
|
30262
30275
|
const paths = [.../* @__PURE__ */ new Set([...baseEntries.keys(), ...candidateEntries.keys()])].sort();
|
|
30263
30276
|
for (const path4 of paths) {
|
|
30264
30277
|
const baseEntry = baseEntries.get(path4);
|
|
@@ -30286,8 +30299,8 @@ function diffResource(logicalPath, base, candidate, changes) {
|
|
|
30286
30299
|
...candidateEntry && field !== "environment" ? { candidateValueSha256: valueHash(candidateEntry.value) } : {}
|
|
30287
30300
|
});
|
|
30288
30301
|
}
|
|
30289
|
-
const baseProse =
|
|
30290
|
-
const candidateProse =
|
|
30302
|
+
const baseProse = kxmProseEntries(base);
|
|
30303
|
+
const candidateProse = kxmProseEntries(candidate);
|
|
30291
30304
|
for (const path4 of [.../* @__PURE__ */ new Set([...baseProse.keys(), ...candidateProse.keys()])].sort()) {
|
|
30292
30305
|
if (baseProse.get(path4) === candidateProse.get(path4)) continue;
|
|
30293
30306
|
changes.push({
|
|
@@ -30313,7 +30326,7 @@ function git(root, args) {
|
|
|
30313
30326
|
maxBuffer: 64 * 1024 * 1024
|
|
30314
30327
|
});
|
|
30315
30328
|
if (result.status !== 0 || result.error) {
|
|
30316
|
-
throw new
|
|
30329
|
+
throw new KxmConfigError([{
|
|
30317
30330
|
phase: "discovery",
|
|
30318
30331
|
code: "git_base_unavailable",
|
|
30319
30332
|
file: args[0] ?? "<git>",
|
|
@@ -30330,7 +30343,7 @@ function gitBuffer(root, args) {
|
|
|
30330
30343
|
maxBuffer: 256 * 1024 * 1024
|
|
30331
30344
|
});
|
|
30332
30345
|
if (result.status !== 0 || result.error) {
|
|
30333
|
-
throw new
|
|
30346
|
+
throw new KxmConfigError([{
|
|
30334
30347
|
phase: "discovery",
|
|
30335
30348
|
code: "git_base_unavailable",
|
|
30336
30349
|
file: args[0] ?? "<git>",
|
|
@@ -30341,7 +30354,7 @@ function gitBuffer(root, args) {
|
|
|
30341
30354
|
}
|
|
30342
30355
|
function resolveTreeRevision(root, revision) {
|
|
30343
30356
|
if (!/^[A-Za-z0-9._/^~-]+$/.test(revision) || revision.includes("..") || revision.startsWith("-")) {
|
|
30344
|
-
throw new
|
|
30357
|
+
throw new KxmConfigError([{
|
|
30345
30358
|
phase: "discovery",
|
|
30346
30359
|
code: "git_revision_invalid",
|
|
30347
30360
|
file: revision,
|
|
@@ -30350,7 +30363,7 @@ function resolveTreeRevision(root, revision) {
|
|
|
30350
30363
|
}
|
|
30351
30364
|
return git(root, ["rev-parse", "--verify", "--quiet", `${revision}^{tree}`]).trim();
|
|
30352
30365
|
}
|
|
30353
|
-
function
|
|
30366
|
+
function loadKxmProjectAtRevision(root, revision, options = {}) {
|
|
30354
30367
|
const tree = resolveTreeRevision(root, revision);
|
|
30355
30368
|
const listing = gitBuffer(root, ["ls-tree", "-r", "-z", "--name-only", tree]).toString("utf8");
|
|
30356
30369
|
const paths = listing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
@@ -30361,7 +30374,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30361
30374
|
for (const path4 of paths) {
|
|
30362
30375
|
const segments = path4.split("/");
|
|
30363
30376
|
if (segments.some((segment) => segment === "" || segment === "." || segment === ".." || /[\\:]/.test(segment))) {
|
|
30364
|
-
throw new
|
|
30377
|
+
throw new KxmConfigError([{
|
|
30365
30378
|
phase: "path",
|
|
30366
30379
|
code: "git_tree_path_invalid",
|
|
30367
30380
|
file: path4,
|
|
@@ -30371,7 +30384,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30371
30384
|
const absolute = join23(shadowResolved, ...segments);
|
|
30372
30385
|
const resolved = resolve17(absolute);
|
|
30373
30386
|
if (!resolved.startsWith(`${shadowResolved}${sep3}`)) {
|
|
30374
|
-
throw new
|
|
30387
|
+
throw new KxmConfigError([{
|
|
30375
30388
|
phase: "path",
|
|
30376
30389
|
code: "git_tree_path_invalid",
|
|
30377
30390
|
file: path4,
|
|
@@ -30388,16 +30401,16 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30388
30401
|
try {
|
|
30389
30402
|
baseProject = loadBaseProjectDeclarations(baseProjectFile);
|
|
30390
30403
|
} catch (error) {
|
|
30391
|
-
if (error instanceof
|
|
30392
|
-
throw new
|
|
30404
|
+
if (error instanceof KxmConfigError) {
|
|
30405
|
+
throw new KxmConfigError(error.issues.map((entry) => ({ ...entry, message: `base ${revision}: ${entry.message}` })));
|
|
30393
30406
|
}
|
|
30394
30407
|
throw error;
|
|
30395
30408
|
}
|
|
30396
30409
|
const shadowBindings = {};
|
|
30397
30410
|
for (const member of baseProject) {
|
|
30398
30411
|
if (member.role !== "member") continue;
|
|
30399
|
-
if (!
|
|
30400
|
-
throw new
|
|
30412
|
+
if (!kxmResourceIdentifier(member.repositoryId)) {
|
|
30413
|
+
throw new KxmConfigError([{
|
|
30401
30414
|
phase: "path",
|
|
30402
30415
|
code: "git_tree_path_invalid",
|
|
30403
30416
|
file: ".kxm/project.yaml",
|
|
@@ -30405,7 +30418,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30405
30418
|
}]);
|
|
30406
30419
|
}
|
|
30407
30420
|
if (member.pathHint !== void 0 && !portableMemberPathHint(member.pathHint)) {
|
|
30408
|
-
throw new
|
|
30421
|
+
throw new KxmConfigError([{
|
|
30409
30422
|
phase: "path",
|
|
30410
30423
|
code: "git_tree_path_invalid",
|
|
30411
30424
|
file: ".kxm/project.yaml",
|
|
@@ -30416,7 +30429,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30416
30429
|
const memberWorktree = boundPath ? resolve17(boundPath) : member.pathHint ? resolve17(root, ...member.pathHint.split("/")) : void 0;
|
|
30417
30430
|
if (!memberWorktree || !existsSync20(memberWorktree)) {
|
|
30418
30431
|
if (member.required === false) continue;
|
|
30419
|
-
throw new
|
|
30432
|
+
throw new KxmConfigError([{
|
|
30420
30433
|
phase: "discovery",
|
|
30421
30434
|
code: "trust_scope_unsupported",
|
|
30422
30435
|
file: ".kxm/project.yaml",
|
|
@@ -30429,7 +30442,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30429
30442
|
if (gitlink.length > 0) {
|
|
30430
30443
|
const match = /^160000 commit ([0-9a-f]{40,64})\t/.exec(gitlink);
|
|
30431
30444
|
if (!match) {
|
|
30432
|
-
throw new
|
|
30445
|
+
throw new KxmConfigError([{
|
|
30433
30446
|
phase: "discovery",
|
|
30434
30447
|
code: "trust_scope_unsupported",
|
|
30435
30448
|
file: ".kxm/project.yaml",
|
|
@@ -30440,7 +30453,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30440
30453
|
} else if (boundPath) {
|
|
30441
30454
|
pinnedCommit = git(memberWorktree, ["rev-parse", "--verify", "--quiet", "HEAD^{commit}"]).trim();
|
|
30442
30455
|
} else {
|
|
30443
|
-
throw new
|
|
30456
|
+
throw new KxmConfigError([{
|
|
30444
30457
|
phase: "discovery",
|
|
30445
30458
|
code: "trust_scope_unsupported",
|
|
30446
30459
|
file: ".kxm/project.yaml",
|
|
@@ -30451,7 +30464,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30451
30464
|
pinnedCommit = git(memberWorktree, ["rev-parse", "--verify", "--quiet", "HEAD^{commit}"]).trim();
|
|
30452
30465
|
}
|
|
30453
30466
|
if (!pinnedCommit) {
|
|
30454
|
-
throw new
|
|
30467
|
+
throw new KxmConfigError([{
|
|
30455
30468
|
phase: "discovery",
|
|
30456
30469
|
code: "trust_scope_unsupported",
|
|
30457
30470
|
file: ".kxm/project.yaml",
|
|
@@ -30463,7 +30476,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30463
30476
|
const memberPaths = memberListing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
30464
30477
|
const memberShadowRoot = join23(shadowResolved, shadowMembersDir, member.repositoryId);
|
|
30465
30478
|
if (!resolve17(memberShadowRoot).startsWith(`${resolve17(shadowResolved, shadowMembersDir)}${sep3}`)) {
|
|
30466
|
-
throw new
|
|
30479
|
+
throw new KxmConfigError([{
|
|
30467
30480
|
phase: "path",
|
|
30468
30481
|
code: "git_tree_path_invalid",
|
|
30469
30482
|
file: ".kxm/project.yaml",
|
|
@@ -30473,12 +30486,12 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30473
30486
|
for (const path4 of memberPaths) {
|
|
30474
30487
|
const segments = path4.split("/");
|
|
30475
30488
|
if (segments.some((segment) => segment === "" || segment === "." || segment === ".." || /[\\:]/.test(segment))) {
|
|
30476
|
-
throw new
|
|
30489
|
+
throw new KxmConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path4, message: "member Git tree entry contains a traversal or non-portable segment" }]);
|
|
30477
30490
|
}
|
|
30478
30491
|
const absolute = join23(memberShadowRoot, ...segments);
|
|
30479
30492
|
const resolved = resolve17(absolute);
|
|
30480
30493
|
if (!resolved.startsWith(`${resolve17(memberShadowRoot)}${sep3}`)) {
|
|
30481
|
-
throw new
|
|
30494
|
+
throw new KxmConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path4, message: "member Git tree entry escapes the shadow root" }]);
|
|
30482
30495
|
}
|
|
30483
30496
|
const content = gitBuffer(memberWorktree, ["cat-file", "blob", `${memberTree}:${path4}`]);
|
|
30484
30497
|
mkdirSync17(dirname14(absolute), { recursive: true });
|
|
@@ -30488,10 +30501,10 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30488
30501
|
shadowBindings[member.repositoryId] = memberShadowRoot;
|
|
30489
30502
|
}
|
|
30490
30503
|
try {
|
|
30491
|
-
return
|
|
30504
|
+
return loadKxmProject(shadowResolved, { ...options, repositoryBindings: shadowBindings });
|
|
30492
30505
|
} catch (error) {
|
|
30493
|
-
if (error instanceof
|
|
30494
|
-
throw new
|
|
30506
|
+
if (error instanceof KxmConfigError) {
|
|
30507
|
+
throw new KxmConfigError(error.issues.map((entry) => ({ ...entry, message: `base ${revision}: ${entry.message}` })));
|
|
30495
30508
|
}
|
|
30496
30509
|
throw error;
|
|
30497
30510
|
}
|
|
@@ -30500,7 +30513,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30500
30513
|
}
|
|
30501
30514
|
}
|
|
30502
30515
|
function portableMemberPathHint(pathHint) {
|
|
30503
|
-
return pathHint !== "." &&
|
|
30516
|
+
return pathHint !== "." && kxmPortablePath(pathHint);
|
|
30504
30517
|
}
|
|
30505
30518
|
function loadBaseProjectDeclarations(projectFile) {
|
|
30506
30519
|
if (!existsSync20(projectFile)) return [];
|
|
@@ -30528,7 +30541,7 @@ function initShadowGitRoot(directory) {
|
|
|
30528
30541
|
windowsHide: true
|
|
30529
30542
|
});
|
|
30530
30543
|
if (result.status !== 0 || result.error) {
|
|
30531
|
-
throw new
|
|
30544
|
+
throw new KxmConfigError([{
|
|
30532
30545
|
phase: "discovery",
|
|
30533
30546
|
code: "git_base_unavailable",
|
|
30534
30547
|
file: directory,
|
|
@@ -30536,12 +30549,12 @@ function initShadowGitRoot(directory) {
|
|
|
30536
30549
|
}]);
|
|
30537
30550
|
}
|
|
30538
30551
|
}
|
|
30539
|
-
function
|
|
30540
|
-
const base =
|
|
30541
|
-
const candidate =
|
|
30542
|
-
return
|
|
30552
|
+
function diffKxmProjectAgainstRevision(root, revision, options = {}) {
|
|
30553
|
+
const base = loadKxmProjectAtRevision(root, revision, options);
|
|
30554
|
+
const candidate = loadKxmProject(root, options);
|
|
30555
|
+
return computeKxmPermissionDiff(base, candidate);
|
|
30543
30556
|
}
|
|
30544
|
-
function
|
|
30557
|
+
function formatKxmPermissionDiff(diff) {
|
|
30545
30558
|
const lines = [];
|
|
30546
30559
|
lines.push(`permission diff: ${diff.baseRevision.slice(0, 19)}\u2026 -> ${diff.candidateRevision.slice(0, 19)}\u2026`);
|
|
30547
30560
|
if (diff.changes.length === 0) {
|
|
@@ -30555,7 +30568,7 @@ function formatVnextPermissionDiff(diff) {
|
|
|
30555
30568
|
return lines.join("\n");
|
|
30556
30569
|
}
|
|
30557
30570
|
|
|
30558
|
-
// plugins/kxm/src/
|
|
30571
|
+
// plugins/kxm/src/repair.ts
|
|
30559
30572
|
function resourceKindForTemplatePath(path4) {
|
|
30560
30573
|
if (path4 === ".kxm/project.yaml") return "project";
|
|
30561
30574
|
if (path4 === ".kxm/gates.yaml") return "gate-registry";
|
|
@@ -30578,7 +30591,7 @@ function repairIssue(code, file, message, phase = "semantic") {
|
|
|
30578
30591
|
return { phase, code, file, message };
|
|
30579
30592
|
}
|
|
30580
30593
|
function fail3(code, file, message, phase = "semantic") {
|
|
30581
|
-
throw new
|
|
30594
|
+
throw new KxmConfigError([repairIssue(code, file, message, phase)]);
|
|
30582
30595
|
}
|
|
30583
30596
|
function syncDirectory2(path4) {
|
|
30584
30597
|
let descriptor;
|
|
@@ -30647,7 +30660,7 @@ function backupFile(projectRoot, portablePath2) {
|
|
|
30647
30660
|
return join24(transactionRoot(projectRoot), "backups", ...portablePath2.split("/"));
|
|
30648
30661
|
}
|
|
30649
30662
|
function portableManagedPath(path4) {
|
|
30650
|
-
return path4.startsWith(".kxm/") && path4 !==
|
|
30663
|
+
return path4.startsWith(".kxm/") && path4 !== KXM_TEMPLATE_PROVENANCE_PATH && path4.length <= 1024 && !path4.includes("\\") && !isAbsolute7(path4) && PORTABLE_PATH.test(path4) && !/[<>:"|?*]/.test(path4);
|
|
30651
30664
|
}
|
|
30652
30665
|
function readRegularBounded(file, label) {
|
|
30653
30666
|
const stat = lstatSync7(file);
|
|
@@ -30669,61 +30682,61 @@ function readOptionalManaged(projectRoot, path4) {
|
|
|
30669
30682
|
}
|
|
30670
30683
|
function readProjectAndProvenance(projectRoot, schemasDir) {
|
|
30671
30684
|
const projectFile = join24(projectRoot, ".kxm", "project.yaml");
|
|
30672
|
-
const provenanceFile = join24(projectRoot, ...
|
|
30685
|
+
const provenanceFile = join24(projectRoot, ...KXM_TEMPLATE_PROVENANCE_PATH.split("/"));
|
|
30673
30686
|
if (!existsSync21(projectFile) || !existsSync21(provenanceFile)) return void 0;
|
|
30674
30687
|
const projectBytes = readOptionalManaged(projectRoot, ".kxm/project.yaml");
|
|
30675
|
-
const provenanceBytes = readOptionalManaged(projectRoot,
|
|
30688
|
+
const provenanceBytes = readOptionalManaged(projectRoot, KXM_TEMPLATE_PROVENANCE_PATH);
|
|
30676
30689
|
if (!projectBytes || !provenanceBytes) return void 0;
|
|
30677
30690
|
const project = parseRestrictedYaml2(projectBytes, ".kxm/project.yaml");
|
|
30678
|
-
const provenanceValue = parseRestrictedYaml2(provenanceBytes,
|
|
30679
|
-
const registry = new
|
|
30691
|
+
const provenanceValue = parseRestrictedYaml2(provenanceBytes, KXM_TEMPLATE_PROVENANCE_PATH);
|
|
30692
|
+
const registry = new KxmSchemaRegistry(schemasDir);
|
|
30680
30693
|
const issues = [
|
|
30681
30694
|
...registry.validate("project", project, ".kxm/project.yaml"),
|
|
30682
|
-
...registry.validateTemplateProvenance(provenanceValue,
|
|
30695
|
+
...registry.validateTemplateProvenance(provenanceValue, KXM_TEMPLATE_PROVENANCE_PATH)
|
|
30683
30696
|
];
|
|
30684
|
-
if (issues.length > 0) throw new
|
|
30685
|
-
const provenance =
|
|
30686
|
-
if (!provenance) fail3("template_provenance_revision_invalid",
|
|
30697
|
+
if (issues.length > 0) throw new KxmConfigError(issues);
|
|
30698
|
+
const provenance = resolveKxmTemplateBaseline(provenanceValue);
|
|
30699
|
+
if (!provenance) fail3("template_provenance_revision_invalid", KXM_TEMPLATE_PROVENANCE_PATH, "template provenance does not exactly match a supported built-in baseline");
|
|
30687
30700
|
if (project.id !== provenance.inputs.projectId) {
|
|
30688
|
-
fail3("template_provenance_project_mismatch",
|
|
30701
|
+
fail3("template_provenance_project_mismatch", KXM_TEMPLATE_PROVENANCE_PATH, "template provenance belongs to a different project identity");
|
|
30689
30702
|
}
|
|
30690
30703
|
const seen = /* @__PURE__ */ new Set();
|
|
30691
30704
|
let prior = "";
|
|
30692
30705
|
let totalBytes = 0;
|
|
30693
30706
|
for (const record of provenance.files) {
|
|
30694
|
-
if (!portableManagedPath(record.path)) fail3("template_provenance_path_invalid",
|
|
30707
|
+
if (!portableManagedPath(record.path)) fail3("template_provenance_path_invalid", KXM_TEMPLATE_PROVENANCE_PATH, `managed path ${record.path} is invalid`, "path");
|
|
30695
30708
|
const folded = record.path.toLocaleLowerCase("en-US");
|
|
30696
|
-
if (seen.has(folded)) fail3("template_provenance_path_collision",
|
|
30697
|
-
if (prior && compareCodeUnits5(prior, record.path) >= 0) fail3("template_provenance_order_invalid",
|
|
30709
|
+
if (seen.has(folded)) fail3("template_provenance_path_collision", KXM_TEMPLATE_PROVENANCE_PATH, `managed path ${record.path} collides after case folding`, "path");
|
|
30710
|
+
if (prior && compareCodeUnits5(prior, record.path) >= 0) fail3("template_provenance_order_invalid", KXM_TEMPLATE_PROVENANCE_PATH, "managed files are not in strict code-unit order");
|
|
30698
30711
|
totalBytes += record.bytes;
|
|
30699
30712
|
seen.add(folded);
|
|
30700
30713
|
prior = record.path;
|
|
30701
30714
|
}
|
|
30702
30715
|
if (provenance.files.length > MAX_MANAGED_FILES || totalBytes > MAX_MANAGED_TOTAL_BYTES) {
|
|
30703
|
-
fail3("template_provenance_bounds_exceeded",
|
|
30716
|
+
fail3("template_provenance_bounds_exceeded", KXM_TEMPLATE_PROVENANCE_PATH, "managed template manifest exceeds bounded file or byte limits", "parse");
|
|
30704
30717
|
}
|
|
30705
30718
|
return { project, provenance, provenanceBytes };
|
|
30706
30719
|
}
|
|
30707
|
-
function
|
|
30720
|
+
function planKxmTemplateRepair(projectRoot, options = {}) {
|
|
30708
30721
|
assertNoRegisteredGates(options);
|
|
30709
30722
|
const root = resolve18(projectRoot);
|
|
30710
30723
|
const source = readProjectAndProvenance(root, options.schemasDir);
|
|
30711
30724
|
if (!source) return void 0;
|
|
30712
|
-
const target =
|
|
30725
|
+
const target = renderKxmTemplate(
|
|
30713
30726
|
source.provenance.inputs.projectId,
|
|
30714
30727
|
source.provenance.inputs.projectName,
|
|
30715
|
-
options.templateVariant ??
|
|
30728
|
+
options.templateVariant ?? CURRENT_KXM_TEMPLATE_VARIANT
|
|
30716
30729
|
);
|
|
30717
30730
|
const baseByPath = new Map(source.provenance.files.map((record) => [record.path, record]));
|
|
30718
30731
|
const targetByPath = new Map(target.provenance.files.map((record) => [record.path, record]));
|
|
30719
30732
|
const paths = [.../* @__PURE__ */ new Set([...baseByPath.keys(), ...targetByPath.keys()])].sort(compareCodeUnits5);
|
|
30720
|
-
const sourceRenderer =
|
|
30721
|
-
const expectedProvenance = sourceRenderer?.files.get(
|
|
30733
|
+
const sourceRenderer = SUPPORTED_KXM_TEMPLATE_VARIANTS.map((variant) => renderKxmTemplate(source.provenance.inputs.projectId, source.provenance.inputs.projectName, variant)).find((candidate) => candidate.templateRevision === source.provenance.templateRevision);
|
|
30734
|
+
const expectedProvenance = sourceRenderer?.files.get(KXM_TEMPLATE_PROVENANCE_PATH);
|
|
30722
30735
|
const issues = [];
|
|
30723
|
-
if (!expectedProvenance ||
|
|
30736
|
+
if (!expectedProvenance || kxmContentSha256(source.provenanceBytes) !== kxmContentSha256(expectedProvenance)) {
|
|
30724
30737
|
issues.push(repairIssue(
|
|
30725
30738
|
"template_provenance_user_modified",
|
|
30726
|
-
|
|
30739
|
+
KXM_TEMPLATE_PROVENANCE_PATH,
|
|
30727
30740
|
"template provenance formatting or bytes differ from the supported baseline and require review"
|
|
30728
30741
|
));
|
|
30729
30742
|
}
|
|
@@ -30731,10 +30744,10 @@ function planVnextTemplateRepair(projectRoot, options = {}) {
|
|
|
30731
30744
|
const base = baseByPath.get(path4);
|
|
30732
30745
|
const targetRecord = targetByPath.get(path4);
|
|
30733
30746
|
const local = readOptionalManaged(root, path4);
|
|
30734
|
-
const localSha256 = local &&
|
|
30747
|
+
const localSha256 = local && kxmContentSha256(local);
|
|
30735
30748
|
const baseSha256 = base?.sha256;
|
|
30736
30749
|
if (base && localSha256 === base.sha256 && local?.byteLength !== base.bytes) {
|
|
30737
|
-
fail3("template_provenance_bytes_invalid",
|
|
30750
|
+
fail3("template_provenance_bytes_invalid", KXM_TEMPLATE_PROVENANCE_PATH, `recorded byte count for ${path4} does not match its baseline content`);
|
|
30738
30751
|
}
|
|
30739
30752
|
const targetSha256 = targetRecord?.sha256;
|
|
30740
30753
|
if (baseSha256 === localSha256 && localSha256 === targetSha256) {
|
|
@@ -30756,7 +30769,7 @@ function planVnextTemplateRepair(projectRoot, options = {}) {
|
|
|
30756
30769
|
if (authorityChanged || !base) {
|
|
30757
30770
|
const baseValue = base ? sourceRenderer?.values.get(path4) : void 0;
|
|
30758
30771
|
const targetValue = target.values.get(path4);
|
|
30759
|
-
const detail = baseValue && targetValue ?
|
|
30772
|
+
const detail = baseValue && targetValue ? computeKxmResourcePermissionDiff(resourceKindForTemplatePath(path4), path4, baseValue, targetValue).map((change) => `${change.path} ${change.field} ${change.direction}`).join("; ") : "";
|
|
30760
30773
|
issues.push(repairIssue(
|
|
30761
30774
|
"template_policy_review_required",
|
|
30762
30775
|
path4,
|
|
@@ -30820,7 +30833,7 @@ function planVnextTemplateRepair(projectRoot, options = {}) {
|
|
|
30820
30833
|
};
|
|
30821
30834
|
}
|
|
30822
30835
|
function operationPlanSha(operation) {
|
|
30823
|
-
return
|
|
30836
|
+
return kxmContentSha256(JSON.stringify({
|
|
30824
30837
|
kind: operation.kind,
|
|
30825
30838
|
projectRoot: operation.projectRoot,
|
|
30826
30839
|
projectId: operation.projectId,
|
|
@@ -30862,9 +30875,9 @@ function readOperation(projectRoot, schemasDir) {
|
|
|
30862
30875
|
fail3("init_transaction_record_missing", TRANSACTION_NAME, "initialization transaction without an operation record contains unrecognized state");
|
|
30863
30876
|
}
|
|
30864
30877
|
const value = parseRestrictedYaml2(readRegularBounded(file, `${TRANSACTION_NAME}/${OPERATION_FILE}`), `${TRANSACTION_NAME}/${OPERATION_FILE}`);
|
|
30865
|
-
const registry = new
|
|
30878
|
+
const registry = new KxmSchemaRegistry(schemasDir);
|
|
30866
30879
|
const issues = registry.validateInitOperation(value, `${TRANSACTION_NAME}/${OPERATION_FILE}`);
|
|
30867
|
-
if (issues.length > 0) throw new
|
|
30880
|
+
if (issues.length > 0) throw new KxmConfigError(issues);
|
|
30868
30881
|
const operation = value;
|
|
30869
30882
|
if (!sameHostPath3(operation.projectRoot, projectRoot)) fail3("init_transaction_project_mismatch", TRANSACTION_NAME, "operation belongs to a different project root");
|
|
30870
30883
|
const expectedPlanSha = operationPlanSha(operation);
|
|
@@ -30882,7 +30895,7 @@ function readOperation(projectRoot, schemasDir) {
|
|
|
30882
30895
|
validateOperationIntent(projectRoot, operation);
|
|
30883
30896
|
return operation;
|
|
30884
30897
|
}
|
|
30885
|
-
function
|
|
30898
|
+
function hasKxmInitTransaction(projectRoot) {
|
|
30886
30899
|
return existsSync21(transactionRoot(projectRoot));
|
|
30887
30900
|
}
|
|
30888
30901
|
function readTarget(projectRoot, path4) {
|
|
@@ -30899,7 +30912,7 @@ function writeAndVerifyBackups(projectRoot, operation) {
|
|
|
30899
30912
|
for (const entry of operation.files) {
|
|
30900
30913
|
if (entry.observedSha256 === null) continue;
|
|
30901
30914
|
const current = readOptionalManaged(projectRoot, entry.path);
|
|
30902
|
-
if (!current ||
|
|
30915
|
+
if (!current || kxmContentSha256(current) !== entry.observedSha256) {
|
|
30903
30916
|
fail3("repair_preimage_changed", entry.path, "destination changed before transaction preparation; local bytes were preserved");
|
|
30904
30917
|
}
|
|
30905
30918
|
const file = backupFile(projectRoot, entry.path);
|
|
@@ -30914,7 +30927,7 @@ function writeKnownBackups(projectRoot, operation) {
|
|
|
30914
30927
|
for (const entry of operation.files) {
|
|
30915
30928
|
if (entry.observedSha256 === null) continue;
|
|
30916
30929
|
const bytes = source.files.get(entry.path);
|
|
30917
|
-
if (!bytes ||
|
|
30930
|
+
if (!bytes || kxmContentSha256(bytes) !== entry.observedSha256) {
|
|
30918
30931
|
fail3("init_transaction_backup_source_invalid", entry.path, "supported source template cannot reproduce the pinned preimage");
|
|
30919
30932
|
}
|
|
30920
30933
|
const file = backupFile(projectRoot, entry.path);
|
|
@@ -30927,7 +30940,7 @@ function verifyBackups(projectRoot, operation) {
|
|
|
30927
30940
|
for (const entry of operation.files) {
|
|
30928
30941
|
if (entry.observedSha256 === null) continue;
|
|
30929
30942
|
const bytes = readOptionalManaged(join24(transactionRoot(projectRoot), "backups"), entry.path);
|
|
30930
|
-
if (!bytes ||
|
|
30943
|
+
if (!bytes || kxmContentSha256(bytes) !== entry.observedSha256) {
|
|
30931
30944
|
fail3("init_transaction_backup_invalid", entry.path, "pinned preimage backup is missing or corrupt");
|
|
30932
30945
|
}
|
|
30933
30946
|
}
|
|
@@ -30938,7 +30951,7 @@ function verifyTargetArtifacts(projectRoot, operation) {
|
|
|
30938
30951
|
const bytes = readTarget(projectRoot, entry.path);
|
|
30939
30952
|
if (!bytes) fail3("init_transaction_target_missing", entry.path, "pinned target artifact is missing");
|
|
30940
30953
|
total += bytes.byteLength;
|
|
30941
|
-
if (
|
|
30954
|
+
if (kxmContentSha256(bytes) !== entry.targetSha256) fail3("init_transaction_target_mismatch", entry.path, "pinned target artifact hash does not match the operation");
|
|
30942
30955
|
}
|
|
30943
30956
|
if (operation.files.length > MAX_MANAGED_FILES || total > MAX_MANAGED_TOTAL_BYTES) fail3("init_transaction_bounds_exceeded", TRANSACTION_NAME, "operation exceeds bounded file or byte limits", "parse");
|
|
30944
30957
|
}
|
|
@@ -30955,7 +30968,7 @@ function sourceConfigFiles(projectRoot) {
|
|
|
30955
30968
|
const fixed = [
|
|
30956
30969
|
".kxm/project.yaml",
|
|
30957
30970
|
".kxm/gates.yaml",
|
|
30958
|
-
|
|
30971
|
+
KXM_TEMPLATE_PROVENANCE_PATH,
|
|
30959
30972
|
".kxm/project/env.yaml",
|
|
30960
30973
|
".kxm/repo/repo.yaml",
|
|
30961
30974
|
".kxm/repo/env.yaml"
|
|
@@ -31016,10 +31029,10 @@ function prepareShadow(projectRoot, operation, options) {
|
|
|
31016
31029
|
}
|
|
31017
31030
|
const project = parseRestrictedYaml2(readFileSync21(join24(shadow, ".kxm", "project.yaml")), ".kxm/project.yaml");
|
|
31018
31031
|
const bound = absoluteMemberBindings(projectRoot, project, options.repositoryBindings);
|
|
31019
|
-
|
|
31032
|
+
loadKxmProject(shadow, { ...loaderOptions(options), repositoryBindings: bound });
|
|
31020
31033
|
const provenance = readProjectAndProvenance(shadow, options.schemasDir)?.provenance;
|
|
31021
31034
|
if (!provenance || provenance.templateRevision !== operation.targetTemplateRevision) {
|
|
31022
|
-
fail3("repair_shadow_provenance_invalid",
|
|
31035
|
+
fail3("repair_shadow_provenance_invalid", KXM_TEMPLATE_PROVENANCE_PATH, "prospective template provenance does not match the pinned target");
|
|
31023
31036
|
}
|
|
31024
31037
|
}
|
|
31025
31038
|
function createOperation(projectRoot, kind, rendered, files, sourceTemplateRevision) {
|
|
@@ -31031,7 +31044,7 @@ function createOperation(projectRoot, kind, rendered, files, sourceTemplateRevis
|
|
|
31031
31044
|
projectRoot: root,
|
|
31032
31045
|
projectId: rendered.projectId,
|
|
31033
31046
|
projectName: rendered.projectName,
|
|
31034
|
-
templateId:
|
|
31047
|
+
templateId: KXM_TEMPLATE_ID,
|
|
31035
31048
|
sourceTemplateRevision,
|
|
31036
31049
|
targetTemplateRevision: rendered.templateRevision,
|
|
31037
31050
|
files: [...files].sort((left, right) => compareCodeUnits5(left.path, right.path))
|
|
@@ -31045,8 +31058,8 @@ function createOperation(projectRoot, kind, rendered, files, sourceTemplateRevis
|
|
|
31045
31058
|
function validateOperationRecord(operation, schemasDir) {
|
|
31046
31059
|
const label = `${TRANSACTION_NAME}/${OPERATION_FILE}`;
|
|
31047
31060
|
const value = parseRestrictedYaml2(Buffer.from(JSON.stringify(operation), "utf8"), label);
|
|
31048
|
-
const issues = new
|
|
31049
|
-
if (issues.length > 0) throw new
|
|
31061
|
+
const issues = new KxmSchemaRegistry(schemasDir).validateInitOperation(value, label);
|
|
31062
|
+
if (issues.length > 0) throw new KxmConfigError(issues);
|
|
31050
31063
|
}
|
|
31051
31064
|
function prepareOperation(projectRoot, operation, rendered, options) {
|
|
31052
31065
|
const transaction = transactionRoot(projectRoot);
|
|
@@ -31059,7 +31072,7 @@ function prepareOperation(projectRoot, operation, rendered, options) {
|
|
|
31059
31072
|
try {
|
|
31060
31073
|
for (const entry of operation.files) {
|
|
31061
31074
|
const bytes = rendered.files.get(entry.path);
|
|
31062
|
-
if (!bytes ||
|
|
31075
|
+
if (!bytes || kxmContentSha256(bytes) !== entry.targetSha256) fail3("template_target_unavailable", entry.path, "renderer cannot reproduce the pinned target bytes");
|
|
31063
31076
|
writeTarget(projectRoot, entry.path, bytes);
|
|
31064
31077
|
}
|
|
31065
31078
|
writeAndVerifyBackups(projectRoot, operation);
|
|
@@ -31087,7 +31100,7 @@ function ensureDestinationParents(projectRoot, path4) {
|
|
|
31087
31100
|
function destinationSha(projectRoot, path4) {
|
|
31088
31101
|
const file = join24(projectRoot, ...path4.split("/"));
|
|
31089
31102
|
if (!existsSync21(file)) return void 0;
|
|
31090
|
-
return
|
|
31103
|
+
return kxmContentSha256(readRegularBounded(file, path4));
|
|
31091
31104
|
}
|
|
31092
31105
|
function requireConditionalLinkSupport(directory, operationId, path4) {
|
|
31093
31106
|
const nonce = randomUUID10();
|
|
@@ -31111,12 +31124,12 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31111
31124
|
ensureDestinationParents(projectRoot, entry.path);
|
|
31112
31125
|
const directory = dirname15(destination);
|
|
31113
31126
|
const temporaryPrefix = `.kxm-repair-${operation.operationId}-`;
|
|
31114
|
-
const pathKey =
|
|
31127
|
+
const pathKey = kxmContentSha256(entry.path).slice("sha256:".length, "sha256:".length + 16);
|
|
31115
31128
|
const displaced = join24(directory, `${temporaryPrefix}${pathKey}.preimage`);
|
|
31116
31129
|
if (existsSync21(displaced)) {
|
|
31117
31130
|
const stat = lstatSync7(displaced);
|
|
31118
31131
|
if (stat.isSymbolicLink() || !stat.isFile()) fail3("repair_preimage_temporary_invalid", entry.path, "stale displaced preimage is not a regular file", "path");
|
|
31119
|
-
if (entry.observedSha256 === null ||
|
|
31132
|
+
if (entry.observedSha256 === null || kxmContentSha256(readFileSync21(displaced)) !== entry.observedSha256) {
|
|
31120
31133
|
fail3("repair_preimage_temporary_mismatch", entry.path, "stale displaced preimage does not match the pinned operation");
|
|
31121
31134
|
}
|
|
31122
31135
|
if (!existsSync21(destination)) {
|
|
@@ -31151,7 +31164,7 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31151
31164
|
if (entry.observedSha256 !== null) {
|
|
31152
31165
|
renameSync6(destination, displaced);
|
|
31153
31166
|
syncDirectory2(directory);
|
|
31154
|
-
if (
|
|
31167
|
+
if (kxmContentSha256(readFileSync21(displaced)) !== entry.observedSha256) {
|
|
31155
31168
|
if (!existsSync21(destination)) {
|
|
31156
31169
|
try {
|
|
31157
31170
|
linkSync(displaced, destination);
|
|
@@ -31249,23 +31262,23 @@ function applyOperation(projectRoot, original, options, resumed) {
|
|
|
31249
31262
|
fail3("create_resume_conflict", ".kxm", "existing project configuration does not match the pinned create operation");
|
|
31250
31263
|
}
|
|
31251
31264
|
} else {
|
|
31252
|
-
const resources = operation.files.filter((entry) => entry.path !==
|
|
31265
|
+
const resources = operation.files.filter((entry) => entry.path !== KXM_TEMPLATE_PROVENANCE_PATH && entry.action !== "none");
|
|
31253
31266
|
let installed = 0;
|
|
31254
31267
|
for (const entry of resources) {
|
|
31255
31268
|
atomicInstallTarget(projectRoot, operation, entry);
|
|
31256
31269
|
installed += 1;
|
|
31257
31270
|
if (installed === 1 && options.testFaultAt === "first-resource") throw new Error("injected init fault after first resource");
|
|
31258
31271
|
}
|
|
31259
|
-
|
|
31260
|
-
const provenance = operation.files.find((entry) => entry.path ===
|
|
31272
|
+
loadKxmProject(projectRoot, loaderOptions(effectiveOptions));
|
|
31273
|
+
const provenance = operation.files.find((entry) => entry.path === KXM_TEMPLATE_PROVENANCE_PATH);
|
|
31261
31274
|
if (!provenance) fail3("repair_provenance_target_missing", TRANSACTION_NAME, "repair operation has no final provenance target");
|
|
31262
31275
|
atomicInstallTarget(projectRoot, operation, provenance);
|
|
31263
31276
|
if (options.testFaultAt === "provenance") throw new Error("injected init fault after provenance");
|
|
31264
31277
|
}
|
|
31265
|
-
const bundle =
|
|
31278
|
+
const bundle = loadKxmProject(projectRoot, loaderOptions(effectiveOptions));
|
|
31266
31279
|
const source = readProjectAndProvenance(projectRoot, effectiveOptions.schemasDir);
|
|
31267
31280
|
if (!source || source.provenance.templateRevision !== operation.targetTemplateRevision) {
|
|
31268
|
-
fail3("init_operation_verification_failed",
|
|
31281
|
+
fail3("init_operation_verification_failed", KXM_TEMPLATE_PROVENANCE_PATH, "installed provenance does not match the pinned transaction");
|
|
31269
31282
|
}
|
|
31270
31283
|
operation = updatePhase(projectRoot, operation, "verified");
|
|
31271
31284
|
if (options.testFaultAt === "verified") throw new Error("injected init fault after verification");
|
|
@@ -31273,12 +31286,12 @@ function applyOperation(projectRoot, original, options, resumed) {
|
|
|
31273
31286
|
syncTreeDirectories(join24(projectRoot, ".kxm"));
|
|
31274
31287
|
return { kind: operation.kind, resumed, bundle, files };
|
|
31275
31288
|
}
|
|
31276
|
-
function
|
|
31289
|
+
function prepareAndApplyKxmCreate(projectRoot, rendered, options = {}) {
|
|
31277
31290
|
assertNoRegisteredGates(options);
|
|
31278
31291
|
const files = [...rendered.files.entries()].map(([path4, bytes]) => ({
|
|
31279
31292
|
path: path4,
|
|
31280
31293
|
observedSha256: null,
|
|
31281
|
-
targetSha256:
|
|
31294
|
+
targetSha256: kxmContentSha256(bytes),
|
|
31282
31295
|
classification: "template-only",
|
|
31283
31296
|
action: "create"
|
|
31284
31297
|
}));
|
|
@@ -31287,16 +31300,16 @@ function prepareAndApplyVnextCreate(projectRoot, rendered, options = {}) {
|
|
|
31287
31300
|
if (options.testFaultAt === "prepared") throw new Error("injected init fault after prepare");
|
|
31288
31301
|
return applyOperation(projectRoot, prepared, options, false);
|
|
31289
31302
|
}
|
|
31290
|
-
function
|
|
31303
|
+
function prepareAndApplyKxmRepair(plan, options = {}) {
|
|
31291
31304
|
assertNoRegisteredGates(options);
|
|
31292
31305
|
if (!plan.canApply) fail3("template_repair_not_applicable", ".kxm", "template repair has conflicts, policy changes, or no safe template-only update");
|
|
31293
|
-
const rendered =
|
|
31306
|
+
const rendered = renderKxmTemplate(plan.projectId, plan.projectName, options.templateVariant ?? CURRENT_KXM_TEMPLATE_VARIANT);
|
|
31294
31307
|
if (rendered.templateRevision !== plan.targetTemplateRevision) fail3("template_repair_target_changed", ".kxm", "template target changed after planning");
|
|
31295
31308
|
const actionable = plan.changes.filter((change) => change.classification === "template-only");
|
|
31296
|
-
const provenanceBytes = rendered.files.get(
|
|
31297
|
-
if (!provenanceBytes) fail3("template_provenance_target_missing",
|
|
31298
|
-
const sourceProvenance = readOptionalManaged(plan.projectRoot,
|
|
31299
|
-
if (!sourceProvenance) fail3("template_provenance_missing",
|
|
31309
|
+
const provenanceBytes = rendered.files.get(KXM_TEMPLATE_PROVENANCE_PATH);
|
|
31310
|
+
if (!provenanceBytes) fail3("template_provenance_target_missing", KXM_TEMPLATE_PROVENANCE_PATH, "renderer did not produce provenance");
|
|
31311
|
+
const sourceProvenance = readOptionalManaged(plan.projectRoot, KXM_TEMPLATE_PROVENANCE_PATH);
|
|
31312
|
+
if (!sourceProvenance) fail3("template_provenance_missing", KXM_TEMPLATE_PROVENANCE_PATH, "repair requires recorded provenance");
|
|
31300
31313
|
const files = actionable.map((change) => ({
|
|
31301
31314
|
path: change.path,
|
|
31302
31315
|
observedSha256: change.localSha256 ?? null,
|
|
@@ -31305,9 +31318,9 @@ function prepareAndApplyVnextRepair(plan, options = {}) {
|
|
|
31305
31318
|
action: change.action
|
|
31306
31319
|
}));
|
|
31307
31320
|
files.push({
|
|
31308
|
-
path:
|
|
31309
|
-
observedSha256:
|
|
31310
|
-
targetSha256:
|
|
31321
|
+
path: KXM_TEMPLATE_PROVENANCE_PATH,
|
|
31322
|
+
observedSha256: kxmContentSha256(sourceProvenance),
|
|
31323
|
+
targetSha256: kxmContentSha256(provenanceBytes),
|
|
31311
31324
|
classification: "template-only",
|
|
31312
31325
|
action: "replace"
|
|
31313
31326
|
});
|
|
@@ -31317,8 +31330,8 @@ function prepareAndApplyVnextRepair(plan, options = {}) {
|
|
|
31317
31330
|
return applyOperation(plan.projectRoot, prepared, options, false);
|
|
31318
31331
|
}
|
|
31319
31332
|
function rendererForRevision(operation, revision) {
|
|
31320
|
-
for (const variant of
|
|
31321
|
-
const rendered =
|
|
31333
|
+
for (const variant of SUPPORTED_KXM_TEMPLATE_VARIANTS) {
|
|
31334
|
+
const rendered = renderKxmTemplate(operation.projectId, operation.projectName, variant);
|
|
31322
31335
|
if (rendered.templateRevision === revision) return rendered;
|
|
31323
31336
|
}
|
|
31324
31337
|
return void 0;
|
|
@@ -31337,7 +31350,7 @@ function validateOperationIntent(projectRoot, operation) {
|
|
|
31337
31350
|
if (entries.size !== target.files.size) fail3("init_transaction_create_files_invalid", TRANSACTION_NAME, "create operation does not contain the exact built-in target file set");
|
|
31338
31351
|
for (const [path4, bytes] of target.files) {
|
|
31339
31352
|
const entry = entries.get(path4);
|
|
31340
|
-
if (!entry || entry.observedSha256 !== null || entry.targetSha256 !==
|
|
31353
|
+
if (!entry || entry.observedSha256 !== null || entry.targetSha256 !== kxmContentSha256(bytes) || entry.classification !== "template-only" || entry.action !== "create") {
|
|
31341
31354
|
fail3("init_transaction_create_file_invalid", path4, "create operation file does not match its built-in target");
|
|
31342
31355
|
}
|
|
31343
31356
|
}
|
|
@@ -31361,14 +31374,14 @@ function validateOperationIntent(projectRoot, operation) {
|
|
|
31361
31374
|
}
|
|
31362
31375
|
if (base.sha256 !== next.sha256) safeChangedPaths.push(path4);
|
|
31363
31376
|
}
|
|
31364
|
-
const provenanceEntry = entries.get(
|
|
31365
|
-
const sourceProvenanceBytes = source.files.get(
|
|
31366
|
-
const targetProvenanceBytes = target.files.get(
|
|
31367
|
-
if (!provenanceEntry || provenanceEntry.observedSha256 !==
|
|
31368
|
-
fail3("init_transaction_provenance_intent_invalid",
|
|
31377
|
+
const provenanceEntry = entries.get(KXM_TEMPLATE_PROVENANCE_PATH);
|
|
31378
|
+
const sourceProvenanceBytes = source.files.get(KXM_TEMPLATE_PROVENANCE_PATH);
|
|
31379
|
+
const targetProvenanceBytes = target.files.get(KXM_TEMPLATE_PROVENANCE_PATH);
|
|
31380
|
+
if (!provenanceEntry || provenanceEntry.observedSha256 !== kxmContentSha256(sourceProvenanceBytes) || provenanceEntry.targetSha256 !== kxmContentSha256(targetProvenanceBytes) || provenanceEntry.classification !== "template-only" || provenanceEntry.action !== "replace") {
|
|
31381
|
+
fail3("init_transaction_provenance_intent_invalid", KXM_TEMPLATE_PROVENANCE_PATH, "repair provenance action does not match supported source and target templates");
|
|
31369
31382
|
}
|
|
31370
31383
|
for (const [path4, entry] of entries) {
|
|
31371
|
-
if (path4 ===
|
|
31384
|
+
if (path4 === KXM_TEMPLATE_PROVENANCE_PATH) continue;
|
|
31372
31385
|
const base = sourceRecords.get(path4);
|
|
31373
31386
|
const next = targetRecords.get(path4);
|
|
31374
31387
|
if (!base || !next || base.sha256 === next.sha256 || entry.observedSha256 !== base.sha256 || entry.targetSha256 !== next.sha256 || entry.classification !== "template-only" || entry.action !== "replace") {
|
|
@@ -31389,7 +31402,7 @@ function finishPreparingOperation(projectRoot, operation, options) {
|
|
|
31389
31402
|
}
|
|
31390
31403
|
for (const entry of operation.files) {
|
|
31391
31404
|
const bytes = rendered.files.get(entry.path);
|
|
31392
|
-
if (!bytes ||
|
|
31405
|
+
if (!bytes || kxmContentSha256(bytes) !== entry.targetSha256) fail3("template_target_unavailable", entry.path, "renderer cannot reproduce the pinned target bytes");
|
|
31393
31406
|
writeTarget(projectRoot, entry.path, bytes);
|
|
31394
31407
|
}
|
|
31395
31408
|
writeKnownBackups(projectRoot, operation);
|
|
@@ -31399,7 +31412,7 @@ function finishPreparingOperation(projectRoot, operation, options) {
|
|
|
31399
31412
|
syncTreeDirectories(transactionRoot(projectRoot));
|
|
31400
31413
|
return updatePhase(projectRoot, operation, "prepared");
|
|
31401
31414
|
}
|
|
31402
|
-
function
|
|
31415
|
+
function resumeKxmInitTransaction(projectRoot, options = {}) {
|
|
31403
31416
|
assertNoRegisteredGates(options);
|
|
31404
31417
|
let operation = readOperation(projectRoot, options.schemasDir);
|
|
31405
31418
|
if (!operation) {
|
|
@@ -31414,7 +31427,7 @@ function resumeVnextInitTransaction(projectRoot, options = {}) {
|
|
|
31414
31427
|
verifyTargetArtifacts(projectRoot, operation);
|
|
31415
31428
|
return applyOperation(projectRoot, operation, options, true);
|
|
31416
31429
|
}
|
|
31417
|
-
function
|
|
31430
|
+
function commitKxmInitTransaction(projectRoot, schemasDir) {
|
|
31418
31431
|
const operation = readOperation(projectRoot, schemasDir);
|
|
31419
31432
|
if (!operation || operation.phase !== "verified") {
|
|
31420
31433
|
fail3("init_transaction_not_verified", TRANSACTION_NAME, "initialization transaction cannot commit before installed state is verified");
|
|
@@ -31426,7 +31439,7 @@ function commitVnextInitTransaction(projectRoot, schemasDir) {
|
|
|
31426
31439
|
rmSync8(retired, { recursive: true, force: true });
|
|
31427
31440
|
syncDirectory2(projectRoot);
|
|
31428
31441
|
}
|
|
31429
|
-
function
|
|
31442
|
+
function inspectKxmInitTransaction(projectRoot, schemasDir) {
|
|
31430
31443
|
const operation = readOperation(projectRoot, schemasDir);
|
|
31431
31444
|
if (operation && operation.phase !== "preparing") {
|
|
31432
31445
|
verifyTargetArtifacts(projectRoot, operation);
|
|
@@ -31435,7 +31448,7 @@ function inspectVnextInitTransaction(projectRoot, schemasDir) {
|
|
|
31435
31448
|
return operation;
|
|
31436
31449
|
}
|
|
31437
31450
|
|
|
31438
|
-
// plugins/kxm/src/
|
|
31451
|
+
// plugins/kxm/src/init.ts
|
|
31439
31452
|
var PROJECT_ID = /^prj_[A-Za-z0-9][A-Za-z0-9_-]{5,127}$/;
|
|
31440
31453
|
function initIssue(code, file, message) {
|
|
31441
31454
|
return { phase: "discovery", code, file, message };
|
|
@@ -31443,14 +31456,14 @@ function initIssue(code, file, message) {
|
|
|
31443
31456
|
function normalizedProjectName(root, requested) {
|
|
31444
31457
|
const name = (requested ?? basename5(root) ?? "KXM Project").trim();
|
|
31445
31458
|
if (name.length < 1 || name.length > 120 || /[\u0000\r\n]/.test(name)) {
|
|
31446
|
-
throw new
|
|
31459
|
+
throw new KxmConfigError([initIssue("project_name_invalid", ".kxm/project.yaml", "project name must contain 1-120 characters on one line")]);
|
|
31447
31460
|
}
|
|
31448
31461
|
return name;
|
|
31449
31462
|
}
|
|
31450
31463
|
function generatedProjectId(requested) {
|
|
31451
31464
|
const id = requested?.trim() || `prj_${randomUUID11().replaceAll("-", "")}`;
|
|
31452
31465
|
if (!PROJECT_ID.test(id) || id.length > 144) {
|
|
31453
|
-
throw new
|
|
31466
|
+
throw new KxmConfigError([initIssue("project_id_invalid", ".kxm/project.yaml", "project ID must satisfy the kxm.project.v1 opaque ID grammar and use the prj_ prefix")]);
|
|
31454
31467
|
}
|
|
31455
31468
|
return id;
|
|
31456
31469
|
}
|
|
@@ -31466,7 +31479,7 @@ function configOptions(options, repositoryBindings) {
|
|
|
31466
31479
|
function repairOptions(options, repositoryBindings) {
|
|
31467
31480
|
return {
|
|
31468
31481
|
...configOptions(options, repositoryBindings),
|
|
31469
|
-
templateVariant: options.templateVariant ??
|
|
31482
|
+
templateVariant: options.templateVariant ?? CURRENT_KXM_TEMPLATE_VARIANT,
|
|
31470
31483
|
...options.testFaultAt === void 0 ? {} : { testFaultAt: options.testFaultAt }
|
|
31471
31484
|
};
|
|
31472
31485
|
}
|
|
@@ -31485,7 +31498,7 @@ function memberRepositoryIds(project) {
|
|
|
31485
31498
|
}));
|
|
31486
31499
|
}
|
|
31487
31500
|
function completedPlan(projectRoot, options) {
|
|
31488
|
-
return
|
|
31501
|
+
return planKxmInitialization(projectRoot, options);
|
|
31489
31502
|
}
|
|
31490
31503
|
function finalizeBindingUpdate(bundle, persisted, allBindings, explicitBindings, storeOptions, mutationLock, dryRun) {
|
|
31491
31504
|
const memberIds = validateBindingIdentities(bundle, persisted, explicitBindings);
|
|
@@ -31494,10 +31507,10 @@ function finalizeBindingUpdate(bundle, persisted, allBindings, explicitBindings,
|
|
|
31494
31507
|
}
|
|
31495
31508
|
const memberBindings = Object.fromEntries(Object.entries(allBindings).filter(([repositoryId]) => memberIds.has(repositoryId)));
|
|
31496
31509
|
const projectId = String(bundle.project.value.id);
|
|
31497
|
-
const bindingPlan =
|
|
31510
|
+
const bindingPlan = planKxmLocalBindings(bundle.projectRoot, projectId, memberBindings, storeOptions);
|
|
31498
31511
|
if (dryRun) return { localBindingFile: bindingPlan.file, bindingsChanged: bindingPlan.written };
|
|
31499
31512
|
if (bindingPlan.written && !mutationLock) throw new Error("project mutation lock is required to persist repository bindings");
|
|
31500
|
-
const result = bindingPlan.written ?
|
|
31513
|
+
const result = bindingPlan.written ? writeKxmLocalBindings(bundle.projectRoot, projectId, memberBindings, storeOptions, mutationLock) : bindingPlan;
|
|
31501
31514
|
return { localBindingFile: result.file, bindingsChanged: result.written };
|
|
31502
31515
|
}
|
|
31503
31516
|
function plannedRepairResult(plan, projectRoot, repairPlan) {
|
|
@@ -31512,37 +31525,37 @@ function plannedRepairResult(plan, projectRoot, repairPlan) {
|
|
|
31512
31525
|
function validateBindingIdentities(bundle, persisted, explicit) {
|
|
31513
31526
|
const projectId = String(bundle.project.value.id);
|
|
31514
31527
|
if (persisted && persisted.projectId !== projectId) {
|
|
31515
|
-
throw new
|
|
31528
|
+
throw new KxmConfigError([initIssue("local_binding_project_id_mismatch", "Runtime-local repository bindings", "binding record belongs to a different project identity")]);
|
|
31516
31529
|
}
|
|
31517
31530
|
const memberIds = memberRepositoryIds(bundle.project.value);
|
|
31518
31531
|
for (const repositoryId of Object.keys(persisted?.repositories ?? {})) {
|
|
31519
31532
|
if (!memberIds.has(repositoryId)) {
|
|
31520
|
-
throw new
|
|
31533
|
+
throw new KxmConfigError([initIssue("local_binding_repository_invalid", "Runtime-local repository bindings", `persisted binding ${repositoryId} is not a member repository`)]);
|
|
31521
31534
|
}
|
|
31522
31535
|
}
|
|
31523
31536
|
for (const repositoryId of Object.keys(explicit)) {
|
|
31524
31537
|
if (!memberIds.has(repositoryId)) {
|
|
31525
|
-
throw new
|
|
31538
|
+
throw new KxmConfigError([initIssue("local_binding_repository_invalid", "Runtime-local repository bindings", `explicit binding ${repositoryId} is not a member repository`)]);
|
|
31526
31539
|
}
|
|
31527
31540
|
}
|
|
31528
31541
|
return memberIds;
|
|
31529
31542
|
}
|
|
31530
|
-
function
|
|
31543
|
+
function initializeKxmProjectAtGitRoot(start, gitRoot, options, mutationLock) {
|
|
31531
31544
|
const storeOptions = bindingStoreOptions(options);
|
|
31532
|
-
const persisted = existsSync22(join25(gitRoot, ".kxm", "project.yaml")) ?
|
|
31545
|
+
const persisted = existsSync22(join25(gitRoot, ".kxm", "project.yaml")) ? readKxmLocalBindings(gitRoot, storeOptions) : void 0;
|
|
31533
31546
|
const repositoryBindings = Object.fromEntries([
|
|
31534
31547
|
...Object.entries(persisted?.repositories ?? {}),
|
|
31535
31548
|
...Object.entries(options.repositoryBindings ?? {})
|
|
31536
31549
|
]);
|
|
31537
31550
|
const loaderOptions2 = configOptions(options, repositoryBindings);
|
|
31538
31551
|
const transactionOptions = repairOptions(options, repositoryBindings);
|
|
31539
|
-
if (
|
|
31540
|
-
const operation =
|
|
31541
|
-
const plan2 =
|
|
31552
|
+
if (hasKxmInitTransaction(gitRoot)) {
|
|
31553
|
+
const operation = inspectKxmInitTransaction(gitRoot, options.schemasDir);
|
|
31554
|
+
const plan2 = planKxmInitialization(start, loaderOptions2);
|
|
31542
31555
|
if (!operation) {
|
|
31543
31556
|
if (options.dryRun) return { action: "planned", plan: plan2, projectRoot: gitRoot, resumePending: true, files: [] };
|
|
31544
31557
|
if (!mutationLock) throw new Error("project mutation lock is required to clean an empty transaction");
|
|
31545
|
-
|
|
31558
|
+
resumeKxmInitTransaction(gitRoot, transactionOptions);
|
|
31546
31559
|
} else if (options.dryRun) {
|
|
31547
31560
|
return {
|
|
31548
31561
|
action: "planned",
|
|
@@ -31555,13 +31568,13 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31555
31568
|
} else {
|
|
31556
31569
|
if (!mutationLock) throw new Error("project mutation lock is required to resume initialization");
|
|
31557
31570
|
if (options.projectId !== void 0 && options.projectId !== operation.projectId) {
|
|
31558
|
-
throw new
|
|
31571
|
+
throw new KxmConfigError([initIssue("resume_project_id_mismatch", "--project-id", "requested project ID differs from the pinned initialization transaction")]);
|
|
31559
31572
|
}
|
|
31560
31573
|
if (options.projectName !== void 0 && options.projectName !== operation.projectName) {
|
|
31561
|
-
throw new
|
|
31574
|
+
throw new KxmConfigError([initIssue("resume_project_name_mismatch", "--name", "requested project name differs from the pinned initialization transaction")]);
|
|
31562
31575
|
}
|
|
31563
31576
|
if (operation.kind === "repair" && Object.keys(options.repositoryBindings ?? {}).length > 0) {
|
|
31564
|
-
const currentBundle =
|
|
31577
|
+
const currentBundle = loadKxmProject(gitRoot, loaderOptions2);
|
|
31565
31578
|
finalizeBindingUpdate(
|
|
31566
31579
|
currentBundle,
|
|
31567
31580
|
persisted,
|
|
@@ -31572,7 +31585,7 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31572
31585
|
false
|
|
31573
31586
|
);
|
|
31574
31587
|
}
|
|
31575
|
-
const result =
|
|
31588
|
+
const result = resumeKxmInitTransaction(gitRoot, transactionOptions);
|
|
31576
31589
|
if (!result) throw new Error("initialization transaction disappeared while holding the project lock");
|
|
31577
31590
|
const bindingResult = finalizeBindingUpdate(
|
|
31578
31591
|
result.bundle,
|
|
@@ -31583,7 +31596,7 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31583
31596
|
mutationLock,
|
|
31584
31597
|
false
|
|
31585
31598
|
);
|
|
31586
|
-
|
|
31599
|
+
commitKxmInitTransaction(gitRoot, options.schemasDir);
|
|
31587
31600
|
return {
|
|
31588
31601
|
action: "resumed",
|
|
31589
31602
|
plan: completedPlan(gitRoot, loaderOptions2),
|
|
@@ -31595,7 +31608,7 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31595
31608
|
};
|
|
31596
31609
|
}
|
|
31597
31610
|
}
|
|
31598
|
-
const plan =
|
|
31611
|
+
const plan = planKxmInitialization(start, loaderOptions2);
|
|
31599
31612
|
if (plan.mode === "migrate") {
|
|
31600
31613
|
return { action: "planned", plan, ...plan.projectRoot ? { projectRoot: plan.projectRoot } : {}, files: [] };
|
|
31601
31614
|
}
|
|
@@ -31603,9 +31616,9 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31603
31616
|
const projectRoot = plan.projectRoot ?? gitRoot;
|
|
31604
31617
|
let templateRepair;
|
|
31605
31618
|
try {
|
|
31606
|
-
templateRepair =
|
|
31619
|
+
templateRepair = planKxmTemplateRepair(projectRoot, transactionOptions);
|
|
31607
31620
|
} catch (error) {
|
|
31608
|
-
if (!(error instanceof
|
|
31621
|
+
if (!(error instanceof KxmConfigError)) throw error;
|
|
31609
31622
|
return plannedRepairResult({ ...plan, issues: [...plan.issues, ...error.issues] }, projectRoot);
|
|
31610
31623
|
}
|
|
31611
31624
|
if (!templateRepair?.canApply) return plannedRepairResult(plan, projectRoot, templateRepair);
|
|
@@ -31623,7 +31636,7 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31623
31636
|
return plannedRepairResult(plan, projectRoot, blockedRepair);
|
|
31624
31637
|
}
|
|
31625
31638
|
if (!mutationLock) throw new Error("project mutation lock is required to apply template repair");
|
|
31626
|
-
const repaired =
|
|
31639
|
+
const repaired = prepareAndApplyKxmRepair(templateRepair, transactionOptions);
|
|
31627
31640
|
const bindingResult = finalizeBindingUpdate(
|
|
31628
31641
|
repaired.bundle,
|
|
31629
31642
|
persisted,
|
|
@@ -31633,7 +31646,7 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31633
31646
|
mutationLock,
|
|
31634
31647
|
false
|
|
31635
31648
|
);
|
|
31636
|
-
|
|
31649
|
+
commitKxmInitTransaction(projectRoot, options.schemasDir);
|
|
31637
31650
|
return {
|
|
31638
31651
|
action: "repaired",
|
|
31639
31652
|
plan: completedPlan(projectRoot, loaderOptions2),
|
|
@@ -31646,8 +31659,8 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31646
31659
|
}
|
|
31647
31660
|
if (plan.mode === "ready") {
|
|
31648
31661
|
const projectRoot = plan.projectRoot ?? gitRoot;
|
|
31649
|
-
const bundle =
|
|
31650
|
-
const templateRepair =
|
|
31662
|
+
const bundle = loadKxmProject(projectRoot, loaderOptions2);
|
|
31663
|
+
const templateRepair = planKxmTemplateRepair(projectRoot, transactionOptions);
|
|
31651
31664
|
if (templateRepair?.changesRequired) {
|
|
31652
31665
|
if (!templateRepair.canApply || options.dryRun) return plannedRepairResult(plan, projectRoot, templateRepair);
|
|
31653
31666
|
if (!mutationLock) throw new Error("project mutation lock is required to apply template repair");
|
|
@@ -31660,7 +31673,7 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31660
31673
|
mutationLock,
|
|
31661
31674
|
false
|
|
31662
31675
|
);
|
|
31663
|
-
const repaired =
|
|
31676
|
+
const repaired = prepareAndApplyKxmRepair(templateRepair, transactionOptions);
|
|
31664
31677
|
finalizeBindingUpdate(
|
|
31665
31678
|
repaired.bundle,
|
|
31666
31679
|
persisted,
|
|
@@ -31670,7 +31683,7 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31670
31683
|
mutationLock,
|
|
31671
31684
|
false
|
|
31672
31685
|
);
|
|
31673
|
-
|
|
31686
|
+
commitKxmInitTransaction(projectRoot, options.schemasDir);
|
|
31674
31687
|
return {
|
|
31675
31688
|
action: "repaired",
|
|
31676
31689
|
plan: completedPlan(projectRoot, loaderOptions2),
|
|
@@ -31710,19 +31723,19 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31710
31723
|
};
|
|
31711
31724
|
}
|
|
31712
31725
|
if (plan.projectRoot !== gitRoot) {
|
|
31713
|
-
throw new
|
|
31726
|
+
throw new KxmConfigError([initIssue("git_root_required", ".", "kxm init must run inside the authoritative Git worktree")]);
|
|
31714
31727
|
}
|
|
31715
31728
|
const projectId = generatedProjectId(options.projectId);
|
|
31716
31729
|
const projectName = normalizedProjectName(gitRoot, options.projectName);
|
|
31717
|
-
const rendered =
|
|
31730
|
+
const rendered = renderKxmTemplate(projectId, projectName, options.templateVariant ?? CURRENT_KXM_TEMPLATE_VARIANT);
|
|
31718
31731
|
const files = [...rendered.files.keys()];
|
|
31719
31732
|
if (options.dryRun) return { action: "planned", plan, projectRoot: gitRoot, files };
|
|
31720
31733
|
if (!mutationLock) throw new Error("project mutation lock is required to create configuration");
|
|
31721
31734
|
if (existsSync22(join25(gitRoot, ".kxm"))) {
|
|
31722
|
-
throw new
|
|
31735
|
+
throw new KxmConfigError([initIssue("workspace_changed", ".kxm", "workspace changed after planning; existing .kxm state was not overwritten")]);
|
|
31723
31736
|
}
|
|
31724
|
-
const created =
|
|
31725
|
-
|
|
31737
|
+
const created = prepareAndApplyKxmCreate(gitRoot, rendered, transactionOptions);
|
|
31738
|
+
commitKxmInitTransaction(gitRoot, options.schemasDir);
|
|
31726
31739
|
return {
|
|
31727
31740
|
action: "created",
|
|
31728
31741
|
plan: completedPlan(gitRoot, loaderOptions2),
|
|
@@ -31731,23 +31744,23 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31731
31744
|
files: created.files
|
|
31732
31745
|
};
|
|
31733
31746
|
}
|
|
31734
|
-
function
|
|
31747
|
+
function initializeKxmProject(start = process.cwd(), options = {}) {
|
|
31735
31748
|
assertNoRegisteredGates(options);
|
|
31736
31749
|
const gitRoot = discoverGitRoot(start);
|
|
31737
31750
|
if (!gitRoot) {
|
|
31738
|
-
throw new
|
|
31751
|
+
throw new KxmConfigError([initIssue("git_root_required", ".", "kxm init must run inside the authoritative Git worktree")]);
|
|
31739
31752
|
}
|
|
31740
31753
|
if (options.projectId !== void 0) generatedProjectId(options.projectId);
|
|
31741
31754
|
if (options.projectName !== void 0) normalizedProjectName(gitRoot, options.projectName);
|
|
31742
|
-
if (options.dryRun) return
|
|
31743
|
-
const preflight =
|
|
31755
|
+
if (options.dryRun) return initializeKxmProjectAtGitRoot(start, gitRoot, options);
|
|
31756
|
+
const preflight = initializeKxmProjectAtGitRoot(start, gitRoot, { ...options, dryRun: true });
|
|
31744
31757
|
const mutationRequired = preflight.resumePending === true || preflight.plan.mode === "create" || preflight.repairPlan?.canApply === true && !(preflight.plan.mode === "repair" && Object.keys(options.repositoryBindings ?? {}).length > 0) || Object.keys(options.repositoryBindings ?? {}).length > 0 && preflight.plan.mode === "ready";
|
|
31745
|
-
if (!mutationRequired) return
|
|
31758
|
+
if (!mutationRequired) return initializeKxmProjectAtGitRoot(start, gitRoot, options);
|
|
31746
31759
|
const storeOptions = bindingStoreOptions(options);
|
|
31747
|
-
return
|
|
31760
|
+
return withKxmLocalBindingLock(gitRoot, storeOptions, (lock) => initializeKxmProjectAtGitRoot(start, gitRoot, options, lock));
|
|
31748
31761
|
}
|
|
31749
31762
|
|
|
31750
|
-
// plugins/kxm/src/
|
|
31763
|
+
// plugins/kxm/src/migrate.ts
|
|
31751
31764
|
var import_yaml12 = __toESM(require_dist(), 1);
|
|
31752
31765
|
import { createHash as createHash13 } from "node:crypto";
|
|
31753
31766
|
import { chmodSync as chmodSync6, closeSync as closeSync3, existsSync as existsSync23, fsyncSync as fsyncSync3, lstatSync as lstatSync8, mkdirSync as mkdirSync19, openSync as openSync3, readFileSync as readFileSync22, renameSync as renameSync7, rmSync as rmSync9, writeFileSync as writeFileSync18 } from "node:fs";
|
|
@@ -31760,7 +31773,7 @@ function migrateIssue(phase, code, file, message) {
|
|
|
31760
31773
|
return { phase, code, file, message };
|
|
31761
31774
|
}
|
|
31762
31775
|
function migrateFail(code, file, message) {
|
|
31763
|
-
throw new
|
|
31776
|
+
throw new KxmConfigError([migrateIssue("parse", code, file, message)]);
|
|
31764
31777
|
}
|
|
31765
31778
|
function parseLegacyJson(text, label) {
|
|
31766
31779
|
const bytes = Buffer.byteLength(text, "utf8");
|
|
@@ -31914,23 +31927,23 @@ function detectDuplicateKeys(text, label) {
|
|
|
31914
31927
|
function sha256Of(input) {
|
|
31915
31928
|
return `sha256:${createHash13("sha256").update(input).digest("hex")}`;
|
|
31916
31929
|
}
|
|
31917
|
-
function
|
|
31930
|
+
function readKxmLegacySources(root) {
|
|
31918
31931
|
const files = legacyConfigFilesAt(root);
|
|
31919
31932
|
if (files.length > MAX_LEGACY_SOURCES) {
|
|
31920
|
-
throw new
|
|
31933
|
+
throw new KxmConfigError([migrateIssue("discovery", "legacy_source_limit", ".kxm/config", `legacy configuration exceeds ${MAX_LEGACY_SOURCES} files`)]);
|
|
31921
31934
|
}
|
|
31922
31935
|
return files.map((path4) => {
|
|
31923
31936
|
const absolute = join26(root, ...path4.split("/"));
|
|
31924
31937
|
const stat = lstatSync8(absolute);
|
|
31925
31938
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
31926
|
-
throw new
|
|
31939
|
+
throw new KxmConfigError([migrateIssue("path", "legacy_source_invalid", path4, "legacy configuration must be a regular file, not a link")]);
|
|
31927
31940
|
}
|
|
31928
31941
|
const buffer = readFileSync22(absolute);
|
|
31929
31942
|
let text;
|
|
31930
31943
|
try {
|
|
31931
31944
|
text = new TextDecoder("utf-8", { fatal: true }).decode(buffer);
|
|
31932
31945
|
} catch {
|
|
31933
|
-
throw new
|
|
31946
|
+
throw new KxmConfigError([migrateIssue("parse", "invalid_utf8", path4, "document is not valid UTF-8")]);
|
|
31934
31947
|
}
|
|
31935
31948
|
return {
|
|
31936
31949
|
path: path4,
|
|
@@ -31941,7 +31954,7 @@ function readVnextLegacySources(root) {
|
|
|
31941
31954
|
});
|
|
31942
31955
|
}
|
|
31943
31956
|
function legacySourceDigest(sources) {
|
|
31944
|
-
return sha256Of(
|
|
31957
|
+
return sha256Of(kxmCanonicalJson(sources.map((source) => ({ path: source.path, sha256: source.sha256, bytes: source.bytes }))));
|
|
31945
31958
|
}
|
|
31946
31959
|
var IDENTIFIER2 = /^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/;
|
|
31947
31960
|
var KNOWN_AGENT_FIELDS = /* @__PURE__ */ new Set(["name", "kind", "driver", "model", "thinking", "purpose"]);
|
|
@@ -31997,11 +32010,11 @@ function keyFragment(raw) {
|
|
|
31997
32010
|
return `${normalized}-${digest}`;
|
|
31998
32011
|
}
|
|
31999
32012
|
function recordUnmapped(plan, sourcePath, pointer, value, sensitive) {
|
|
32000
|
-
const digestInput = sensitive ? { redacted: true, bytes: Buffer.byteLength(
|
|
32013
|
+
const digestInput = sensitive ? { redacted: true, bytes: Buffer.byteLength(kxmCanonicalJson(value === void 0 ? null : value), "utf8") } : value === void 0 ? null : value;
|
|
32001
32014
|
plan.unmapped.push({
|
|
32002
32015
|
sourcePath,
|
|
32003
32016
|
jsonPointer: pointer,
|
|
32004
|
-
valueSha256: sha256Of(
|
|
32017
|
+
valueSha256: sha256Of(kxmCanonicalJson(digestInput)),
|
|
32005
32018
|
sensitive
|
|
32006
32019
|
});
|
|
32007
32020
|
}
|
|
@@ -32041,7 +32054,7 @@ function mapIdentity(plan, sourcePath, raw, kind, taken, decisions, dropPointer,
|
|
|
32041
32054
|
`identity:${kind}:${keyFragment(raw)}`,
|
|
32042
32055
|
"identity",
|
|
32043
32056
|
sourcePath,
|
|
32044
|
-
`${kind} name ${JSON.stringify(elide(raw, 200))} cannot be normalized to a
|
|
32057
|
+
`${kind} name ${JSON.stringify(elide(raw, 200))} cannot be normalized to a KXM identifier; supply a decision with the target identifier`,
|
|
32045
32058
|
["<identifier>"],
|
|
32046
32059
|
decisions
|
|
32047
32060
|
);
|
|
@@ -32297,7 +32310,7 @@ function convertGatesRoster(plan, source, decisions) {
|
|
|
32297
32310
|
`gate:${keyFragment(name)}`,
|
|
32298
32311
|
"unsupported",
|
|
32299
32312
|
source.path,
|
|
32300
|
-
`gate ${JSON.stringify(elide(name, 200))} has no registered deterministic runner in
|
|
32313
|
+
`gate ${JSON.stringify(elide(name, 200))} has no registered deterministic runner in KXM; it is preserved in the migration report only`,
|
|
32301
32314
|
["report-only"],
|
|
32302
32315
|
decisions
|
|
32303
32316
|
);
|
|
@@ -32328,7 +32341,7 @@ function convertTransition(plan, source, context, stageId, stageKey, outcome, ra
|
|
|
32328
32341
|
`terminal:${context.workflowKey}:${stageKey}:${outcome}`,
|
|
32329
32342
|
"terminal-status",
|
|
32330
32343
|
source.path,
|
|
32331
|
-
`legacy transition ${context.workflowId}/${stageId} outcome ${outcome} ends the run; choose the
|
|
32344
|
+
`legacy transition ${context.workflowId}/${stageId} outcome ${outcome} ends the run; choose the KXM terminal status (legacy semantics completed the run even on failure outcomes)`,
|
|
32332
32345
|
outcome === "passed" ? ["completed"] : ["completed", "failed", "cancelled"],
|
|
32333
32346
|
decisions
|
|
32334
32347
|
);
|
|
@@ -32375,7 +32388,7 @@ function convertTransition(plan, source, context, stageId, stageKey, outcome, ra
|
|
|
32375
32388
|
`backedge:${context.workflowKey}:${stageKey}:${outcome}`,
|
|
32376
32389
|
"transition-budget",
|
|
32377
32390
|
source.path,
|
|
32378
|
-
`back-edge ${context.workflowId}/${stageId} -> ${targetId} (outcome ${outcome}) has no per-edge budget in legacy;
|
|
32391
|
+
`back-edge ${context.workflowId}/${stageId} -> ${targetId} (outcome ${outcome}) has no per-edge budget in legacy; KXM requires maxTransitions (1-100)`,
|
|
32379
32392
|
[2, 3, 4, 5],
|
|
32380
32393
|
decisions
|
|
32381
32394
|
);
|
|
@@ -32413,7 +32426,7 @@ function convertWorkflowFile(plan, source, decisions, agentIds, agentRawNames, p
|
|
|
32413
32426
|
`secret:${workflowKey}:${field}`,
|
|
32414
32427
|
"secret-reference",
|
|
32415
32428
|
source.path,
|
|
32416
|
-
`workflow ${workflowId} field ${field} configures a webhook secret;
|
|
32429
|
+
`workflow ${workflowId} field ${field} configures a webhook secret; KXM workflows never embed secrets \u2014 confirm the field is dropped and re-granted through scoped secret references when the trigger surface lands`,
|
|
32417
32430
|
["drop"],
|
|
32418
32431
|
decisions
|
|
32419
32432
|
);
|
|
@@ -32519,7 +32532,7 @@ function convertWorkflowFile(plan, source, decisions, agentIds, agentRawNames, p
|
|
|
32519
32532
|
`instructions:${workflowKey}:${stepKey}`,
|
|
32520
32533
|
"unsupported",
|
|
32521
32534
|
source.path,
|
|
32522
|
-
`stage ${stepId} has no instructions;
|
|
32535
|
+
`stage ${stepId} has no instructions; KXM agent steps require executable instructions \u2014 confirm the stage is dropped`,
|
|
32523
32536
|
["drop"],
|
|
32524
32537
|
decisions
|
|
32525
32538
|
);
|
|
@@ -32682,7 +32695,7 @@ function convertWorkflowFile(plan, source, decisions, agentIds, agentRawNames, p
|
|
|
32682
32695
|
`statuses:${workflowKey}:${stepKey}:${policyKey}`,
|
|
32683
32696
|
"evidence-policy",
|
|
32684
32697
|
source.path,
|
|
32685
|
-
acceptedStatusesMalformed ? `evidence policy ${policyKey} acceptedStatuses is malformed (not an array) and was preserved in the report; confirm mapping the policy to
|
|
32698
|
+
acceptedStatusesMalformed ? `evidence policy ${policyKey} acceptedStatuses is malformed (not an array) and was preserved in the report; confirm mapping the policy to KXM 'passed'` : `evidence policy ${policyKey} accepted statuses ${JSON.stringify(elide(accepted.map((candidate) => String(candidate)).join(","), 200))} cannot map losslessly; confirm mapping to KXM 'passed'`,
|
|
32686
32699
|
["passed"],
|
|
32687
32700
|
decisions
|
|
32688
32701
|
);
|
|
@@ -32700,7 +32713,7 @@ function convertWorkflowFile(plan, source, decisions, agentIds, agentRawNames, p
|
|
|
32700
32713
|
sourcePath: source.path,
|
|
32701
32714
|
targetPath: `.kxm/workflows/${workflowId}.yaml`,
|
|
32702
32715
|
direction: "expansion",
|
|
32703
|
-
summary: `step ${stepId}: assignment pool widens from the single legacy coordinator to coordinator plus evidence producers so
|
|
32716
|
+
summary: `step ${stepId}: assignment pool widens from the single legacy coordinator to coordinator plus evidence producers so KXM producer evidence stays in scope`,
|
|
32704
32717
|
decisionKey: `evidence:${workflowKey}:${stepKey}:${policyKey}`
|
|
32705
32718
|
});
|
|
32706
32719
|
resolveDecision(
|
|
@@ -32813,7 +32826,7 @@ function convertWorkflowFile(plan, source, decisions, agentIds, agentRawNames, p
|
|
|
32813
32826
|
`budget:${workflowKey}`,
|
|
32814
32827
|
"transition-budget",
|
|
32815
32828
|
source.path,
|
|
32816
|
-
`workflow ${workflowId} has back-edges but no legacy global maxTransitions;
|
|
32829
|
+
`workflow ${workflowId} has back-edges but no legacy global maxTransitions; KXM requires limits.maxTransitions (1-1000)`,
|
|
32817
32830
|
[28],
|
|
32818
32831
|
decisions
|
|
32819
32832
|
);
|
|
@@ -32869,16 +32882,16 @@ function sortedRecord(map, prefix) {
|
|
|
32869
32882
|
function migrationGitRoot(start) {
|
|
32870
32883
|
const root = discoverGitRoot(start);
|
|
32871
32884
|
if (!root) {
|
|
32872
|
-
throw new
|
|
32885
|
+
throw new KxmConfigError([migrateIssue("discovery", "git_root_required", ".", "kxm migrate must run inside the authoritative Git worktree")]);
|
|
32873
32886
|
}
|
|
32874
32887
|
return root;
|
|
32875
32888
|
}
|
|
32876
|
-
function
|
|
32889
|
+
function planKxmMigration(projectRoot, options = {}) {
|
|
32877
32890
|
const root = migrationGitRoot(projectRoot);
|
|
32878
|
-
const registry = new
|
|
32879
|
-
const sources =
|
|
32891
|
+
const registry = new KxmSchemaRegistry(options.schemasDir);
|
|
32892
|
+
const sources = readKxmLegacySources(root);
|
|
32880
32893
|
if (sources.length === 0) {
|
|
32881
|
-
throw new
|
|
32894
|
+
throw new KxmConfigError([migrateIssue("discovery", "legacy_sources_missing", ".kxm/config", "no legacy configuration files found to migrate")]);
|
|
32882
32895
|
}
|
|
32883
32896
|
const decisions = options.decisions ?? {};
|
|
32884
32897
|
const plan = { ambiguities: [], invalidDecisions: [], decisionKeys: /* @__PURE__ */ new Set(), decisionAllowedValues: /* @__PURE__ */ new Map(), unmapped: [], renames: [], permissionChanges: [] };
|
|
@@ -32916,11 +32929,11 @@ function planVnextMigration(projectRoot, options = {}) {
|
|
|
32916
32929
|
}
|
|
32917
32930
|
const projectId = options.projectId ?? `prj_mig${sha256Of(legacySourceDigest(sources)).slice(7, 39)}`;
|
|
32918
32931
|
if (!PROJECT_ID2.test(projectId)) {
|
|
32919
|
-
throw new
|
|
32932
|
+
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")]);
|
|
32920
32933
|
}
|
|
32921
32934
|
const projectName = options.projectName ?? "Migrated legacy project";
|
|
32922
32935
|
if (projectName.length < 1 || projectName.length > 120 || /[\u0000\r\n]/.test(projectName)) {
|
|
32923
|
-
throw new
|
|
32936
|
+
throw new KxmConfigError([migrateIssue("semantic", "project_name_invalid", ".kxm/project.yaml", "project name must contain 1-120 characters on one line")]);
|
|
32924
32937
|
}
|
|
32925
32938
|
const resources = /* @__PURE__ */ new Map();
|
|
32926
32939
|
resources.set(".kxm/project.yaml", {
|
|
@@ -32957,10 +32970,10 @@ function planVnextMigration(projectRoot, options = {}) {
|
|
|
32957
32970
|
const id = idOf(path4);
|
|
32958
32971
|
semanticResources.set(path4, kind === "repository" ? { kind, id: "control", value } : { kind, ...id === void 0 ? {} : { id }, value });
|
|
32959
32972
|
}
|
|
32960
|
-
if (schemaIssues.length > 0) throw new
|
|
32973
|
+
if (schemaIssues.length > 0) throw new KxmConfigError(schemaIssues);
|
|
32961
32974
|
if (plan.ambiguities.length === 0) {
|
|
32962
|
-
const semanticIssues =
|
|
32963
|
-
if (semanticIssues.length > 0) throw new
|
|
32975
|
+
const semanticIssues = validateKxmResources(semanticResources, options);
|
|
32976
|
+
if (semanticIssues.length > 0) throw new KxmConfigError(semanticIssues);
|
|
32964
32977
|
}
|
|
32965
32978
|
const planRecord = {
|
|
32966
32979
|
schema: "kxm.migration-plan.v1",
|
|
@@ -32985,7 +32998,7 @@ function planVnextMigration(projectRoot, options = {}) {
|
|
|
32985
32998
|
canApply: plan.ambiguities.length === 0
|
|
32986
32999
|
};
|
|
32987
33000
|
const planIssues = registry.validateMigrationPlan(planRecord, "kxm.migration-plan.v1");
|
|
32988
|
-
if (planIssues.length > 0) throw new
|
|
33001
|
+
if (planIssues.length > 0) throw new KxmConfigError(planIssues);
|
|
32989
33002
|
return {
|
|
32990
33003
|
plan: planRecord,
|
|
32991
33004
|
resources,
|
|
@@ -32997,14 +33010,14 @@ function planVnextMigration(projectRoot, options = {}) {
|
|
|
32997
33010
|
sources
|
|
32998
33011
|
};
|
|
32999
33012
|
}
|
|
33000
|
-
function
|
|
33013
|
+
function readKxmMigrationDecisions(path4, schemasDir) {
|
|
33001
33014
|
if (!existsSync23(path4)) {
|
|
33002
|
-
throw new
|
|
33015
|
+
throw new KxmConfigError([migrateIssue("discovery", "decisions_missing", path4, "migration decisions file does not exist")]);
|
|
33003
33016
|
}
|
|
33004
|
-
const registry = new
|
|
33017
|
+
const registry = new KxmSchemaRegistry(schemasDir);
|
|
33005
33018
|
const value = parseRestrictedYaml2(readFileSync22(path4), path4);
|
|
33006
33019
|
const issues = registry.validateMigrationDecision(value, path4);
|
|
33007
|
-
if (issues.length > 0) throw new
|
|
33020
|
+
if (issues.length > 0) throw new KxmConfigError(issues);
|
|
33008
33021
|
return value;
|
|
33009
33022
|
}
|
|
33010
33023
|
function resolutionsOf(decisions) {
|
|
@@ -33046,44 +33059,44 @@ function writeDurable2(path4, content) {
|
|
|
33046
33059
|
if (created && existsSync23(temp)) rmSync9(temp, { force: true });
|
|
33047
33060
|
}
|
|
33048
33061
|
}
|
|
33049
|
-
function
|
|
33062
|
+
function applyKxmMigration(projectRoot, options = {}) {
|
|
33050
33063
|
const root = migrationGitRoot(projectRoot);
|
|
33051
33064
|
const storeOptions = {
|
|
33052
33065
|
...options.localStateRoot === void 0 ? {} : { stateRoot: options.localStateRoot },
|
|
33053
33066
|
...options.schemasDir === void 0 ? {} : { schemasDir: options.schemasDir }
|
|
33054
33067
|
};
|
|
33055
33068
|
const execute = (lock) => {
|
|
33056
|
-
const receiptAbsolute = join26(root, ...
|
|
33069
|
+
const receiptAbsolute = join26(root, ...KXM_MIGRATION_RECEIPT_PATH.split("/"));
|
|
33057
33070
|
if (existsSync23(receiptAbsolute)) {
|
|
33058
33071
|
const stat = lstatSync8(receiptAbsolute);
|
|
33059
33072
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
33060
|
-
throw new
|
|
33073
|
+
throw new KxmConfigError([migrateIssue("path", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "migration receipt must be a regular file, not a link")]);
|
|
33061
33074
|
}
|
|
33062
|
-
const existing =
|
|
33075
|
+
const existing = loadKxmProject(root, options);
|
|
33063
33076
|
return {
|
|
33064
33077
|
action: "already-migrated",
|
|
33065
33078
|
projectRoot: root,
|
|
33066
|
-
receiptPath:
|
|
33079
|
+
receiptPath: KXM_MIGRATION_RECEIPT_PATH,
|
|
33067
33080
|
configRevision: existing.configRevision,
|
|
33068
33081
|
files: []
|
|
33069
33082
|
};
|
|
33070
33083
|
}
|
|
33071
|
-
const decisionsRecord = options.decisionsFile ?
|
|
33084
|
+
const decisionsRecord = options.decisionsFile ? readKxmMigrationDecisions(options.decisionsFile, options.schemasDir) : void 0;
|
|
33072
33085
|
const decisions = decisionsRecord ? resolutionsOf(decisionsRecord) : options.decisions ?? {};
|
|
33073
|
-
const first =
|
|
33086
|
+
const first = planKxmMigration(root, { ...options, decisions });
|
|
33074
33087
|
if (decisionsRecord) {
|
|
33075
33088
|
if (decisionsRecord.projectId !== first.plan.projectId) {
|
|
33076
|
-
throw new
|
|
33089
|
+
throw new KxmConfigError([migrateIssue("semantic", "decision_project_mismatch", options.decisionsFile ?? "<decisions>", "decisions file projectId does not match the recomputed plan")]);
|
|
33077
33090
|
}
|
|
33078
33091
|
if (decisionsRecord.projectName !== first.plan.projectName) {
|
|
33079
|
-
throw new
|
|
33092
|
+
throw new KxmConfigError([migrateIssue("semantic", "decision_project_mismatch", options.decisionsFile ?? "<decisions>", "decisions file projectName does not match the recomputed plan")]);
|
|
33080
33093
|
}
|
|
33081
33094
|
if (decisionsRecord.sourceDigest !== first.plan.sourceDigest) {
|
|
33082
|
-
throw new
|
|
33095
|
+
throw new KxmConfigError([migrateIssue("semantic", "decision_source_changed", options.decisionsFile ?? "<decisions>", "legacy sources changed after the decisions file was reviewed")]);
|
|
33083
33096
|
}
|
|
33084
33097
|
}
|
|
33085
33098
|
if (Object.keys(decisions).length > 0) {
|
|
33086
|
-
const universe =
|
|
33099
|
+
const universe = planKxmMigration(root, { ...options, decisions: {} });
|
|
33087
33100
|
const unknown = [];
|
|
33088
33101
|
const invalid = [];
|
|
33089
33102
|
for (const [key, value] of Object.entries(decisions)) {
|
|
@@ -33096,11 +33109,11 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33096
33109
|
}
|
|
33097
33110
|
}
|
|
33098
33111
|
if (unknown.length > 0) {
|
|
33099
|
-
throw new
|
|
33112
|
+
throw new KxmConfigError(unknown.sort(compareCodeUnits6).map((key) => migrateIssue("semantic", "decision_unknown", key, "decision key does not match any current ambiguity")));
|
|
33100
33113
|
}
|
|
33101
33114
|
const allInvalid = [.../* @__PURE__ */ new Set([...invalid, ...first.invalidDecisions])].sort(compareCodeUnits6);
|
|
33102
33115
|
if (allInvalid.length > 0) {
|
|
33103
|
-
throw new
|
|
33116
|
+
throw new KxmConfigError(allInvalid.map((key) => migrateIssue("semantic", "decision_value_invalid", key, "decision value is not one of the plan's allowed values")));
|
|
33104
33117
|
}
|
|
33105
33118
|
}
|
|
33106
33119
|
if (first.ambiguities.length > 0) {
|
|
@@ -33109,7 +33122,7 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33109
33122
|
const files = [...first.resources.entries()].sort(([left], [right]) => compareCodeUnits6(left, right)).map(([path4, value]) => ({ path: path4, bytes: Buffer.from((0, import_yaml12.stringify)(value, { lineWidth: 0 }), "utf8") }));
|
|
33110
33123
|
const collisions = files.filter((file) => existsSync23(join26(root, ...file.path.split("/"))));
|
|
33111
33124
|
if (collisions.length > 0) {
|
|
33112
|
-
throw new
|
|
33125
|
+
throw new KxmConfigError(collisions.map((file) => migrateIssue("semantic", "migration_target_exists", file.path, "target resource already exists; refusing to overwrite")));
|
|
33113
33126
|
}
|
|
33114
33127
|
const parentIssues = [];
|
|
33115
33128
|
for (const file of files) {
|
|
@@ -33125,7 +33138,7 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33125
33138
|
}
|
|
33126
33139
|
}
|
|
33127
33140
|
}
|
|
33128
|
-
if (parentIssues.length > 0) throw new
|
|
33141
|
+
if (parentIssues.length > 0) throw new KxmConfigError(parentIssues);
|
|
33129
33142
|
if (options.dryRun) {
|
|
33130
33143
|
return { action: "planned", projectRoot: root, files: files.map((file) => file.path), plan: first.plan };
|
|
33131
33144
|
}
|
|
@@ -33138,29 +33151,29 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33138
33151
|
written.push(absolute);
|
|
33139
33152
|
writeDurable2(absolute, file.bytes);
|
|
33140
33153
|
}
|
|
33141
|
-
const bundle =
|
|
33154
|
+
const bundle = loadKxmProject(root, { ...options, allowUnreceiptedLegacyConfig: true });
|
|
33142
33155
|
const receipt = {
|
|
33143
33156
|
schema: "kxm.migration-receipt.v1",
|
|
33144
33157
|
migrationId: `mig_${sha256Of(`${first.plan.sourceDigest}
|
|
33145
33158
|
${bundle.configRevision}`).slice(7, 39)}`,
|
|
33146
33159
|
projectId: String(first.plan.projectId),
|
|
33147
33160
|
sourceDigest: String(first.plan.sourceDigest),
|
|
33148
|
-
decisionDigest: sha256Of(
|
|
33161
|
+
decisionDigest: sha256Of(kxmCanonicalJson(decisionsRecord ?? { schema: "kxm.migration-decision.v1", projectId: first.plan.projectId, projectName: first.plan.projectName, sourceDigest: first.plan.sourceDigest, resolutions: decisions })),
|
|
33149
33162
|
configRevision: bundle.configRevision,
|
|
33150
33163
|
sources: first.plan.sources,
|
|
33151
33164
|
resources: files.map((file) => ({ path: file.path, sha256: sha256Of(file.bytes), bytes: file.bytes.byteLength }))
|
|
33152
33165
|
};
|
|
33153
33166
|
receipt.receiptSha256 = migrationReceiptSelfHash(receipt);
|
|
33154
|
-
const registry = new
|
|
33155
|
-
const receiptIssues = registry.validateMigrationReceipt(receipt,
|
|
33156
|
-
if (receiptIssues.length > 0) throw new
|
|
33167
|
+
const registry = new KxmSchemaRegistry(options.schemasDir);
|
|
33168
|
+
const receiptIssues = registry.validateMigrationReceipt(receipt, KXM_MIGRATION_RECEIPT_PATH);
|
|
33169
|
+
if (receiptIssues.length > 0) throw new KxmConfigError(receiptIssues);
|
|
33157
33170
|
written.push(receiptAbsolute);
|
|
33158
33171
|
writeDurable2(receiptAbsolute, Buffer.from((0, import_yaml12.stringify)(receipt, { lineWidth: 0 }), "utf8"));
|
|
33159
|
-
const verified =
|
|
33172
|
+
const verified = loadKxmProject(root, options);
|
|
33160
33173
|
return {
|
|
33161
33174
|
action: "applied",
|
|
33162
33175
|
projectRoot: root,
|
|
33163
|
-
receiptPath:
|
|
33176
|
+
receiptPath: KXM_MIGRATION_RECEIPT_PATH,
|
|
33164
33177
|
configRevision: verified.configRevision,
|
|
33165
33178
|
files: files.map((file) => file.path),
|
|
33166
33179
|
plan: first.plan
|
|
@@ -33176,59 +33189,59 @@ ${bundle.configRevision}`).slice(7, 39)}`,
|
|
|
33176
33189
|
}
|
|
33177
33190
|
};
|
|
33178
33191
|
if (options.dryRun) return execute(void 0);
|
|
33179
|
-
return
|
|
33192
|
+
return withKxmLocalBindingLock(root, storeOptions, (lock) => execute(lock));
|
|
33180
33193
|
}
|
|
33181
|
-
function
|
|
33194
|
+
function verifyKxmMigration(projectRoot, options = {}) {
|
|
33182
33195
|
const root = migrationGitRoot(projectRoot);
|
|
33183
|
-
const receiptAbsolute = join26(root, ...
|
|
33196
|
+
const receiptAbsolute = join26(root, ...KXM_MIGRATION_RECEIPT_PATH.split("/"));
|
|
33184
33197
|
if (!existsSync23(receiptAbsolute)) {
|
|
33185
33198
|
return {
|
|
33186
33199
|
ok: false,
|
|
33187
33200
|
projectRoot: root,
|
|
33188
|
-
receiptPath:
|
|
33189
|
-
issues: [migrateIssue("discovery", "migration_receipt_missing",
|
|
33201
|
+
receiptPath: KXM_MIGRATION_RECEIPT_PATH,
|
|
33202
|
+
issues: [migrateIssue("discovery", "migration_receipt_missing", KXM_MIGRATION_RECEIPT_PATH, "no migration receipt exists")]
|
|
33190
33203
|
};
|
|
33191
33204
|
}
|
|
33192
33205
|
try {
|
|
33193
|
-
const bundle =
|
|
33206
|
+
const bundle = loadKxmProject(root, options);
|
|
33194
33207
|
const receipt = bundle.migrationReceipt;
|
|
33195
33208
|
if (!receipt) {
|
|
33196
33209
|
if (legacyConfigFilesAt(root).length === 0) {
|
|
33197
|
-
const direct =
|
|
33210
|
+
const direct = readKxmMigrationReceipt(root, options);
|
|
33198
33211
|
return {
|
|
33199
33212
|
ok: false,
|
|
33200
33213
|
projectRoot: root,
|
|
33201
|
-
receiptPath:
|
|
33214
|
+
receiptPath: KXM_MIGRATION_RECEIPT_PATH,
|
|
33202
33215
|
configRevision: bundle.configRevision,
|
|
33203
|
-
issues: direct.issues.length > 0 ? direct.issues : [migrateIssue("semantic", "migration_receipt_invalid",
|
|
33216
|
+
issues: direct.issues.length > 0 ? direct.issues : [migrateIssue("semantic", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "receipt did not validate")]
|
|
33204
33217
|
};
|
|
33205
33218
|
}
|
|
33206
33219
|
return {
|
|
33207
33220
|
ok: false,
|
|
33208
33221
|
projectRoot: root,
|
|
33209
|
-
receiptPath:
|
|
33222
|
+
receiptPath: KXM_MIGRATION_RECEIPT_PATH,
|
|
33210
33223
|
configRevision: bundle.configRevision,
|
|
33211
|
-
issues: [migrateIssue("semantic", "migration_receipt_invalid",
|
|
33224
|
+
issues: [migrateIssue("semantic", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "receipt did not validate during project load")]
|
|
33212
33225
|
};
|
|
33213
33226
|
}
|
|
33214
|
-
const targetIssues =
|
|
33227
|
+
const targetIssues = verifyKxmMigrationReceiptTarget(root, receipt, bundle.resources, bundle.configRevision);
|
|
33215
33228
|
return {
|
|
33216
33229
|
ok: targetIssues.length === 0,
|
|
33217
33230
|
projectRoot: root,
|
|
33218
|
-
receiptPath:
|
|
33231
|
+
receiptPath: KXM_MIGRATION_RECEIPT_PATH,
|
|
33219
33232
|
configRevision: bundle.configRevision,
|
|
33220
33233
|
issues: targetIssues
|
|
33221
33234
|
};
|
|
33222
33235
|
} catch (error) {
|
|
33223
|
-
if (error instanceof
|
|
33224
|
-
return { ok: false, projectRoot: root, receiptPath:
|
|
33236
|
+
if (error instanceof KxmConfigError) {
|
|
33237
|
+
return { ok: false, projectRoot: root, receiptPath: KXM_MIGRATION_RECEIPT_PATH, issues: error.issues };
|
|
33225
33238
|
}
|
|
33226
33239
|
throw error;
|
|
33227
33240
|
}
|
|
33228
33241
|
}
|
|
33229
33242
|
|
|
33230
|
-
// plugins/kxm/src/cli/
|
|
33231
|
-
var
|
|
33243
|
+
// plugins/kxm/src/cli/project.ts
|
|
33244
|
+
var kxmDriveCliSeams = {};
|
|
33232
33245
|
function initPlanPayload(plan) {
|
|
33233
33246
|
return {
|
|
33234
33247
|
mode: plan.mode,
|
|
@@ -33248,7 +33261,7 @@ function explicitRepositoryBindings(values) {
|
|
|
33248
33261
|
const repositoryId = separator < 0 ? "" : value.slice(0, separator).trim();
|
|
33249
33262
|
const path4 = separator < 0 ? "" : value.slice(separator + 1).trim();
|
|
33250
33263
|
if (!repositoryId || !path4) {
|
|
33251
|
-
throw new
|
|
33264
|
+
throw new KxmConfigError([{
|
|
33252
33265
|
phase: "discovery",
|
|
33253
33266
|
code: "repository_binding_argument_invalid",
|
|
33254
33267
|
file: "--repository",
|
|
@@ -33256,7 +33269,7 @@ function explicitRepositoryBindings(values) {
|
|
|
33256
33269
|
}]);
|
|
33257
33270
|
}
|
|
33258
33271
|
if (Object.hasOwn(result, repositoryId)) {
|
|
33259
|
-
throw new
|
|
33272
|
+
throw new KxmConfigError([{
|
|
33260
33273
|
phase: "discovery",
|
|
33261
33274
|
code: "repository_binding_argument_duplicate",
|
|
33262
33275
|
file: "--repository",
|
|
@@ -33267,7 +33280,7 @@ function explicitRepositoryBindings(values) {
|
|
|
33267
33280
|
}
|
|
33268
33281
|
return result;
|
|
33269
33282
|
}
|
|
33270
|
-
async function
|
|
33283
|
+
async function cmdKxmInit(runtime, options, postHooks) {
|
|
33271
33284
|
if (runtime.workspaceFlag !== void 0) {
|
|
33272
33285
|
print(runtime.io, runtime.json, {
|
|
33273
33286
|
ok: false,
|
|
@@ -33277,11 +33290,11 @@ async function cmdVnextInit(runtime, options, postHooks) {
|
|
|
33277
33290
|
return 2;
|
|
33278
33291
|
}
|
|
33279
33292
|
try {
|
|
33280
|
-
const initialized =
|
|
33293
|
+
const initialized = initializeKxmProject(runtime.cwd, {
|
|
33281
33294
|
...options.name?.trim() ? { projectName: options.name.trim() } : {},
|
|
33282
33295
|
...options.projectId?.trim() ? { projectId: options.projectId.trim() } : {},
|
|
33283
33296
|
repositoryBindings: explicitRepositoryBindings(options.repository ?? []),
|
|
33284
|
-
localStateRoot:
|
|
33297
|
+
localStateRoot: kxmUserStateRoot({ env: runtime.env }),
|
|
33285
33298
|
dryRun: runtime.dryRun
|
|
33286
33299
|
});
|
|
33287
33300
|
const payload = {
|
|
@@ -33305,46 +33318,46 @@ async function cmdVnextInit(runtime, options, postHooks) {
|
|
|
33305
33318
|
if (initialized.action === "created") {
|
|
33306
33319
|
if (postHooks?.maybeOfferCompletionInstall) await postHooks.maybeOfferCompletionInstall(runtime);
|
|
33307
33320
|
if (postHooks?.maybeOfferGuideSetup) await postHooks.maybeOfferGuideSetup(runtime);
|
|
33308
|
-
return finishInit(0, `initialized
|
|
33321
|
+
return finishInit(0, `initialized KXM project at ${initialized.projectRoot ?? runtime.cwd}`);
|
|
33309
33322
|
}
|
|
33310
33323
|
if (initialized.action === "joined") {
|
|
33311
33324
|
if (postHooks?.maybeOfferCompletionInstall) await postHooks.maybeOfferCompletionInstall(runtime);
|
|
33312
33325
|
if (postHooks?.maybeOfferGuideSetup) await postHooks.maybeOfferGuideSetup(runtime);
|
|
33313
|
-
return finishInit(0, `joined
|
|
33326
|
+
return finishInit(0, `joined KXM project at ${initialized.projectRoot ?? runtime.cwd}`);
|
|
33314
33327
|
}
|
|
33315
33328
|
if (initialized.action === "repaired") {
|
|
33316
|
-
return finishInit(0, `repaired
|
|
33329
|
+
return finishInit(0, `repaired KXM project at ${initialized.projectRoot ?? runtime.cwd}`);
|
|
33317
33330
|
}
|
|
33318
33331
|
if (initialized.action === "resumed") {
|
|
33319
|
-
return finishInit(0, `resumed
|
|
33332
|
+
return finishInit(0, `resumed KXM ${initialized.transactionKind ?? "initialization"} at ${initialized.projectRoot ?? runtime.cwd}`);
|
|
33320
33333
|
}
|
|
33321
33334
|
if (initialized.action === "validated") {
|
|
33322
|
-
return finishInit(0, `validated
|
|
33335
|
+
return finishInit(0, `validated KXM project at ${initialized.projectRoot ?? runtime.cwd}`);
|
|
33323
33336
|
}
|
|
33324
33337
|
if (runtime.dryRun) {
|
|
33325
33338
|
return finishInit(0, `init plan: ${initialized.plan.mode}`);
|
|
33326
33339
|
}
|
|
33327
|
-
const next = initialized.plan.mode === "migrate" ? "legacy state requires reviewed migration; conversion is not available in this implementation slice" : initialized.repairPlan?.issues.length ? "managed-template repair is blocked by conflicts or authority changes; local files were preserved" : "partial or provenance-free
|
|
33340
|
+
const next = initialized.plan.mode === "migrate" ? "legacy state requires reviewed migration; conversion is not available in this implementation slice" : initialized.repairPlan?.issues.length ? "managed-template repair is blocked by conflicts or authority changes; local files were preserved" : "partial or provenance-free KXM state requires explicit repair; no files were overwritten";
|
|
33328
33341
|
return finishInit(1, next);
|
|
33329
33342
|
} catch (error) {
|
|
33330
|
-
if (error instanceof
|
|
33343
|
+
if (error instanceof KxmConfigError) {
|
|
33331
33344
|
print(runtime.io, runtime.json, {
|
|
33332
33345
|
ok: false,
|
|
33333
33346
|
command: "init",
|
|
33334
|
-
error: "
|
|
33347
|
+
error: "initialization_failed",
|
|
33335
33348
|
issues: error.issues
|
|
33336
|
-
}, `
|
|
33349
|
+
}, `KXM initialization failed: ${error.message}`);
|
|
33337
33350
|
return 1;
|
|
33338
33351
|
}
|
|
33339
33352
|
print(runtime.io, runtime.json, {
|
|
33340
33353
|
ok: false,
|
|
33341
33354
|
command: "init",
|
|
33342
|
-
error: "
|
|
33343
|
-
}, "
|
|
33355
|
+
error: "initialization_io_failed"
|
|
33356
|
+
}, "KXM initialization failed because a local filesystem operation did not complete");
|
|
33344
33357
|
return 1;
|
|
33345
33358
|
}
|
|
33346
33359
|
}
|
|
33347
|
-
async function
|
|
33360
|
+
async function cmdKxmMigratePlan(runtime) {
|
|
33348
33361
|
if (runtime.workspaceFlag !== void 0) {
|
|
33349
33362
|
print(runtime.io, runtime.json, {
|
|
33350
33363
|
ok: false,
|
|
@@ -33354,7 +33367,7 @@ async function cmdVnextMigratePlan(runtime) {
|
|
|
33354
33367
|
return 2;
|
|
33355
33368
|
}
|
|
33356
33369
|
try {
|
|
33357
|
-
const result =
|
|
33370
|
+
const result = planKxmMigration(runtime.cwd, {});
|
|
33358
33371
|
const ambiguities = result.plan.ambiguities ?? [];
|
|
33359
33372
|
const unmapped = result.plan.unmapped ?? [];
|
|
33360
33373
|
const payload = {
|
|
@@ -33376,7 +33389,7 @@ ${ambiguities.map((candidate) => ` - ${candidate.key}: ${candidate.message}`).j
|
|
|
33376
33389
|
);
|
|
33377
33390
|
return 1;
|
|
33378
33391
|
} catch (error) {
|
|
33379
|
-
if (error instanceof
|
|
33392
|
+
if (error instanceof KxmConfigError) {
|
|
33380
33393
|
print(runtime.io, runtime.json, { ok: false, command: "migrate plan", error: "migration_plan_failed", issues: error.issues }, `migration plan failed: ${error.message}`);
|
|
33381
33394
|
return 1;
|
|
33382
33395
|
}
|
|
@@ -33384,7 +33397,7 @@ ${ambiguities.map((candidate) => ` - ${candidate.key}: ${candidate.message}`).j
|
|
|
33384
33397
|
return 1;
|
|
33385
33398
|
}
|
|
33386
33399
|
}
|
|
33387
|
-
async function
|
|
33400
|
+
async function cmdKxmMigrateApply(runtime, options) {
|
|
33388
33401
|
if (runtime.workspaceFlag !== void 0) {
|
|
33389
33402
|
print(runtime.io, runtime.json, {
|
|
33390
33403
|
ok: false,
|
|
@@ -33394,11 +33407,11 @@ async function cmdVnextMigrateApply(runtime, options) {
|
|
|
33394
33407
|
return 2;
|
|
33395
33408
|
}
|
|
33396
33409
|
try {
|
|
33397
|
-
const result =
|
|
33410
|
+
const result = applyKxmMigration(runtime.cwd, {
|
|
33398
33411
|
...options.decisions?.trim() ? { decisionsFile: options.decisions.trim() } : {},
|
|
33399
33412
|
...options.projectId?.trim() ? { projectId: options.projectId.trim() } : {},
|
|
33400
33413
|
...options.name?.trim() ? { projectName: options.name.trim() } : {},
|
|
33401
|
-
localStateRoot:
|
|
33414
|
+
localStateRoot: kxmUserStateRoot({ env: runtime.env }),
|
|
33402
33415
|
dryRun: runtime.dryRun
|
|
33403
33416
|
});
|
|
33404
33417
|
const payload = {
|
|
@@ -33432,7 +33445,7 @@ ${ambiguities.map((candidate) => ` - ${candidate.key}: ${candidate.message}`).j
|
|
|
33432
33445
|
);
|
|
33433
33446
|
return 1;
|
|
33434
33447
|
} catch (error) {
|
|
33435
|
-
if (error instanceof
|
|
33448
|
+
if (error instanceof KxmConfigError) {
|
|
33436
33449
|
print(runtime.io, runtime.json, { ok: false, command: "migrate apply", error: "migration_apply_failed", issues: error.issues }, `migration apply failed: ${error.message}`);
|
|
33437
33450
|
return 1;
|
|
33438
33451
|
}
|
|
@@ -33440,7 +33453,7 @@ ${ambiguities.map((candidate) => ` - ${candidate.key}: ${candidate.message}`).j
|
|
|
33440
33453
|
return 1;
|
|
33441
33454
|
}
|
|
33442
33455
|
}
|
|
33443
|
-
async function
|
|
33456
|
+
async function cmdKxmMigrateVerify(runtime) {
|
|
33444
33457
|
if (runtime.workspaceFlag !== void 0) {
|
|
33445
33458
|
print(runtime.io, runtime.json, {
|
|
33446
33459
|
ok: false,
|
|
@@ -33451,9 +33464,9 @@ async function cmdVnextMigrateVerify(runtime) {
|
|
|
33451
33464
|
}
|
|
33452
33465
|
let result;
|
|
33453
33466
|
try {
|
|
33454
|
-
result =
|
|
33467
|
+
result = verifyKxmMigration(runtime.cwd, {});
|
|
33455
33468
|
} catch (error) {
|
|
33456
|
-
if (error instanceof
|
|
33469
|
+
if (error instanceof KxmConfigError) {
|
|
33457
33470
|
print(runtime.io, runtime.json, { ok: false, command: "migrate verify", error: "migration_verify_failed", issues: error.issues }, `migration verification failed: ${error.message}`);
|
|
33458
33471
|
return 1;
|
|
33459
33472
|
}
|
|
@@ -33495,7 +33508,7 @@ async function cmdBackup(runtime, options) {
|
|
|
33495
33508
|
print(runtime.io, runtime.json, payload, summary);
|
|
33496
33509
|
return 0;
|
|
33497
33510
|
} catch (error) {
|
|
33498
|
-
if (error instanceof
|
|
33511
|
+
if (error instanceof KxmConfigError) {
|
|
33499
33512
|
print(runtime.io, runtime.json, { ok: false, command: "backup", error: "backup_failed", issues: error.issues }, `backup failed: ${error.message}`);
|
|
33500
33513
|
return 1;
|
|
33501
33514
|
}
|
|
@@ -33522,7 +33535,7 @@ async function cmdRestore(runtime, manifestArg) {
|
|
|
33522
33535
|
print(runtime.io, runtime.json, payload, summary);
|
|
33523
33536
|
return 0;
|
|
33524
33537
|
} catch (error) {
|
|
33525
|
-
if (error instanceof
|
|
33538
|
+
if (error instanceof KxmConfigError) {
|
|
33526
33539
|
print(runtime.io, runtime.json, { ok: false, command: "restore", error: "restore_failed", issues: error.issues }, `restore failed: ${error.message}`);
|
|
33527
33540
|
return 1;
|
|
33528
33541
|
}
|
|
@@ -33530,7 +33543,7 @@ async function cmdRestore(runtime, manifestArg) {
|
|
|
33530
33543
|
return 1;
|
|
33531
33544
|
}
|
|
33532
33545
|
}
|
|
33533
|
-
async function
|
|
33546
|
+
async function cmdKxmTrust(runtime, check, options) {
|
|
33534
33547
|
if (runtime.workspaceFlag !== void 0) {
|
|
33535
33548
|
print(runtime.io, runtime.json, {
|
|
33536
33549
|
ok: false,
|
|
@@ -33541,9 +33554,9 @@ async function cmdVnextTrust(runtime, check, options) {
|
|
|
33541
33554
|
}
|
|
33542
33555
|
const command = check ? "trust check" : "trust diff";
|
|
33543
33556
|
try {
|
|
33544
|
-
const projectRoot =
|
|
33545
|
-
const bindings =
|
|
33546
|
-
const diff =
|
|
33557
|
+
const projectRoot = discoverKxmProjectRoot(runtime.cwd) ?? runtime.cwd;
|
|
33558
|
+
const bindings = readKxmLocalBindings(projectRoot, { stateRoot: kxmUserStateRoot({ env: runtime.env }) });
|
|
33559
|
+
const diff = diffKxmProjectAgainstRevision(projectRoot, options.base?.trim() || "HEAD", {
|
|
33547
33560
|
repositoryBindings: bindings?.repositories ?? {}
|
|
33548
33561
|
});
|
|
33549
33562
|
const payload = {
|
|
@@ -33557,7 +33570,7 @@ async function cmdVnextTrust(runtime, check, options) {
|
|
|
33557
33570
|
neutralChanges: diff.neutralChanges.length,
|
|
33558
33571
|
changes: diff.changes
|
|
33559
33572
|
};
|
|
33560
|
-
const text =
|
|
33573
|
+
const text = formatKxmPermissionDiff(diff);
|
|
33561
33574
|
if (check && diff.requiresReview) {
|
|
33562
33575
|
print(runtime.io, runtime.json, payload, `${text}
|
|
33563
33576
|
trust check failed: review every expansion above before merging`);
|
|
@@ -33566,7 +33579,7 @@ trust check failed: review every expansion above before merging`);
|
|
|
33566
33579
|
print(runtime.io, runtime.json, payload, text);
|
|
33567
33580
|
return 0;
|
|
33568
33581
|
} catch (error) {
|
|
33569
|
-
if (error instanceof
|
|
33582
|
+
if (error instanceof KxmConfigError) {
|
|
33570
33583
|
print(runtime.io, runtime.json, { ok: false, command, error: "trust_diff_failed", issues: error.issues }, `permission diff failed: ${error.message}`);
|
|
33571
33584
|
return 1;
|
|
33572
33585
|
}
|
|
@@ -33576,7 +33589,7 @@ trust check failed: review every expansion above before merging`);
|
|
|
33576
33589
|
}
|
|
33577
33590
|
var RUN_ENGINE_PHASE = "pre-3a";
|
|
33578
33591
|
var RUN_ENGINE_NOTICE = "runs remain created until the run engine lands; no steps execute yet";
|
|
33579
|
-
async function
|
|
33592
|
+
async function cmdKxmRun(runtime, workflow, promptParts) {
|
|
33580
33593
|
if (runtime.workspaceFlag !== void 0) {
|
|
33581
33594
|
print(runtime.io, runtime.json, {
|
|
33582
33595
|
ok: false,
|
|
@@ -33590,12 +33603,12 @@ async function cmdVnextRun(runtime, workflow, promptParts) {
|
|
|
33590
33603
|
return 2;
|
|
33591
33604
|
}
|
|
33592
33605
|
try {
|
|
33593
|
-
const projectRoot =
|
|
33606
|
+
const projectRoot = discoverKxmProjectRoot(runtime.cwd);
|
|
33594
33607
|
if (!projectRoot) {
|
|
33595
|
-
print(runtime.io, runtime.json, { ok: false, command: "run", error: "project_required" }, "kxm run requires a
|
|
33608
|
+
print(runtime.io, runtime.json, { ok: false, command: "run", error: "project_required" }, "kxm run requires a KXM project (run kxm init first)");
|
|
33596
33609
|
return 1;
|
|
33597
33610
|
}
|
|
33598
|
-
const bundle =
|
|
33611
|
+
const bundle = loadKxmProject(projectRoot, {});
|
|
33599
33612
|
if (!bundle.workflows.has(workflow)) {
|
|
33600
33613
|
print(runtime.io, runtime.json, { ok: false, command: "run", error: "run_workflow_unknown", workflow }, `workflow ${workflow} does not exist in this project`);
|
|
33601
33614
|
return 1;
|
|
@@ -33611,9 +33624,9 @@ async function cmdVnextRun(runtime, workflow, promptParts) {
|
|
|
33611
33624
|
}, `run plan: workflow ${workflow} at ${bundle.configRevision.slice(0, 19)}\u2026 (no run created)`);
|
|
33612
33625
|
return 0;
|
|
33613
33626
|
}
|
|
33614
|
-
const supervisor = await
|
|
33627
|
+
const supervisor = await ensureKxmSupervisor({ env: runtime.env });
|
|
33615
33628
|
const prompt = promptParts.join(" ").trim();
|
|
33616
|
-
const acceptance = await
|
|
33629
|
+
const acceptance = await kxmRuntimeRequest(supervisor, "POST", "/v1/runs", {
|
|
33617
33630
|
projectRoot,
|
|
33618
33631
|
workflowId: workflow,
|
|
33619
33632
|
prompt
|
|
@@ -33630,7 +33643,7 @@ async function cmdVnextRun(runtime, workflow, promptParts) {
|
|
|
33630
33643
|
${RUN_ENGINE_NOTICE}`);
|
|
33631
33644
|
return 0;
|
|
33632
33645
|
} catch (error) {
|
|
33633
|
-
if (error instanceof
|
|
33646
|
+
if (error instanceof KxmConfigError) {
|
|
33634
33647
|
print(runtime.io, runtime.json, { ok: false, command: "run", error: "run_failed", issues: error.issues }, `run failed: ${error.message}`);
|
|
33635
33648
|
return 1;
|
|
33636
33649
|
}
|
|
@@ -33672,15 +33685,15 @@ function formatRunStatusLine(run, drive) {
|
|
|
33672
33685
|
const statusLabel = run.status === "cancelled" ? formatCancelledStatus(reason) : run.status;
|
|
33673
33686
|
return `run ${run.runId}: ${statusLabel} (workflow ${run.workflowId}, updated ${run.updatedAt})`;
|
|
33674
33687
|
}
|
|
33675
|
-
async function
|
|
33688
|
+
async function cmdKxmRunStatus(runtime, runId) {
|
|
33676
33689
|
try {
|
|
33677
|
-
const projectRoot =
|
|
33690
|
+
const projectRoot = discoverKxmProjectRoot(runtime.cwd);
|
|
33678
33691
|
if (!projectRoot) {
|
|
33679
|
-
print(runtime.io, runtime.json, { ok: false, command: "runs status", error: "project_required" }, "kxm runs status requires a
|
|
33692
|
+
print(runtime.io, runtime.json, { ok: false, command: "runs status", error: "project_required" }, "kxm runs status requires a KXM project (run kxm init first)");
|
|
33680
33693
|
return 1;
|
|
33681
33694
|
}
|
|
33682
|
-
const supervisor = await (
|
|
33683
|
-
const result = await (
|
|
33695
|
+
const supervisor = await (kxmDriveCliSeams.ensureSupervisor ?? ensureKxmSupervisor)({ env: runtime.env });
|
|
33696
|
+
const result = await (kxmDriveCliSeams.runtimeRequest ?? kxmRuntimeRequest)(supervisor, "GET", `/v1/runs/${encodeURIComponent(runId)}?projectRoot=${encodeURIComponent(projectRoot)}`);
|
|
33684
33697
|
const run = result.run;
|
|
33685
33698
|
const drive = result.drive;
|
|
33686
33699
|
const driveLine = formatDriveStatusLine(run.status, drive);
|
|
@@ -33693,7 +33706,7 @@ ${driveLine}` : ""}`
|
|
|
33693
33706
|
);
|
|
33694
33707
|
return 0;
|
|
33695
33708
|
} catch (error) {
|
|
33696
|
-
if (error instanceof
|
|
33709
|
+
if (error instanceof KxmConfigError) {
|
|
33697
33710
|
print(runtime.io, runtime.json, { ok: false, command: "runs status", error: "run_status_failed", issues: error.issues }, `run status failed: ${error.message}`);
|
|
33698
33711
|
return 1;
|
|
33699
33712
|
}
|
|
@@ -33715,11 +33728,11 @@ function sleepMs(ms) {
|
|
|
33715
33728
|
function driveWaitCompleted(drive) {
|
|
33716
33729
|
return drive?.verified === true && drive.receipt?.settlement?.kind === "terminal" && drive.receipt.settlement.status === "completed";
|
|
33717
33730
|
}
|
|
33718
|
-
async function
|
|
33731
|
+
async function cmdKxmRunDrive(runtime, runId, simulated, options = {}) {
|
|
33719
33732
|
try {
|
|
33720
|
-
const projectRoot =
|
|
33733
|
+
const projectRoot = discoverKxmProjectRoot(runtime.cwd);
|
|
33721
33734
|
if (!projectRoot) {
|
|
33722
|
-
print(runtime.io, runtime.json, { ok: false, command: "runs drive", error: "project_required" }, "kxm runs drive requires a
|
|
33735
|
+
print(runtime.io, runtime.json, { ok: false, command: "runs drive", error: "project_required" }, "kxm runs drive requires a KXM project (run kxm init first)");
|
|
33723
33736
|
return 1;
|
|
33724
33737
|
}
|
|
33725
33738
|
const mode = simulated ? "simulated" : "live";
|
|
@@ -33737,8 +33750,8 @@ async function cmdVnextRunDrive(runtime, runId, simulated, options = {}) {
|
|
|
33737
33750
|
);
|
|
33738
33751
|
return 1;
|
|
33739
33752
|
}
|
|
33740
|
-
const supervisor = await (
|
|
33741
|
-
const request =
|
|
33753
|
+
const supervisor = await (kxmDriveCliSeams.ensureSupervisor ?? ensureKxmSupervisor)({ env: runtime.env });
|
|
33754
|
+
const request = kxmDriveCliSeams.runtimeRequest ?? kxmRuntimeRequest;
|
|
33742
33755
|
const result = await request(supervisor, "POST", `/v1/runs/${encodeURIComponent(runId)}/drive?projectRoot=${encodeURIComponent(projectRoot)}`, { mode });
|
|
33743
33756
|
const driveId = result.driveId;
|
|
33744
33757
|
const poll = result.poll;
|
|
@@ -33778,7 +33791,7 @@ async function cmdVnextRunDrive(runtime, runId, simulated, options = {}) {
|
|
|
33778
33791
|
print(runtime.io, runtime.json, { ok: false, command: "runs drive", error: "timeout" }, "drive wait timed out");
|
|
33779
33792
|
return 1;
|
|
33780
33793
|
} catch (error) {
|
|
33781
|
-
if (error instanceof
|
|
33794
|
+
if (error instanceof KxmConfigError) {
|
|
33782
33795
|
print(runtime.io, runtime.json, { ok: false, command: "runs drive", error: "run_drive_failed", issues: error.issues }, `run drive failed: ${error.message}`);
|
|
33783
33796
|
return 1;
|
|
33784
33797
|
}
|
|
@@ -33786,19 +33799,19 @@ async function cmdVnextRunDrive(runtime, runId, simulated, options = {}) {
|
|
|
33786
33799
|
return 1;
|
|
33787
33800
|
}
|
|
33788
33801
|
}
|
|
33789
|
-
async function
|
|
33802
|
+
async function cmdKxmRunCancel(runtime, runId) {
|
|
33790
33803
|
try {
|
|
33791
|
-
const projectRoot =
|
|
33804
|
+
const projectRoot = discoverKxmProjectRoot(runtime.cwd);
|
|
33792
33805
|
if (!projectRoot) {
|
|
33793
|
-
print(runtime.io, runtime.json, { ok: false, command: "runs cancel", error: "project_required" }, "kxm runs cancel requires a
|
|
33806
|
+
print(runtime.io, runtime.json, { ok: false, command: "runs cancel", error: "project_required" }, "kxm runs cancel requires a KXM project (run kxm init first)");
|
|
33794
33807
|
return 1;
|
|
33795
33808
|
}
|
|
33796
33809
|
if (runtime.dryRun) {
|
|
33797
33810
|
print(runtime.io, runtime.json, { ok: true, command: "runs cancel", dryRun: true, runId }, `cancel plan: run ${runId} (no events written)`);
|
|
33798
33811
|
return 0;
|
|
33799
33812
|
}
|
|
33800
|
-
const supervisor = await
|
|
33801
|
-
const result = await
|
|
33813
|
+
const supervisor = await ensureKxmSupervisor({ env: runtime.env });
|
|
33814
|
+
const result = await kxmRuntimeRequest(supervisor, "POST", `/v1/runs/${encodeURIComponent(runId)}/cancel?projectRoot=${encodeURIComponent(projectRoot)}`, {});
|
|
33802
33815
|
const run = result.run;
|
|
33803
33816
|
print(runtime.io, runtime.json, {
|
|
33804
33817
|
ok: true,
|
|
@@ -33808,7 +33821,7 @@ async function cmdVnextRunCancel(runtime, runId) {
|
|
|
33808
33821
|
}, `run ${run.runId}: ${run.status}`);
|
|
33809
33822
|
return 0;
|
|
33810
33823
|
} catch (error) {
|
|
33811
|
-
if (error instanceof
|
|
33824
|
+
if (error instanceof KxmConfigError) {
|
|
33812
33825
|
print(runtime.io, runtime.json, { ok: false, command: "runs cancel", error: "run_cancel_failed", issues: error.issues }, `run cancel failed: ${error.message}`);
|
|
33813
33826
|
return 1;
|
|
33814
33827
|
}
|
|
@@ -33816,17 +33829,17 @@ async function cmdVnextRunCancel(runtime, runId) {
|
|
|
33816
33829
|
return 1;
|
|
33817
33830
|
}
|
|
33818
33831
|
}
|
|
33819
|
-
async function
|
|
33832
|
+
async function cmdKxmRunList(runtime) {
|
|
33820
33833
|
try {
|
|
33821
|
-
const projectRoot =
|
|
33834
|
+
const projectRoot = discoverKxmProjectRoot(runtime.cwd);
|
|
33822
33835
|
if (!projectRoot) {
|
|
33823
|
-
print(runtime.io, runtime.json, { ok: false, command: "runs list", error: "project_required" }, "kxm runs list requires a
|
|
33836
|
+
print(runtime.io, runtime.json, { ok: false, command: "runs list", error: "project_required" }, "kxm runs list requires a KXM project (run kxm init first)");
|
|
33824
33837
|
return 1;
|
|
33825
33838
|
}
|
|
33826
|
-
const bundle =
|
|
33839
|
+
const bundle = loadKxmProject(projectRoot, {});
|
|
33827
33840
|
const projectId = String(bundle.project.value.id);
|
|
33828
|
-
const supervisor = await
|
|
33829
|
-
const result = await
|
|
33841
|
+
const supervisor = await ensureKxmSupervisor({ env: runtime.env });
|
|
33842
|
+
const result = await kxmRuntimeRequest(supervisor, "GET", `/v1/projects/${encodeURIComponent(projectId)}/runs?projectRoot=${encodeURIComponent(projectRoot)}`);
|
|
33830
33843
|
const runs = result.runs ?? [];
|
|
33831
33844
|
print(
|
|
33832
33845
|
runtime.io,
|
|
@@ -33836,7 +33849,7 @@ async function cmdVnextRunList(runtime) {
|
|
|
33836
33849
|
);
|
|
33837
33850
|
return 0;
|
|
33838
33851
|
} catch (error) {
|
|
33839
|
-
if (error instanceof
|
|
33852
|
+
if (error instanceof KxmConfigError) {
|
|
33840
33853
|
print(runtime.io, runtime.json, { ok: false, command: "runs list", error: "run_list_failed", issues: error.issues }, `run list failed: ${error.message}`);
|
|
33841
33854
|
return 1;
|
|
33842
33855
|
}
|
|
@@ -33920,15 +33933,15 @@ async function cmdModelInventoryRefresh(runtime) {
|
|
|
33920
33933
|
print(runtime.io, runtime.json, { ok: !failed, command: "models inventory refresh", output: ".kxm/models/inventory.yaml", ...inventory }, `wrote ${inventory.models.length} models to .kxm/models/inventory.yaml`);
|
|
33921
33934
|
return failed ? 1 : 0;
|
|
33922
33935
|
}
|
|
33923
|
-
async function
|
|
33924
|
-
const paths =
|
|
33936
|
+
async function cmdKxmRuntime(runtime, action) {
|
|
33937
|
+
const paths = kxmRuntimePaths({ env: runtime.env });
|
|
33925
33938
|
try {
|
|
33926
33939
|
if (action === "start") {
|
|
33927
33940
|
if (runtime.dryRun) {
|
|
33928
33941
|
print(runtime.io, runtime.json, { ok: true, command: "runtime start", dryRun: true }, "runtime supervisor would auto-start");
|
|
33929
33942
|
return 0;
|
|
33930
33943
|
}
|
|
33931
|
-
const supervisor = await
|
|
33944
|
+
const supervisor = await ensureKxmSupervisor({ env: runtime.env });
|
|
33932
33945
|
print(runtime.io, runtime.json, {
|
|
33933
33946
|
ok: true,
|
|
33934
33947
|
command: "runtime start",
|
|
@@ -33939,12 +33952,12 @@ async function cmdVnextRuntime(runtime, action) {
|
|
|
33939
33952
|
return 0;
|
|
33940
33953
|
}
|
|
33941
33954
|
if (action === "status") {
|
|
33942
|
-
const status =
|
|
33955
|
+
const status = kxmSupervisorStatus(paths);
|
|
33943
33956
|
print(runtime.io, runtime.json, { ok: true, command: "runtime status", ...status }, status.running ? `runtime supervisor running: ${status.runtimeId} pid ${status.pid} on 127.0.0.1:${status.port}` : "runtime supervisor is not running");
|
|
33944
33957
|
return status.running ? 0 : 1;
|
|
33945
33958
|
}
|
|
33946
33959
|
if (action === "stop") {
|
|
33947
|
-
const status =
|
|
33960
|
+
const status = kxmSupervisorStatus(paths);
|
|
33948
33961
|
if (!status.running || !status.port) {
|
|
33949
33962
|
print(runtime.io, runtime.json, { ok: true, command: "runtime stop", stopped: false }, "runtime supervisor is not running");
|
|
33950
33963
|
return 0;
|
|
@@ -33953,15 +33966,15 @@ async function cmdVnextRuntime(runtime, action) {
|
|
|
33953
33966
|
print(runtime.io, runtime.json, { ok: true, command: "runtime stop", dryRun: true }, `would stop runtime supervisor pid ${status.pid}`);
|
|
33954
33967
|
return 0;
|
|
33955
33968
|
}
|
|
33956
|
-
const supervisor = await
|
|
33957
|
-
await
|
|
33969
|
+
const supervisor = await ensureKxmSupervisor({ env: runtime.env });
|
|
33970
|
+
await kxmRuntimeRequest(supervisor, "POST", "/v1/shutdown", {});
|
|
33958
33971
|
print(runtime.io, runtime.json, { ok: true, command: "runtime stop", stopped: true }, `runtime supervisor ${status.runtimeId} stopping`);
|
|
33959
33972
|
return 0;
|
|
33960
33973
|
}
|
|
33961
33974
|
print(runtime.io, runtime.json, { ok: false, command: "runtime", error: "unknown_action" }, `unknown runtime action: ${action}`);
|
|
33962
33975
|
return 2;
|
|
33963
33976
|
} catch (error) {
|
|
33964
|
-
if (error instanceof
|
|
33977
|
+
if (error instanceof KxmConfigError) {
|
|
33965
33978
|
print(runtime.io, runtime.json, { ok: false, command: "runtime", error: "runtime_failed", issues: error.issues }, `runtime failed: ${error.message}`);
|
|
33966
33979
|
return 1;
|
|
33967
33980
|
}
|
|
@@ -33969,15 +33982,15 @@ async function cmdVnextRuntime(runtime, action) {
|
|
|
33969
33982
|
return 1;
|
|
33970
33983
|
}
|
|
33971
33984
|
}
|
|
33972
|
-
async function
|
|
33985
|
+
async function cmdKxmRunReceipt(runtime, runId, options = {}) {
|
|
33973
33986
|
try {
|
|
33974
|
-
const projectRoot =
|
|
33987
|
+
const projectRoot = discoverKxmProjectRoot(runtime.cwd);
|
|
33975
33988
|
if (!projectRoot) {
|
|
33976
|
-
print(runtime.io, runtime.json, { ok: false, command: "runs receipt", error: "project_required" }, "kxm runs receipt requires a
|
|
33989
|
+
print(runtime.io, runtime.json, { ok: false, command: "runs receipt", error: "project_required" }, "kxm runs receipt requires a KXM project (run kxm init first)");
|
|
33977
33990
|
return 1;
|
|
33978
33991
|
}
|
|
33979
|
-
const supervisor = await (
|
|
33980
|
-
const result = await (
|
|
33992
|
+
const supervisor = await (kxmDriveCliSeams.ensureSupervisor ?? ensureKxmSupervisor)({ env: runtime.env });
|
|
33993
|
+
const result = await (kxmDriveCliSeams.runtimeRequest ?? kxmRuntimeRequest)(
|
|
33981
33994
|
supervisor,
|
|
33982
33995
|
"GET",
|
|
33983
33996
|
`/v1/runs/${encodeURIComponent(runId)}/drive?projectRoot=${encodeURIComponent(projectRoot)}`
|
|
@@ -34000,7 +34013,7 @@ async function cmdVnextRunReceipt(runtime, runId, options = {}) {
|
|
|
34000
34013
|
print(runtime.io, runtime.json, { ok: true, command: "runs receipt", receipt: latest }, JSON.stringify(settlement, null, 2));
|
|
34001
34014
|
return 0;
|
|
34002
34015
|
} catch (error) {
|
|
34003
|
-
if (error instanceof
|
|
34016
|
+
if (error instanceof KxmConfigError) {
|
|
34004
34017
|
print(runtime.io, runtime.json, { ok: false, command: "runs receipt", error: "run_receipt_failed", issues: error.issues }, `run receipt failed: ${error.message}`);
|
|
34005
34018
|
return 1;
|
|
34006
34019
|
}
|
|
@@ -34155,7 +34168,7 @@ async function cmdTaskRun(runtime, taskId) {
|
|
|
34155
34168
|
return 1;
|
|
34156
34169
|
}
|
|
34157
34170
|
const workflow = task.assignedWorkflow ?? "default";
|
|
34158
|
-
const exitCode = await
|
|
34171
|
+
const exitCode = await cmdKxmRun(runtime, workflow, [task.objective]);
|
|
34159
34172
|
if (exitCode === 0) {
|
|
34160
34173
|
updateTaskStatus(runtime.cwd, taskId, "in_progress");
|
|
34161
34174
|
}
|
|
@@ -34186,7 +34199,7 @@ async function cmdTaskSync(runtime, taskId) {
|
|
|
34186
34199
|
}
|
|
34187
34200
|
async function cmdStudioLayout(runtime, workflowPath) {
|
|
34188
34201
|
try {
|
|
34189
|
-
const projectRoot =
|
|
34202
|
+
const projectRoot = discoverKxmProjectRoot(runtime.cwd) ?? runtime.cwd;
|
|
34190
34203
|
let filePath = workflowPath;
|
|
34191
34204
|
if (!filePath) {
|
|
34192
34205
|
filePath = resolve21(projectRoot, ".kxm", "workflows", "default.yaml");
|
|
@@ -34235,7 +34248,7 @@ steps:
|
|
|
34235
34248
|
`;
|
|
34236
34249
|
}
|
|
34237
34250
|
const parsedYaml = (0, import_yaml13.parse)(yamlContent);
|
|
34238
|
-
const plan =
|
|
34251
|
+
const plan = compileKxmWorkflow({ id: workflowId, value: parsedYaml });
|
|
34239
34252
|
const layout = generateStudioLayout(plan);
|
|
34240
34253
|
print(runtime.io, runtime.json, { ok: true, command: "studio layout", layout }, JSON.stringify(layout, null, 2));
|
|
34241
34254
|
return 0;
|
|
@@ -34278,7 +34291,7 @@ async function cmdStudioServe(runtime, options) {
|
|
|
34278
34291
|
const raw = readFileSync23(targetPath, "utf8");
|
|
34279
34292
|
const parsed = (0, import_yaml13.parse)(raw);
|
|
34280
34293
|
const wfId = basename6(targetPath).replace(/\.(yaml|yml)$/, "");
|
|
34281
|
-
return
|
|
34294
|
+
return compileKxmWorkflow({ id: wfId, value: parsed });
|
|
34282
34295
|
}
|
|
34283
34296
|
} catch {
|
|
34284
34297
|
}
|
|
@@ -43758,6 +43771,130 @@ import { mkdirSync as mkdirSync23 } from "node:fs";
|
|
|
43758
43771
|
import { join as join37, resolve as resolve24, dirname as dirname18 } from "node:path";
|
|
43759
43772
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
43760
43773
|
|
|
43774
|
+
// packages/core/tui/src/types/surface.ts
|
|
43775
|
+
var KXM_TUI_LIMITS = Object.freeze({
|
|
43776
|
+
sourceMax: 128,
|
|
43777
|
+
idMax: 128,
|
|
43778
|
+
choiceIdMax: 256,
|
|
43779
|
+
labelMax: 48,
|
|
43780
|
+
choiceLabelMax: 96,
|
|
43781
|
+
detailMax: 240,
|
|
43782
|
+
shortDetailMax: 96,
|
|
43783
|
+
stepDetailMax: 160,
|
|
43784
|
+
statusTextMax: 240,
|
|
43785
|
+
valueMax: 4096,
|
|
43786
|
+
keyPathMax: 128,
|
|
43787
|
+
outputLineMax: 512,
|
|
43788
|
+
outputMaxLines: 64,
|
|
43789
|
+
choicesMax: 128,
|
|
43790
|
+
actionsMax: 4,
|
|
43791
|
+
stepsMax: 24,
|
|
43792
|
+
fieldsMax: 64,
|
|
43793
|
+
sectionsMax: 32,
|
|
43794
|
+
orderMax: 1e3
|
|
43795
|
+
});
|
|
43796
|
+
|
|
43797
|
+
// packages/core/tui/src/tui/keys.ts
|
|
43798
|
+
var NAMED_KEYS = Object.freeze({
|
|
43799
|
+
up: "up",
|
|
43800
|
+
down: "down",
|
|
43801
|
+
left: "left",
|
|
43802
|
+
right: "right",
|
|
43803
|
+
home: "home",
|
|
43804
|
+
end: "end",
|
|
43805
|
+
pageup: "pageUp",
|
|
43806
|
+
pagedown: "pageDown",
|
|
43807
|
+
enter: "enter",
|
|
43808
|
+
return: "enter",
|
|
43809
|
+
escape: "escape",
|
|
43810
|
+
esc: "escape",
|
|
43811
|
+
tab: "tab",
|
|
43812
|
+
backspace: "backspace",
|
|
43813
|
+
delete: "delete"
|
|
43814
|
+
});
|
|
43815
|
+
|
|
43816
|
+
// packages/core/tui/src/tui/layout.ts
|
|
43817
|
+
var KXM_TUI_MARKS = Object.freeze({
|
|
43818
|
+
pending: "\u25CB",
|
|
43819
|
+
active: "\u25B6",
|
|
43820
|
+
waiting: "\u29D7",
|
|
43821
|
+
passed: "\u2714",
|
|
43822
|
+
failed: "\u2716",
|
|
43823
|
+
cancelled: "\u2298",
|
|
43824
|
+
blocked: "\u2717",
|
|
43825
|
+
ready: "\u25CF",
|
|
43826
|
+
available: "\u25D0",
|
|
43827
|
+
cursor: "\u25B8",
|
|
43828
|
+
blankCursor: " "
|
|
43829
|
+
});
|
|
43830
|
+
|
|
43831
|
+
// packages/core/tui/src/tui/theme.ts
|
|
43832
|
+
var SGR = Object.freeze({
|
|
43833
|
+
text: "37",
|
|
43834
|
+
accent: "1;36",
|
|
43835
|
+
muted: "2",
|
|
43836
|
+
dim: "2",
|
|
43837
|
+
success: "1;32",
|
|
43838
|
+
error: "1;31",
|
|
43839
|
+
warning: "1;33",
|
|
43840
|
+
border: "90"
|
|
43841
|
+
});
|
|
43842
|
+
function createPlainKxmTuiTheme() {
|
|
43843
|
+
const passthrough = (text) => text;
|
|
43844
|
+
return {
|
|
43845
|
+
colored: false,
|
|
43846
|
+
fg: (_token, text) => text,
|
|
43847
|
+
accent: passthrough,
|
|
43848
|
+
success: passthrough,
|
|
43849
|
+
error: passthrough,
|
|
43850
|
+
warning: passthrough,
|
|
43851
|
+
muted: passthrough,
|
|
43852
|
+
dim: passthrough,
|
|
43853
|
+
label: passthrough,
|
|
43854
|
+
value: passthrough,
|
|
43855
|
+
key: passthrough,
|
|
43856
|
+
cursor: passthrough,
|
|
43857
|
+
headerBg: passthrough,
|
|
43858
|
+
panelBg: passthrough
|
|
43859
|
+
};
|
|
43860
|
+
}
|
|
43861
|
+
function createKxmTuiAnsiTheme(color) {
|
|
43862
|
+
if (!color) return createPlainKxmTuiTheme();
|
|
43863
|
+
const fg = (token, text) => `\x1B[${SGR[token]}m${text}\x1B[0m`;
|
|
43864
|
+
return {
|
|
43865
|
+
colored: true,
|
|
43866
|
+
fg,
|
|
43867
|
+
accent: (text) => fg("accent", text),
|
|
43868
|
+
success: (text) => fg("success", text),
|
|
43869
|
+
error: (text) => fg("error", text),
|
|
43870
|
+
warning: (text) => fg("warning", text),
|
|
43871
|
+
muted: (text) => fg("muted", text),
|
|
43872
|
+
dim: (text) => fg("dim", text),
|
|
43873
|
+
label: (text) => fg("text", text),
|
|
43874
|
+
value: (text) => `\x1B[1m${text}\x1B[0m`,
|
|
43875
|
+
key: (text) => fg("muted", text),
|
|
43876
|
+
cursor: (text) => fg("accent", text),
|
|
43877
|
+
headerBg: (text) => `\x1B[1;97;44m${text}\x1B[0m`,
|
|
43878
|
+
panelBg: (text) => `\x1B[48;5;236m${text}\x1B[0m`
|
|
43879
|
+
};
|
|
43880
|
+
}
|
|
43881
|
+
|
|
43882
|
+
// packages/core/tui/src/tui/render.ts
|
|
43883
|
+
var SECTION_PANE_RATIO = 1 / 3;
|
|
43884
|
+
var STEP_MARKS = {
|
|
43885
|
+
pending: "\xB7",
|
|
43886
|
+
satisfied: KXM_TUI_MARKS.passed,
|
|
43887
|
+
running: KXM_TUI_MARKS.active,
|
|
43888
|
+
done: KXM_TUI_MARKS.passed,
|
|
43889
|
+
failed: KXM_TUI_MARKS.failed
|
|
43890
|
+
};
|
|
43891
|
+
|
|
43892
|
+
// packages/core/tui/src/tui/panelComponent.ts
|
|
43893
|
+
var KXM_TUI_PANEL_HELP = Object.freeze([
|
|
43894
|
+
"\u2191\u2193 move \xB7 \u2190\u2192 or Tab panes \xB7 PgUp/PgDn section \xB7 enter edit or open list",
|
|
43895
|
+
"type to filter a list \xB7 x clears a value \xB7 esc backs out \xB7 q quit \xB7 h help"
|
|
43896
|
+
]);
|
|
43897
|
+
|
|
43761
43898
|
// plugins/kxm/src/external-effects.ts
|
|
43762
43899
|
function slugifyBranchPart(text, maxLength = 40) {
|
|
43763
43900
|
const cleaned = text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -43893,9 +44030,9 @@ function resolveKxmSnapshotPaths(cwd, env = process.env) {
|
|
|
43893
44030
|
const dataPath = configured ? resolve23(cwd, configured) : join36(stateDir, "kxm.db");
|
|
43894
44031
|
return { dataPath, stateDir };
|
|
43895
44032
|
}
|
|
43896
|
-
function
|
|
43897
|
-
if (options?.
|
|
43898
|
-
return resolve23(options.
|
|
44033
|
+
function resolveKxmStateRoot(stateDir, options) {
|
|
44034
|
+
if (options?.kxmStateRoot && existsSync27(options.kxmStateRoot)) {
|
|
44035
|
+
return resolve23(options.kxmStateRoot);
|
|
43899
44036
|
}
|
|
43900
44037
|
if (existsSync27(join36(stateDir, "runtime", "registry.db")) || existsSync27(join36(stateDir, "runtime", "projects"))) {
|
|
43901
44038
|
return stateDir;
|
|
@@ -43943,17 +44080,17 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43943
44080
|
database.close();
|
|
43944
44081
|
}
|
|
43945
44082
|
}
|
|
43946
|
-
let
|
|
43947
|
-
const
|
|
43948
|
-
let
|
|
43949
|
-
const
|
|
43950
|
-
if (
|
|
43951
|
-
const runtimeDir = join36(
|
|
44083
|
+
let hasKxm = false;
|
|
44084
|
+
const kxmRuns = [];
|
|
44085
|
+
let kxmRunTotal = 0;
|
|
44086
|
+
const kxmStateRoot = resolveKxmStateRoot(stateDir, options);
|
|
44087
|
+
if (kxmStateRoot) {
|
|
44088
|
+
const runtimeDir = join36(kxmStateRoot, "runtime");
|
|
43952
44089
|
const registryDbPath = join36(runtimeDir, "registry.db");
|
|
43953
44090
|
const projectsDir = join36(runtimeDir, "projects");
|
|
43954
44091
|
const projectKeys = /* @__PURE__ */ new Set();
|
|
43955
44092
|
if (existsSync27(registryDbPath)) {
|
|
43956
|
-
|
|
44093
|
+
hasKxm = true;
|
|
43957
44094
|
try {
|
|
43958
44095
|
const regDb = new DatabaseSync(registryDbPath, { readOnly: true });
|
|
43959
44096
|
try {
|
|
@@ -43981,7 +44118,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43981
44118
|
for (const key of projectKeys) {
|
|
43982
44119
|
const eventDbPath = join36(projectsDir, key, "run-events.db");
|
|
43983
44120
|
if (existsSync27(eventDbPath)) {
|
|
43984
|
-
|
|
44121
|
+
hasKxm = true;
|
|
43985
44122
|
try {
|
|
43986
44123
|
const eventDb = new DatabaseSync(eventDbPath, { readOnly: true });
|
|
43987
44124
|
try {
|
|
@@ -43991,9 +44128,9 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43991
44128
|
FROM runs ORDER BY created_at DESC, run_id DESC LIMIT 8
|
|
43992
44129
|
`).all();
|
|
43993
44130
|
const countRow = eventDb.prepare("SELECT COUNT(*) AS total FROM runs").get();
|
|
43994
|
-
|
|
44131
|
+
kxmRunTotal += Number(countRow?.total ?? runRows.length);
|
|
43995
44132
|
for (const r of runRows) {
|
|
43996
|
-
|
|
44133
|
+
kxmRuns.push({
|
|
43997
44134
|
id: r.run_id,
|
|
43998
44135
|
status: r.status,
|
|
43999
44136
|
definitionId: r.workflow_id,
|
|
@@ -44027,7 +44164,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
44027
44164
|
}
|
|
44028
44165
|
const combinedRuns = [
|
|
44029
44166
|
...legacyRuns.map((run) => summarizeMeshRun(run)),
|
|
44030
|
-
...
|
|
44167
|
+
...kxmRuns
|
|
44031
44168
|
];
|
|
44032
44169
|
const seenIds = /* @__PURE__ */ new Set();
|
|
44033
44170
|
const uniqueRuns = [];
|
|
@@ -44043,12 +44180,12 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
44043
44180
|
return bt - at;
|
|
44044
44181
|
});
|
|
44045
44182
|
const runs = uniqueRuns.slice(0, 16);
|
|
44046
|
-
const runTotal = legacyRunTotal +
|
|
44183
|
+
const runTotal = legacyRunTotal + kxmRunTotal;
|
|
44047
44184
|
let source;
|
|
44048
|
-
if (hasLegacy &&
|
|
44185
|
+
if (hasLegacy && hasKxm) {
|
|
44049
44186
|
source = "both";
|
|
44050
|
-
} else if (
|
|
44051
|
-
source = "
|
|
44187
|
+
} else if (hasKxm) {
|
|
44188
|
+
source = "runtime";
|
|
44052
44189
|
} else {
|
|
44053
44190
|
source = "legacy";
|
|
44054
44191
|
}
|
|
@@ -44245,7 +44382,7 @@ function pad(value, width) {
|
|
|
44245
44382
|
if (text.length <= width) return text.padEnd(width);
|
|
44246
44383
|
return `${text.slice(0, Math.max(0, width - 1))}\u2026`;
|
|
44247
44384
|
}
|
|
44248
|
-
function
|
|
44385
|
+
function progressBar2(done, total, width = 10) {
|
|
44249
44386
|
if (total <= 0) return "-".repeat(width);
|
|
44250
44387
|
const filled = Math.max(0, Math.min(width, Math.round(done / total * width)));
|
|
44251
44388
|
return "#".repeat(filled) + "-".repeat(width - filled);
|
|
@@ -44259,19 +44396,10 @@ function stageMark(status, theme) {
|
|
|
44259
44396
|
return theme.dim("[ ]");
|
|
44260
44397
|
}
|
|
44261
44398
|
function meshTuiTheme(color) {
|
|
44262
|
-
|
|
44263
|
-
return {
|
|
44264
|
-
accent: ansi("1;36"),
|
|
44265
|
-
dim: ansi("2"),
|
|
44266
|
-
error: ansi("1;31"),
|
|
44267
|
-
success: ansi("1;32"),
|
|
44268
|
-
warning: ansi("1;33"),
|
|
44269
|
-
headerBg: ansi("1;97;44"),
|
|
44270
|
-
panelBg: ansi("48;5;236")
|
|
44271
|
-
};
|
|
44399
|
+
return createKxmTuiAnsiTheme(color);
|
|
44272
44400
|
}
|
|
44273
44401
|
function visibleAgents(snapshot) {
|
|
44274
|
-
return snapshot.agents.filter((agent) => agent.model !== "
|
|
44402
|
+
return snapshot.agents.filter((agent) => agent.model !== "tui");
|
|
44275
44403
|
}
|
|
44276
44404
|
function panelMetric(snapshot, panel) {
|
|
44277
44405
|
if (panel === "agents") {
|
|
@@ -44329,7 +44457,7 @@ function listLines(snapshot, view, theme) {
|
|
|
44329
44457
|
const runs = view.tab === "tasks" ? snapshot.runs.filter((run) => run.status === "running" || run.status === "waiting") : snapshot.runs;
|
|
44330
44458
|
return runs.map((run, index) => {
|
|
44331
44459
|
const counts = run.progress ? `${run.progress.done}/${run.progress.total}` : "-";
|
|
44332
|
-
const bar = run.progress ?
|
|
44460
|
+
const bar = run.progress ? progressBar2(run.progress.done, run.progress.total, 8) : "--------";
|
|
44333
44461
|
return `${mark(index)}${pad(run.definitionId, 14)} ${pad(run.status, 8)} ${bar} ${pad(counts, 5)} ${run.id}`;
|
|
44334
44462
|
});
|
|
44335
44463
|
}
|
|
@@ -44612,7 +44740,7 @@ async function runMeshTui(input) {
|
|
|
44612
44740
|
let identity;
|
|
44613
44741
|
let useOpsStream = true;
|
|
44614
44742
|
let interactive;
|
|
44615
|
-
const name = `
|
|
44743
|
+
const name = `tui-${process.pid}`;
|
|
44616
44744
|
const view = defaultMeshTuiView(input.screen);
|
|
44617
44745
|
const paint = (snapshot) => {
|
|
44618
44746
|
if (interactive) {
|
|
@@ -44709,7 +44837,7 @@ async function runMeshTui(input) {
|
|
|
44709
44837
|
name,
|
|
44710
44838
|
purpose: "Read-only mesh observer TUI",
|
|
44711
44839
|
project: input.project,
|
|
44712
|
-
model: "
|
|
44840
|
+
model: "tui"
|
|
44713
44841
|
})
|
|
44714
44842
|
});
|
|
44715
44843
|
if (!registration.ok) throw new Error(`observer registration failed with HTTP ${registration.status}`);
|
|
@@ -45393,7 +45521,7 @@ var import_yaml16 = __toESM(require_dist(), 1);
|
|
|
45393
45521
|
import { existsSync as existsSync30, readFileSync as readFileSync30 } from "node:fs";
|
|
45394
45522
|
import { join as join40 } from "node:path";
|
|
45395
45523
|
function loadKxmUpdateConfig(env = process.env) {
|
|
45396
|
-
const path4 = join40(
|
|
45524
|
+
const path4 = join40(kxmUserStateRoot({ env }), "update.yaml");
|
|
45397
45525
|
if (!existsSync30(path4)) return { schema: KXM_UPDATE_SCHEMA, auto: false, source: "github" };
|
|
45398
45526
|
let parsed;
|
|
45399
45527
|
try {
|
|
@@ -45585,7 +45713,7 @@ function installProbeFrom(runtime) {
|
|
|
45585
45713
|
function warnIgnoredProjectUpdateYaml(runtime) {
|
|
45586
45714
|
const projectFile = join42(runtime.dirs.workspace, "update.yaml");
|
|
45587
45715
|
if (!existsSync32(projectFile)) return;
|
|
45588
|
-
const userFile = join42(
|
|
45716
|
+
const userFile = join42(kxmUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
45589
45717
|
runtime.io.stderr(`kxm: ignoring .kxm/update.yaml in ${runtime.dirs.workdir}; update settings are read only from ${userFile}
|
|
45590
45718
|
`);
|
|
45591
45719
|
}
|
|
@@ -45657,7 +45785,7 @@ async function cmdHub(runtime) {
|
|
|
45657
45785
|
config = loadKxmUpdateConfig(runtime.env);
|
|
45658
45786
|
} catch (error) {
|
|
45659
45787
|
if (error instanceof KxmUpdateConfigError) {
|
|
45660
|
-
const yamlPath = join42(
|
|
45788
|
+
const yamlPath = join42(kxmUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
45661
45789
|
runtime.io.stderr(`kxm: ${error.message}; update check skipped; fix or remove ${yamlPath}
|
|
45662
45790
|
`);
|
|
45663
45791
|
} else {
|
|
@@ -47160,15 +47288,15 @@ _kxm() {
|
|
|
47160
47288
|
|
|
47161
47289
|
local -a commands
|
|
47162
47290
|
commands=(
|
|
47163
|
-
'init:Create or validate a
|
|
47291
|
+
'init:Create or validate a KXM project'
|
|
47164
47292
|
'migrate:Plan, apply, and verify legacy configuration migration'
|
|
47165
47293
|
'backup:Create a verified SQLite backup manifest'
|
|
47166
47294
|
'restore:Restore SQLite stores from a backup manifest'
|
|
47167
|
-
'run:Create a
|
|
47168
|
-
'runs:Inspect
|
|
47295
|
+
'run:Create a KXM workflow run'
|
|
47296
|
+
'runs:Inspect KXM runs'
|
|
47169
47297
|
'harness:Detect coding-agent harnesses and auth'
|
|
47170
47298
|
'update:Update kxm, harness CLIs, and model catalogs'
|
|
47171
|
-
'runtime:Manage the
|
|
47299
|
+
'runtime:Manage the KXM Runtime supervisor'
|
|
47172
47300
|
'trust:Permission-diff trust review'
|
|
47173
47301
|
'agent:Run and supervise agents'
|
|
47174
47302
|
'session:Create manifests and brief recent hub work'
|
|
@@ -48692,25 +48820,25 @@ async function dispatchAgentCliCommand(runtime, toolName, rawArgs) {
|
|
|
48692
48820
|
}
|
|
48693
48821
|
if (toolName === "kxm_workflow_wait") {
|
|
48694
48822
|
const runId = typeof args.runId === "string" ? args.runId : void 0;
|
|
48695
|
-
const projectRoot =
|
|
48823
|
+
const projectRoot = discoverKxmProjectRoot(runtime.cwd);
|
|
48696
48824
|
if (runId && projectRoot && /^run_[a-f0-9]{32}$/i.test(runId)) {
|
|
48697
48825
|
if (runtime.dryRun) {
|
|
48698
|
-
print(runtime.io, runtime.json, { ok: true, command: "workflow wait", runId, dryRun: true }, `would wait for signal on
|
|
48826
|
+
print(runtime.io, runtime.json, { ok: true, command: "workflow wait", runId, dryRun: true }, `would wait for signal on KXM run ${runId}`);
|
|
48699
48827
|
return 0;
|
|
48700
48828
|
}
|
|
48701
48829
|
try {
|
|
48702
|
-
const supervisor = await
|
|
48703
|
-
const result = await
|
|
48830
|
+
const supervisor = await ensureKxmSupervisor({ env: runtime.env });
|
|
48831
|
+
const result = await kxmRuntimeRequest(
|
|
48704
48832
|
supervisor,
|
|
48705
48833
|
"POST",
|
|
48706
48834
|
`/v1/runs/${encodeURIComponent(runId)}/wait?projectRoot=${encodeURIComponent(projectRoot)}`,
|
|
48707
48835
|
args
|
|
48708
48836
|
);
|
|
48709
|
-
print(runtime.io, runtime.json, result, `waiting for signal on
|
|
48837
|
+
print(runtime.io, runtime.json, result, `waiting for signal on KXM run ${runId}`);
|
|
48710
48838
|
return 0;
|
|
48711
48839
|
} catch (error) {
|
|
48712
|
-
const msg = error instanceof Error ? error.message : "
|
|
48713
|
-
print(runtime.io, runtime.json, { ok: false, error: "
|
|
48840
|
+
const msg = error instanceof Error ? error.message : "wait_failed";
|
|
48841
|
+
print(runtime.io, runtime.json, { ok: false, error: "wait_failed", detail: msg }, `KXM wait failed: ${msg}`);
|
|
48714
48842
|
return 1;
|
|
48715
48843
|
}
|
|
48716
48844
|
}
|
|
@@ -48752,22 +48880,22 @@ function createProgram(ctx, result) {
|
|
|
48752
48880
|
writeErr: (text) => ctx.io.stderr(text)
|
|
48753
48881
|
}).helpCommand("help", "Show help");
|
|
48754
48882
|
addGlobalOptions(program2);
|
|
48755
|
-
program2.command("init").description("Create, validate, or plan migration of a
|
|
48756
|
-
result.code = await
|
|
48883
|
+
program2.command("init").description("Create, validate, or plan migration of a KXM project").option("--json", "Print machine-readable JSON").option("--dry-run", "Plan without making changes").option("--name <name>", "Project display name for a new project").option("--project-id <id>", "Stable project ID for controlled provisioning").option("--repository <id=absolute-path>", "Bind a member repository outside Git configuration", (value, previous) => [...previous, value], []).action(async function initAction(options) {
|
|
48884
|
+
result.code = await cmdKxmInit(runtimeFrom(ctx, this), options, {
|
|
48757
48885
|
maybeOfferCompletionInstall,
|
|
48758
48886
|
maybeOfferGuideSetup
|
|
48759
48887
|
});
|
|
48760
48888
|
});
|
|
48761
48889
|
const migrate = addGlobalOptions(program2.command("migrate").description("Plan, apply, and verify legacy JSON configuration migration"));
|
|
48762
48890
|
migrate.helpCommand("help", "Show migrate help");
|
|
48763
|
-
addGlobalOptions(migrate.command("plan").description("Compute the deterministic legacy-to-
|
|
48764
|
-
result.code = await
|
|
48891
|
+
addGlobalOptions(migrate.command("plan").description("Compute the deterministic legacy-to-KXM migration plan without writes")).action(async function migratePlanAction() {
|
|
48892
|
+
result.code = await cmdKxmMigratePlan(runtimeFrom(ctx, this));
|
|
48765
48893
|
});
|
|
48766
48894
|
addGlobalOptions(migrate.command("apply").description("Install a reviewed migration with a hash-linked receipt")).option("--decisions <file>", "Reviewed kxm.migration-decision.v1 YAML file").option("--project-id <id>", "Stable project ID for controlled provisioning").option("--name <name>", "Project display name").action(async function migrateApplyAction(options) {
|
|
48767
|
-
result.code = await
|
|
48895
|
+
result.code = await cmdKxmMigrateApply(runtimeFrom(ctx, this), options);
|
|
48768
48896
|
});
|
|
48769
48897
|
addGlobalOptions(migrate.command("verify").description("Verify a migration receipt against current sources and target bundle")).action(async function migrateVerifyAction() {
|
|
48770
|
-
result.code = await
|
|
48898
|
+
result.code = await cmdKxmMigrateVerify(runtimeFrom(ctx, this));
|
|
48771
48899
|
});
|
|
48772
48900
|
addGlobalOptions(program2.command("backup").description("Create a verified SQLite backup of all stores with a hashed manifest")).option("--out <dir>", "Directory to write backup and manifest").action(async function backupAction(options) {
|
|
48773
48901
|
result.code = await cmdBackup(runtimeFrom(ctx, this), options);
|
|
@@ -48775,28 +48903,28 @@ function createProgram(ctx, result) {
|
|
|
48775
48903
|
addGlobalOptions(program2.command("restore <manifest>").description("Restore SQLite stores from a verified backup manifest")).action(async function restoreAction(manifest) {
|
|
48776
48904
|
result.code = await cmdRestore(runtimeFrom(ctx, this), manifest);
|
|
48777
48905
|
});
|
|
48778
|
-
addGlobalOptions(program2.command("run").description("Create a
|
|
48779
|
-
result.code = await
|
|
48906
|
+
addGlobalOptions(program2.command("run").description("Create a KXM run (offline-first; no steps execute until the run engine lands)").argument("[workflow]", "Workflow id to run").argument("[prompt...]", "Run prompt (hashed, never stored raw)").action(async function runAction(workflow2, promptParts) {
|
|
48907
|
+
result.code = await cmdKxmRun(runtimeFrom(ctx, this), workflow2, promptParts);
|
|
48780
48908
|
}));
|
|
48781
|
-
const runCmd = addGlobalOptions(program2.command("runs").description("Inspect
|
|
48909
|
+
const runCmd = addGlobalOptions(program2.command("runs").description("Inspect KXM runs"));
|
|
48782
48910
|
runCmd.helpCommand("help", "Show runs help");
|
|
48783
48911
|
addGlobalOptions(runCmd.command("status").description("Show the projected status of a run, including durable drive receipt state (open / receipt verified / unsettled / orphaned)")).argument("<runId>", "Run id").action(async function runStatusAction(runId) {
|
|
48784
|
-
result.code = await
|
|
48912
|
+
result.code = await cmdKxmRunStatus(runtimeFrom(ctx, this), runId);
|
|
48785
48913
|
});
|
|
48786
48914
|
addGlobalOptions(runCmd.command("drive").description("Drive a run with an explicit model-free simulation")).argument("<runId>", "Run id").option("--simulated", "Use the model-free simulation producer").option("--wait", "Wait until a drive receipt is recorded; exits 0 only for a VERIFIED COMPLETED settlement").option("--timeout-ms <n>", "Wait timeout in milliseconds (default 60000, max 600000)").action(async function runDriveAction(runId, options) {
|
|
48787
|
-
result.code = await
|
|
48915
|
+
result.code = await cmdKxmRunDrive(runtimeFrom(ctx, this), runId, options.simulated === true, {
|
|
48788
48916
|
wait: options.wait === true,
|
|
48789
48917
|
...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {}
|
|
48790
48918
|
});
|
|
48791
48919
|
});
|
|
48792
48920
|
addGlobalOptions(runCmd.command("receipt").description("Print the newest drive receipt for a run")).argument("<runId>", "Run id").option("--all", "Print the capped receipt list for the run").action(async function runReceiptAction(runId, options) {
|
|
48793
|
-
result.code = await
|
|
48921
|
+
result.code = await cmdKxmRunReceipt(runtimeFrom(ctx, this), runId, { all: options.all === true });
|
|
48794
48922
|
});
|
|
48795
48923
|
addGlobalOptions(runCmd.command("cancel").description("Durably request cancellation of a run")).argument("<runId>", "Run id").action(async function runCancelAction(runId) {
|
|
48796
|
-
result.code = await
|
|
48924
|
+
result.code = await cmdKxmRunCancel(runtimeFrom(ctx, this), runId);
|
|
48797
48925
|
});
|
|
48798
48926
|
addGlobalOptions(runCmd.command("list").description("List recent runs for the current project")).action(async function runListAction() {
|
|
48799
|
-
result.code = await
|
|
48927
|
+
result.code = await cmdKxmRunList(runtimeFrom(ctx, this));
|
|
48800
48928
|
});
|
|
48801
48929
|
const modelsCmd = addGlobalOptions(program2.command("models").description("Manage model catalogs, roles, and route state"));
|
|
48802
48930
|
modelsCmd.action(async function modelsScreenAction() {
|
|
@@ -48830,24 +48958,24 @@ function createProgram(ctx, result) {
|
|
|
48830
48958
|
addGlobalOptions(program2.command("update").description("Update kxm, harness CLIs, extensions, plugins, and model catalogs").argument("[harness]", "Harness id (default: every detected harness)").option("--check", "Check for a kxm package update without applying").option("--kxm", "Apply the kxm operator package update (GitHub release tarball or npm)").option("--self", "Update only the harness CLI").option("--extensions", "Update only extensions/plugins (Pi packages, Claude kxm)").option("--models", "Refresh model catalogs where the harness supports it")).action(async function updateAction(harness, options) {
|
|
48831
48959
|
result.code = await cmdUpdate(runtimeFrom(ctx, this), harness, options);
|
|
48832
48960
|
});
|
|
48833
|
-
const runtimeCmd = addGlobalOptions(program2.command("runtime").description("Manage the
|
|
48961
|
+
const runtimeCmd = addGlobalOptions(program2.command("runtime").description("Manage the KXM Runtime supervisor"));
|
|
48834
48962
|
runtimeCmd.helpCommand("help", "Show runtime help");
|
|
48835
48963
|
addGlobalOptions(runtimeCmd.command("start").description("Start the Runtime supervisor if not running")).action(async function runtimeStartAction() {
|
|
48836
|
-
result.code = await
|
|
48964
|
+
result.code = await cmdKxmRuntime(runtimeFrom(ctx, this), "start");
|
|
48837
48965
|
});
|
|
48838
48966
|
addGlobalOptions(runtimeCmd.command("status").description("Show Runtime supervisor liveness")).action(async function runtimeStatusAction() {
|
|
48839
|
-
result.code = await
|
|
48967
|
+
result.code = await cmdKxmRuntime(runtimeFrom(ctx, this), "status");
|
|
48840
48968
|
});
|
|
48841
48969
|
addGlobalOptions(runtimeCmd.command("stop").description("Gracefully stop the Runtime supervisor")).action(async function runtimeStopAction() {
|
|
48842
|
-
result.code = await
|
|
48970
|
+
result.code = await cmdKxmRuntime(runtimeFrom(ctx, this), "stop");
|
|
48843
48971
|
});
|
|
48844
|
-
const trust = addGlobalOptions(program2.command("trust").description("Permission-diff trust review for
|
|
48972
|
+
const trust = addGlobalOptions(program2.command("trust").description("Permission-diff trust review for KXM configuration"));
|
|
48845
48973
|
trust.helpCommand("help", "Show trust help");
|
|
48846
48974
|
addGlobalOptions(trust.command("diff").description("Show the structured permission diff against a base Git revision")).option("--base <revision>", "Base Git revision (default: HEAD)").action(async function trustDiffAction(options) {
|
|
48847
|
-
result.code = await
|
|
48975
|
+
result.code = await cmdKxmTrust(runtimeFrom(ctx, this), false, options);
|
|
48848
48976
|
});
|
|
48849
48977
|
addGlobalOptions(trust.command("check").description("Exit non-zero when the working tree expands permissions against the base revision")).option("--base <revision>", "Base Git revision (default: HEAD)").action(async function trustCheckAction(options) {
|
|
48850
|
-
result.code = await
|
|
48978
|
+
result.code = await cmdKxmTrust(runtimeFrom(ctx, this), true, options);
|
|
48851
48979
|
});
|
|
48852
48980
|
const agent = addGlobalOptions(program2.command("agent").description("Run and supervise agents"));
|
|
48853
48981
|
agent.helpCommand("help", "Show agent help");
|
|
@@ -48938,7 +49066,7 @@ function createProgram(ctx, result) {
|
|
|
48938
49066
|
};
|
|
48939
49067
|
result.code = await dispatchAgentCliCommand(runtimeFrom(ctx, this), "kxm_workflow_wait", options);
|
|
48940
49068
|
});
|
|
48941
|
-
addGlobalOptions(workflow.command("signal").description("Post a signed workflow callback or unblock a
|
|
49069
|
+
addGlobalOptions(workflow.command("signal").description("Post a signed workflow callback or unblock a KXM run")).argument("<runId>", "Workflow run ID").argument("<signalKey>", "Wait signal key").argument("<status>", "passed, warning, or failed").argument("<summary>", "Callback summary").argument("[evidence...]", "required-key=evidence pairs").option("--delivery-id <id>", "Stable callback delivery ID").action(async function workflowSignalAction(runId, signalKey, status, summary, evidence, options) {
|
|
48942
49070
|
result.code = await cmdSignal(runtimeFrom(ctx, this), runId, signalKey, status, summary, evidence ?? [], options.deliveryId);
|
|
48943
49071
|
});
|
|
48944
49072
|
addGlobalOptions(workflow.command("start").description("POST a signed workflow-start webhook")).argument("[definitionId]", "Workflow definition ID").option("--payload <json>", "JSON object or @file", "{}").option("--delivery-id <id>", "Stable provider delivery ID").option("--event <name>", "Optional provider event name").action(async function startAction(definitionId, options) {
|
|
@@ -48996,7 +49124,7 @@ function createProgram(ctx, result) {
|
|
|
48996
49124
|
addGlobalOptions(gate.command("degrade").description("Approve a configured lower peer quorum")).argument("<runId>", "Workflow run ID").argument("<stageId>", "Active stage ID").option("--requirement <key>", "Canonical requirement key").option("--reason <text>", "Non-secret operator reason").action(async function degradeAction(runId, stageId, options) {
|
|
48997
49125
|
result.code = await cmdWorkflowDegrade(runtimeFrom(ctx, this), runId, stageId, options);
|
|
48998
49126
|
});
|
|
48999
|
-
addGlobalOptions(gate.command("signal").description("Post a signed workflow callback")).argument("<runId>", "Workflow run ID").argument("<signalKey>", "Wait signal key").argument("<status>", "passed, warning, or failed").argument("<summary>", "Callback summary").argument("[evidence...]", "required-key=evidence pairs").option("--delivery-id <id>", "Stable callback delivery ID").option("--recovery-action <action>", "
|
|
49127
|
+
addGlobalOptions(gate.command("signal").description("Post a signed workflow callback")).argument("<runId>", "Workflow run ID").argument("<signalKey>", "Wait signal key").argument("<status>", "passed, warning, or failed").argument("<summary>", "Callback summary").argument("[evidence...]", "required-key=evidence pairs").option("--delivery-id <id>", "Stable callback delivery ID").option("--recovery-action <action>", "KXM recovery action: retry, fail, cancel, unblock").action(async function signalAction(runId, signalKey, status, summary, evidence, options) {
|
|
49000
49128
|
result.code = await cmdSignal(runtimeFrom(ctx, this), runId, signalKey, status, summary, evidence ?? [], options.deliveryId, options.recoveryAction);
|
|
49001
49129
|
});
|
|
49002
49130
|
const github = addGlobalOptions(gate.command("github").description("GitHub adapters"));
|