@kontextmind/kxm 0.7.52 → 0.7.54
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 +34 -0
- package/docs/agent-skills.md +1 -1
- package/docs/configuration.md +0 -3
- package/docs/contracts/migration.md +50 -220
- package/docs/contracts/validation.md +15 -33
- package/docs/test-matrix.md +1 -1
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +380 -2146
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/runtime-supervisor.js +23 -178
- package/plugins/kxm/dist/runtime.js +23 -178
- package/plugins/kxm/dist/server.js +6 -105
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/kxm/SKILL.md +1 -1
- package/plugins/kxm/skills/kxm-project-setup/SKILL.md +4 -7
- package/plugins/kxm/src/autocomplete.ts +0 -3
- package/plugins/kxm/src/cli/project.ts +2 -133
- package/plugins/kxm/src/cli.ts +3 -24
- package/plugins/kxm/src/database.ts +9 -21
- package/plugins/kxm/src/external-effects.ts +37 -27
- package/plugins/kxm/src/init.ts +10 -6
- package/plugins/kxm/src/intake.ts +6 -11
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/project-config.ts +54 -173
- package/plugins/kxm/src/runtime-store.ts +0 -69
- package/plugins/kxm/src/store.ts +0 -92
- package/schemas/README.md +0 -3
- package/plugins/kxm/src/migrate.ts +0 -1848
- package/schemas/migration-decision.schema.json +0 -26
- package/schemas/migration-plan.schema.json +0 -123
- package/schemas/migration-receipt.schema.json +0 -52
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -164,10 +164,10 @@ var require_code = __commonJS({
|
|
|
164
164
|
function interpolate(x2) {
|
|
165
165
|
return typeof x2 == "number" || typeof x2 == "boolean" || x2 === null ? x2 : safeStringify(Array.isArray(x2) ? x2.join(",") : x2);
|
|
166
166
|
}
|
|
167
|
-
function
|
|
167
|
+
function stringify10(x2) {
|
|
168
168
|
return new _Code(safeStringify(x2));
|
|
169
169
|
}
|
|
170
|
-
exports.stringify =
|
|
170
|
+
exports.stringify = stringify10;
|
|
171
171
|
function safeStringify(x2) {
|
|
172
172
|
return JSON.stringify(x2).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
173
173
|
}
|
|
@@ -2987,7 +2987,7 @@ var require_compile = __commonJS({
|
|
|
2987
2987
|
const schOrFunc = root.refs[ref];
|
|
2988
2988
|
if (schOrFunc)
|
|
2989
2989
|
return schOrFunc;
|
|
2990
|
-
let _sch =
|
|
2990
|
+
let _sch = resolve30.call(this, root, ref);
|
|
2991
2991
|
if (_sch === void 0) {
|
|
2992
2992
|
const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
2993
2993
|
const { schemaId } = this.opts;
|
|
@@ -3014,7 +3014,7 @@ var require_compile = __commonJS({
|
|
|
3014
3014
|
function sameSchemaEnv(s1, s2) {
|
|
3015
3015
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
3016
3016
|
}
|
|
3017
|
-
function
|
|
3017
|
+
function resolve30(root, ref) {
|
|
3018
3018
|
let sch;
|
|
3019
3019
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3020
3020
|
ref = sch;
|
|
@@ -3839,7 +3839,7 @@ var require_fast_uri = __commonJS({
|
|
|
3839
3839
|
}
|
|
3840
3840
|
return uri;
|
|
3841
3841
|
}
|
|
3842
|
-
function
|
|
3842
|
+
function resolve30(baseURI, relativeURI, options) {
|
|
3843
3843
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3844
3844
|
const {
|
|
3845
3845
|
parsed: baseParsed,
|
|
@@ -4201,7 +4201,7 @@ var require_fast_uri = __commonJS({
|
|
|
4201
4201
|
var fastUri = {
|
|
4202
4202
|
SCHEMES,
|
|
4203
4203
|
normalize,
|
|
4204
|
-
resolve:
|
|
4204
|
+
resolve: resolve30,
|
|
4205
4205
|
resolveComponent,
|
|
4206
4206
|
equal,
|
|
4207
4207
|
serialize,
|
|
@@ -8918,7 +8918,7 @@ var require_stringify = __commonJS({
|
|
|
8918
8918
|
props.push(doc.directives.tagString(tag));
|
|
8919
8919
|
return props.join(" ");
|
|
8920
8920
|
}
|
|
8921
|
-
function
|
|
8921
|
+
function stringify10(item, ctx, onComment, onChompKeep) {
|
|
8922
8922
|
if (identity.isPair(item))
|
|
8923
8923
|
return item.toString(ctx, onComment, onChompKeep);
|
|
8924
8924
|
if (identity.isAlias(item)) {
|
|
@@ -8947,7 +8947,7 @@ var require_stringify = __commonJS({
|
|
|
8947
8947
|
${ctx.indent}${str}`;
|
|
8948
8948
|
}
|
|
8949
8949
|
exports.createStringifyContext = createStringifyContext;
|
|
8950
|
-
exports.stringify =
|
|
8950
|
+
exports.stringify = stringify10;
|
|
8951
8951
|
}
|
|
8952
8952
|
});
|
|
8953
8953
|
|
|
@@ -8957,7 +8957,7 @@ var require_stringifyPair = __commonJS({
|
|
|
8957
8957
|
"use strict";
|
|
8958
8958
|
var identity = require_identity();
|
|
8959
8959
|
var Scalar = require_Scalar();
|
|
8960
|
-
var
|
|
8960
|
+
var stringify10 = require_stringify();
|
|
8961
8961
|
var stringifyComment = require_stringifyComment();
|
|
8962
8962
|
function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
|
|
8963
8963
|
const { allNullValues, doc, indent, indentStep, options: { commentString, indentSeq, simpleKeys } } = ctx;
|
|
@@ -8979,7 +8979,7 @@ var require_stringifyPair = __commonJS({
|
|
|
8979
8979
|
});
|
|
8980
8980
|
let keyCommentDone = false;
|
|
8981
8981
|
let chompKeep = false;
|
|
8982
|
-
let str =
|
|
8982
|
+
let str = stringify10.stringify(key, ctx, () => keyCommentDone = true, () => chompKeep = true);
|
|
8983
8983
|
if (!explicitKey && !ctx.inFlow && str.length > 1024) {
|
|
8984
8984
|
if (simpleKeys)
|
|
8985
8985
|
throw new Error("With simple keys, single line scalar must not span more than 1024 characters");
|
|
@@ -9031,7 +9031,7 @@ ${indent}:`;
|
|
|
9031
9031
|
ctx.indent = ctx.indent.substring(2);
|
|
9032
9032
|
}
|
|
9033
9033
|
let valueCommentDone = false;
|
|
9034
|
-
const valueStr =
|
|
9034
|
+
const valueStr = stringify10.stringify(value, ctx, () => valueCommentDone = true, () => chompKeep = true);
|
|
9035
9035
|
let ws = " ";
|
|
9036
9036
|
if (keyComment || vsb || vcb) {
|
|
9037
9037
|
ws = vsb ? "\n" : "";
|
|
@@ -9172,7 +9172,7 @@ var require_addPairToJSMap = __commonJS({
|
|
|
9172
9172
|
"use strict";
|
|
9173
9173
|
var log = require_log();
|
|
9174
9174
|
var merge = require_merge();
|
|
9175
|
-
var
|
|
9175
|
+
var stringify10 = require_stringify();
|
|
9176
9176
|
var identity = require_identity();
|
|
9177
9177
|
var toJS = require_toJS();
|
|
9178
9178
|
function addPairToJSMap(ctx, map, { key, value }) {
|
|
@@ -9208,7 +9208,7 @@ var require_addPairToJSMap = __commonJS({
|
|
|
9208
9208
|
if (typeof jsKey !== "object")
|
|
9209
9209
|
return String(jsKey);
|
|
9210
9210
|
if (identity.isNode(key) && ctx?.doc) {
|
|
9211
|
-
const strCtx =
|
|
9211
|
+
const strCtx = stringify10.createStringifyContext(ctx.doc, {});
|
|
9212
9212
|
strCtx.anchors = /* @__PURE__ */ new Set();
|
|
9213
9213
|
for (const node of ctx.anchors.keys())
|
|
9214
9214
|
strCtx.anchors.add(node.anchor);
|
|
@@ -9275,12 +9275,12 @@ var require_stringifyCollection = __commonJS({
|
|
|
9275
9275
|
"node_modules/yaml/dist/stringify/stringifyCollection.js"(exports) {
|
|
9276
9276
|
"use strict";
|
|
9277
9277
|
var identity = require_identity();
|
|
9278
|
-
var
|
|
9278
|
+
var stringify10 = require_stringify();
|
|
9279
9279
|
var stringifyComment = require_stringifyComment();
|
|
9280
9280
|
function stringifyCollection(collection, ctx, options) {
|
|
9281
9281
|
const flow = ctx.inFlow ?? collection.flow;
|
|
9282
|
-
const
|
|
9283
|
-
return
|
|
9282
|
+
const stringify11 = flow ? stringifyFlowCollection : stringifyBlockCollection;
|
|
9283
|
+
return stringify11(collection, ctx, options);
|
|
9284
9284
|
}
|
|
9285
9285
|
function stringifyBlockCollection({ comment, items }, ctx, { blockItemPrefix, flowChars, itemIndent, onChompKeep, onComment }) {
|
|
9286
9286
|
const { indent, options: { commentString } } = ctx;
|
|
@@ -9305,7 +9305,7 @@ var require_stringifyCollection = __commonJS({
|
|
|
9305
9305
|
}
|
|
9306
9306
|
}
|
|
9307
9307
|
chompKeep = false;
|
|
9308
|
-
let str2 =
|
|
9308
|
+
let str2 = stringify10.stringify(item, itemCtx, () => comment2 = null, () => chompKeep = true);
|
|
9309
9309
|
if (comment2)
|
|
9310
9310
|
str2 += stringifyComment.lineComment(str2, itemIndent, commentString(comment2));
|
|
9311
9311
|
if (chompKeep && comment2)
|
|
@@ -9372,7 +9372,7 @@ ${indent}${line}` : "\n";
|
|
|
9372
9372
|
}
|
|
9373
9373
|
if (comment)
|
|
9374
9374
|
reqNewline = true;
|
|
9375
|
-
let str =
|
|
9375
|
+
let str = stringify10.stringify(item, itemCtx, () => comment = null);
|
|
9376
9376
|
reqNewline || (reqNewline = lines.length > linesAtValue || str.includes("\n"));
|
|
9377
9377
|
if (i < items.length - 1) {
|
|
9378
9378
|
str += ",";
|
|
@@ -10733,7 +10733,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
10733
10733
|
"node_modules/yaml/dist/stringify/stringifyDocument.js"(exports) {
|
|
10734
10734
|
"use strict";
|
|
10735
10735
|
var identity = require_identity();
|
|
10736
|
-
var
|
|
10736
|
+
var stringify10 = require_stringify();
|
|
10737
10737
|
var stringifyComment = require_stringifyComment();
|
|
10738
10738
|
function stringifyDocument(doc, options) {
|
|
10739
10739
|
const lines = [];
|
|
@@ -10748,7 +10748,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
10748
10748
|
}
|
|
10749
10749
|
if (hasDirectives)
|
|
10750
10750
|
lines.push("---");
|
|
10751
|
-
const ctx =
|
|
10751
|
+
const ctx = stringify10.createStringifyContext(doc, options);
|
|
10752
10752
|
const { commentString } = ctx.options;
|
|
10753
10753
|
if (doc.commentBefore) {
|
|
10754
10754
|
if (lines.length !== 1)
|
|
@@ -10770,7 +10770,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
10770
10770
|
contentComment = doc.contents.comment;
|
|
10771
10771
|
}
|
|
10772
10772
|
const onChompKeep = contentComment ? void 0 : () => chompKeep = true;
|
|
10773
|
-
let body =
|
|
10773
|
+
let body = stringify10.stringify(doc.contents, ctx, () => contentComment = null, onChompKeep);
|
|
10774
10774
|
if (contentComment)
|
|
10775
10775
|
body += stringifyComment.lineComment(body, "", commentString(contentComment));
|
|
10776
10776
|
if ((body[0] === "|" || body[0] === ">") && lines[lines.length - 1] === "---") {
|
|
@@ -10778,7 +10778,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
10778
10778
|
} else
|
|
10779
10779
|
lines.push(body);
|
|
10780
10780
|
} else {
|
|
10781
|
-
lines.push(
|
|
10781
|
+
lines.push(stringify10.stringify(doc.contents, ctx));
|
|
10782
10782
|
}
|
|
10783
10783
|
if (doc.directives?.docEnd) {
|
|
10784
10784
|
if (doc.comment) {
|
|
@@ -12914,7 +12914,7 @@ var require_cst_scalar = __commonJS({
|
|
|
12914
12914
|
var require_cst_stringify = __commonJS({
|
|
12915
12915
|
"node_modules/yaml/dist/parse/cst-stringify.js"(exports) {
|
|
12916
12916
|
"use strict";
|
|
12917
|
-
var
|
|
12917
|
+
var stringify10 = (cst) => "type" in cst ? stringifyToken(cst) : stringifyItem(cst);
|
|
12918
12918
|
function stringifyToken(token) {
|
|
12919
12919
|
switch (token.type) {
|
|
12920
12920
|
case "block-scalar": {
|
|
@@ -12967,7 +12967,7 @@ var require_cst_stringify = __commonJS({
|
|
|
12967
12967
|
res += stringifyToken(value);
|
|
12968
12968
|
return res;
|
|
12969
12969
|
}
|
|
12970
|
-
exports.stringify =
|
|
12970
|
+
exports.stringify = stringify10;
|
|
12971
12971
|
}
|
|
12972
12972
|
});
|
|
12973
12973
|
|
|
@@ -14697,7 +14697,7 @@ var require_public_api = __commonJS({
|
|
|
14697
14697
|
}
|
|
14698
14698
|
return doc.toJS(Object.assign({ reviver: _reviver }, options));
|
|
14699
14699
|
}
|
|
14700
|
-
function
|
|
14700
|
+
function stringify10(value, replacer, options) {
|
|
14701
14701
|
let _replacer = null;
|
|
14702
14702
|
if (typeof replacer === "function" || Array.isArray(replacer)) {
|
|
14703
14703
|
_replacer = replacer;
|
|
@@ -14722,7 +14722,7 @@ var require_public_api = __commonJS({
|
|
|
14722
14722
|
exports.parse = parse12;
|
|
14723
14723
|
exports.parseAllDocuments = parseAllDocuments;
|
|
14724
14724
|
exports.parseDocument = parseDocument2;
|
|
14725
|
-
exports.stringify =
|
|
14725
|
+
exports.stringify = stringify10;
|
|
14726
14726
|
}
|
|
14727
14727
|
});
|
|
14728
14728
|
|
|
@@ -14779,7 +14779,7 @@ var require_dist = __commonJS({
|
|
|
14779
14779
|
});
|
|
14780
14780
|
|
|
14781
14781
|
// plugins/kxm/src/cli.ts
|
|
14782
|
-
import { resolve as
|
|
14782
|
+
import { resolve as resolve29 } from "node:path";
|
|
14783
14783
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
14784
14784
|
|
|
14785
14785
|
// node_modules/commander/lib/error.js
|
|
@@ -19446,7 +19446,7 @@ var HubClient = class {
|
|
|
19446
19446
|
if (signal?.aborted) throw new MeshWaitError("aborted", messageId);
|
|
19447
19447
|
const message = await this.getMessage(messageId);
|
|
19448
19448
|
if (["replied", "cancelled", "expired", "error"].includes(message.status)) return message;
|
|
19449
|
-
await new Promise((
|
|
19449
|
+
await new Promise((resolve30, reject) => {
|
|
19450
19450
|
const onAbort = () => {
|
|
19451
19451
|
signal?.removeEventListener("abort", onAbort);
|
|
19452
19452
|
clearTimeout(timer);
|
|
@@ -19454,7 +19454,7 @@ var HubClient = class {
|
|
|
19454
19454
|
};
|
|
19455
19455
|
const timer = setTimeout(() => {
|
|
19456
19456
|
signal?.removeEventListener("abort", onAbort);
|
|
19457
|
-
|
|
19457
|
+
resolve30();
|
|
19458
19458
|
}, Math.min(500, Math.max(1, deadline - Date.now())));
|
|
19459
19459
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
19460
19460
|
if (signal?.aborted) onAbort();
|
|
@@ -19509,7 +19509,7 @@ var HubClient = class {
|
|
|
19509
19509
|
} catch (error) {
|
|
19510
19510
|
if (this.stopped || error instanceof Error && error.name === "AbortError") return;
|
|
19511
19511
|
}
|
|
19512
|
-
if (!this.stopped) await new Promise((
|
|
19512
|
+
if (!this.stopped) await new Promise((resolve30) => setTimeout(resolve30, this.options.reconnectMs));
|
|
19513
19513
|
}
|
|
19514
19514
|
}
|
|
19515
19515
|
headers(includeIdentity = true) {
|
|
@@ -20960,7 +20960,7 @@ function defaultSpawn(command, args, options) {
|
|
|
20960
20960
|
if (options.signal?.aborted) {
|
|
20961
20961
|
return Promise.resolve({ stdout: "", stderr: "", code: null, started: false, observedChildExit: false, error: new Error("process_aborted") });
|
|
20962
20962
|
}
|
|
20963
|
-
return new Promise((
|
|
20963
|
+
return new Promise((resolve30) => {
|
|
20964
20964
|
const stdout = [];
|
|
20965
20965
|
const stderr = [];
|
|
20966
20966
|
let outputBytes = 0;
|
|
@@ -20991,7 +20991,7 @@ function defaultSpawn(command, args, options) {
|
|
|
20991
20991
|
const started = Boolean(child?.pid);
|
|
20992
20992
|
if (started && !observedChildExit) error ??= new Error("process_exit_unobserved");
|
|
20993
20993
|
const unverifiedDescendants = stopping || started && !observedChildExit;
|
|
20994
|
-
|
|
20994
|
+
resolve30({
|
|
20995
20995
|
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
20996
20996
|
stderr: Buffer.concat(stderr).toString("utf8"),
|
|
20997
20997
|
code,
|
|
@@ -22060,9 +22060,6 @@ var KxmSchemaRegistry = class {
|
|
|
22060
22060
|
localBindingsValidator;
|
|
22061
22061
|
templateProvenanceValidator;
|
|
22062
22062
|
initOperationValidator;
|
|
22063
|
-
migrationPlanValidator;
|
|
22064
|
-
migrationDecisionValidator;
|
|
22065
|
-
migrationReceiptValidator;
|
|
22066
22063
|
permissionDiffValidator;
|
|
22067
22064
|
runEventValidator;
|
|
22068
22065
|
driveReceiptValidator;
|
|
@@ -22079,9 +22076,6 @@ var KxmSchemaRegistry = class {
|
|
|
22079
22076
|
const localBindingsFile = "local-repository-bindings.schema.json";
|
|
22080
22077
|
const templateProvenanceFile = "template-provenance.schema.json";
|
|
22081
22078
|
const initOperationFile = "init-operation.schema.json";
|
|
22082
|
-
const migrationPlanFile = "migration-plan.schema.json";
|
|
22083
|
-
const migrationDecisionFile = "migration-decision.schema.json";
|
|
22084
|
-
const migrationReceiptFile = "migration-receipt.schema.json";
|
|
22085
22079
|
const permissionDiffFile = "permission-diff.schema.json";
|
|
22086
22080
|
const runEventFile = "run-event.schema.json";
|
|
22087
22081
|
const driveReceiptFile = "drive-receipt.schema.json";
|
|
@@ -22090,9 +22084,6 @@ var KxmSchemaRegistry = class {
|
|
|
22090
22084
|
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, localBindingsFile)));
|
|
22091
22085
|
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, templateProvenanceFile)));
|
|
22092
22086
|
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, initOperationFile)));
|
|
22093
|
-
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, migrationPlanFile)));
|
|
22094
|
-
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, migrationDecisionFile)));
|
|
22095
|
-
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, migrationReceiptFile)));
|
|
22096
22087
|
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, permissionDiffFile)));
|
|
22097
22088
|
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, runEventFile)));
|
|
22098
22089
|
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, driveReceiptFile)));
|
|
@@ -22106,9 +22097,6 @@ var KxmSchemaRegistry = class {
|
|
|
22106
22097
|
const localBindingsValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${localBindingsFile}`);
|
|
22107
22098
|
const templateProvenanceValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${templateProvenanceFile}`);
|
|
22108
22099
|
const initOperationValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${initOperationFile}`);
|
|
22109
|
-
const migrationPlanValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${migrationPlanFile}`);
|
|
22110
|
-
const migrationDecisionValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${migrationDecisionFile}`);
|
|
22111
|
-
const migrationReceiptValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${migrationReceiptFile}`);
|
|
22112
22100
|
const permissionDiffValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${permissionDiffFile}`);
|
|
22113
22101
|
const runEventValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${runEventFile}`);
|
|
22114
22102
|
const driveReceiptValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${driveReceiptFile}`);
|
|
@@ -22117,9 +22105,6 @@ var KxmSchemaRegistry = class {
|
|
|
22117
22105
|
if (!localBindingsValidator) throw new Error(`schema did not compile: ${localBindingsFile}`);
|
|
22118
22106
|
if (!templateProvenanceValidator) throw new Error(`schema did not compile: ${templateProvenanceFile}`);
|
|
22119
22107
|
if (!initOperationValidator) throw new Error(`schema did not compile: ${initOperationFile}`);
|
|
22120
|
-
if (!migrationPlanValidator) throw new Error(`schema did not compile: ${migrationPlanFile}`);
|
|
22121
|
-
if (!migrationDecisionValidator) throw new Error(`schema did not compile: ${migrationDecisionFile}`);
|
|
22122
|
-
if (!migrationReceiptValidator) throw new Error(`schema did not compile: ${migrationReceiptFile}`);
|
|
22123
22108
|
if (!permissionDiffValidator) throw new Error(`schema did not compile: ${permissionDiffFile}`);
|
|
22124
22109
|
if (!runEventValidator) throw new Error(`schema did not compile: ${runEventFile}`);
|
|
22125
22110
|
if (!driveReceiptValidator) throw new Error(`schema did not compile: ${driveReceiptFile}`);
|
|
@@ -22128,9 +22113,6 @@ var KxmSchemaRegistry = class {
|
|
|
22128
22113
|
this.localBindingsValidator = localBindingsValidator;
|
|
22129
22114
|
this.templateProvenanceValidator = templateProvenanceValidator;
|
|
22130
22115
|
this.initOperationValidator = initOperationValidator;
|
|
22131
|
-
this.migrationPlanValidator = migrationPlanValidator;
|
|
22132
|
-
this.migrationDecisionValidator = migrationDecisionValidator;
|
|
22133
|
-
this.migrationReceiptValidator = migrationReceiptValidator;
|
|
22134
22116
|
this.permissionDiffValidator = permissionDiffValidator;
|
|
22135
22117
|
this.runEventValidator = runEventValidator;
|
|
22136
22118
|
this.driveReceiptValidator = driveReceiptValidator;
|
|
@@ -22156,15 +22138,6 @@ var KxmSchemaRegistry = class {
|
|
|
22156
22138
|
validateInitOperation(value, file) {
|
|
22157
22139
|
return this.validateAuxiliary(value, file, "kxm.init-operation.v1", this.initOperationValidator);
|
|
22158
22140
|
}
|
|
22159
|
-
validateMigrationPlan(value, file) {
|
|
22160
|
-
return this.validateAuxiliary(value, file, "kxm.migration-plan.v1", this.migrationPlanValidator);
|
|
22161
|
-
}
|
|
22162
|
-
validateMigrationDecision(value, file) {
|
|
22163
|
-
return this.validateAuxiliary(value, file, "kxm.migration-decision.v1", this.migrationDecisionValidator);
|
|
22164
|
-
}
|
|
22165
|
-
validateMigrationReceipt(value, file) {
|
|
22166
|
-
return this.validateAuxiliary(value, file, "kxm.migration-receipt.v1", this.migrationReceiptValidator);
|
|
22167
|
-
}
|
|
22168
22141
|
validatePermissionDiff(value, file) {
|
|
22169
22142
|
return this.validateAuxiliary(value, file, "kxm.permission-diff.v1", this.permissionDiffValidator);
|
|
22170
22143
|
}
|
|
@@ -22516,35 +22489,6 @@ function validateToolPolicy(resource, policy, label, issues) {
|
|
|
22516
22489
|
if (allowed.has(tool)) issues.push(issue2("semantic", "tool_policy_contradiction", resource.logicalPath, `${label} both allows and denies ${tool}`));
|
|
22517
22490
|
}
|
|
22518
22491
|
}
|
|
22519
|
-
function validateKxmResources(resources, options = {}) {
|
|
22520
|
-
const make = (logicalPath, kind, id, value) => ({
|
|
22521
|
-
kind,
|
|
22522
|
-
...id === void 0 ? {} : { id },
|
|
22523
|
-
file: logicalPath,
|
|
22524
|
-
logicalPath,
|
|
22525
|
-
value
|
|
22526
|
-
});
|
|
22527
|
-
assertNoRegisteredGates(options);
|
|
22528
|
-
let gateRegistry;
|
|
22529
|
-
let project;
|
|
22530
|
-
const repositories = /* @__PURE__ */ new Map();
|
|
22531
|
-
const agents = /* @__PURE__ */ new Map();
|
|
22532
|
-
const models = /* @__PURE__ */ new Map();
|
|
22533
|
-
const workflows = /* @__PURE__ */ new Map();
|
|
22534
|
-
const environments = [];
|
|
22535
|
-
for (const [logicalPath, resource] of resources) {
|
|
22536
|
-
const made = make(logicalPath, resource.kind, resource.id, resource.value);
|
|
22537
|
-
if (resource.kind === "project") project = made;
|
|
22538
|
-
else if (resource.kind === "repository" && resource.id) repositories.set(resource.id, made);
|
|
22539
|
-
else if (resource.kind === "agent" && resource.id) agents.set(resource.id, made);
|
|
22540
|
-
else if (resource.kind === "model" && resource.id) models.set(resource.id, made);
|
|
22541
|
-
else if (resource.kind === "workflow" && resource.id) workflows.set(resource.id, made);
|
|
22542
|
-
else if (resource.kind === "environment") environments.push(made);
|
|
22543
|
-
else if (resource.kind === "gate-registry") gateRegistry = made;
|
|
22544
|
-
}
|
|
22545
|
-
if (!project) return [issue2("discovery", "project_definition_missing", ".kxm/project.yaml", "resource set has no project definition")];
|
|
22546
|
-
return validateBundle(project, repositories, agents, models, workflows, environments, options, gateRegistry);
|
|
22547
|
-
}
|
|
22548
22492
|
function validateAgentScope(agent, step, repositories, file, stepId, issues) {
|
|
22549
22493
|
validateToolScope(agent, step, file, stepId, issues);
|
|
22550
22494
|
const agentRepositories = objectValue(agent.value.repositories) ?? {};
|
|
@@ -22667,8 +22611,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
22667
22611
|
const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
|
|
22668
22612
|
if (maxWriteRepositories > writable) issues.push(issue2("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
|
|
22669
22613
|
}
|
|
22670
|
-
const
|
|
22671
|
-
const minimumPassed =
|
|
22614
|
+
const join49 = objectValue(step.join);
|
|
22615
|
+
const minimumPassed = join49 && typeof join49.minimumPassed === "number" ? join49.minimumPassed : void 0;
|
|
22672
22616
|
if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue2("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
|
|
22673
22617
|
const distinctBy = names(assignment?.distinctBy);
|
|
22674
22618
|
if (distinctBy.length > 0) {
|
|
@@ -22956,11 +22900,14 @@ function assertNoRegisteredGates(options) {
|
|
|
22956
22900
|
function loadKxmProject(projectRoot, options = {}) {
|
|
22957
22901
|
assertNoRegisteredGates(options);
|
|
22958
22902
|
const root = resolve3(projectRoot);
|
|
22959
|
-
|
|
22960
|
-
if (
|
|
22961
|
-
|
|
22962
|
-
|
|
22963
|
-
|
|
22903
|
+
const legacyPresent = legacyConfigFilesAt(root);
|
|
22904
|
+
if (legacyPresent.length > 0) {
|
|
22905
|
+
throw new KxmConfigError(legacyPresent.map((file) => issue2(
|
|
22906
|
+
"semantic",
|
|
22907
|
+
"legacy_state_unsupported",
|
|
22908
|
+
file,
|
|
22909
|
+
"legacy JSON configuration is present and this build does not migrate it: delete these files once their YAML replacements exist in .kxm/, or initialise a fresh project"
|
|
22910
|
+
)));
|
|
22964
22911
|
}
|
|
22965
22912
|
const registry = new KxmSchemaRegistry(options.schemasDir);
|
|
22966
22913
|
const project = readResource(registry, root, join6(root, ".kxm", "project.yaml"), ".kxm/project.yaml", "project");
|
|
@@ -22973,9 +22920,6 @@ function loadKxmProject(projectRoot, options = {}) {
|
|
|
22973
22920
|
earlyIssues.push(issue2("semantic", "template_provenance_project_mismatch", ".kxm/template-provenance.yaml", "template provenance belongs to a different project identity"));
|
|
22974
22921
|
}
|
|
22975
22922
|
}
|
|
22976
|
-
if (migrationReceipt && stringValue(migrationReceipt.projectId) !== stringValue(project.value.id)) {
|
|
22977
|
-
earlyIssues.push(issue2("semantic", "migration_project_mismatch", KXM_MIGRATION_RECEIPT_PATH, "migration receipt belongs to a different project identity"));
|
|
22978
|
-
}
|
|
22979
22923
|
const declaredRepositoryIds = new Set(valuesOf(project.value, "repositories").map((candidate) => stringValue(objectValue(candidate)?.id)).filter((candidate) => candidate !== void 0));
|
|
22980
22924
|
for (const repositoryId of Object.keys(options.repositoryBindings ?? {}).sort(compareCodeUnits3)) {
|
|
22981
22925
|
if (!resourceIdentifier(repositoryId)) {
|
|
@@ -23052,6 +22996,15 @@ function loadKxmProject(projectRoot, options = {}) {
|
|
|
23052
22996
|
continue;
|
|
23053
22997
|
}
|
|
23054
22998
|
}
|
|
22999
|
+
const memberLegacy = binding === root ? [] : legacyConfigFilesAt(binding);
|
|
23000
|
+
if (memberLegacy.length > 0) {
|
|
23001
|
+
throw new KxmConfigError(memberLegacy.map((file) => issue2(
|
|
23002
|
+
"semantic",
|
|
23003
|
+
"legacy_state_unsupported",
|
|
23004
|
+
`${repositoryId}/${file}`,
|
|
23005
|
+
`repository ${repositoryId} holds legacy JSON configuration and this build does not migrate it: delete those files once their YAML replacements exist, or bind a clean worktree`
|
|
23006
|
+
)));
|
|
23007
|
+
}
|
|
23055
23008
|
const foldedBinding = canonicalHostPath(binding).toLocaleLowerCase("en-US");
|
|
23056
23009
|
const priorBinding = seenBindings.get(foldedBinding);
|
|
23057
23010
|
if (priorBinding && priorBinding !== repositoryId) {
|
|
@@ -23105,50 +23058,10 @@ function loadKxmProject(projectRoot, options = {}) {
|
|
|
23105
23058
|
environments,
|
|
23106
23059
|
...gateRegistry ? { gateRegistry } : {},
|
|
23107
23060
|
...templateProvenance === void 0 ? {} : { templateProvenance },
|
|
23108
|
-
...migrationReceipt === void 0 ? {} : { migrationReceipt },
|
|
23109
23061
|
resources,
|
|
23110
23062
|
configRevision: bundleRevision(resources)
|
|
23111
23063
|
};
|
|
23112
23064
|
}
|
|
23113
|
-
function verifyKxmMigrationReceiptTarget(root, receipt, resources, configRevision) {
|
|
23114
|
-
const issues = [];
|
|
23115
|
-
if (receipt.configRevision !== configRevision) {
|
|
23116
|
-
issues.push(issue2("semantic", "migration_target_changed", KXM_MIGRATION_RECEIPT_PATH, "target configuration revision no longer matches the migration receipt"));
|
|
23117
|
-
}
|
|
23118
|
-
const declared = /* @__PURE__ */ new Map();
|
|
23119
|
-
for (const candidate of Array.isArray(receipt.resources) ? receipt.resources : []) {
|
|
23120
|
-
if (candidate && typeof candidate === "object" && !Array.isArray(candidate)) {
|
|
23121
|
-
const record = candidate;
|
|
23122
|
-
if (typeof record.path === "string") declared.set(record.path, record);
|
|
23123
|
-
}
|
|
23124
|
-
}
|
|
23125
|
-
const installedPaths = /* @__PURE__ */ new Set();
|
|
23126
|
-
for (const resource of resources) {
|
|
23127
|
-
const relative7 = resource.file.startsWith(root) ? relativePortable(root, resource.file) : void 0;
|
|
23128
|
-
if (!relative7) continue;
|
|
23129
|
-
installedPaths.add(relative7);
|
|
23130
|
-
const record = declared.get(relative7);
|
|
23131
|
-
if (!record) {
|
|
23132
|
-
issues.push(issue2("semantic", "migration_target_unreceipted", relative7, "installed resource is not covered by the migration receipt"));
|
|
23133
|
-
continue;
|
|
23134
|
-
}
|
|
23135
|
-
const current = hashFileRecord(root, relative7);
|
|
23136
|
-
if (!current || current.sha256 !== record.sha256 || current.bytes !== record.bytes) {
|
|
23137
|
-
issues.push(issue2("semantic", "migration_target_modified", relative7, "installed resource bytes differ from the migration receipt"));
|
|
23138
|
-
}
|
|
23139
|
-
}
|
|
23140
|
-
for (const path4 of declared.keys()) {
|
|
23141
|
-
if (!installedPaths.has(path4)) {
|
|
23142
|
-
issues.push(issue2("semantic", "migration_target_missing", path4, "receipt-covered resource is not part of the validated configuration"));
|
|
23143
|
-
}
|
|
23144
|
-
}
|
|
23145
|
-
return sortIssues2(issues);
|
|
23146
|
-
}
|
|
23147
|
-
function relativePortable(root, absolute) {
|
|
23148
|
-
const rel = relative(root, absolute);
|
|
23149
|
-
if (!rel || isAbsolute2(rel) || rel === ".." || rel.startsWith(`..${sep}`)) return void 0;
|
|
23150
|
-
return rel.split(sep).join("/");
|
|
23151
|
-
}
|
|
23152
23065
|
function legacyInputsAt(root) {
|
|
23153
23066
|
const candidates = [
|
|
23154
23067
|
".kxm/config/agents.json",
|
|
@@ -23158,7 +23071,6 @@ function legacyInputsAt(root) {
|
|
|
23158
23071
|
];
|
|
23159
23072
|
return candidates.filter((candidate) => existsSync6(join6(root, ...candidate.split("/"))));
|
|
23160
23073
|
}
|
|
23161
|
-
var KXM_MIGRATION_RECEIPT_PATH = ".kxm/migration-receipt.yaml";
|
|
23162
23074
|
var LEGACY_CONFIG_FILES = [".kxm/config/agents.json", ".kxm/config/gates.json"];
|
|
23163
23075
|
function legacyConfigFilesAt(root) {
|
|
23164
23076
|
const files = [];
|
|
@@ -23184,66 +23096,6 @@ function legacyConfigFilesAt(root) {
|
|
|
23184
23096
|
}
|
|
23185
23097
|
return files;
|
|
23186
23098
|
}
|
|
23187
|
-
function hashFileRecord(root, relativePath) {
|
|
23188
|
-
const absolute = join6(root, ...relativePath.split("/"));
|
|
23189
|
-
if (!existsSync6(absolute)) return void 0;
|
|
23190
|
-
const bytes = readFileSync5(absolute);
|
|
23191
|
-
return {
|
|
23192
|
-
path: relativePath,
|
|
23193
|
-
sha256: `sha256:${createHash6("sha256").update(bytes).digest("hex")}`,
|
|
23194
|
-
bytes: bytes.byteLength
|
|
23195
|
-
};
|
|
23196
|
-
}
|
|
23197
|
-
function migrationReceiptSelfHash(receipt) {
|
|
23198
|
-
const { receiptSha256: _ignored, ...unsigned } = receipt;
|
|
23199
|
-
return `sha256:${createHash6("sha256").update(kxmCanonicalJson(unsigned), "utf8").digest("hex")}`;
|
|
23200
|
-
}
|
|
23201
|
-
function readKxmMigrationReceipt(root, options = {}) {
|
|
23202
|
-
const receiptPath = join6(root, ...KXM_MIGRATION_RECEIPT_PATH.split("/"));
|
|
23203
|
-
const legacyFiles = legacyConfigFilesAt(root);
|
|
23204
|
-
if (!existsSync6(receiptPath)) {
|
|
23205
|
-
return {
|
|
23206
|
-
issues: legacyFiles.map((file) => issue2("semantic", "legacy_kxm_conflict", file, "legacy and KXM configuration cannot coexist before an accepted migration receipt"))
|
|
23207
|
-
};
|
|
23208
|
-
}
|
|
23209
|
-
const receiptStat = lstatSync(receiptPath);
|
|
23210
|
-
if (receiptStat.isSymbolicLink() || !receiptStat.isFile()) {
|
|
23211
|
-
return { issues: [issue2("path", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "migration receipt must be a regular file, not a link")] };
|
|
23212
|
-
}
|
|
23213
|
-
let receipt;
|
|
23214
|
-
try {
|
|
23215
|
-
receipt = parseRestrictedYaml2(readFileSync5(receiptPath), KXM_MIGRATION_RECEIPT_PATH);
|
|
23216
|
-
} catch (error) {
|
|
23217
|
-
if (error instanceof KxmConfigError) return { issues: [...error.issues] };
|
|
23218
|
-
throw error;
|
|
23219
|
-
}
|
|
23220
|
-
const registry = new KxmSchemaRegistry(options.schemasDir);
|
|
23221
|
-
const schemaIssues = registry.validateMigrationReceipt(receipt, KXM_MIGRATION_RECEIPT_PATH);
|
|
23222
|
-
if (schemaIssues.length > 0) return { issues: schemaIssues };
|
|
23223
|
-
if (receipt.receiptSha256 !== migrationReceiptSelfHash(receipt)) {
|
|
23224
|
-
return { issues: [issue2("semantic", "migration_receipt_hash_mismatch", KXM_MIGRATION_RECEIPT_PATH, "receipt self-hash does not match its content")] };
|
|
23225
|
-
}
|
|
23226
|
-
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);
|
|
23227
|
-
const issues = [];
|
|
23228
|
-
const declared = new Set(sources);
|
|
23229
|
-
for (const file of legacyFiles) {
|
|
23230
|
-
if (!declared.has(file)) {
|
|
23231
|
-
issues.push(issue2("semantic", "migration_source_unmigrated", file, "legacy configuration file is not covered by the migration receipt"));
|
|
23232
|
-
continue;
|
|
23233
|
-
}
|
|
23234
|
-
const record = (Array.isArray(receipt.sources) ? receipt.sources : []).map((candidate) => candidate && typeof candidate === "object" && !Array.isArray(candidate) ? candidate : void 0).find((candidate) => candidate?.path === file);
|
|
23235
|
-
const current = hashFileRecord(root, file);
|
|
23236
|
-
if (!current || current.sha256 !== record?.sha256 || current.bytes !== record?.bytes) {
|
|
23237
|
-
issues.push(issue2("semantic", "migration_source_changed", file, "legacy configuration changed after the migration receipt was issued"));
|
|
23238
|
-
}
|
|
23239
|
-
}
|
|
23240
|
-
for (const file of sources) {
|
|
23241
|
-
if (!legacyFiles.includes(file)) {
|
|
23242
|
-
issues.push(issue2("semantic", "migration_source_missing", file, "receipt covers a legacy configuration file that no longer exists"));
|
|
23243
|
-
}
|
|
23244
|
-
}
|
|
23245
|
-
return issues.length > 0 ? { issues } : { receipt, issues: [] };
|
|
23246
|
-
}
|
|
23247
23099
|
function discoverLegacyRoot(start) {
|
|
23248
23100
|
let initial = resolve3(start);
|
|
23249
23101
|
if (existsSync6(initial) && !lstatSync(initial).isDirectory()) initial = dirname4(initial);
|
|
@@ -23260,16 +23112,32 @@ function planKxmInitialization(start = process.cwd(), options = {}) {
|
|
|
23260
23112
|
return { mode: "ready", inspectedFrom, projectRoot, changesRequired: false, issues: [], legacyInputs: [], configRevision: bundle.configRevision };
|
|
23261
23113
|
} catch (error) {
|
|
23262
23114
|
if (!(error instanceof KxmConfigError)) throw error;
|
|
23115
|
+
const legacyIssues = error.issues.filter((candidate) => candidate.code === "legacy_state_unsupported");
|
|
23263
23116
|
const legacyInputs = legacyInputsAt(projectRoot);
|
|
23264
|
-
if (legacyInputs.length > 0) {
|
|
23265
|
-
return {
|
|
23117
|
+
if (legacyInputs.length > 0 || legacyIssues.length > 0) {
|
|
23118
|
+
return {
|
|
23119
|
+
mode: "legacy",
|
|
23120
|
+
inspectedFrom,
|
|
23121
|
+
projectRoot,
|
|
23122
|
+
legacyRoot: projectRoot,
|
|
23123
|
+
changesRequired: true,
|
|
23124
|
+
issues: [...error.issues, ...legacyInputs.length > 0 ? [issue2("discovery", "legacy_state_unsupported", ".kxm", "legacy configuration is present and this build does not migrate it: initialise a fresh project directory and carry over the YAML definitions you want to keep")] : []],
|
|
23125
|
+
legacyInputs: [.../* @__PURE__ */ new Set([...legacyInputs, ...legacyIssues.map((candidate) => candidate.file)])]
|
|
23126
|
+
};
|
|
23266
23127
|
}
|
|
23267
23128
|
return { mode: "repair", inspectedFrom, projectRoot, changesRequired: true, issues: error.issues, legacyInputs: [] };
|
|
23268
23129
|
}
|
|
23269
23130
|
}
|
|
23270
23131
|
const legacy = discoverLegacyRoot(inspectedFrom);
|
|
23271
23132
|
if (legacy) {
|
|
23272
|
-
return {
|
|
23133
|
+
return {
|
|
23134
|
+
mode: "legacy",
|
|
23135
|
+
inspectedFrom,
|
|
23136
|
+
legacyRoot: legacy.root,
|
|
23137
|
+
changesRequired: true,
|
|
23138
|
+
issues: [issue2("discovery", "legacy_state_unsupported", legacy.root, "legacy KXM/Mesh configuration discovered; this build does not migrate it \u2014 initialise a fresh project directory and copy the YAML definitions you want to keep")],
|
|
23139
|
+
legacyInputs: legacy.inputs
|
|
23140
|
+
};
|
|
23273
23141
|
}
|
|
23274
23142
|
const gitRoot = discoverGitRoot(inspectedFrom);
|
|
23275
23143
|
const candidateRoot = gitRoot ?? inspectedFrom;
|
|
@@ -23767,20 +23635,11 @@ function openDatabase(file, description, spec) {
|
|
|
23767
23635
|
database.exec(spec.schema);
|
|
23768
23636
|
database.exec(`PRAGMA user_version = ${spec.version}`);
|
|
23769
23637
|
} else if (version < spec.version) {
|
|
23770
|
-
|
|
23771
|
-
|
|
23772
|
-
|
|
23773
|
-
|
|
23774
|
-
|
|
23775
|
-
"runtime_schema_outdated",
|
|
23776
|
-
file,
|
|
23777
|
-
`${description} schema version ${version} is older than ${spec.version}; no migration lane, backup and restore remain E6`
|
|
23778
|
-
);
|
|
23779
|
-
}
|
|
23780
|
-
step.migrate(database);
|
|
23781
|
-
currentVersion = step.toVersion;
|
|
23782
|
-
database.exec(`PRAGMA user_version = ${currentVersion}`);
|
|
23783
|
-
}
|
|
23638
|
+
throw databaseError(
|
|
23639
|
+
"runtime_schema_outdated",
|
|
23640
|
+
file,
|
|
23641
|
+
`${description} is schema version ${version}; this build requires ${spec.version}. Delete the state file to start fresh and let its owning process recreate it (\`kxm hub start\` for hub state, the Runtime for registry/event stores); \`kxm init\` is project-only and rebuilds no database \u2014 upgrading old state in place is deliberately unsupported`
|
|
23642
|
+
);
|
|
23784
23643
|
}
|
|
23785
23644
|
if (spec.tables) {
|
|
23786
23645
|
verifyExpectedTables(database, file, description, spec.tables);
|
|
@@ -24541,7 +24400,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
24541
24400
|
const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
|
|
24542
24401
|
const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
|
|
24543
24402
|
const assignments = compileAssignments(step, id, agent, sink);
|
|
24544
|
-
const
|
|
24403
|
+
const join49 = compileJoin(step, id, sink);
|
|
24545
24404
|
const requiredEvidence = compileEvidence(step, id, sink);
|
|
24546
24405
|
const transitions = compileTransitions(step, id, index, stepIndex, sink);
|
|
24547
24406
|
const outcomes = Object.keys(transitions).sort(compareCodeUnits4);
|
|
@@ -24569,7 +24428,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
24569
24428
|
transitions: orderedTransitions,
|
|
24570
24429
|
requiresPlanHash: requirePlanHash.includes(id),
|
|
24571
24430
|
assignments,
|
|
24572
|
-
join:
|
|
24431
|
+
join: join49
|
|
24573
24432
|
};
|
|
24574
24433
|
if (kind === "agent" || kind === "moa") {
|
|
24575
24434
|
if (!agent) return void 0;
|
|
@@ -24619,15 +24478,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
|
|
|
24619
24478
|
};
|
|
24620
24479
|
}
|
|
24621
24480
|
function compileJoin(step, stepId, sink) {
|
|
24622
|
-
const
|
|
24623
|
-
if (!
|
|
24624
|
-
const declared = stringValue2(
|
|
24481
|
+
const join49 = objectValue2(step.join);
|
|
24482
|
+
if (!join49) return { strategy: "all" };
|
|
24483
|
+
const declared = stringValue2(join49.strategy);
|
|
24625
24484
|
const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
|
|
24626
|
-
const minimumPassed = compileOptionalCount(
|
|
24485
|
+
const minimumPassed = compileOptionalCount(join49.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
|
|
24627
24486
|
const compiled = {
|
|
24628
24487
|
strategy,
|
|
24629
24488
|
...minimumPassed !== void 0 ? { minimumPassed } : {},
|
|
24630
|
-
...typeof
|
|
24489
|
+
...typeof join49.cancelRemaining === "boolean" ? { cancelRemaining: join49.cancelRemaining } : {}
|
|
24631
24490
|
};
|
|
24632
24491
|
return compiled;
|
|
24633
24492
|
}
|
|
@@ -27856,7 +27715,7 @@ async function watchGithubChecks(input) {
|
|
|
27856
27715
|
}
|
|
27857
27716
|
const fetchImpl = input.fetchImpl ?? fetch;
|
|
27858
27717
|
const now = input.now ?? Date.now;
|
|
27859
|
-
const sleep = input.sleep ?? ((ms) => new Promise((
|
|
27718
|
+
const sleep = input.sleep ?? ((ms) => new Promise((resolve30) => setTimeout(resolve30, ms)));
|
|
27860
27719
|
const deadline = now() + input.timeoutMs;
|
|
27861
27720
|
const headers = {
|
|
27862
27721
|
authorization: `Bearer ${token}`,
|
|
@@ -28851,9 +28710,9 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28851
28710
|
}
|
|
28852
28711
|
|
|
28853
28712
|
// plugins/kxm/src/cli/tasks.ts
|
|
28854
|
-
var
|
|
28855
|
-
import { existsSync as
|
|
28856
|
-
import { basename as basename6, join as
|
|
28713
|
+
var import_yaml12 = __toESM(require_dist(), 1);
|
|
28714
|
+
import { existsSync as existsSync23, readFileSync as readFileSync22, readdirSync as readdirSync8 } from "node:fs";
|
|
28715
|
+
import { basename as basename6, join as join27, resolve as resolve20 } from "node:path";
|
|
28857
28716
|
|
|
28858
28717
|
// plugins/kxm/src/suggest.ts
|
|
28859
28718
|
var WORKFLOW_PATTERNS = [
|
|
@@ -29863,7 +29722,7 @@ function createStudioServer(options = {}) {
|
|
|
29863
29722
|
}
|
|
29864
29723
|
|
|
29865
29724
|
// plugins/kxm/src/cli/project.ts
|
|
29866
|
-
import { join as
|
|
29725
|
+
import { join as join26, resolve as resolve19 } from "node:path";
|
|
29867
29726
|
import { createInterface as createInterface2 } from "node:readline";
|
|
29868
29727
|
|
|
29869
29728
|
// plugins/kxm/src/model-inventory.ts
|
|
@@ -31692,17 +31551,20 @@ function initializeKxmProjectAtGitRoot(start, gitRoot, options, mutationLock) {
|
|
|
31692
31551
|
]);
|
|
31693
31552
|
const loaderOptions2 = configOptions(options, repositoryBindings);
|
|
31694
31553
|
const transactionOptions = repairOptions(options, repositoryBindings);
|
|
31554
|
+
const plan = planKxmInitialization(start, loaderOptions2);
|
|
31555
|
+
if (plan.mode === "legacy") {
|
|
31556
|
+
return { action: "planned", plan, ...plan.projectRoot ? { projectRoot: plan.projectRoot } : {}, files: [] };
|
|
31557
|
+
}
|
|
31695
31558
|
if (hasKxmInitTransaction(gitRoot)) {
|
|
31696
31559
|
const operation = inspectKxmInitTransaction(gitRoot, options.schemasDir);
|
|
31697
|
-
const plan2 = planKxmInitialization(start, loaderOptions2);
|
|
31698
31560
|
if (!operation) {
|
|
31699
|
-
if (options.dryRun) return { action: "planned", plan
|
|
31561
|
+
if (options.dryRun) return { action: "planned", plan, projectRoot: gitRoot, resumePending: true, files: [] };
|
|
31700
31562
|
if (!mutationLock) throw new Error("project mutation lock is required to clean an empty transaction");
|
|
31701
31563
|
resumeKxmInitTransaction(gitRoot, transactionOptions);
|
|
31702
31564
|
} else if (options.dryRun) {
|
|
31703
31565
|
return {
|
|
31704
31566
|
action: "planned",
|
|
31705
|
-
plan
|
|
31567
|
+
plan,
|
|
31706
31568
|
projectRoot: gitRoot,
|
|
31707
31569
|
resumePending: true,
|
|
31708
31570
|
transactionKind: operation.kind,
|
|
@@ -31751,10 +31613,6 @@ function initializeKxmProjectAtGitRoot(start, gitRoot, options, mutationLock) {
|
|
|
31751
31613
|
};
|
|
31752
31614
|
}
|
|
31753
31615
|
}
|
|
31754
|
-
const plan = planKxmInitialization(start, loaderOptions2);
|
|
31755
|
-
if (plan.mode === "migrate") {
|
|
31756
|
-
return { action: "planned", plan, ...plan.projectRoot ? { projectRoot: plan.projectRoot } : {}, files: [] };
|
|
31757
|
-
}
|
|
31758
31616
|
if (plan.mode === "repair") {
|
|
31759
31617
|
const projectRoot = plan.projectRoot ?? gitRoot;
|
|
31760
31618
|
let templateRepair;
|
|
@@ -31903,1486 +31761,6 @@ function initializeKxmProject(start = process.cwd(), options = {}) {
|
|
|
31903
31761
|
return withKxmLocalBindingLock(gitRoot, storeOptions, (lock) => initializeKxmProjectAtGitRoot(start, gitRoot, options, lock));
|
|
31904
31762
|
}
|
|
31905
31763
|
|
|
31906
|
-
// plugins/kxm/src/migrate.ts
|
|
31907
|
-
var import_yaml12 = __toESM(require_dist(), 1);
|
|
31908
|
-
import { createHash as createHash13 } from "node:crypto";
|
|
31909
|
-
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";
|
|
31910
|
-
import { join as join26 } from "node:path";
|
|
31911
|
-
var MAX_LEGACY_JSON_BYTES = 1024 * 1024;
|
|
31912
|
-
var MAX_LEGACY_JSON_DEPTH = 32;
|
|
31913
|
-
var MAX_LEGACY_JSON_NODES = 32768;
|
|
31914
|
-
var MAX_LEGACY_SOURCES = 64;
|
|
31915
|
-
function migrateIssue(phase, code, file, message) {
|
|
31916
|
-
return { phase, code, file, message };
|
|
31917
|
-
}
|
|
31918
|
-
function migrateFail(code, file, message) {
|
|
31919
|
-
throw new KxmConfigError([migrateIssue("parse", code, file, message)]);
|
|
31920
|
-
}
|
|
31921
|
-
function parseLegacyJson(text, label) {
|
|
31922
|
-
const bytes = Buffer.byteLength(text, "utf8");
|
|
31923
|
-
if (bytes > MAX_LEGACY_JSON_BYTES) migrateFail("document_too_large", label, `document exceeds ${MAX_LEGACY_JSON_BYTES} bytes`);
|
|
31924
|
-
const state = { nodes: 0 };
|
|
31925
|
-
const parseNode = (value, path4, depth) => {
|
|
31926
|
-
state.nodes += 1;
|
|
31927
|
-
if (state.nodes > MAX_LEGACY_JSON_NODES) migrateFail("node_limit", label, `document exceeds ${MAX_LEGACY_JSON_NODES} nodes`);
|
|
31928
|
-
if (depth > MAX_LEGACY_JSON_DEPTH) migrateFail("depth_limit", label, `document exceeds nesting depth ${MAX_LEGACY_JSON_DEPTH}`);
|
|
31929
|
-
if (value === null || typeof value === "boolean" || typeof value === "string") return value;
|
|
31930
|
-
if (typeof value === "number") {
|
|
31931
|
-
if (!Number.isFinite(value)) migrateFail("non_json_number", label, `${path4} is not a finite number`);
|
|
31932
|
-
return value;
|
|
31933
|
-
}
|
|
31934
|
-
if (Array.isArray(value)) {
|
|
31935
|
-
return value.map((entry, index) => parseNode(entry, `${path4}[${index}]`, depth + 1));
|
|
31936
|
-
}
|
|
31937
|
-
if (value && typeof value === "object") {
|
|
31938
|
-
const record = {};
|
|
31939
|
-
for (const [key, entry] of Object.entries(value)) record[key] = parseNode(entry, `${path4}.${key}`, depth + 1);
|
|
31940
|
-
return record;
|
|
31941
|
-
}
|
|
31942
|
-
migrateFail("non_json_value", label, `${path4} is not JSON-compatible`);
|
|
31943
|
-
};
|
|
31944
|
-
let raw;
|
|
31945
|
-
try {
|
|
31946
|
-
raw = JSON.parse(text);
|
|
31947
|
-
} catch (error) {
|
|
31948
|
-
migrateFail("invalid_json", label, error instanceof Error ? error.message : String(error));
|
|
31949
|
-
}
|
|
31950
|
-
detectDuplicateKeys(text, label);
|
|
31951
|
-
return parseNode(raw, "$", 0);
|
|
31952
|
-
}
|
|
31953
|
-
function detectDuplicateKeys(text, label) {
|
|
31954
|
-
const stack = [];
|
|
31955
|
-
let index = 0;
|
|
31956
|
-
const length = text.length;
|
|
31957
|
-
const skipWhitespace = () => {
|
|
31958
|
-
while (index < length && /[\s]/.test(text[index])) index += 1;
|
|
31959
|
-
};
|
|
31960
|
-
const parseString = () => {
|
|
31961
|
-
let result = "";
|
|
31962
|
-
index += 1;
|
|
31963
|
-
while (index < length) {
|
|
31964
|
-
const char = text[index];
|
|
31965
|
-
if (char === '"') {
|
|
31966
|
-
index += 1;
|
|
31967
|
-
return result;
|
|
31968
|
-
}
|
|
31969
|
-
if (char === "\\") {
|
|
31970
|
-
const escape2 = text[index + 1];
|
|
31971
|
-
if (escape2 === "u") {
|
|
31972
|
-
result += String.fromCharCode(Number.parseInt(text.slice(index + 2, index + 6), 16));
|
|
31973
|
-
index += 6;
|
|
31974
|
-
} else {
|
|
31975
|
-
const escapes = { '"': '"', "\\": "\\", "/": "/", b: "\b", f: "\f", n: "\n", r: "\r", t: " " };
|
|
31976
|
-
result += escapes[escape2] ?? escape2;
|
|
31977
|
-
index += 2;
|
|
31978
|
-
}
|
|
31979
|
-
} else {
|
|
31980
|
-
result += char;
|
|
31981
|
-
index += 1;
|
|
31982
|
-
}
|
|
31983
|
-
}
|
|
31984
|
-
migrateFail("invalid_json", label, "unterminated string");
|
|
31985
|
-
};
|
|
31986
|
-
const skipValue = () => {
|
|
31987
|
-
skipWhitespace();
|
|
31988
|
-
const char = text[index];
|
|
31989
|
-
if (char === '"') {
|
|
31990
|
-
parseString();
|
|
31991
|
-
return;
|
|
31992
|
-
}
|
|
31993
|
-
if (char === "{" || char === "[") {
|
|
31994
|
-
parseContainer();
|
|
31995
|
-
return;
|
|
31996
|
-
}
|
|
31997
|
-
while (index < length && !/[\s,\]}]/.test(text[index])) index += 1;
|
|
31998
|
-
};
|
|
31999
|
-
const parseContainer = () => {
|
|
32000
|
-
const char = text[index];
|
|
32001
|
-
if (stack.length > MAX_LEGACY_JSON_DEPTH) migrateFail("depth_limit", label, `document exceeds nesting depth ${MAX_LEGACY_JSON_DEPTH}`);
|
|
32002
|
-
if (char === "{") {
|
|
32003
|
-
const keys = /* @__PURE__ */ new Set();
|
|
32004
|
-
stack.push(keys);
|
|
32005
|
-
index += 1;
|
|
32006
|
-
skipWhitespace();
|
|
32007
|
-
if (text[index] === "}") {
|
|
32008
|
-
index += 1;
|
|
32009
|
-
stack.pop();
|
|
32010
|
-
return;
|
|
32011
|
-
}
|
|
32012
|
-
for (; ; ) {
|
|
32013
|
-
skipWhitespace();
|
|
32014
|
-
if (text[index] !== '"') migrateFail("invalid_json", label, `expected object key at byte ${index}`);
|
|
32015
|
-
const key = parseString();
|
|
32016
|
-
if (key === "__proto__" || key === "constructor" || key === "prototype") {
|
|
32017
|
-
migrateFail("forbidden_key", label, `key ${JSON.stringify(key)} is forbidden`);
|
|
32018
|
-
}
|
|
32019
|
-
const frame = stack[stack.length - 1];
|
|
32020
|
-
if (frame instanceof Set) {
|
|
32021
|
-
if (frame.has(key)) migrateFail("duplicate_key", label, `duplicate key ${JSON.stringify(key)}`);
|
|
32022
|
-
frame.add(key);
|
|
32023
|
-
}
|
|
32024
|
-
skipWhitespace();
|
|
32025
|
-
if (text[index] !== ":") migrateFail("invalid_json", label, `expected ':' at byte ${index}`);
|
|
32026
|
-
index += 1;
|
|
32027
|
-
skipValue();
|
|
32028
|
-
skipWhitespace();
|
|
32029
|
-
if (text[index] === ",") {
|
|
32030
|
-
index += 1;
|
|
32031
|
-
continue;
|
|
32032
|
-
}
|
|
32033
|
-
if (text[index] === "}") {
|
|
32034
|
-
index += 1;
|
|
32035
|
-
stack.pop();
|
|
32036
|
-
return;
|
|
32037
|
-
}
|
|
32038
|
-
migrateFail("invalid_json", label, `expected ',' or '}' at byte ${index}`);
|
|
32039
|
-
}
|
|
32040
|
-
}
|
|
32041
|
-
if (char === "[") {
|
|
32042
|
-
stack.push("array");
|
|
32043
|
-
index += 1;
|
|
32044
|
-
skipWhitespace();
|
|
32045
|
-
if (text[index] === "]") {
|
|
32046
|
-
index += 1;
|
|
32047
|
-
stack.pop();
|
|
32048
|
-
return;
|
|
32049
|
-
}
|
|
32050
|
-
for (; ; ) {
|
|
32051
|
-
skipValue();
|
|
32052
|
-
skipWhitespace();
|
|
32053
|
-
if (text[index] === ",") {
|
|
32054
|
-
index += 1;
|
|
32055
|
-
continue;
|
|
32056
|
-
}
|
|
32057
|
-
if (text[index] === "]") {
|
|
32058
|
-
index += 1;
|
|
32059
|
-
stack.pop();
|
|
32060
|
-
return;
|
|
32061
|
-
}
|
|
32062
|
-
migrateFail("invalid_json", label, `expected ',' or ']' at byte ${index}`);
|
|
32063
|
-
}
|
|
32064
|
-
}
|
|
32065
|
-
};
|
|
32066
|
-
skipValue();
|
|
32067
|
-
skipWhitespace();
|
|
32068
|
-
if (index !== length) migrateFail("invalid_json", label, `trailing content at byte ${index}`);
|
|
32069
|
-
}
|
|
32070
|
-
function sha256Of(input) {
|
|
32071
|
-
return `sha256:${createHash13("sha256").update(input).digest("hex")}`;
|
|
32072
|
-
}
|
|
32073
|
-
function readKxmLegacySources(root) {
|
|
32074
|
-
const files = legacyConfigFilesAt(root);
|
|
32075
|
-
if (files.length > MAX_LEGACY_SOURCES) {
|
|
32076
|
-
throw new KxmConfigError([migrateIssue("discovery", "legacy_source_limit", ".kxm/config", `legacy configuration exceeds ${MAX_LEGACY_SOURCES} files`)]);
|
|
32077
|
-
}
|
|
32078
|
-
return files.map((path4) => {
|
|
32079
|
-
const absolute = join26(root, ...path4.split("/"));
|
|
32080
|
-
const stat = lstatSync8(absolute);
|
|
32081
|
-
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
32082
|
-
throw new KxmConfigError([migrateIssue("path", "legacy_source_invalid", path4, "legacy configuration must be a regular file, not a link")]);
|
|
32083
|
-
}
|
|
32084
|
-
const buffer = readFileSync22(absolute);
|
|
32085
|
-
let text;
|
|
32086
|
-
try {
|
|
32087
|
-
text = new TextDecoder("utf-8", { fatal: true }).decode(buffer);
|
|
32088
|
-
} catch {
|
|
32089
|
-
throw new KxmConfigError([migrateIssue("parse", "invalid_utf8", path4, "document is not valid UTF-8")]);
|
|
32090
|
-
}
|
|
32091
|
-
return {
|
|
32092
|
-
path: path4,
|
|
32093
|
-
sha256: sha256Of(buffer),
|
|
32094
|
-
bytes: buffer.byteLength,
|
|
32095
|
-
value: parseLegacyJson(text, path4)
|
|
32096
|
-
};
|
|
32097
|
-
});
|
|
32098
|
-
}
|
|
32099
|
-
function legacySourceDigest(sources) {
|
|
32100
|
-
return sha256Of(kxmCanonicalJson(sources.map((source) => ({ path: source.path, sha256: source.sha256, bytes: source.bytes }))));
|
|
32101
|
-
}
|
|
32102
|
-
var IDENTIFIER2 = /^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/;
|
|
32103
|
-
var KNOWN_AGENT_FIELDS = /* @__PURE__ */ new Set(["name", "kind", "driver", "model", "thinking", "purpose"]);
|
|
32104
|
-
var KNOWN_GATE_FIELDS = /* @__PURE__ */ new Set(["name", "kind", "driver", "purpose"]);
|
|
32105
|
-
var KNOWN_WORKFLOW_FIELDS = /* @__PURE__ */ new Set([
|
|
32106
|
-
"id",
|
|
32107
|
-
"source",
|
|
32108
|
-
"project",
|
|
32109
|
-
"target",
|
|
32110
|
-
"secret",
|
|
32111
|
-
"secretEnv",
|
|
32112
|
-
"signalSecret",
|
|
32113
|
-
"signalSecretEnv",
|
|
32114
|
-
"event",
|
|
32115
|
-
"filter",
|
|
32116
|
-
"delivery",
|
|
32117
|
-
"ttlMs",
|
|
32118
|
-
"promptTemplate",
|
|
32119
|
-
"stages",
|
|
32120
|
-
"maxTransitions",
|
|
32121
|
-
"reproOracle",
|
|
32122
|
-
"planHash",
|
|
32123
|
-
"requirePlanHash"
|
|
32124
|
-
]);
|
|
32125
|
-
var KNOWN_STAGE_FIELDS = /* @__PURE__ */ new Set(["id", "label", "instructions", "requiredEvidence", "maxAttempts", "area", "evidencePolicies", "on", "maxTransitions"]);
|
|
32126
|
-
var KNOWN_POLICY_FIELDS = /* @__PURE__ */ new Set(["kind", "minProducers", "eligibleAgents", "acceptedStatuses", "degradation"]);
|
|
32127
|
-
var KNOWN_TRANSITION_FIELDS = /* @__PURE__ */ new Set(["target", "maxTransitions"]);
|
|
32128
|
-
function compareCodeUnits6(left, right) {
|
|
32129
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
32130
|
-
}
|
|
32131
|
-
function asObject2(value) {
|
|
32132
|
-
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
32133
|
-
}
|
|
32134
|
-
function asString(value) {
|
|
32135
|
-
return typeof value === "string" ? value : void 0;
|
|
32136
|
-
}
|
|
32137
|
-
function normalizeIdentifier(raw) {
|
|
32138
|
-
return raw.toLocaleLowerCase("en-US").replace(/[^a-z0-9_-]+/g, "-").replace(/[-_]{2,}/g, "-").replace(/^[-_]+/, "").replace(/[-_]+$/, "").replace(/^(?=[0-9])/, "id-");
|
|
32139
|
-
}
|
|
32140
|
-
function pointerEscape2(segment) {
|
|
32141
|
-
const escaped = segment.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
32142
|
-
if (escaped.length <= 200) return escaped;
|
|
32143
|
-
const digest = createHash13("sha256").update(segment, "utf8").digest("hex").slice(0, 8);
|
|
32144
|
-
return `${escaped.slice(0, 180)}~digest-${digest}`;
|
|
32145
|
-
}
|
|
32146
|
-
function elide(raw, max = 120) {
|
|
32147
|
-
return raw.length <= max ? raw : `${raw.slice(0, max - 15)}\u2026[${raw.length}]`;
|
|
32148
|
-
}
|
|
32149
|
-
function keyFragment(raw) {
|
|
32150
|
-
const full = normalizeIdentifier(raw) || "unnamed";
|
|
32151
|
-
const normalized = full.length > 96 ? `${full.slice(0, 96)}-${full.length}` : full;
|
|
32152
|
-
const digest = createHash13("sha256").update(raw, "utf8").digest("hex").slice(0, 8);
|
|
32153
|
-
return `${normalized}-${digest}`;
|
|
32154
|
-
}
|
|
32155
|
-
function recordUnmapped(plan, sourcePath, pointer, value, sensitive) {
|
|
32156
|
-
const digestInput = sensitive ? { redacted: true, bytes: Buffer.byteLength(kxmCanonicalJson(value === void 0 ? null : value), "utf8") } : value === void 0 ? null : value;
|
|
32157
|
-
plan.unmapped.push({
|
|
32158
|
-
sourcePath,
|
|
32159
|
-
jsonPointer: pointer,
|
|
32160
|
-
valueSha256: sha256Of(kxmCanonicalJson(digestInput)),
|
|
32161
|
-
sensitive
|
|
32162
|
-
});
|
|
32163
|
-
}
|
|
32164
|
-
function recordUnknownFields(plan, sourcePath, pointer, record, known) {
|
|
32165
|
-
for (const key of Object.keys(record).sort(compareCodeUnits6)) {
|
|
32166
|
-
if (!known.has(key)) recordUnmapped(plan, sourcePath, `${pointer}/${pointerEscape2(key)}`, record[key], false);
|
|
32167
|
-
}
|
|
32168
|
-
}
|
|
32169
|
-
function mapIdentity(plan, sourcePath, raw, kind, taken, decisions, dropPointer, dropValue) {
|
|
32170
|
-
const normalized = normalizeIdentifier(raw);
|
|
32171
|
-
const usable = (candidate) => IDENTIFIER2.test(candidate) && candidate.length <= 64;
|
|
32172
|
-
const adopt = (candidate) => {
|
|
32173
|
-
const foldedCandidate = candidate.toLocaleLowerCase("en-US");
|
|
32174
|
-
const priorCandidate = taken.get(foldedCandidate);
|
|
32175
|
-
if (priorCandidate !== void 0 && priorCandidate !== raw) return { outcome: "taken" };
|
|
32176
|
-
if (priorCandidate === raw) return { outcome: "duplicate" };
|
|
32177
|
-
taken.set(foldedCandidate, raw);
|
|
32178
|
-
plan.renames.push({ from: elide(raw), to: candidate, kind });
|
|
32179
|
-
return { outcome: "adopted", id: candidate };
|
|
32180
|
-
};
|
|
32181
|
-
const reportDuplicate = () => {
|
|
32182
|
-
const decided = resolveDecision(
|
|
32183
|
-
plan,
|
|
32184
|
-
`identity-duplicate:${kind}:${keyFragment(raw)}`,
|
|
32185
|
-
"unsupported",
|
|
32186
|
-
sourcePath,
|
|
32187
|
-
`${kind} name ${JSON.stringify(elide(raw, 200))} is declared more than once; confirm the duplicate definition is dropped`,
|
|
32188
|
-
["drop"],
|
|
32189
|
-
decisions
|
|
32190
|
-
);
|
|
32191
|
-
recordUnmapped(plan, sourcePath, dropPointer ?? `/duplicates/${pointerEscape2(raw)}`, dropValue ?? raw, false);
|
|
32192
|
-
return decided === "drop" ? { status: "dropped" } : { status: "pending" };
|
|
32193
|
-
};
|
|
32194
|
-
if (!normalized || !usable(normalized)) {
|
|
32195
|
-
const supplied = resolveDecision(
|
|
32196
|
-
plan,
|
|
32197
|
-
`identity:${kind}:${keyFragment(raw)}`,
|
|
32198
|
-
"identity",
|
|
32199
|
-
sourcePath,
|
|
32200
|
-
`${kind} name ${JSON.stringify(elide(raw, 200))} cannot be normalized to a KXM identifier; supply a decision with the target identifier`,
|
|
32201
|
-
["<identifier>"],
|
|
32202
|
-
decisions
|
|
32203
|
-
);
|
|
32204
|
-
if (typeof supplied === "string" && usable(supplied)) {
|
|
32205
|
-
const adopted = adopt(supplied);
|
|
32206
|
-
if (adopted.outcome === "adopted") return { status: "adopted", id: adopted.id };
|
|
32207
|
-
if (adopted.outcome === "duplicate") return reportDuplicate();
|
|
32208
|
-
plan.ambiguities.push({
|
|
32209
|
-
key: `identity:${kind}:${keyFragment(raw)}`,
|
|
32210
|
-
category: "identity",
|
|
32211
|
-
sourcePath,
|
|
32212
|
-
message: `decision-supplied identifier ${JSON.stringify(elide(supplied, 200))} for ${kind} ${JSON.stringify(elide(raw, 200))} collides with another migrated identity`,
|
|
32213
|
-
allowedValues: ["<identifier>"]
|
|
32214
|
-
});
|
|
32215
|
-
}
|
|
32216
|
-
return { status: "pending" };
|
|
32217
|
-
}
|
|
32218
|
-
const folded = normalized.toLocaleLowerCase("en-US");
|
|
32219
|
-
const prior = taken.get(folded);
|
|
32220
|
-
if (prior && prior !== raw) {
|
|
32221
|
-
const supplied = resolveDecision(
|
|
32222
|
-
plan,
|
|
32223
|
-
`identity-collision:${kind}:${folded}-${keyFragment(raw)}`,
|
|
32224
|
-
"identity",
|
|
32225
|
-
sourcePath,
|
|
32226
|
-
`${kind} names ${JSON.stringify(elide(prior, 200))} and ${JSON.stringify(elide(raw, 200))} collide after normalization; supply a distinct identifier for ${JSON.stringify(elide(raw, 200))}`,
|
|
32227
|
-
["<identifier>"],
|
|
32228
|
-
decisions
|
|
32229
|
-
);
|
|
32230
|
-
if (typeof supplied === "string" && usable(supplied)) {
|
|
32231
|
-
const adopted = adopt(supplied);
|
|
32232
|
-
if (adopted.outcome === "adopted") return { status: "adopted", id: adopted.id };
|
|
32233
|
-
if (adopted.outcome === "duplicate") return reportDuplicate();
|
|
32234
|
-
plan.ambiguities.push({
|
|
32235
|
-
key: `identity-collision:${kind}:${folded}-${keyFragment(raw)}`,
|
|
32236
|
-
category: "identity",
|
|
32237
|
-
sourcePath,
|
|
32238
|
-
message: `decision-supplied identifier ${JSON.stringify(elide(supplied, 200))} for ${kind} ${JSON.stringify(elide(raw, 200))} collides with another migrated identity`,
|
|
32239
|
-
allowedValues: ["<identifier>"]
|
|
32240
|
-
});
|
|
32241
|
-
}
|
|
32242
|
-
return { status: "pending" };
|
|
32243
|
-
}
|
|
32244
|
-
if (prior === raw) return reportDuplicate();
|
|
32245
|
-
taken.set(folded, raw);
|
|
32246
|
-
if (normalized !== raw && !plan.renames.some((rename) => rename.kind === kind && rename.from === raw)) {
|
|
32247
|
-
plan.renames.push({ from: elide(raw), to: normalized, kind });
|
|
32248
|
-
}
|
|
32249
|
-
return { status: "adopted", id: normalized };
|
|
32250
|
-
}
|
|
32251
|
-
function decisionValueAllowed(key, value, allowed) {
|
|
32252
|
-
if (value === void 0) return false;
|
|
32253
|
-
if (allowed.some((candidate) => candidate === "<identifier>")) {
|
|
32254
|
-
return typeof value === "string" && IDENTIFIER2.test(value) && value.length <= 64;
|
|
32255
|
-
}
|
|
32256
|
-
if (allowed.some((candidate) => candidate === "<provider/model>")) {
|
|
32257
|
-
if (typeof value !== "string") return false;
|
|
32258
|
-
const separator = value.indexOf("/");
|
|
32259
|
-
const provider = separator > 0 ? normalizeIdentifier(value.slice(0, separator)) : "";
|
|
32260
|
-
const modelId2 = separator > 0 ? value.slice(separator + 1) : "";
|
|
32261
|
-
return IDENTIFIER2.test(provider) && provider.length <= 64 && modelId2.length >= 1 && modelId2.length <= 200;
|
|
32262
|
-
}
|
|
32263
|
-
if (key.startsWith("backedge:")) {
|
|
32264
|
-
return typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= 100;
|
|
32265
|
-
}
|
|
32266
|
-
if (key.startsWith("budget:")) {
|
|
32267
|
-
return typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= 1e3;
|
|
32268
|
-
}
|
|
32269
|
-
if (key.startsWith("coordinator:") || key.startsWith("producer:")) {
|
|
32270
|
-
if (allowed.some((candidate) => candidate === value)) return true;
|
|
32271
|
-
return allowed.length >= 64 && typeof value === "string" && IDENTIFIER2.test(value) && value.length <= 64;
|
|
32272
|
-
}
|
|
32273
|
-
return allowed.some((candidate) => candidate === value);
|
|
32274
|
-
}
|
|
32275
|
-
function resolveDecision(plan, key, category, sourcePath, message, allowedValues, decisions) {
|
|
32276
|
-
plan.decisionKeys.add(key);
|
|
32277
|
-
plan.decisionAllowedValues.set(key, allowedValues);
|
|
32278
|
-
if (Object.hasOwn(decisions, key)) {
|
|
32279
|
-
const value = decisions[key];
|
|
32280
|
-
if (decisionValueAllowed(key, value, allowedValues)) return value;
|
|
32281
|
-
if (!plan.invalidDecisions.includes(key)) plan.invalidDecisions.push(key);
|
|
32282
|
-
}
|
|
32283
|
-
if (!plan.ambiguities.some((ambiguity) => ambiguity.key === key)) {
|
|
32284
|
-
plan.ambiguities.push({ key, category, sourcePath, message, allowedValues });
|
|
32285
|
-
}
|
|
32286
|
-
return void 0;
|
|
32287
|
-
}
|
|
32288
|
-
function convertAgentsRoster(plan, source, decisions, agentNames) {
|
|
32289
|
-
const agents = /* @__PURE__ */ new Map();
|
|
32290
|
-
const models = /* @__PURE__ */ new Map();
|
|
32291
|
-
const rawNames = /* @__PURE__ */ new Map();
|
|
32292
|
-
const pendingRawNames = /* @__PURE__ */ new Set();
|
|
32293
|
-
const modelNames = /* @__PURE__ */ new Map();
|
|
32294
|
-
let identityPending = false;
|
|
32295
|
-
const root = asObject2(source.value);
|
|
32296
|
-
if (!root) {
|
|
32297
|
-
resolveDecision(
|
|
32298
|
-
plan,
|
|
32299
|
-
`unsupported:${source.path}:/`,
|
|
32300
|
-
"unsupported",
|
|
32301
|
-
source.path,
|
|
32302
|
-
"agents.json must be a JSON object with an agents array; confirm it is dropped from conversion",
|
|
32303
|
-
["drop"],
|
|
32304
|
-
decisions
|
|
32305
|
-
);
|
|
32306
|
-
return { agents, models, rawNames, pendingRawNames, identityPending };
|
|
32307
|
-
}
|
|
32308
|
-
recordUnknownFields(plan, source.path, "", root, /* @__PURE__ */ new Set(["schema", "project", "host", "agents", "ownership"]));
|
|
32309
|
-
if (root.ownership !== void 0) recordUnmapped(plan, source.path, "/ownership", root.ownership, false);
|
|
32310
|
-
if (root.host !== void 0) recordUnmapped(plan, source.path, "/host", root.host, false);
|
|
32311
|
-
if (root.project !== void 0) recordUnmapped(plan, source.path, "/project", root.project, false);
|
|
32312
|
-
if (root.schema !== void 0 && root.schema !== "kxm.agents.v1") recordUnmapped(plan, source.path, "/schema", root.schema, false);
|
|
32313
|
-
const list = Array.isArray(root.agents) ? root.agents : [];
|
|
32314
|
-
for (const [index, entry] of list.entries()) {
|
|
32315
|
-
const pointer = `/agents/${index}`;
|
|
32316
|
-
const record = asObject2(entry);
|
|
32317
|
-
if (!record) {
|
|
32318
|
-
recordUnmapped(plan, source.path, pointer, entry, false);
|
|
32319
|
-
continue;
|
|
32320
|
-
}
|
|
32321
|
-
recordUnknownFields(plan, source.path, pointer, record, KNOWN_AGENT_FIELDS);
|
|
32322
|
-
const name = asString(record.name);
|
|
32323
|
-
const kind = asString(record.kind) ?? "agent";
|
|
32324
|
-
const driver = asString(record.driver) ?? "ai";
|
|
32325
|
-
if (!name || kind !== "agent" || driver !== "ai") {
|
|
32326
|
-
resolveDecision(
|
|
32327
|
-
plan,
|
|
32328
|
-
`unsupported:${source.path}:${pointer}`,
|
|
32329
|
-
"unsupported",
|
|
32330
|
-
source.path,
|
|
32331
|
-
`roster entry ${index} (${name === void 0 ? "unnamed" : elide(name, 200)}) has kind ${elide(kind, 64)}/driver ${elide(driver, 64)}; only agent/ai entries convert losslessly \u2014 confirm the entry is dropped`,
|
|
32332
|
-
["drop"],
|
|
32333
|
-
decisions
|
|
32334
|
-
);
|
|
32335
|
-
recordUnmapped(plan, source.path, pointer, record, false);
|
|
32336
|
-
continue;
|
|
32337
|
-
}
|
|
32338
|
-
resolveDecision(
|
|
32339
|
-
plan,
|
|
32340
|
-
`permission:${keyFragment(name)}`,
|
|
32341
|
-
"permission",
|
|
32342
|
-
source.path,
|
|
32343
|
-
`approve the narrowed tool/repository/network ceiling for agent ${elide(name, 200)}`,
|
|
32344
|
-
["approve"],
|
|
32345
|
-
decisions
|
|
32346
|
-
);
|
|
32347
|
-
const agentIdentity = mapIdentity(plan, source.path, name, "agent", agentNames, decisions, pointer, record);
|
|
32348
|
-
if (agentIdentity.status === "pending") {
|
|
32349
|
-
identityPending = true;
|
|
32350
|
-
pendingRawNames.add(name);
|
|
32351
|
-
}
|
|
32352
|
-
if (agentIdentity.status !== "adopted") continue;
|
|
32353
|
-
const id = agentIdentity.id;
|
|
32354
|
-
const agent = {
|
|
32355
|
-
schema: "kxm.agent.v1",
|
|
32356
|
-
purpose: asString(record.purpose) ?? `Migrated legacy agent ${elide(name, 200)}.`
|
|
32357
|
-
};
|
|
32358
|
-
const model = asString(record.model);
|
|
32359
|
-
if (model) {
|
|
32360
|
-
const applyModel = (candidate) => {
|
|
32361
|
-
const separator = candidate.indexOf("/");
|
|
32362
|
-
if (separator <= 0) return false;
|
|
32363
|
-
const provider = normalizeIdentifier(candidate.slice(0, separator));
|
|
32364
|
-
const modelId2 = candidate.slice(separator + 1);
|
|
32365
|
-
if (IDENTIFIER2.test(provider) && provider.length <= 64 && modelId2.length >= 1 && modelId2.length <= 200) {
|
|
32366
|
-
agent.model = { provider, model: modelId2 };
|
|
32367
|
-
return true;
|
|
32368
|
-
}
|
|
32369
|
-
return false;
|
|
32370
|
-
};
|
|
32371
|
-
if (!applyModel(model)) {
|
|
32372
|
-
const supplied = resolveDecision(
|
|
32373
|
-
plan,
|
|
32374
|
-
`model:${keyFragment(name)}`,
|
|
32375
|
-
"identity",
|
|
32376
|
-
source.path,
|
|
32377
|
-
`agent ${elide(name, 200)} model ${JSON.stringify(elide(model, 200))} does not map to a provider identifier + model id pair; supply <provider>/<model>`,
|
|
32378
|
-
["<provider/model>"],
|
|
32379
|
-
decisions
|
|
32380
|
-
);
|
|
32381
|
-
if (typeof supplied === "string" && supplied !== model) {
|
|
32382
|
-
applyModel(supplied);
|
|
32383
|
-
} else if (typeof supplied !== "string") {
|
|
32384
|
-
recordUnmapped(plan, source.path, `${pointer}/model`, model, false);
|
|
32385
|
-
}
|
|
32386
|
-
}
|
|
32387
|
-
}
|
|
32388
|
-
const thinking = asString(record.thinking);
|
|
32389
|
-
if (thinking) {
|
|
32390
|
-
const selector = asObject2(agent.model);
|
|
32391
|
-
if (selector && typeof selector.profile !== "string") {
|
|
32392
|
-
const profileIdentity = mapIdentity(plan, source.path, `${id}-primary`, "model", modelNames, decisions);
|
|
32393
|
-
const profileId = profileIdentity.status === "adopted" ? profileIdentity.id : void 0;
|
|
32394
|
-
if (profileId) {
|
|
32395
|
-
const profile = {
|
|
32396
|
-
schema: "kxm.model.v1",
|
|
32397
|
-
provider: selector.provider,
|
|
32398
|
-
model: selector.model,
|
|
32399
|
-
thinking
|
|
32400
|
-
};
|
|
32401
|
-
models.set(profileId, profile);
|
|
32402
|
-
agent.model = { profile: profileId };
|
|
32403
|
-
}
|
|
32404
|
-
} else {
|
|
32405
|
-
recordUnmapped(plan, source.path, `${pointer}/thinking`, thinking, false);
|
|
32406
|
-
}
|
|
32407
|
-
}
|
|
32408
|
-
agent.tools = { preset: "workspace-writer" };
|
|
32409
|
-
agent.defaultRepositoryAccess = "none";
|
|
32410
|
-
agent.network = "provider-only";
|
|
32411
|
-
plan.permissionChanges.push({
|
|
32412
|
-
sourcePath: source.path,
|
|
32413
|
-
targetPath: `.kxm/agents/${id}.yaml`,
|
|
32414
|
-
direction: "unknown",
|
|
32415
|
-
summary: `agent ${elide(name, 200)}: legacy workers used launch-time tool flags the converter cannot observe; migrated ceiling is workspace-writer tools, no repository access, provider-only network`,
|
|
32416
|
-
decisionKey: `permission:${keyFragment(name)}`
|
|
32417
|
-
});
|
|
32418
|
-
agents.set(id, agent);
|
|
32419
|
-
if (!rawNames.has(name)) rawNames.set(name, id);
|
|
32420
|
-
}
|
|
32421
|
-
return { agents, models, rawNames, pendingRawNames, identityPending };
|
|
32422
|
-
}
|
|
32423
|
-
var IMPLEMENTED_GATES = /* @__PURE__ */ new Set(["test", "scm-delivery"]);
|
|
32424
|
-
function convertGatesRoster(plan, source, decisions) {
|
|
32425
|
-
const root = asObject2(source.value);
|
|
32426
|
-
if (!root) {
|
|
32427
|
-
resolveDecision(
|
|
32428
|
-
plan,
|
|
32429
|
-
`unsupported:${source.path}:/`,
|
|
32430
|
-
"unsupported",
|
|
32431
|
-
source.path,
|
|
32432
|
-
"gates.json must be a JSON object with a gates array; confirm it is dropped from conversion",
|
|
32433
|
-
["drop"],
|
|
32434
|
-
decisions
|
|
32435
|
-
);
|
|
32436
|
-
return;
|
|
32437
|
-
}
|
|
32438
|
-
recordUnknownFields(plan, source.path, "", root, /* @__PURE__ */ new Set(["schema", "gates"]));
|
|
32439
|
-
if (root.schema !== void 0 && root.schema !== "kxm.gates.v1") recordUnmapped(plan, source.path, "/schema", root.schema, false);
|
|
32440
|
-
const list = Array.isArray(root.gates) ? root.gates : [];
|
|
32441
|
-
for (const [index, entry] of list.entries()) {
|
|
32442
|
-
const pointer = `/gates/${index}`;
|
|
32443
|
-
const record = asObject2(entry);
|
|
32444
|
-
if (!record) {
|
|
32445
|
-
recordUnmapped(plan, source.path, pointer, entry, false);
|
|
32446
|
-
continue;
|
|
32447
|
-
}
|
|
32448
|
-
recordUnknownFields(plan, source.path, pointer, record, KNOWN_GATE_FIELDS);
|
|
32449
|
-
const name = asString(record.name) ?? `gate-${index}`;
|
|
32450
|
-
if (!IMPLEMENTED_GATES.has(name)) {
|
|
32451
|
-
resolveDecision(
|
|
32452
|
-
plan,
|
|
32453
|
-
`gate:${keyFragment(name)}`,
|
|
32454
|
-
"unsupported",
|
|
32455
|
-
source.path,
|
|
32456
|
-
`gate ${JSON.stringify(elide(name, 200))} has no registered deterministic runner in KXM; it is preserved in the migration report only`,
|
|
32457
|
-
["report-only"],
|
|
32458
|
-
decisions
|
|
32459
|
-
);
|
|
32460
|
-
recordUnmapped(plan, source.path, pointer, entry, false);
|
|
32461
|
-
}
|
|
32462
|
-
}
|
|
32463
|
-
}
|
|
32464
|
-
function mapStageRef(context, raw) {
|
|
32465
|
-
return context.renamesByKind.get(raw) ?? normalizeIdentifier(raw);
|
|
32466
|
-
}
|
|
32467
|
-
function convertTransition(plan, source, context, stageId, stageKey, outcome, rawOutcome, rawValue, decisions, stagePointer) {
|
|
32468
|
-
const pointer = `${stagePointer}/on/${pointerEscape2(rawOutcome)}`;
|
|
32469
|
-
const rule = typeof rawValue === "string" ? { target: rawValue } : asObject2(rawValue);
|
|
32470
|
-
if (!rule) {
|
|
32471
|
-
recordUnmapped(plan, source.path, pointer, rawValue, false);
|
|
32472
|
-
return void 0;
|
|
32473
|
-
}
|
|
32474
|
-
if (typeof rawValue !== "string") recordUnknownFields(plan, source.path, pointer, rule, KNOWN_TRANSITION_FIELDS);
|
|
32475
|
-
const target = asString(rule.target);
|
|
32476
|
-
if (!target) {
|
|
32477
|
-
recordUnmapped(plan, source.path, pointer, rawValue, false);
|
|
32478
|
-
return void 0;
|
|
32479
|
-
}
|
|
32480
|
-
const sourceIndex = context.stageIds.indexOf(stageId);
|
|
32481
|
-
if (target === "$terminal") {
|
|
32482
|
-
const chosen = resolveDecision(
|
|
32483
|
-
plan,
|
|
32484
|
-
`terminal:${context.workflowKey}:${stageKey}:${outcome}`,
|
|
32485
|
-
"terminal-status",
|
|
32486
|
-
source.path,
|
|
32487
|
-
`legacy transition ${context.workflowId}/${stageId} outcome ${outcome} ends the run; choose the KXM terminal status (legacy semantics completed the run even on failure outcomes)`,
|
|
32488
|
-
outcome === "passed" ? ["completed"] : ["completed", "failed", "cancelled"],
|
|
32489
|
-
decisions
|
|
32490
|
-
);
|
|
32491
|
-
const status = typeof chosen === "string" && ["completed", "failed", "cancelled"].includes(chosen) ? chosen : "completed";
|
|
32492
|
-
const objectRule2 = asObject2(rawValue);
|
|
32493
|
-
const result = { target: "$terminal", terminalStatus: status };
|
|
32494
|
-
if (typeof objectRule2?.maxTransitions === "number") {
|
|
32495
|
-
if (Number.isInteger(objectRule2.maxTransitions) && objectRule2.maxTransitions >= 1 && objectRule2.maxTransitions <= 100) {
|
|
32496
|
-
result.maxTransitions = objectRule2.maxTransitions;
|
|
32497
|
-
} else {
|
|
32498
|
-
recordUnmapped(plan, source.path, `${pointer}/maxTransitions`, objectRule2.maxTransitions, false);
|
|
32499
|
-
}
|
|
32500
|
-
}
|
|
32501
|
-
return result;
|
|
32502
|
-
}
|
|
32503
|
-
const targetId = mapStageRef(context, target);
|
|
32504
|
-
const targetIndex = context.stageIds.indexOf(targetId);
|
|
32505
|
-
if (targetIndex < 0) {
|
|
32506
|
-
resolveDecision(
|
|
32507
|
-
plan,
|
|
32508
|
-
`transition-target:${context.workflowKey}:${stageKey}:${outcome}`,
|
|
32509
|
-
"identity",
|
|
32510
|
-
source.path,
|
|
32511
|
-
`transition target ${JSON.stringify(elide(target, 200))} is not a stage of workflow ${context.workflowId}; confirm the edge is dropped`,
|
|
32512
|
-
["drop"],
|
|
32513
|
-
decisions
|
|
32514
|
-
);
|
|
32515
|
-
recordUnmapped(plan, source.path, pointer, rawValue, false);
|
|
32516
|
-
return void 0;
|
|
32517
|
-
}
|
|
32518
|
-
const objectRule = asObject2(rawValue);
|
|
32519
|
-
let explicitBudget;
|
|
32520
|
-
if (typeof objectRule?.maxTransitions === "number") {
|
|
32521
|
-
if (Number.isInteger(objectRule.maxTransitions) && objectRule.maxTransitions >= 1 && objectRule.maxTransitions <= 100) {
|
|
32522
|
-
explicitBudget = objectRule.maxTransitions;
|
|
32523
|
-
} else {
|
|
32524
|
-
recordUnmapped(plan, source.path, `${pointer}/maxTransitions`, objectRule.maxTransitions, false);
|
|
32525
|
-
}
|
|
32526
|
-
}
|
|
32527
|
-
const isBackEdge = targetIndex <= sourceIndex;
|
|
32528
|
-
if (isBackEdge && explicitBudget === void 0) {
|
|
32529
|
-
const chosen = resolveDecision(
|
|
32530
|
-
plan,
|
|
32531
|
-
`backedge:${context.workflowKey}:${stageKey}:${outcome}`,
|
|
32532
|
-
"transition-budget",
|
|
32533
|
-
source.path,
|
|
32534
|
-
`back-edge ${context.workflowId}/${stageId} -> ${targetId} (outcome ${outcome}) has no per-edge budget in legacy; KXM requires maxTransitions (1-100)`,
|
|
32535
|
-
[2, 3, 4, 5],
|
|
32536
|
-
decisions
|
|
32537
|
-
);
|
|
32538
|
-
const budget = typeof chosen === "number" && Number.isInteger(chosen) && chosen >= 1 && chosen <= 100 ? chosen : 2;
|
|
32539
|
-
return { target: targetId, maxTransitions: budget };
|
|
32540
|
-
}
|
|
32541
|
-
if (explicitBudget !== void 0) return { target: targetId, maxTransitions: explicitBudget };
|
|
32542
|
-
return targetId;
|
|
32543
|
-
}
|
|
32544
|
-
function convertWorkflowFile(plan, source, decisions, agentIds, agentRawNames, pendingAgentRawNames, rosterIdentityPending, workflowNames) {
|
|
32545
|
-
const workflows = /* @__PURE__ */ new Map();
|
|
32546
|
-
const list = Array.isArray(source.value) ? source.value : [source.value];
|
|
32547
|
-
for (const [definitionIndex, entry] of list.entries()) {
|
|
32548
|
-
const definition = asObject2(entry);
|
|
32549
|
-
const basePointer = Array.isArray(source.value) ? `/${definitionIndex}` : "";
|
|
32550
|
-
if (!definition) {
|
|
32551
|
-
recordUnmapped(plan, source.path, basePointer || "/", entry, false);
|
|
32552
|
-
continue;
|
|
32553
|
-
}
|
|
32554
|
-
recordUnknownFields(plan, source.path, basePointer, definition, KNOWN_WORKFLOW_FIELDS);
|
|
32555
|
-
const fileStem = source.path.slice(source.path.lastIndexOf("/") + 1).replace(/\.json$/u, "");
|
|
32556
|
-
const rawId = asString(definition.id) ?? `${fileStem}-${definitionIndex}`;
|
|
32557
|
-
const workflowIdentity = mapIdentity(plan, source.path, rawId, "workflow", workflowNames, decisions, basePointer || "/", definition);
|
|
32558
|
-
if (workflowIdentity.status === "dropped") continue;
|
|
32559
|
-
const workflowId = workflowIdentity.status === "adopted" ? workflowIdentity.id : `preview-${(normalizeIdentifier(rawId) || "unnamed").slice(0, 46).replace(/[-_]+$/u, "")}-${createHash13("sha256").update(`${rawId}#${source.path}#${definitionIndex}`, "utf8").digest("hex").slice(0, 8)}`;
|
|
32560
|
-
const workflowKey = keyFragment(rawId);
|
|
32561
|
-
for (const field of ["source", "project", "event", "filter", "delivery", "ttlMs", "promptTemplate"]) {
|
|
32562
|
-
if (definition[field] !== void 0) recordUnmapped(plan, source.path, `${basePointer}/${field}`, definition[field], false);
|
|
32563
|
-
}
|
|
32564
|
-
for (const field of ["secret", "signalSecret", "secretEnv", "signalSecretEnv"]) {
|
|
32565
|
-
if (definition[field] !== void 0) {
|
|
32566
|
-
recordUnmapped(plan, source.path, `${basePointer}/${field}`, definition[field], true);
|
|
32567
|
-
resolveDecision(
|
|
32568
|
-
plan,
|
|
32569
|
-
`secret:${workflowKey}:${field}`,
|
|
32570
|
-
"secret-reference",
|
|
32571
|
-
source.path,
|
|
32572
|
-
`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`,
|
|
32573
|
-
["drop"],
|
|
32574
|
-
decisions
|
|
32575
|
-
);
|
|
32576
|
-
}
|
|
32577
|
-
}
|
|
32578
|
-
const rawTarget = asString(definition.target);
|
|
32579
|
-
const normalizedTarget = rawTarget ? normalizeIdentifier(rawTarget) : void 0;
|
|
32580
|
-
let stepAgent = rawTarget !== void 0 ? agentRawNames.get(rawTarget) : void 0;
|
|
32581
|
-
if (!stepAgent && rawTarget !== void 0 && pendingAgentRawNames.has(rawTarget)) {
|
|
32582
|
-
stepAgent = void 0;
|
|
32583
|
-
} else if (!stepAgent && rawTarget !== void 0) {
|
|
32584
|
-
const foldedTarget = rawTarget.toLocaleLowerCase("en-US");
|
|
32585
|
-
for (const [rawName, id] of agentRawNames) {
|
|
32586
|
-
if (rawName.toLocaleLowerCase("en-US") === foldedTarget) {
|
|
32587
|
-
stepAgent = id;
|
|
32588
|
-
break;
|
|
32589
|
-
}
|
|
32590
|
-
}
|
|
32591
|
-
}
|
|
32592
|
-
if (!stepAgent && agentRawNames.size === 0 && normalizedTarget && agentIds.has(normalizedTarget)) {
|
|
32593
|
-
stepAgent = normalizedTarget;
|
|
32594
|
-
}
|
|
32595
|
-
const targetIsPendingAgent = rawTarget !== void 0 && [...pendingAgentRawNames].some((pending) => pending === rawTarget || pending.toLocaleLowerCase("en-US") === rawTarget.toLocaleLowerCase("en-US"));
|
|
32596
|
-
if (!stepAgent && targetIsPendingAgent) {
|
|
32597
|
-
stepAgent = normalizedTarget && IDENTIFIER2.test(normalizedTarget) && normalizedTarget.length <= 64 ? normalizedTarget : "coordinator";
|
|
32598
|
-
}
|
|
32599
|
-
if (!stepAgent) {
|
|
32600
|
-
if (agentIds.size === 0 && rosterIdentityPending) {
|
|
32601
|
-
stepAgent = normalizedTarget && IDENTIFIER2.test(normalizedTarget) && normalizedTarget.length <= 64 ? normalizedTarget : "coordinator";
|
|
32602
|
-
} else if (agentIds.size === 0) {
|
|
32603
|
-
const dropped = resolveDecision(
|
|
32604
|
-
plan,
|
|
32605
|
-
`coordinator:${workflowKey}`,
|
|
32606
|
-
"identity",
|
|
32607
|
-
source.path,
|
|
32608
|
-
`workflow ${workflowId} target ${JSON.stringify(rawTarget === void 0 ? "" : elide(rawTarget, 200))} matches no migrated agent and the roster is empty; confirm the workflow is dropped`,
|
|
32609
|
-
["drop"],
|
|
32610
|
-
decisions
|
|
32611
|
-
);
|
|
32612
|
-
if (dropped === "drop") continue;
|
|
32613
|
-
stepAgent = normalizedTarget && IDENTIFIER2.test(normalizedTarget) && normalizedTarget.length <= 64 ? normalizedTarget : "coordinator";
|
|
32614
|
-
} else {
|
|
32615
|
-
const chosen = resolveDecision(
|
|
32616
|
-
plan,
|
|
32617
|
-
`coordinator:${workflowKey}`,
|
|
32618
|
-
"identity",
|
|
32619
|
-
source.path,
|
|
32620
|
-
`workflow ${workflowId} target ${JSON.stringify(rawTarget === void 0 ? "" : elide(rawTarget, 200))} is not a migrated agent; choose the roster agent that executes its steps`,
|
|
32621
|
-
[...agentIds.keys()].sort(compareCodeUnits6).slice(0, 64),
|
|
32622
|
-
decisions
|
|
32623
|
-
);
|
|
32624
|
-
if (typeof chosen === "string" && agentIds.has(chosen)) {
|
|
32625
|
-
stepAgent = chosen;
|
|
32626
|
-
if (rawTarget) plan.renames.push({ from: elide(rawTarget), to: chosen, kind: "agent" });
|
|
32627
|
-
} else {
|
|
32628
|
-
if (chosen !== void 0 && !plan.invalidDecisions.includes(`coordinator:${workflowKey}`)) {
|
|
32629
|
-
plan.invalidDecisions.push(`coordinator:${workflowKey}`);
|
|
32630
|
-
}
|
|
32631
|
-
if (chosen !== void 0 && !plan.ambiguities.some((ambiguity) => ambiguity.key === `coordinator:${workflowKey}`)) {
|
|
32632
|
-
plan.ambiguities.push({
|
|
32633
|
-
key: `coordinator:${workflowKey}`,
|
|
32634
|
-
category: "identity",
|
|
32635
|
-
sourcePath: source.path,
|
|
32636
|
-
message: `decision value ${JSON.stringify(typeof chosen === "string" ? elide(chosen, 200) : chosen)} for workflow ${workflowId} is not a migrated agent`,
|
|
32637
|
-
allowedValues: [...agentIds.keys()].sort(compareCodeUnits6).slice(0, 64)
|
|
32638
|
-
});
|
|
32639
|
-
}
|
|
32640
|
-
stepAgent = normalizedTarget && IDENTIFIER2.test(normalizedTarget) && normalizedTarget.length <= 64 ? normalizedTarget : "coordinator";
|
|
32641
|
-
}
|
|
32642
|
-
}
|
|
32643
|
-
}
|
|
32644
|
-
const rawStages = Array.isArray(definition.stages) ? definition.stages : [];
|
|
32645
|
-
const stageIds = [];
|
|
32646
|
-
const stageRename = /* @__PURE__ */ new Map();
|
|
32647
|
-
const stepIdByIndex = /* @__PURE__ */ new Map();
|
|
32648
|
-
const stageKeyByRaw = /* @__PURE__ */ new Map();
|
|
32649
|
-
const droppedStageIndexes = /* @__PURE__ */ new Set();
|
|
32650
|
-
const takenSteps = /* @__PURE__ */ new Map();
|
|
32651
|
-
for (const [stageIndex, stageEntry] of rawStages.entries()) {
|
|
32652
|
-
const stage = asObject2(stageEntry);
|
|
32653
|
-
if (!stage) {
|
|
32654
|
-
recordUnmapped(plan, source.path, `${basePointer}/stages/${stageIndex}`, stageEntry, false);
|
|
32655
|
-
droppedStageIndexes.add(stageIndex);
|
|
32656
|
-
continue;
|
|
32657
|
-
}
|
|
32658
|
-
const rawStageId = asString(stage.id);
|
|
32659
|
-
if (!rawStageId) {
|
|
32660
|
-
recordUnmapped(plan, source.path, `${basePointer}/stages/${stageIndex}`, stage, false);
|
|
32661
|
-
droppedStageIndexes.add(stageIndex);
|
|
32662
|
-
continue;
|
|
32663
|
-
}
|
|
32664
|
-
const stepIdentity = mapIdentity(plan, source.path, rawStageId, "step", takenSteps, decisions, `${basePointer}/stages/${stageIndex}`, stage);
|
|
32665
|
-
if (stepIdentity.status === "dropped") {
|
|
32666
|
-
droppedStageIndexes.add(stageIndex);
|
|
32667
|
-
continue;
|
|
32668
|
-
}
|
|
32669
|
-
const stepId = stepIdentity.status === "adopted" ? stepIdentity.id : `preview-${(normalizeIdentifier(rawStageId) || "unnamed").slice(0, 46).replace(/[-_]+$/u, "")}-${createHash13("sha256").update(`${rawStageId}#${stageIndex}`, "utf8").digest("hex").slice(0, 8)}`;
|
|
32670
|
-
const stepKey = keyFragment(rawStageId);
|
|
32671
|
-
stageKeyByRaw.set(rawStageId, stepKey);
|
|
32672
|
-
if (!asString(stage.instructions)) {
|
|
32673
|
-
resolveDecision(
|
|
32674
|
-
plan,
|
|
32675
|
-
`instructions:${workflowKey}:${stepKey}`,
|
|
32676
|
-
"unsupported",
|
|
32677
|
-
source.path,
|
|
32678
|
-
`stage ${stepId} has no instructions; KXM agent steps require executable instructions \u2014 confirm the stage is dropped`,
|
|
32679
|
-
["drop"],
|
|
32680
|
-
decisions
|
|
32681
|
-
);
|
|
32682
|
-
recordUnmapped(plan, source.path, `${basePointer}/stages/${stageIndex}`, stage, false);
|
|
32683
|
-
droppedStageIndexes.add(stageIndex);
|
|
32684
|
-
continue;
|
|
32685
|
-
}
|
|
32686
|
-
if (!stageRename.has(rawStageId)) stageRename.set(rawStageId, stepId);
|
|
32687
|
-
stepIdByIndex.set(stageIndex, stepId);
|
|
32688
|
-
stageIds.push(stepId);
|
|
32689
|
-
}
|
|
32690
|
-
const context = { workflowId, workflowKey, stageIds, renamesByKind: stageRename };
|
|
32691
|
-
const steps = [];
|
|
32692
|
-
for (const [stageIndex, stageEntry] of rawStages.entries()) {
|
|
32693
|
-
if (droppedStageIndexes.has(stageIndex)) continue;
|
|
32694
|
-
const stage = asObject2(stageEntry);
|
|
32695
|
-
if (!stage) continue;
|
|
32696
|
-
const rawStageId = asString(stage.id);
|
|
32697
|
-
if (!rawStageId) continue;
|
|
32698
|
-
const stepId = stepIdByIndex.get(stageIndex);
|
|
32699
|
-
if (!stepId) continue;
|
|
32700
|
-
const stepKey = stageKeyByRaw.get(rawStageId) ?? keyFragment(rawStageId);
|
|
32701
|
-
const pointer = `${basePointer}/stages/${stageIndex}`;
|
|
32702
|
-
recordUnknownFields(plan, source.path, pointer, stage, KNOWN_STAGE_FIELDS);
|
|
32703
|
-
const label = asString(stage.label);
|
|
32704
|
-
const instructions = asString(stage.instructions);
|
|
32705
|
-
if (!instructions) continue;
|
|
32706
|
-
const step = {
|
|
32707
|
-
id: stepId,
|
|
32708
|
-
kind: "agent",
|
|
32709
|
-
agent: stepAgent
|
|
32710
|
-
};
|
|
32711
|
-
if (label) step.description = label;
|
|
32712
|
-
let maxAttempts = 3;
|
|
32713
|
-
if (typeof stage.maxAttempts === "number" && Number.isInteger(stage.maxAttempts) && stage.maxAttempts >= 1 && stage.maxAttempts <= 20) {
|
|
32714
|
-
maxAttempts = stage.maxAttempts;
|
|
32715
|
-
} else if (stage.maxAttempts !== void 0) {
|
|
32716
|
-
recordUnmapped(plan, source.path, `${pointer}/maxAttempts`, stage.maxAttempts, false);
|
|
32717
|
-
}
|
|
32718
|
-
step.maxAttempts = maxAttempts;
|
|
32719
|
-
step.instructions = instructions;
|
|
32720
|
-
const requiredEvidence = [];
|
|
32721
|
-
const policyProducers = /* @__PURE__ */ new Set();
|
|
32722
|
-
let policyProducerMinimum = 0;
|
|
32723
|
-
const rawEvidence = Array.isArray(stage.requiredEvidence) ? stage.requiredEvidence : [];
|
|
32724
|
-
const seenKeys = /* @__PURE__ */ new Set();
|
|
32725
|
-
for (const [evidenceIndex, evidenceEntry] of rawEvidence.entries()) {
|
|
32726
|
-
const rawKey = asString(evidenceEntry);
|
|
32727
|
-
if (!rawKey) {
|
|
32728
|
-
recordUnmapped(plan, source.path, `${pointer}/requiredEvidence/${evidenceIndex}`, evidenceEntry, false);
|
|
32729
|
-
continue;
|
|
32730
|
-
}
|
|
32731
|
-
const key = normalizeIdentifier(rawKey);
|
|
32732
|
-
if (!IDENTIFIER2.test(key) || key.length > 64) {
|
|
32733
|
-
recordUnmapped(plan, source.path, `${pointer}/requiredEvidence/${evidenceIndex}`, evidenceEntry, false);
|
|
32734
|
-
continue;
|
|
32735
|
-
}
|
|
32736
|
-
if (seenKeys.has(key)) {
|
|
32737
|
-
recordUnmapped(plan, source.path, `${pointer}/requiredEvidence/${evidenceIndex}`, evidenceEntry, false);
|
|
32738
|
-
continue;
|
|
32739
|
-
}
|
|
32740
|
-
if (key !== rawKey) plan.renames.push({ from: elide(rawKey), to: key, kind: "evidence" });
|
|
32741
|
-
seenKeys.add(key);
|
|
32742
|
-
requiredEvidence.push({ key, kind: "assignment-result" });
|
|
32743
|
-
}
|
|
32744
|
-
const policies = asObject2(stage.evidencePolicies);
|
|
32745
|
-
if (policies) {
|
|
32746
|
-
const seenPolicies = /* @__PURE__ */ new Set();
|
|
32747
|
-
for (const [rawPolicyKey, policyEntry] of Object.entries(policies).sort(([left], [right]) => compareCodeUnits6(left, right))) {
|
|
32748
|
-
const policy = asObject2(policyEntry);
|
|
32749
|
-
const policyKey = normalizeIdentifier(rawPolicyKey);
|
|
32750
|
-
if (seenPolicies.has(policyKey)) {
|
|
32751
|
-
recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}`, policyEntry, false);
|
|
32752
|
-
continue;
|
|
32753
|
-
}
|
|
32754
|
-
seenPolicies.add(policyKey);
|
|
32755
|
-
const requirement = requiredEvidence.find((candidate) => candidate.key === policyKey);
|
|
32756
|
-
if (!policy || !requirement) {
|
|
32757
|
-
recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}`, policyEntry, false);
|
|
32758
|
-
continue;
|
|
32759
|
-
}
|
|
32760
|
-
recordUnknownFields(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}`, policy, KNOWN_POLICY_FIELDS);
|
|
32761
|
-
let minProducers = 1;
|
|
32762
|
-
if (typeof policy.minProducers === "number" && Number.isInteger(policy.minProducers) && policy.minProducers >= 1 && policy.minProducers <= 16) {
|
|
32763
|
-
minProducers = policy.minProducers;
|
|
32764
|
-
} else if (policy.minProducers !== void 0) {
|
|
32765
|
-
recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}/minProducers`, policy.minProducers, false);
|
|
32766
|
-
}
|
|
32767
|
-
if (policy.eligibleAgents !== void 0 && !Array.isArray(policy.eligibleAgents)) {
|
|
32768
|
-
recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}/eligibleAgents`, policy.eligibleAgents, false);
|
|
32769
|
-
}
|
|
32770
|
-
const eligible = Array.isArray(policy.eligibleAgents) ? policy.eligibleAgents : [];
|
|
32771
|
-
const eligibleIds = [];
|
|
32772
|
-
for (const [eligibleIndex, candidate] of eligible.entries()) {
|
|
32773
|
-
const rawName = asString(candidate);
|
|
32774
|
-
if (!rawName) {
|
|
32775
|
-
recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}/eligibleAgents/${eligibleIndex}`, candidate, false);
|
|
32776
|
-
continue;
|
|
32777
|
-
}
|
|
32778
|
-
const rawBound = pendingAgentRawNames.has(rawName) ? void 0 : agentRawNames.get(rawName) ?? [...agentRawNames].find(([candidateName]) => candidateName.toLocaleLowerCase("en-US") === rawName.toLocaleLowerCase("en-US"))?.[1];
|
|
32779
|
-
if (rawBound) {
|
|
32780
|
-
if (!eligibleIds.includes(rawBound)) eligibleIds.push(rawBound);
|
|
32781
|
-
continue;
|
|
32782
|
-
}
|
|
32783
|
-
if ([...pendingAgentRawNames].some((pending) => pending === rawName || pending.toLocaleLowerCase("en-US") === rawName.toLocaleLowerCase("en-US"))) {
|
|
32784
|
-
const previewId = normalizeIdentifier(rawName);
|
|
32785
|
-
if (IDENTIFIER2.test(previewId) && previewId.length <= 64 && !eligibleIds.includes(previewId)) {
|
|
32786
|
-
eligibleIds.push(previewId);
|
|
32787
|
-
}
|
|
32788
|
-
continue;
|
|
32789
|
-
}
|
|
32790
|
-
const normalized = normalizeIdentifier(rawName);
|
|
32791
|
-
if (agentRawNames.size === 0 && agentIds.has(normalized)) {
|
|
32792
|
-
if (!eligibleIds.includes(normalized)) eligibleIds.push(normalized);
|
|
32793
|
-
continue;
|
|
32794
|
-
}
|
|
32795
|
-
if (agentIds.size === 0) {
|
|
32796
|
-
recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}/eligibleAgents/${eligibleIndex}`, candidate, false);
|
|
32797
|
-
continue;
|
|
32798
|
-
}
|
|
32799
|
-
const mapped = resolveDecision(
|
|
32800
|
-
plan,
|
|
32801
|
-
`producer:${workflowKey}:${stepKey}:${keyFragment(rawName)}`,
|
|
32802
|
-
"evidence-policy",
|
|
32803
|
-
source.path,
|
|
32804
|
-
`evidence policy on ${stepId}.${policyKey} names producer ${JSON.stringify(elide(rawName, 200))} which is not a migrated agent; choose the roster agent that takes this producer role`,
|
|
32805
|
-
[...agentIds.keys()].sort(compareCodeUnits6).slice(0, 64),
|
|
32806
|
-
decisions
|
|
32807
|
-
);
|
|
32808
|
-
if (typeof mapped === "string" && agentIds.has(mapped)) {
|
|
32809
|
-
plan.renames.push({ from: elide(rawName), to: mapped, kind: "agent" });
|
|
32810
|
-
if (!eligibleIds.includes(mapped)) eligibleIds.push(mapped);
|
|
32811
|
-
} else if (mapped !== void 0) {
|
|
32812
|
-
if (!plan.invalidDecisions.includes(`producer:${workflowKey}:${stepKey}:${keyFragment(rawName)}`)) {
|
|
32813
|
-
plan.invalidDecisions.push(`producer:${workflowKey}:${stepKey}:${keyFragment(rawName)}`);
|
|
32814
|
-
}
|
|
32815
|
-
if (!plan.ambiguities.some((ambiguity) => ambiguity.key === `producer:${workflowKey}:${stepKey}:${keyFragment(rawName)}`)) {
|
|
32816
|
-
plan.ambiguities.push({
|
|
32817
|
-
key: `producer:${workflowKey}:${stepKey}:${keyFragment(rawName)}`,
|
|
32818
|
-
category: "evidence-policy",
|
|
32819
|
-
sourcePath: source.path,
|
|
32820
|
-
message: `decision value ${JSON.stringify(typeof mapped === "string" ? elide(mapped, 200) : mapped)} for producer ${JSON.stringify(elide(rawName, 200))} is not a migrated agent`,
|
|
32821
|
-
allowedValues: [...agentIds.keys()].sort(compareCodeUnits6).slice(0, 64)
|
|
32822
|
-
});
|
|
32823
|
-
}
|
|
32824
|
-
}
|
|
32825
|
-
}
|
|
32826
|
-
const acceptedStatusesMalformed = policy.acceptedStatuses !== void 0 && !Array.isArray(policy.acceptedStatuses);
|
|
32827
|
-
if (acceptedStatusesMalformed) {
|
|
32828
|
-
recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}/acceptedStatuses`, policy.acceptedStatuses, false);
|
|
32829
|
-
}
|
|
32830
|
-
const accepted = acceptedStatusesMalformed ? [] : Array.isArray(policy.acceptedStatuses) ? policy.acceptedStatuses : ["replied"];
|
|
32831
|
-
if (Array.isArray(policy.acceptedStatuses) && policy.acceptedStatuses.length === 0) {
|
|
32832
|
-
recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}/acceptedStatuses`, policy.acceptedStatuses, false);
|
|
32833
|
-
}
|
|
32834
|
-
let acceptedStatuses = accepted.length > 0 && accepted.every((status) => status === "replied") ? ["passed"] : void 0;
|
|
32835
|
-
if (!acceptedStatuses) {
|
|
32836
|
-
const chosen = resolveDecision(
|
|
32837
|
-
plan,
|
|
32838
|
-
`statuses:${workflowKey}:${stepKey}:${policyKey}`,
|
|
32839
|
-
"evidence-policy",
|
|
32840
|
-
source.path,
|
|
32841
|
-
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'`,
|
|
32842
|
-
["passed"],
|
|
32843
|
-
decisions
|
|
32844
|
-
);
|
|
32845
|
-
if (chosen === "passed") acceptedStatuses = ["passed"];
|
|
32846
|
-
}
|
|
32847
|
-
if (acceptedStatuses) {
|
|
32848
|
-
plan.permissionChanges.push({
|
|
32849
|
-
sourcePath: source.path,
|
|
32850
|
-
targetPath: `.kxm/workflows/${workflowId}.yaml`,
|
|
32851
|
-
direction: "narrowing",
|
|
32852
|
-
summary: `evidence ${policyKey} on ${stepId}: legacy peer-reply policy (status 'replied') migrates to assignment-result producer policy requiring 'passed'`,
|
|
32853
|
-
decisionKey: `evidence:${workflowKey}:${stepKey}:${policyKey}`
|
|
32854
|
-
});
|
|
32855
|
-
plan.permissionChanges.push({
|
|
32856
|
-
sourcePath: source.path,
|
|
32857
|
-
targetPath: `.kxm/workflows/${workflowId}.yaml`,
|
|
32858
|
-
direction: "expansion",
|
|
32859
|
-
summary: `step ${stepId}: assignment pool widens from the single legacy coordinator to coordinator plus evidence producers so KXM producer evidence stays in scope`,
|
|
32860
|
-
decisionKey: `evidence:${workflowKey}:${stepKey}:${policyKey}`
|
|
32861
|
-
});
|
|
32862
|
-
resolveDecision(
|
|
32863
|
-
plan,
|
|
32864
|
-
`evidence:${workflowKey}:${stepKey}:${policyKey}`,
|
|
32865
|
-
"evidence-policy",
|
|
32866
|
-
source.path,
|
|
32867
|
-
`approve strengthening ${stepId}.${policyKey} from 'peer replied' to 'peer assignment passed' and widening the step assignment pool to include the producers`,
|
|
32868
|
-
["approve"],
|
|
32869
|
-
decisions
|
|
32870
|
-
);
|
|
32871
|
-
}
|
|
32872
|
-
if (eligibleIds.length > 0 && acceptedStatuses) {
|
|
32873
|
-
requirement.kind = "assignment-result";
|
|
32874
|
-
requirement.producerPolicy = {
|
|
32875
|
-
minimumProducers: minProducers,
|
|
32876
|
-
eligibleAgents: eligibleIds,
|
|
32877
|
-
acceptedStatuses
|
|
32878
|
-
};
|
|
32879
|
-
for (const producer of eligibleIds) policyProducers.add(producer);
|
|
32880
|
-
policyProducerMinimum = Math.max(policyProducerMinimum, minProducers);
|
|
32881
|
-
const degradation = asObject2(policy.degradation);
|
|
32882
|
-
if (degradation && degradation.minProducers !== void 0) {
|
|
32883
|
-
if (typeof degradation.minProducers === "number" && Number.isInteger(degradation.minProducers) && degradation.minProducers >= 1 && degradation.minProducers <= 15 && degradation.minProducers < minProducers) {
|
|
32884
|
-
requirement.producerPolicy.degradation = { minimumProducers: degradation.minProducers };
|
|
32885
|
-
} else {
|
|
32886
|
-
recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}/degradation`, policy.degradation, false);
|
|
32887
|
-
}
|
|
32888
|
-
}
|
|
32889
|
-
} else {
|
|
32890
|
-
recordUnmapped(plan, source.path, `${pointer}/evidencePolicies/${pointerEscape2(rawPolicyKey)}`, policyEntry, false);
|
|
32891
|
-
}
|
|
32892
|
-
}
|
|
32893
|
-
}
|
|
32894
|
-
if (requiredEvidence.length > 0) step.requiredEvidence = requiredEvidence;
|
|
32895
|
-
if (policyProducers.size > 0) {
|
|
32896
|
-
const pool = [stepAgent, ...[...policyProducers].filter((candidate) => candidate !== stepAgent).sort(compareCodeUnits6)];
|
|
32897
|
-
step.assignments = {
|
|
32898
|
-
allowedAgents: pool,
|
|
32899
|
-
minimum: 1,
|
|
32900
|
-
target: Math.max(1, policyProducerMinimum),
|
|
32901
|
-
maximum: pool.length,
|
|
32902
|
-
maxParallel: pool.length
|
|
32903
|
-
};
|
|
32904
|
-
}
|
|
32905
|
-
const on = asObject2(stage.on);
|
|
32906
|
-
const transitions = {};
|
|
32907
|
-
if (on) {
|
|
32908
|
-
const seenOutcomes = /* @__PURE__ */ new Set();
|
|
32909
|
-
for (const [rawOutcome, rawTransition] of Object.entries(on).sort(([left], [right]) => compareCodeUnits6(left, right))) {
|
|
32910
|
-
const outcome = normalizeIdentifier(rawOutcome);
|
|
32911
|
-
if (!IDENTIFIER2.test(outcome) || outcome.length > 64) {
|
|
32912
|
-
recordUnmapped(plan, source.path, `${pointer}/on/${pointerEscape2(rawOutcome)}`, rawTransition, false);
|
|
32913
|
-
continue;
|
|
32914
|
-
}
|
|
32915
|
-
if (seenOutcomes.has(outcome)) {
|
|
32916
|
-
recordUnmapped(plan, source.path, `${pointer}/on/${pointerEscape2(rawOutcome)}`, rawTransition, false);
|
|
32917
|
-
continue;
|
|
32918
|
-
}
|
|
32919
|
-
seenOutcomes.add(outcome);
|
|
32920
|
-
if (outcome !== rawOutcome) plan.renames.push({ from: elide(rawOutcome), to: outcome, kind: "outcome" });
|
|
32921
|
-
const converted = convertTransition(plan, source, context, stepId, stepKey, outcome, rawOutcome, rawTransition, decisions, pointer);
|
|
32922
|
-
if (converted !== void 0) transitions[outcome] = converted;
|
|
32923
|
-
}
|
|
32924
|
-
if (transitions.passed === void 0) {
|
|
32925
|
-
const nextId = stageIds[stageIds.indexOf(stepId) + 1];
|
|
32926
|
-
transitions.passed = nextId ?? { target: "$terminal", terminalStatus: "completed" };
|
|
32927
|
-
}
|
|
32928
|
-
} else {
|
|
32929
|
-
const nextId = stageIds[stageIds.indexOf(stepId) + 1];
|
|
32930
|
-
transitions.passed = nextId ?? { target: "$terminal", terminalStatus: "completed" };
|
|
32931
|
-
}
|
|
32932
|
-
step.on = transitions;
|
|
32933
|
-
if (typeof stage.maxTransitions === "number") {
|
|
32934
|
-
recordUnmapped(plan, source.path, `${pointer}/maxTransitions`, stage.maxTransitions, false);
|
|
32935
|
-
}
|
|
32936
|
-
if (stage.area !== void 0) recordUnmapped(plan, source.path, `${pointer}/area`, stage.area, false);
|
|
32937
|
-
steps.push(step);
|
|
32938
|
-
}
|
|
32939
|
-
if (steps.length === 0) {
|
|
32940
|
-
resolveDecision(
|
|
32941
|
-
plan,
|
|
32942
|
-
`stages:${workflowKey}`,
|
|
32943
|
-
"unsupported",
|
|
32944
|
-
source.path,
|
|
32945
|
-
`workflow ${workflowId} produced no convertible steps; confirm it is dropped`,
|
|
32946
|
-
["drop"],
|
|
32947
|
-
decisions
|
|
32948
|
-
);
|
|
32949
|
-
continue;
|
|
32950
|
-
}
|
|
32951
|
-
const workflow = {
|
|
32952
|
-
schema: "kxm.workflow.v1",
|
|
32953
|
-
coordinator: stepAgent,
|
|
32954
|
-
steps
|
|
32955
|
-
};
|
|
32956
|
-
if (typeof definition.maxTransitions === "number" && Number.isInteger(definition.maxTransitions) && definition.maxTransitions >= 1 && definition.maxTransitions <= 1e3) {
|
|
32957
|
-
workflow.limits = { maxTransitions: definition.maxTransitions };
|
|
32958
|
-
} else if (definition.maxTransitions !== void 0) {
|
|
32959
|
-
recordUnmapped(plan, source.path, `${basePointer}/maxTransitions`, definition.maxTransitions, false);
|
|
32960
|
-
}
|
|
32961
|
-
if (workflow.limits === void 0) {
|
|
32962
|
-
const hasBackEdge = steps.some((step) => Object.values(asObject2(step.on) ?? {}).some((rule) => {
|
|
32963
|
-
const target = typeof rule === "string" ? rule : asObject2(rule)?.target;
|
|
32964
|
-
return typeof target === "string" && target !== "$terminal" && stageIds.indexOf(target) <= stageIds.indexOf(String(step.id));
|
|
32965
|
-
}));
|
|
32966
|
-
if (hasBackEdge) {
|
|
32967
|
-
const chosen = resolveDecision(
|
|
32968
|
-
plan,
|
|
32969
|
-
`budget:${workflowKey}`,
|
|
32970
|
-
"transition-budget",
|
|
32971
|
-
source.path,
|
|
32972
|
-
`workflow ${workflowId} has back-edges but no legacy global maxTransitions; KXM requires limits.maxTransitions (1-1000)`,
|
|
32973
|
-
[28],
|
|
32974
|
-
decisions
|
|
32975
|
-
);
|
|
32976
|
-
workflow.limits = { maxTransitions: typeof chosen === "number" && Number.isInteger(chosen) && chosen >= 1 && chosen <= 1e3 ? chosen : 28 };
|
|
32977
|
-
}
|
|
32978
|
-
}
|
|
32979
|
-
for (const oracleField of ["reproOracle", "planHash"]) {
|
|
32980
|
-
const oracle = asObject2(definition[oracleField]);
|
|
32981
|
-
if (!oracle) continue;
|
|
32982
|
-
const oracleStage = asString(oracle.stageId);
|
|
32983
|
-
const oracleEvidence = asString(oracle.evidenceKey);
|
|
32984
|
-
if (!oracleStage || !oracleEvidence) {
|
|
32985
|
-
recordUnmapped(plan, source.path, `${basePointer}/${oracleField}`, definition[oracleField], false);
|
|
32986
|
-
continue;
|
|
32987
|
-
}
|
|
32988
|
-
const mappedStage = context.renamesByKind.get(oracleStage);
|
|
32989
|
-
if (!mappedStage) {
|
|
32990
|
-
if (!context.stageIds.includes(normalizeIdentifier(oracleStage))) {
|
|
32991
|
-
recordUnmapped(plan, source.path, `${basePointer}/${oracleField}`, definition[oracleField], false);
|
|
32992
|
-
continue;
|
|
32993
|
-
}
|
|
32994
|
-
}
|
|
32995
|
-
workflow[oracleField] = {
|
|
32996
|
-
stageId: mappedStage ?? normalizeIdentifier(oracleStage),
|
|
32997
|
-
evidenceKey: normalizeIdentifier(oracleEvidence)
|
|
32998
|
-
};
|
|
32999
|
-
}
|
|
33000
|
-
if (Array.isArray(definition.requirePlanHash)) {
|
|
33001
|
-
const mapped = [];
|
|
33002
|
-
for (const [requireIndex, candidate] of definition.requirePlanHash.entries()) {
|
|
33003
|
-
const rawStage = asString(candidate);
|
|
33004
|
-
if (!rawStage) {
|
|
33005
|
-
recordUnmapped(plan, source.path, `${basePointer}/requirePlanHash/${requireIndex}`, candidate, false);
|
|
33006
|
-
continue;
|
|
33007
|
-
}
|
|
33008
|
-
const mappedStage = context.renamesByKind.get(rawStage);
|
|
33009
|
-
if (!mappedStage && !context.stageIds.includes(normalizeIdentifier(rawStage))) {
|
|
33010
|
-
recordUnmapped(plan, source.path, `${basePointer}/requirePlanHash/${requireIndex}`, candidate, false);
|
|
33011
|
-
continue;
|
|
33012
|
-
}
|
|
33013
|
-
mapped.push(mappedStage ?? normalizeIdentifier(rawStage));
|
|
33014
|
-
}
|
|
33015
|
-
if (mapped.length > 0) workflow.requirePlanHash = [...new Set(mapped)].sort(compareCodeUnits6);
|
|
33016
|
-
}
|
|
33017
|
-
workflows.set(workflowId, workflow);
|
|
33018
|
-
}
|
|
33019
|
-
return workflows;
|
|
33020
|
-
}
|
|
33021
|
-
var PROJECT_ID2 = /^prj_[A-Za-z0-9][A-Za-z0-9_-]{5,127}$/;
|
|
33022
|
-
function sortedRecord(map, prefix) {
|
|
33023
|
-
return new Map([...map.entries()].sort(([left], [right]) => compareCodeUnits6(left, right)).map(([key, value]) => [`${prefix}${key}.yaml`, value]));
|
|
33024
|
-
}
|
|
33025
|
-
function migrationGitRoot(start) {
|
|
33026
|
-
const root = discoverGitRoot(start);
|
|
33027
|
-
if (!root) {
|
|
33028
|
-
throw new KxmConfigError([migrateIssue("discovery", "git_root_required", ".", "kxm migrate must run inside the authoritative Git worktree")]);
|
|
33029
|
-
}
|
|
33030
|
-
return root;
|
|
33031
|
-
}
|
|
33032
|
-
function planKxmMigration(projectRoot, options = {}) {
|
|
33033
|
-
const root = migrationGitRoot(projectRoot);
|
|
33034
|
-
const registry = new KxmSchemaRegistry(options.schemasDir);
|
|
33035
|
-
const sources = readKxmLegacySources(root);
|
|
33036
|
-
if (sources.length === 0) {
|
|
33037
|
-
throw new KxmConfigError([migrateIssue("discovery", "legacy_sources_missing", ".kxm/config", "no legacy configuration files found to migrate")]);
|
|
33038
|
-
}
|
|
33039
|
-
const decisions = options.decisions ?? {};
|
|
33040
|
-
const plan = { ambiguities: [], invalidDecisions: [], decisionKeys: /* @__PURE__ */ new Set(), decisionAllowedValues: /* @__PURE__ */ new Map(), unmapped: [], renames: [], permissionChanges: [] };
|
|
33041
|
-
const agentNames = /* @__PURE__ */ new Map();
|
|
33042
|
-
const workflowNames = /* @__PURE__ */ new Map();
|
|
33043
|
-
const agentsSource = sources.find((source) => source.path === ".kxm/config/agents.json");
|
|
33044
|
-
const gatesSource = sources.find((source) => source.path === ".kxm/config/gates.json");
|
|
33045
|
-
const converted = agentsSource ? convertAgentsRoster(plan, agentsSource, decisions, agentNames) : { agents: /* @__PURE__ */ new Map(), models: /* @__PURE__ */ new Map(), rawNames: /* @__PURE__ */ new Map(), pendingRawNames: /* @__PURE__ */ new Set(), identityPending: false };
|
|
33046
|
-
if (!agentsSource) {
|
|
33047
|
-
resolveDecision(
|
|
33048
|
-
plan,
|
|
33049
|
-
"agents-missing",
|
|
33050
|
-
"unsupported",
|
|
33051
|
-
".kxm/config/agents.json",
|
|
33052
|
-
"no agents.json roster; workflows convert against an empty agent set \u2014 confirm conversion continues",
|
|
33053
|
-
["continue"],
|
|
33054
|
-
decisions
|
|
33055
|
-
);
|
|
33056
|
-
}
|
|
33057
|
-
if (gatesSource) convertGatesRoster(plan, gatesSource, decisions);
|
|
33058
|
-
const workflows = /* @__PURE__ */ new Map();
|
|
33059
|
-
for (const source of sources) {
|
|
33060
|
-
if (!source.path.startsWith(".kxm/config/workflows/")) continue;
|
|
33061
|
-
const convertedWorkflows = convertWorkflowFile(
|
|
33062
|
-
plan,
|
|
33063
|
-
source,
|
|
33064
|
-
decisions,
|
|
33065
|
-
converted.agents,
|
|
33066
|
-
converted.rawNames,
|
|
33067
|
-
converted.pendingRawNames,
|
|
33068
|
-
converted.identityPending,
|
|
33069
|
-
workflowNames
|
|
33070
|
-
);
|
|
33071
|
-
for (const [id, workflow] of convertedWorkflows) workflows.set(id, workflow);
|
|
33072
|
-
}
|
|
33073
|
-
const projectId = options.projectId ?? `prj_mig${sha256Of(legacySourceDigest(sources)).slice(7, 39)}`;
|
|
33074
|
-
if (!PROJECT_ID2.test(projectId)) {
|
|
33075
|
-
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")]);
|
|
33076
|
-
}
|
|
33077
|
-
const projectName = options.projectName ?? "Migrated legacy project";
|
|
33078
|
-
if (projectName.length < 1 || projectName.length > 120 || /[\u0000\r\n]/.test(projectName)) {
|
|
33079
|
-
throw new KxmConfigError([migrateIssue("semantic", "project_name_invalid", ".kxm/project.yaml", "project name must contain 1-120 characters on one line")]);
|
|
33080
|
-
}
|
|
33081
|
-
const resources = /* @__PURE__ */ new Map();
|
|
33082
|
-
resources.set(".kxm/project.yaml", {
|
|
33083
|
-
schema: "kxm.project.v1",
|
|
33084
|
-
id: projectId,
|
|
33085
|
-
name: projectName,
|
|
33086
|
-
...workflows.size > 0 ? { defaultWorkflow: [...workflows.keys()].sort(compareCodeUnits6)[0] } : {},
|
|
33087
|
-
defaultExecutor: "local",
|
|
33088
|
-
repositories: [{ id: "control", role: "control", required: true, pathHint: "." }],
|
|
33089
|
-
workspace: {
|
|
33090
|
-
dirtySnapshot: {
|
|
33091
|
-
untracked: "ask",
|
|
33092
|
-
dirtySubmodules: "fail"
|
|
33093
|
-
}
|
|
33094
|
-
}
|
|
33095
|
-
});
|
|
33096
|
-
resources.set(".kxm/repo/repo.yaml", {
|
|
33097
|
-
schema: "kxm.repository.v1",
|
|
33098
|
-
projectId,
|
|
33099
|
-
repositoryId: "control",
|
|
33100
|
-
description: "Authoritative project configuration and repository content.",
|
|
33101
|
-
defaultAccess: "write"
|
|
33102
|
-
});
|
|
33103
|
-
for (const [path4, value] of sortedRecord(converted.agents, ".kxm/agents/")) resources.set(path4, value);
|
|
33104
|
-
for (const [path4, value] of sortedRecord(converted.models, ".kxm/models/")) resources.set(path4, value);
|
|
33105
|
-
for (const [path4, value] of sortedRecord(workflows, ".kxm/workflows/")) resources.set(path4, value);
|
|
33106
|
-
const schemaIssues = [];
|
|
33107
|
-
const kindOf = (path4) => path4 === ".kxm/project.yaml" ? "project" : path4.endsWith("repo.yaml") ? "repository" : path4.startsWith(".kxm/agents/") ? "agent" : path4.startsWith(".kxm/models/") ? "model" : "workflow";
|
|
33108
|
-
const idOf = (path4) => path4 === ".kxm/project.yaml" || path4.endsWith("repo.yaml") ? void 0 : path4.slice(path4.lastIndexOf("/") + 1, -".yaml".length);
|
|
33109
|
-
const semanticResources = /* @__PURE__ */ new Map();
|
|
33110
|
-
for (const [path4, value] of [...resources.entries()].sort(([left], [right]) => compareCodeUnits6(left, right))) {
|
|
33111
|
-
const kind = kindOf(path4);
|
|
33112
|
-
schemaIssues.push(...registry.validate(kind, value, path4));
|
|
33113
|
-
const id = idOf(path4);
|
|
33114
|
-
semanticResources.set(path4, kind === "repository" ? { kind, id: "control", value } : { kind, ...id === void 0 ? {} : { id }, value });
|
|
33115
|
-
}
|
|
33116
|
-
if (schemaIssues.length > 0) throw new KxmConfigError(schemaIssues);
|
|
33117
|
-
if (plan.ambiguities.length === 0) {
|
|
33118
|
-
const semanticIssues = validateKxmResources(semanticResources, options);
|
|
33119
|
-
if (semanticIssues.length > 0) throw new KxmConfigError(semanticIssues);
|
|
33120
|
-
}
|
|
33121
|
-
const planRecord = {
|
|
33122
|
-
schema: "kxm.migration-plan.v1",
|
|
33123
|
-
projectId,
|
|
33124
|
-
projectName,
|
|
33125
|
-
sourceDigest: legacySourceDigest(sources),
|
|
33126
|
-
sources: sources.map((source) => ({ path: source.path, sha256: source.sha256, bytes: source.bytes })),
|
|
33127
|
-
resources: [...resources.keys()].sort(compareCodeUnits6).map((path4) => {
|
|
33128
|
-
const bytes = Buffer.from((0, import_yaml12.stringify)(resources.get(path4), { lineWidth: 0 }), "utf8");
|
|
33129
|
-
return { path: path4, sha256: sha256Of(bytes), bytes: bytes.byteLength };
|
|
33130
|
-
}),
|
|
33131
|
-
ambiguities: [...plan.ambiguities].sort((left, right) => compareCodeUnits6(left.key, right.key)).map((ambiguity) => ({
|
|
33132
|
-
key: ambiguity.key,
|
|
33133
|
-
category: ambiguity.category,
|
|
33134
|
-
sourcePath: ambiguity.sourcePath,
|
|
33135
|
-
message: ambiguity.message,
|
|
33136
|
-
allowedValues: [...ambiguity.allowedValues]
|
|
33137
|
-
})),
|
|
33138
|
-
unmapped: [...plan.unmapped].sort((left, right) => compareCodeUnits6(left.sourcePath, right.sourcePath) || compareCodeUnits6(left.jsonPointer, right.jsonPointer)).map((entry) => ({ ...entry })),
|
|
33139
|
-
renames: [...new Map(plan.renames.map((rename) => [JSON.stringify([rename.kind, rename.from, rename.to]), rename])).values()].sort((left, right) => compareCodeUnits6(left.kind, right.kind) || compareCodeUnits6(left.from, right.from)).map((entry) => ({ ...entry })),
|
|
33140
|
-
permissionChanges: [...plan.permissionChanges].sort((left, right) => compareCodeUnits6(left.decisionKey, right.decisionKey)).map((entry) => ({ ...entry })),
|
|
33141
|
-
canApply: plan.ambiguities.length === 0
|
|
33142
|
-
};
|
|
33143
|
-
const planIssues = registry.validateMigrationPlan(planRecord, "kxm.migration-plan.v1");
|
|
33144
|
-
if (planIssues.length > 0) throw new KxmConfigError(planIssues);
|
|
33145
|
-
return {
|
|
33146
|
-
plan: planRecord,
|
|
33147
|
-
resources,
|
|
33148
|
-
ambiguities: plan.ambiguities,
|
|
33149
|
-
decisionKeys: plan.decisionKeys,
|
|
33150
|
-
decisionAllowedValues: plan.decisionAllowedValues,
|
|
33151
|
-
invalidDecisions: plan.invalidDecisions,
|
|
33152
|
-
decisions,
|
|
33153
|
-
sources
|
|
33154
|
-
};
|
|
33155
|
-
}
|
|
33156
|
-
function readKxmMigrationDecisions(path4, schemasDir) {
|
|
33157
|
-
if (!existsSync23(path4)) {
|
|
33158
|
-
throw new KxmConfigError([migrateIssue("discovery", "decisions_missing", path4, "migration decisions file does not exist")]);
|
|
33159
|
-
}
|
|
33160
|
-
const registry = new KxmSchemaRegistry(schemasDir);
|
|
33161
|
-
const value = parseRestrictedYaml2(readFileSync22(path4), path4);
|
|
33162
|
-
const issues = registry.validateMigrationDecision(value, path4);
|
|
33163
|
-
if (issues.length > 0) throw new KxmConfigError(issues);
|
|
33164
|
-
return value;
|
|
33165
|
-
}
|
|
33166
|
-
function resolutionsOf(decisions) {
|
|
33167
|
-
const resolutions = decisions.resolutions;
|
|
33168
|
-
if (!resolutions || typeof resolutions !== "object" || Array.isArray(resolutions)) return {};
|
|
33169
|
-
return { ...resolutions };
|
|
33170
|
-
}
|
|
33171
|
-
function syncDirectory3(path4) {
|
|
33172
|
-
let descriptor;
|
|
33173
|
-
try {
|
|
33174
|
-
descriptor = openSync3(path4, "r");
|
|
33175
|
-
fsyncSync3(descriptor);
|
|
33176
|
-
} catch (error) {
|
|
33177
|
-
const code = error.code;
|
|
33178
|
-
if (process.platform !== "win32" && code !== "EINVAL" && code !== "ENOTSUP" && code !== "EISDIR") throw error;
|
|
33179
|
-
} finally {
|
|
33180
|
-
if (descriptor !== void 0) closeSync3(descriptor);
|
|
33181
|
-
}
|
|
33182
|
-
}
|
|
33183
|
-
function writeDurable2(path4, content) {
|
|
33184
|
-
const temp = `${path4}.kxm-migration-tmp-${process.pid}-${createHash13("sha256").update(`${path4}${Date.now()}${Math.random()}`, "utf8").digest("hex").slice(0, 12)}`;
|
|
33185
|
-
let created = false;
|
|
33186
|
-
try {
|
|
33187
|
-
const descriptor = openSync3(temp, "wx", 384);
|
|
33188
|
-
created = true;
|
|
33189
|
-
try {
|
|
33190
|
-
writeFileSync18(descriptor, content);
|
|
33191
|
-
fsyncSync3(descriptor);
|
|
33192
|
-
} finally {
|
|
33193
|
-
closeSync3(descriptor);
|
|
33194
|
-
}
|
|
33195
|
-
renameSync7(temp, path4);
|
|
33196
|
-
try {
|
|
33197
|
-
chmodSync6(path4, 384);
|
|
33198
|
-
} catch {
|
|
33199
|
-
}
|
|
33200
|
-
syncDirectory3(join26(path4, ".."));
|
|
33201
|
-
} finally {
|
|
33202
|
-
if (created && existsSync23(temp)) rmSync9(temp, { force: true });
|
|
33203
|
-
}
|
|
33204
|
-
}
|
|
33205
|
-
function applyKxmMigration(projectRoot, options = {}) {
|
|
33206
|
-
const root = migrationGitRoot(projectRoot);
|
|
33207
|
-
const storeOptions = {
|
|
33208
|
-
...options.localStateRoot === void 0 ? {} : { stateRoot: options.localStateRoot },
|
|
33209
|
-
...options.schemasDir === void 0 ? {} : { schemasDir: options.schemasDir }
|
|
33210
|
-
};
|
|
33211
|
-
const execute = (lock) => {
|
|
33212
|
-
const receiptAbsolute = join26(root, ...KXM_MIGRATION_RECEIPT_PATH.split("/"));
|
|
33213
|
-
if (existsSync23(receiptAbsolute)) {
|
|
33214
|
-
const stat = lstatSync8(receiptAbsolute);
|
|
33215
|
-
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
33216
|
-
throw new KxmConfigError([migrateIssue("path", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "migration receipt must be a regular file, not a link")]);
|
|
33217
|
-
}
|
|
33218
|
-
const existing = loadKxmProject(root, options);
|
|
33219
|
-
return {
|
|
33220
|
-
action: "already-migrated",
|
|
33221
|
-
projectRoot: root,
|
|
33222
|
-
receiptPath: KXM_MIGRATION_RECEIPT_PATH,
|
|
33223
|
-
configRevision: existing.configRevision,
|
|
33224
|
-
files: []
|
|
33225
|
-
};
|
|
33226
|
-
}
|
|
33227
|
-
const decisionsRecord = options.decisionsFile ? readKxmMigrationDecisions(options.decisionsFile, options.schemasDir) : void 0;
|
|
33228
|
-
const decisions = decisionsRecord ? resolutionsOf(decisionsRecord) : options.decisions ?? {};
|
|
33229
|
-
const first = planKxmMigration(root, { ...options, decisions });
|
|
33230
|
-
if (decisionsRecord) {
|
|
33231
|
-
if (decisionsRecord.projectId !== first.plan.projectId) {
|
|
33232
|
-
throw new KxmConfigError([migrateIssue("semantic", "decision_project_mismatch", options.decisionsFile ?? "<decisions>", "decisions file projectId does not match the recomputed plan")]);
|
|
33233
|
-
}
|
|
33234
|
-
if (decisionsRecord.projectName !== first.plan.projectName) {
|
|
33235
|
-
throw new KxmConfigError([migrateIssue("semantic", "decision_project_mismatch", options.decisionsFile ?? "<decisions>", "decisions file projectName does not match the recomputed plan")]);
|
|
33236
|
-
}
|
|
33237
|
-
if (decisionsRecord.sourceDigest !== first.plan.sourceDigest) {
|
|
33238
|
-
throw new KxmConfigError([migrateIssue("semantic", "decision_source_changed", options.decisionsFile ?? "<decisions>", "legacy sources changed after the decisions file was reviewed")]);
|
|
33239
|
-
}
|
|
33240
|
-
}
|
|
33241
|
-
if (Object.keys(decisions).length > 0) {
|
|
33242
|
-
const universe = planKxmMigration(root, { ...options, decisions: {} });
|
|
33243
|
-
const unknown = [];
|
|
33244
|
-
const invalid = [];
|
|
33245
|
-
for (const [key, value] of Object.entries(decisions)) {
|
|
33246
|
-
if (first.decisionKeys.has(key)) continue;
|
|
33247
|
-
const universeAllowed = universe.decisionAllowedValues.get(key);
|
|
33248
|
-
if (!universeAllowed) {
|
|
33249
|
-
unknown.push(key);
|
|
33250
|
-
} else if (!decisionValueAllowed(key, value, universeAllowed)) {
|
|
33251
|
-
invalid.push(key);
|
|
33252
|
-
}
|
|
33253
|
-
}
|
|
33254
|
-
if (unknown.length > 0) {
|
|
33255
|
-
throw new KxmConfigError(unknown.sort(compareCodeUnits6).map((key) => migrateIssue("semantic", "decision_unknown", key, "decision key does not match any current ambiguity")));
|
|
33256
|
-
}
|
|
33257
|
-
const allInvalid = [.../* @__PURE__ */ new Set([...invalid, ...first.invalidDecisions])].sort(compareCodeUnits6);
|
|
33258
|
-
if (allInvalid.length > 0) {
|
|
33259
|
-
throw new KxmConfigError(allInvalid.map((key) => migrateIssue("semantic", "decision_value_invalid", key, "decision value is not one of the plan's allowed values")));
|
|
33260
|
-
}
|
|
33261
|
-
}
|
|
33262
|
-
if (first.ambiguities.length > 0) {
|
|
33263
|
-
return { action: "planned", projectRoot: root, files: [], plan: first.plan };
|
|
33264
|
-
}
|
|
33265
|
-
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") }));
|
|
33266
|
-
const collisions = files.filter((file) => existsSync23(join26(root, ...file.path.split("/"))));
|
|
33267
|
-
if (collisions.length > 0) {
|
|
33268
|
-
throw new KxmConfigError(collisions.map((file) => migrateIssue("semantic", "migration_target_exists", file.path, "target resource already exists; refusing to overwrite")));
|
|
33269
|
-
}
|
|
33270
|
-
const parentIssues = [];
|
|
33271
|
-
for (const file of files) {
|
|
33272
|
-
const segments = file.path.split("/");
|
|
33273
|
-
let current = root;
|
|
33274
|
-
for (const segment of segments.slice(0, -1)) {
|
|
33275
|
-
current = join26(current, segment);
|
|
33276
|
-
if (!existsSync23(current)) continue;
|
|
33277
|
-
const stat = lstatSync8(current);
|
|
33278
|
-
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
33279
|
-
parentIssues.push(migrateIssue("path", "migration_target_parent_invalid", file.path, `migration target parent ${segment} must be a regular directory, not a link`));
|
|
33280
|
-
break;
|
|
33281
|
-
}
|
|
33282
|
-
}
|
|
33283
|
-
}
|
|
33284
|
-
if (parentIssues.length > 0) throw new KxmConfigError(parentIssues);
|
|
33285
|
-
if (options.dryRun) {
|
|
33286
|
-
return { action: "planned", projectRoot: root, files: files.map((file) => file.path), plan: first.plan };
|
|
33287
|
-
}
|
|
33288
|
-
if (!lock) throw new Error("project mutation lock is required to apply a migration");
|
|
33289
|
-
const written = [];
|
|
33290
|
-
try {
|
|
33291
|
-
for (const file of files) {
|
|
33292
|
-
const absolute = join26(root, ...file.path.split("/"));
|
|
33293
|
-
mkdirSync19(join26(absolute, ".."), { recursive: true });
|
|
33294
|
-
written.push(absolute);
|
|
33295
|
-
writeDurable2(absolute, file.bytes);
|
|
33296
|
-
}
|
|
33297
|
-
const bundle = loadKxmProject(root, { ...options, allowUnreceiptedLegacyConfig: true });
|
|
33298
|
-
const receipt = {
|
|
33299
|
-
schema: "kxm.migration-receipt.v1",
|
|
33300
|
-
migrationId: `mig_${sha256Of(`${first.plan.sourceDigest}
|
|
33301
|
-
${bundle.configRevision}`).slice(7, 39)}`,
|
|
33302
|
-
projectId: String(first.plan.projectId),
|
|
33303
|
-
sourceDigest: String(first.plan.sourceDigest),
|
|
33304
|
-
decisionDigest: sha256Of(kxmCanonicalJson(decisionsRecord ?? { schema: "kxm.migration-decision.v1", projectId: first.plan.projectId, projectName: first.plan.projectName, sourceDigest: first.plan.sourceDigest, resolutions: decisions })),
|
|
33305
|
-
configRevision: bundle.configRevision,
|
|
33306
|
-
sources: first.plan.sources,
|
|
33307
|
-
resources: files.map((file) => ({ path: file.path, sha256: sha256Of(file.bytes), bytes: file.bytes.byteLength }))
|
|
33308
|
-
};
|
|
33309
|
-
receipt.receiptSha256 = migrationReceiptSelfHash(receipt);
|
|
33310
|
-
const registry = new KxmSchemaRegistry(options.schemasDir);
|
|
33311
|
-
const receiptIssues = registry.validateMigrationReceipt(receipt, KXM_MIGRATION_RECEIPT_PATH);
|
|
33312
|
-
if (receiptIssues.length > 0) throw new KxmConfigError(receiptIssues);
|
|
33313
|
-
written.push(receiptAbsolute);
|
|
33314
|
-
writeDurable2(receiptAbsolute, Buffer.from((0, import_yaml12.stringify)(receipt, { lineWidth: 0 }), "utf8"));
|
|
33315
|
-
const verified = loadKxmProject(root, options);
|
|
33316
|
-
return {
|
|
33317
|
-
action: "applied",
|
|
33318
|
-
projectRoot: root,
|
|
33319
|
-
receiptPath: KXM_MIGRATION_RECEIPT_PATH,
|
|
33320
|
-
configRevision: verified.configRevision,
|
|
33321
|
-
files: files.map((file) => file.path),
|
|
33322
|
-
plan: first.plan
|
|
33323
|
-
};
|
|
33324
|
-
} catch (error) {
|
|
33325
|
-
for (const absolute of written.reverse()) {
|
|
33326
|
-
try {
|
|
33327
|
-
rmSync9(absolute, { force: true });
|
|
33328
|
-
} catch {
|
|
33329
|
-
}
|
|
33330
|
-
}
|
|
33331
|
-
throw error;
|
|
33332
|
-
}
|
|
33333
|
-
};
|
|
33334
|
-
if (options.dryRun) return execute(void 0);
|
|
33335
|
-
return withKxmLocalBindingLock(root, storeOptions, (lock) => execute(lock));
|
|
33336
|
-
}
|
|
33337
|
-
function verifyKxmMigration(projectRoot, options = {}) {
|
|
33338
|
-
const root = migrationGitRoot(projectRoot);
|
|
33339
|
-
const receiptAbsolute = join26(root, ...KXM_MIGRATION_RECEIPT_PATH.split("/"));
|
|
33340
|
-
if (!existsSync23(receiptAbsolute)) {
|
|
33341
|
-
return {
|
|
33342
|
-
ok: false,
|
|
33343
|
-
projectRoot: root,
|
|
33344
|
-
receiptPath: KXM_MIGRATION_RECEIPT_PATH,
|
|
33345
|
-
issues: [migrateIssue("discovery", "migration_receipt_missing", KXM_MIGRATION_RECEIPT_PATH, "no migration receipt exists")]
|
|
33346
|
-
};
|
|
33347
|
-
}
|
|
33348
|
-
try {
|
|
33349
|
-
const bundle = loadKxmProject(root, options);
|
|
33350
|
-
const receipt = bundle.migrationReceipt;
|
|
33351
|
-
if (!receipt) {
|
|
33352
|
-
if (legacyConfigFilesAt(root).length === 0) {
|
|
33353
|
-
const direct = readKxmMigrationReceipt(root, options);
|
|
33354
|
-
return {
|
|
33355
|
-
ok: false,
|
|
33356
|
-
projectRoot: root,
|
|
33357
|
-
receiptPath: KXM_MIGRATION_RECEIPT_PATH,
|
|
33358
|
-
configRevision: bundle.configRevision,
|
|
33359
|
-
issues: direct.issues.length > 0 ? direct.issues : [migrateIssue("semantic", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "receipt did not validate")]
|
|
33360
|
-
};
|
|
33361
|
-
}
|
|
33362
|
-
return {
|
|
33363
|
-
ok: false,
|
|
33364
|
-
projectRoot: root,
|
|
33365
|
-
receiptPath: KXM_MIGRATION_RECEIPT_PATH,
|
|
33366
|
-
configRevision: bundle.configRevision,
|
|
33367
|
-
issues: [migrateIssue("semantic", "migration_receipt_invalid", KXM_MIGRATION_RECEIPT_PATH, "receipt did not validate during project load")]
|
|
33368
|
-
};
|
|
33369
|
-
}
|
|
33370
|
-
const targetIssues = verifyKxmMigrationReceiptTarget(root, receipt, bundle.resources, bundle.configRevision);
|
|
33371
|
-
return {
|
|
33372
|
-
ok: targetIssues.length === 0,
|
|
33373
|
-
projectRoot: root,
|
|
33374
|
-
receiptPath: KXM_MIGRATION_RECEIPT_PATH,
|
|
33375
|
-
configRevision: bundle.configRevision,
|
|
33376
|
-
issues: targetIssues
|
|
33377
|
-
};
|
|
33378
|
-
} catch (error) {
|
|
33379
|
-
if (error instanceof KxmConfigError) {
|
|
33380
|
-
return { ok: false, projectRoot: root, receiptPath: KXM_MIGRATION_RECEIPT_PATH, issues: error.issues };
|
|
33381
|
-
}
|
|
33382
|
-
throw error;
|
|
33383
|
-
}
|
|
33384
|
-
}
|
|
33385
|
-
|
|
33386
31764
|
// plugins/kxm/src/cli/project.ts
|
|
33387
31765
|
var kxmDriveCliSeams = {};
|
|
33388
31766
|
function initPlanPayload(plan) {
|
|
@@ -33480,7 +31858,7 @@ async function cmdKxmInit(runtime, options, postHooks) {
|
|
|
33480
31858
|
if (runtime.dryRun) {
|
|
33481
31859
|
return finishInit(0, `init plan: ${initialized.plan.mode}`);
|
|
33482
31860
|
}
|
|
33483
|
-
const next = initialized.plan.mode === "
|
|
31861
|
+
const next = initialized.plan.mode === "legacy" ? "legacy state is not migrated by this build: initialise a fresh project directory and copy the YAML definitions you want to keep" : 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";
|
|
33484
31862
|
return finishInit(1, next);
|
|
33485
31863
|
} catch (error) {
|
|
33486
31864
|
if (error instanceof KxmConfigError) {
|
|
@@ -33500,141 +31878,11 @@ async function cmdKxmInit(runtime, options, postHooks) {
|
|
|
33500
31878
|
return 1;
|
|
33501
31879
|
}
|
|
33502
31880
|
}
|
|
33503
|
-
async function cmdKxmMigratePlan(runtime) {
|
|
33504
|
-
if (runtime.workspaceFlag !== void 0) {
|
|
33505
|
-
print(runtime.io, runtime.json, {
|
|
33506
|
-
ok: false,
|
|
33507
|
-
command: "migrate plan",
|
|
33508
|
-
error: "workspace_option_unsupported"
|
|
33509
|
-
}, "kxm migrate discovers the authoritative Git root from the current directory; --workspace is not supported");
|
|
33510
|
-
return 2;
|
|
33511
|
-
}
|
|
33512
|
-
try {
|
|
33513
|
-
const result = planKxmMigration(runtime.cwd, {});
|
|
33514
|
-
const ambiguities = result.plan.ambiguities ?? [];
|
|
33515
|
-
const unmapped = result.plan.unmapped ?? [];
|
|
33516
|
-
const payload = {
|
|
33517
|
-
ok: result.plan.canApply === true,
|
|
33518
|
-
command: "migrate plan",
|
|
33519
|
-
plan: result.plan,
|
|
33520
|
-
plannedOnly: result.plan.canApply !== true
|
|
33521
|
-
};
|
|
33522
|
-
if (result.plan.canApply === true) {
|
|
33523
|
-
print(runtime.io, runtime.json, payload, `migration plan: ${ambiguities.length} ambiguities, ${unmapped.length} preserved fields; ready to apply`);
|
|
33524
|
-
return 0;
|
|
33525
|
-
}
|
|
33526
|
-
print(
|
|
33527
|
-
runtime.io,
|
|
33528
|
-
runtime.json,
|
|
33529
|
-
payload,
|
|
33530
|
-
`migration plan requires ${ambiguities.length} reviewed decision(s):
|
|
33531
|
-
${ambiguities.map((candidate) => ` - ${candidate.key}: ${candidate.message}`).join("\n")}`
|
|
33532
|
-
);
|
|
33533
|
-
return 1;
|
|
33534
|
-
} catch (error) {
|
|
33535
|
-
if (error instanceof KxmConfigError) {
|
|
33536
|
-
print(runtime.io, runtime.json, { ok: false, command: "migrate plan", error: "migration_plan_failed", issues: error.issues }, `migration plan failed: ${error.message}`);
|
|
33537
|
-
return 1;
|
|
33538
|
-
}
|
|
33539
|
-
print(runtime.io, runtime.json, { ok: false, command: "migrate plan", error: "migration_plan_io_failed" }, "migration plan failed because a local filesystem operation did not complete");
|
|
33540
|
-
return 1;
|
|
33541
|
-
}
|
|
33542
|
-
}
|
|
33543
|
-
async function cmdKxmMigrateApply(runtime, options) {
|
|
33544
|
-
if (runtime.workspaceFlag !== void 0) {
|
|
33545
|
-
print(runtime.io, runtime.json, {
|
|
33546
|
-
ok: false,
|
|
33547
|
-
command: "migrate apply",
|
|
33548
|
-
error: "workspace_option_unsupported"
|
|
33549
|
-
}, "kxm migrate discovers the authoritative Git root from the current directory; --workspace is not supported");
|
|
33550
|
-
return 2;
|
|
33551
|
-
}
|
|
33552
|
-
try {
|
|
33553
|
-
const result = applyKxmMigration(runtime.cwd, {
|
|
33554
|
-
...options.decisions?.trim() ? { decisionsFile: options.decisions.trim() } : {},
|
|
33555
|
-
...options.projectId?.trim() ? { projectId: options.projectId.trim() } : {},
|
|
33556
|
-
...options.name?.trim() ? { projectName: options.name.trim() } : {},
|
|
33557
|
-
localStateRoot: kxmUserStateRoot({ env: runtime.env }),
|
|
33558
|
-
dryRun: runtime.dryRun
|
|
33559
|
-
});
|
|
33560
|
-
const payload = {
|
|
33561
|
-
ok: result.action !== "planned" || runtime.dryRun === true && result.plan?.canApply === true,
|
|
33562
|
-
command: "migrate apply",
|
|
33563
|
-
action: result.action,
|
|
33564
|
-
files: result.files,
|
|
33565
|
-
...result.configRevision ? { configRevision: result.configRevision } : {},
|
|
33566
|
-
...result.receiptPath ? { receiptPath: result.receiptPath } : {},
|
|
33567
|
-
plannedOnly: result.action === "planned"
|
|
33568
|
-
};
|
|
33569
|
-
if (result.action === "applied") {
|
|
33570
|
-
print(runtime.io, runtime.json, payload, `migration applied: ${result.files.length} resources installed, receipt at ${result.receiptPath ?? ""}`);
|
|
33571
|
-
return 0;
|
|
33572
|
-
}
|
|
33573
|
-
if (result.action === "already-migrated") {
|
|
33574
|
-
print(runtime.io, runtime.json, payload, "migration receipt already exists; nothing to apply");
|
|
33575
|
-
return 0;
|
|
33576
|
-
}
|
|
33577
|
-
if (runtime.dryRun && result.plan?.canApply === true) {
|
|
33578
|
-
print(runtime.io, runtime.json, payload, `migration dry run: ${result.files.length} resources would be installed`);
|
|
33579
|
-
return 0;
|
|
33580
|
-
}
|
|
33581
|
-
const ambiguities = result.plan?.ambiguities ?? [];
|
|
33582
|
-
print(
|
|
33583
|
-
runtime.io,
|
|
33584
|
-
runtime.json,
|
|
33585
|
-
{ ...payload, plan: result.plan },
|
|
33586
|
-
`migration blocked by ${ambiguities.length} unresolved decision(s); review 'kxm migrate plan' and pass --decisions:
|
|
33587
|
-
${ambiguities.map((candidate) => ` - ${candidate.key}: ${candidate.message}`).join("\n")}`
|
|
33588
|
-
);
|
|
33589
|
-
return 1;
|
|
33590
|
-
} catch (error) {
|
|
33591
|
-
if (error instanceof KxmConfigError) {
|
|
33592
|
-
print(runtime.io, runtime.json, { ok: false, command: "migrate apply", error: "migration_apply_failed", issues: error.issues }, `migration apply failed: ${error.message}`);
|
|
33593
|
-
return 1;
|
|
33594
|
-
}
|
|
33595
|
-
print(runtime.io, runtime.json, { ok: false, command: "migrate apply", error: "migration_apply_io_failed" }, "migration apply failed because a local filesystem operation did not complete");
|
|
33596
|
-
return 1;
|
|
33597
|
-
}
|
|
33598
|
-
}
|
|
33599
|
-
async function cmdKxmMigrateVerify(runtime) {
|
|
33600
|
-
if (runtime.workspaceFlag !== void 0) {
|
|
33601
|
-
print(runtime.io, runtime.json, {
|
|
33602
|
-
ok: false,
|
|
33603
|
-
command: "migrate verify",
|
|
33604
|
-
error: "workspace_option_unsupported"
|
|
33605
|
-
}, "kxm migrate discovers the authoritative Git root from the current directory; --workspace is not supported");
|
|
33606
|
-
return 2;
|
|
33607
|
-
}
|
|
33608
|
-
let result;
|
|
33609
|
-
try {
|
|
33610
|
-
result = verifyKxmMigration(runtime.cwd, {});
|
|
33611
|
-
} catch (error) {
|
|
33612
|
-
if (error instanceof KxmConfigError) {
|
|
33613
|
-
print(runtime.io, runtime.json, { ok: false, command: "migrate verify", error: "migration_verify_failed", issues: error.issues }, `migration verification failed: ${error.message}`);
|
|
33614
|
-
return 1;
|
|
33615
|
-
}
|
|
33616
|
-
print(runtime.io, runtime.json, { ok: false, command: "migrate verify", error: "migration_verify_io_failed" }, "migration verification failed because a local filesystem operation did not complete");
|
|
33617
|
-
return 1;
|
|
33618
|
-
}
|
|
33619
|
-
const payload = {
|
|
33620
|
-
ok: result.ok,
|
|
33621
|
-
command: "migrate verify",
|
|
33622
|
-
...result.configRevision ? { configRevision: result.configRevision } : {},
|
|
33623
|
-
issues: result.issues
|
|
33624
|
-
};
|
|
33625
|
-
if (result.ok) {
|
|
33626
|
-
print(runtime.io, runtime.json, payload, `migration receipt verified: legacy sources unchanged, target bundle matches ${result.configRevision ?? ""}`);
|
|
33627
|
-
return 0;
|
|
33628
|
-
}
|
|
33629
|
-
print(runtime.io, runtime.json, payload, `migration verification failed:
|
|
33630
|
-
${result.issues.map((issue3) => ` - ${issue3.file}: ${issue3.code}: ${issue3.message}`).join("\n")}`);
|
|
33631
|
-
return 1;
|
|
33632
|
-
}
|
|
33633
31881
|
async function cmdBackup(runtime, options) {
|
|
33634
31882
|
try {
|
|
33635
31883
|
const { manifest, outDir } = createBackup({
|
|
33636
31884
|
projectRoot: runtime.cwd,
|
|
33637
|
-
...options.out ? { outDir:
|
|
31885
|
+
...options.out ? { outDir: resolve19(runtime.cwd, options.out) } : {}
|
|
33638
31886
|
});
|
|
33639
31887
|
const payload = {
|
|
33640
31888
|
ok: true,
|
|
@@ -33646,7 +31894,7 @@ async function cmdBackup(runtime, options) {
|
|
|
33646
31894
|
const summary = [
|
|
33647
31895
|
`Created SQLite backup with ${manifest.stores.length} store(s):`,
|
|
33648
31896
|
...manifest.stores.map((s) => ` - ${s.storeId}: ${s.sourcePath} -> ${s.backupFile} (schema v${s.schemaVersion}, ${s.bytes} bytes, sha256 ${s.sha256.slice(0, 12)}...)`),
|
|
33649
|
-
`Manifest: ${
|
|
31897
|
+
`Manifest: ${join26(outDir, "manifest.json")}`
|
|
33650
31898
|
].join("\n");
|
|
33651
31899
|
print(runtime.io, runtime.json, payload, summary);
|
|
33652
31900
|
return 0;
|
|
@@ -33661,7 +31909,7 @@ async function cmdBackup(runtime, options) {
|
|
|
33661
31909
|
}
|
|
33662
31910
|
async function cmdRestore(runtime, manifestArg) {
|
|
33663
31911
|
try {
|
|
33664
|
-
const result = restoreBackup(
|
|
31912
|
+
const result = restoreBackup(resolve19(runtime.cwd, manifestArg), {
|
|
33665
31913
|
projectRoot: runtime.cwd
|
|
33666
31914
|
});
|
|
33667
31915
|
const payload = {
|
|
@@ -33866,7 +32114,7 @@ function parseDriveWaitTimeoutMs(raw) {
|
|
|
33866
32114
|
return value;
|
|
33867
32115
|
}
|
|
33868
32116
|
function sleepMs(ms) {
|
|
33869
|
-
return new Promise((
|
|
32117
|
+
return new Promise((resolve30) => setTimeout(resolve30, ms));
|
|
33870
32118
|
}
|
|
33871
32119
|
function driveWaitCompleted(drive) {
|
|
33872
32120
|
return drive?.verified === true && drive.receipt?.settlement?.kind === "terminal" && drive.receipt.settlement.status === "completed";
|
|
@@ -34011,7 +32259,7 @@ async function selectInventoryModel(runtime, requested) {
|
|
|
34011
32259
|
if (runtime.json || !process.stdin.isTTY || models.length === 0) return void 0;
|
|
34012
32260
|
runtime.io.stdout(models.slice(0, 100).map((model, index2) => `${index2 + 1}. ${model}`).join("\n") + "\nSelect model number: ");
|
|
34013
32261
|
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
34014
|
-
const answer = await new Promise((
|
|
32262
|
+
const answer = await new Promise((resolve30) => rl.once("line", resolve30));
|
|
34015
32263
|
rl.close();
|
|
34016
32264
|
const index = Number.parseInt(answer.trim(), 10) - 1;
|
|
34017
32265
|
return Number.isInteger(index) && index >= 0 && index < models.length ? models[index] : void 0;
|
|
@@ -34037,7 +32285,7 @@ async function cmdModelsScreen(runtime) {
|
|
|
34037
32285
|
return 2;
|
|
34038
32286
|
}
|
|
34039
32287
|
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
34040
|
-
const ask = (q2) => new Promise((
|
|
32288
|
+
const ask = (q2) => new Promise((resolve30) => rl.question(q2, resolve30));
|
|
34041
32289
|
try {
|
|
34042
32290
|
while (true) {
|
|
34043
32291
|
const policy = loadRoutePolicy(runtime.dirs.workdir);
|
|
@@ -34345,12 +32593,12 @@ async function cmdStudioLayout(runtime, workflowPath) {
|
|
|
34345
32593
|
const projectRoot = discoverKxmProjectRoot(runtime.cwd) ?? runtime.cwd;
|
|
34346
32594
|
let filePath = workflowPath;
|
|
34347
32595
|
if (!filePath) {
|
|
34348
|
-
filePath =
|
|
32596
|
+
filePath = resolve20(projectRoot, ".kxm", "workflows", "default.yaml");
|
|
34349
32597
|
}
|
|
34350
32598
|
let yamlContent;
|
|
34351
32599
|
let workflowId = "default";
|
|
34352
|
-
if (
|
|
34353
|
-
yamlContent =
|
|
32600
|
+
if (existsSync23(filePath)) {
|
|
32601
|
+
yamlContent = readFileSync22(filePath, "utf8");
|
|
34354
32602
|
} else {
|
|
34355
32603
|
yamlContent = `schema: kxm.workflow.v1
|
|
34356
32604
|
description: Feature implementation workflow
|
|
@@ -34390,7 +32638,7 @@ steps:
|
|
|
34390
32638
|
maxTransitions: 2
|
|
34391
32639
|
`;
|
|
34392
32640
|
}
|
|
34393
|
-
const parsedYaml = (0,
|
|
32641
|
+
const parsedYaml = (0, import_yaml12.parse)(yamlContent);
|
|
34394
32642
|
const plan = compileKxmWorkflow({ id: workflowId, value: parsedYaml });
|
|
34395
32643
|
const layout = generateStudioLayout(plan);
|
|
34396
32644
|
print(runtime.io, runtime.json, { ok: true, command: "studio layout", layout }, JSON.stringify(layout, null, 2));
|
|
@@ -34423,16 +32671,16 @@ async function cmdStudioServe(runtime, options) {
|
|
|
34423
32671
|
sessionToken,
|
|
34424
32672
|
planProvider: () => {
|
|
34425
32673
|
try {
|
|
34426
|
-
const wfDir =
|
|
34427
|
-
const defaultPath =
|
|
34428
|
-
let targetPath =
|
|
34429
|
-
if (!targetPath &&
|
|
32674
|
+
const wfDir = join27(runtime.cwd, ".kxm", "workflows");
|
|
32675
|
+
const defaultPath = join27(wfDir, "default.yaml");
|
|
32676
|
+
let targetPath = existsSync23(defaultPath) ? defaultPath : void 0;
|
|
32677
|
+
if (!targetPath && existsSync23(wfDir)) {
|
|
34430
32678
|
const yml = readdirSync8(wfDir).find((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
|
|
34431
|
-
if (yml) targetPath =
|
|
32679
|
+
if (yml) targetPath = join27(wfDir, yml);
|
|
34432
32680
|
}
|
|
34433
|
-
if (targetPath &&
|
|
34434
|
-
const raw =
|
|
34435
|
-
const parsed = (0,
|
|
32681
|
+
if (targetPath && existsSync23(targetPath)) {
|
|
32682
|
+
const raw = readFileSync22(targetPath, "utf8");
|
|
32683
|
+
const parsed = (0, import_yaml12.parse)(raw);
|
|
34436
32684
|
const wfId = basename6(targetPath).replace(/\.(yaml|yml)$/, "");
|
|
34437
32685
|
return compileKxmWorkflow({ id: wfId, value: parsed });
|
|
34438
32686
|
}
|
|
@@ -34481,14 +32729,14 @@ Press Ctrl+C to stop.
|
|
|
34481
32729
|
}
|
|
34482
32730
|
|
|
34483
32731
|
// plugins/kxm/src/cli/context-skills.ts
|
|
34484
|
-
import { readFileSync as
|
|
34485
|
-
import { join as
|
|
32732
|
+
import { readFileSync as readFileSync25 } from "node:fs";
|
|
32733
|
+
import { join as join31, relative as relative5 } from "node:path";
|
|
34486
32734
|
|
|
34487
32735
|
// plugins/kxm/src/memory.ts
|
|
34488
|
-
var
|
|
32736
|
+
var import_yaml13 = __toESM(require_dist(), 1);
|
|
34489
32737
|
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
34490
|
-
import { existsSync as
|
|
34491
|
-
import { extname as extname2, join as
|
|
32738
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync19, readdirSync as readdirSync9, readFileSync as readFileSync23, writeFileSync as writeFileSync18 } from "node:fs";
|
|
32739
|
+
import { extname as extname2, join as join28, resolve as resolve21 } from "node:path";
|
|
34492
32740
|
var MEMORY_SCHEMA = "kxm.memory.v1";
|
|
34493
32741
|
var MEMORY_BRIEF_SCHEMA = "kxm.memory-brief.v1";
|
|
34494
32742
|
var MEMORY_MARKER_START = "<!-- kxm:memory:start -->";
|
|
@@ -34521,7 +32769,7 @@ function parseFrontmatter(content) {
|
|
|
34521
32769
|
}
|
|
34522
32770
|
function parseMemoryRecord(raw, filename = "memory.md") {
|
|
34523
32771
|
const { frontmatter, body } = parseFrontmatter(raw);
|
|
34524
|
-
const data = (0,
|
|
32772
|
+
const data = (0, import_yaml13.parse)(frontmatter);
|
|
34525
32773
|
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
34526
32774
|
throw new Error(`invalid YAML frontmatter in ${filename}`);
|
|
34527
32775
|
}
|
|
@@ -34601,7 +32849,7 @@ function formatMemoryRecord(record) {
|
|
|
34601
32849
|
lifecycle: record.lifecycle,
|
|
34602
32850
|
evidenceRefs: record.evidenceRefs
|
|
34603
32851
|
};
|
|
34604
|
-
const yamlText = (0,
|
|
32852
|
+
const yamlText = (0, import_yaml13.stringify)(frontmatter).trim();
|
|
34605
32853
|
const bodyText = record.body?.trim() ?? "";
|
|
34606
32854
|
return bodyText ? `---
|
|
34607
32855
|
${yamlText}
|
|
@@ -34614,21 +32862,21 @@ ${yamlText}
|
|
|
34614
32862
|
`;
|
|
34615
32863
|
}
|
|
34616
32864
|
function memoryDirectories(repoRoot) {
|
|
34617
|
-
const root =
|
|
34618
|
-
const memoryDir =
|
|
34619
|
-
const candidatesDir =
|
|
32865
|
+
const root = resolve21(repoRoot);
|
|
32866
|
+
const memoryDir = join28(root, ".kxm", "memory");
|
|
32867
|
+
const candidatesDir = join28(memoryDir, "candidates");
|
|
34620
32868
|
return { memoryDir, candidatesDir };
|
|
34621
32869
|
}
|
|
34622
32870
|
function loadAuthoredMemory(repoRoot) {
|
|
34623
32871
|
const { memoryDir } = memoryDirectories(repoRoot);
|
|
34624
|
-
if (!
|
|
32872
|
+
if (!existsSync24(memoryDir)) return [];
|
|
34625
32873
|
const records = [];
|
|
34626
32874
|
const entries = readdirSync9(memoryDir, { withFileTypes: true });
|
|
34627
32875
|
for (const entry of entries) {
|
|
34628
32876
|
if (entry.isFile() && extname2(entry.name) === ".md") {
|
|
34629
|
-
const fullPath =
|
|
32877
|
+
const fullPath = join28(memoryDir, entry.name);
|
|
34630
32878
|
try {
|
|
34631
|
-
const text =
|
|
32879
|
+
const text = readFileSync23(fullPath, "utf8");
|
|
34632
32880
|
const record = parseMemoryRecord(text, entry.name);
|
|
34633
32881
|
if (record.lifecycle === "active") {
|
|
34634
32882
|
records.push(record);
|
|
@@ -34642,7 +32890,7 @@ function loadAuthoredMemory(repoRoot) {
|
|
|
34642
32890
|
}
|
|
34643
32891
|
function createMemoryNote(repoRoot, summary, options = {}) {
|
|
34644
32892
|
const { candidatesDir } = memoryDirectories(repoRoot);
|
|
34645
|
-
|
|
32893
|
+
mkdirSync19(candidatesDir, { recursive: true });
|
|
34646
32894
|
const scope = options.scope ?? "project";
|
|
34647
32895
|
if (!VALID_SCOPES.has(scope)) {
|
|
34648
32896
|
throw new Error(`invalid memory note scope: ${scope}; must be one of agent, project, run, operator`);
|
|
@@ -34667,8 +32915,8 @@ function createMemoryNote(repoRoot, summary, options = {}) {
|
|
|
34667
32915
|
evidenceRefs: [],
|
|
34668
32916
|
...options.body ? { body: options.body.trim() } : {}
|
|
34669
32917
|
};
|
|
34670
|
-
const targetPath =
|
|
34671
|
-
|
|
32918
|
+
const targetPath = join28(candidatesDir, `${id}.md`);
|
|
32919
|
+
writeFileSync18(targetPath, formatMemoryRecord(record), "utf8");
|
|
34672
32920
|
return { record, path: targetPath };
|
|
34673
32921
|
}
|
|
34674
32922
|
function generateMemoryBrief(repoRoot) {
|
|
@@ -34704,8 +32952,8 @@ function formatHarnessMemoryBlock(records) {
|
|
|
34704
32952
|
}
|
|
34705
32953
|
function updateHarnessDocument(filePath, block, defaultHeader) {
|
|
34706
32954
|
let original = "";
|
|
34707
|
-
if (
|
|
34708
|
-
original =
|
|
32955
|
+
if (existsSync24(filePath)) {
|
|
32956
|
+
original = readFileSync23(filePath, "utf8");
|
|
34709
32957
|
}
|
|
34710
32958
|
let updated = "";
|
|
34711
32959
|
if (original.includes(MEMORY_MARKER_START) && original.includes(MEMORY_MARKER_END)) {
|
|
@@ -34733,25 +32981,25 @@ ${block}
|
|
|
34733
32981
|
`;
|
|
34734
32982
|
}
|
|
34735
32983
|
if (updated !== original) {
|
|
34736
|
-
|
|
32984
|
+
writeFileSync18(filePath, updated, "utf8");
|
|
34737
32985
|
return true;
|
|
34738
32986
|
}
|
|
34739
32987
|
return false;
|
|
34740
32988
|
}
|
|
34741
32989
|
function syncHarnessMemory(repoRoot) {
|
|
34742
|
-
const root =
|
|
32990
|
+
const root = resolve21(repoRoot);
|
|
34743
32991
|
const records = loadAuthoredMemory(root);
|
|
34744
32992
|
const block = formatHarnessMemoryBlock(records);
|
|
34745
32993
|
const updated = [];
|
|
34746
32994
|
const created = [];
|
|
34747
|
-
const agentsPath =
|
|
32995
|
+
const agentsPath = join28(root, "AGENTS.md");
|
|
34748
32996
|
const agentsHeader = "# AGENTS\n\nFollow project instructions.\n";
|
|
34749
|
-
const agentsExisted =
|
|
32997
|
+
const agentsExisted = existsSync24(agentsPath);
|
|
34750
32998
|
if (updateHarnessDocument(agentsPath, block, agentsHeader)) {
|
|
34751
32999
|
if (agentsExisted) updated.push("AGENTS.md");
|
|
34752
33000
|
else created.push("AGENTS.md");
|
|
34753
33001
|
}
|
|
34754
|
-
const claudePath =
|
|
33002
|
+
const claudePath = join28(root, "CLAUDE.md");
|
|
34755
33003
|
const claudeHeader = `# KXM (Claude)
|
|
34756
33004
|
|
|
34757
33005
|
Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
@@ -34763,12 +33011,12 @@ rotation, not a sole writer. If \`grok\` is logged out, never bill Grok through
|
|
|
34763
33011
|
use a relief route Tracking **admits**, or stop and name the limits hit. Your reviews are
|
|
34764
33012
|
artifacts, not hub \`peer-reply\` evidence.
|
|
34765
33013
|
`;
|
|
34766
|
-
const claudeExisted =
|
|
33014
|
+
const claudeExisted = existsSync24(claudePath);
|
|
34767
33015
|
if (updateHarnessDocument(claudePath, block, claudeHeader)) {
|
|
34768
33016
|
if (claudeExisted) updated.push("CLAUDE.md");
|
|
34769
33017
|
else created.push("CLAUDE.md");
|
|
34770
33018
|
}
|
|
34771
|
-
const geminiPath =
|
|
33019
|
+
const geminiPath = join28(root, "GEMINI.md");
|
|
34772
33020
|
const geminiHeader = `# KXM (Gemini / Antigravity)
|
|
34773
33021
|
|
|
34774
33022
|
Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
@@ -34779,7 +33027,7 @@ Google goes through the \`antigravity\` **Pi provider** (Tracking \u2192 Decided
|
|
|
34779
33027
|
Current admissions come from Tracking and \`kxm harness list\`. Starting rotation
|
|
34780
33028
|
remains Grok.
|
|
34781
33029
|
`;
|
|
34782
|
-
const geminiExisted =
|
|
33030
|
+
const geminiExisted = existsSync24(geminiPath);
|
|
34783
33031
|
if (updateHarnessDocument(geminiPath, block, geminiHeader)) {
|
|
34784
33032
|
if (geminiExisted) updated.push("GEMINI.md");
|
|
34785
33033
|
else created.push("GEMINI.md");
|
|
@@ -34788,10 +33036,10 @@ remains Grok.
|
|
|
34788
33036
|
}
|
|
34789
33037
|
|
|
34790
33038
|
// plugins/kxm/src/skills.ts
|
|
34791
|
-
var
|
|
34792
|
-
import { createHash as
|
|
34793
|
-
import { existsSync as
|
|
34794
|
-
import { join as
|
|
33039
|
+
var import_yaml14 = __toESM(require_dist(), 1);
|
|
33040
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
33041
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync20, readdirSync as readdirSync10, readFileSync as readFileSync24, renameSync as renameSync7, rmSync as rmSync9, statSync as statSync3, writeFileSync as writeFileSync19 } from "node:fs";
|
|
33042
|
+
import { join as join29 } from "node:path";
|
|
34795
33043
|
var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
|
|
34796
33044
|
var SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
|
|
34797
33045
|
var SKILL_DECISION_SCHEMA = "kxm.skill-decision.v1";
|
|
@@ -34814,7 +33062,7 @@ var SkillLifecycleError = class extends Error {
|
|
|
34814
33062
|
}
|
|
34815
33063
|
};
|
|
34816
33064
|
function skillContentSha256(content) {
|
|
34817
|
-
return
|
|
33065
|
+
return createHash13("sha256").update(content, "utf8").digest("hex");
|
|
34818
33066
|
}
|
|
34819
33067
|
function skillIdFor(name, contentSha256) {
|
|
34820
33068
|
const slug = name.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
@@ -34832,7 +33080,7 @@ function parseSkillFrontmatter(content) {
|
|
|
34832
33080
|
return { frontmatter: null, body: content };
|
|
34833
33081
|
}
|
|
34834
33082
|
try {
|
|
34835
|
-
const parsed = (0,
|
|
33083
|
+
const parsed = (0, import_yaml14.parse)(rawFm);
|
|
34836
33084
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
34837
33085
|
return { frontmatter: parsed, body: rawBody };
|
|
34838
33086
|
}
|
|
@@ -34885,48 +33133,48 @@ var SkillLifecycle = class {
|
|
|
34885
33133
|
this.allowOptimizationEvals = options.allowOptimizationEvals === true;
|
|
34886
33134
|
}
|
|
34887
33135
|
dir(state) {
|
|
34888
|
-
return
|
|
33136
|
+
return join29(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
|
|
34889
33137
|
}
|
|
34890
33138
|
historyFile(id) {
|
|
34891
|
-
return
|
|
33139
|
+
return join29(this.root, "history", `${id}.jsonl`);
|
|
34892
33140
|
}
|
|
34893
33141
|
paths(state, id) {
|
|
34894
|
-
const dir =
|
|
34895
|
-
return { dir, metadata:
|
|
33142
|
+
const dir = join29(this.dir(state), id);
|
|
33143
|
+
return { dir, metadata: join29(dir, "metadata.json"), skill: join29(dir, "SKILL.md") };
|
|
34896
33144
|
}
|
|
34897
33145
|
appendHistory(id, record) {
|
|
34898
|
-
|
|
33146
|
+
mkdirSync20(join29(this.root, "history"), { recursive: true });
|
|
34899
33147
|
const line = `${JSON.stringify(record)}
|
|
34900
33148
|
`;
|
|
34901
|
-
if (
|
|
34902
|
-
const existing =
|
|
33149
|
+
if (existsSync25(this.historyFile(id))) {
|
|
33150
|
+
const existing = readFileSync24(this.historyFile(id), "utf8");
|
|
34903
33151
|
const lines = existing.split("\n").filter((entry) => entry.trim());
|
|
34904
|
-
|
|
33152
|
+
writeFileSync19(this.historyFile(id), [...lines.slice(-499), line.trim()].join("\n") + "\n");
|
|
34905
33153
|
} else {
|
|
34906
|
-
|
|
33154
|
+
writeFileSync19(this.historyFile(id), line);
|
|
34907
33155
|
}
|
|
34908
33156
|
}
|
|
34909
33157
|
history(id) {
|
|
34910
33158
|
const file = this.historyFile(id);
|
|
34911
|
-
if (!
|
|
34912
|
-
return
|
|
33159
|
+
if (!existsSync25(file)) return [];
|
|
33160
|
+
return readFileSync24(file, "utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
34913
33161
|
}
|
|
34914
33162
|
readMetadata(state, id) {
|
|
34915
33163
|
const { metadata } = this.paths(state, id);
|
|
34916
|
-
if (!
|
|
33164
|
+
if (!existsSync25(metadata)) {
|
|
34917
33165
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${state}`);
|
|
34918
33166
|
}
|
|
34919
|
-
return JSON.parse(
|
|
33167
|
+
return JSON.parse(readFileSync24(metadata, "utf8"));
|
|
34920
33168
|
}
|
|
34921
33169
|
move(from, to, id) {
|
|
34922
|
-
const fromDir =
|
|
34923
|
-
const toDir =
|
|
34924
|
-
if (!
|
|
33170
|
+
const fromDir = join29(this.dir(from), id);
|
|
33171
|
+
const toDir = join29(this.dir(to), id);
|
|
33172
|
+
if (!existsSync25(fromDir)) {
|
|
34925
33173
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${from}`);
|
|
34926
33174
|
}
|
|
34927
|
-
|
|
34928
|
-
if (
|
|
34929
|
-
|
|
33175
|
+
mkdirSync20(this.dir(to), { recursive: true });
|
|
33176
|
+
if (existsSync25(toDir)) rmSync9(toDir, { recursive: true, force: true });
|
|
33177
|
+
renameSync7(fromDir, toDir);
|
|
34930
33178
|
}
|
|
34931
33179
|
/** Submit a new skill candidate. Content is redacted of secret material at
|
|
34932
33180
|
* creation; the ID is derived from name + content hash. */
|
|
@@ -34968,7 +33216,7 @@ var SkillLifecycle = class {
|
|
|
34968
33216
|
const contentSha256 = skillContentSha256(content);
|
|
34969
33217
|
const id = skillIdFor(name, contentSha256);
|
|
34970
33218
|
const { dir, metadata, skill } = this.paths("candidate", id);
|
|
34971
|
-
if (
|
|
33219
|
+
if (existsSync25(metadata)) {
|
|
34972
33220
|
throw new SkillLifecycleError(
|
|
34973
33221
|
"skill_candidate_exists",
|
|
34974
33222
|
`identical candidate ${id} already exists; changed behavior requires changed content`
|
|
@@ -34987,9 +33235,9 @@ var SkillLifecycle = class {
|
|
|
34987
33235
|
createdAt: this.now(),
|
|
34988
33236
|
...input.supersedes ? { supersedes: input.supersedes } : {}
|
|
34989
33237
|
};
|
|
34990
|
-
|
|
34991
|
-
|
|
34992
|
-
|
|
33238
|
+
mkdirSync20(dir, { recursive: true });
|
|
33239
|
+
writeFileSync19(skill, content);
|
|
33240
|
+
writeFileSync19(metadata, `${JSON.stringify(record, null, 2)}
|
|
34993
33241
|
`);
|
|
34994
33242
|
this.appendHistory(id, { schema: "kxm.skill-history-event.v1", event: "candidate_created", by: createdBy, supersedes: input.supersedes, at: record.createdAt });
|
|
34995
33243
|
return record;
|
|
@@ -35078,18 +33326,18 @@ var SkillLifecycle = class {
|
|
|
35078
33326
|
};
|
|
35079
33327
|
const candidatePaths = this.paths("candidate", candidateId);
|
|
35080
33328
|
const promotedPaths = this.paths("promoted", candidateId);
|
|
35081
|
-
|
|
35082
|
-
const skillContent =
|
|
35083
|
-
const metadataContent =
|
|
35084
|
-
|
|
35085
|
-
|
|
35086
|
-
const patchesDir =
|
|
35087
|
-
|
|
35088
|
-
const patchPath =
|
|
33329
|
+
mkdirSync20(promotedPaths.dir, { recursive: true });
|
|
33330
|
+
const skillContent = readFileSync24(candidatePaths.skill, "utf8");
|
|
33331
|
+
const metadataContent = readFileSync24(candidatePaths.metadata, "utf8");
|
|
33332
|
+
writeFileSync19(promotedPaths.skill, skillContent);
|
|
33333
|
+
writeFileSync19(promotedPaths.metadata, metadataContent);
|
|
33334
|
+
const patchesDir = join29(this.root, "patches");
|
|
33335
|
+
mkdirSync20(patchesDir, { recursive: true });
|
|
33336
|
+
const patchPath = join29(patchesDir, `${candidateId}.patch`);
|
|
35089
33337
|
const relSkillPath = `.kxm/skills/promoted/${candidateId}/SKILL.md`;
|
|
35090
33338
|
const relMetaPath = `.kxm/skills/promoted/${candidateId}/metadata.json`;
|
|
35091
33339
|
const patch = `${createUnifiedPatch(relSkillPath, skillContent)}${createUnifiedPatch(relMetaPath, metadataContent)}`;
|
|
35092
|
-
|
|
33340
|
+
writeFileSync19(patchPath, patch, "utf8");
|
|
35093
33341
|
this.appendHistory(candidateId, record);
|
|
35094
33342
|
return { ...metadata, patch, patchPath };
|
|
35095
33343
|
}
|
|
@@ -35113,7 +33361,7 @@ var SkillLifecycle = class {
|
|
|
35113
33361
|
verify(state, id) {
|
|
35114
33362
|
const metadata = this.readMetadata(state, id);
|
|
35115
33363
|
const { skill } = this.paths(state, id);
|
|
35116
|
-
const content =
|
|
33364
|
+
const content = readFileSync24(skill, "utf8");
|
|
35117
33365
|
if (skillContentSha256(content) !== metadata.contentSha256) {
|
|
35118
33366
|
throw new SkillLifecycleError(
|
|
35119
33367
|
"skill_integrity_violation",
|
|
@@ -35131,7 +33379,7 @@ var SkillLifecycle = class {
|
|
|
35131
33379
|
}
|
|
35132
33380
|
list(state) {
|
|
35133
33381
|
const dir = this.dir(state);
|
|
35134
|
-
if (!
|
|
33382
|
+
if (!existsSync25(dir)) return [];
|
|
35135
33383
|
const ids = readdirSorted(dir);
|
|
35136
33384
|
return ids.map((id) => {
|
|
35137
33385
|
try {
|
|
@@ -35144,7 +33392,7 @@ var SkillLifecycle = class {
|
|
|
35144
33392
|
read(state, id) {
|
|
35145
33393
|
const metadata = this.readMetadata(state, id);
|
|
35146
33394
|
const { skill } = this.paths(state, id);
|
|
35147
|
-
return { metadata, content:
|
|
33395
|
+
return { metadata, content: readFileSync24(skill, "utf8") };
|
|
35148
33396
|
}
|
|
35149
33397
|
};
|
|
35150
33398
|
function boundedList(value, field) {
|
|
@@ -35159,18 +33407,18 @@ function boundedList(value, field) {
|
|
|
35159
33407
|
return [...new Set(refs)];
|
|
35160
33408
|
}
|
|
35161
33409
|
function readdirSorted(dir) {
|
|
35162
|
-
return readdirSync10(dir).filter((entry) => statSync3(
|
|
33410
|
+
return readdirSync10(dir).filter((entry) => statSync3(join29(dir, entry)).isDirectory()).sort();
|
|
35163
33411
|
}
|
|
35164
33412
|
|
|
35165
33413
|
// plugins/kxm/src/wiki.ts
|
|
35166
|
-
import { mkdirSync as
|
|
35167
|
-
import { join as
|
|
33414
|
+
import { mkdirSync as mkdirSync21, writeFileSync as writeFileSync20 } from "node:fs";
|
|
33415
|
+
import { join as join30 } from "node:path";
|
|
35168
33416
|
function writeCompiledWiki(root, wiki) {
|
|
35169
33417
|
const written = [];
|
|
35170
33418
|
for (const [relativePath, content] of [...wiki.pages].sort(([left], [right]) => left.localeCompare(right))) {
|
|
35171
|
-
const absolute =
|
|
35172
|
-
|
|
35173
|
-
|
|
33419
|
+
const absolute = join30(root, relativePath);
|
|
33420
|
+
mkdirSync21(absolute.slice(0, absolute.lastIndexOf("/")), { recursive: true });
|
|
33421
|
+
writeFileSync20(absolute, content);
|
|
35174
33422
|
written.push(relativePath);
|
|
35175
33423
|
}
|
|
35176
33424
|
return written;
|
|
@@ -35336,7 +33584,7 @@ function skillStateFromFlag(value) {
|
|
|
35336
33584
|
throw new Error(`invalid skill state ${value}`);
|
|
35337
33585
|
}
|
|
35338
33586
|
function skillsRoot(runtime) {
|
|
35339
|
-
return
|
|
33587
|
+
return join31(runtime.dirs.workdir, ".kxm", "skills");
|
|
35340
33588
|
}
|
|
35341
33589
|
function csv(value) {
|
|
35342
33590
|
if (!value) return void 0;
|
|
@@ -35353,7 +33601,7 @@ async function cmdSkillsCreate(runtime, options) {
|
|
|
35353
33601
|
const metadata = lifecycle.create({
|
|
35354
33602
|
name: options.name,
|
|
35355
33603
|
description: options.description ?? "",
|
|
35356
|
-
content:
|
|
33604
|
+
content: readFileSync25(options.file, "utf8"),
|
|
35357
33605
|
createdBy: options.createdBy,
|
|
35358
33606
|
sources: {
|
|
35359
33607
|
runIds: csv(options.run) ?? [],
|
|
@@ -35511,8 +33759,8 @@ async function cmdMemorySync(runtime) {
|
|
|
35511
33759
|
|
|
35512
33760
|
// plugins/kxm/src/cli/hub.ts
|
|
35513
33761
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
35514
|
-
import { existsSync as
|
|
35515
|
-
import { join as
|
|
33762
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync25, readFileSync as readFileSync31, readdirSync as readdirSync12, rmSync as rmSync10, writeFileSync as writeFileSync23 } from "node:fs";
|
|
33763
|
+
import { join as join41, resolve as resolve24 } from "node:path";
|
|
35516
33764
|
|
|
35517
33765
|
// node_modules/marked/lib/marked.esm.js
|
|
35518
33766
|
function M() {
|
|
@@ -39674,10 +37922,10 @@ var TuiBase = class _TuiBase extends Container {
|
|
|
39674
37922
|
* @returns Promise containing the parsed RGB color, or undefined if it times out or fails to parse.
|
|
39675
37923
|
*/
|
|
39676
37924
|
queryTerminalBackgroundColor({ timeoutMs }) {
|
|
39677
|
-
return new Promise((
|
|
37925
|
+
return new Promise((resolve30) => {
|
|
39678
37926
|
const query = {
|
|
39679
37927
|
settled: false,
|
|
39680
|
-
resolve:
|
|
37928
|
+
resolve: resolve30,
|
|
39681
37929
|
timer: void 0
|
|
39682
37930
|
};
|
|
39683
37931
|
query.timer = setTimeout(() => {
|
|
@@ -39700,7 +37948,7 @@ var TuiBase = class _TuiBase extends Container {
|
|
|
39700
37948
|
* `CSI ? 997 ; 1 n` for dark or `CSI ? 997 ; 2 n` for light.
|
|
39701
37949
|
*/
|
|
39702
37950
|
queryTerminalColorScheme({ timeoutMs }) {
|
|
39703
|
-
return new Promise((
|
|
37951
|
+
return new Promise((resolve30) => {
|
|
39704
37952
|
let settled = false;
|
|
39705
37953
|
let timer;
|
|
39706
37954
|
let unsubscribe = () => {
|
|
@@ -39714,7 +37962,7 @@ var TuiBase = class _TuiBase extends Container {
|
|
|
39714
37962
|
timer = void 0;
|
|
39715
37963
|
}
|
|
39716
37964
|
unsubscribe();
|
|
39717
|
-
|
|
37965
|
+
resolve30(scheme);
|
|
39718
37966
|
};
|
|
39719
37967
|
unsubscribe = this.onTerminalColorSchemeChange(settle);
|
|
39720
37968
|
timer = setTimeout(() => settle(void 0), timeoutMs);
|
|
@@ -41445,7 +39693,7 @@ import * as path2 from "node:path";
|
|
|
41445
39693
|
|
|
41446
39694
|
// node_modules/@earendil-works/pi-tui/dist/native-module-path.js
|
|
41447
39695
|
import { createRequire as createRequire2 } from "node:module";
|
|
41448
|
-
import { dirname as dirname17, join as
|
|
39696
|
+
import { dirname as dirname17, join as join32 } from "node:path";
|
|
41449
39697
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
41450
39698
|
var moduleRequire = createRequire2(import.meta.url);
|
|
41451
39699
|
var TUI_PACKAGE_NAME = "@earendil-works/pi-tui";
|
|
@@ -41454,10 +39702,10 @@ function getNativeModuleCandidates(nativePath, options = {}) {
|
|
|
41454
39702
|
const candidates = [];
|
|
41455
39703
|
try {
|
|
41456
39704
|
const packageEntry = (options.resolvePackage ?? moduleRequire.resolve)(TUI_PACKAGE_NAME);
|
|
41457
|
-
candidates.push(
|
|
39705
|
+
candidates.push(join32(dirname17(packageEntry), "..", nativePath));
|
|
41458
39706
|
} catch {
|
|
41459
39707
|
}
|
|
41460
|
-
candidates.push(
|
|
39708
|
+
candidates.push(join32(moduleDir, "..", nativePath), join32(moduleDir, nativePath), join32(dirname17(options.execPath ?? process.execPath), nativePath));
|
|
41461
39709
|
return Array.from(new Set(candidates));
|
|
41462
39710
|
}
|
|
41463
39711
|
|
|
@@ -41798,7 +40046,7 @@ var ProcessTerminal = class {
|
|
|
41798
40046
|
break;
|
|
41799
40047
|
if (now - lastDataTime >= idleMs)
|
|
41800
40048
|
break;
|
|
41801
|
-
await new Promise((
|
|
40049
|
+
await new Promise((resolve30) => setTimeout(resolve30, Math.min(idleMs, timeLeft)));
|
|
41802
40050
|
}
|
|
41803
40051
|
} finally {
|
|
41804
40052
|
process.stdin.removeListener("data", onData);
|
|
@@ -43913,8 +42161,8 @@ var TuiAltScreen = class extends TuiBase {
|
|
|
43913
42161
|
var MAX_RENDER_WRITE_CHARS = 1024 * 1024;
|
|
43914
42162
|
|
|
43915
42163
|
// plugins/kxm/src/tui.ts
|
|
43916
|
-
import { mkdirSync as
|
|
43917
|
-
import { join as
|
|
42164
|
+
import { mkdirSync as mkdirSync22 } from "node:fs";
|
|
42165
|
+
import { join as join36, resolve as resolve23, dirname as dirname18 } from "node:path";
|
|
43918
42166
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
43919
42167
|
|
|
43920
42168
|
// packages/core/tui/src/types/surface.ts
|
|
@@ -44049,9 +42297,9 @@ function slugifyBranchPart(text, maxLength = 40) {
|
|
|
44049
42297
|
}
|
|
44050
42298
|
|
|
44051
42299
|
// plugins/kxm/src/local-snapshot.ts
|
|
44052
|
-
import { existsSync as
|
|
42300
|
+
import { existsSync as existsSync26, readdirSync as readdirSync11, readFileSync as readFileSync26 } from "node:fs";
|
|
44053
42301
|
import { homedir as homedir6 } from "node:os";
|
|
44054
|
-
import { isAbsolute as isAbsolute8, join as
|
|
42302
|
+
import { isAbsolute as isAbsolute8, join as join35, resolve as resolve22 } from "node:path";
|
|
44055
42303
|
function processExists2(pid) {
|
|
44056
42304
|
try {
|
|
44057
42305
|
process.kill(pid, 0);
|
|
@@ -44171,36 +42419,36 @@ function readOpenMessageMetadata(database) {
|
|
|
44171
42419
|
return messages;
|
|
44172
42420
|
}
|
|
44173
42421
|
function resolveKxmSnapshotPaths(cwd, env = process.env) {
|
|
44174
|
-
const stateDir = env.KXM_STATE_DIR?.trim() ||
|
|
42422
|
+
const stateDir = env.KXM_STATE_DIR?.trim() || join35(cwd, ".kxm", "state");
|
|
44175
42423
|
const configured = env.KXM_DATA_PATH?.trim();
|
|
44176
|
-
const dataPath = configured ?
|
|
42424
|
+
const dataPath = configured ? resolve22(cwd, configured) : join35(stateDir, "kxm.db");
|
|
44177
42425
|
return { dataPath, stateDir };
|
|
44178
42426
|
}
|
|
44179
42427
|
function resolveKxmStateRoot(stateDir, options) {
|
|
44180
|
-
if (options?.kxmStateRoot &&
|
|
44181
|
-
return
|
|
42428
|
+
if (options?.kxmStateRoot && existsSync26(options.kxmStateRoot)) {
|
|
42429
|
+
return resolve22(options.kxmStateRoot);
|
|
44182
42430
|
}
|
|
44183
|
-
if (
|
|
42431
|
+
if (existsSync26(join35(stateDir, "runtime", "registry.db")) || existsSync26(join35(stateDir, "runtime", "projects"))) {
|
|
44184
42432
|
return stateDir;
|
|
44185
42433
|
}
|
|
44186
42434
|
const env = options?.env ?? process.env;
|
|
44187
42435
|
const explicit = env.KXM_STATE_HOME?.trim() || env.KXM_USER_STATE_DIR?.trim() || env.KXM_STATE_ROOT?.trim();
|
|
44188
|
-
if (explicit && isAbsolute8(explicit) &&
|
|
44189
|
-
return
|
|
42436
|
+
if (explicit && isAbsolute8(explicit) && existsSync26(resolve22(explicit))) {
|
|
42437
|
+
return resolve22(explicit);
|
|
44190
42438
|
}
|
|
44191
42439
|
let base;
|
|
44192
42440
|
if (process.platform === "win32") {
|
|
44193
42441
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
44194
|
-
base = localAppData && isAbsolute8(localAppData) ? localAppData :
|
|
44195
|
-
base =
|
|
42442
|
+
base = localAppData && isAbsolute8(localAppData) ? localAppData : join35(homedir6(), "AppData", "Local");
|
|
42443
|
+
base = resolve22(base, "KXM");
|
|
44196
42444
|
} else if (process.platform === "darwin") {
|
|
44197
|
-
base =
|
|
42445
|
+
base = resolve22(homedir6(), "Library", "Application Support", "KXM");
|
|
44198
42446
|
} else {
|
|
44199
42447
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
44200
|
-
base = xdgState && isAbsolute8(xdgState) ? xdgState :
|
|
44201
|
-
base =
|
|
42448
|
+
base = xdgState && isAbsolute8(xdgState) ? xdgState : join35(homedir6(), ".local", "state");
|
|
42449
|
+
base = resolve22(base, "kxm");
|
|
44202
42450
|
}
|
|
44203
|
-
if (
|
|
42451
|
+
if (existsSync26(base)) return base;
|
|
44204
42452
|
return void 0;
|
|
44205
42453
|
}
|
|
44206
42454
|
function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
@@ -44211,7 +42459,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
44211
42459
|
let legacyRuns = [];
|
|
44212
42460
|
let legacyRunTotal = 0;
|
|
44213
42461
|
let plans = [];
|
|
44214
|
-
if (
|
|
42462
|
+
if (existsSync26(dataPath)) {
|
|
44215
42463
|
hasLegacy = true;
|
|
44216
42464
|
const database = new DatabaseSync(dataPath, { readOnly: true });
|
|
44217
42465
|
try {
|
|
@@ -44231,11 +42479,11 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
44231
42479
|
let kxmRunTotal = 0;
|
|
44232
42480
|
const kxmStateRoot = resolveKxmStateRoot(stateDir, options);
|
|
44233
42481
|
if (kxmStateRoot) {
|
|
44234
|
-
const runtimeDir =
|
|
44235
|
-
const registryDbPath =
|
|
44236
|
-
const projectsDir =
|
|
42482
|
+
const runtimeDir = join35(kxmStateRoot, "runtime");
|
|
42483
|
+
const registryDbPath = join35(runtimeDir, "registry.db");
|
|
42484
|
+
const projectsDir = join35(runtimeDir, "projects");
|
|
44237
42485
|
const projectKeys = /* @__PURE__ */ new Set();
|
|
44238
|
-
if (
|
|
42486
|
+
if (existsSync26(registryDbPath)) {
|
|
44239
42487
|
hasKxm = true;
|
|
44240
42488
|
try {
|
|
44241
42489
|
const regDb = new DatabaseSync(registryDbPath, { readOnly: true });
|
|
@@ -44251,7 +42499,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
44251
42499
|
} catch {
|
|
44252
42500
|
}
|
|
44253
42501
|
}
|
|
44254
|
-
if (
|
|
42502
|
+
if (existsSync26(projectsDir)) {
|
|
44255
42503
|
try {
|
|
44256
42504
|
for (const entry of readdirSync11(projectsDir, { withFileTypes: true })) {
|
|
44257
42505
|
if (entry.isDirectory()) {
|
|
@@ -44262,8 +42510,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
44262
42510
|
}
|
|
44263
42511
|
}
|
|
44264
42512
|
for (const key of projectKeys) {
|
|
44265
|
-
const eventDbPath =
|
|
44266
|
-
if (
|
|
42513
|
+
const eventDbPath = join35(projectsDir, key, "run-events.db");
|
|
42514
|
+
if (existsSync26(eventDbPath)) {
|
|
44267
42515
|
hasKxm = true;
|
|
44268
42516
|
try {
|
|
44269
42517
|
const eventDb = new DatabaseSync(eventDbPath, { readOnly: true });
|
|
@@ -44293,10 +42541,10 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
44293
42541
|
}
|
|
44294
42542
|
}
|
|
44295
42543
|
const pids = [];
|
|
44296
|
-
if (
|
|
42544
|
+
if (existsSync26(stateDir)) {
|
|
44297
42545
|
for (const file of readdirSync11(stateDir).filter((name) => name.endsWith(".pid"))) {
|
|
44298
42546
|
try {
|
|
44299
|
-
const record = JSON.parse(
|
|
42547
|
+
const record = JSON.parse(readFileSync26(join35(stateDir, file), "utf8"));
|
|
44300
42548
|
pids.push({
|
|
44301
42549
|
file,
|
|
44302
42550
|
...record.role ? { role: record.role } : {},
|
|
@@ -44335,8 +42583,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
44335
42583
|
} else {
|
|
44336
42584
|
source = "legacy";
|
|
44337
42585
|
}
|
|
44338
|
-
const telemetryFile =
|
|
44339
|
-
const spend =
|
|
42586
|
+
const telemetryFile = join35(stateDir, "telemetry.jsonl");
|
|
42587
|
+
const spend = existsSync26(telemetryFile) ? readRoutingRecords(telemetryFile) : [];
|
|
44340
42588
|
return {
|
|
44341
42589
|
source,
|
|
44342
42590
|
agents: agents.sort((a, b2) => Number(b2.online) - Number(a.online) || a.name.localeCompare(b2.name)),
|
|
@@ -44470,11 +42718,11 @@ function spawnDegradeWorktree(repoRoot, runId, options) {
|
|
|
44470
42718
|
const cleanRunId = runId.replace(/^run_/, "");
|
|
44471
42719
|
const desc = options?.description ? slugifyBranchPart(options.description, 30) : "degrade";
|
|
44472
42720
|
const branchName = `kxm/run-${cleanRunId}-${desc}`;
|
|
44473
|
-
const relativeWtPath =
|
|
44474
|
-
const absoluteWtPath =
|
|
42721
|
+
const relativeWtPath = join36(".kxm", "worktrees", `run-${cleanRunId}-${desc}`);
|
|
42722
|
+
const absoluteWtPath = resolve23(repoRoot, relativeWtPath);
|
|
44475
42723
|
const jumpCommand = `cd "${absoluteWtPath}"`;
|
|
44476
42724
|
try {
|
|
44477
|
-
|
|
42725
|
+
mkdirSync22(dirname18(absoluteWtPath), { recursive: true });
|
|
44478
42726
|
const branchCheck = runner("git", ["rev-parse", "--verify", `refs/heads/${branchName}`]);
|
|
44479
42727
|
let wtRes;
|
|
44480
42728
|
if (branchCheck.status === 0) {
|
|
@@ -44864,11 +43112,11 @@ async function readJson(response) {
|
|
|
44864
43112
|
}
|
|
44865
43113
|
async function waitForReconnect(signal, milliseconds = 1e3) {
|
|
44866
43114
|
if (signal.aborted) return;
|
|
44867
|
-
await new Promise((
|
|
43115
|
+
await new Promise((resolve30) => {
|
|
44868
43116
|
const done = () => {
|
|
44869
43117
|
clearTimeout(timer);
|
|
44870
43118
|
signal.removeEventListener("abort", done);
|
|
44871
|
-
|
|
43119
|
+
resolve30();
|
|
44872
43120
|
};
|
|
44873
43121
|
const timer = setTimeout(done, milliseconds);
|
|
44874
43122
|
timer.unref();
|
|
@@ -45231,8 +43479,8 @@ async function runMeshTui(input) {
|
|
|
45231
43479
|
// plugins/kxm/src/session-work.ts
|
|
45232
43480
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
45233
43481
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
45234
|
-
import { existsSync as
|
|
45235
|
-
import { join as
|
|
43482
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync23, readFileSync as readFileSync27, renameSync as renameSync8, writeFileSync as writeFileSync21 } from "node:fs";
|
|
43483
|
+
import { join as join37 } from "node:path";
|
|
45236
43484
|
var MAX_SESSION_BRIEF_TASKS = 5;
|
|
45237
43485
|
var MAX_SESSION_BRIEF_PLANS = 5;
|
|
45238
43486
|
var SESSION_BRIEF_SCHEMA = "kxm.session-brief.v1";
|
|
@@ -45389,10 +43637,10 @@ function buildSessionBrief(snapshot, current, hub, ship, updateLatest, cost, ses
|
|
|
45389
43637
|
};
|
|
45390
43638
|
}
|
|
45391
43639
|
function readCachedSessionBrief(stateDir) {
|
|
45392
|
-
const file =
|
|
43640
|
+
const file = join37(stateDir, "session-brief.json");
|
|
45393
43641
|
try {
|
|
45394
|
-
if (!
|
|
45395
|
-
const raw =
|
|
43642
|
+
if (!existsSync27(file)) return void 0;
|
|
43643
|
+
const raw = readFileSync27(file, "utf8");
|
|
45396
43644
|
const parsed = JSON.parse(raw);
|
|
45397
43645
|
if (parsed && parsed.schema === "kxm.session-brief.v1" && typeof parsed.generatedAt === "string") {
|
|
45398
43646
|
const ageMs = Date.now() - Date.parse(parsed.generatedAt);
|
|
@@ -45407,18 +43655,18 @@ function readCachedSessionBrief(stateDir) {
|
|
|
45407
43655
|
}
|
|
45408
43656
|
function writeCachedSessionBrief(stateDir, brief) {
|
|
45409
43657
|
try {
|
|
45410
|
-
|
|
45411
|
-
const file =
|
|
43658
|
+
mkdirSync23(stateDir, { recursive: true, mode: 448 });
|
|
43659
|
+
const file = join37(stateDir, "session-brief.json");
|
|
45412
43660
|
const tmp = `${file}.tmp.${randomUUID13().slice(0, 8)}`;
|
|
45413
|
-
|
|
45414
|
-
|
|
43661
|
+
writeFileSync21(tmp, JSON.stringify(brief, null, 2), { encoding: "utf8", mode: 384 });
|
|
43662
|
+
renameSync8(tmp, file);
|
|
45415
43663
|
} catch {
|
|
45416
43664
|
}
|
|
45417
43665
|
}
|
|
45418
43666
|
function estimateSessionCost(stateDir) {
|
|
45419
43667
|
try {
|
|
45420
|
-
const telemetryFile =
|
|
45421
|
-
if (!
|
|
43668
|
+
const telemetryFile = join37(stateDir, "telemetry.jsonl");
|
|
43669
|
+
if (!existsSync27(telemetryFile)) return void 0;
|
|
45422
43670
|
const records = readRoutingRecords(telemetryFile);
|
|
45423
43671
|
if (records.length === 0) return void 0;
|
|
45424
43672
|
let totalCost = 0;
|
|
@@ -45586,11 +43834,11 @@ function formatSessionBriefText(brief) {
|
|
|
45586
43834
|
}
|
|
45587
43835
|
|
|
45588
43836
|
// plugins/kxm/src/kxm-install-kind.ts
|
|
45589
|
-
import { existsSync as
|
|
45590
|
-
import { dirname as dirname19, join as
|
|
43837
|
+
import { existsSync as existsSync28, readFileSync as readFileSync28 } from "node:fs";
|
|
43838
|
+
import { dirname as dirname19, join as join38 } from "node:path";
|
|
45591
43839
|
function packageIsKxm(root) {
|
|
45592
43840
|
try {
|
|
45593
|
-
const pkg = JSON.parse(
|
|
43841
|
+
const pkg = JSON.parse(readFileSync28(join38(root, "package.json"), "utf8"));
|
|
45594
43842
|
return pkg.name === "@kontextmind/kxm";
|
|
45595
43843
|
} catch {
|
|
45596
43844
|
return false;
|
|
@@ -45639,12 +43887,12 @@ function report(kind, root) {
|
|
|
45639
43887
|
return { kind, root, instruction: installKindInstruction(kind, root) };
|
|
45640
43888
|
}
|
|
45641
43889
|
function classifyInstallRoot(probe) {
|
|
45642
|
-
const piGitRoot =
|
|
43890
|
+
const piGitRoot = join38(probe.homeDir, ".pi", "agent", "git");
|
|
45643
43891
|
if (isUnder(probe.repoRoot, piGitRoot, probe.platform)) return report("pi-git", probe.repoRoot);
|
|
45644
|
-
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() ||
|
|
45645
|
-
const pluginsRoot =
|
|
43892
|
+
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() || join38(probe.homeDir, ".claude");
|
|
43893
|
+
const pluginsRoot = join38(claudeHome, "plugins");
|
|
45646
43894
|
if (isUnder(probe.moduleDir, pluginsRoot, probe.platform)) return report("claude-marketplace", probe.moduleDir);
|
|
45647
|
-
const hasGit =
|
|
43895
|
+
const hasGit = existsSync28(join38(probe.repoRoot, ".git"));
|
|
45648
43896
|
if (hasGit && packageIsKxm(probe.repoRoot)) return report("source", probe.repoRoot);
|
|
45649
43897
|
if (isNpmPackageLayout(probe.repoRoot, probe.platform) && packageIsKxm(probe.repoRoot) && !hasGit) {
|
|
45650
43898
|
return report("npm-package", probe.repoRoot);
|
|
@@ -45664,15 +43912,15 @@ function resolveInstallKind(probe, npmGlobalRoot) {
|
|
|
45664
43912
|
}
|
|
45665
43913
|
|
|
45666
43914
|
// plugins/kxm/src/kxm-update-config.ts
|
|
45667
|
-
var
|
|
45668
|
-
import { existsSync as
|
|
45669
|
-
import { join as
|
|
43915
|
+
var import_yaml15 = __toESM(require_dist(), 1);
|
|
43916
|
+
import { existsSync as existsSync29, readFileSync as readFileSync29 } from "node:fs";
|
|
43917
|
+
import { join as join39 } from "node:path";
|
|
45670
43918
|
function loadKxmUpdateConfig(env = process.env) {
|
|
45671
|
-
const path4 =
|
|
45672
|
-
if (!
|
|
43919
|
+
const path4 = join39(kxmUserStateRoot({ env }), "update.yaml");
|
|
43920
|
+
if (!existsSync29(path4)) return { schema: KXM_UPDATE_SCHEMA, auto: false, source: "github" };
|
|
45673
43921
|
let parsed;
|
|
45674
43922
|
try {
|
|
45675
|
-
parsed = (0,
|
|
43923
|
+
parsed = (0, import_yaml15.parse)(readFileSync29(path4, "utf8"));
|
|
45676
43924
|
} catch {
|
|
45677
43925
|
throw new KxmUpdateConfigError("update.yaml is not valid YAML");
|
|
45678
43926
|
}
|
|
@@ -45698,8 +43946,8 @@ function loadKxmUpdateConfig(env = process.env) {
|
|
|
45698
43946
|
}
|
|
45699
43947
|
|
|
45700
43948
|
// plugins/kxm/src/session.ts
|
|
45701
|
-
import { existsSync as
|
|
45702
|
-
import { join as
|
|
43949
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync24, readFileSync as readFileSync30, writeFileSync as writeFileSync22 } from "node:fs";
|
|
43950
|
+
import { join as join40 } from "node:path";
|
|
45703
43951
|
var SESSION_SCHEMA = "kxm.session.v1";
|
|
45704
43952
|
var SessionConfigError = class extends Error {
|
|
45705
43953
|
code = "session_config_invalid";
|
|
@@ -45709,12 +43957,12 @@ var SessionConfigError = class extends Error {
|
|
|
45709
43957
|
}
|
|
45710
43958
|
};
|
|
45711
43959
|
function workflowAssetDirs(assetsDir, workflowId) {
|
|
45712
|
-
const root =
|
|
45713
|
-
return [root,
|
|
43960
|
+
const root = join40(assetsDir, "workflows", workflowId);
|
|
43961
|
+
return [root, join40(root, "inputs"), join40(root, "outputs"), join40(root, "generated")];
|
|
45714
43962
|
}
|
|
45715
43963
|
function sessionAssetDirs(assetsDir, sessionId) {
|
|
45716
|
-
const root =
|
|
45717
|
-
return [root,
|
|
43964
|
+
const root = join40(assetsDir, "sessions", sessionId);
|
|
43965
|
+
return [root, join40(root, "inputs"), join40(root, "outputs")];
|
|
45718
43966
|
}
|
|
45719
43967
|
function rosterNames(configDir) {
|
|
45720
43968
|
return [...loadRosterMap(configDir).values()].map((row) => String(row.name));
|
|
@@ -45764,7 +44012,7 @@ function workerFromRosterRow(name, row, project) {
|
|
|
45764
44012
|
function loadRosterMap(configDir) {
|
|
45765
44013
|
const byName = /* @__PURE__ */ new Map();
|
|
45766
44014
|
for (const [file, key] of [["agents.json", "agents"], ["gates.json", "gates"]]) {
|
|
45767
|
-
const path4 =
|
|
44015
|
+
const path4 = join40(configDir, file);
|
|
45768
44016
|
for (const row of loadRoster(path4, key)) {
|
|
45769
44017
|
const name = String(row.name).trim();
|
|
45770
44018
|
const lowered = name.toLowerCase();
|
|
@@ -45778,10 +44026,10 @@ function loadRosterMap(configDir) {
|
|
|
45778
44026
|
return byName;
|
|
45779
44027
|
}
|
|
45780
44028
|
function loadRoster(path4, key) {
|
|
45781
|
-
if (!
|
|
44029
|
+
if (!existsSync30(path4)) return [];
|
|
45782
44030
|
let parsed;
|
|
45783
44031
|
try {
|
|
45784
|
-
parsed = JSON.parse(
|
|
44032
|
+
parsed = JSON.parse(readFileSync30(path4, "utf8"));
|
|
45785
44033
|
} catch (error) {
|
|
45786
44034
|
throw new SessionConfigError(
|
|
45787
44035
|
`${key} roster at ${path4} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -45806,7 +44054,7 @@ function loadRoster(path4, key) {
|
|
|
45806
44054
|
});
|
|
45807
44055
|
}
|
|
45808
44056
|
function createSession(input) {
|
|
45809
|
-
const assetDir = input.mode === "workflow" && input.workflowId ?
|
|
44057
|
+
const assetDir = input.mode === "workflow" && input.workflowId ? join40("assets", "workflows", input.workflowId) : join40("assets", "sessions", input.id);
|
|
45810
44058
|
return {
|
|
45811
44059
|
schema: SESSION_SCHEMA,
|
|
45812
44060
|
id: input.id,
|
|
@@ -45819,11 +44067,11 @@ function createSession(input) {
|
|
|
45819
44067
|
};
|
|
45820
44068
|
}
|
|
45821
44069
|
function writeSession(assetsDir, session, dryRun = false) {
|
|
45822
|
-
const dir =
|
|
45823
|
-
const path4 =
|
|
44070
|
+
const dir = join40(assetsDir, "sessions", session.id);
|
|
44071
|
+
const path4 = join40(dir, "session.json");
|
|
45824
44072
|
if (!dryRun) {
|
|
45825
|
-
|
|
45826
|
-
|
|
44073
|
+
mkdirSync24(dir, { recursive: true });
|
|
44074
|
+
writeFileSync22(path4, `${JSON.stringify(session, null, 2)}
|
|
45827
44075
|
`, { encoding: "utf8" });
|
|
45828
44076
|
}
|
|
45829
44077
|
return path4;
|
|
@@ -45851,22 +44099,22 @@ function installProbeFrom(runtime) {
|
|
|
45851
44099
|
const partial = runtime.io.installProbe ?? {};
|
|
45852
44100
|
return {
|
|
45853
44101
|
moduleDir: partial.moduleDir ?? dirname20(fileURLToPath3(import.meta.url)),
|
|
45854
|
-
repoRoot: partial.repoRoot ??
|
|
44102
|
+
repoRoot: partial.repoRoot ?? resolve24("."),
|
|
45855
44103
|
homeDir: partial.homeDir ?? homedir7(),
|
|
45856
44104
|
platform: partial.platform ?? process.platform,
|
|
45857
44105
|
env: partial.env ?? runtime.env
|
|
45858
44106
|
};
|
|
45859
44107
|
}
|
|
45860
44108
|
function warnIgnoredProjectUpdateYaml(runtime) {
|
|
45861
|
-
const projectFile =
|
|
45862
|
-
if (!
|
|
45863
|
-
const userFile =
|
|
44109
|
+
const projectFile = join41(runtime.dirs.workspace, "update.yaml");
|
|
44110
|
+
if (!existsSync31(projectFile)) return;
|
|
44111
|
+
const userFile = join41(kxmUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
45864
44112
|
runtime.io.stderr(`kxm: ignoring .kxm/update.yaml in ${runtime.dirs.workdir}; update settings are read only from ${userFile}
|
|
45865
44113
|
`);
|
|
45866
44114
|
}
|
|
45867
44115
|
async function refreshKxmUpdateNotice(runtime, config) {
|
|
45868
44116
|
const resolved = config ?? loadKxmUpdateConfig(runtime.env);
|
|
45869
|
-
const current = readInstalledKxmVersion(
|
|
44117
|
+
const current = readInstalledKxmVersion(resolve24("."));
|
|
45870
44118
|
const fetched = await fetchLatestKxmVersion(resolved.source, runtime.env, runtime.fetchImpl);
|
|
45871
44119
|
const notice = noticeFromVersions(current, fetched.latest, resolved, fetched.error, fetched.asset);
|
|
45872
44120
|
writeUpdateCache(runtime.dirs.state, notice);
|
|
@@ -45899,7 +44147,7 @@ async function cmdDash(runtime, options = {}) {
|
|
|
45899
44147
|
return 2;
|
|
45900
44148
|
}
|
|
45901
44149
|
const screen = requested;
|
|
45902
|
-
const dataPath =
|
|
44150
|
+
const dataPath = resolve24(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join41(runtime.dirs.state, "kxm.db"));
|
|
45903
44151
|
if (runtime.dryRun) {
|
|
45904
44152
|
print(runtime.io, runtime.json, {
|
|
45905
44153
|
ok: true,
|
|
@@ -45945,7 +44193,7 @@ async function cmdHub(runtime) {
|
|
|
45945
44193
|
config = loadKxmUpdateConfig(runtime.env);
|
|
45946
44194
|
} catch (error) {
|
|
45947
44195
|
if (error instanceof KxmUpdateConfigError) {
|
|
45948
|
-
const yamlPath =
|
|
44196
|
+
const yamlPath = join41(kxmUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
45949
44197
|
runtime.io.stderr(`kxm: ${error.message}; update check skipped; fix or remove ${yamlPath}
|
|
45950
44198
|
`);
|
|
45951
44199
|
} else {
|
|
@@ -46132,7 +44380,7 @@ async function cmdWorker(runtime, options) {
|
|
|
46132
44380
|
return await (runtime.io.spawnWorker ?? ((launchEnv) => spawnScript("kxm-worker.mjs", launchEnv)))(extraEnv);
|
|
46133
44381
|
}
|
|
46134
44382
|
async function cmdStop(runtime, waitMsFlag) {
|
|
46135
|
-
const pids =
|
|
44383
|
+
const pids = existsSync31(runtime.dirs.state) ? readdirSync12(runtime.dirs.state).filter((name) => name.endsWith(".pid")) : [];
|
|
46136
44384
|
if (runtime.dryRun) {
|
|
46137
44385
|
print(runtime.io, runtime.json, { ok: true, command: "stop", dryRun: true, pidFiles: pids }, "would signal pid files");
|
|
46138
44386
|
return 0;
|
|
@@ -46147,7 +44395,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
46147
44395
|
const orphans = [];
|
|
46148
44396
|
for (const file of pids) {
|
|
46149
44397
|
try {
|
|
46150
|
-
const record = JSON.parse(
|
|
44398
|
+
const record = JSON.parse(readFileSync31(join41(runtime.dirs.state, file), "utf8"));
|
|
46151
44399
|
const expectedControl = file === "hub.pid" ? "hub.stop" : file.startsWith("worker-") ? `${file.slice(0, -4)}.stop` : void 0;
|
|
46152
44400
|
const expectedRole = file === "hub.pid" ? "hub" : file.startsWith("worker-") ? "worker" : void 0;
|
|
46153
44401
|
if (record.version !== 1 || !Number.isInteger(record.pid) || record.pid <= 0 || !record.startedAt || !expectedControl || record.controlFile !== expectedControl || record.role !== expectedRole) {
|
|
@@ -46167,7 +44415,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
46167
44415
|
ignored.push(file);
|
|
46168
44416
|
continue;
|
|
46169
44417
|
}
|
|
46170
|
-
|
|
44418
|
+
writeFileSync23(join41(runtime.dirs.state, record.controlFile), `${JSON.stringify({ startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {}, requestedAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
46171
44419
|
`, { encoding: "utf8", mode: 384 });
|
|
46172
44420
|
requested.push(file);
|
|
46173
44421
|
records.set(file, { pid: record.pid, startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {} });
|
|
@@ -46185,7 +44433,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
46185
44433
|
while (Date.now() <= deadline && stopped.size < requested.length) {
|
|
46186
44434
|
for (const [file, record] of records) {
|
|
46187
44435
|
try {
|
|
46188
|
-
const current = JSON.parse(
|
|
44436
|
+
const current = JSON.parse(readFileSync31(join41(runtime.dirs.state, file), "utf8"));
|
|
46189
44437
|
if (current.pid !== record.pid || current.startedAt !== record.startedAt || current.generation !== record.generation || !processExists(record.pid)) stopped.add(file);
|
|
46190
44438
|
} catch {
|
|
46191
44439
|
stopped.add(file);
|
|
@@ -46198,7 +44446,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
46198
44446
|
for (const file of orphans) {
|
|
46199
44447
|
while (Date.now() <= deadlineOrphans) {
|
|
46200
44448
|
try {
|
|
46201
|
-
const current = JSON.parse(
|
|
44449
|
+
const current = JSON.parse(readFileSync31(join41(runtime.dirs.state, file), "utf8"));
|
|
46202
44450
|
if (!Number.isInteger(current.serverPid) || !processExists(current.serverPid)) break;
|
|
46203
44451
|
} catch {
|
|
46204
44452
|
break;
|
|
@@ -46206,14 +44454,14 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
46206
44454
|
await (runtime.io.sleep ?? ((ms) => new Promise((resolveSleep) => setTimeout(resolveSleep, ms))))(100);
|
|
46207
44455
|
}
|
|
46208
44456
|
try {
|
|
46209
|
-
const current = JSON.parse(
|
|
44457
|
+
const current = JSON.parse(readFileSync31(join41(runtime.dirs.state, file), "utf8"));
|
|
46210
44458
|
if (Number.isInteger(current.serverPid) && processExists(current.serverPid)) {
|
|
46211
44459
|
try {
|
|
46212
44460
|
process.kill(current.serverPid, "SIGKILL");
|
|
46213
44461
|
} catch {
|
|
46214
44462
|
}
|
|
46215
44463
|
}
|
|
46216
|
-
|
|
44464
|
+
rmSync10(join41(runtime.dirs.state, file), { force: true });
|
|
46217
44465
|
} catch {
|
|
46218
44466
|
}
|
|
46219
44467
|
stopped.add(file);
|
|
@@ -46224,11 +44472,11 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
46224
44472
|
}
|
|
46225
44473
|
async function cmdSessionStatus(runtime) {
|
|
46226
44474
|
const stateDir = runtime.dirs.state;
|
|
46227
|
-
const names3 =
|
|
44475
|
+
const names3 = existsSync31(stateDir) ? readdirSync12(stateDir) : [];
|
|
46228
44476
|
const claims = [];
|
|
46229
44477
|
for (const file of names3.filter((name) => name.endsWith(".pid"))) {
|
|
46230
44478
|
try {
|
|
46231
|
-
const record = JSON.parse(
|
|
44479
|
+
const record = JSON.parse(readFileSync31(join41(stateDir, file), "utf8"));
|
|
46232
44480
|
claims.push({
|
|
46233
44481
|
file,
|
|
46234
44482
|
role: record.role,
|
|
@@ -46243,7 +44491,7 @@ async function cmdSessionStatus(runtime) {
|
|
|
46243
44491
|
const recoveries = [];
|
|
46244
44492
|
for (const file of names3.filter((name) => name.startsWith("worker-recovery-") && name.endsWith(".json"))) {
|
|
46245
44493
|
try {
|
|
46246
|
-
const envelope = JSON.parse(
|
|
44494
|
+
const envelope = JSON.parse(readFileSync31(join41(stateDir, file), "utf8"));
|
|
46247
44495
|
recoveries.push({
|
|
46248
44496
|
file,
|
|
46249
44497
|
reason: envelope.reason,
|
|
@@ -46348,7 +44596,7 @@ async function cmdSessionBrief(runtime, options = {}) {
|
|
|
46348
44596
|
print(runtime.io, runtime.json, { ok: true, command: "session brief", sessionToken }, sessionToken);
|
|
46349
44597
|
return 0;
|
|
46350
44598
|
}
|
|
46351
|
-
const dataPath =
|
|
44599
|
+
const dataPath = resolve24(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join41(runtime.dirs.state, "kxm.db"));
|
|
46352
44600
|
const env = {
|
|
46353
44601
|
...runtime.env,
|
|
46354
44602
|
KXM_STATE_DIR: runtime.dirs.state,
|
|
@@ -46425,7 +44673,7 @@ async function cmdSessionStart(runtime, options) {
|
|
|
46425
44673
|
...workflowId ? workflowAssetDirs(runtime.dirs.assets, workflowId) : []
|
|
46426
44674
|
];
|
|
46427
44675
|
if (!runtime.dryRun) {
|
|
46428
|
-
for (const directory of created)
|
|
44676
|
+
for (const directory of created) mkdirSync25(directory, { recursive: true });
|
|
46429
44677
|
writeSession(runtime.dirs.assets, session);
|
|
46430
44678
|
}
|
|
46431
44679
|
print(runtime.io, runtime.json, {
|
|
@@ -46440,16 +44688,16 @@ async function cmdSessionStart(runtime, options) {
|
|
|
46440
44688
|
|
|
46441
44689
|
// plugins/kxm/src/cli/system.ts
|
|
46442
44690
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
46443
|
-
import { createHash as
|
|
46444
|
-
import { existsSync as
|
|
44691
|
+
import { createHash as createHash15 } from "node:crypto";
|
|
44692
|
+
import { existsSync as existsSync37, mkdtempSync as mkdtempSync2, readFileSync as readFileSync36, rmSync as rmSync12 } from "node:fs";
|
|
46445
44693
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
46446
|
-
import { join as
|
|
44694
|
+
import { join as join47, resolve as resolve28 } from "node:path";
|
|
46447
44695
|
import { createInterface as createInterface3 } from "node:readline";
|
|
46448
44696
|
|
|
46449
44697
|
// plugins/kxm/src/improve.ts
|
|
46450
|
-
import { createHash as
|
|
46451
|
-
import { existsSync as
|
|
46452
|
-
import { join as
|
|
44698
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
44699
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync26, writeFileSync as writeFileSync24 } from "node:fs";
|
|
44700
|
+
import { join as join42, relative as relative6, resolve as resolve25 } from "node:path";
|
|
46453
44701
|
var CANDIDATE_SCHEMA = "kxm.candidate.v1";
|
|
46454
44702
|
var IMPROVEMENT_REPORT_SCHEMA = "kxm.improvement-report.v2";
|
|
46455
44703
|
function classifyCandidateKind(stepId, agentRole) {
|
|
@@ -46595,7 +44843,7 @@ function groupRoutingRecords(records, options = {}) {
|
|
|
46595
44843
|
const isCandidate = recurrence >= minRecurrence && verifyPassRate >= minPassRate;
|
|
46596
44844
|
const candidateKind = isCandidate ? classifyCandidateKind(group.stepId, group.agentRole) : void 0;
|
|
46597
44845
|
const safeSlug = group.stepId.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 16) || "step";
|
|
46598
|
-
const keyHash =
|
|
44846
|
+
const keyHash = createHash14("sha256").update(`${group.workflowHash}:${group.stepId}:${group.agentRole}:${group.promptHash}`).digest("hex").slice(0, 10);
|
|
46599
44847
|
const candidateId = isCandidate && candidateKind ? `cand_${candidateKind.replace(/-/g, "_")}_${safeSlug}_${keyHash}` : void 0;
|
|
46600
44848
|
rows.push({
|
|
46601
44849
|
workflowHash: group.workflowHash,
|
|
@@ -46620,8 +44868,8 @@ function groupRoutingRecords(records, options = {}) {
|
|
|
46620
44868
|
});
|
|
46621
44869
|
}
|
|
46622
44870
|
function buildImprovementReport(records, options = {}) {
|
|
46623
|
-
const projectRoot = options.projectRoot ?
|
|
46624
|
-
const candidatesDir = options.candidatesDir ?
|
|
44871
|
+
const projectRoot = options.projectRoot ? resolve25(options.projectRoot) : process.cwd();
|
|
44872
|
+
const candidatesDir = options.candidatesDir ? resolve25(options.candidatesDir) : join42(projectRoot, ".kxm", "candidates");
|
|
46625
44873
|
const groups = groupRoutingRecords(records, options);
|
|
46626
44874
|
const candidates = [];
|
|
46627
44875
|
for (const group of groups) {
|
|
@@ -46633,7 +44881,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46633
44881
|
group.workflowHash
|
|
46634
44882
|
);
|
|
46635
44883
|
const diffFileName = `${group.candidateId}.diff`;
|
|
46636
|
-
const diffFilePath =
|
|
44884
|
+
const diffFilePath = join42(candidatesDir, diffFileName);
|
|
46637
44885
|
const relDiffPath = relative6(projectRoot, diffFilePath).replace(/\\/g, "/");
|
|
46638
44886
|
const candidate = {
|
|
46639
44887
|
schema: CANDIDATE_SCHEMA,
|
|
@@ -46655,12 +44903,12 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46655
44903
|
createdAt: nowIso()
|
|
46656
44904
|
};
|
|
46657
44905
|
if (!options.dryRun) {
|
|
46658
|
-
if (!
|
|
46659
|
-
|
|
44906
|
+
if (!existsSync32(candidatesDir)) {
|
|
44907
|
+
mkdirSync26(candidatesDir, { recursive: true });
|
|
46660
44908
|
}
|
|
46661
|
-
|
|
46662
|
-
const jsonFilePath =
|
|
46663
|
-
|
|
44909
|
+
writeFileSync24(diffFilePath, diff, "utf8");
|
|
44910
|
+
const jsonFilePath = join42(candidatesDir, `${group.candidateId}.json`);
|
|
44911
|
+
writeFileSync24(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
|
|
46664
44912
|
}
|
|
46665
44913
|
candidates.push(candidate);
|
|
46666
44914
|
}
|
|
@@ -46675,10 +44923,10 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46675
44923
|
}
|
|
46676
44924
|
function writeImprovementReport(improvementsDir, report2, dryRun = false) {
|
|
46677
44925
|
const stamp = report2.createdAt.replace(/[:.]/g, "-");
|
|
46678
|
-
const path4 =
|
|
44926
|
+
const path4 = join42(improvementsDir, `${stamp}.json`);
|
|
46679
44927
|
if (!dryRun) {
|
|
46680
|
-
|
|
46681
|
-
|
|
44928
|
+
mkdirSync26(improvementsDir, { recursive: true });
|
|
44929
|
+
writeFileSync24(path4, `${JSON.stringify(report2, null, 2)}
|
|
46682
44930
|
`, { encoding: "utf8" });
|
|
46683
44931
|
}
|
|
46684
44932
|
return path4;
|
|
@@ -46717,9 +44965,9 @@ function formatImprovementReport(report2) {
|
|
|
46717
44965
|
}
|
|
46718
44966
|
|
|
46719
44967
|
// plugins/kxm/src/modes.ts
|
|
46720
|
-
var
|
|
46721
|
-
import { existsSync as
|
|
46722
|
-
import { join as
|
|
44968
|
+
var import_yaml16 = __toESM(require_dist(), 1);
|
|
44969
|
+
import { existsSync as existsSync33, readFileSync as readFileSync33 } from "node:fs";
|
|
44970
|
+
import { join as join43 } from "node:path";
|
|
46723
44971
|
var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
46724
44972
|
schema: "kxm.modes.v1",
|
|
46725
44973
|
majorModes: {
|
|
@@ -46782,13 +45030,13 @@ function loadModesConfig(projectRoot) {
|
|
|
46782
45030
|
if (!projectRoot) {
|
|
46783
45031
|
return DEFAULT_MODES_CONFIG;
|
|
46784
45032
|
}
|
|
46785
|
-
const modesPath =
|
|
46786
|
-
if (!
|
|
45033
|
+
const modesPath = join43(projectRoot, ".kxm", "modes.yaml");
|
|
45034
|
+
if (!existsSync33(modesPath)) {
|
|
46787
45035
|
return DEFAULT_MODES_CONFIG;
|
|
46788
45036
|
}
|
|
46789
45037
|
try {
|
|
46790
|
-
const raw =
|
|
46791
|
-
const parsed = (0,
|
|
45038
|
+
const raw = readFileSync33(modesPath, "utf8");
|
|
45039
|
+
const parsed = (0, import_yaml16.parse)(raw);
|
|
46792
45040
|
if (parsed && parsed.schema === "kxm.modes.v1" && parsed.majorModes) {
|
|
46793
45041
|
return {
|
|
46794
45042
|
schema: "kxm.modes.v1",
|
|
@@ -46873,11 +45121,11 @@ function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog
|
|
|
46873
45121
|
estimatedTokens: estimateTokens(baseSystemPromptChars)
|
|
46874
45122
|
});
|
|
46875
45123
|
for (const relPath of resolved.contextFiles) {
|
|
46876
|
-
const fullPath =
|
|
45124
|
+
const fullPath = join43(projectRoot, relPath);
|
|
46877
45125
|
let chars = 0;
|
|
46878
|
-
if (
|
|
45126
|
+
if (existsSync33(fullPath)) {
|
|
46879
45127
|
try {
|
|
46880
|
-
chars =
|
|
45128
|
+
chars = readFileSync33(fullPath, "utf8").length;
|
|
46881
45129
|
} catch {
|
|
46882
45130
|
chars = 0;
|
|
46883
45131
|
}
|
|
@@ -47009,9 +45257,9 @@ ${divider}
|
|
|
47009
45257
|
|
|
47010
45258
|
// plugins/kxm/src/ssh-remote.ts
|
|
47011
45259
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
47012
|
-
import { existsSync as
|
|
45260
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync27, readFileSync as readFileSync34, readdirSync as readdirSync13, rmSync as rmSync11, statSync as statSync5 } from "node:fs";
|
|
47013
45261
|
import { homedir as homedir8 } from "node:os";
|
|
47014
|
-
import { join as
|
|
45262
|
+
import { join as join44, resolve as resolve26 } from "node:path";
|
|
47015
45263
|
var MAX_SSH_OUTPUT_BYTES = 50 * 1024;
|
|
47016
45264
|
var MAX_SSH_OUTPUT_LINES = 2e3;
|
|
47017
45265
|
var DEFAULT_SOCKET_DIR = ".kxm/run/ssh-sockets";
|
|
@@ -47037,12 +45285,12 @@ function truncateSshOutput(raw) {
|
|
|
47037
45285
|
return { text, truncated };
|
|
47038
45286
|
}
|
|
47039
45287
|
function parseSshConfig(configPath) {
|
|
47040
|
-
const targetPath = configPath ??
|
|
47041
|
-
if (!
|
|
45288
|
+
const targetPath = configPath ?? join44(homedir8(), ".ssh", "config");
|
|
45289
|
+
if (!existsSync34(targetPath)) {
|
|
47042
45290
|
return [];
|
|
47043
45291
|
}
|
|
47044
45292
|
try {
|
|
47045
|
-
const content =
|
|
45293
|
+
const content = readFileSync34(targetPath, "utf-8");
|
|
47046
45294
|
const lines = content.split("\n");
|
|
47047
45295
|
const hosts = [];
|
|
47048
45296
|
let currentHosts = [];
|
|
@@ -47119,15 +45367,15 @@ function resolveSshHostG(host, execFn = spawnSync7) {
|
|
|
47119
45367
|
}
|
|
47120
45368
|
}
|
|
47121
45369
|
function ensureSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
47122
|
-
const resolved =
|
|
47123
|
-
if (!
|
|
47124
|
-
|
|
45370
|
+
const resolved = resolve26(socketDir);
|
|
45371
|
+
if (!existsSync34(resolved)) {
|
|
45372
|
+
mkdirSync27(resolved, { recursive: true, mode: 448 });
|
|
47125
45373
|
}
|
|
47126
45374
|
return resolved;
|
|
47127
45375
|
}
|
|
47128
45376
|
function buildSshArgs(options) {
|
|
47129
45377
|
const socketDir = ensureSocketDir(options.socketDir ?? DEFAULT_SOCKET_DIR);
|
|
47130
|
-
const controlPath =
|
|
45378
|
+
const controlPath = join44(socketDir, "%C");
|
|
47131
45379
|
const persist = options.controlPersist ?? DEFAULT_CONTROL_PERSIST;
|
|
47132
45380
|
const args = [
|
|
47133
45381
|
"-o",
|
|
@@ -47152,7 +45400,7 @@ function buildSshArgs(options) {
|
|
|
47152
45400
|
}
|
|
47153
45401
|
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
47154
45402
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
47155
|
-
const controlPath =
|
|
45403
|
+
const controlPath = join44(resolvedDir, "%C");
|
|
47156
45404
|
try {
|
|
47157
45405
|
const result = execFn("ssh", ["-O", "check", "-o", `ControlPath=${controlPath}`, host], {
|
|
47158
45406
|
encoding: "utf-8"
|
|
@@ -47164,7 +45412,7 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
47164
45412
|
}
|
|
47165
45413
|
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
47166
45414
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
47167
|
-
const controlPath =
|
|
45415
|
+
const controlPath = join44(resolvedDir, "%C");
|
|
47168
45416
|
try {
|
|
47169
45417
|
const result = execFn("ssh", ["-O", "stop", "-o", `ControlPath=${controlPath}`, host], {
|
|
47170
45418
|
encoding: "utf-8"
|
|
@@ -47376,7 +45624,6 @@ function executeSshRun(params) {
|
|
|
47376
45624
|
// plugins/kxm/src/autocomplete.ts
|
|
47377
45625
|
var TOP_LEVEL_COMMANDS = [
|
|
47378
45626
|
"init",
|
|
47379
|
-
"migrate",
|
|
47380
45627
|
"backup",
|
|
47381
45628
|
"restore",
|
|
47382
45629
|
"run",
|
|
@@ -47409,7 +45656,6 @@ var TOP_LEVEL_COMMANDS = [
|
|
|
47409
45656
|
];
|
|
47410
45657
|
var SUBCOMMANDS = {
|
|
47411
45658
|
runs: ["status", "cancel", "list"],
|
|
47412
|
-
migrate: ["plan", "apply", "verify"],
|
|
47413
45659
|
harness: ["list"],
|
|
47414
45660
|
runtime: ["start", "status", "stop"],
|
|
47415
45661
|
trust: ["diff", "check"],
|
|
@@ -47501,7 +45747,6 @@ _kxm() {
|
|
|
47501
45747
|
local -a commands
|
|
47502
45748
|
commands=(
|
|
47503
45749
|
'init:Create or validate a KXM project'
|
|
47504
|
-
'migrate:Plan, apply, and verify legacy configuration migration'
|
|
47505
45750
|
'backup:Create a verified SQLite backup manifest'
|
|
47506
45751
|
'restore:Restore SQLite stores from a backup manifest'
|
|
47507
45752
|
'run:Create a KXM workflow run'
|
|
@@ -47610,9 +45855,9 @@ complete -c kxm -n "__fish_seen_subcommand_from goal" -a "create list get"
|
|
|
47610
45855
|
}
|
|
47611
45856
|
|
|
47612
45857
|
// plugins/kxm/src/completion-install.ts
|
|
47613
|
-
import { existsSync as
|
|
45858
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync28, readFileSync as readFileSync35, writeFileSync as writeFileSync25 } from "node:fs";
|
|
47614
45859
|
import { homedir as homedir9 } from "node:os";
|
|
47615
|
-
import { basename as basename9, delimiter, dirname as dirname22, isAbsolute as isAbsolute9, join as
|
|
45860
|
+
import { basename as basename9, delimiter, dirname as dirname22, isAbsolute as isAbsolute9, join as join45, resolve as resolve27 } from "node:path";
|
|
47616
45861
|
var COMPLETION_MARKER = "# kxm completion";
|
|
47617
45862
|
var PATH_MARKER = "# kxm path";
|
|
47618
45863
|
function detectShell(env = process.env, platform = process.platform) {
|
|
@@ -47628,31 +45873,31 @@ function effectiveHome(options) {
|
|
|
47628
45873
|
const env = options.env ?? process.env;
|
|
47629
45874
|
if (options.homeDir) return options.homeDir;
|
|
47630
45875
|
const envHome = env.HOME?.trim() ?? env.USERPROFILE?.trim();
|
|
47631
|
-
return envHome && envHome.length > 0 ?
|
|
45876
|
+
return envHome && envHome.length > 0 ? resolve27(envHome) : homedir9();
|
|
47632
45877
|
}
|
|
47633
45878
|
function completionScriptPath(shell, options = {}) {
|
|
47634
45879
|
const env = options.env ?? process.env;
|
|
47635
45880
|
const explicit = options.configDir ?? env.KXM_USER_CONFIG_DIR?.trim();
|
|
47636
|
-
const base = explicit && explicit.length > 0 ?
|
|
47637
|
-
return
|
|
45881
|
+
const base = explicit && explicit.length > 0 ? resolve27(explicit) : resolve27(effectiveHome(options), ".config", "kxm");
|
|
45882
|
+
return join45(base, "completions", `kxm.${shell}`);
|
|
47638
45883
|
}
|
|
47639
45884
|
function bashRcCandidate(options) {
|
|
47640
45885
|
const home = effectiveHome(options);
|
|
47641
|
-
const candidates = [
|
|
47642
|
-
const existing = candidates.find((candidate) =>
|
|
45886
|
+
const candidates = [join45(home, ".bashrc"), join45(home, ".bash_profile")];
|
|
45887
|
+
const existing = candidates.find((candidate) => existsSync35(candidate));
|
|
47643
45888
|
return existing ?? candidates[0];
|
|
47644
45889
|
}
|
|
47645
45890
|
function zshRcCandidate(options) {
|
|
47646
45891
|
const env = options.env ?? process.env;
|
|
47647
45892
|
const home = effectiveHome(options);
|
|
47648
|
-
if (env.ZDOTDIR?.trim()) return
|
|
47649
|
-
return
|
|
45893
|
+
if (env.ZDOTDIR?.trim()) return join45(resolve27(env.ZDOTDIR.trim()), ".zshrc");
|
|
45894
|
+
return join45(home, ".zshrc");
|
|
47650
45895
|
}
|
|
47651
45896
|
function fishCompletionTarget(shell, options) {
|
|
47652
45897
|
const env = options.env ?? process.env;
|
|
47653
45898
|
const home = effectiveHome(options);
|
|
47654
|
-
if (env.XDG_CONFIG_HOME?.trim()) return
|
|
47655
|
-
return
|
|
45899
|
+
if (env.XDG_CONFIG_HOME?.trim()) return join45(resolve27(env.XDG_CONFIG_HOME.trim()), "fish", "completions", "kxm.fish");
|
|
45900
|
+
return join45(home, ".config", "fish", "completions", "kxm.fish");
|
|
47656
45901
|
}
|
|
47657
45902
|
function completionRcTarget(shell, options = {}) {
|
|
47658
45903
|
if (shell === "fish") {
|
|
@@ -47684,17 +45929,17 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47684
45929
|
const scriptPath = completionScriptPath(shell, options);
|
|
47685
45930
|
const { rcFile } = completionRcTarget(shell, options);
|
|
47686
45931
|
const script = generateShellCompletion(shell);
|
|
47687
|
-
const existingScript =
|
|
47688
|
-
const existingScriptMatches = existingScript &&
|
|
45932
|
+
const existingScript = existsSync35(scriptPath);
|
|
45933
|
+
const existingScriptMatches = existingScript && readFileSync35(scriptPath, "utf8") === script;
|
|
47689
45934
|
let rcModified = false;
|
|
47690
45935
|
let alreadyInstalled = false;
|
|
47691
45936
|
if (shell === "fish") {
|
|
47692
45937
|
const fishTarget = fishCompletionTarget(shell, options);
|
|
47693
|
-
const fishInstalled =
|
|
45938
|
+
const fishInstalled = existsSync35(fishTarget) && readFileSync35(fishTarget, "utf8") === script;
|
|
47694
45939
|
alreadyInstalled = fishInstalled;
|
|
47695
45940
|
if (!options.dryRun && (!fishInstalled || options.overwrite)) {
|
|
47696
|
-
|
|
47697
|
-
|
|
45941
|
+
mkdirSync28(resolve27(fishTarget, ".."), { recursive: true });
|
|
45942
|
+
writeFileSync25(fishTarget, script, { encoding: "utf8" });
|
|
47698
45943
|
}
|
|
47699
45944
|
return {
|
|
47700
45945
|
ok: true,
|
|
@@ -47707,13 +45952,13 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47707
45952
|
}
|
|
47708
45953
|
if (rcFile) {
|
|
47709
45954
|
const line = sourceLine(shell, scriptPath);
|
|
47710
|
-
const rcContent =
|
|
45955
|
+
const rcContent = existsSync35(rcFile) ? readFileSync35(rcFile, "utf8") : "";
|
|
47711
45956
|
alreadyInstalled = rcContent.includes(line) || rcContent.includes(`${COMPLETION_MARKER}`);
|
|
47712
45957
|
}
|
|
47713
45958
|
if (!options.dryRun) {
|
|
47714
45959
|
if (!existingScriptMatches || options.overwrite) {
|
|
47715
|
-
|
|
47716
|
-
|
|
45960
|
+
mkdirSync28(resolve27(scriptPath, ".."), { recursive: true });
|
|
45961
|
+
writeFileSync25(scriptPath, script, { encoding: "utf8" });
|
|
47717
45962
|
}
|
|
47718
45963
|
if (rcFile && !alreadyInstalled) {
|
|
47719
45964
|
const line = sourceLine(shell, scriptPath);
|
|
@@ -47722,8 +45967,8 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47722
45967
|
${marker}
|
|
47723
45968
|
${line}
|
|
47724
45969
|
`;
|
|
47725
|
-
|
|
47726
|
-
|
|
45970
|
+
mkdirSync28(resolve27(rcFile, ".."), { recursive: true });
|
|
45971
|
+
writeFileSync25(rcFile, (existsSync35(rcFile) ? readFileSync35(rcFile, "utf8") : "") + stanza, { encoding: "utf8" });
|
|
47727
45972
|
rcModified = true;
|
|
47728
45973
|
}
|
|
47729
45974
|
}
|
|
@@ -47740,13 +45985,13 @@ function kxmBinDir(env = process.env) {
|
|
|
47740
45985
|
const argv1 = env.KXM_ENTRY ?? process.argv[1];
|
|
47741
45986
|
if (argv1 && isAbsolute9(argv1)) {
|
|
47742
45987
|
const dir = dirname22(argv1);
|
|
47743
|
-
if (
|
|
45988
|
+
if (existsSync35(join45(dir, process.platform === "win32" ? "kxm.cmd" : "kxm"))) return dir;
|
|
47744
45989
|
}
|
|
47745
45990
|
const pathEnv = env.PATH ?? "";
|
|
47746
45991
|
for (const part of pathEnv.split(delimiter)) {
|
|
47747
45992
|
if (!part) continue;
|
|
47748
|
-
const candidate =
|
|
47749
|
-
if (
|
|
45993
|
+
const candidate = resolve27(part, process.platform === "win32" ? "kxm.cmd" : "kxm");
|
|
45994
|
+
if (existsSync35(candidate)) return resolve27(part);
|
|
47750
45995
|
}
|
|
47751
45996
|
return void 0;
|
|
47752
45997
|
}
|
|
@@ -47764,11 +46009,11 @@ function installPathEntry(shellInput, options = {}) {
|
|
|
47764
46009
|
}
|
|
47765
46010
|
const { rcFile } = completionRcTarget(shell, options);
|
|
47766
46011
|
const line = pathLine(binDir);
|
|
47767
|
-
const rcContent =
|
|
46012
|
+
const rcContent = existsSync35(rcFile ?? "") ? readFileSync35(rcFile, "utf8") : "";
|
|
47768
46013
|
const alreadyInstalled = rcContent.includes(binDir) || (options.env?.PATH ?? process.env.PATH ?? "").split(delimiter).includes(binDir);
|
|
47769
46014
|
if (!options.dryRun && rcFile && !alreadyInstalled) {
|
|
47770
|
-
|
|
47771
|
-
|
|
46015
|
+
mkdirSync28(dirname22(rcFile), { recursive: true });
|
|
46016
|
+
writeFileSync25(rcFile, rcContent + `
|
|
47772
46017
|
${PATH_MARKER}
|
|
47773
46018
|
${line}
|
|
47774
46019
|
`, { encoding: "utf8" });
|
|
@@ -47777,9 +46022,9 @@ ${line}
|
|
|
47777
46022
|
}
|
|
47778
46023
|
|
|
47779
46024
|
// plugins/kxm/src/init-guide-setup.ts
|
|
47780
|
-
var
|
|
47781
|
-
import { existsSync as
|
|
47782
|
-
import { dirname as dirname23, join as
|
|
46025
|
+
var import_yaml17 = __toESM(require_dist(), 1);
|
|
46026
|
+
import { existsSync as existsSync36, mkdirSync as mkdirSync29, writeFileSync as writeFileSync26 } from "node:fs";
|
|
46027
|
+
import { dirname as dirname23, join as join46 } from "node:path";
|
|
47783
46028
|
var NATIVE_VENDOR_HARNESS = Object.freeze({
|
|
47784
46029
|
anthropic: "claude",
|
|
47785
46030
|
openai: "codex",
|
|
@@ -48178,14 +46423,14 @@ function renderGuideSetupFiles(projectRoot, plan) {
|
|
|
48178
46423
|
const stage = roleStages.get(role);
|
|
48179
46424
|
if (!stage) continue;
|
|
48180
46425
|
files.push({
|
|
48181
|
-
path:
|
|
48182
|
-
content: (0,
|
|
46426
|
+
path: join46(projectRoot, ".kxm", "agents", `${role}.yaml`),
|
|
46427
|
+
content: (0, import_yaml17.stringify)(agentDocument(role, stage, binding))
|
|
48183
46428
|
});
|
|
48184
46429
|
}
|
|
48185
46430
|
for (const workflow of plan.workflows) {
|
|
48186
46431
|
files.push({
|
|
48187
|
-
path:
|
|
48188
|
-
content: (0,
|
|
46432
|
+
path: join46(projectRoot, ".kxm", "workflows", `${workflow.slug}.yaml`),
|
|
46433
|
+
content: (0, import_yaml17.stringify)(workflowDocument(workflow))
|
|
48189
46434
|
});
|
|
48190
46435
|
}
|
|
48191
46436
|
return files;
|
|
@@ -48194,12 +46439,12 @@ function writeGuideSetupFiles(files) {
|
|
|
48194
46439
|
const written = [];
|
|
48195
46440
|
const existed = [];
|
|
48196
46441
|
for (const file of files) {
|
|
48197
|
-
if (
|
|
46442
|
+
if (existsSync36(file.path)) {
|
|
48198
46443
|
existed.push(file.path);
|
|
48199
46444
|
continue;
|
|
48200
46445
|
}
|
|
48201
|
-
|
|
48202
|
-
|
|
46446
|
+
mkdirSync29(dirname23(file.path), { recursive: true });
|
|
46447
|
+
writeFileSync26(file.path, file.content, "utf8");
|
|
48203
46448
|
written.push(file.path);
|
|
48204
46449
|
}
|
|
48205
46450
|
return { written, existed };
|
|
@@ -48262,7 +46507,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
48262
46507
|
detail: `release v${notice.latest} has no sha256 digest for ${name}; refusing to install`
|
|
48263
46508
|
};
|
|
48264
46509
|
}
|
|
48265
|
-
const releaseDir = mkdtempSync2(
|
|
46510
|
+
const releaseDir = mkdtempSync2(join47(tmpdir2(), "kxm-pkg-update-"));
|
|
48266
46511
|
try {
|
|
48267
46512
|
const planned = planKxmPackageUpdate(notice.source, notice.latest, releaseDir, notice.asset);
|
|
48268
46513
|
if (runtime.dryRun) {
|
|
@@ -48271,7 +46516,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
48271
46516
|
for (const step of planned) {
|
|
48272
46517
|
if (step.kind === "verify") {
|
|
48273
46518
|
if (!verifyReleaseAssetDigest(step.path, step.sha256)) {
|
|
48274
|
-
const actual =
|
|
46519
|
+
const actual = existsSync37(step.path) ? createHash15("sha256").update(readFileSync36(step.path)).digest("hex") : "missing";
|
|
48275
46520
|
return {
|
|
48276
46521
|
ok: false,
|
|
48277
46522
|
error: "release_digest_mismatch",
|
|
@@ -48288,7 +46533,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
48288
46533
|
}
|
|
48289
46534
|
return { ok: true, detail: `installed ${notice.latest} from ${notice.source}` };
|
|
48290
46535
|
} finally {
|
|
48291
|
-
|
|
46536
|
+
rmSync12(releaseDir, { recursive: true, force: true });
|
|
48292
46537
|
}
|
|
48293
46538
|
}
|
|
48294
46539
|
async function cmdExplain(runtime, options) {
|
|
@@ -48536,13 +46781,13 @@ async function cmdValidate(runtime, fileFlag) {
|
|
|
48536
46781
|
return 2;
|
|
48537
46782
|
}
|
|
48538
46783
|
const selectedFile = explicitFile || configuredFile;
|
|
48539
|
-
const file = selectedFile ?
|
|
48540
|
-
if (file && !
|
|
46784
|
+
const file = selectedFile ? resolve28(runtime.cwd, selectedFile) : void 0;
|
|
46785
|
+
if (file && !existsSync37(file)) {
|
|
48541
46786
|
printWorker(runtime, worker, { ok: false, command: "validate", error: "file_not_found", file }, `workflow file not found: ${file}`);
|
|
48542
46787
|
return 1;
|
|
48543
46788
|
}
|
|
48544
46789
|
try {
|
|
48545
|
-
const raw = file ?
|
|
46790
|
+
const raw = file ? readFileSync36(file, "utf8") : inline;
|
|
48546
46791
|
const warnings = [];
|
|
48547
46792
|
const definitions = parseWorkflowDefinitions(raw, runtime.env, (message) => warnings.push(message));
|
|
48548
46793
|
const secretEnvs = definitions.map((definition) => ({
|
|
@@ -48567,7 +46812,7 @@ async function cmdValidate(runtime, fileFlag) {
|
|
|
48567
46812
|
}
|
|
48568
46813
|
async function cmdArtifactsExist(runtime, pathFlag) {
|
|
48569
46814
|
const worker = gateOf(runtime, "artifacts-exist");
|
|
48570
|
-
const checked = verifyArtifactExists(runtime.dirs.assets,
|
|
46815
|
+
const checked = verifyArtifactExists(runtime.dirs.assets, resolve28(runtime.cwd, pathFlag));
|
|
48571
46816
|
if (!checked.ok) {
|
|
48572
46817
|
printWorker(
|
|
48573
46818
|
runtime,
|
|
@@ -48586,15 +46831,15 @@ async function cmdArtifactsExist(runtime, pathFlag) {
|
|
|
48586
46831
|
return 0;
|
|
48587
46832
|
}
|
|
48588
46833
|
async function cmdImprove(runtime, options = {}) {
|
|
48589
|
-
const file = options.file ?
|
|
48590
|
-
const routingRecords =
|
|
48591
|
-
const candidatesDir = options.outDir ?
|
|
46834
|
+
const file = options.file ? resolve28(runtime.cwd, options.file) : telemetryPath(runtime.dirs.logs);
|
|
46835
|
+
const routingRecords = existsSync37(file) ? readRoutingRecords(file).map((entry) => entry.routing) : [];
|
|
46836
|
+
const candidatesDir = options.outDir ? resolve28(runtime.cwd, options.outDir) : join47(runtime.cwd, ".kxm", "candidates");
|
|
48592
46837
|
const report2 = buildImprovementReport(routingRecords, {
|
|
48593
46838
|
candidatesDir,
|
|
48594
46839
|
projectRoot: runtime.cwd,
|
|
48595
46840
|
dryRun: runtime.dryRun
|
|
48596
46841
|
});
|
|
48597
|
-
const reportDir =
|
|
46842
|
+
const reportDir = join47(runtime.dirs.assets, "improvements");
|
|
48598
46843
|
const reportPath = writeImprovementReport(reportDir, report2, runtime.dryRun);
|
|
48599
46844
|
const text = formatImprovementReport(report2);
|
|
48600
46845
|
print(runtime.io, runtime.json, {
|
|
@@ -48726,9 +46971,9 @@ async function maybeOfferCompletionInstall(runtime) {
|
|
|
48726
46971
|
if (!pathNeeded) {
|
|
48727
46972
|
const scriptPath = completionScriptPath(shell, { env: runtime.env, configDir: runtime.env.KXM_USER_CONFIG_DIR });
|
|
48728
46973
|
const { rcFile } = completionRcTarget(shell, { env: runtime.env });
|
|
48729
|
-
if (rcFile &&
|
|
46974
|
+
if (rcFile && existsSync37(rcFile)) {
|
|
48730
46975
|
try {
|
|
48731
|
-
if (
|
|
46976
|
+
if (readFileSync36(rcFile, "utf8").includes(scriptPath)) return;
|
|
48732
46977
|
} catch {
|
|
48733
46978
|
}
|
|
48734
46979
|
}
|
|
@@ -48860,7 +47105,7 @@ async function cmdRoutingReport(runtime, options) {
|
|
|
48860
47105
|
let catalog;
|
|
48861
47106
|
if (includeEquivalentListCost) {
|
|
48862
47107
|
try {
|
|
48863
|
-
const pricesPath = options.prices ?
|
|
47108
|
+
const pricesPath = options.prices ? resolve28(runtime.cwd, options.prices) : join47(runtime.dirs.workspace, "prices.yaml");
|
|
48864
47109
|
catalog = loadPriceCatalog(pricesPath);
|
|
48865
47110
|
} catch {
|
|
48866
47111
|
}
|
|
@@ -49092,23 +47337,12 @@ function createProgram(ctx, result) {
|
|
|
49092
47337
|
writeErr: (text) => ctx.io.stderr(text)
|
|
49093
47338
|
}).helpCommand("help", "Show help");
|
|
49094
47339
|
addGlobalOptions(program2);
|
|
49095
|
-
program2.command("init").description("Create, validate, or
|
|
47340
|
+
program2.command("init").description("Create, validate, repair, or join 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) {
|
|
49096
47341
|
result.code = await cmdKxmInit(runtimeFrom(ctx, this), options, {
|
|
49097
47342
|
maybeOfferCompletionInstall,
|
|
49098
47343
|
maybeOfferGuideSetup
|
|
49099
47344
|
});
|
|
49100
47345
|
});
|
|
49101
|
-
const migrate = addGlobalOptions(program2.command("migrate").description("Plan, apply, and verify legacy JSON configuration migration"));
|
|
49102
|
-
migrate.helpCommand("help", "Show migrate help");
|
|
49103
|
-
addGlobalOptions(migrate.command("plan").description("Compute the deterministic legacy-to-KXM migration plan without writes")).action(async function migratePlanAction() {
|
|
49104
|
-
result.code = await cmdKxmMigratePlan(runtimeFrom(ctx, this));
|
|
49105
|
-
});
|
|
49106
|
-
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) {
|
|
49107
|
-
result.code = await cmdKxmMigrateApply(runtimeFrom(ctx, this), options);
|
|
49108
|
-
});
|
|
49109
|
-
addGlobalOptions(migrate.command("verify").description("Verify a migration receipt against current sources and target bundle")).action(async function migrateVerifyAction() {
|
|
49110
|
-
result.code = await cmdKxmMigrateVerify(runtimeFrom(ctx, this));
|
|
49111
|
-
});
|
|
49112
47346
|
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) {
|
|
49113
47347
|
result.code = await cmdBackup(runtimeFrom(ctx, this), options);
|
|
49114
47348
|
});
|
|
@@ -49565,7 +47799,7 @@ async function runCli(argv, env = process.env, io = { stdout: (text) => process.
|
|
|
49565
47799
|
throw error;
|
|
49566
47800
|
}
|
|
49567
47801
|
}
|
|
49568
|
-
if (process.argv[1] &&
|
|
47802
|
+
if (process.argv[1] && resolve29(process.argv[1]) === fileURLToPath4(import.meta.url)) {
|
|
49569
47803
|
const code = await runCli(process.argv.slice(2));
|
|
49570
47804
|
process.exitCode = code;
|
|
49571
47805
|
}
|