@kontextmind/kxm 0.7.103 → 0.7.104
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 +27 -8
- package/docs/concepts/data-and-storage.md +1 -1
- package/docs/contributing/test-matrix.md +7 -5
- package/docs/operations/backup-and-restore.md +59 -27
- package/docs/operations/deploy.md +1 -1
- package/docs/reference/cli-reference.md +31 -20
- package/docs/reference/config-reference.md +1 -1
- package/docs/start/quickstart-claude-code.md +1 -1
- package/docs/templates/runbook.md +2 -1
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +788 -649
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/runtime-supervisor.js +321 -291
- package/plugins/kxm/dist/runtime.js +424 -348
- package/plugins/kxm/dist/server.js +78 -78
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +14 -7
- package/plugins/kxm/src/cli/project.ts +66 -12
- package/plugins/kxm/src/cli.ts +7 -5
- package/plugins/kxm/src/database.ts +193 -65
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/runtime-paths.ts +50 -0
- package/plugins/kxm/src/runtime-store.ts +22 -53
- package/plugins/kxm/src/runtime-supervisor.ts +38 -17
- package/schemas/backup-manifest.schema.json +15 -0
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -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 = resolve35.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 resolve35(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 resolve35(baseURI, relativeURI, options) {
|
|
3843
3843
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3844
3844
|
const {
|
|
3845
3845
|
parsed: baseParsed,
|
|
@@ -3872,49 +3872,49 @@ var require_fast_uri = __commonJS({
|
|
|
3872
3872
|
schemelessOptions.skipEscape = true;
|
|
3873
3873
|
return serialize(resolved, schemelessOptions);
|
|
3874
3874
|
}
|
|
3875
|
-
function resolveComponent(base,
|
|
3875
|
+
function resolveComponent(base, relative8, options, skipNormalization) {
|
|
3876
3876
|
const target = {};
|
|
3877
3877
|
if (!skipNormalization) {
|
|
3878
3878
|
base = parse12(serialize(base, options), options);
|
|
3879
|
-
|
|
3879
|
+
relative8 = parse12(serialize(relative8, options), options);
|
|
3880
3880
|
}
|
|
3881
3881
|
options = options || {};
|
|
3882
|
-
if (!options.tolerant &&
|
|
3883
|
-
target.scheme =
|
|
3884
|
-
target.userinfo =
|
|
3885
|
-
target.host =
|
|
3886
|
-
target.port =
|
|
3887
|
-
target.path = removeDotSegments(
|
|
3888
|
-
target.query =
|
|
3882
|
+
if (!options.tolerant && relative8.scheme) {
|
|
3883
|
+
target.scheme = relative8.scheme;
|
|
3884
|
+
target.userinfo = relative8.userinfo;
|
|
3885
|
+
target.host = relative8.host;
|
|
3886
|
+
target.port = relative8.port;
|
|
3887
|
+
target.path = removeDotSegments(relative8.path || "");
|
|
3888
|
+
target.query = relative8.query;
|
|
3889
3889
|
} else {
|
|
3890
|
-
if (
|
|
3891
|
-
target.userinfo =
|
|
3892
|
-
target.host =
|
|
3893
|
-
target.port =
|
|
3894
|
-
target.path = removeDotSegments(
|
|
3895
|
-
target.query =
|
|
3890
|
+
if (relative8.userinfo !== void 0 || relative8.host !== void 0 || relative8.port !== void 0) {
|
|
3891
|
+
target.userinfo = relative8.userinfo;
|
|
3892
|
+
target.host = relative8.host;
|
|
3893
|
+
target.port = relative8.port;
|
|
3894
|
+
target.path = removeDotSegments(relative8.path || "");
|
|
3895
|
+
target.query = relative8.query;
|
|
3896
3896
|
} else {
|
|
3897
|
-
if (!
|
|
3897
|
+
if (!relative8.path) {
|
|
3898
3898
|
target.path = base.path;
|
|
3899
|
-
if (
|
|
3900
|
-
target.query =
|
|
3899
|
+
if (relative8.query !== void 0) {
|
|
3900
|
+
target.query = relative8.query;
|
|
3901
3901
|
} else {
|
|
3902
3902
|
target.query = base.query;
|
|
3903
3903
|
}
|
|
3904
3904
|
} else {
|
|
3905
|
-
if (
|
|
3906
|
-
target.path = removeDotSegments(
|
|
3905
|
+
if (relative8.path[0] === "/") {
|
|
3906
|
+
target.path = removeDotSegments(relative8.path);
|
|
3907
3907
|
} else {
|
|
3908
3908
|
if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
|
|
3909
|
-
target.path = "/" +
|
|
3909
|
+
target.path = "/" + relative8.path;
|
|
3910
3910
|
} else if (!base.path) {
|
|
3911
|
-
target.path =
|
|
3911
|
+
target.path = relative8.path;
|
|
3912
3912
|
} else {
|
|
3913
|
-
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) +
|
|
3913
|
+
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative8.path;
|
|
3914
3914
|
}
|
|
3915
3915
|
target.path = removeDotSegments(target.path);
|
|
3916
3916
|
}
|
|
3917
|
-
target.query =
|
|
3917
|
+
target.query = relative8.query;
|
|
3918
3918
|
}
|
|
3919
3919
|
target.userinfo = base.userinfo;
|
|
3920
3920
|
target.host = base.host;
|
|
@@ -3922,7 +3922,7 @@ var require_fast_uri = __commonJS({
|
|
|
3922
3922
|
}
|
|
3923
3923
|
target.scheme = base.scheme;
|
|
3924
3924
|
}
|
|
3925
|
-
target.fragment =
|
|
3925
|
+
target.fragment = relative8.fragment;
|
|
3926
3926
|
return target;
|
|
3927
3927
|
}
|
|
3928
3928
|
function equal(uriA, uriB, options) {
|
|
@@ -4201,7 +4201,7 @@ var require_fast_uri = __commonJS({
|
|
|
4201
4201
|
var fastUri = {
|
|
4202
4202
|
SCHEMES,
|
|
4203
4203
|
normalize,
|
|
4204
|
-
resolve:
|
|
4204
|
+
resolve: resolve35,
|
|
4205
4205
|
resolveComponent,
|
|
4206
4206
|
equal,
|
|
4207
4207
|
serialize,
|
|
@@ -11411,10 +11411,10 @@ var require_resolve_block_map = __commonJS({
|
|
|
11411
11411
|
let offset = bm.offset;
|
|
11412
11412
|
let commentEnd = null;
|
|
11413
11413
|
for (const collItem of bm.items) {
|
|
11414
|
-
const { start, key, sep:
|
|
11414
|
+
const { start, key, sep: sep5, value } = collItem;
|
|
11415
11415
|
const keyProps = resolveProps.resolveProps(start, {
|
|
11416
11416
|
indicator: "explicit-key-ind",
|
|
11417
|
-
next: key ??
|
|
11417
|
+
next: key ?? sep5?.[0],
|
|
11418
11418
|
offset,
|
|
11419
11419
|
onError,
|
|
11420
11420
|
parentIndent: bm.indent,
|
|
@@ -11428,7 +11428,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
11428
11428
|
else if ("indent" in key && key.indent !== bm.indent)
|
|
11429
11429
|
onError(offset, "BAD_INDENT", startColMsg);
|
|
11430
11430
|
}
|
|
11431
|
-
if (!keyProps.anchor && !keyProps.tag && !
|
|
11431
|
+
if (!keyProps.anchor && !keyProps.tag && !sep5) {
|
|
11432
11432
|
commentEnd = keyProps.end;
|
|
11433
11433
|
if (keyProps.comment) {
|
|
11434
11434
|
if (map.comment)
|
|
@@ -11452,7 +11452,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
11452
11452
|
ctx.atKey = false;
|
|
11453
11453
|
if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
|
|
11454
11454
|
onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
|
|
11455
|
-
const valueProps = resolveProps.resolveProps(
|
|
11455
|
+
const valueProps = resolveProps.resolveProps(sep5 ?? [], {
|
|
11456
11456
|
indicator: "map-value-ind",
|
|
11457
11457
|
next: value,
|
|
11458
11458
|
offset: keyNode.range[2],
|
|
@@ -11468,7 +11468,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
11468
11468
|
if (ctx.options.strict && keyProps.start < valueProps.found.offset - 1024)
|
|
11469
11469
|
onError(keyNode.range, "KEY_OVER_1024_CHARS", "The : indicator must be at most 1024 chars after the start of an implicit block mapping key");
|
|
11470
11470
|
}
|
|
11471
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset,
|
|
11471
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep5, null, valueProps, onError);
|
|
11472
11472
|
if (ctx.schema.compat)
|
|
11473
11473
|
utilFlowIndentCheck.flowIndentCheck(bm.indent, value, onError);
|
|
11474
11474
|
offset = valueNode.range[2];
|
|
@@ -11559,7 +11559,7 @@ var require_resolve_end = __commonJS({
|
|
|
11559
11559
|
let comment = "";
|
|
11560
11560
|
if (end) {
|
|
11561
11561
|
let hasSpace = false;
|
|
11562
|
-
let
|
|
11562
|
+
let sep5 = "";
|
|
11563
11563
|
for (const token of end) {
|
|
11564
11564
|
const { source, type } = token;
|
|
11565
11565
|
switch (type) {
|
|
@@ -11573,13 +11573,13 @@ var require_resolve_end = __commonJS({
|
|
|
11573
11573
|
if (!comment)
|
|
11574
11574
|
comment = cb;
|
|
11575
11575
|
else
|
|
11576
|
-
comment +=
|
|
11577
|
-
|
|
11576
|
+
comment += sep5 + cb;
|
|
11577
|
+
sep5 = "";
|
|
11578
11578
|
break;
|
|
11579
11579
|
}
|
|
11580
11580
|
case "newline":
|
|
11581
11581
|
if (comment)
|
|
11582
|
-
|
|
11582
|
+
sep5 += source;
|
|
11583
11583
|
hasSpace = true;
|
|
11584
11584
|
break;
|
|
11585
11585
|
default:
|
|
@@ -11622,18 +11622,18 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
11622
11622
|
let offset = fc.offset + fc.start.source.length;
|
|
11623
11623
|
for (let i = 0; i < fc.items.length; ++i) {
|
|
11624
11624
|
const collItem = fc.items[i];
|
|
11625
|
-
const { start, key, sep:
|
|
11625
|
+
const { start, key, sep: sep5, value } = collItem;
|
|
11626
11626
|
const props = resolveProps.resolveProps(start, {
|
|
11627
11627
|
flow: fcName,
|
|
11628
11628
|
indicator: "explicit-key-ind",
|
|
11629
|
-
next: key ??
|
|
11629
|
+
next: key ?? sep5?.[0],
|
|
11630
11630
|
offset,
|
|
11631
11631
|
onError,
|
|
11632
11632
|
parentIndent: fc.indent,
|
|
11633
11633
|
startOnNewline: false
|
|
11634
11634
|
});
|
|
11635
11635
|
if (!props.found) {
|
|
11636
|
-
if (!props.anchor && !props.tag && !
|
|
11636
|
+
if (!props.anchor && !props.tag && !sep5 && !value) {
|
|
11637
11637
|
if (i === 0 && props.comma)
|
|
11638
11638
|
onError(props.comma, "UNEXPECTED_TOKEN", `Unexpected , in ${fcName}`);
|
|
11639
11639
|
else if (i < fc.items.length - 1)
|
|
@@ -11687,8 +11687,8 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
11687
11687
|
}
|
|
11688
11688
|
}
|
|
11689
11689
|
}
|
|
11690
|
-
if (!isMap2 && !
|
|
11691
|
-
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end,
|
|
11690
|
+
if (!isMap2 && !sep5 && !props.found) {
|
|
11691
|
+
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep5, null, props, onError);
|
|
11692
11692
|
coll.items.push(valueNode);
|
|
11693
11693
|
offset = valueNode.range[2];
|
|
11694
11694
|
if (isBlock(value))
|
|
@@ -11700,7 +11700,7 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
11700
11700
|
if (isBlock(key))
|
|
11701
11701
|
onError(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
11702
11702
|
ctx.atKey = false;
|
|
11703
|
-
const valueProps = resolveProps.resolveProps(
|
|
11703
|
+
const valueProps = resolveProps.resolveProps(sep5 ?? [], {
|
|
11704
11704
|
flow: fcName,
|
|
11705
11705
|
indicator: "map-value-ind",
|
|
11706
11706
|
next: value,
|
|
@@ -11711,8 +11711,8 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
11711
11711
|
});
|
|
11712
11712
|
if (valueProps.found) {
|
|
11713
11713
|
if (!isMap2 && !props.found && ctx.options.strict) {
|
|
11714
|
-
if (
|
|
11715
|
-
for (const st2 of
|
|
11714
|
+
if (sep5)
|
|
11715
|
+
for (const st2 of sep5) {
|
|
11716
11716
|
if (st2 === valueProps.found)
|
|
11717
11717
|
break;
|
|
11718
11718
|
if (st2.type === "newline") {
|
|
@@ -11729,7 +11729,7 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
11729
11729
|
else
|
|
11730
11730
|
onError(valueProps.start, "MISSING_CHAR", `Missing , or : between ${fcName} items`);
|
|
11731
11731
|
}
|
|
11732
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end,
|
|
11732
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep5, null, valueProps, onError) : null;
|
|
11733
11733
|
if (valueNode) {
|
|
11734
11734
|
if (isBlock(value))
|
|
11735
11735
|
onError(valueNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
@@ -11909,7 +11909,7 @@ var require_resolve_block_scalar = __commonJS({
|
|
|
11909
11909
|
chompStart = i + 1;
|
|
11910
11910
|
}
|
|
11911
11911
|
let value = "";
|
|
11912
|
-
let
|
|
11912
|
+
let sep5 = "";
|
|
11913
11913
|
let prevMoreIndented = false;
|
|
11914
11914
|
for (let i = 0; i < contentStart; ++i)
|
|
11915
11915
|
value += lines[i][0].slice(trimIndent) + "\n";
|
|
@@ -11926,24 +11926,24 @@ var require_resolve_block_scalar = __commonJS({
|
|
|
11926
11926
|
indent = "";
|
|
11927
11927
|
}
|
|
11928
11928
|
if (type === Scalar.Scalar.BLOCK_LITERAL) {
|
|
11929
|
-
value +=
|
|
11930
|
-
|
|
11929
|
+
value += sep5 + indent.slice(trimIndent) + content;
|
|
11930
|
+
sep5 = "\n";
|
|
11931
11931
|
} else if (indent.length > trimIndent || content[0] === " ") {
|
|
11932
|
-
if (
|
|
11933
|
-
|
|
11934
|
-
else if (!prevMoreIndented &&
|
|
11935
|
-
|
|
11936
|
-
value +=
|
|
11937
|
-
|
|
11932
|
+
if (sep5 === " ")
|
|
11933
|
+
sep5 = "\n";
|
|
11934
|
+
else if (!prevMoreIndented && sep5 === "\n")
|
|
11935
|
+
sep5 = "\n\n";
|
|
11936
|
+
value += sep5 + indent.slice(trimIndent) + content;
|
|
11937
|
+
sep5 = "\n";
|
|
11938
11938
|
prevMoreIndented = true;
|
|
11939
11939
|
} else if (content === "") {
|
|
11940
|
-
if (
|
|
11940
|
+
if (sep5 === "\n")
|
|
11941
11941
|
value += "\n";
|
|
11942
11942
|
else
|
|
11943
|
-
|
|
11943
|
+
sep5 = "\n";
|
|
11944
11944
|
} else {
|
|
11945
|
-
value +=
|
|
11946
|
-
|
|
11945
|
+
value += sep5 + content;
|
|
11946
|
+
sep5 = " ";
|
|
11947
11947
|
prevMoreIndented = false;
|
|
11948
11948
|
}
|
|
11949
11949
|
}
|
|
@@ -12126,25 +12126,25 @@ var require_resolve_flow_scalar = __commonJS({
|
|
|
12126
12126
|
trimBoth = /^[ \t]+|[ \t]+$/g;
|
|
12127
12127
|
}
|
|
12128
12128
|
let res = match[1].replace(trimEnd, "");
|
|
12129
|
-
let
|
|
12129
|
+
let sep5 = " ";
|
|
12130
12130
|
let pos = line.lastIndex;
|
|
12131
12131
|
while (match = line.exec(source)) {
|
|
12132
12132
|
const lm = match[1].replace(trimBoth, "");
|
|
12133
12133
|
if (lm === "") {
|
|
12134
|
-
if (
|
|
12135
|
-
res +=
|
|
12134
|
+
if (sep5 === "\n")
|
|
12135
|
+
res += sep5;
|
|
12136
12136
|
else
|
|
12137
|
-
|
|
12137
|
+
sep5 = "\n";
|
|
12138
12138
|
} else {
|
|
12139
|
-
res +=
|
|
12140
|
-
|
|
12139
|
+
res += sep5 + lm;
|
|
12140
|
+
sep5 = " ";
|
|
12141
12141
|
}
|
|
12142
12142
|
pos = line.lastIndex;
|
|
12143
12143
|
}
|
|
12144
12144
|
const last = /[ \t]*(.*)/sy;
|
|
12145
12145
|
last.lastIndex = pos;
|
|
12146
12146
|
match = last.exec(source);
|
|
12147
|
-
return res +
|
|
12147
|
+
return res + sep5 + (match?.[1] ?? "");
|
|
12148
12148
|
}
|
|
12149
12149
|
function doubleQuotedValue(source, onError) {
|
|
12150
12150
|
let res = "";
|
|
@@ -12954,14 +12954,14 @@ var require_cst_stringify = __commonJS({
|
|
|
12954
12954
|
}
|
|
12955
12955
|
}
|
|
12956
12956
|
}
|
|
12957
|
-
function stringifyItem({ start, key, sep:
|
|
12957
|
+
function stringifyItem({ start, key, sep: sep5, value }) {
|
|
12958
12958
|
let res = "";
|
|
12959
12959
|
for (const st2 of start)
|
|
12960
12960
|
res += st2.source;
|
|
12961
12961
|
if (key)
|
|
12962
12962
|
res += stringifyToken(key);
|
|
12963
|
-
if (
|
|
12964
|
-
for (const st2 of
|
|
12963
|
+
if (sep5)
|
|
12964
|
+
for (const st2 of sep5)
|
|
12965
12965
|
res += st2.source;
|
|
12966
12966
|
if (value)
|
|
12967
12967
|
res += stringifyToken(value);
|
|
@@ -14128,18 +14128,18 @@ var require_parser = __commonJS({
|
|
|
14128
14128
|
if (this.type === "map-value-ind") {
|
|
14129
14129
|
const prev = getPrevProps(this.peek(2));
|
|
14130
14130
|
const start = getFirstKeyStartProps(prev);
|
|
14131
|
-
let
|
|
14131
|
+
let sep5;
|
|
14132
14132
|
if (scalar.end) {
|
|
14133
|
-
|
|
14134
|
-
|
|
14133
|
+
sep5 = scalar.end;
|
|
14134
|
+
sep5.push(this.sourceToken);
|
|
14135
14135
|
delete scalar.end;
|
|
14136
14136
|
} else
|
|
14137
|
-
|
|
14137
|
+
sep5 = [this.sourceToken];
|
|
14138
14138
|
const map = {
|
|
14139
14139
|
type: "block-map",
|
|
14140
14140
|
offset: scalar.offset,
|
|
14141
14141
|
indent: scalar.indent,
|
|
14142
|
-
items: [{ start, key: scalar, sep:
|
|
14142
|
+
items: [{ start, key: scalar, sep: sep5 }]
|
|
14143
14143
|
};
|
|
14144
14144
|
this.onKeyLine = true;
|
|
14145
14145
|
this.stack[this.stack.length - 1] = map;
|
|
@@ -14292,15 +14292,15 @@ var require_parser = __commonJS({
|
|
|
14292
14292
|
} else if (isFlowToken(it.key) && !includesToken(it.sep, "newline")) {
|
|
14293
14293
|
const start2 = getFirstKeyStartProps(it.start);
|
|
14294
14294
|
const key = it.key;
|
|
14295
|
-
const
|
|
14296
|
-
|
|
14295
|
+
const sep5 = it.sep;
|
|
14296
|
+
sep5.push(this.sourceToken);
|
|
14297
14297
|
delete it.key;
|
|
14298
14298
|
delete it.sep;
|
|
14299
14299
|
this.stack.push({
|
|
14300
14300
|
type: "block-map",
|
|
14301
14301
|
offset: this.offset,
|
|
14302
14302
|
indent: this.indent,
|
|
14303
|
-
items: [{ start: start2, key, sep:
|
|
14303
|
+
items: [{ start: start2, key, sep: sep5 }]
|
|
14304
14304
|
});
|
|
14305
14305
|
} else if (start.length > 0) {
|
|
14306
14306
|
it.sep = it.sep.concat(start, this.sourceToken);
|
|
@@ -14494,13 +14494,13 @@ var require_parser = __commonJS({
|
|
|
14494
14494
|
const prev = getPrevProps(parent);
|
|
14495
14495
|
const start = getFirstKeyStartProps(prev);
|
|
14496
14496
|
fixFlowSeqItems(fc);
|
|
14497
|
-
const
|
|
14498
|
-
|
|
14497
|
+
const sep5 = fc.end.splice(1, fc.end.length);
|
|
14498
|
+
sep5.push(this.sourceToken);
|
|
14499
14499
|
const map = {
|
|
14500
14500
|
type: "block-map",
|
|
14501
14501
|
offset: fc.offset,
|
|
14502
14502
|
indent: fc.indent,
|
|
14503
|
-
items: [{ start, key: fc, sep:
|
|
14503
|
+
items: [{ start, key: fc, sep: sep5 }]
|
|
14504
14504
|
};
|
|
14505
14505
|
this.onKeyLine = true;
|
|
14506
14506
|
this.stack[this.stack.length - 1] = map;
|
|
@@ -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 resolve34 } from "node:path";
|
|
14783
14783
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
14784
14784
|
|
|
14785
14785
|
// node_modules/commander/lib/error.js
|
|
@@ -19751,7 +19751,7 @@ var HubClient = class {
|
|
|
19751
19751
|
if (signal?.aborted) throw new MeshWaitError("aborted", messageId);
|
|
19752
19752
|
const message = await this.getMessage(messageId);
|
|
19753
19753
|
if (["replied", "cancelled", "expired", "error"].includes(message.status)) return message;
|
|
19754
|
-
await new Promise((
|
|
19754
|
+
await new Promise((resolve35, reject) => {
|
|
19755
19755
|
const onAbort = () => {
|
|
19756
19756
|
signal?.removeEventListener("abort", onAbort);
|
|
19757
19757
|
clearTimeout(timer);
|
|
@@ -19759,7 +19759,7 @@ var HubClient = class {
|
|
|
19759
19759
|
};
|
|
19760
19760
|
const timer = setTimeout(() => {
|
|
19761
19761
|
signal?.removeEventListener("abort", onAbort);
|
|
19762
|
-
|
|
19762
|
+
resolve35();
|
|
19763
19763
|
}, Math.min(500, Math.max(1, deadline - Date.now())));
|
|
19764
19764
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
19765
19765
|
if (signal?.aborted) onAbort();
|
|
@@ -19814,7 +19814,7 @@ var HubClient = class {
|
|
|
19814
19814
|
} catch (error) {
|
|
19815
19815
|
if (this.stopped || error instanceof Error && error.name === "AbortError") return;
|
|
19816
19816
|
}
|
|
19817
|
-
if (!this.stopped) await new Promise((
|
|
19817
|
+
if (!this.stopped) await new Promise((resolve35) => setTimeout(resolve35, this.options.reconnectMs));
|
|
19818
19818
|
}
|
|
19819
19819
|
}
|
|
19820
19820
|
headers(includeIdentity = true) {
|
|
@@ -21350,7 +21350,7 @@ function defaultSpawn(command, args, options) {
|
|
|
21350
21350
|
if (options.signal?.aborted) {
|
|
21351
21351
|
return Promise.resolve({ stdout: "", stderr: "", code: null, started: false, observedChildExit: false, error: new Error("process_aborted") });
|
|
21352
21352
|
}
|
|
21353
|
-
return new Promise((
|
|
21353
|
+
return new Promise((resolve35) => {
|
|
21354
21354
|
const stdout = [];
|
|
21355
21355
|
const stderr = [];
|
|
21356
21356
|
let outputBytes = 0;
|
|
@@ -21381,7 +21381,7 @@ function defaultSpawn(command, args, options) {
|
|
|
21381
21381
|
const started = Boolean(child?.pid);
|
|
21382
21382
|
if (started && !observedChildExit) error ??= new Error("process_exit_unobserved");
|
|
21383
21383
|
const unverifiedDescendants = stopping || started && !observedChildExit;
|
|
21384
|
-
|
|
21384
|
+
resolve35({
|
|
21385
21385
|
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
21386
21386
|
stderr: Buffer.concat(stderr).toString("utf8"),
|
|
21387
21387
|
code,
|
|
@@ -23094,8 +23094,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
23094
23094
|
const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
|
|
23095
23095
|
if (maxWriteRepositories > writable) issues.push(issue2("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
|
|
23096
23096
|
}
|
|
23097
|
-
const
|
|
23098
|
-
const minimumPassed =
|
|
23097
|
+
const join51 = objectValue(step.join);
|
|
23098
|
+
const minimumPassed = join51 && typeof join51.minimumPassed === "number" ? join51.minimumPassed : void 0;
|
|
23099
23099
|
if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue2("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
|
|
23100
23100
|
const distinctBy = names(assignment?.distinctBy);
|
|
23101
23101
|
if (distinctBy.length > 0) {
|
|
@@ -23661,12 +23661,11 @@ function planKxmInitialization(start = process.cwd(), options = {}) {
|
|
|
23661
23661
|
import { spawn as spawn2 } from "node:child_process";
|
|
23662
23662
|
import { createHash as createHash13, createHmac as createHmac2, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
23663
23663
|
import { chmodSync as chmodSync4, existsSync as existsSync16, lstatSync as lstatSync6, mkdirSync as mkdirSync11, readFileSync as readFileSync14, renameSync as renameSync5, rmSync as rmSync5, writeFileSync as writeFileSync12 } from "node:fs";
|
|
23664
|
-
import { dirname as dirname11, isAbsolute as
|
|
23664
|
+
import { dirname as dirname11, isAbsolute as isAbsolute7, join as join16 } from "node:path";
|
|
23665
23665
|
|
|
23666
23666
|
// plugins/kxm/src/runtime-store.ts
|
|
23667
|
-
import {
|
|
23668
|
-
import {
|
|
23669
|
-
import { dirname as dirname7, join as join9, resolve as resolve7 } from "node:path";
|
|
23667
|
+
import { existsSync as existsSync10, lstatSync as lstatSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
|
|
23668
|
+
import { dirname as dirname7, resolve as resolve8 } from "node:path";
|
|
23670
23669
|
|
|
23671
23670
|
// plugins/kxm/src/sqlite.ts
|
|
23672
23671
|
import { existsSync as existsSync7 } from "node:fs";
|
|
@@ -23716,6 +23715,11 @@ function openReadOnlyDatabase(path4) {
|
|
|
23716
23715
|
return new DatabaseSync(uri.href, { readOnly: true });
|
|
23717
23716
|
}
|
|
23718
23717
|
|
|
23718
|
+
// plugins/kxm/src/runtime-paths.ts
|
|
23719
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
23720
|
+
import { realpathSync as realpathSync3 } from "node:fs";
|
|
23721
|
+
import { join as join8, resolve as resolve6 } from "node:path";
|
|
23722
|
+
|
|
23719
23723
|
// plugins/kxm/src/bindings.ts
|
|
23720
23724
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
23721
23725
|
import { createHash as createHash7, randomUUID as randomUUID3 } from "node:crypto";
|
|
@@ -24028,8 +24032,33 @@ function writeKxmLocalBindings(projectRoot, projectId, repositories, options = {
|
|
|
24028
24032
|
return { file, written: true, record };
|
|
24029
24033
|
}
|
|
24030
24034
|
|
|
24035
|
+
// plugins/kxm/src/runtime-paths.ts
|
|
24036
|
+
function kxmRuntimePaths(options = {}) {
|
|
24037
|
+
const stateRoot = options.stateRoot ? resolve6(options.stateRoot) : kxmUserStateRoot({ ...options.env ? { env: options.env } : {}, ...options.homeDir ? { homeDir: options.homeDir } : {} });
|
|
24038
|
+
const runtimeDir = join8(stateRoot, "runtime");
|
|
24039
|
+
return {
|
|
24040
|
+
stateRoot,
|
|
24041
|
+
runtimeDir,
|
|
24042
|
+
registryDb: join8(runtimeDir, "registry.db"),
|
|
24043
|
+
projectsDir: join8(runtimeDir, "projects")
|
|
24044
|
+
};
|
|
24045
|
+
}
|
|
24046
|
+
function projectRuntimeKey(projectRoot) {
|
|
24047
|
+
let canonical2;
|
|
24048
|
+
try {
|
|
24049
|
+
canonical2 = realpathSync3.native(resolve6(projectRoot));
|
|
24050
|
+
} catch {
|
|
24051
|
+
canonical2 = resolve6(projectRoot);
|
|
24052
|
+
}
|
|
24053
|
+
const folded = process.platform === "win32" ? canonical2.toLocaleLowerCase("en-US") : canonical2;
|
|
24054
|
+
return createHash8("sha256").update(folded, "utf8").digest("hex").slice(0, 24);
|
|
24055
|
+
}
|
|
24056
|
+
function kxmProjectRunEventsPath(projectRoot, env) {
|
|
24057
|
+
return join8(kxmRuntimePaths({ env }).projectsDir, projectRuntimeKey(projectRoot), "run-events.db");
|
|
24058
|
+
}
|
|
24059
|
+
|
|
24031
24060
|
// plugins/kxm/src/sync-transform.ts
|
|
24032
|
-
import { createHash as
|
|
24061
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
24033
24062
|
var KXM_DEFAULT_SYNC_POLICY = Object.freeze({
|
|
24034
24063
|
prompts: "title-only",
|
|
24035
24064
|
results: "bounded-summary",
|
|
@@ -24040,7 +24069,7 @@ var KXM_DEFAULT_SYNC_POLICY = Object.freeze({
|
|
|
24040
24069
|
diffs: false,
|
|
24041
24070
|
environmentValues: false
|
|
24042
24071
|
});
|
|
24043
|
-
var KXM_DEFAULT_SYNC_POLICY_REVISION = `sha256:${
|
|
24072
|
+
var KXM_DEFAULT_SYNC_POLICY_REVISION = `sha256:${createHash9("sha256").update(kxmCanonicalJson(KXM_DEFAULT_SYNC_POLICY), "utf8").digest("hex")}`;
|
|
24044
24073
|
var SCALAR_FIELDS = [
|
|
24045
24074
|
"workflowId",
|
|
24046
24075
|
"promptHash",
|
|
@@ -24080,7 +24109,7 @@ var CARRIED_FIELDS = /* @__PURE__ */ new Set([
|
|
|
24080
24109
|
]);
|
|
24081
24110
|
|
|
24082
24111
|
// plugins/kxm/src/database.ts
|
|
24083
|
-
import { createHash as
|
|
24112
|
+
import { createHash as createHash10, randomBytes } from "node:crypto";
|
|
24084
24113
|
import {
|
|
24085
24114
|
chmodSync as chmodSync3,
|
|
24086
24115
|
copyFileSync,
|
|
@@ -24092,7 +24121,7 @@ import {
|
|
|
24092
24121
|
unlinkSync as unlinkSync2,
|
|
24093
24122
|
writeFileSync as writeFileSync5
|
|
24094
24123
|
} from "node:fs";
|
|
24095
|
-
import { basename as basename3, dirname as dirname6, join as
|
|
24124
|
+
import { basename as basename3, dirname as dirname6, isAbsolute as isAbsolute4, join as join9, relative as relative3, resolve as resolve7, sep as sep3 } from "node:path";
|
|
24096
24125
|
function databaseError(code, file, message) {
|
|
24097
24126
|
const issue3 = { phase: "semantic", code, file, message };
|
|
24098
24127
|
return new KxmConfigError([issue3]);
|
|
@@ -24233,11 +24262,11 @@ function checkIntegrity(database) {
|
|
|
24233
24262
|
}
|
|
24234
24263
|
function fileSha256(filePath) {
|
|
24235
24264
|
const bytes = readFileSync7(filePath);
|
|
24236
|
-
return `sha256:${
|
|
24265
|
+
return `sha256:${createHash10("sha256").update(bytes).digest("hex")}`;
|
|
24237
24266
|
}
|
|
24238
24267
|
function backupDatabaseFile(sourcePath, targetPath, storeId) {
|
|
24239
|
-
const resolvedSource =
|
|
24240
|
-
const resolvedTarget =
|
|
24268
|
+
const resolvedSource = resolve7(sourcePath);
|
|
24269
|
+
const resolvedTarget = resolve7(targetPath);
|
|
24241
24270
|
const sourceStat = lstatSync3(resolvedSource, { throwIfNoEntry: false });
|
|
24242
24271
|
if (!sourceStat || !sourceStat.isFile() || sourceStat.isSymbolicLink()) {
|
|
24243
24272
|
throw databaseError("runtime_path_invalid", resolvedSource, `source database ${resolvedSource} must be a regular file, not a link or directory`);
|
|
@@ -24287,8 +24316,8 @@ function backupDatabaseFile(sourcePath, targetPath, storeId) {
|
|
|
24287
24316
|
};
|
|
24288
24317
|
}
|
|
24289
24318
|
function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVersion, maxSupportedVersion) {
|
|
24290
|
-
const resolvedBackup =
|
|
24291
|
-
const resolvedTarget =
|
|
24319
|
+
const resolvedBackup = resolve7(backupPath);
|
|
24320
|
+
const resolvedTarget = resolve7(targetPath);
|
|
24292
24321
|
const backupStat = lstatSync3(resolvedBackup, { throwIfNoEntry: false });
|
|
24293
24322
|
if (!backupStat || !backupStat.isFile() || backupStat.isSymbolicLink()) {
|
|
24294
24323
|
throw databaseError("runtime_path_invalid", resolvedBackup, `backup database ${resolvedBackup} must be a regular file, not a link or directory`);
|
|
@@ -24365,69 +24394,74 @@ function pushStore(stores, storeId, sourcePath) {
|
|
|
24365
24394
|
if (stores.some((store) => store.storeId === storeId || store.sourcePath === sourcePath)) return;
|
|
24366
24395
|
stores.push({ storeId, sourcePath, maxSupportedVersion: kxmBackupCeiling(storeId) });
|
|
24367
24396
|
}
|
|
24368
|
-
function
|
|
24369
|
-
|
|
24397
|
+
function pushEventStore(stores, files, paths, key) {
|
|
24398
|
+
const dbPath = join9(paths.projectsDir, key, "run-events.db");
|
|
24399
|
+
if (!existsSync9(dbPath)) return;
|
|
24400
|
+
const safe = key.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
24401
|
+
let storeId = `events:${safe}`;
|
|
24402
|
+
if (stores.some((store) => store.storeId === storeId)) storeId = `events:runtime:${safe}`;
|
|
24403
|
+
pushStore(stores, storeId, dbPath);
|
|
24404
|
+
const sidecar = `${dbPath}.run-prompts.json`;
|
|
24405
|
+
if (existsSync9(sidecar)) {
|
|
24406
|
+
const id = `${storeId}:run-prompts`;
|
|
24407
|
+
if (!files.some((file) => file.id === id || file.sourcePath === sidecar)) {
|
|
24408
|
+
files.push({ id, sourcePath: sidecar });
|
|
24409
|
+
}
|
|
24410
|
+
}
|
|
24411
|
+
}
|
|
24412
|
+
function discoverUserRuntime(runtimeProjectKey, options, stores, files) {
|
|
24413
|
+
let paths;
|
|
24370
24414
|
try {
|
|
24371
|
-
|
|
24415
|
+
paths = kxmRuntimePaths(options.env ? { env: options.env } : {});
|
|
24372
24416
|
} catch {
|
|
24373
|
-
return;
|
|
24417
|
+
return void 0;
|
|
24374
24418
|
}
|
|
24375
|
-
|
|
24376
|
-
|
|
24377
|
-
|
|
24419
|
+
if (!options.allProjects) {
|
|
24420
|
+
pushEventStore(stores, files, paths, runtimeProjectKey);
|
|
24421
|
+
return paths.stateRoot;
|
|
24422
|
+
}
|
|
24423
|
+
if (existsSync9(paths.registryDb)) {
|
|
24378
24424
|
const storeId = stores.some((store) => store.storeId === "registry") ? "runtime-registry" : "registry";
|
|
24379
|
-
pushStore(stores, storeId,
|
|
24425
|
+
pushStore(stores, storeId, paths.registryDb);
|
|
24380
24426
|
}
|
|
24381
|
-
|
|
24382
|
-
if (!existsSync9(projectsDir)) return;
|
|
24427
|
+
if (!existsSync9(paths.projectsDir)) return paths.stateRoot;
|
|
24383
24428
|
let entries;
|
|
24384
24429
|
try {
|
|
24385
|
-
entries = readdirSync2(projectsDir, { withFileTypes: true });
|
|
24430
|
+
entries = readdirSync2(paths.projectsDir, { withFileTypes: true });
|
|
24386
24431
|
} catch {
|
|
24387
|
-
return;
|
|
24432
|
+
return paths.stateRoot;
|
|
24388
24433
|
}
|
|
24389
24434
|
for (const entry of entries) {
|
|
24390
|
-
if (
|
|
24391
|
-
const dbPath = join8(projectsDir, entry.name, "run-events.db");
|
|
24392
|
-
if (!existsSync9(dbPath)) continue;
|
|
24393
|
-
const safe = entry.name.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
24394
|
-
let storeId = `events:${safe}`;
|
|
24395
|
-
if (stores.some((store) => store.storeId === storeId)) storeId = `events:runtime:${safe}`;
|
|
24396
|
-
pushStore(stores, storeId, dbPath);
|
|
24397
|
-
const sidecar = `${dbPath}.run-prompts.json`;
|
|
24398
|
-
if (existsSync9(sidecar)) {
|
|
24399
|
-
const id = `${storeId}:run-prompts`;
|
|
24400
|
-
if (!files.some((file) => file.id === id || file.sourcePath === sidecar)) {
|
|
24401
|
-
files.push({ id, sourcePath: sidecar });
|
|
24402
|
-
}
|
|
24403
|
-
}
|
|
24435
|
+
if (entry.isDirectory()) pushEventStore(stores, files, paths, entry.name);
|
|
24404
24436
|
}
|
|
24437
|
+
return paths.stateRoot;
|
|
24405
24438
|
}
|
|
24406
24439
|
function discoverBackupSources(projectRoot, options = {}) {
|
|
24407
|
-
const root =
|
|
24440
|
+
const root = resolve7(projectRoot);
|
|
24408
24441
|
const stores = [];
|
|
24409
24442
|
const files = [];
|
|
24410
|
-
const hubPath = options.hubDataPath ?
|
|
24443
|
+
const hubPath = options.hubDataPath ? resolve7(options.hubDataPath) : join9(root, ".kxm", "state", "kxm.db");
|
|
24411
24444
|
if (existsSync9(hubPath)) pushStore(stores, "hub-store", hubPath);
|
|
24412
|
-
const registryPath =
|
|
24445
|
+
const registryPath = join9(root, ".kxm", "runtime", "registry.db");
|
|
24413
24446
|
if (existsSync9(registryPath)) pushStore(stores, "registry", registryPath);
|
|
24414
|
-
const bindingsPath =
|
|
24447
|
+
const bindingsPath = join9(root, ".kxm", "runtime", "bindings.db");
|
|
24415
24448
|
if (existsSync9(bindingsPath)) pushStore(stores, "binding-store", bindingsPath);
|
|
24416
|
-
const eventsDir =
|
|
24449
|
+
const eventsDir = join9(root, ".kxm", "runtime", "events");
|
|
24417
24450
|
if (existsSync9(eventsDir)) {
|
|
24418
24451
|
const entries = readdirSync2(eventsDir, { withFileTypes: true });
|
|
24419
24452
|
for (const entry of entries) {
|
|
24420
24453
|
if (entry.isFile() && entry.name.endsWith(".db")) {
|
|
24421
24454
|
const key = entry.name.replace(/\.db$/, "").replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
24422
|
-
pushStore(stores, `events:${key}`,
|
|
24455
|
+
pushStore(stores, `events:${key}`, join9(eventsDir, entry.name));
|
|
24423
24456
|
}
|
|
24424
24457
|
}
|
|
24425
24458
|
}
|
|
24426
|
-
|
|
24427
|
-
|
|
24459
|
+
const runtimeProjectKey = projectRuntimeKey(root);
|
|
24460
|
+
const stateRoot = discoverUserRuntime(runtimeProjectKey, options, stores, files);
|
|
24461
|
+
return { stores, files, runtimeProjectKey, ...stateRoot !== void 0 ? { stateRoot } : {} };
|
|
24428
24462
|
}
|
|
24429
24463
|
function backupPlainFile(sourcePath, targetPath, id) {
|
|
24430
|
-
const resolvedSource =
|
|
24464
|
+
const resolvedSource = resolve7(sourcePath);
|
|
24431
24465
|
const sourceStat = lstatSync3(resolvedSource, { throwIfNoEntry: false });
|
|
24432
24466
|
if (!sourceStat || !sourceStat.isFile() || sourceStat.isSymbolicLink()) {
|
|
24433
24467
|
throw databaseError("runtime_path_invalid", resolvedSource, `backup file ${resolvedSource} must be a regular file, not a link or directory`);
|
|
@@ -24467,18 +24501,19 @@ function restorePlainFile(backupFilePath, targetPath) {
|
|
|
24467
24501
|
function backupDiscoverOptions(options) {
|
|
24468
24502
|
return {
|
|
24469
24503
|
...options.hubDataPath !== void 0 ? { hubDataPath: options.hubDataPath } : {},
|
|
24470
|
-
...options.env !== void 0 ? { env: options.env } : {}
|
|
24504
|
+
...options.env !== void 0 ? { env: options.env } : {},
|
|
24505
|
+
...options.allProjects === true ? { allProjects: true } : {}
|
|
24471
24506
|
};
|
|
24472
24507
|
}
|
|
24473
24508
|
function planBackup(options = {}) {
|
|
24474
|
-
const projectRoot = options.projectRoot ?
|
|
24509
|
+
const projectRoot = options.projectRoot ? resolve7(options.projectRoot) : process.cwd();
|
|
24475
24510
|
const discovered = discoverBackupSources(projectRoot, backupDiscoverOptions(options));
|
|
24476
24511
|
if (discovered.stores.length === 0) {
|
|
24477
24512
|
throw databaseError("backup_no_stores", projectRoot, "no existing SQLite stores found to backup");
|
|
24478
24513
|
}
|
|
24479
24514
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24480
24515
|
const timestamp = createdAt.replace(/[:.]/g, "-");
|
|
24481
|
-
const outDir = options.outDir ?
|
|
24516
|
+
const outDir = options.outDir ? resolve7(options.outDir) : join9(projectRoot, ".kxm", "backups", `backup-${timestamp}`);
|
|
24482
24517
|
const usedFilenames = /* @__PURE__ */ new Set();
|
|
24483
24518
|
const stores = discovered.stores.map((store) => ({
|
|
24484
24519
|
storeId: store.storeId,
|
|
@@ -24490,10 +24525,19 @@ function planBackup(options = {}) {
|
|
|
24490
24525
|
sourcePath: file.sourcePath,
|
|
24491
24526
|
backupFile: backupFilename(file.sourcePath, file.id, usedFilenames)
|
|
24492
24527
|
}));
|
|
24493
|
-
return {
|
|
24528
|
+
return {
|
|
24529
|
+
projectRoot,
|
|
24530
|
+
outDir,
|
|
24531
|
+
createdAt,
|
|
24532
|
+
scope: options.allProjects === true ? "all-projects" : "project",
|
|
24533
|
+
...discovered.stateRoot !== void 0 ? { stateRoot: discovered.stateRoot } : {},
|
|
24534
|
+
runtimeProjectKey: discovered.runtimeProjectKey,
|
|
24535
|
+
stores,
|
|
24536
|
+
files
|
|
24537
|
+
};
|
|
24494
24538
|
}
|
|
24495
24539
|
function createBackup(options = {}) {
|
|
24496
|
-
const { projectRoot, outDir, createdAt, stores, files } = planBackup(options);
|
|
24540
|
+
const { projectRoot, outDir, createdAt, scope, stateRoot, runtimeProjectKey, stores, files } = planBackup(options);
|
|
24497
24541
|
const backupId = `bk_${randomBytes(8).toString("hex")}`;
|
|
24498
24542
|
if (!existsSync9(outDir)) {
|
|
24499
24543
|
mkdirSync5(outDir, { recursive: true, mode: 448 });
|
|
@@ -24503,14 +24547,14 @@ function createBackup(options = {}) {
|
|
|
24503
24547
|
const omitted = [];
|
|
24504
24548
|
for (const store of stores) {
|
|
24505
24549
|
try {
|
|
24506
|
-
backedUpStores.push(backupDatabaseFile(store.sourcePath,
|
|
24550
|
+
backedUpStores.push(backupDatabaseFile(store.sourcePath, join9(outDir, store.backupFile), store.storeId));
|
|
24507
24551
|
} catch {
|
|
24508
24552
|
omitted.push(store.storeId);
|
|
24509
24553
|
}
|
|
24510
24554
|
}
|
|
24511
24555
|
for (const file of files) {
|
|
24512
24556
|
try {
|
|
24513
|
-
backedUpFiles.push(backupPlainFile(file.sourcePath,
|
|
24557
|
+
backedUpFiles.push(backupPlainFile(file.sourcePath, join9(outDir, file.backupFile), file.id));
|
|
24514
24558
|
} catch {
|
|
24515
24559
|
omitted.push(file.id);
|
|
24516
24560
|
}
|
|
@@ -24534,27 +24578,53 @@ function createBackup(options = {}) {
|
|
|
24534
24578
|
backupId,
|
|
24535
24579
|
createdAt,
|
|
24536
24580
|
projectRoot,
|
|
24581
|
+
scope,
|
|
24582
|
+
...stateRoot !== void 0 ? { stateRoot } : {},
|
|
24583
|
+
runtimeProjectKey,
|
|
24537
24584
|
stores: backedUpStores,
|
|
24538
24585
|
...backedUpFiles.length > 0 ? { files: backedUpFiles } : {},
|
|
24539
24586
|
complete: omitted.length === 0,
|
|
24540
24587
|
...omitted.length > 0 ? { omitted } : {}
|
|
24541
24588
|
};
|
|
24542
24589
|
const manifestJson = JSON.stringify(manifest, null, 2) + "\n";
|
|
24543
|
-
const manifestSha256 = `sha256:${
|
|
24590
|
+
const manifestSha256 = `sha256:${createHash10("sha256").update(manifestJson, "utf8").digest("hex")}`;
|
|
24544
24591
|
manifest.manifestSha256 = manifestSha256;
|
|
24545
24592
|
const finalJson = JSON.stringify(manifest, null, 2) + "\n";
|
|
24546
|
-
const manifestPath =
|
|
24593
|
+
const manifestPath = join9(outDir, "manifest.json");
|
|
24547
24594
|
writeFileSync5(manifestPath, finalJson, "utf8");
|
|
24548
24595
|
return { manifest, outDir };
|
|
24549
24596
|
}
|
|
24597
|
+
function pathUnder(root, path4) {
|
|
24598
|
+
if (!root) return void 0;
|
|
24599
|
+
const rel = relative3(root, path4);
|
|
24600
|
+
if (rel === "" || rel === ".." || rel.startsWith(`..${sep3}`) || isAbsolute4(rel)) return void 0;
|
|
24601
|
+
return rel;
|
|
24602
|
+
}
|
|
24603
|
+
function restoreTarget(manifest, sourcePath, id, options, currentStateRoot) {
|
|
24604
|
+
const stateRel = pathUnder(manifest.stateRoot, sourcePath);
|
|
24605
|
+
const projectRel = pathUnder(manifest.projectRoot, sourcePath);
|
|
24606
|
+
if (stateRel !== void 0 && (projectRel === void 0 || stateRel.length <= projectRel.length)) {
|
|
24607
|
+
const ownEvents = manifest.runtimeProjectKey !== void 0 ? join9("runtime", "projects", manifest.runtimeProjectKey, "run-events.db") : void 0;
|
|
24608
|
+
const own = ownEvents !== void 0 && (stateRel === ownEvents || stateRel === `${ownEvents}.run-prompts.json`);
|
|
24609
|
+
if (own && !options.allProjects && options.projectRoot !== void 0) {
|
|
24610
|
+
const eventsPath = kxmProjectRunEventsPath(resolve7(options.projectRoot), options.env ?? process.env);
|
|
24611
|
+
return { targetPath: stateRel === ownEvents ? eventsPath : `${eventsPath}.run-prompts.json`, machineWide: false };
|
|
24612
|
+
}
|
|
24613
|
+
return { targetPath: join9(currentStateRoot(), stateRel), machineWide: !own };
|
|
24614
|
+
}
|
|
24615
|
+
if (projectRel !== void 0) {
|
|
24616
|
+
return { targetPath: options.projectRoot ? join9(resolve7(options.projectRoot), projectRel) : sourcePath, machineWide: false };
|
|
24617
|
+
}
|
|
24618
|
+
return { targetPath: sourcePath, machineWide: id !== "hub-store" };
|
|
24619
|
+
}
|
|
24550
24620
|
function planRestore(manifestPathOrDir, options = {}) {
|
|
24551
|
-
let manifestPath =
|
|
24621
|
+
let manifestPath = resolve7(manifestPathOrDir);
|
|
24552
24622
|
const stat = lstatSync3(manifestPath, { throwIfNoEntry: false });
|
|
24553
24623
|
if (!stat) {
|
|
24554
24624
|
throw databaseError("runtime_path_invalid", manifestPath, `manifest path ${manifestPath} does not exist`);
|
|
24555
24625
|
}
|
|
24556
24626
|
if (stat.isDirectory()) {
|
|
24557
|
-
manifestPath =
|
|
24627
|
+
manifestPath = join9(manifestPath, "manifest.json");
|
|
24558
24628
|
}
|
|
24559
24629
|
if (!existsSync9(manifestPath)) {
|
|
24560
24630
|
throw databaseError("runtime_path_invalid", manifestPath, `backup manifest ${manifestPath} not found`);
|
|
@@ -24573,9 +24643,12 @@ function planRestore(manifestPathOrDir, options = {}) {
|
|
|
24573
24643
|
if (manifest.complete === false) {
|
|
24574
24644
|
throw databaseError("restore_incomplete", manifestPath, "backup manifest is incomplete; refusing to restore a partial copy");
|
|
24575
24645
|
}
|
|
24646
|
+
let stateRoot;
|
|
24647
|
+
const currentStateRoot = () => stateRoot ??= kxmRuntimePaths({ env: options.env ?? process.env }).stateRoot;
|
|
24648
|
+
const machineWide = [];
|
|
24576
24649
|
const stores = [];
|
|
24577
24650
|
for (const store of manifest.stores) {
|
|
24578
|
-
const backupFilePath =
|
|
24651
|
+
const backupFilePath = join9(manifestDir, store.backupFile);
|
|
24579
24652
|
if (!existsSync9(backupFilePath)) {
|
|
24580
24653
|
throw databaseError("restore_file_missing", backupFilePath, `backup file ${store.backupFile} missing from ${manifestDir}`);
|
|
24581
24654
|
}
|
|
@@ -24595,16 +24668,13 @@ function planRestore(manifestPathOrDir, options = {}) {
|
|
|
24595
24668
|
`backup store ${store.storeId} schema version ${store.schemaVersion} is newer than supported maximum ${maxSupportedVersion}`
|
|
24596
24669
|
);
|
|
24597
24670
|
}
|
|
24598
|
-
|
|
24599
|
-
if (
|
|
24600
|
-
|
|
24601
|
-
targetPath = join8(resolve6(options.projectRoot), rel);
|
|
24602
|
-
}
|
|
24603
|
-
stores.push({ storeId: store.storeId, backupFilePath, targetPath, schemaVersion: store.schemaVersion, maxSupportedVersion });
|
|
24671
|
+
const target = restoreTarget(manifest, store.sourcePath, store.storeId, options, currentStateRoot);
|
|
24672
|
+
if (target.machineWide) machineWide.push(store.storeId);
|
|
24673
|
+
stores.push({ storeId: store.storeId, backupFilePath, targetPath: target.targetPath, schemaVersion: store.schemaVersion, maxSupportedVersion });
|
|
24604
24674
|
}
|
|
24605
24675
|
const files = [];
|
|
24606
24676
|
for (const file of manifest.files ?? []) {
|
|
24607
|
-
const backupFilePath =
|
|
24677
|
+
const backupFilePath = join9(manifestDir, file.backupFile);
|
|
24608
24678
|
if (!existsSync9(backupFilePath)) {
|
|
24609
24679
|
throw databaseError("restore_file_missing", backupFilePath, `backup file ${file.backupFile} missing from ${manifestDir}`);
|
|
24610
24680
|
}
|
|
@@ -24616,17 +24686,26 @@ function planRestore(manifestPathOrDir, options = {}) {
|
|
|
24616
24686
|
`backup file ${file.backupFile} sha256 ${actualSha256} does not match manifest hash ${file.sha256}`
|
|
24617
24687
|
);
|
|
24618
24688
|
}
|
|
24619
|
-
|
|
24620
|
-
if (
|
|
24621
|
-
|
|
24622
|
-
|
|
24623
|
-
|
|
24624
|
-
|
|
24689
|
+
const target = restoreTarget(manifest, file.sourcePath, file.id, options, currentStateRoot);
|
|
24690
|
+
if (target.machineWide) machineWide.push(file.id);
|
|
24691
|
+
files.push({ id: file.id, backupFilePath, targetPath: target.targetPath });
|
|
24692
|
+
}
|
|
24693
|
+
if (machineWide.length > 0 && !options.allProjects) {
|
|
24694
|
+
throw databaseError(
|
|
24695
|
+
"restore_requires_all_projects",
|
|
24696
|
+
manifestPath,
|
|
24697
|
+
`backup ${manifest.backupId} holds Runtime state shared by every project on this machine (${machineWide.join(", ")}); restoring it rolls back the registry or other projects' runs. Pass --all-projects to restore all of it, or restore a backup taken without --all-projects`
|
|
24698
|
+
);
|
|
24625
24699
|
}
|
|
24626
|
-
return {
|
|
24700
|
+
return {
|
|
24701
|
+
manifestPath,
|
|
24702
|
+
backupId: manifest.backupId,
|
|
24703
|
+
...manifest.scope !== void 0 ? { scope: manifest.scope } : {},
|
|
24704
|
+
stores,
|
|
24705
|
+
files
|
|
24706
|
+
};
|
|
24627
24707
|
}
|
|
24628
|
-
function
|
|
24629
|
-
const plan = planRestore(manifestPathOrDir, options);
|
|
24708
|
+
function applyRestorePlan(plan) {
|
|
24630
24709
|
const restoredStores = plan.stores.map((store) => restoreDatabaseFile(
|
|
24631
24710
|
store.backupFilePath,
|
|
24632
24711
|
store.targetPath,
|
|
@@ -24645,35 +24724,12 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
24645
24724
|
}
|
|
24646
24725
|
|
|
24647
24726
|
// plugins/kxm/src/runtime-store.ts
|
|
24648
|
-
function kxmRuntimePaths(options = {}) {
|
|
24649
|
-
const stateRoot = options.stateRoot ? resolve7(options.stateRoot) : kxmUserStateRoot({ ...options.env ? { env: options.env } : {}, ...options.homeDir ? { homeDir: options.homeDir } : {} });
|
|
24650
|
-
const runtimeDir = join9(stateRoot, "runtime");
|
|
24651
|
-
return {
|
|
24652
|
-
stateRoot,
|
|
24653
|
-
runtimeDir,
|
|
24654
|
-
registryDb: join9(runtimeDir, "registry.db"),
|
|
24655
|
-
projectsDir: join9(runtimeDir, "projects")
|
|
24656
|
-
};
|
|
24657
|
-
}
|
|
24658
24727
|
function runtimeIssue(phase, code, file, message) {
|
|
24659
24728
|
return { phase, code, file, message };
|
|
24660
24729
|
}
|
|
24661
24730
|
function runtimeError(code, file, message) {
|
|
24662
24731
|
return new KxmConfigError([runtimeIssue("semantic", code, file, message)]);
|
|
24663
24732
|
}
|
|
24664
|
-
function projectRuntimeKey(projectRoot) {
|
|
24665
|
-
let canonical2;
|
|
24666
|
-
try {
|
|
24667
|
-
canonical2 = realpathSync3.native(resolve7(projectRoot));
|
|
24668
|
-
} catch {
|
|
24669
|
-
canonical2 = resolve7(projectRoot);
|
|
24670
|
-
}
|
|
24671
|
-
const folded = process.platform === "win32" ? canonical2.toLocaleLowerCase("en-US") : canonical2;
|
|
24672
|
-
return createHash10("sha256").update(folded, "utf8").digest("hex").slice(0, 24);
|
|
24673
|
-
}
|
|
24674
|
-
function kxmProjectRunEventsPath(projectRoot, env) {
|
|
24675
|
-
return join9(kxmRuntimePaths({ env }).projectsDir, projectRuntimeKey(projectRoot), "run-events.db");
|
|
24676
|
-
}
|
|
24677
24733
|
function projectRuntimeOwnsRun(projectRoot, runId, env) {
|
|
24678
24734
|
const path4 = kxmProjectRunEventsPath(projectRoot, env);
|
|
24679
24735
|
if (!existsSync10(path4)) return false;
|
|
@@ -24710,11 +24766,23 @@ CREATE TABLE projects (
|
|
|
24710
24766
|
registered_at TEXT NOT NULL
|
|
24711
24767
|
) STRICT;
|
|
24712
24768
|
`;
|
|
24769
|
+
function readKxmSupervisorRecord(database) {
|
|
24770
|
+
const row = database.prepare("SELECT runtime_id, pid, port, token_hash, started_at, heartbeat_at, state FROM supervisor WHERE singleton_id = 1").get();
|
|
24771
|
+
return row ? {
|
|
24772
|
+
runtimeId: row.runtime_id,
|
|
24773
|
+
pid: row.pid,
|
|
24774
|
+
port: row.port,
|
|
24775
|
+
tokenHash: row.token_hash,
|
|
24776
|
+
startedAt: row.started_at,
|
|
24777
|
+
heartbeatAt: row.heartbeat_at,
|
|
24778
|
+
state: row.state
|
|
24779
|
+
} : void 0;
|
|
24780
|
+
}
|
|
24713
24781
|
var KxmRuntimeRegistry = class {
|
|
24714
24782
|
path;
|
|
24715
24783
|
database;
|
|
24716
24784
|
constructor(path4) {
|
|
24717
|
-
this.path =
|
|
24785
|
+
this.path = resolve8(path4);
|
|
24718
24786
|
this.database = openDatabase(this.path, "runtime registry", {
|
|
24719
24787
|
schema: REGISTRY_SCHEMA,
|
|
24720
24788
|
version: KXM_REGISTRY_SCHEMA_VERSION,
|
|
@@ -24788,16 +24856,7 @@ var KxmRuntimeRegistry = class {
|
|
|
24788
24856
|
return Number(result.changes);
|
|
24789
24857
|
}
|
|
24790
24858
|
readSupervisorRow() {
|
|
24791
|
-
|
|
24792
|
-
return row ? {
|
|
24793
|
-
runtimeId: row.runtime_id,
|
|
24794
|
-
pid: row.pid,
|
|
24795
|
-
port: row.port,
|
|
24796
|
-
tokenHash: row.token_hash,
|
|
24797
|
-
startedAt: row.started_at,
|
|
24798
|
-
heartbeatAt: row.heartbeat_at,
|
|
24799
|
-
state: row.state
|
|
24800
|
-
} : void 0;
|
|
24859
|
+
return readKxmSupervisorRecord(this.database);
|
|
24801
24860
|
}
|
|
24802
24861
|
supervisor() {
|
|
24803
24862
|
return this.readSupervisorRow();
|
|
@@ -24813,7 +24872,7 @@ var KxmRuntimeRegistry = class {
|
|
|
24813
24872
|
return rows.map((row) => ({ projectRoot: row.project_root, projectId: row.project_id }));
|
|
24814
24873
|
}
|
|
24815
24874
|
registerProject(registration) {
|
|
24816
|
-
const projectRoot =
|
|
24875
|
+
const projectRoot = resolve8(registration.projectRoot);
|
|
24817
24876
|
const projectKey = projectRuntimeKey(projectRoot);
|
|
24818
24877
|
this.database.exec("BEGIN IMMEDIATE");
|
|
24819
24878
|
try {
|
|
@@ -25151,7 +25210,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
25151
25210
|
const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
|
|
25152
25211
|
const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
|
|
25153
25212
|
const assignments = compileAssignments(step, id, agent, sink);
|
|
25154
|
-
const
|
|
25213
|
+
const join51 = compileJoin(step, id, sink);
|
|
25155
25214
|
const requiredEvidence = compileEvidence(step, id, sink);
|
|
25156
25215
|
const transitions = compileTransitions(step, id, index, stepIndex, sink);
|
|
25157
25216
|
const outcomes = Object.keys(transitions).sort(compareCodeUnits4);
|
|
@@ -25179,7 +25238,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
25179
25238
|
transitions: orderedTransitions,
|
|
25180
25239
|
requiresPlanHash: requirePlanHash.includes(id),
|
|
25181
25240
|
assignments,
|
|
25182
|
-
join:
|
|
25241
|
+
join: join51
|
|
25183
25242
|
};
|
|
25184
25243
|
if (kind === "agent" || kind === "moa") {
|
|
25185
25244
|
if (!agent) return void 0;
|
|
@@ -25229,15 +25288,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
|
|
|
25229
25288
|
};
|
|
25230
25289
|
}
|
|
25231
25290
|
function compileJoin(step, stepId, sink) {
|
|
25232
|
-
const
|
|
25233
|
-
if (!
|
|
25234
|
-
const declared = stringValue2(
|
|
25291
|
+
const join51 = objectValue2(step.join);
|
|
25292
|
+
if (!join51) return { strategy: "all" };
|
|
25293
|
+
const declared = stringValue2(join51.strategy);
|
|
25235
25294
|
const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
|
|
25236
|
-
const minimumPassed = compileOptionalCount(
|
|
25295
|
+
const minimumPassed = compileOptionalCount(join51.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
|
|
25237
25296
|
const compiled = {
|
|
25238
25297
|
strategy,
|
|
25239
25298
|
...minimumPassed !== void 0 ? { minimumPassed } : {},
|
|
25240
|
-
...typeof
|
|
25299
|
+
...typeof join51.cancelRemaining === "boolean" ? { cancelRemaining: join51.cancelRemaining } : {}
|
|
25241
25300
|
};
|
|
25242
25301
|
return compiled;
|
|
25243
25302
|
}
|
|
@@ -25518,7 +25577,7 @@ var RECORD_LIMIT = 16 * 1024 * 1024;
|
|
|
25518
25577
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
25519
25578
|
import { createHash as createHash11 } from "node:crypto";
|
|
25520
25579
|
import { existsSync as existsSync11, readFileSync as readFileSync9, statSync, writeFileSync as writeFileSync7 } from "node:fs";
|
|
25521
|
-
import { join as
|
|
25580
|
+
import { join as join11 } from "node:path";
|
|
25522
25581
|
|
|
25523
25582
|
// plugins/kxm/src/price-calc.ts
|
|
25524
25583
|
var PRICES_SCHEMA = "kxm.prices.v1";
|
|
@@ -25670,7 +25729,7 @@ function parsePriceCatalog(text) {
|
|
|
25670
25729
|
return catalog;
|
|
25671
25730
|
}
|
|
25672
25731
|
function loadPriceCatalog(rootOrPath) {
|
|
25673
|
-
const candidatePath = existsSync11(
|
|
25732
|
+
const candidatePath = existsSync11(join11(rootOrPath, ".kxm", "prices.yaml")) ? join11(rootOrPath, ".kxm", "prices.yaml") : existsSync11(join11(rootOrPath, "prices.yaml")) ? join11(rootOrPath, "prices.yaml") : existsSync11(rootOrPath) && statSync(rootOrPath).isFile() ? rootOrPath : void 0;
|
|
25674
25733
|
if (!candidatePath || !existsSync11(candidatePath)) {
|
|
25675
25734
|
return void 0;
|
|
25676
25735
|
}
|
|
@@ -25690,7 +25749,7 @@ function loadPriceCatalogForEstimate(options) {
|
|
|
25690
25749
|
return { catalog, unavailable: false, stale: false };
|
|
25691
25750
|
}
|
|
25692
25751
|
function acknowledgePriceCatalog(projectRoot, now = /* @__PURE__ */ new Date()) {
|
|
25693
|
-
const path4 =
|
|
25752
|
+
const path4 = join11(projectRoot, ".kxm", "prices.yaml");
|
|
25694
25753
|
const loaded = loadPriceCatalog(projectRoot);
|
|
25695
25754
|
if (!loaded) throw new Error("price catalog missing");
|
|
25696
25755
|
const date = now.toISOString().slice(0, 10);
|
|
@@ -25721,12 +25780,12 @@ var import_yaml7 = __toESM(require_dist(), 1);
|
|
|
25721
25780
|
// plugins/kxm/src/routes.ts
|
|
25722
25781
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
25723
25782
|
import { existsSync as existsSync12, readFileSync as readFileSync10, mkdirSync as mkdirSync7, writeFileSync as writeFileSync8, readdirSync as readdirSync3 } from "node:fs";
|
|
25724
|
-
import { join as
|
|
25783
|
+
import { join as join12 } from "node:path";
|
|
25725
25784
|
var RETIRED_POLICY = ".kxm/producers.yaml";
|
|
25726
25785
|
var empty = () => ({ schema: "kxm.routes.v2", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), admitted: [], disabled: [], roles: {} });
|
|
25727
25786
|
function loadRoutePolicy(root) {
|
|
25728
|
-
if (existsSync12(
|
|
25729
|
-
const path4 =
|
|
25787
|
+
if (existsSync12(join12(root, RETIRED_POLICY))) throw new Error(`retired ${RETIRED_POLICY} present; use .kxm/routes.yaml (kxm.routes.v2)`);
|
|
25788
|
+
const path4 = join12(root, ".kxm", "routes.yaml");
|
|
25730
25789
|
if (!existsSync12(path4)) return empty();
|
|
25731
25790
|
const value = (0, import_yaml4.parse)(readFileSync10(path4, "utf8"));
|
|
25732
25791
|
if (value?.schema !== "kxm.routes.v2" || !Array.isArray(value.admitted)) throw new Error("invalid .kxm/routes.yaml");
|
|
@@ -25743,7 +25802,7 @@ function setRouteState(root, model, state, role, removeRole2 = false) {
|
|
|
25743
25802
|
else policy.disabled.push(model);
|
|
25744
25803
|
if (role) {
|
|
25745
25804
|
if (!/^[a-z][a-z0-9_-]{0,63}$/i.test(role)) throw new Error("invalid role id");
|
|
25746
|
-
const rolePath =
|
|
25805
|
+
const rolePath = join12(root, ".kxm", "roles", `${role}.yaml`);
|
|
25747
25806
|
let roleFile = {};
|
|
25748
25807
|
if (existsSync12(rolePath)) {
|
|
25749
25808
|
const parsed = (0, import_yaml4.parse)(readFileSync10(rolePath, "utf8"));
|
|
@@ -25757,27 +25816,27 @@ function setRouteState(root, model, state, role, removeRole2 = false) {
|
|
|
25757
25816
|
roleFile.schema ??= "kxm.role.v1";
|
|
25758
25817
|
roleFile.id ??= role;
|
|
25759
25818
|
roleFile.roster = roster;
|
|
25760
|
-
mkdirSync7(
|
|
25819
|
+
mkdirSync7(join12(root, ".kxm", "roles"), { recursive: true });
|
|
25761
25820
|
writeFileSync8(rolePath, (0, import_yaml4.stringify)(roleFile), "utf8");
|
|
25762
25821
|
}
|
|
25763
25822
|
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
25764
|
-
mkdirSync7(
|
|
25765
|
-
writeFileSync8(
|
|
25823
|
+
mkdirSync7(join12(root, ".kxm"), { recursive: true });
|
|
25824
|
+
writeFileSync8(join12(root, ".kxm", "routes.yaml"), (0, import_yaml4.stringify)(policy), "utf8");
|
|
25766
25825
|
return policy;
|
|
25767
25826
|
}
|
|
25768
25827
|
function listRoleBindings(root) {
|
|
25769
|
-
const dir =
|
|
25828
|
+
const dir = join12(root, ".kxm", "roles");
|
|
25770
25829
|
const result = {};
|
|
25771
25830
|
if (!existsSync12(dir)) return result;
|
|
25772
25831
|
for (const file of readdirSync3(dir).filter((name) => name.endsWith(".yaml"))) {
|
|
25773
25832
|
const role = file.slice(0, -5);
|
|
25774
|
-
const value = (0, import_yaml4.parse)(readFileSync10(
|
|
25833
|
+
const value = (0, import_yaml4.parse)(readFileSync10(join12(dir, file), "utf8"));
|
|
25775
25834
|
result[role] = (value.roster ?? []).map((entry) => entry.model).filter((model) => typeof model === "string");
|
|
25776
25835
|
}
|
|
25777
25836
|
return result;
|
|
25778
25837
|
}
|
|
25779
25838
|
function listInventoryModels(root) {
|
|
25780
|
-
const path4 =
|
|
25839
|
+
const path4 = join12(root, ".kxm", "models", "inventory.yaml");
|
|
25781
25840
|
if (!existsSync12(path4)) return [];
|
|
25782
25841
|
const value = (0, import_yaml4.parse)(readFileSync10(path4, "utf8"));
|
|
25783
25842
|
return (value.models ?? []).map((m2) => m2.id).filter((id) => typeof id === "string");
|
|
@@ -25785,9 +25844,9 @@ function listInventoryModels(root) {
|
|
|
25785
25844
|
|
|
25786
25845
|
// plugins/kxm/src/memory.ts
|
|
25787
25846
|
var import_yaml5 = __toESM(require_dist(), 1);
|
|
25788
|
-
import { randomUUID as
|
|
25847
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
25789
25848
|
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readdirSync as readdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "node:fs";
|
|
25790
|
-
import { extname as extname2, join as
|
|
25849
|
+
import { extname as extname2, join as join13, resolve as resolve9 } from "node:path";
|
|
25791
25850
|
var MEMORY_SCHEMA = "kxm.memory.v1";
|
|
25792
25851
|
var MEMORY_BRIEF_SCHEMA = "kxm.memory-brief.v1";
|
|
25793
25852
|
var MEMORY_MARKER_START = "<!-- kxm:memory:start -->";
|
|
@@ -25913,9 +25972,9 @@ ${yamlText}
|
|
|
25913
25972
|
`;
|
|
25914
25973
|
}
|
|
25915
25974
|
function memoryDirectories(repoRoot) {
|
|
25916
|
-
const root =
|
|
25917
|
-
const memoryDir =
|
|
25918
|
-
const candidatesDir =
|
|
25975
|
+
const root = resolve9(repoRoot);
|
|
25976
|
+
const memoryDir = join13(root, ".kxm", "memory");
|
|
25977
|
+
const candidatesDir = join13(memoryDir, "candidates");
|
|
25919
25978
|
return { memoryDir, candidatesDir };
|
|
25920
25979
|
}
|
|
25921
25980
|
function loadAuthoredMemory(repoRoot) {
|
|
@@ -25925,7 +25984,7 @@ function loadAuthoredMemory(repoRoot) {
|
|
|
25925
25984
|
const entries = readdirSync4(memoryDir, { withFileTypes: true });
|
|
25926
25985
|
for (const entry of entries) {
|
|
25927
25986
|
if (entry.isFile() && extname2(entry.name) === ".md") {
|
|
25928
|
-
const fullPath =
|
|
25987
|
+
const fullPath = join13(memoryDir, entry.name);
|
|
25929
25988
|
try {
|
|
25930
25989
|
const text = readFileSync11(fullPath, "utf8");
|
|
25931
25990
|
const record = parseMemoryRecord(text, entry.name);
|
|
@@ -25945,7 +26004,7 @@ function createMemoryNote(repoRoot, summary, options = {}) {
|
|
|
25945
26004
|
if (!VALID_SCOPES.has(scope)) {
|
|
25946
26005
|
throw new Error(`invalid memory note scope: ${scope}; must be one of agent, project, run, operator`);
|
|
25947
26006
|
}
|
|
25948
|
-
const hex =
|
|
26007
|
+
const hex = randomUUID4().replaceAll("-", "").slice(0, 12);
|
|
25949
26008
|
const id = `cand_${scope}_${hex}`;
|
|
25950
26009
|
const record = {
|
|
25951
26010
|
schema: MEMORY_SCHEMA,
|
|
@@ -25965,7 +26024,7 @@ function createMemoryNote(repoRoot, summary, options = {}) {
|
|
|
25965
26024
|
evidenceRefs: [],
|
|
25966
26025
|
...options.body ? { body: options.body.trim() } : {}
|
|
25967
26026
|
};
|
|
25968
|
-
const targetPath =
|
|
26027
|
+
const targetPath = join13(candidatesDir, `${id}.md`);
|
|
25969
26028
|
if (options.dryRun) return { record, path: targetPath };
|
|
25970
26029
|
mkdirSync8(candidatesDir, { recursive: true });
|
|
25971
26030
|
writeFileSync9(targetPath, formatMemoryRecord(record), "utf8");
|
|
@@ -26026,8 +26085,8 @@ ${block}
|
|
|
26026
26085
|
return original.slice(0, startIdx) + block + original.slice(endIdx);
|
|
26027
26086
|
}
|
|
26028
26087
|
function syncHarnessMemory(repoRoot, options = {}) {
|
|
26029
|
-
const root =
|
|
26030
|
-
const present = HARNESS_INSTRUCTION_FILES.filter((name) => existsSync13(
|
|
26088
|
+
const root = resolve9(repoRoot);
|
|
26089
|
+
const present = HARNESS_INSTRUCTION_FILES.filter((name) => existsSync13(join13(root, name)));
|
|
26031
26090
|
const missing = HARNESS_INSTRUCTION_FILES.filter((name) => !present.includes(name));
|
|
26032
26091
|
if (present.length === 0) {
|
|
26033
26092
|
throw new Error(
|
|
@@ -26035,7 +26094,7 @@ function syncHarnessMemory(repoRoot, options = {}) {
|
|
|
26035
26094
|
);
|
|
26036
26095
|
}
|
|
26037
26096
|
const documents = present.map((name) => {
|
|
26038
|
-
const original = readFileSync11(
|
|
26097
|
+
const original = readFileSync11(join13(root, name), "utf8");
|
|
26039
26098
|
return { name, original, problem: memoryMarkerProblem(original) };
|
|
26040
26099
|
});
|
|
26041
26100
|
const malformed = documents.filter((doc) => doc.problem !== void 0);
|
|
@@ -26052,7 +26111,7 @@ function syncHarnessMemory(repoRoot, options = {}) {
|
|
|
26052
26111
|
if (next === original) {
|
|
26053
26112
|
unchanged.push(name);
|
|
26054
26113
|
} else {
|
|
26055
|
-
if (!options.dryRun) writeFileSync9(
|
|
26114
|
+
if (!options.dryRun) writeFileSync9(join13(root, name), next, "utf8");
|
|
26056
26115
|
updated.push(name);
|
|
26057
26116
|
}
|
|
26058
26117
|
}
|
|
@@ -26063,7 +26122,7 @@ function syncHarnessMemory(repoRoot, options = {}) {
|
|
|
26063
26122
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
26064
26123
|
import { createHash as createHash12 } from "node:crypto";
|
|
26065
26124
|
import { existsSync as existsSync14, mkdirSync as mkdirSync9, readdirSync as readdirSync5, readFileSync as readFileSync12, renameSync as renameSync3, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync10 } from "node:fs";
|
|
26066
|
-
import { dirname as dirname9, join as
|
|
26125
|
+
import { dirname as dirname9, join as join14 } from "node:path";
|
|
26067
26126
|
var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
|
|
26068
26127
|
var SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
|
|
26069
26128
|
var SKILL_DECISION_SCHEMA = "kxm.skill-decision.v1";
|
|
@@ -26169,14 +26228,14 @@ var SkillLifecycle = class {
|
|
|
26169
26228
|
writeFileSync10(file, content);
|
|
26170
26229
|
}
|
|
26171
26230
|
dir(state) {
|
|
26172
|
-
return
|
|
26231
|
+
return join14(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
|
|
26173
26232
|
}
|
|
26174
26233
|
historyFile(id) {
|
|
26175
|
-
return
|
|
26234
|
+
return join14(this.root, "history", `${id}.jsonl`);
|
|
26176
26235
|
}
|
|
26177
26236
|
paths(state, id) {
|
|
26178
|
-
const dir =
|
|
26179
|
-
return { dir, metadata:
|
|
26237
|
+
const dir = join14(this.dir(state), id);
|
|
26238
|
+
return { dir, metadata: join14(dir, "metadata.json"), skill: join14(dir, "SKILL.md") };
|
|
26180
26239
|
}
|
|
26181
26240
|
appendHistory(id, record) {
|
|
26182
26241
|
const line = `${JSON.stringify(record)}
|
|
@@ -26202,8 +26261,8 @@ var SkillLifecycle = class {
|
|
|
26202
26261
|
return JSON.parse(readFileSync12(metadata, "utf8"));
|
|
26203
26262
|
}
|
|
26204
26263
|
move(from, to, id) {
|
|
26205
|
-
const fromDir =
|
|
26206
|
-
const toDir =
|
|
26264
|
+
const fromDir = join14(this.dir(from), id);
|
|
26265
|
+
const toDir = join14(this.dir(to), id);
|
|
26207
26266
|
if (!existsSync14(fromDir)) {
|
|
26208
26267
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${from}`);
|
|
26209
26268
|
}
|
|
@@ -26368,7 +26427,7 @@ var SkillLifecycle = class {
|
|
|
26368
26427
|
const metadataContent = readFileSync12(candidatePaths.metadata, "utf8");
|
|
26369
26428
|
this.write(promotedPaths.skill, skillContent);
|
|
26370
26429
|
this.write(promotedPaths.metadata, metadataContent);
|
|
26371
|
-
const patchPath =
|
|
26430
|
+
const patchPath = join14(this.root, "patches", `${candidateId}.patch`);
|
|
26372
26431
|
const relSkillPath = `.kxm/skills/promoted/${candidateId}/SKILL.md`;
|
|
26373
26432
|
const relMetaPath = `.kxm/skills/promoted/${candidateId}/metadata.json`;
|
|
26374
26433
|
const patch = `${createUnifiedPatch(relSkillPath, skillContent)}${createUnifiedPatch(relMetaPath, metadataContent)}`;
|
|
@@ -26442,7 +26501,7 @@ function boundedList(value, field) {
|
|
|
26442
26501
|
return [...new Set(refs)];
|
|
26443
26502
|
}
|
|
26444
26503
|
function readdirSorted(dir) {
|
|
26445
|
-
return readdirSync5(dir).filter((entry) => statSync2(
|
|
26504
|
+
return readdirSync5(dir).filter((entry) => statSync2(join14(dir, entry)).isDirectory()).sort();
|
|
26446
26505
|
}
|
|
26447
26506
|
|
|
26448
26507
|
// plugins/kxm/src/dispatch-context.ts
|
|
@@ -26464,14 +26523,14 @@ var NOT_LOADED_DISPATCH_SOURCES = Object.freeze({
|
|
|
26464
26523
|
|
|
26465
26524
|
// plugins/kxm/src/artifacts-exist.ts
|
|
26466
26525
|
import { lstatSync as lstatSync5, realpathSync as realpathSync4, statSync as statSync3 } from "node:fs";
|
|
26467
|
-
import { isAbsolute as
|
|
26526
|
+
import { isAbsolute as isAbsolute5, relative as relative4, resolve as resolve10 } from "node:path";
|
|
26468
26527
|
function staysUnder(root, candidate) {
|
|
26469
|
-
const child =
|
|
26470
|
-
return child === "" || !
|
|
26528
|
+
const child = relative4(root, candidate);
|
|
26529
|
+
return child === "" || !isAbsolute5(child) && child !== ".." && !child.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`);
|
|
26471
26530
|
}
|
|
26472
26531
|
function verifyArtifactExists(rootInput, pathInput) {
|
|
26473
|
-
const lexicalRoot =
|
|
26474
|
-
const lexicalPath =
|
|
26532
|
+
const lexicalRoot = resolve10(rootInput);
|
|
26533
|
+
const lexicalPath = resolve10(pathInput);
|
|
26475
26534
|
if (!staysUnder(lexicalRoot, lexicalPath)) {
|
|
26476
26535
|
return { ok: false, error: "artifact_outside_workspace_assets", path: lexicalPath };
|
|
26477
26536
|
}
|
|
@@ -27106,7 +27165,7 @@ var MAX_PRODUCER_ROUTING_METADATA_FIELDS = MAX_PROVIDER_METADATA_FIELDS - ENGINE
|
|
|
27106
27165
|
// plugins/kxm/src/hub-binding.ts
|
|
27107
27166
|
import { existsSync as existsSync15, mkdirSync as mkdirSync10, readFileSync as readFileSync13, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as writeFileSync11 } from "node:fs";
|
|
27108
27167
|
import { homedir as homedir4 } from "node:os";
|
|
27109
|
-
import { dirname as dirname10, isAbsolute as
|
|
27168
|
+
import { dirname as dirname10, isAbsolute as isAbsolute6, join as join15, resolve as resolve11 } from "node:path";
|
|
27110
27169
|
var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
27111
27170
|
var HUB_HEALTH_PROBE_MS = 300;
|
|
27112
27171
|
var HubBindingError = class extends Error {
|
|
@@ -27118,21 +27177,21 @@ var HubBindingError = class extends Error {
|
|
|
27118
27177
|
function resolveUserStateRoot2(env) {
|
|
27119
27178
|
const explicit = env.KXM_STATE_HOME?.trim();
|
|
27120
27179
|
if (explicit) {
|
|
27121
|
-
if (!
|
|
27122
|
-
return
|
|
27180
|
+
if (!isAbsolute6(explicit)) throw new HubBindingError("local_state_root_not_absolute");
|
|
27181
|
+
return resolve11(explicit);
|
|
27123
27182
|
}
|
|
27124
27183
|
if (process.platform === "win32") {
|
|
27125
27184
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
27126
|
-
const base2 = localAppData &&
|
|
27127
|
-
return
|
|
27185
|
+
const base2 = localAppData && isAbsolute6(localAppData) ? localAppData : join15(homedir4(), "AppData", "Local");
|
|
27186
|
+
return resolve11(base2, "KXM");
|
|
27128
27187
|
}
|
|
27129
|
-
if (process.platform === "darwin") return
|
|
27188
|
+
if (process.platform === "darwin") return resolve11(homedir4(), "Library", "Application Support", "KXM");
|
|
27130
27189
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
27131
|
-
const base = xdgState &&
|
|
27132
|
-
return
|
|
27190
|
+
const base = xdgState && isAbsolute6(xdgState) ? xdgState : join15(homedir4(), ".local", "state");
|
|
27191
|
+
return resolve11(base, "kxm");
|
|
27133
27192
|
}
|
|
27134
27193
|
function hubBindingFile(env = process.env) {
|
|
27135
|
-
return
|
|
27194
|
+
return join15(resolveUserStateRoot2(env), "hub-binding.json");
|
|
27136
27195
|
}
|
|
27137
27196
|
function validateHubUrl(raw) {
|
|
27138
27197
|
let parsed;
|
|
@@ -27194,7 +27253,7 @@ function readHubBinding(env = process.env) {
|
|
|
27194
27253
|
function writeHubBinding(record, env = process.env) {
|
|
27195
27254
|
const file = hubBindingFile(env);
|
|
27196
27255
|
mkdirSync10(dirname10(file), { recursive: true, mode: 448 });
|
|
27197
|
-
const temporary =
|
|
27256
|
+
const temporary = join15(dirname10(file), `.hub-binding-${process.pid}.tmp`);
|
|
27198
27257
|
try {
|
|
27199
27258
|
writeFileSync11(temporary, `${JSON.stringify(record, null, 2)}
|
|
27200
27259
|
`, { encoding: "utf8", mode: 384 });
|
|
@@ -27243,7 +27302,7 @@ var DEFAULT_LOG_MAX_BYTES = 10 * 1024 * 1024;
|
|
|
27243
27302
|
|
|
27244
27303
|
// plugins/kxm/src/runtime-supervisor.ts
|
|
27245
27304
|
function kxmSupervisorTokenFile(paths) {
|
|
27246
|
-
return
|
|
27305
|
+
return join16(paths.runtimeDir, "supervisor.token");
|
|
27247
27306
|
}
|
|
27248
27307
|
function readKxmSupervisorToken(paths) {
|
|
27249
27308
|
const file = kxmSupervisorTokenFile(paths);
|
|
@@ -27266,7 +27325,7 @@ function processAlive(pid) {
|
|
|
27266
27325
|
var HEARTBEAT_STALE_MS = 15e3;
|
|
27267
27326
|
var SUPERVISOR_ERROR_MAX_AGE_MS = 3e4;
|
|
27268
27327
|
function supervisorErrorFile(paths) {
|
|
27269
|
-
return
|
|
27328
|
+
return join16(paths.runtimeDir, "supervisor.error");
|
|
27270
27329
|
}
|
|
27271
27330
|
function clearSupervisorError(paths) {
|
|
27272
27331
|
const file = supervisorErrorFile(paths);
|
|
@@ -27284,24 +27343,35 @@ function readRecentSupervisorError(paths) {
|
|
|
27284
27343
|
return void 0;
|
|
27285
27344
|
}
|
|
27286
27345
|
}
|
|
27287
|
-
function
|
|
27346
|
+
function supervisorStatusOf(record) {
|
|
27347
|
+
if (!record) return { running: false };
|
|
27348
|
+
const heartbeatAgeMs = Date.now() - Date.parse(record.heartbeatAt);
|
|
27349
|
+
const fresh = Number.isFinite(heartbeatAgeMs) && heartbeatAgeMs < HEARTBEAT_STALE_MS;
|
|
27350
|
+
const alive = record.state === "running" && fresh && processAlive(record.pid);
|
|
27351
|
+
return {
|
|
27352
|
+
running: alive,
|
|
27353
|
+
runtimeId: record.runtimeId,
|
|
27354
|
+
pid: record.pid,
|
|
27355
|
+
port: record.port,
|
|
27356
|
+
state: alive ? record.state : "dead",
|
|
27357
|
+
heartbeatAt: record.heartbeatAt,
|
|
27358
|
+
startedAt: record.startedAt
|
|
27359
|
+
};
|
|
27360
|
+
}
|
|
27361
|
+
function kxmSupervisorStatus(paths, options = {}) {
|
|
27288
27362
|
if (!existsSync16(paths.registryDb)) return { running: false };
|
|
27363
|
+
if (options.readOnly) {
|
|
27364
|
+
const database = openReadOnlyDatabase(paths.registryDb);
|
|
27365
|
+
try {
|
|
27366
|
+
database.exec("PRAGMA busy_timeout = 5000");
|
|
27367
|
+
return supervisorStatusOf(readKxmSupervisorRecord(database));
|
|
27368
|
+
} finally {
|
|
27369
|
+
database.close();
|
|
27370
|
+
}
|
|
27371
|
+
}
|
|
27289
27372
|
const registry = new KxmRuntimeRegistry(paths.registryDb);
|
|
27290
27373
|
try {
|
|
27291
|
-
|
|
27292
|
-
if (!record) return { running: false };
|
|
27293
|
-
const heartbeatAgeMs = Date.now() - Date.parse(record.heartbeatAt);
|
|
27294
|
-
const fresh = Number.isFinite(heartbeatAgeMs) && heartbeatAgeMs < HEARTBEAT_STALE_MS;
|
|
27295
|
-
const alive = record.state === "running" && fresh && processAlive(record.pid);
|
|
27296
|
-
return {
|
|
27297
|
-
running: alive,
|
|
27298
|
-
runtimeId: record.runtimeId,
|
|
27299
|
-
pid: record.pid,
|
|
27300
|
-
port: record.port,
|
|
27301
|
-
state: alive ? record.state : "dead",
|
|
27302
|
-
heartbeatAt: record.heartbeatAt,
|
|
27303
|
-
startedAt: record.startedAt
|
|
27304
|
-
};
|
|
27374
|
+
return supervisorStatusOf(registry.supervisor());
|
|
27305
27375
|
} finally {
|
|
27306
27376
|
registry.close();
|
|
27307
27377
|
}
|
|
@@ -27355,7 +27425,7 @@ async function ensureKxmSupervisor(options = {}) {
|
|
|
27355
27425
|
throw runtimeError("runtime_supervisor_unreachable", paths.registryDb, `runtime supervisor pid ${status.pid} is registered as running but cannot be probed`);
|
|
27356
27426
|
}
|
|
27357
27427
|
clearSupervisorError(paths);
|
|
27358
|
-
const scriptPath =
|
|
27428
|
+
const scriptPath = join16(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
|
|
27359
27429
|
const spawnImpl = options.spawnImpl ?? ((script, env) => {
|
|
27360
27430
|
const child = spawn2(process.execPath, [script], {
|
|
27361
27431
|
detached: true,
|
|
@@ -27419,11 +27489,11 @@ function handoffSuffix(handoff) {
|
|
|
27419
27489
|
|
|
27420
27490
|
// plugins/kxm/src/cli/types.ts
|
|
27421
27491
|
import { spawn as spawn3 } from "node:child_process";
|
|
27422
|
-
import { join as
|
|
27492
|
+
import { join as join18, resolve as resolve12 } from "node:path";
|
|
27423
27493
|
|
|
27424
27494
|
// plugins/kxm/src/telemetry.ts
|
|
27425
27495
|
import { appendFileSync, mkdirSync as mkdirSync12, readFileSync as readFileSync15 } from "node:fs";
|
|
27426
|
-
import { dirname as dirname12, join as
|
|
27496
|
+
import { dirname as dirname12, join as join17 } from "node:path";
|
|
27427
27497
|
var TELEMETRY_SCHEMA = "kxm.telemetry.v1";
|
|
27428
27498
|
function inferImprovementTarget(input) {
|
|
27429
27499
|
const explicit = input.env?.KXM_IMPROVE_TARGET?.trim();
|
|
@@ -27438,7 +27508,7 @@ function appendTelemetry(path4, event) {
|
|
|
27438
27508
|
`, { encoding: "utf8", mode: 384 });
|
|
27439
27509
|
}
|
|
27440
27510
|
function telemetryPath(logsDir) {
|
|
27441
|
-
return
|
|
27511
|
+
return join17(logsDir, "telemetry.jsonl");
|
|
27442
27512
|
}
|
|
27443
27513
|
function makeTelemetryEvent(input) {
|
|
27444
27514
|
return {
|
|
@@ -27532,7 +27602,7 @@ function workerResult(worker, payload) {
|
|
|
27532
27602
|
// plugins/kxm/src/cli/types.ts
|
|
27533
27603
|
function spawnScript(scriptName, extraEnv = {}) {
|
|
27534
27604
|
return new Promise((resolveExit) => {
|
|
27535
|
-
const child = spawn3(process.execPath, [
|
|
27605
|
+
const child = spawn3(process.execPath, [join18(findKxmRepoRoot(import.meta.url), "scripts", scriptName)], {
|
|
27536
27606
|
stdio: "inherit",
|
|
27537
27607
|
env: { ...process.env, ...extraEnv }
|
|
27538
27608
|
});
|
|
@@ -27627,16 +27697,16 @@ function redactCliValue(value, field = "") {
|
|
|
27627
27697
|
return value;
|
|
27628
27698
|
}
|
|
27629
27699
|
function workspaceDirs(cwd, workspaceFlag, env) {
|
|
27630
|
-
const workdir =
|
|
27631
|
-
const workspace =
|
|
27700
|
+
const workdir = resolve12(env.KXM_WORKDIR?.trim() || cwd);
|
|
27701
|
+
const workspace = resolve12(workdir, workspaceFlag || env.KXM_WORKSPACE_DIR?.trim() || ".kxm");
|
|
27632
27702
|
const derive = workspaceFlag !== void 0;
|
|
27633
27703
|
return {
|
|
27634
27704
|
workdir,
|
|
27635
27705
|
workspace,
|
|
27636
|
-
config: derive ?
|
|
27637
|
-
logs: derive ?
|
|
27638
|
-
assets: derive ?
|
|
27639
|
-
state: derive ?
|
|
27706
|
+
config: derive ? join18(workspace, "config") : resolve12(workdir, env.KXM_CONFIG_DIR?.trim() || join18(workspace, "config")),
|
|
27707
|
+
logs: derive ? join18(workspace, "logs") : resolve12(workdir, env.KXM_LOGS_DIR?.trim() || join18(workspace, "logs")),
|
|
27708
|
+
assets: derive ? join18(workspace, "assets") : resolve12(workdir, env.KXM_ASSETS_DIR?.trim() || join18(workspace, "assets")),
|
|
27709
|
+
state: derive ? join18(workspace, "state") : resolve12(workdir, env.KXM_STATE_DIR?.trim() || join18(workspace, "state"))
|
|
27640
27710
|
};
|
|
27641
27711
|
}
|
|
27642
27712
|
function maskEnvName(name) {
|
|
@@ -27703,21 +27773,21 @@ function workspaceEnv(runtime) {
|
|
|
27703
27773
|
|
|
27704
27774
|
// plugins/kxm/src/cli/roles.ts
|
|
27705
27775
|
var import_yaml10 = __toESM(require_dist(), 1);
|
|
27706
|
-
import { randomUUID as
|
|
27776
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
27707
27777
|
import { existsSync as existsSync19, readFileSync as readFileSync18 } from "node:fs";
|
|
27708
|
-
import { join as
|
|
27778
|
+
import { join as join21, resolve as resolve15 } from "node:path";
|
|
27709
27779
|
import { createInterface } from "node:readline";
|
|
27710
27780
|
|
|
27711
27781
|
// plugins/kxm/src/role.ts
|
|
27712
27782
|
var import_yaml9 = __toESM(require_dist(), 1);
|
|
27713
27783
|
import { existsSync as existsSync18, mkdirSync as mkdirSync14, readdirSync as readdirSync6, readFileSync as readFileSync17, rmSync as rmSync6, writeFileSync as writeFileSync14 } from "node:fs";
|
|
27714
|
-
import { join as
|
|
27784
|
+
import { join as join20 } from "node:path";
|
|
27715
27785
|
|
|
27716
27786
|
// plugins/kxm/src/config.ts
|
|
27717
27787
|
var import_yaml8 = __toESM(require_dist(), 1);
|
|
27718
27788
|
import { existsSync as existsSync17, mkdirSync as mkdirSync13, readFileSync as readFileSync16, writeFileSync as writeFileSync13 } from "node:fs";
|
|
27719
27789
|
import { homedir as homedir5 } from "node:os";
|
|
27720
|
-
import { dirname as dirname13, join as
|
|
27790
|
+
import { dirname as dirname13, join as join19, resolve as resolve13 } from "node:path";
|
|
27721
27791
|
var KXM_CONFIG_SCHEMA = "kxm.config.v1";
|
|
27722
27792
|
var IMPROVEMENT_PROMOTION_POLICIES = ["manual_pr", "critic_quorum", "auto_threshold"];
|
|
27723
27793
|
var DEFAULT_KXM_CONFIG = {
|
|
@@ -27771,11 +27841,11 @@ var DEFAULT_KXM_CONFIG = {
|
|
|
27771
27841
|
}
|
|
27772
27842
|
};
|
|
27773
27843
|
function userConfigDirectory(overrideDir) {
|
|
27774
|
-
if (overrideDir) return
|
|
27775
|
-
return
|
|
27844
|
+
if (overrideDir) return resolve13(overrideDir);
|
|
27845
|
+
return resolve13(process.env.KXM_USER_CONFIG_DIR?.trim() || join19(homedir5(), ".config", "kxm"));
|
|
27776
27846
|
}
|
|
27777
27847
|
function repoConfigDirectory(repoRoot) {
|
|
27778
|
-
return
|
|
27848
|
+
return resolve13(repoRoot, ".kxm");
|
|
27779
27849
|
}
|
|
27780
27850
|
function deepMerge(target, source) {
|
|
27781
27851
|
const result = { ...target };
|
|
@@ -27819,9 +27889,9 @@ function normalizeImprovementConfig(raw) {
|
|
|
27819
27889
|
}
|
|
27820
27890
|
function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
|
|
27821
27891
|
const userDir = userConfigDirectory(options.userConfigDir);
|
|
27822
|
-
const userConfigFile =
|
|
27892
|
+
const userConfigFile = join19(userDir, "config.yaml");
|
|
27823
27893
|
const repoDir = repoConfigDirectory(repoRoot);
|
|
27824
|
-
const repoConfigFile =
|
|
27894
|
+
const repoConfigFile = join19(repoDir, "config.yaml");
|
|
27825
27895
|
let userRaw = {};
|
|
27826
27896
|
let userLoadedPath;
|
|
27827
27897
|
if (existsSync17(userConfigFile)) {
|
|
@@ -27873,7 +27943,7 @@ function getKxmConfigValue(config, keyPath) {
|
|
|
27873
27943
|
return current;
|
|
27874
27944
|
}
|
|
27875
27945
|
function kxmConfigFileForScope(repoRoot, scope, userConfigDir) {
|
|
27876
|
-
return scope === "user" ?
|
|
27946
|
+
return scope === "user" ? join19(userConfigDirectory(userConfigDir), "config.yaml") : join19(repoConfigDirectory(repoRoot), "config.yaml");
|
|
27877
27947
|
}
|
|
27878
27948
|
function configKeyParts(keyPath) {
|
|
27879
27949
|
const parts = keyPath.split(".");
|
|
@@ -28004,9 +28074,9 @@ var DEFAULT_ROLES = {
|
|
|
28004
28074
|
};
|
|
28005
28075
|
function rolesDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
28006
28076
|
if (scope === "global") {
|
|
28007
|
-
return
|
|
28077
|
+
return join20(userConfigDirectory(userConfigDir), "roles");
|
|
28008
28078
|
}
|
|
28009
|
-
return
|
|
28079
|
+
return join20(repoConfigDirectory(repoRoot), "roles");
|
|
28010
28080
|
}
|
|
28011
28081
|
function ensureRolesDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
28012
28082
|
const dir = rolesDirectory(scope, repoRoot, userConfigDir);
|
|
@@ -28048,7 +28118,7 @@ function listRoles(options = {}) {
|
|
|
28048
28118
|
if (scopeFilter !== "global" && existsSync18(localDir)) {
|
|
28049
28119
|
for (const entry of readdirSync6(localDir)) {
|
|
28050
28120
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
28051
|
-
const filePath =
|
|
28121
|
+
const filePath = join20(localDir, entry);
|
|
28052
28122
|
const parsed = parseRoleFile(filePath);
|
|
28053
28123
|
if (parsed) {
|
|
28054
28124
|
localRoles.set(parsed.id, { role: parsed, filePath });
|
|
@@ -28060,7 +28130,7 @@ function listRoles(options = {}) {
|
|
|
28060
28130
|
if (scopeFilter !== "local" && existsSync18(globalDir)) {
|
|
28061
28131
|
for (const entry of readdirSync6(globalDir)) {
|
|
28062
28132
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
28063
|
-
const filePath =
|
|
28133
|
+
const filePath = join20(globalDir, entry);
|
|
28064
28134
|
const parsed = parseRoleFile(filePath);
|
|
28065
28135
|
if (parsed) {
|
|
28066
28136
|
globalRoles.set(parsed.id, { role: parsed, filePath });
|
|
@@ -28108,13 +28178,13 @@ function getRole(roleId, options = {}) {
|
|
|
28108
28178
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
28109
28179
|
if (scope !== "global") {
|
|
28110
28180
|
const localDir = rolesDirectory("local", repoRoot, options.userConfigDir);
|
|
28111
|
-
const localFile =
|
|
28181
|
+
const localFile = join20(localDir, `${roleId}.yaml`);
|
|
28112
28182
|
const parsed = parseRoleFile(localFile);
|
|
28113
28183
|
if (parsed) return { role: parsed, scope: "local", filePath: localFile };
|
|
28114
28184
|
}
|
|
28115
28185
|
if (scope !== "local") {
|
|
28116
28186
|
const globalDir = rolesDirectory("global", repoRoot, options.userConfigDir);
|
|
28117
|
-
const globalFile =
|
|
28187
|
+
const globalFile = join20(globalDir, `${roleId}.yaml`);
|
|
28118
28188
|
const parsed = parseRoleFile(globalFile);
|
|
28119
28189
|
if (parsed) return { role: parsed, scope: "global", filePath: globalFile };
|
|
28120
28190
|
}
|
|
@@ -28124,7 +28194,7 @@ function addRole(role, options = {}) {
|
|
|
28124
28194
|
const scope = options.scope ?? "local";
|
|
28125
28195
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
28126
28196
|
const dir = options.dryRun ? rolesDirectory(scope, repoRoot, options.userConfigDir) : ensureRolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
28127
|
-
const filePath =
|
|
28197
|
+
const filePath = join20(dir, `${role.id}.yaml`);
|
|
28128
28198
|
if (existsSync18(filePath) && !options.overwrite) {
|
|
28129
28199
|
throw new Error(`role_already_exists: role '${role.id}' already exists at ${filePath}`);
|
|
28130
28200
|
}
|
|
@@ -28135,7 +28205,7 @@ function removeRole(roleId, options = {}) {
|
|
|
28135
28205
|
const scope = options.scope ?? "local";
|
|
28136
28206
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
28137
28207
|
const dir = rolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
28138
|
-
const filePath =
|
|
28208
|
+
const filePath = join20(dir, `${roleId}.yaml`);
|
|
28139
28209
|
if (!existsSync18(filePath)) {
|
|
28140
28210
|
throw new Error(`role_not_found: role '${roleId}' not found in ${scope} directory (${filePath})`);
|
|
28141
28211
|
}
|
|
@@ -28158,7 +28228,7 @@ function modifyRole(roleId, updates, options = {}) {
|
|
|
28158
28228
|
const scope = options.scope ?? target.scope;
|
|
28159
28229
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
28160
28230
|
const dir = options.dryRun ? rolesDirectory(scope, repoRoot, options.userConfigDir) : ensureRolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
28161
|
-
const filePath =
|
|
28231
|
+
const filePath = join20(dir, `${roleId}.yaml`);
|
|
28162
28232
|
if (!options.dryRun) writeFileSync14(filePath, (0, import_yaml9.stringify)(updated), "utf8");
|
|
28163
28233
|
return { id: roleId, role: updated, filePath, scope };
|
|
28164
28234
|
}
|
|
@@ -28207,9 +28277,9 @@ var DEFAULT_ROLE_SEATS = {
|
|
|
28207
28277
|
};
|
|
28208
28278
|
function findExistingRoleHostsFile(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
28209
28279
|
const dir = scope === "global" ? userConfigDirectory(userConfigDir) : repoConfigDirectory(repoRoot);
|
|
28210
|
-
const yamlPath =
|
|
28211
|
-
const ymlPath =
|
|
28212
|
-
const jsonPath =
|
|
28280
|
+
const yamlPath = join20(dir, "role-hosts.yaml");
|
|
28281
|
+
const ymlPath = join20(dir, "role-hosts.yml");
|
|
28282
|
+
const jsonPath = join20(dir, "role-hosts.json");
|
|
28213
28283
|
if (existsSync18(yamlPath)) return { filePath: yamlPath, exists: true, format: "yaml" };
|
|
28214
28284
|
if (existsSync18(ymlPath)) return { filePath: ymlPath, exists: true, format: "yaml" };
|
|
28215
28285
|
if (existsSync18(jsonPath)) return { filePath: jsonPath, exists: true, format: "json" };
|
|
@@ -28291,7 +28361,7 @@ function saveRoleHostsConfig(config, options = {}) {
|
|
|
28291
28361
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
28292
28362
|
const dir = scope === "global" ? userConfigDirectory(options.userConfigDir) : repoConfigDirectory(repoRoot);
|
|
28293
28363
|
const format = options.format ?? "yaml";
|
|
28294
|
-
const filePath =
|
|
28364
|
+
const filePath = join20(dir, format === "json" ? "role-hosts.json" : "role-hosts.yaml");
|
|
28295
28365
|
if (options.dryRun) return { filePath, scope };
|
|
28296
28366
|
if (!existsSync18(dir)) {
|
|
28297
28367
|
mkdirSync14(dir, { recursive: true });
|
|
@@ -28542,7 +28612,7 @@ async function cmdRoleAdd(runtime, roleId, options) {
|
|
|
28542
28612
|
}
|
|
28543
28613
|
let roleDef;
|
|
28544
28614
|
if (options.file) {
|
|
28545
|
-
const filePath =
|
|
28615
|
+
const filePath = resolve15(runtime.cwd, options.file);
|
|
28546
28616
|
const content = readFileSync18(filePath, "utf8");
|
|
28547
28617
|
roleDef = (0, import_yaml10.parse)(content);
|
|
28548
28618
|
roleDef.id = roleId;
|
|
@@ -28872,7 +28942,7 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
28872
28942
|
return 1;
|
|
28873
28943
|
}
|
|
28874
28944
|
}
|
|
28875
|
-
const dbPath =
|
|
28945
|
+
const dbPath = join21(runtime.cwd, ".kxm", "state", "kxm.db");
|
|
28876
28946
|
if (existsSync19(dbPath)) {
|
|
28877
28947
|
try {
|
|
28878
28948
|
const database = runtime.dryRun ? openReadOnlyDatabase(dbPath) : new DatabaseSync(dbPath);
|
|
@@ -28899,7 +28969,7 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
28899
28969
|
JSON.stringify(resumeResult.run),
|
|
28900
28970
|
runId
|
|
28901
28971
|
);
|
|
28902
|
-
const journalId =
|
|
28972
|
+
const journalId = randomUUID5();
|
|
28903
28973
|
const journalPayload = {
|
|
28904
28974
|
id: journalId,
|
|
28905
28975
|
runId,
|
|
@@ -28944,13 +29014,13 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
28944
29014
|
|
|
28945
29015
|
// plugins/kxm/src/cli/workflows.ts
|
|
28946
29016
|
var import_yaml12 = __toESM(require_dist(), 1);
|
|
28947
|
-
import { randomUUID as
|
|
29017
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
28948
29018
|
import { existsSync as existsSync21, readFileSync as readFileSync20 } from "node:fs";
|
|
28949
|
-
import { join as
|
|
29019
|
+
import { join as join23, resolve as resolve18 } from "node:path";
|
|
28950
29020
|
|
|
28951
29021
|
// plugins/kxm/src/retrospective.ts
|
|
28952
29022
|
import { mkdirSync as mkdirSync15, renameSync as renameSync6, writeFileSync as writeFileSync15 } from "node:fs";
|
|
28953
|
-
import { resolve as
|
|
29023
|
+
import { resolve as resolve16 } from "node:path";
|
|
28954
29024
|
var MAX_RETROSPECTIVE_ENTRIES = 500;
|
|
28955
29025
|
var SAFE_RUN_ID = /^run_[A-Za-z0-9_-]{1,120}$/;
|
|
28956
29026
|
function durationMs(startedAt, completedAt) {
|
|
@@ -29169,9 +29239,9 @@ function renderRetrospectiveMarkdown(doc) {
|
|
|
29169
29239
|
function writeRetrospective(outDir, doc) {
|
|
29170
29240
|
if (!SAFE_RUN_ID.test(doc.runId)) throw new Error("invalid retrospective run id");
|
|
29171
29241
|
mkdirSync15(outDir, { recursive: true });
|
|
29172
|
-
const root =
|
|
29173
|
-
const jsonPath =
|
|
29174
|
-
const mdPath =
|
|
29242
|
+
const root = resolve16(outDir);
|
|
29243
|
+
const jsonPath = resolve16(root, `${doc.runId}.json`);
|
|
29244
|
+
const mdPath = resolve16(root, `${doc.runId}.md`);
|
|
29175
29245
|
const prefix = `${root}${process.platform === "win32" ? "\\" : "/"}`;
|
|
29176
29246
|
if (!jsonPath.startsWith(prefix) || !mdPath.startsWith(prefix)) throw new Error("retrospective path escaped output directory");
|
|
29177
29247
|
const jsonTmp = `${jsonPath}.tmp`;
|
|
@@ -29185,7 +29255,7 @@ function writeRetrospective(outDir, doc) {
|
|
|
29185
29255
|
}
|
|
29186
29256
|
|
|
29187
29257
|
// plugins/kxm/src/github-watch.ts
|
|
29188
|
-
import { randomUUID as
|
|
29258
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
29189
29259
|
async function fetchWithTimeout(fetchImpl, input, init, timeoutMs) {
|
|
29190
29260
|
const controller = new AbortController();
|
|
29191
29261
|
const timer = setTimeout(() => controller.abort(), Math.max(1, timeoutMs));
|
|
@@ -29274,7 +29344,7 @@ async function watchGithubChecks(input) {
|
|
|
29274
29344
|
}
|
|
29275
29345
|
const fetchImpl = input.fetchImpl ?? fetch;
|
|
29276
29346
|
const now = input.now ?? Date.now;
|
|
29277
|
-
const sleep = input.sleep ?? ((ms) => new Promise((
|
|
29347
|
+
const sleep = input.sleep ?? ((ms) => new Promise((resolve35) => setTimeout(resolve35, ms)));
|
|
29278
29348
|
const deadline = now() + input.timeoutMs;
|
|
29279
29349
|
const headers = {
|
|
29280
29350
|
authorization: `Bearer ${token}`,
|
|
@@ -29287,7 +29357,7 @@ async function watchGithubChecks(input) {
|
|
|
29287
29357
|
"workflow.signal": input.signalKey
|
|
29288
29358
|
};
|
|
29289
29359
|
const explicitDeliveryId = input.deliveryId?.trim();
|
|
29290
|
-
const deliveryGeneration =
|
|
29360
|
+
const deliveryGeneration = randomUUID6();
|
|
29291
29361
|
let deliveryId = explicitDeliveryId || `github-watch:${deliveryGeneration}:pr-${input.pr}`;
|
|
29292
29362
|
const deliver = async (status, summary, evidence) => {
|
|
29293
29363
|
const boundedEvidence = Object.fromEntries(Object.entries({ ...contextEvidence, ...evidence }).slice(0, 64));
|
|
@@ -29374,7 +29444,7 @@ async function watchGithubChecks(input) {
|
|
|
29374
29444
|
// plugins/kxm/src/workflow-manager.ts
|
|
29375
29445
|
var import_yaml11 = __toESM(require_dist(), 1);
|
|
29376
29446
|
import { existsSync as existsSync20, mkdirSync as mkdirSync16, readdirSync as readdirSync7, readFileSync as readFileSync19, rmSync as rmSync7, writeFileSync as writeFileSync16 } from "node:fs";
|
|
29377
|
-
import { join as
|
|
29447
|
+
import { join as join22 } from "node:path";
|
|
29378
29448
|
var completed = () => ({ target: "$terminal", terminalStatus: "completed" });
|
|
29379
29449
|
var failed = () => ({ target: "$terminal", terminalStatus: "failed" });
|
|
29380
29450
|
function verifyStep(retryStep) {
|
|
@@ -29511,9 +29581,9 @@ function scaffoldWorkflowDefinition(description) {
|
|
|
29511
29581
|
var DEFAULT_WORKFLOW_TEMPLATE = WORKFLOW_TEMPLATES["implement-and-verify"];
|
|
29512
29582
|
function workflowsDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
29513
29583
|
if (scope === "global") {
|
|
29514
|
-
return
|
|
29584
|
+
return join22(userConfigDirectory(userConfigDir), "workflows");
|
|
29515
29585
|
}
|
|
29516
|
-
return
|
|
29586
|
+
return join22(repoConfigDirectory(repoRoot), "workflows");
|
|
29517
29587
|
}
|
|
29518
29588
|
function ensureWorkflowsDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
29519
29589
|
const dir = workflowsDirectory(scope, repoRoot, userConfigDir);
|
|
@@ -29542,7 +29612,7 @@ function listWorkflowDefinitions(options = {}) {
|
|
|
29542
29612
|
if (scopeFilter !== "global" && existsSync20(localDir)) {
|
|
29543
29613
|
for (const entry of readdirSync7(localDir)) {
|
|
29544
29614
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
29545
|
-
const filePath =
|
|
29615
|
+
const filePath = join22(localDir, entry);
|
|
29546
29616
|
const def = parseWorkflowFile(filePath);
|
|
29547
29617
|
if (def) {
|
|
29548
29618
|
const id = def.id || entry.replace(/\.ya?ml$/i, "");
|
|
@@ -29555,7 +29625,7 @@ function listWorkflowDefinitions(options = {}) {
|
|
|
29555
29625
|
if (scopeFilter !== "local" && existsSync20(globalDir)) {
|
|
29556
29626
|
for (const entry of readdirSync7(globalDir)) {
|
|
29557
29627
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
29558
|
-
const filePath =
|
|
29628
|
+
const filePath = join22(globalDir, entry);
|
|
29559
29629
|
const def = parseWorkflowFile(filePath);
|
|
29560
29630
|
if (def) {
|
|
29561
29631
|
const id = def.id || entry.replace(/\.ya?ml$/i, "");
|
|
@@ -29611,13 +29681,13 @@ function getWorkflowDefinition(workflowId, options = {}) {
|
|
|
29611
29681
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
29612
29682
|
if (scope !== "global") {
|
|
29613
29683
|
const localDir = workflowsDirectory("local", repoRoot, options.userConfigDir);
|
|
29614
|
-
const localFile =
|
|
29684
|
+
const localFile = join22(localDir, `${workflowId}.yaml`);
|
|
29615
29685
|
const parsed = parseWorkflowFile(localFile);
|
|
29616
29686
|
if (parsed) return { workflow: parsed, scope: "local", filePath: localFile };
|
|
29617
29687
|
}
|
|
29618
29688
|
if (scope !== "local") {
|
|
29619
29689
|
const globalDir = workflowsDirectory("global", repoRoot, options.userConfigDir);
|
|
29620
|
-
const globalFile =
|
|
29690
|
+
const globalFile = join22(globalDir, `${workflowId}.yaml`);
|
|
29621
29691
|
const parsed = parseWorkflowFile(globalFile);
|
|
29622
29692
|
if (parsed) return { workflow: parsed, scope: "global", filePath: globalFile };
|
|
29623
29693
|
}
|
|
@@ -29627,7 +29697,7 @@ function addWorkflowDefinition(workflowId, content = DEFAULT_WORKFLOW_TEMPLATE,
|
|
|
29627
29697
|
const scope = options.scope ?? "local";
|
|
29628
29698
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
29629
29699
|
const dir = options.dryRun ? workflowsDirectory(scope, repoRoot, options.userConfigDir) : ensureWorkflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
29630
|
-
const filePath =
|
|
29700
|
+
const filePath = join22(dir, `${workflowId}.yaml`);
|
|
29631
29701
|
if (existsSync20(filePath) && !options.overwrite) {
|
|
29632
29702
|
throw new Error(`workflow_already_exists: workflow '${workflowId}' already exists at ${filePath}`);
|
|
29633
29703
|
}
|
|
@@ -29639,7 +29709,7 @@ function removeWorkflowDefinition(workflowId, options = {}) {
|
|
|
29639
29709
|
const scope = options.scope ?? "local";
|
|
29640
29710
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
29641
29711
|
const dir = workflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
29642
|
-
const filePath =
|
|
29712
|
+
const filePath = join22(dir, `${workflowId}.yaml`);
|
|
29643
29713
|
if (!existsSync20(filePath)) {
|
|
29644
29714
|
throw new Error(`workflow_not_found: workflow '${workflowId}' not found in ${scope} directory (${filePath})`);
|
|
29645
29715
|
}
|
|
@@ -29659,7 +29729,7 @@ function modifyWorkflowDefinition(workflowId, updates, options = {}) {
|
|
|
29659
29729
|
const scope = options.scope ?? target.scope;
|
|
29660
29730
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
29661
29731
|
const dir = options.dryRun ? workflowsDirectory(scope, repoRoot, options.userConfigDir) : ensureWorkflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
29662
|
-
const filePath =
|
|
29732
|
+
const filePath = join22(dir, `${workflowId}.yaml`);
|
|
29663
29733
|
if (!options.dryRun) writeFileSync16(filePath, (0, import_yaml11.stringify)(updated), "utf8");
|
|
29664
29734
|
return { id: workflowId, workflow: updated, filePath, scope };
|
|
29665
29735
|
}
|
|
@@ -29747,7 +29817,7 @@ function activeWorkflowDefinition(runtime, definitionId) {
|
|
|
29747
29817
|
let raw;
|
|
29748
29818
|
if (file) {
|
|
29749
29819
|
try {
|
|
29750
|
-
raw = readFileSync20(
|
|
29820
|
+
raw = readFileSync20(resolve18(runtime.cwd, file), "utf8");
|
|
29751
29821
|
} catch {
|
|
29752
29822
|
throw new Error("workflow definition file is unavailable");
|
|
29753
29823
|
}
|
|
@@ -29843,7 +29913,7 @@ async function cmdWorkflowAdd(runtime, workflowId, options) {
|
|
|
29843
29913
|
}
|
|
29844
29914
|
}
|
|
29845
29915
|
if (options.file) {
|
|
29846
|
-
const filePath =
|
|
29916
|
+
const filePath = resolve18(runtime.cwd, options.file);
|
|
29847
29917
|
content = readFileSync20(filePath, "utf8");
|
|
29848
29918
|
} else if (!content) {
|
|
29849
29919
|
content = scaffoldWorkflowDefinition(options.description || `Workflow ${workflowId}`);
|
|
@@ -30004,7 +30074,7 @@ async function cmdWorkflowModify(runtime, workflowId, options) {
|
|
|
30004
30074
|
}
|
|
30005
30075
|
async function cmdWorkflowStart(runtime, definitionIdArg, options) {
|
|
30006
30076
|
const definitionId = definitionIdArg || runtime.env.KXM_WORKFLOW_ID?.trim();
|
|
30007
|
-
const deliveryId = String(options.deliveryId || `cli-${
|
|
30077
|
+
const deliveryId = String(options.deliveryId || `cli-${randomUUID7()}`);
|
|
30008
30078
|
const event = options.event;
|
|
30009
30079
|
const payloadFlag = options.payload ?? "{}";
|
|
30010
30080
|
if (!definitionId) {
|
|
@@ -30023,7 +30093,7 @@ async function cmdWorkflowStart(runtime, definitionIdArg, options) {
|
|
|
30023
30093
|
}
|
|
30024
30094
|
let payload;
|
|
30025
30095
|
try {
|
|
30026
|
-
const raw = payloadFlag.startsWith("@") ? readFileSync20(
|
|
30096
|
+
const raw = payloadFlag.startsWith("@") ? readFileSync20(resolve18(runtime.cwd, payloadFlag.slice(1)), "utf8") : payloadFlag;
|
|
30027
30097
|
const value = JSON.parse(raw);
|
|
30028
30098
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("object required");
|
|
30029
30099
|
payload = value;
|
|
@@ -30090,7 +30160,7 @@ async function cmdWorkflowDegrade(runtime, runId, stageId, options) {
|
|
|
30090
30160
|
}
|
|
30091
30161
|
}
|
|
30092
30162
|
async function cmdWorkflowInspect(runtime, action, runId) {
|
|
30093
|
-
const dataPath =
|
|
30163
|
+
const dataPath = resolve18(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join23(runtime.dirs.state, "kxm.db"));
|
|
30094
30164
|
if (action === "get" && !runId) {
|
|
30095
30165
|
runtime.io.stderr(`Usage: ${CLI_NAME} workflow get <runId>
|
|
30096
30166
|
`);
|
|
@@ -30135,7 +30205,7 @@ async function cmdSignal(runtime, runId, signalKey, status, summary, evidenceArg
|
|
|
30135
30205
|
printWorker(runtime, worker, { ok: true, command: "signal", dryRun: true, runId, signalKey, status, summary, evidence }, "would post signal to KXM run");
|
|
30136
30206
|
return 0;
|
|
30137
30207
|
}
|
|
30138
|
-
const deliveryId2 = String(deliveryIdFlag || `cli-signal:${
|
|
30208
|
+
const deliveryId2 = String(deliveryIdFlag || `cli-signal:${randomUUID7()}`);
|
|
30139
30209
|
try {
|
|
30140
30210
|
const supervisor = await ensureKxmSupervisor({ env: runtime.env });
|
|
30141
30211
|
const posted = await kxmRuntimeRequest(
|
|
@@ -30171,7 +30241,7 @@ async function cmdSignal(runtime, runId, signalKey, status, summary, evidenceArg
|
|
|
30171
30241
|
printWorker(runtime, worker, { ok: true, command: "signal", dryRun: true, runId, signalKey, status, summary, evidence }, "would post signed signal");
|
|
30172
30242
|
return 0;
|
|
30173
30243
|
}
|
|
30174
|
-
const deliveryId = String(deliveryIdFlag || `cli-signal:${
|
|
30244
|
+
const deliveryId = String(deliveryIdFlag || `cli-signal:${randomUUID7()}`);
|
|
30175
30245
|
try {
|
|
30176
30246
|
const posted = await postWorkflowSignal({
|
|
30177
30247
|
serverUrl: runtime.serverUrl,
|
|
@@ -30259,14 +30329,14 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
30259
30329
|
return 2;
|
|
30260
30330
|
}
|
|
30261
30331
|
const snapshotFlag = String(options.input || "");
|
|
30262
|
-
const snapshotPath = snapshotFlag ?
|
|
30332
|
+
const snapshotPath = snapshotFlag ? resolve18(runtime.cwd, snapshotFlag) : "";
|
|
30263
30333
|
let snapshot;
|
|
30264
30334
|
try {
|
|
30265
30335
|
if (snapshotPath) {
|
|
30266
30336
|
if (!existsSync21(snapshotPath)) throw new Error("snapshot_missing");
|
|
30267
30337
|
snapshot = JSON.parse(readFileSync20(snapshotPath, "utf8"));
|
|
30268
30338
|
} else {
|
|
30269
|
-
const dataPath =
|
|
30339
|
+
const dataPath = resolve18(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join23(runtime.dirs.state, "kxm.db"));
|
|
30270
30340
|
const local = localWorkflowSnapshot(dataPath, runId);
|
|
30271
30341
|
if (!local.runs[0]) throw new Error("workflow_not_found");
|
|
30272
30342
|
snapshot = { run: local.runs[0], journal: local.journal };
|
|
@@ -30278,8 +30348,8 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
30278
30348
|
return 1;
|
|
30279
30349
|
}
|
|
30280
30350
|
const doc = buildRetrospective(snapshot.run, snapshot.journal);
|
|
30281
|
-
const outDir =
|
|
30282
|
-
const assetsRoot =
|
|
30351
|
+
const outDir = resolve18(runtime.cwd, String(options.outDir || join23(runtime.dirs.assets, "retrospectives")));
|
|
30352
|
+
const assetsRoot = resolve18(runtime.dirs.assets);
|
|
30283
30353
|
const assetsPrefix = `${assetsRoot}${process.platform === "win32" ? "\\" : "/"}`;
|
|
30284
30354
|
if (outDir !== assetsRoot && !outDir.startsWith(assetsPrefix)) {
|
|
30285
30355
|
print(runtime.io, runtime.json, { ok: false, command: "retrospective export", error: "output_outside_workspace_assets" }, "retrospectives must stay under the workspace assets directory");
|
|
@@ -30296,8 +30366,8 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
30296
30366
|
|
|
30297
30367
|
// plugins/kxm/src/cli/tasks.ts
|
|
30298
30368
|
var import_yaml15 = __toESM(require_dist(), 1);
|
|
30299
|
-
import { existsSync as existsSync27, readFileSync as
|
|
30300
|
-
import { basename as basename7, join as
|
|
30369
|
+
import { existsSync as existsSync27, readFileSync as readFileSync26, readdirSync as readdirSync10 } from "node:fs";
|
|
30370
|
+
import { basename as basename7, join as join31, resolve as resolve24 } from "node:path";
|
|
30301
30371
|
|
|
30302
30372
|
// plugins/kxm/src/suggest.ts
|
|
30303
30373
|
var WORKFLOW_PATTERNS = [
|
|
@@ -30407,25 +30477,25 @@ function suggestWorkflowAndRoles(prompt, options = {}) {
|
|
|
30407
30477
|
|
|
30408
30478
|
// plugins/kxm/src/task-manager.ts
|
|
30409
30479
|
var import_yaml13 = __toESM(require_dist(), 1);
|
|
30410
|
-
import { randomUUID as
|
|
30480
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
30411
30481
|
import { existsSync as existsSync22, mkdirSync as mkdirSync17, readFileSync as readFileSync21, readdirSync as readdirSync8, writeFileSync as writeFileSync17 } from "node:fs";
|
|
30412
|
-
import { join as
|
|
30482
|
+
import { join as join24, resolve as resolve19 } from "node:path";
|
|
30413
30483
|
var GOAL_SCHEMA = "kxm.goal.v1";
|
|
30414
30484
|
var TASK_SCHEMA = "kxm.task.v1";
|
|
30415
30485
|
function goalsDirectory(repoRoot) {
|
|
30416
|
-
return
|
|
30486
|
+
return resolve19(repoRoot, ".kxm", "goals");
|
|
30417
30487
|
}
|
|
30418
30488
|
function tasksDirectory(repoRoot) {
|
|
30419
|
-
return
|
|
30489
|
+
return resolve19(repoRoot, ".kxm", "tasks");
|
|
30420
30490
|
}
|
|
30421
30491
|
function goalFilePath(repoRoot, goalId) {
|
|
30422
|
-
return
|
|
30492
|
+
return join24(goalsDirectory(repoRoot), `${goalId}.yaml`);
|
|
30423
30493
|
}
|
|
30424
30494
|
function taskFilePath(repoRoot, taskId) {
|
|
30425
|
-
return
|
|
30495
|
+
return join24(tasksDirectory(repoRoot), `${taskId}.yaml`);
|
|
30426
30496
|
}
|
|
30427
30497
|
function createGoal(repoRoot, input, options = {}) {
|
|
30428
|
-
const id = `goal_${
|
|
30498
|
+
const id = `goal_${randomUUID8().replaceAll("-", "").slice(0, 12)}`;
|
|
30429
30499
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
30430
30500
|
const record = {
|
|
30431
30501
|
schema: GOAL_SCHEMA,
|
|
@@ -30451,7 +30521,7 @@ function listGoals(repoRoot) {
|
|
|
30451
30521
|
for (const entry of entries) {
|
|
30452
30522
|
if (entry.isFile() && (entry.name.endsWith(".yaml") || entry.name.endsWith(".yml"))) {
|
|
30453
30523
|
try {
|
|
30454
|
-
const text = readFileSync21(
|
|
30524
|
+
const text = readFileSync21(join24(dir, entry.name), "utf8");
|
|
30455
30525
|
const doc = (0, import_yaml13.parse)(text);
|
|
30456
30526
|
if (doc && doc.schema === GOAL_SCHEMA) goals.push(doc);
|
|
30457
30527
|
} catch {
|
|
@@ -30461,7 +30531,7 @@ function listGoals(repoRoot) {
|
|
|
30461
30531
|
return goals.sort((a, b2) => a.createdAt.localeCompare(b2.createdAt));
|
|
30462
30532
|
}
|
|
30463
30533
|
function createTask(repoRoot, input, options = {}) {
|
|
30464
|
-
const id = `task_${
|
|
30534
|
+
const id = `task_${randomUUID8().replaceAll("-", "").slice(0, 12)}`;
|
|
30465
30535
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
30466
30536
|
const record = {
|
|
30467
30537
|
schema: TASK_SCHEMA,
|
|
@@ -30495,7 +30565,7 @@ function listTasks(repoRoot, options = {}) {
|
|
|
30495
30565
|
for (const entry of entries) {
|
|
30496
30566
|
if (entry.isFile() && (entry.name.endsWith(".yaml") || entry.name.endsWith(".yml"))) {
|
|
30497
30567
|
try {
|
|
30498
|
-
const text = readFileSync21(
|
|
30568
|
+
const text = readFileSync21(join24(dir, entry.name), "utf8");
|
|
30499
30569
|
const doc = (0, import_yaml13.parse)(text);
|
|
30500
30570
|
if (doc && doc.schema === TASK_SCHEMA) {
|
|
30501
30571
|
if (options.goalId && doc.goalId !== options.goalId) continue;
|
|
@@ -30510,7 +30580,7 @@ function listTasks(repoRoot, options = {}) {
|
|
|
30510
30580
|
}
|
|
30511
30581
|
function getTask(repoRoot, taskId) {
|
|
30512
30582
|
const dir = tasksDirectory(repoRoot);
|
|
30513
|
-
const filePath =
|
|
30583
|
+
const filePath = join24(dir, `${taskId}.yaml`);
|
|
30514
30584
|
if (!existsSync22(filePath)) return void 0;
|
|
30515
30585
|
try {
|
|
30516
30586
|
const text = readFileSync21(filePath, "utf8");
|
|
@@ -30549,7 +30619,7 @@ function syncTaskWithTracker(repoRoot, taskId, options = {}) {
|
|
|
30549
30619
|
|
|
30550
30620
|
// plugins/kxm/src/studio-layout.ts
|
|
30551
30621
|
import { createServer } from "node:http";
|
|
30552
|
-
import { randomUUID as
|
|
30622
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
30553
30623
|
var STUDIO_LAYOUT_SCHEMA = "kxm.studio-layout.v1";
|
|
30554
30624
|
function generateStudioLayout(plan, state) {
|
|
30555
30625
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -30812,7 +30882,7 @@ function createStudioServer(options = {}) {
|
|
|
30812
30882
|
}));
|
|
30813
30883
|
return;
|
|
30814
30884
|
}
|
|
30815
|
-
const mutationId = `mut_${
|
|
30885
|
+
const mutationId = `mut_${randomUUID9().replaceAll("-", "").slice(0, 12)}`;
|
|
30816
30886
|
if (options.onMutation) {
|
|
30817
30887
|
try {
|
|
30818
30888
|
const outcome = await options.onMutation(command, args);
|
|
@@ -31311,13 +31381,42 @@ function createStudioServer(options = {}) {
|
|
|
31311
31381
|
|
|
31312
31382
|
// plugins/kxm/src/cli/project.ts
|
|
31313
31383
|
import { existsSync as existsSync26 } from "node:fs";
|
|
31314
|
-
import { join as
|
|
31384
|
+
import { dirname as dirname18, join as join30, resolve as resolve23 } from "node:path";
|
|
31315
31385
|
import { createInterface as createInterface2 } from "node:readline";
|
|
31316
31386
|
|
|
31387
|
+
// plugins/kxm/src/hub-autostart.ts
|
|
31388
|
+
import { closeSync as closeSync2, mkdirSync as mkdirSync18, openSync as openSync2, readFileSync as readFileSync22 } from "node:fs";
|
|
31389
|
+
import { join as join25, resolve as resolve20 } from "node:path";
|
|
31390
|
+
function defaultProcessExists(pid) {
|
|
31391
|
+
try {
|
|
31392
|
+
process.kill(pid, 0);
|
|
31393
|
+
return true;
|
|
31394
|
+
} catch (error) {
|
|
31395
|
+
return error.code === "EPERM";
|
|
31396
|
+
}
|
|
31397
|
+
}
|
|
31398
|
+
function readLiveHubClaim(stateDir, processExists3 = defaultProcessExists) {
|
|
31399
|
+
let parsed;
|
|
31400
|
+
try {
|
|
31401
|
+
parsed = JSON.parse(readFileSync22(join25(stateDir, "hub.pid"), "utf8"));
|
|
31402
|
+
} catch {
|
|
31403
|
+
return void 0;
|
|
31404
|
+
}
|
|
31405
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
31406
|
+
const record = parsed;
|
|
31407
|
+
if (record.version !== 1 || record.role !== "hub" || !Number.isInteger(record.pid)) return void 0;
|
|
31408
|
+
const pid = record.pid;
|
|
31409
|
+
if (pid <= 0 || !processExists3(pid)) return void 0;
|
|
31410
|
+
return {
|
|
31411
|
+
pid,
|
|
31412
|
+
...Number.isInteger(record.serverPid) && record.serverPid > 0 ? { serverPid: record.serverPid } : { serverPid: void 0 }
|
|
31413
|
+
};
|
|
31414
|
+
}
|
|
31415
|
+
|
|
31317
31416
|
// plugins/kxm/src/model-inventory.ts
|
|
31318
31417
|
var import_yaml14 = __toESM(require_dist(), 1);
|
|
31319
|
-
import { mkdirSync as
|
|
31320
|
-
import { join as
|
|
31418
|
+
import { mkdirSync as mkdirSync19, writeFileSync as writeFileSync18 } from "node:fs";
|
|
31419
|
+
import { join as join26 } from "node:path";
|
|
31321
31420
|
var OR_URL = "https://openrouter.ai/api/v1/models";
|
|
31322
31421
|
var NOUS_URL = "https://inference-api.nousresearch.com/v1/models";
|
|
31323
31422
|
function price(value) {
|
|
@@ -31403,41 +31502,41 @@ async function refreshModelInventory(options) {
|
|
|
31403
31502
|
sources.nous = { url: nousUrl, ok: !nous.error, ...nous.error ? { error: nous.error } : {} };
|
|
31404
31503
|
for (const item of nous.data) add(item, "nous", "discount");
|
|
31405
31504
|
const inventory = { schema: "kxm.model-inventory.v1", fetchedAt, currency: "USD", sources, models: [...byId.values()].sort((a, b2) => a.id.localeCompare(b2.id)) };
|
|
31406
|
-
|
|
31407
|
-
writeFileSync18(
|
|
31505
|
+
mkdirSync19(join26(options.outputRoot, ".kxm", "models"), { recursive: true });
|
|
31506
|
+
writeFileSync18(join26(options.outputRoot, ".kxm", "models", "inventory.yaml"), (0, import_yaml14.stringify)(inventory), "utf8");
|
|
31408
31507
|
return inventory;
|
|
31409
31508
|
}
|
|
31410
31509
|
|
|
31411
31510
|
// plugins/kxm/src/init.ts
|
|
31412
|
-
import { randomUUID as
|
|
31511
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
31413
31512
|
import { existsSync as existsSync25 } from "node:fs";
|
|
31414
|
-
import { basename as basename6, join as
|
|
31513
|
+
import { basename as basename6, join as join29 } from "node:path";
|
|
31415
31514
|
|
|
31416
31515
|
// plugins/kxm/src/repair.ts
|
|
31417
|
-
import { randomUUID as
|
|
31516
|
+
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
31418
31517
|
import {
|
|
31419
31518
|
chmodSync as chmodSync5,
|
|
31420
|
-
closeSync as
|
|
31519
|
+
closeSync as closeSync3,
|
|
31421
31520
|
existsSync as existsSync24,
|
|
31422
31521
|
fsyncSync as fsyncSync2,
|
|
31423
31522
|
linkSync,
|
|
31424
31523
|
lstatSync as lstatSync7,
|
|
31425
|
-
mkdirSync as
|
|
31426
|
-
openSync as
|
|
31427
|
-
readFileSync as
|
|
31524
|
+
mkdirSync as mkdirSync21,
|
|
31525
|
+
openSync as openSync3,
|
|
31526
|
+
readFileSync as readFileSync24,
|
|
31428
31527
|
readdirSync as readdirSync9,
|
|
31429
31528
|
renameSync as renameSync7,
|
|
31430
31529
|
rmSync as rmSync9,
|
|
31431
31530
|
writeFileSync as writeFileSync20
|
|
31432
31531
|
} from "node:fs";
|
|
31433
|
-
import { dirname as dirname17, isAbsolute as
|
|
31532
|
+
import { dirname as dirname17, isAbsolute as isAbsolute8, join as join28, relative as relative5, resolve as resolve22 } from "node:path";
|
|
31434
31533
|
|
|
31435
31534
|
// plugins/kxm/src/permission.ts
|
|
31436
31535
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
31437
31536
|
import { createHash as createHash14 } from "node:crypto";
|
|
31438
|
-
import { existsSync as existsSync23, mkdtempSync, mkdirSync as
|
|
31537
|
+
import { existsSync as existsSync23, mkdtempSync, mkdirSync as mkdirSync20, readFileSync as readFileSync23, rmSync as rmSync8, writeFileSync as writeFileSync19 } from "node:fs";
|
|
31439
31538
|
import { tmpdir } from "node:os";
|
|
31440
|
-
import { dirname as dirname16, join as
|
|
31539
|
+
import { dirname as dirname16, join as join27, resolve as resolve21, sep as sep4 } from "node:path";
|
|
31441
31540
|
var PROSE_FIELDS = {
|
|
31442
31541
|
project: /* @__PURE__ */ new Set(["name", "description"]),
|
|
31443
31542
|
repository: /* @__PURE__ */ new Set(["description"]),
|
|
@@ -31958,8 +32057,8 @@ function loadKxmProjectAtRevision(root, revision, options = {}) {
|
|
|
31958
32057
|
const tree = resolveTreeRevision(root, revision);
|
|
31959
32058
|
const listing = gitBuffer(root, ["ls-tree", "-r", "-z", "--name-only", tree]).toString("utf8");
|
|
31960
32059
|
const paths = listing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
31961
|
-
const shadow = mkdtempSync(
|
|
31962
|
-
const shadowResolved =
|
|
32060
|
+
const shadow = mkdtempSync(join27(tmpdir(), "kxm-permission-base-"));
|
|
32061
|
+
const shadowResolved = resolve21(shadow);
|
|
31963
32062
|
const shadowMembersDir = `.kxm-shadow-members-${createHash14("sha256").update(shadowResolved, "utf8").digest("hex").slice(0, 8)}`;
|
|
31964
32063
|
try {
|
|
31965
32064
|
for (const path4 of paths) {
|
|
@@ -31972,9 +32071,9 @@ function loadKxmProjectAtRevision(root, revision, options = {}) {
|
|
|
31972
32071
|
message: "Git tree entry contains a traversal or non-portable segment"
|
|
31973
32072
|
}]);
|
|
31974
32073
|
}
|
|
31975
|
-
const absolute =
|
|
31976
|
-
const resolved =
|
|
31977
|
-
if (!resolved.startsWith(`${shadowResolved}${
|
|
32074
|
+
const absolute = join27(shadowResolved, ...segments);
|
|
32075
|
+
const resolved = resolve21(absolute);
|
|
32076
|
+
if (!resolved.startsWith(`${shadowResolved}${sep4}`)) {
|
|
31978
32077
|
throw new KxmConfigError([{
|
|
31979
32078
|
phase: "path",
|
|
31980
32079
|
code: "git_tree_path_invalid",
|
|
@@ -31983,11 +32082,11 @@ function loadKxmProjectAtRevision(root, revision, options = {}) {
|
|
|
31983
32082
|
}]);
|
|
31984
32083
|
}
|
|
31985
32084
|
const content = gitBuffer(root, ["cat-file", "blob", `${tree}:${path4}`]);
|
|
31986
|
-
|
|
32085
|
+
mkdirSync20(dirname16(absolute), { recursive: true });
|
|
31987
32086
|
writeFileSync19(absolute, content);
|
|
31988
32087
|
}
|
|
31989
32088
|
initShadowGitRoot(shadowResolved);
|
|
31990
|
-
const baseProjectFile =
|
|
32089
|
+
const baseProjectFile = join27(shadowResolved, ".kxm", "project.yaml");
|
|
31991
32090
|
let baseProject;
|
|
31992
32091
|
try {
|
|
31993
32092
|
baseProject = loadBaseProjectDeclarations(baseProjectFile);
|
|
@@ -32017,7 +32116,7 @@ function loadKxmProjectAtRevision(root, revision, options = {}) {
|
|
|
32017
32116
|
}]);
|
|
32018
32117
|
}
|
|
32019
32118
|
const boundPath = options.repositoryBindings?.[member.repositoryId];
|
|
32020
|
-
const memberWorktree = boundPath ?
|
|
32119
|
+
const memberWorktree = boundPath ? resolve21(boundPath) : member.pathHint ? resolve21(root, ...member.pathHint.split("/")) : void 0;
|
|
32021
32120
|
if (!memberWorktree || !existsSync23(memberWorktree)) {
|
|
32022
32121
|
if (member.required === false) continue;
|
|
32023
32122
|
throw new KxmConfigError([{
|
|
@@ -32065,8 +32164,8 @@ function loadKxmProjectAtRevision(root, revision, options = {}) {
|
|
|
32065
32164
|
const memberTree = git(memberWorktree, ["rev-parse", "--verify", "--quiet", `${pinnedCommit}^{tree}`]).trim();
|
|
32066
32165
|
const memberListing = gitBuffer(memberWorktree, ["ls-tree", "-r", "-z", "--name-only", memberTree]).toString("utf8");
|
|
32067
32166
|
const memberPaths = memberListing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
32068
|
-
const memberShadowRoot =
|
|
32069
|
-
if (!
|
|
32167
|
+
const memberShadowRoot = join27(shadowResolved, shadowMembersDir, member.repositoryId);
|
|
32168
|
+
if (!resolve21(memberShadowRoot).startsWith(`${resolve21(shadowResolved, shadowMembersDir)}${sep4}`)) {
|
|
32070
32169
|
throw new KxmConfigError([{
|
|
32071
32170
|
phase: "path",
|
|
32072
32171
|
code: "git_tree_path_invalid",
|
|
@@ -32079,13 +32178,13 @@ function loadKxmProjectAtRevision(root, revision, options = {}) {
|
|
|
32079
32178
|
if (segments.some((segment) => segment === "" || segment === "." || segment === ".." || /[\\:]/.test(segment))) {
|
|
32080
32179
|
throw new KxmConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path4, message: "member Git tree entry contains a traversal or non-portable segment" }]);
|
|
32081
32180
|
}
|
|
32082
|
-
const absolute =
|
|
32083
|
-
const resolved =
|
|
32084
|
-
if (!resolved.startsWith(`${
|
|
32181
|
+
const absolute = join27(memberShadowRoot, ...segments);
|
|
32182
|
+
const resolved = resolve21(absolute);
|
|
32183
|
+
if (!resolved.startsWith(`${resolve21(memberShadowRoot)}${sep4}`)) {
|
|
32085
32184
|
throw new KxmConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path4, message: "member Git tree entry escapes the shadow root" }]);
|
|
32086
32185
|
}
|
|
32087
32186
|
const content = gitBuffer(memberWorktree, ["cat-file", "blob", `${memberTree}:${path4}`]);
|
|
32088
|
-
|
|
32187
|
+
mkdirSync20(dirname16(absolute), { recursive: true });
|
|
32089
32188
|
writeFileSync19(absolute, content);
|
|
32090
32189
|
}
|
|
32091
32190
|
initShadowGitRoot(memberShadowRoot);
|
|
@@ -32108,7 +32207,7 @@ function portableMemberPathHint(pathHint) {
|
|
|
32108
32207
|
}
|
|
32109
32208
|
function loadBaseProjectDeclarations(projectFile) {
|
|
32110
32209
|
if (!existsSync23(projectFile)) return [];
|
|
32111
|
-
const value = parseRestrictedYaml2(
|
|
32210
|
+
const value = parseRestrictedYaml2(readFileSync23(projectFile, "utf8"), ".kxm/project.yaml");
|
|
32112
32211
|
const repositories = Array.isArray(value?.repositories) ? value.repositories : [];
|
|
32113
32212
|
const members = [];
|
|
32114
32213
|
for (const entry of repositories) {
|
|
@@ -32187,83 +32286,83 @@ function fail3(code, file, message, phase = "semantic") {
|
|
|
32187
32286
|
function syncDirectory2(path4) {
|
|
32188
32287
|
let descriptor;
|
|
32189
32288
|
try {
|
|
32190
|
-
descriptor =
|
|
32289
|
+
descriptor = openSync3(path4, "r");
|
|
32191
32290
|
fsyncSync2(descriptor);
|
|
32192
32291
|
} catch (error) {
|
|
32193
32292
|
const code = error.code;
|
|
32194
32293
|
if (process.platform !== "win32" && code !== "EINVAL" && code !== "ENOTSUP" && code !== "EISDIR") throw error;
|
|
32195
32294
|
} finally {
|
|
32196
|
-
if (descriptor !== void 0)
|
|
32295
|
+
if (descriptor !== void 0) closeSync3(descriptor);
|
|
32197
32296
|
}
|
|
32198
32297
|
}
|
|
32199
32298
|
function writeDurableNew(file, bytes, mode) {
|
|
32200
32299
|
let descriptor;
|
|
32201
32300
|
try {
|
|
32202
|
-
descriptor =
|
|
32301
|
+
descriptor = openSync3(file, "wx", mode);
|
|
32203
32302
|
writeFileSync20(descriptor, bytes);
|
|
32204
32303
|
fsyncSync2(descriptor);
|
|
32205
|
-
|
|
32304
|
+
closeSync3(descriptor);
|
|
32206
32305
|
descriptor = void 0;
|
|
32207
32306
|
try {
|
|
32208
32307
|
chmodSync5(file, mode);
|
|
32209
32308
|
} catch {
|
|
32210
32309
|
}
|
|
32211
32310
|
} finally {
|
|
32212
|
-
if (descriptor !== void 0)
|
|
32311
|
+
if (descriptor !== void 0) closeSync3(descriptor);
|
|
32213
32312
|
}
|
|
32214
32313
|
syncDirectory2(dirname17(file));
|
|
32215
32314
|
}
|
|
32216
32315
|
function writeDurable(file, bytes, mode) {
|
|
32217
32316
|
let descriptor;
|
|
32218
32317
|
try {
|
|
32219
|
-
descriptor =
|
|
32318
|
+
descriptor = openSync3(file, "w", mode);
|
|
32220
32319
|
writeFileSync20(descriptor, bytes);
|
|
32221
32320
|
fsyncSync2(descriptor);
|
|
32222
|
-
|
|
32321
|
+
closeSync3(descriptor);
|
|
32223
32322
|
descriptor = void 0;
|
|
32224
32323
|
try {
|
|
32225
32324
|
chmodSync5(file, mode);
|
|
32226
32325
|
} catch {
|
|
32227
32326
|
}
|
|
32228
32327
|
} finally {
|
|
32229
|
-
if (descriptor !== void 0)
|
|
32328
|
+
if (descriptor !== void 0) closeSync3(descriptor);
|
|
32230
32329
|
}
|
|
32231
32330
|
syncDirectory2(dirname17(file));
|
|
32232
32331
|
}
|
|
32233
32332
|
function sameHostPath3(left, right) {
|
|
32234
|
-
const first =
|
|
32235
|
-
const second =
|
|
32333
|
+
const first = resolve22(left);
|
|
32334
|
+
const second = resolve22(right);
|
|
32236
32335
|
return process.platform === "win32" ? first.toLocaleLowerCase("en-US") === second.toLocaleLowerCase("en-US") : first === second;
|
|
32237
32336
|
}
|
|
32238
32337
|
function transactionRoot(projectRoot) {
|
|
32239
|
-
return
|
|
32338
|
+
return join28(resolve22(projectRoot), TRANSACTION_NAME);
|
|
32240
32339
|
}
|
|
32241
32340
|
function operationFile(projectRoot) {
|
|
32242
|
-
return
|
|
32341
|
+
return join28(transactionRoot(projectRoot), OPERATION_FILE);
|
|
32243
32342
|
}
|
|
32244
32343
|
function targetFile(projectRoot, portablePath2) {
|
|
32245
|
-
return
|
|
32344
|
+
return join28(transactionRoot(projectRoot), "targets", ...portablePath2.split("/"));
|
|
32246
32345
|
}
|
|
32247
32346
|
function shadowRoot(projectRoot) {
|
|
32248
|
-
return
|
|
32347
|
+
return join28(transactionRoot(projectRoot), "shadow");
|
|
32249
32348
|
}
|
|
32250
32349
|
function backupFile(projectRoot, portablePath2) {
|
|
32251
|
-
return
|
|
32350
|
+
return join28(transactionRoot(projectRoot), "backups", ...portablePath2.split("/"));
|
|
32252
32351
|
}
|
|
32253
32352
|
function portableManagedPath(path4) {
|
|
32254
|
-
return path4.startsWith(".kxm/") && path4 !== KXM_TEMPLATE_PROVENANCE_PATH && path4.length <= 1024 && !path4.includes("\\") && !
|
|
32353
|
+
return path4.startsWith(".kxm/") && path4 !== KXM_TEMPLATE_PROVENANCE_PATH && path4.length <= 1024 && !path4.includes("\\") && !isAbsolute8(path4) && PORTABLE_PATH.test(path4) && !/[<>:"|?*]/.test(path4);
|
|
32255
32354
|
}
|
|
32256
32355
|
function readRegularBounded(file, label) {
|
|
32257
32356
|
const stat = lstatSync7(file);
|
|
32258
32357
|
if (stat.isSymbolicLink() || !stat.isFile()) fail3("repair_file_invalid", label, "managed file must be a regular file, not a link or directory", "path");
|
|
32259
32358
|
if (stat.size > MAX_MANAGED_FILE_BYTES) fail3("repair_file_too_large", label, `managed file exceeds ${MAX_MANAGED_FILE_BYTES} bytes`, "parse");
|
|
32260
|
-
return
|
|
32359
|
+
return readFileSync24(file);
|
|
32261
32360
|
}
|
|
32262
32361
|
function readOptionalManaged(projectRoot, path4) {
|
|
32263
|
-
const file =
|
|
32362
|
+
const file = join28(projectRoot, ...path4.split("/"));
|
|
32264
32363
|
if (!existsSync24(file)) return void 0;
|
|
32265
32364
|
let parent = dirname17(file);
|
|
32266
|
-
const boundary =
|
|
32365
|
+
const boundary = resolve22(projectRoot);
|
|
32267
32366
|
while (parent !== boundary) {
|
|
32268
32367
|
const stat = lstatSync7(parent);
|
|
32269
32368
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_parent_invalid", path4, "managed file parents must be regular directories", "path");
|
|
@@ -32272,8 +32371,8 @@ function readOptionalManaged(projectRoot, path4) {
|
|
|
32272
32371
|
return readRegularBounded(file, path4);
|
|
32273
32372
|
}
|
|
32274
32373
|
function readProjectAndProvenance(projectRoot, schemasDir) {
|
|
32275
|
-
const projectFile =
|
|
32276
|
-
const provenanceFile =
|
|
32374
|
+
const projectFile = join28(projectRoot, ".kxm", "project.yaml");
|
|
32375
|
+
const provenanceFile = join28(projectRoot, ...KXM_TEMPLATE_PROVENANCE_PATH.split("/"));
|
|
32277
32376
|
if (!existsSync24(projectFile) || !existsSync24(provenanceFile)) return void 0;
|
|
32278
32377
|
const projectBytes = readOptionalManaged(projectRoot, ".kxm/project.yaml");
|
|
32279
32378
|
const provenanceBytes = readOptionalManaged(projectRoot, KXM_TEMPLATE_PROVENANCE_PATH);
|
|
@@ -32310,7 +32409,7 @@ function readProjectAndProvenance(projectRoot, schemasDir) {
|
|
|
32310
32409
|
}
|
|
32311
32410
|
function planKxmTemplateRepair(projectRoot, options = {}) {
|
|
32312
32411
|
assertNoRegisteredGates(options);
|
|
32313
|
-
const root =
|
|
32412
|
+
const root = resolve22(projectRoot);
|
|
32314
32413
|
const source = readProjectAndProvenance(root, options.schemasDir);
|
|
32315
32414
|
if (!source) return void 0;
|
|
32316
32415
|
const target = renderKxmTemplate(
|
|
@@ -32438,7 +32537,7 @@ function operationPlanSha(operation) {
|
|
|
32438
32537
|
function writeOperation(projectRoot, operation) {
|
|
32439
32538
|
const root = transactionRoot(projectRoot);
|
|
32440
32539
|
const file = operationFile(projectRoot);
|
|
32441
|
-
const temporary =
|
|
32540
|
+
const temporary = join28(root, `.operation-${operation.operationId}-${randomUUID10()}.tmp`);
|
|
32442
32541
|
try {
|
|
32443
32542
|
writeDurableNew(temporary, Buffer.from(`${JSON.stringify(operation, null, 2)}
|
|
32444
32543
|
`, "utf8"), 384);
|
|
@@ -32482,7 +32581,7 @@ function readOperation(projectRoot, schemasDir) {
|
|
|
32482
32581
|
seen.add(folded);
|
|
32483
32582
|
prior = entry.path;
|
|
32484
32583
|
}
|
|
32485
|
-
if (!
|
|
32584
|
+
if (!isAbsolute8(operation.projectRoot)) fail3("init_transaction_project_root_invalid", TRANSACTION_NAME, "operation project root must be absolute", "path");
|
|
32486
32585
|
validateOperationIntent(projectRoot, operation);
|
|
32487
32586
|
return operation;
|
|
32488
32587
|
}
|
|
@@ -32490,12 +32589,12 @@ function hasKxmInitTransaction(projectRoot) {
|
|
|
32490
32589
|
return existsSync24(transactionRoot(projectRoot));
|
|
32491
32590
|
}
|
|
32492
32591
|
function readTarget(projectRoot, path4) {
|
|
32493
|
-
return readOptionalManaged(
|
|
32592
|
+
return readOptionalManaged(join28(transactionRoot(projectRoot), "targets"), path4);
|
|
32494
32593
|
}
|
|
32495
32594
|
function writeTarget(projectRoot, path4, bytes) {
|
|
32496
32595
|
if (bytes.byteLength > MAX_MANAGED_FILE_BYTES) fail3("template_target_too_large", path4, `target exceeds ${MAX_MANAGED_FILE_BYTES} bytes`);
|
|
32497
32596
|
const file = targetFile(projectRoot, path4);
|
|
32498
|
-
|
|
32597
|
+
mkdirSync21(dirname17(file), { recursive: true, mode: 448 });
|
|
32499
32598
|
writeDurableNew(file, bytes, 384);
|
|
32500
32599
|
}
|
|
32501
32600
|
function writeAndVerifyBackups(projectRoot, operation) {
|
|
@@ -32507,7 +32606,7 @@ function writeAndVerifyBackups(projectRoot, operation) {
|
|
|
32507
32606
|
fail3("repair_preimage_changed", entry.path, "destination changed before transaction preparation; local bytes were preserved");
|
|
32508
32607
|
}
|
|
32509
32608
|
const file = backupFile(projectRoot, entry.path);
|
|
32510
|
-
|
|
32609
|
+
mkdirSync21(dirname17(file), { recursive: true, mode: 448 });
|
|
32511
32610
|
writeDurableNew(file, current, 384);
|
|
32512
32611
|
}
|
|
32513
32612
|
}
|
|
@@ -32522,7 +32621,7 @@ function writeKnownBackups(projectRoot, operation) {
|
|
|
32522
32621
|
fail3("init_transaction_backup_source_invalid", entry.path, "supported source template cannot reproduce the pinned preimage");
|
|
32523
32622
|
}
|
|
32524
32623
|
const file = backupFile(projectRoot, entry.path);
|
|
32525
|
-
|
|
32624
|
+
mkdirSync21(dirname17(file), { recursive: true, mode: 448 });
|
|
32526
32625
|
writeDurableNew(file, bytes, 384);
|
|
32527
32626
|
}
|
|
32528
32627
|
}
|
|
@@ -32530,7 +32629,7 @@ function verifyBackups(projectRoot, operation) {
|
|
|
32530
32629
|
if (operation.kind !== "repair") return;
|
|
32531
32630
|
for (const entry of operation.files) {
|
|
32532
32631
|
if (entry.observedSha256 === null) continue;
|
|
32533
|
-
const bytes = readOptionalManaged(
|
|
32632
|
+
const bytes = readOptionalManaged(join28(transactionRoot(projectRoot), "backups"), entry.path);
|
|
32534
32633
|
if (!bytes || kxmContentSha256(bytes) !== entry.observedSha256) {
|
|
32535
32634
|
fail3("init_transaction_backup_invalid", entry.path, "pinned preimage backup is missing or corrupt");
|
|
32536
32635
|
}
|
|
@@ -32564,9 +32663,9 @@ function sourceConfigFiles(projectRoot) {
|
|
|
32564
32663
|
".kxm/repo/repo.yaml",
|
|
32565
32664
|
".kxm/repo/env.yaml"
|
|
32566
32665
|
];
|
|
32567
|
-
const files = fixed.filter((path4) => existsSync24(
|
|
32666
|
+
const files = fixed.filter((path4) => existsSync24(join28(projectRoot, ...path4.split("/"))));
|
|
32568
32667
|
for (const directory of ["agents", "models", "workflows"]) {
|
|
32569
|
-
const absolute =
|
|
32668
|
+
const absolute = join28(projectRoot, ".kxm", directory);
|
|
32570
32669
|
if (!existsSync24(absolute)) continue;
|
|
32571
32670
|
const stat = lstatSync7(absolute);
|
|
32572
32671
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_directory_invalid", `.kxm/${directory}`, "configuration directory must be regular", "path");
|
|
@@ -32588,7 +32687,7 @@ function absoluteMemberBindings(projectRoot, project, explicit = {}) {
|
|
|
32588
32687
|
const repository = candidate;
|
|
32589
32688
|
if (repository.role !== "member" || typeof repository.id !== "string" || Object.hasOwn(bindings, repository.id)) continue;
|
|
32590
32689
|
if (typeof repository.pathHint === "string") {
|
|
32591
|
-
const candidate2 =
|
|
32690
|
+
const candidate2 = resolve22(projectRoot, ...repository.pathHint.split("/"));
|
|
32592
32691
|
if (existsSync24(candidate2)) bindings[repository.id] = candidate2;
|
|
32593
32692
|
}
|
|
32594
32693
|
}
|
|
@@ -32596,16 +32695,16 @@ function absoluteMemberBindings(projectRoot, project, explicit = {}) {
|
|
|
32596
32695
|
}
|
|
32597
32696
|
function prepareShadow(projectRoot, operation, options) {
|
|
32598
32697
|
const shadow = shadowRoot(projectRoot);
|
|
32599
|
-
|
|
32698
|
+
mkdirSync21(shadow, { recursive: true, mode: 448 });
|
|
32600
32699
|
let total = 0;
|
|
32601
32700
|
if (operation.kind === "repair") {
|
|
32602
32701
|
for (const path4 of sourceConfigFiles(projectRoot)) {
|
|
32603
32702
|
const bytes = readOptionalManaged(projectRoot, path4);
|
|
32604
32703
|
if (!bytes) fail3("repair_snapshot_file_missing", path4, "configuration changed during shadow preparation");
|
|
32605
32704
|
total += bytes.byteLength;
|
|
32606
|
-
const source =
|
|
32607
|
-
const destination =
|
|
32608
|
-
|
|
32705
|
+
const source = join28(projectRoot, ...path4.split("/"));
|
|
32706
|
+
const destination = join28(shadow, ...path4.split("/"));
|
|
32707
|
+
mkdirSync21(dirname17(destination), { recursive: true, mode: 448 });
|
|
32609
32708
|
writeDurableNew(destination, bytes, lstatSync7(source).mode & 511);
|
|
32610
32709
|
if (total > MAX_MANAGED_TOTAL_BYTES) fail3("repair_snapshot_too_large", ".kxm", `configuration snapshot exceeds ${MAX_MANAGED_TOTAL_BYTES} bytes`, "parse");
|
|
32611
32710
|
}
|
|
@@ -32613,12 +32712,12 @@ function prepareShadow(projectRoot, operation, options) {
|
|
|
32613
32712
|
for (const entry of operation.files) {
|
|
32614
32713
|
const bytes = readTarget(projectRoot, entry.path);
|
|
32615
32714
|
if (!bytes) fail3("init_transaction_target_missing", entry.path, "pinned target artifact is missing");
|
|
32616
|
-
const destination =
|
|
32617
|
-
|
|
32715
|
+
const destination = join28(shadow, ...entry.path.split("/"));
|
|
32716
|
+
mkdirSync21(dirname17(destination), { recursive: true, mode: 448 });
|
|
32618
32717
|
const mode = existsSync24(destination) ? lstatSync7(destination).mode & 511 : 420;
|
|
32619
32718
|
writeDurable(destination, bytes, mode);
|
|
32620
32719
|
}
|
|
32621
|
-
const project = parseRestrictedYaml2(
|
|
32720
|
+
const project = parseRestrictedYaml2(readFileSync24(join28(shadow, ".kxm", "project.yaml")), ".kxm/project.yaml");
|
|
32622
32721
|
const bound = absoluteMemberBindings(projectRoot, project, options.repositoryBindings);
|
|
32623
32722
|
loadKxmProject(shadow, { ...loaderOptions(options), repositoryBindings: bound });
|
|
32624
32723
|
const provenance = readProjectAndProvenance(shadow, options.schemasDir)?.provenance;
|
|
@@ -32627,10 +32726,10 @@ function prepareShadow(projectRoot, operation, options) {
|
|
|
32627
32726
|
}
|
|
32628
32727
|
}
|
|
32629
32728
|
function createOperation(projectRoot, kind, rendered, files, sourceTemplateRevision) {
|
|
32630
|
-
const root =
|
|
32729
|
+
const root = resolve22(projectRoot);
|
|
32631
32730
|
const operationWithoutHash = {
|
|
32632
32731
|
schema: "kxm.init-operation.v1",
|
|
32633
|
-
operationId: `op_${
|
|
32732
|
+
operationId: `op_${randomUUID10().replaceAll("-", "")}`,
|
|
32634
32733
|
kind,
|
|
32635
32734
|
projectRoot: root,
|
|
32636
32735
|
projectId: rendered.projectId,
|
|
@@ -32657,7 +32756,7 @@ function prepareOperation(projectRoot, operation, rendered, options) {
|
|
|
32657
32756
|
validateOperationRecord(operation, options.schemasDir);
|
|
32658
32757
|
validateOperationIntent(projectRoot, operation);
|
|
32659
32758
|
if (existsSync24(transaction)) fail3("init_transaction_exists", TRANSACTION_NAME, "an initialization transaction already exists and must be resumed");
|
|
32660
|
-
|
|
32759
|
+
mkdirSync21(transaction, { mode: 448 });
|
|
32661
32760
|
syncDirectory2(projectRoot);
|
|
32662
32761
|
writeOperation(projectRoot, operation);
|
|
32663
32762
|
try {
|
|
@@ -32678,25 +32777,25 @@ function prepareOperation(projectRoot, operation, rendered, options) {
|
|
|
32678
32777
|
}
|
|
32679
32778
|
}
|
|
32680
32779
|
function ensureDestinationParents(projectRoot, path4) {
|
|
32681
|
-
const boundary =
|
|
32780
|
+
const boundary = resolve22(projectRoot);
|
|
32682
32781
|
const segments = path4.split("/").slice(0, -1);
|
|
32683
32782
|
let current = boundary;
|
|
32684
32783
|
for (const segment of segments) {
|
|
32685
|
-
current =
|
|
32686
|
-
if (!existsSync24(current))
|
|
32784
|
+
current = join28(current, segment);
|
|
32785
|
+
if (!existsSync24(current)) mkdirSync21(current, { mode: 448 });
|
|
32687
32786
|
const stat = lstatSync7(current);
|
|
32688
32787
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_destination_parent_invalid", path4, "destination parent must be a regular directory", "path");
|
|
32689
32788
|
}
|
|
32690
32789
|
}
|
|
32691
32790
|
function destinationSha(projectRoot, path4) {
|
|
32692
|
-
const file =
|
|
32791
|
+
const file = join28(projectRoot, ...path4.split("/"));
|
|
32693
32792
|
if (!existsSync24(file)) return void 0;
|
|
32694
32793
|
return kxmContentSha256(readRegularBounded(file, path4));
|
|
32695
32794
|
}
|
|
32696
32795
|
function requireConditionalLinkSupport(directory, operationId, path4) {
|
|
32697
|
-
const nonce =
|
|
32698
|
-
const source =
|
|
32699
|
-
const target =
|
|
32796
|
+
const nonce = randomUUID10();
|
|
32797
|
+
const source = join28(directory, `.kxm-repair-${operationId}-${nonce}.link-source`);
|
|
32798
|
+
const target = join28(directory, `.kxm-repair-${operationId}-${nonce}.link-target`);
|
|
32700
32799
|
try {
|
|
32701
32800
|
writeDurableNew(source, Buffer.from("kxm-link-probe\n", "utf8"), 384);
|
|
32702
32801
|
try {
|
|
@@ -32711,16 +32810,16 @@ function requireConditionalLinkSupport(directory, operationId, path4) {
|
|
|
32711
32810
|
}
|
|
32712
32811
|
}
|
|
32713
32812
|
function atomicInstallTarget(projectRoot, operation, entry) {
|
|
32714
|
-
const destination =
|
|
32813
|
+
const destination = join28(projectRoot, ...entry.path.split("/"));
|
|
32715
32814
|
ensureDestinationParents(projectRoot, entry.path);
|
|
32716
32815
|
const directory = dirname17(destination);
|
|
32717
32816
|
const temporaryPrefix = `.kxm-repair-${operation.operationId}-`;
|
|
32718
32817
|
const pathKey = kxmContentSha256(entry.path).slice("sha256:".length, "sha256:".length + 16);
|
|
32719
|
-
const displaced =
|
|
32818
|
+
const displaced = join28(directory, `${temporaryPrefix}${pathKey}.preimage`);
|
|
32720
32819
|
if (existsSync24(displaced)) {
|
|
32721
32820
|
const stat = lstatSync7(displaced);
|
|
32722
32821
|
if (stat.isSymbolicLink() || !stat.isFile()) fail3("repair_preimage_temporary_invalid", entry.path, "stale displaced preimage is not a regular file", "path");
|
|
32723
|
-
if (entry.observedSha256 === null || kxmContentSha256(
|
|
32822
|
+
if (entry.observedSha256 === null || kxmContentSha256(readFileSync24(displaced)) !== entry.observedSha256) {
|
|
32724
32823
|
fail3("repair_preimage_temporary_mismatch", entry.path, "stale displaced preimage does not match the pinned operation");
|
|
32725
32824
|
}
|
|
32726
32825
|
if (!existsSync24(destination)) {
|
|
@@ -32738,7 +32837,7 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
32738
32837
|
const owned = candidate.name.startsWith(temporaryPrefix) && (candidate.name.endsWith(".tmp") || candidate.name.endsWith(".link-source") || candidate.name.endsWith(".link-target"));
|
|
32739
32838
|
if (!owned) continue;
|
|
32740
32839
|
if (!candidate.isFile()) fail3("repair_temporary_invalid", entry.path, "stale operation temporary is not a regular file", "path");
|
|
32741
|
-
rmSync9(
|
|
32840
|
+
rmSync9(join28(directory, candidate.name), { force: true });
|
|
32742
32841
|
}
|
|
32743
32842
|
const current = destinationSha(projectRoot, entry.path);
|
|
32744
32843
|
if (current === entry.targetSha256) return;
|
|
@@ -32748,14 +32847,14 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
32748
32847
|
requireConditionalLinkSupport(directory, operation.operationId, entry.path);
|
|
32749
32848
|
const bytes = readTarget(projectRoot, entry.path);
|
|
32750
32849
|
if (!bytes) fail3("init_transaction_target_missing", entry.path, "pinned target artifact is missing");
|
|
32751
|
-
const temporary =
|
|
32850
|
+
const temporary = join28(directory, `${temporaryPrefix}${randomUUID10()}.tmp`);
|
|
32752
32851
|
const mode = existsSync24(destination) ? lstatSync7(destination).mode & 511 : 420;
|
|
32753
32852
|
try {
|
|
32754
32853
|
writeDurableNew(temporary, bytes, mode);
|
|
32755
32854
|
if (entry.observedSha256 !== null) {
|
|
32756
32855
|
renameSync7(destination, displaced);
|
|
32757
32856
|
syncDirectory2(directory);
|
|
32758
|
-
if (kxmContentSha256(
|
|
32857
|
+
if (kxmContentSha256(readFileSync24(displaced)) !== entry.observedSha256) {
|
|
32759
32858
|
if (!existsSync24(destination)) {
|
|
32760
32859
|
try {
|
|
32761
32860
|
linkSync(displaced, destination);
|
|
@@ -32794,12 +32893,12 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
32794
32893
|
if (destinationSha(projectRoot, entry.path) !== entry.targetSha256) fail3("repair_install_verification_failed", entry.path, "installed target hash does not match the pinned operation");
|
|
32795
32894
|
}
|
|
32796
32895
|
function installedCreateMatches(projectRoot, operation) {
|
|
32797
|
-
const configRoot =
|
|
32896
|
+
const configRoot = join28(projectRoot, ".kxm");
|
|
32798
32897
|
if (!existsSync24(configRoot)) return false;
|
|
32799
32898
|
const actual = [];
|
|
32800
32899
|
const visit2 = (directory) => {
|
|
32801
32900
|
for (const entry of readdirSync9(directory, { withFileTypes: true })) {
|
|
32802
|
-
const absolute =
|
|
32901
|
+
const absolute = join28(directory, entry.name);
|
|
32803
32902
|
if (entry.isSymbolicLink()) fail3("create_resume_link", relativeConfigPath(projectRoot, absolute), "created configuration must not contain links", "path");
|
|
32804
32903
|
if (entry.isDirectory()) visit2(absolute);
|
|
32805
32904
|
else if (entry.isFile()) actual.push(relativeConfigPath(projectRoot, absolute));
|
|
@@ -32812,7 +32911,7 @@ function installedCreateMatches(projectRoot, operation) {
|
|
|
32812
32911
|
return actual.length === expected.length && actual.every((path4, index) => path4 === expected[index]) && operation.files.every((entry) => destinationSha(projectRoot, entry.path) === entry.targetSha256);
|
|
32813
32912
|
}
|
|
32814
32913
|
function relativeConfigPath(projectRoot, file) {
|
|
32815
|
-
return
|
|
32914
|
+
return relative5(resolve22(projectRoot), file).replaceAll("\\", "/");
|
|
32816
32915
|
}
|
|
32817
32916
|
function syncTreeDirectories(root) {
|
|
32818
32917
|
if (!existsSync24(root)) return;
|
|
@@ -32820,7 +32919,7 @@ function syncTreeDirectories(root) {
|
|
|
32820
32919
|
const visit2 = (directory) => {
|
|
32821
32920
|
directories.push(directory);
|
|
32822
32921
|
for (const entry of readdirSync9(directory, { withFileTypes: true })) {
|
|
32823
|
-
if (entry.isDirectory()) visit2(
|
|
32922
|
+
if (entry.isDirectory()) visit2(join28(directory, entry.name));
|
|
32824
32923
|
}
|
|
32825
32924
|
};
|
|
32826
32925
|
visit2(root);
|
|
@@ -32834,7 +32933,7 @@ function rebuildCreateShadow(projectRoot, operation, options) {
|
|
|
32834
32933
|
if (stat.isSymbolicLink() || !stat.isDirectory() || !installedCreateMatches(shadow, operation)) {
|
|
32835
32934
|
fail3("create_shadow_invalid", TRANSACTION_NAME, "reconstructed create shadow does not exactly match pinned target files", "path");
|
|
32836
32935
|
}
|
|
32837
|
-
syncTreeDirectories(
|
|
32936
|
+
syncTreeDirectories(join28(shadow, ".kxm"));
|
|
32838
32937
|
}
|
|
32839
32938
|
function applyOperation(projectRoot, original, options, resumed) {
|
|
32840
32939
|
assertNoRegisteredGates(options);
|
|
@@ -32844,10 +32943,10 @@ function applyOperation(projectRoot, original, options, resumed) {
|
|
|
32844
32943
|
verifyBackups(projectRoot, operation);
|
|
32845
32944
|
operation = updatePhase(projectRoot, operation, "applying");
|
|
32846
32945
|
if (operation.kind === "create") {
|
|
32847
|
-
const destination =
|
|
32946
|
+
const destination = join28(projectRoot, ".kxm");
|
|
32848
32947
|
if (!existsSync24(destination)) {
|
|
32849
32948
|
rebuildCreateShadow(projectRoot, operation, effectiveOptions);
|
|
32850
|
-
renameSync7(
|
|
32949
|
+
renameSync7(join28(shadowRoot(projectRoot), ".kxm"), destination);
|
|
32851
32950
|
syncDirectory2(projectRoot);
|
|
32852
32951
|
} else if (!installedCreateMatches(projectRoot, operation)) {
|
|
32853
32952
|
fail3("create_resume_conflict", ".kxm", "existing project configuration does not match the pinned create operation");
|
|
@@ -32874,7 +32973,7 @@ function applyOperation(projectRoot, original, options, resumed) {
|
|
|
32874
32973
|
operation = updatePhase(projectRoot, operation, "verified");
|
|
32875
32974
|
if (options.testFaultAt === "verified") throw new Error("injected init fault after verification");
|
|
32876
32975
|
const files = operation.files.map((entry) => entry.path);
|
|
32877
|
-
syncTreeDirectories(
|
|
32976
|
+
syncTreeDirectories(join28(projectRoot, ".kxm"));
|
|
32878
32977
|
return { kind: operation.kind, resumed, bundle, files };
|
|
32879
32978
|
}
|
|
32880
32979
|
function prepareAndApplyKxmCreate(projectRoot, rendered, options = {}) {
|
|
@@ -32989,7 +33088,7 @@ function finishPreparingOperation(projectRoot, operation, options) {
|
|
|
32989
33088
|
const rendered = rendererForOperation(operation);
|
|
32990
33089
|
if (!rendered) fail3("init_transaction_renderer_unavailable", TRANSACTION_NAME, "this binary cannot reproduce the pinned pre-application target");
|
|
32991
33090
|
for (const directory of ["targets", "backups", "shadow"]) {
|
|
32992
|
-
rmSync9(
|
|
33091
|
+
rmSync9(join28(transactionRoot(projectRoot), directory), { recursive: true, force: true });
|
|
32993
33092
|
}
|
|
32994
33093
|
for (const entry of operation.files) {
|
|
32995
33094
|
const bytes = rendered.files.get(entry.path);
|
|
@@ -33024,7 +33123,7 @@ function commitKxmInitTransaction(projectRoot, schemasDir) {
|
|
|
33024
33123
|
fail3("init_transaction_not_verified", TRANSACTION_NAME, "initialization transaction cannot commit before installed state is verified");
|
|
33025
33124
|
}
|
|
33026
33125
|
const transaction = transactionRoot(projectRoot);
|
|
33027
|
-
const retired =
|
|
33126
|
+
const retired = join28(projectRoot, `${TRANSACTION_NAME}-cleanup-${operation.operationId}-${randomUUID10()}`);
|
|
33028
33127
|
renameSync7(transaction, retired);
|
|
33029
33128
|
syncDirectory2(projectRoot);
|
|
33030
33129
|
rmSync9(retired, { recursive: true, force: true });
|
|
@@ -33052,7 +33151,7 @@ function normalizedProjectName(root, requested) {
|
|
|
33052
33151
|
return name;
|
|
33053
33152
|
}
|
|
33054
33153
|
function generatedProjectId(requested) {
|
|
33055
|
-
const id = requested?.trim() || `prj_${
|
|
33154
|
+
const id = requested?.trim() || `prj_${randomUUID11().replaceAll("-", "")}`;
|
|
33056
33155
|
if (!PROJECT_ID.test(id) || id.length > 144) {
|
|
33057
33156
|
throw new KxmConfigError([initIssue("project_id_invalid", ".kxm/project.yaml", "project ID must satisfy the kxm.project.v1 opaque ID grammar and use the prj_ prefix")]);
|
|
33058
33157
|
}
|
|
@@ -33133,7 +33232,7 @@ function validateBindingIdentities(bundle, persisted, explicit) {
|
|
|
33133
33232
|
}
|
|
33134
33233
|
function initializeKxmProjectAtGitRoot(start, gitRoot, options, mutationLock) {
|
|
33135
33234
|
const storeOptions = bindingStoreOptions(options);
|
|
33136
|
-
const persisted = existsSync25(
|
|
33235
|
+
const persisted = existsSync25(join29(gitRoot, ".kxm", "project.yaml")) ? readKxmLocalBindings(gitRoot, storeOptions) : void 0;
|
|
33137
33236
|
const repositoryBindings = Object.fromEntries([
|
|
33138
33237
|
...Object.entries(persisted?.repositories ?? {}),
|
|
33139
33238
|
...Object.entries(options.repositoryBindings ?? {})
|
|
@@ -33321,7 +33420,7 @@ function initializeKxmProjectAtGitRoot(start, gitRoot, options, mutationLock) {
|
|
|
33321
33420
|
const files = [...rendered.files.keys()];
|
|
33322
33421
|
if (options.dryRun) return { action: "planned", plan, projectRoot: gitRoot, files };
|
|
33323
33422
|
if (!mutationLock) throw new Error("project mutation lock is required to create configuration");
|
|
33324
|
-
if (existsSync25(
|
|
33423
|
+
if (existsSync25(join29(gitRoot, ".kxm"))) {
|
|
33325
33424
|
throw new KxmConfigError([initIssue("workspace_changed", ".kxm", "workspace changed after planning; existing .kxm state was not overwritten")]);
|
|
33326
33425
|
}
|
|
33327
33426
|
const created = prepareAndApplyKxmCreate(gitRoot, rendered, transactionOptions);
|
|
@@ -33637,23 +33736,27 @@ async function cmdKxmInit(runtime, options, postHooks) {
|
|
|
33637
33736
|
return 1;
|
|
33638
33737
|
}
|
|
33639
33738
|
}
|
|
33739
|
+
function backupProjectRoot(runtime) {
|
|
33740
|
+
return discoverKxmProjectRoot(runtime.cwd) ?? runtime.cwd;
|
|
33741
|
+
}
|
|
33640
33742
|
async function cmdBackup(runtime, options) {
|
|
33641
33743
|
try {
|
|
33642
33744
|
const backupOptions = {
|
|
33643
|
-
projectRoot: runtime
|
|
33745
|
+
projectRoot: backupProjectRoot(runtime),
|
|
33644
33746
|
env: runtime.env,
|
|
33645
|
-
...options.
|
|
33747
|
+
...options.allProjects === true ? { allProjects: true } : {},
|
|
33748
|
+
...options.out ? { outDir: resolve23(runtime.cwd, options.out) } : {}
|
|
33646
33749
|
};
|
|
33647
33750
|
if (runtime.dryRun) {
|
|
33648
33751
|
const plan = planBackup(backupOptions);
|
|
33649
33752
|
printPlan(
|
|
33650
33753
|
runtime,
|
|
33651
|
-
{ command: "backup", outDir: plan.outDir, stores: plan.stores, files: plan.files },
|
|
33754
|
+
{ command: "backup", scope: plan.scope, outDir: plan.outDir, stores: plan.stores, files: plan.files },
|
|
33652
33755
|
[
|
|
33653
|
-
...[...plan.stores, ...plan.files].map((entry) => ({ action: "write", target:
|
|
33654
|
-
{ action: "write", target:
|
|
33756
|
+
...[...plan.stores, ...plan.files].map((entry) => ({ action: "write", target: join30(plan.outDir, entry.backupFile) })),
|
|
33757
|
+
{ action: "write", target: join30(plan.outDir, "manifest.json") }
|
|
33655
33758
|
],
|
|
33656
|
-
`back up ${plan.stores.length} store(s) and ${plan.files.length} file(s) to ${plan.outDir} (sources are not opened, so their WAL is not checkpointed)`
|
|
33759
|
+
`back up ${plan.stores.length} store(s) and ${plan.files.length} file(s) (${plan.scope} scope) to ${plan.outDir} (sources are not opened, so their WAL is not checkpointed)`
|
|
33657
33760
|
);
|
|
33658
33761
|
return 0;
|
|
33659
33762
|
}
|
|
@@ -33667,10 +33770,10 @@ async function cmdBackup(runtime, options) {
|
|
|
33667
33770
|
manifest
|
|
33668
33771
|
};
|
|
33669
33772
|
const summary = [
|
|
33670
|
-
complete ? `Created SQLite backup with ${manifest.stores.length} store(s):` : `Backup is incomplete (${manifest.omitted?.length ?? 0} omitted); not ok:`,
|
|
33773
|
+
complete ? `Created SQLite backup with ${manifest.stores.length} store(s) (${manifest.scope ?? "project"} scope):` : `Backup is incomplete (${manifest.omitted?.length ?? 0} omitted); not ok:`,
|
|
33671
33774
|
...manifest.stores.map((s) => ` - ${s.storeId}: ${s.sourcePath} -> ${s.backupFile} (schema v${s.schemaVersion}, ${s.bytes} bytes, sha256 ${s.sha256.slice(0, 12)}...)`),
|
|
33672
33775
|
...(manifest.omitted ?? []).map((id) => ` - omitted ${id}`),
|
|
33673
|
-
`Manifest: ${
|
|
33776
|
+
`Manifest: ${join30(outDir, "manifest.json")}`
|
|
33674
33777
|
].join("\n");
|
|
33675
33778
|
print(runtime.io, runtime.json, payload, summary);
|
|
33676
33779
|
return complete ? 0 : 1;
|
|
@@ -33683,16 +33786,53 @@ async function cmdBackup(runtime, options) {
|
|
|
33683
33786
|
return 1;
|
|
33684
33787
|
}
|
|
33685
33788
|
}
|
|
33686
|
-
|
|
33789
|
+
function assertRestoreTargetsStopped(runtime, plan) {
|
|
33790
|
+
const paths = kxmRuntimePaths({ env: runtime.env });
|
|
33791
|
+
let supervisor;
|
|
33687
33792
|
try {
|
|
33793
|
+
supervisor = kxmSupervisorStatus(paths, { readOnly: true });
|
|
33794
|
+
} catch (error) {
|
|
33795
|
+
throw databaseError(
|
|
33796
|
+
"restore_runtime_unverified",
|
|
33797
|
+
paths.registryDb,
|
|
33798
|
+
`cannot read the Runtime registry to check whether the supervisor is running (${error instanceof Error ? error.message : String(error)}); stop the Runtime, move the registry aside, and restore again`
|
|
33799
|
+
);
|
|
33800
|
+
}
|
|
33801
|
+
if (supervisor.running) {
|
|
33802
|
+
throw databaseError(
|
|
33803
|
+
"restore_runtime_running",
|
|
33804
|
+
paths.registryDb,
|
|
33805
|
+
`the Runtime supervisor is running (pid ${String(supervisor.pid)}); stop it with \`kxm runtime stop\` and keep it stopped until the restore finishes`
|
|
33806
|
+
);
|
|
33807
|
+
}
|
|
33808
|
+
for (const store of plan.stores) {
|
|
33809
|
+
if (store.storeId !== "hub-store") continue;
|
|
33810
|
+
const claim = readLiveHubClaim(dirname18(store.targetPath));
|
|
33811
|
+
if (claim) {
|
|
33812
|
+
throw databaseError(
|
|
33813
|
+
"restore_hub_running",
|
|
33814
|
+
store.targetPath,
|
|
33815
|
+
`a hub (pid ${String(claim.pid)}) is running on ${store.targetPath}; stop it with \`kxm hub stop\` before restoring`
|
|
33816
|
+
);
|
|
33817
|
+
}
|
|
33818
|
+
}
|
|
33819
|
+
}
|
|
33820
|
+
async function cmdRestore(runtime, manifestArg, options = {}) {
|
|
33821
|
+
try {
|
|
33822
|
+
const plan = planRestore(resolve23(runtime.cwd, manifestArg), {
|
|
33823
|
+
projectRoot: backupProjectRoot(runtime),
|
|
33824
|
+
env: runtime.env,
|
|
33825
|
+
...options.allProjects === true ? { allProjects: true } : {}
|
|
33826
|
+
});
|
|
33827
|
+
assertRestoreTargetsStopped(runtime, plan);
|
|
33688
33828
|
if (runtime.dryRun) {
|
|
33689
|
-
const plan = planRestore(resolve21(runtime.cwd, manifestArg), { projectRoot: runtime.cwd });
|
|
33690
33829
|
printPlan(
|
|
33691
33830
|
runtime,
|
|
33692
33831
|
{
|
|
33693
33832
|
command: "restore",
|
|
33694
33833
|
backupId: plan.backupId,
|
|
33695
33834
|
manifestPath: plan.manifestPath,
|
|
33835
|
+
...plan.scope !== void 0 ? { scope: plan.scope } : {},
|
|
33696
33836
|
stores: plan.stores.map(({ storeId, targetPath, schemaVersion }) => ({ storeId, targetPath, schemaVersion })),
|
|
33697
33837
|
files: plan.files.map(({ id, targetPath }) => ({ id, targetPath }))
|
|
33698
33838
|
},
|
|
@@ -33707,14 +33847,13 @@ async function cmdRestore(runtime, manifestArg) {
|
|
|
33707
33847
|
);
|
|
33708
33848
|
return 0;
|
|
33709
33849
|
}
|
|
33710
|
-
const result =
|
|
33711
|
-
projectRoot: runtime.cwd
|
|
33712
|
-
});
|
|
33850
|
+
const result = applyRestorePlan(plan);
|
|
33713
33851
|
const payload = {
|
|
33714
33852
|
ok: true,
|
|
33715
33853
|
command: "restore",
|
|
33716
33854
|
backupId: result.backupId,
|
|
33717
33855
|
manifestPath: result.manifestPath,
|
|
33856
|
+
...plan.scope !== void 0 ? { scope: plan.scope } : {},
|
|
33718
33857
|
restoredStores: result.restoredStores
|
|
33719
33858
|
};
|
|
33720
33859
|
const summary = [
|
|
@@ -33924,7 +34063,7 @@ function parseDriveWaitTimeoutMs(raw) {
|
|
|
33924
34063
|
return value;
|
|
33925
34064
|
}
|
|
33926
34065
|
function sleepMs(ms) {
|
|
33927
|
-
return new Promise((
|
|
34066
|
+
return new Promise((resolve35) => setTimeout(resolve35, ms));
|
|
33928
34067
|
}
|
|
33929
34068
|
function driveWaitCompleted(drive) {
|
|
33930
34069
|
return drive?.verified === true && drive.receipt?.settlement?.kind === "terminal" && drive.receipt.settlement.status === "completed";
|
|
@@ -34131,7 +34270,7 @@ async function selectInventoryModel(runtime, requested) {
|
|
|
34131
34270
|
if (runtime.json || !process.stdin.isTTY || models.length === 0) return void 0;
|
|
34132
34271
|
runtime.io.stdout(models.slice(0, 100).map((model, index2) => `${index2 + 1}. ${model}`).join("\n") + "\nSelect model number: ");
|
|
34133
34272
|
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
34134
|
-
const answer = await new Promise((
|
|
34273
|
+
const answer = await new Promise((resolve35) => rl.once("line", resolve35));
|
|
34135
34274
|
rl.close();
|
|
34136
34275
|
const index = Number.parseInt(answer.trim(), 10) - 1;
|
|
34137
34276
|
return Number.isInteger(index) && index >= 0 && index < models.length ? models[index] : void 0;
|
|
@@ -34157,7 +34296,7 @@ async function cmdModelsScreen(runtime) {
|
|
|
34157
34296
|
return 2;
|
|
34158
34297
|
}
|
|
34159
34298
|
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
34160
|
-
const ask = (q2) => new Promise((
|
|
34299
|
+
const ask = (q2) => new Promise((resolve35) => rl.question(q2, resolve35));
|
|
34161
34300
|
try {
|
|
34162
34301
|
while (true) {
|
|
34163
34302
|
const policy = loadRoutePolicy(runtime.dirs.workdir);
|
|
@@ -34540,12 +34679,12 @@ async function cmdStudioLayout(runtime, workflowPath) {
|
|
|
34540
34679
|
const projectRoot = discoverKxmProjectRoot(runtime.cwd) ?? runtime.cwd;
|
|
34541
34680
|
let filePath = workflowPath;
|
|
34542
34681
|
if (!filePath) {
|
|
34543
|
-
filePath =
|
|
34682
|
+
filePath = resolve24(projectRoot, ".kxm", "workflows", "default.yaml");
|
|
34544
34683
|
}
|
|
34545
34684
|
let yamlContent;
|
|
34546
34685
|
let workflowId = "default";
|
|
34547
34686
|
if (existsSync27(filePath)) {
|
|
34548
|
-
yamlContent =
|
|
34687
|
+
yamlContent = readFileSync26(filePath, "utf8");
|
|
34549
34688
|
} else {
|
|
34550
34689
|
yamlContent = `schema: kxm.workflow.v1
|
|
34551
34690
|
description: Feature implementation workflow
|
|
@@ -34618,15 +34757,15 @@ async function cmdStudioServe(runtime, options) {
|
|
|
34618
34757
|
sessionToken,
|
|
34619
34758
|
planProvider: () => {
|
|
34620
34759
|
try {
|
|
34621
|
-
const wfDir =
|
|
34622
|
-
const defaultPath =
|
|
34760
|
+
const wfDir = join31(runtime.cwd, ".kxm", "workflows");
|
|
34761
|
+
const defaultPath = join31(wfDir, "default.yaml");
|
|
34623
34762
|
let targetPath = existsSync27(defaultPath) ? defaultPath : void 0;
|
|
34624
34763
|
if (!targetPath && existsSync27(wfDir)) {
|
|
34625
34764
|
const yml = readdirSync10(wfDir).find((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
|
|
34626
|
-
if (yml) targetPath =
|
|
34765
|
+
if (yml) targetPath = join31(wfDir, yml);
|
|
34627
34766
|
}
|
|
34628
34767
|
if (targetPath && existsSync27(targetPath)) {
|
|
34629
|
-
const raw =
|
|
34768
|
+
const raw = readFileSync26(targetPath, "utf8");
|
|
34630
34769
|
const parsed = (0, import_yaml15.parse)(raw);
|
|
34631
34770
|
const wfId = basename7(targetPath).replace(/\.(yaml|yml)$/, "");
|
|
34632
34771
|
return compileKxmWorkflow({ id: wfId, value: parsed });
|
|
@@ -34676,17 +34815,17 @@ Press Ctrl+C to stop.
|
|
|
34676
34815
|
}
|
|
34677
34816
|
|
|
34678
34817
|
// plugins/kxm/src/cli/context-skills.ts
|
|
34679
|
-
import { readFileSync as
|
|
34680
|
-
import { join as
|
|
34818
|
+
import { readFileSync as readFileSync27 } from "node:fs";
|
|
34819
|
+
import { join as join33, relative as relative6, resolve as resolve25 } from "node:path";
|
|
34681
34820
|
|
|
34682
34821
|
// plugins/kxm/src/wiki.ts
|
|
34683
|
-
import { mkdirSync as
|
|
34684
|
-
import { join as
|
|
34822
|
+
import { mkdirSync as mkdirSync23, writeFileSync as writeFileSync21 } from "node:fs";
|
|
34823
|
+
import { join as join32 } from "node:path";
|
|
34685
34824
|
function writeCompiledWiki(root, wiki) {
|
|
34686
34825
|
const written = [];
|
|
34687
34826
|
for (const [relativePath, content] of [...wiki.pages].sort(([left], [right]) => left.localeCompare(right))) {
|
|
34688
|
-
const absolute =
|
|
34689
|
-
|
|
34827
|
+
const absolute = join32(root, relativePath);
|
|
34828
|
+
mkdirSync23(absolute.slice(0, absolute.lastIndexOf("/")), { recursive: true });
|
|
34690
34829
|
writeFileSync21(absolute, content);
|
|
34691
34830
|
written.push(relativePath);
|
|
34692
34831
|
}
|
|
@@ -34837,7 +34976,7 @@ async function cmdContextWikiCompile(runtime, project, options) {
|
|
|
34837
34976
|
printPlan(
|
|
34838
34977
|
runtime,
|
|
34839
34978
|
{ command: "context wiki-compile", project, pages: compiled.audit.pages, openContradictions: compiled.audit.contradictions, outDir },
|
|
34840
|
-
compiled.pages.map((page) => ({ action: "write", target:
|
|
34979
|
+
compiled.pages.map((page) => ({ action: "write", target: resolve25(outDir, page.path) })),
|
|
34841
34980
|
`write ${compiled.pages.length} compiled wiki page(s) to ${outDir}`
|
|
34842
34981
|
);
|
|
34843
34982
|
return 0;
|
|
@@ -34872,7 +35011,7 @@ function skillStateFromFlag(value) {
|
|
|
34872
35011
|
throw new Error(`invalid skill state ${value}`);
|
|
34873
35012
|
}
|
|
34874
35013
|
function skillsRoot(runtime) {
|
|
34875
|
-
return
|
|
35014
|
+
return join33(runtime.dirs.workdir, ".kxm", "skills");
|
|
34876
35015
|
}
|
|
34877
35016
|
function csv(value) {
|
|
34878
35017
|
if (!value) return void 0;
|
|
@@ -34889,7 +35028,7 @@ async function cmdSkillsCreate(runtime, options) {
|
|
|
34889
35028
|
const metadata = lifecycle.create({
|
|
34890
35029
|
name: options.name,
|
|
34891
35030
|
description: options.description ?? "",
|
|
34892
|
-
content:
|
|
35031
|
+
content: readFileSync27(options.file, "utf8"),
|
|
34893
35032
|
createdBy: options.createdBy,
|
|
34894
35033
|
sources: {
|
|
34895
35034
|
runIds: csv(options.run) ?? [],
|
|
@@ -35025,7 +35164,7 @@ async function cmdMemoryNote(runtime, fact, options) {
|
|
|
35025
35164
|
...options.body !== void 0 ? { body: options.body } : {},
|
|
35026
35165
|
dryRun: runtime.dryRun
|
|
35027
35166
|
});
|
|
35028
|
-
const relPath =
|
|
35167
|
+
const relPath = relative6(runtime.cwd, path4);
|
|
35029
35168
|
if (runtime.dryRun) {
|
|
35030
35169
|
printPlan(runtime, { command: "memory note", candidate: record, path: relPath }, [{ action: "write", target: path4 }], `record memory candidate in ${relPath} (the id is assigned when it is recorded)`);
|
|
35031
35170
|
return 0;
|
|
@@ -35051,7 +35190,7 @@ async function cmdMemorySync(runtime) {
|
|
|
35051
35190
|
printPlan(
|
|
35052
35191
|
runtime,
|
|
35053
35192
|
{ command: "memory sync", ...result },
|
|
35054
|
-
result.updated.map((file) => ({ action: "write", target:
|
|
35193
|
+
result.updated.map((file) => ({ action: "write", target: join33(runtime.cwd, file) })),
|
|
35055
35194
|
"regenerate the project memory block in the instruction files this project already has"
|
|
35056
35195
|
);
|
|
35057
35196
|
return 0;
|
|
@@ -35078,9 +35217,9 @@ ${lines.join("\n")}`
|
|
|
35078
35217
|
}
|
|
35079
35218
|
|
|
35080
35219
|
// plugins/kxm/src/cli/hub.ts
|
|
35081
|
-
import { randomUUID as
|
|
35082
|
-
import { existsSync as existsSync33, mkdirSync as
|
|
35083
|
-
import { join as
|
|
35220
|
+
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
35221
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync27, readFileSync as readFileSync33, readdirSync as readdirSync12, rmSync as rmSync11, writeFileSync as writeFileSync24 } from "node:fs";
|
|
35222
|
+
import { join as join43, resolve as resolve28 } from "node:path";
|
|
35084
35223
|
|
|
35085
35224
|
// node_modules/marked/lib/marked.esm.js
|
|
35086
35225
|
function M() {
|
|
@@ -39242,10 +39381,10 @@ var TuiBase = class _TuiBase extends Container {
|
|
|
39242
39381
|
* @returns Promise containing the parsed RGB color, or undefined if it times out or fails to parse.
|
|
39243
39382
|
*/
|
|
39244
39383
|
queryTerminalBackgroundColor({ timeoutMs }) {
|
|
39245
|
-
return new Promise((
|
|
39384
|
+
return new Promise((resolve35) => {
|
|
39246
39385
|
const query = {
|
|
39247
39386
|
settled: false,
|
|
39248
|
-
resolve:
|
|
39387
|
+
resolve: resolve35,
|
|
39249
39388
|
timer: void 0
|
|
39250
39389
|
};
|
|
39251
39390
|
query.timer = setTimeout(() => {
|
|
@@ -39268,7 +39407,7 @@ var TuiBase = class _TuiBase extends Container {
|
|
|
39268
39407
|
* `CSI ? 997 ; 1 n` for dark or `CSI ? 997 ; 2 n` for light.
|
|
39269
39408
|
*/
|
|
39270
39409
|
queryTerminalColorScheme({ timeoutMs }) {
|
|
39271
|
-
return new Promise((
|
|
39410
|
+
return new Promise((resolve35) => {
|
|
39272
39411
|
let settled = false;
|
|
39273
39412
|
let timer;
|
|
39274
39413
|
let unsubscribe = () => {
|
|
@@ -39282,7 +39421,7 @@ var TuiBase = class _TuiBase extends Container {
|
|
|
39282
39421
|
timer = void 0;
|
|
39283
39422
|
}
|
|
39284
39423
|
unsubscribe();
|
|
39285
|
-
|
|
39424
|
+
resolve35(scheme);
|
|
39286
39425
|
};
|
|
39287
39426
|
unsubscribe = this.onTerminalColorSchemeChange(settle);
|
|
39288
39427
|
timer = setTimeout(() => settle(void 0), timeoutMs);
|
|
@@ -41013,19 +41152,19 @@ import * as path2 from "node:path";
|
|
|
41013
41152
|
|
|
41014
41153
|
// node_modules/@earendil-works/pi-tui/dist/native-module-path.js
|
|
41015
41154
|
import { createRequire as createRequire2 } from "node:module";
|
|
41016
|
-
import { dirname as
|
|
41155
|
+
import { dirname as dirname19, join as join34 } from "node:path";
|
|
41017
41156
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
41018
41157
|
var moduleRequire = createRequire2(import.meta.url);
|
|
41019
41158
|
var TUI_PACKAGE_NAME = "@earendil-works/pi-tui";
|
|
41020
41159
|
function getNativeModuleCandidates(nativePath, options = {}) {
|
|
41021
|
-
const moduleDir =
|
|
41160
|
+
const moduleDir = dirname19(fileURLToPath2(options.moduleUrl ?? import.meta.url));
|
|
41022
41161
|
const candidates = [];
|
|
41023
41162
|
try {
|
|
41024
41163
|
const packageEntry = (options.resolvePackage ?? moduleRequire.resolve)(TUI_PACKAGE_NAME);
|
|
41025
|
-
candidates.push(
|
|
41164
|
+
candidates.push(join34(dirname19(packageEntry), "..", nativePath));
|
|
41026
41165
|
} catch {
|
|
41027
41166
|
}
|
|
41028
|
-
candidates.push(
|
|
41167
|
+
candidates.push(join34(moduleDir, "..", nativePath), join34(moduleDir, nativePath), join34(dirname19(options.execPath ?? process.execPath), nativePath));
|
|
41029
41168
|
return Array.from(new Set(candidates));
|
|
41030
41169
|
}
|
|
41031
41170
|
|
|
@@ -41366,7 +41505,7 @@ var ProcessTerminal = class {
|
|
|
41366
41505
|
break;
|
|
41367
41506
|
if (now - lastDataTime >= idleMs)
|
|
41368
41507
|
break;
|
|
41369
|
-
await new Promise((
|
|
41508
|
+
await new Promise((resolve35) => setTimeout(resolve35, Math.min(idleMs, timeLeft)));
|
|
41370
41509
|
}
|
|
41371
41510
|
} finally {
|
|
41372
41511
|
process.stdin.removeListener("data", onData);
|
|
@@ -43481,8 +43620,8 @@ var TuiAltScreen = class extends TuiBase {
|
|
|
43481
43620
|
var MAX_RENDER_WRITE_CHARS = 1024 * 1024;
|
|
43482
43621
|
|
|
43483
43622
|
// plugins/kxm/src/tui.ts
|
|
43484
|
-
import { mkdirSync as
|
|
43485
|
-
import { join as
|
|
43623
|
+
import { mkdirSync as mkdirSync24 } from "node:fs";
|
|
43624
|
+
import { join as join38, resolve as resolve27, dirname as dirname20 } from "node:path";
|
|
43486
43625
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
43487
43626
|
|
|
43488
43627
|
// packages/core/tui/src/types/surface.ts
|
|
@@ -43623,9 +43762,9 @@ var SHARED_EFFECT_KINDS = Object.freeze([
|
|
|
43623
43762
|
]);
|
|
43624
43763
|
|
|
43625
43764
|
// plugins/kxm/src/local-snapshot.ts
|
|
43626
|
-
import { existsSync as existsSync28, readdirSync as readdirSync11, readFileSync as
|
|
43765
|
+
import { existsSync as existsSync28, readdirSync as readdirSync11, readFileSync as readFileSync28 } from "node:fs";
|
|
43627
43766
|
import { homedir as homedir6 } from "node:os";
|
|
43628
|
-
import { isAbsolute as
|
|
43767
|
+
import { isAbsolute as isAbsolute9, join as join37, resolve as resolve26 } from "node:path";
|
|
43629
43768
|
var DEFAULT_BUSY_TIMEOUT_MS = 5e3;
|
|
43630
43769
|
var RUNTIME_PROJECT_KEY = /^[A-Za-z0-9_-][A-Za-z0-9._-]*$/;
|
|
43631
43770
|
function processExists2(pid) {
|
|
@@ -43750,34 +43889,34 @@ function readOpenMessageMetadata(database, where = OPEN_MESSAGE_WHERE, params =
|
|
|
43750
43889
|
return messages;
|
|
43751
43890
|
}
|
|
43752
43891
|
function resolveKxmSnapshotPaths(cwd, env = process.env) {
|
|
43753
|
-
const stateDir = env.KXM_STATE_DIR?.trim() ||
|
|
43892
|
+
const stateDir = env.KXM_STATE_DIR?.trim() || join37(cwd, ".kxm", "state");
|
|
43754
43893
|
const configured = env.KXM_DATA_PATH?.trim();
|
|
43755
|
-
const dataPath = configured ?
|
|
43894
|
+
const dataPath = configured ? resolve26(cwd, configured) : join37(stateDir, "kxm.db");
|
|
43756
43895
|
return { dataPath, stateDir };
|
|
43757
43896
|
}
|
|
43758
43897
|
function resolveKxmStateRoot(stateDir, options) {
|
|
43759
43898
|
if (options?.kxmStateRoot && existsSync28(options.kxmStateRoot)) {
|
|
43760
|
-
return
|
|
43899
|
+
return resolve26(options.kxmStateRoot);
|
|
43761
43900
|
}
|
|
43762
|
-
if (existsSync28(
|
|
43901
|
+
if (existsSync28(join37(stateDir, "runtime", "registry.db")) || existsSync28(join37(stateDir, "runtime", "projects"))) {
|
|
43763
43902
|
return stateDir;
|
|
43764
43903
|
}
|
|
43765
43904
|
const env = options?.env ?? process.env;
|
|
43766
43905
|
const explicit = env.KXM_STATE_HOME?.trim() || env.KXM_USER_STATE_DIR?.trim() || env.KXM_STATE_ROOT?.trim();
|
|
43767
|
-
if (explicit &&
|
|
43768
|
-
return
|
|
43906
|
+
if (explicit && isAbsolute9(explicit) && existsSync28(resolve26(explicit))) {
|
|
43907
|
+
return resolve26(explicit);
|
|
43769
43908
|
}
|
|
43770
43909
|
let base;
|
|
43771
43910
|
if (process.platform === "win32") {
|
|
43772
43911
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
43773
|
-
base = localAppData &&
|
|
43774
|
-
base =
|
|
43912
|
+
base = localAppData && isAbsolute9(localAppData) ? localAppData : join37(homedir6(), "AppData", "Local");
|
|
43913
|
+
base = resolve26(base, "KXM");
|
|
43775
43914
|
} else if (process.platform === "darwin") {
|
|
43776
|
-
base =
|
|
43915
|
+
base = resolve26(homedir6(), "Library", "Application Support", "KXM");
|
|
43777
43916
|
} else {
|
|
43778
43917
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
43779
|
-
base = xdgState &&
|
|
43780
|
-
base =
|
|
43918
|
+
base = xdgState && isAbsolute9(xdgState) ? xdgState : join37(homedir6(), ".local", "state");
|
|
43919
|
+
base = resolve26(base, "kxm");
|
|
43781
43920
|
}
|
|
43782
43921
|
if (existsSync28(base)) return base;
|
|
43783
43922
|
return void 0;
|
|
@@ -43843,9 +43982,9 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43843
43982
|
let kxmRunTotal = 0;
|
|
43844
43983
|
const kxmStateRoot = scope && !scope.runtimeProjectId ? void 0 : resolveKxmStateRoot(stateDir, options);
|
|
43845
43984
|
if (kxmStateRoot) {
|
|
43846
|
-
const runtimeDir =
|
|
43847
|
-
const registryDbPath =
|
|
43848
|
-
const projectsDir =
|
|
43985
|
+
const runtimeDir = join37(kxmStateRoot, "runtime");
|
|
43986
|
+
const registryDbPath = join37(runtimeDir, "registry.db");
|
|
43987
|
+
const projectsDir = join37(runtimeDir, "projects");
|
|
43849
43988
|
const projectKeys = /* @__PURE__ */ new Set();
|
|
43850
43989
|
if (existsSync28(registryDbPath)) {
|
|
43851
43990
|
hasKxm = true;
|
|
@@ -43875,7 +44014,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43875
44014
|
}
|
|
43876
44015
|
for (const key of projectKeys) {
|
|
43877
44016
|
if (scope && !RUNTIME_PROJECT_KEY.test(key)) continue;
|
|
43878
|
-
const eventDbPath =
|
|
44017
|
+
const eventDbPath = join37(projectsDir, key, "run-events.db");
|
|
43879
44018
|
if (existsSync28(eventDbPath)) {
|
|
43880
44019
|
hasKxm = true;
|
|
43881
44020
|
try {
|
|
@@ -43897,7 +44036,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43897
44036
|
if (existsSync28(stateDir)) {
|
|
43898
44037
|
for (const file of readdirSync11(stateDir).filter((name) => name.endsWith(".pid"))) {
|
|
43899
44038
|
try {
|
|
43900
|
-
const record = JSON.parse(
|
|
44039
|
+
const record = JSON.parse(readFileSync28(join37(stateDir, file), "utf8"));
|
|
43901
44040
|
pids.push({
|
|
43902
44041
|
file,
|
|
43903
44042
|
...record.role ? { role: record.role } : {},
|
|
@@ -43936,7 +44075,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43936
44075
|
} else {
|
|
43937
44076
|
source = "legacy";
|
|
43938
44077
|
}
|
|
43939
|
-
const telemetryFile =
|
|
44078
|
+
const telemetryFile = join37(stateDir, "telemetry.jsonl");
|
|
43940
44079
|
const spend = existsSync28(telemetryFile) ? readRoutingRecords(telemetryFile) : [];
|
|
43941
44080
|
return {
|
|
43942
44081
|
source,
|
|
@@ -44071,11 +44210,11 @@ function spawnDegradeWorktree(repoRoot, runId, options) {
|
|
|
44071
44210
|
const cleanRunId = runId.replace(/^run_/, "");
|
|
44072
44211
|
const desc = options?.description ? slugifyBranchPart(options.description, 30) : "degrade";
|
|
44073
44212
|
const branchName = `kxm/run-${cleanRunId}-${desc}`;
|
|
44074
|
-
const relativeWtPath =
|
|
44075
|
-
const absoluteWtPath =
|
|
44213
|
+
const relativeWtPath = join38(".kxm", "worktrees", `run-${cleanRunId}-${desc}`);
|
|
44214
|
+
const absoluteWtPath = resolve27(repoRoot, relativeWtPath);
|
|
44076
44215
|
const jumpCommand = `cd "${absoluteWtPath}"`;
|
|
44077
44216
|
try {
|
|
44078
|
-
|
|
44217
|
+
mkdirSync24(dirname20(absoluteWtPath), { recursive: true });
|
|
44079
44218
|
const branchCheck = runner("git", ["rev-parse", "--verify", `refs/heads/${branchName}`]);
|
|
44080
44219
|
let wtRes;
|
|
44081
44220
|
if (branchCheck.status === 0) {
|
|
@@ -44473,11 +44612,11 @@ async function readJson(response) {
|
|
|
44473
44612
|
}
|
|
44474
44613
|
async function waitForReconnect(signal, milliseconds = 1e3) {
|
|
44475
44614
|
if (signal.aborted) return;
|
|
44476
|
-
await new Promise((
|
|
44615
|
+
await new Promise((resolve35) => {
|
|
44477
44616
|
const done = () => {
|
|
44478
44617
|
clearTimeout(timer);
|
|
44479
44618
|
signal.removeEventListener("abort", done);
|
|
44480
|
-
|
|
44619
|
+
resolve35();
|
|
44481
44620
|
};
|
|
44482
44621
|
const timer = setTimeout(done, milliseconds);
|
|
44483
44622
|
timer.unref();
|
|
@@ -44839,9 +44978,9 @@ async function runMeshTui(input) {
|
|
|
44839
44978
|
|
|
44840
44979
|
// plugins/kxm/src/session-work.ts
|
|
44841
44980
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
44842
|
-
import { randomUUID as
|
|
44843
|
-
import { existsSync as existsSync29, mkdirSync as
|
|
44844
|
-
import { join as
|
|
44981
|
+
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
44982
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync25, readFileSync as readFileSync29, renameSync as renameSync8, writeFileSync as writeFileSync22 } from "node:fs";
|
|
44983
|
+
import { join as join39 } from "node:path";
|
|
44845
44984
|
var MAX_SESSION_BRIEF_TASKS = 5;
|
|
44846
44985
|
var MAX_SESSION_BRIEF_PLANS = 5;
|
|
44847
44986
|
var SESSION_BRIEF_SCHEMA = "kxm.session-brief.v1";
|
|
@@ -44998,10 +45137,10 @@ function buildSessionBrief(snapshot, current, hub, ship, updateLatest, cost, ses
|
|
|
44998
45137
|
};
|
|
44999
45138
|
}
|
|
45000
45139
|
function readCachedSessionBrief(stateDir) {
|
|
45001
|
-
const file =
|
|
45140
|
+
const file = join39(stateDir, "session-brief.json");
|
|
45002
45141
|
try {
|
|
45003
45142
|
if (!existsSync29(file)) return void 0;
|
|
45004
|
-
const raw =
|
|
45143
|
+
const raw = readFileSync29(file, "utf8");
|
|
45005
45144
|
const parsed = JSON.parse(raw);
|
|
45006
45145
|
if (parsed && parsed.schema === "kxm.session-brief.v1" && typeof parsed.generatedAt === "string") {
|
|
45007
45146
|
const ageMs = Date.now() - Date.parse(parsed.generatedAt);
|
|
@@ -45016,9 +45155,9 @@ function readCachedSessionBrief(stateDir) {
|
|
|
45016
45155
|
}
|
|
45017
45156
|
function writeCachedSessionBrief(stateDir, brief) {
|
|
45018
45157
|
try {
|
|
45019
|
-
|
|
45020
|
-
const file =
|
|
45021
|
-
const tmp = `${file}.tmp.${
|
|
45158
|
+
mkdirSync25(stateDir, { recursive: true, mode: 448 });
|
|
45159
|
+
const file = join39(stateDir, "session-brief.json");
|
|
45160
|
+
const tmp = `${file}.tmp.${randomUUID12().slice(0, 8)}`;
|
|
45022
45161
|
writeFileSync22(tmp, JSON.stringify(brief, null, 2), { encoding: "utf8", mode: 384 });
|
|
45023
45162
|
renameSync8(tmp, file);
|
|
45024
45163
|
} catch {
|
|
@@ -45026,7 +45165,7 @@ function writeCachedSessionBrief(stateDir, brief) {
|
|
|
45026
45165
|
}
|
|
45027
45166
|
function estimateSessionCost(stateDir) {
|
|
45028
45167
|
try {
|
|
45029
|
-
const telemetryFile =
|
|
45168
|
+
const telemetryFile = join39(stateDir, "telemetry.jsonl");
|
|
45030
45169
|
if (!existsSync29(telemetryFile)) return void 0;
|
|
45031
45170
|
const records = readRoutingRecords(telemetryFile);
|
|
45032
45171
|
if (records.length === 0) return void 0;
|
|
@@ -45195,11 +45334,11 @@ function formatSessionBriefText(brief) {
|
|
|
45195
45334
|
}
|
|
45196
45335
|
|
|
45197
45336
|
// plugins/kxm/src/kxm-install-kind.ts
|
|
45198
|
-
import { existsSync as existsSync30, readFileSync as
|
|
45199
|
-
import { dirname as
|
|
45337
|
+
import { existsSync as existsSync30, readFileSync as readFileSync30 } from "node:fs";
|
|
45338
|
+
import { dirname as dirname21, join as join40 } from "node:path";
|
|
45200
45339
|
function packageIsKxm(root) {
|
|
45201
45340
|
try {
|
|
45202
|
-
const pkg = JSON.parse(
|
|
45341
|
+
const pkg = JSON.parse(readFileSync30(join40(root, "package.json"), "utf8"));
|
|
45203
45342
|
return pkg.name === "@kontextmind/kxm";
|
|
45204
45343
|
} catch {
|
|
45205
45344
|
return false;
|
|
@@ -45248,12 +45387,12 @@ function report(kind, root) {
|
|
|
45248
45387
|
return { kind, root, instruction: installKindInstruction(kind, root) };
|
|
45249
45388
|
}
|
|
45250
45389
|
function classifyInstallRoot(probe) {
|
|
45251
|
-
const piGitRoot =
|
|
45390
|
+
const piGitRoot = join40(probe.homeDir, ".pi", "agent", "git");
|
|
45252
45391
|
if (isUnder(probe.repoRoot, piGitRoot, probe.platform)) return report("pi-git", probe.repoRoot);
|
|
45253
|
-
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() ||
|
|
45254
|
-
const pluginsRoot =
|
|
45392
|
+
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() || join40(probe.homeDir, ".claude");
|
|
45393
|
+
const pluginsRoot = join40(claudeHome, "plugins");
|
|
45255
45394
|
if (isUnder(probe.moduleDir, pluginsRoot, probe.platform)) return report("claude-marketplace", probe.moduleDir);
|
|
45256
|
-
const hasGit = existsSync30(
|
|
45395
|
+
const hasGit = existsSync30(join40(probe.repoRoot, ".git"));
|
|
45257
45396
|
if (hasGit && packageIsKxm(probe.repoRoot)) return report("source", probe.repoRoot);
|
|
45258
45397
|
if (isNpmPackageLayout(probe.repoRoot, probe.platform) && packageIsKxm(probe.repoRoot) && !hasGit) {
|
|
45259
45398
|
return report("npm-package", probe.repoRoot);
|
|
@@ -45267,21 +45406,21 @@ function resolveInstallKind(probe, npmGlobalRoot) {
|
|
|
45267
45406
|
if (typeof globalRoot !== "string" || globalRoot.trim() === "") {
|
|
45268
45407
|
return report("unknown", classified.root);
|
|
45269
45408
|
}
|
|
45270
|
-
const expected =
|
|
45409
|
+
const expected = dirname21(dirname21(classified.root));
|
|
45271
45410
|
if (sameHostPath2(globalRoot.trim(), expected, probe.platform)) return report("npm-global", classified.root);
|
|
45272
45411
|
return report("npm-local", classified.root);
|
|
45273
45412
|
}
|
|
45274
45413
|
|
|
45275
45414
|
// plugins/kxm/src/kxm-update-config.ts
|
|
45276
45415
|
var import_yaml16 = __toESM(require_dist(), 1);
|
|
45277
|
-
import { existsSync as existsSync31, readFileSync as
|
|
45278
|
-
import { join as
|
|
45416
|
+
import { existsSync as existsSync31, readFileSync as readFileSync31 } from "node:fs";
|
|
45417
|
+
import { join as join41 } from "node:path";
|
|
45279
45418
|
function loadKxmUpdateConfig(env = process.env) {
|
|
45280
|
-
const path4 =
|
|
45419
|
+
const path4 = join41(kxmUserStateRoot({ env }), "update.yaml");
|
|
45281
45420
|
if (!existsSync31(path4)) return { schema: KXM_UPDATE_SCHEMA, auto: false, source: "github" };
|
|
45282
45421
|
let parsed;
|
|
45283
45422
|
try {
|
|
45284
|
-
parsed = (0, import_yaml16.parse)(
|
|
45423
|
+
parsed = (0, import_yaml16.parse)(readFileSync31(path4, "utf8"));
|
|
45285
45424
|
} catch {
|
|
45286
45425
|
throw new KxmUpdateConfigError("update.yaml is not valid YAML");
|
|
45287
45426
|
}
|
|
@@ -45307,8 +45446,8 @@ function loadKxmUpdateConfig(env = process.env) {
|
|
|
45307
45446
|
}
|
|
45308
45447
|
|
|
45309
45448
|
// plugins/kxm/src/session.ts
|
|
45310
|
-
import { existsSync as existsSync32, mkdirSync as
|
|
45311
|
-
import { join as
|
|
45449
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync26, readFileSync as readFileSync32, writeFileSync as writeFileSync23 } from "node:fs";
|
|
45450
|
+
import { join as join42 } from "node:path";
|
|
45312
45451
|
var SESSION_SCHEMA = "kxm.session.v1";
|
|
45313
45452
|
var SessionConfigError = class extends Error {
|
|
45314
45453
|
code = "session_config_invalid";
|
|
@@ -45318,12 +45457,12 @@ var SessionConfigError = class extends Error {
|
|
|
45318
45457
|
}
|
|
45319
45458
|
};
|
|
45320
45459
|
function workflowAssetDirs(assetsDir, workflowId) {
|
|
45321
|
-
const root =
|
|
45322
|
-
return [root,
|
|
45460
|
+
const root = join42(assetsDir, "workflows", workflowId);
|
|
45461
|
+
return [root, join42(root, "inputs"), join42(root, "outputs"), join42(root, "generated")];
|
|
45323
45462
|
}
|
|
45324
45463
|
function sessionAssetDirs(assetsDir, sessionId) {
|
|
45325
|
-
const root =
|
|
45326
|
-
return [root,
|
|
45464
|
+
const root = join42(assetsDir, "sessions", sessionId);
|
|
45465
|
+
return [root, join42(root, "inputs"), join42(root, "outputs")];
|
|
45327
45466
|
}
|
|
45328
45467
|
function rosterNames(configDir) {
|
|
45329
45468
|
return [...loadRosterMap(configDir).values()].map((row) => String(row.name));
|
|
@@ -45373,7 +45512,7 @@ function workerFromRosterRow(name, row, project) {
|
|
|
45373
45512
|
function loadRosterMap(configDir) {
|
|
45374
45513
|
const byName = /* @__PURE__ */ new Map();
|
|
45375
45514
|
for (const [file, key] of [["agents.json", "agents"], ["gates.json", "gates"]]) {
|
|
45376
|
-
const path4 =
|
|
45515
|
+
const path4 = join42(configDir, file);
|
|
45377
45516
|
for (const row of loadRoster(path4, key)) {
|
|
45378
45517
|
const name = String(row.name).trim();
|
|
45379
45518
|
const lowered = name.toLowerCase();
|
|
@@ -45390,7 +45529,7 @@ function loadRoster(path4, key) {
|
|
|
45390
45529
|
if (!existsSync32(path4)) return [];
|
|
45391
45530
|
let parsed;
|
|
45392
45531
|
try {
|
|
45393
|
-
parsed = JSON.parse(
|
|
45532
|
+
parsed = JSON.parse(readFileSync32(path4, "utf8"));
|
|
45394
45533
|
} catch (error) {
|
|
45395
45534
|
throw new SessionConfigError(
|
|
45396
45535
|
`${key} roster at ${path4} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -45415,7 +45554,7 @@ function loadRoster(path4, key) {
|
|
|
45415
45554
|
});
|
|
45416
45555
|
}
|
|
45417
45556
|
function createSession(input) {
|
|
45418
|
-
const assetDir = input.mode === "workflow" && input.workflowId ?
|
|
45557
|
+
const assetDir = input.mode === "workflow" && input.workflowId ? join42("assets", "workflows", input.workflowId) : join42("assets", "sessions", input.id);
|
|
45419
45558
|
return {
|
|
45420
45559
|
schema: SESSION_SCHEMA,
|
|
45421
45560
|
id: input.id,
|
|
@@ -45428,10 +45567,10 @@ function createSession(input) {
|
|
|
45428
45567
|
};
|
|
45429
45568
|
}
|
|
45430
45569
|
function writeSession(assetsDir, session, dryRun = false) {
|
|
45431
|
-
const dir =
|
|
45432
|
-
const path4 =
|
|
45570
|
+
const dir = join42(assetsDir, "sessions", session.id);
|
|
45571
|
+
const path4 = join42(dir, "session.json");
|
|
45433
45572
|
if (!dryRun) {
|
|
45434
|
-
|
|
45573
|
+
mkdirSync26(dir, { recursive: true });
|
|
45435
45574
|
writeFileSync23(path4, `${JSON.stringify(session, null, 2)}
|
|
45436
45575
|
`, { encoding: "utf8" });
|
|
45437
45576
|
}
|
|
@@ -45440,7 +45579,7 @@ function writeSession(assetsDir, session, dryRun = false) {
|
|
|
45440
45579
|
|
|
45441
45580
|
// plugins/kxm/src/cli/hub.ts
|
|
45442
45581
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
45443
|
-
import { dirname as
|
|
45582
|
+
import { dirname as dirname22 } from "node:path";
|
|
45444
45583
|
import { homedir as homedir7 } from "node:os";
|
|
45445
45584
|
async function hubGet(url, fetchImpl) {
|
|
45446
45585
|
try {
|
|
@@ -45458,7 +45597,7 @@ async function hubGet(url, fetchImpl) {
|
|
|
45458
45597
|
}
|
|
45459
45598
|
function installProbeFrom(runtime) {
|
|
45460
45599
|
const partial = runtime.io.installProbe ?? {};
|
|
45461
|
-
const moduleDir = partial.moduleDir ??
|
|
45600
|
+
const moduleDir = partial.moduleDir ?? dirname22(fileURLToPath3(import.meta.url));
|
|
45462
45601
|
return {
|
|
45463
45602
|
moduleDir,
|
|
45464
45603
|
// Classify the install that is **running**, never the directory the caller
|
|
@@ -45479,13 +45618,13 @@ function moduleInstallRoot() {
|
|
|
45479
45618
|
try {
|
|
45480
45619
|
return findKxmRepoRoot(import.meta.url);
|
|
45481
45620
|
} catch {
|
|
45482
|
-
return
|
|
45621
|
+
return dirname22(fileURLToPath3(import.meta.url));
|
|
45483
45622
|
}
|
|
45484
45623
|
}
|
|
45485
45624
|
function warnIgnoredProjectUpdateYaml(runtime) {
|
|
45486
|
-
const projectFile =
|
|
45625
|
+
const projectFile = join43(runtime.dirs.workspace, "update.yaml");
|
|
45487
45626
|
if (!existsSync33(projectFile)) return;
|
|
45488
|
-
const userFile =
|
|
45627
|
+
const userFile = join43(kxmUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
45489
45628
|
runtime.io.stderr(`kxm: ignoring .kxm/update.yaml in ${runtime.dirs.workdir}; update settings are read only from ${userFile}
|
|
45490
45629
|
`);
|
|
45491
45630
|
}
|
|
@@ -45533,7 +45672,7 @@ async function cmdDash(runtime, options = {}) {
|
|
|
45533
45672
|
return 2;
|
|
45534
45673
|
}
|
|
45535
45674
|
const screen = requested;
|
|
45536
|
-
const dataPath =
|
|
45675
|
+
const dataPath = resolve28(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join43(runtime.dirs.state, "kxm.db"));
|
|
45537
45676
|
if (runtime.dryRun) {
|
|
45538
45677
|
print(runtime.io, runtime.json, {
|
|
45539
45678
|
ok: true,
|
|
@@ -45579,7 +45718,7 @@ async function cmdHub(runtime) {
|
|
|
45579
45718
|
config = loadKxmUpdateConfig(runtime.env);
|
|
45580
45719
|
} catch (error) {
|
|
45581
45720
|
if (error instanceof KxmUpdateConfigError) {
|
|
45582
|
-
const yamlPath =
|
|
45721
|
+
const yamlPath = join43(kxmUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
45583
45722
|
runtime.io.stderr(`kxm: ${error.message}; update check skipped; fix or remove ${yamlPath}
|
|
45584
45723
|
`);
|
|
45585
45724
|
} else {
|
|
@@ -45781,7 +45920,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45781
45920
|
const orphans = [];
|
|
45782
45921
|
for (const file of pids) {
|
|
45783
45922
|
try {
|
|
45784
|
-
const record = JSON.parse(
|
|
45923
|
+
const record = JSON.parse(readFileSync33(join43(runtime.dirs.state, file), "utf8"));
|
|
45785
45924
|
const expectedControl = file === "hub.pid" ? "hub.stop" : file.startsWith("worker-") ? `${file.slice(0, -4)}.stop` : void 0;
|
|
45786
45925
|
const expectedRole = file === "hub.pid" ? "hub" : file.startsWith("worker-") ? "worker" : void 0;
|
|
45787
45926
|
if (record.version !== 1 || !Number.isInteger(record.pid) || record.pid <= 0 || !record.startedAt || !expectedControl || record.controlFile !== expectedControl || record.role !== expectedRole) {
|
|
@@ -45801,7 +45940,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45801
45940
|
ignored.push(file);
|
|
45802
45941
|
continue;
|
|
45803
45942
|
}
|
|
45804
|
-
writeFileSync24(
|
|
45943
|
+
writeFileSync24(join43(runtime.dirs.state, record.controlFile), `${JSON.stringify({ startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {}, requestedAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
45805
45944
|
`, { encoding: "utf8", mode: 384 });
|
|
45806
45945
|
requested.push(file);
|
|
45807
45946
|
records.set(file, { pid: record.pid, startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {} });
|
|
@@ -45819,7 +45958,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45819
45958
|
while (Date.now() <= deadline && stopped.size < requested.length) {
|
|
45820
45959
|
for (const [file, record] of records) {
|
|
45821
45960
|
try {
|
|
45822
|
-
const current = JSON.parse(
|
|
45961
|
+
const current = JSON.parse(readFileSync33(join43(runtime.dirs.state, file), "utf8"));
|
|
45823
45962
|
if (current.pid !== record.pid || current.startedAt !== record.startedAt || current.generation !== record.generation || !processExists(record.pid)) stopped.add(file);
|
|
45824
45963
|
} catch {
|
|
45825
45964
|
stopped.add(file);
|
|
@@ -45832,7 +45971,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45832
45971
|
for (const file of orphans) {
|
|
45833
45972
|
while (Date.now() <= deadlineOrphans) {
|
|
45834
45973
|
try {
|
|
45835
|
-
const current = JSON.parse(
|
|
45974
|
+
const current = JSON.parse(readFileSync33(join43(runtime.dirs.state, file), "utf8"));
|
|
45836
45975
|
if (!Number.isInteger(current.serverPid) || !processExists(current.serverPid)) break;
|
|
45837
45976
|
} catch {
|
|
45838
45977
|
break;
|
|
@@ -45840,14 +45979,14 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45840
45979
|
await (runtime.io.sleep ?? ((ms) => new Promise((resolveSleep) => setTimeout(resolveSleep, ms))))(100);
|
|
45841
45980
|
}
|
|
45842
45981
|
try {
|
|
45843
|
-
const current = JSON.parse(
|
|
45982
|
+
const current = JSON.parse(readFileSync33(join43(runtime.dirs.state, file), "utf8"));
|
|
45844
45983
|
if (Number.isInteger(current.serverPid) && processExists(current.serverPid)) {
|
|
45845
45984
|
try {
|
|
45846
45985
|
process.kill(current.serverPid, "SIGKILL");
|
|
45847
45986
|
} catch {
|
|
45848
45987
|
}
|
|
45849
45988
|
}
|
|
45850
|
-
rmSync11(
|
|
45989
|
+
rmSync11(join43(runtime.dirs.state, file), { force: true });
|
|
45851
45990
|
} catch {
|
|
45852
45991
|
}
|
|
45853
45992
|
stopped.add(file);
|
|
@@ -45862,7 +46001,7 @@ async function cmdSessionStatus(runtime) {
|
|
|
45862
46001
|
const claims = [];
|
|
45863
46002
|
for (const file of names3.filter((name) => name.endsWith(".pid"))) {
|
|
45864
46003
|
try {
|
|
45865
|
-
const record = JSON.parse(
|
|
46004
|
+
const record = JSON.parse(readFileSync33(join43(stateDir, file), "utf8"));
|
|
45866
46005
|
claims.push({
|
|
45867
46006
|
file,
|
|
45868
46007
|
role: record.role,
|
|
@@ -45877,7 +46016,7 @@ async function cmdSessionStatus(runtime) {
|
|
|
45877
46016
|
const recoveries = [];
|
|
45878
46017
|
for (const file of names3.filter((name) => name.startsWith("worker-recovery-") && name.endsWith(".json"))) {
|
|
45879
46018
|
try {
|
|
45880
|
-
const envelope = JSON.parse(
|
|
46019
|
+
const envelope = JSON.parse(readFileSync33(join43(stateDir, file), "utf8"));
|
|
45881
46020
|
recoveries.push({
|
|
45882
46021
|
file,
|
|
45883
46022
|
reason: envelope.reason,
|
|
@@ -45992,7 +46131,7 @@ async function cmdSessionBrief(runtime, options = {}) {
|
|
|
45992
46131
|
print(runtime.io, runtime.json, { ok: true, command: "session brief", sessionToken }, sessionToken);
|
|
45993
46132
|
return 0;
|
|
45994
46133
|
}
|
|
45995
|
-
const dataPath =
|
|
46134
|
+
const dataPath = resolve28(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join43(runtime.dirs.state, "kxm.db"));
|
|
45996
46135
|
const env = {
|
|
45997
46136
|
...runtime.env,
|
|
45998
46137
|
KXM_STATE_DIR: runtime.dirs.state,
|
|
@@ -46018,7 +46157,7 @@ async function cmdSessionBrief(runtime, options = {}) {
|
|
|
46018
46157
|
writeCache: !runtime.dryRun
|
|
46019
46158
|
});
|
|
46020
46159
|
if (runtime.dryRun) {
|
|
46021
|
-
if (!readCachedSessionBrief(runtime.dirs.state)) planned.push({ action: "write", target:
|
|
46160
|
+
if (!readCachedSessionBrief(runtime.dirs.state)) planned.push({ action: "write", target: join43(runtime.dirs.state, "session-brief.json") });
|
|
46022
46161
|
print(runtime.io, runtime.json, { ...brief, dryRun: true, planned }, [
|
|
46023
46162
|
options.status ? brief.statusLine : formatSessionBriefText(brief),
|
|
46024
46163
|
...planned.map((change) => `dry run: would ${change.action} ${change.target}`)
|
|
@@ -46041,7 +46180,7 @@ Session token: ${sessionToken}
|
|
|
46041
46180
|
return 0;
|
|
46042
46181
|
}
|
|
46043
46182
|
async function cmdSessionStart(runtime, options) {
|
|
46044
|
-
const id = options.id?.trim() || `session_${
|
|
46183
|
+
const id = options.id?.trim() || `session_${randomUUID13().replaceAll("-", "").slice(0, 12)}`;
|
|
46045
46184
|
const workflowId = options.workflow?.trim();
|
|
46046
46185
|
const mix = options.mix?.trim();
|
|
46047
46186
|
if (workflowId && mix) {
|
|
@@ -46078,7 +46217,7 @@ async function cmdSessionStart(runtime, options) {
|
|
|
46078
46217
|
...workflowId ? workflowAssetDirs(runtime.dirs.assets, workflowId) : []
|
|
46079
46218
|
];
|
|
46080
46219
|
if (!runtime.dryRun) {
|
|
46081
|
-
for (const directory of created)
|
|
46220
|
+
for (const directory of created) mkdirSync27(directory, { recursive: true });
|
|
46082
46221
|
writeSession(runtime.dirs.assets, session);
|
|
46083
46222
|
}
|
|
46084
46223
|
print(runtime.io, runtime.json, {
|
|
@@ -46094,15 +46233,15 @@ async function cmdSessionStart(runtime, options) {
|
|
|
46094
46233
|
// plugins/kxm/src/cli/system.ts
|
|
46095
46234
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
46096
46235
|
import { createHash as createHash16 } from "node:crypto";
|
|
46097
|
-
import { existsSync as existsSync40, mkdtempSync as mkdtempSync3, readFileSync as
|
|
46236
|
+
import { existsSync as existsSync40, mkdtempSync as mkdtempSync3, readFileSync as readFileSync38, rmSync as rmSync13 } from "node:fs";
|
|
46098
46237
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
46099
|
-
import { join as
|
|
46238
|
+
import { join as join49, resolve as resolve33 } from "node:path";
|
|
46100
46239
|
import { createInterface as createInterface3 } from "node:readline";
|
|
46101
46240
|
|
|
46102
46241
|
// plugins/kxm/src/improve.ts
|
|
46103
46242
|
import { createHash as createHash15 } from "node:crypto";
|
|
46104
|
-
import { existsSync as existsSync34, mkdirSync as
|
|
46105
|
-
import { join as
|
|
46243
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync28, writeFileSync as writeFileSync25 } from "node:fs";
|
|
46244
|
+
import { join as join44, relative as relative7, resolve as resolve29 } from "node:path";
|
|
46106
46245
|
var CANDIDATE_SCHEMA = "kxm.candidate.v1";
|
|
46107
46246
|
var IMPROVEMENT_REPORT_SCHEMA = "kxm.improvement-report.v2";
|
|
46108
46247
|
function classifyCandidateKind(stepId, agentRole) {
|
|
@@ -46357,8 +46496,8 @@ function groupRoutingRecords(records, options = {}) {
|
|
|
46357
46496
|
}).map((entry) => entry.row);
|
|
46358
46497
|
}
|
|
46359
46498
|
function buildImprovementReport(records, options = {}) {
|
|
46360
|
-
const projectRoot = options.projectRoot ?
|
|
46361
|
-
const candidatesDir = options.candidatesDir ?
|
|
46499
|
+
const projectRoot = options.projectRoot ? resolve29(options.projectRoot) : process.cwd();
|
|
46500
|
+
const candidatesDir = options.candidatesDir ? resolve29(options.candidatesDir) : join44(projectRoot, ".kxm", "candidates");
|
|
46362
46501
|
const promotionPolicy = options.promotionPolicy ?? "manual_pr";
|
|
46363
46502
|
const groups = groupRoutingRecords(records, options);
|
|
46364
46503
|
const candidates = [];
|
|
@@ -46372,8 +46511,8 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46372
46511
|
group.workflowId
|
|
46373
46512
|
);
|
|
46374
46513
|
const diffFileName = `${group.candidateId}.diff`;
|
|
46375
|
-
const diffFilePath =
|
|
46376
|
-
const relDiffPath =
|
|
46514
|
+
const diffFilePath = join44(candidatesDir, diffFileName);
|
|
46515
|
+
const relDiffPath = relative7(projectRoot, diffFilePath).replace(/\\/g, "/");
|
|
46377
46516
|
const candidate = {
|
|
46378
46517
|
schema: CANDIDATE_SCHEMA,
|
|
46379
46518
|
id: group.candidateId,
|
|
@@ -46395,10 +46534,10 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46395
46534
|
};
|
|
46396
46535
|
if (!options.dryRun) {
|
|
46397
46536
|
if (!existsSync34(candidatesDir)) {
|
|
46398
|
-
|
|
46537
|
+
mkdirSync28(candidatesDir, { recursive: true });
|
|
46399
46538
|
}
|
|
46400
46539
|
writeFileSync25(diffFilePath, diff, "utf8");
|
|
46401
|
-
const jsonFilePath =
|
|
46540
|
+
const jsonFilePath = join44(candidatesDir, `${group.candidateId}.json`);
|
|
46402
46541
|
writeFileSync25(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
|
|
46403
46542
|
}
|
|
46404
46543
|
candidates.push(candidate);
|
|
@@ -46427,9 +46566,9 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46427
46566
|
}
|
|
46428
46567
|
function writeImprovementReport(improvementsDir, report2, dryRun = false) {
|
|
46429
46568
|
const stamp = report2.createdAt.replace(/[:.]/g, "-");
|
|
46430
|
-
const path4 =
|
|
46569
|
+
const path4 = join44(improvementsDir, `${stamp}.json`);
|
|
46431
46570
|
if (!dryRun) {
|
|
46432
|
-
|
|
46571
|
+
mkdirSync28(improvementsDir, { recursive: true });
|
|
46433
46572
|
writeFileSync25(path4, `${JSON.stringify(report2, null, 2)}
|
|
46434
46573
|
`, { encoding: "utf8" });
|
|
46435
46574
|
}
|
|
@@ -46507,7 +46646,7 @@ function evaluatePromotionPolicy(candidate, policy = "manual_pr", options = {})
|
|
|
46507
46646
|
|
|
46508
46647
|
// plugins/kxm/src/improve-sources.ts
|
|
46509
46648
|
import { existsSync as existsSync35 } from "node:fs";
|
|
46510
|
-
import { resolve as
|
|
46649
|
+
import { resolve as resolve30 } from "node:path";
|
|
46511
46650
|
var ENGINE_EVENTS_SQL = "SELECT run_id, sequence, event_type, payload FROM events WHERE event_type IN ('routing.attempt.recorded','step.entered','run.status_changed') ORDER BY run_id, sequence";
|
|
46512
46651
|
var SIMULATED_HARNESS = "driver-simulated";
|
|
46513
46652
|
function parsePayload(text) {
|
|
@@ -46618,7 +46757,7 @@ function loadRoutingSources(options) {
|
|
|
46618
46757
|
const projectRoot = discoverKxmProjectRoot(options.cwd);
|
|
46619
46758
|
const reads = [];
|
|
46620
46759
|
if (options.file !== void 0) {
|
|
46621
|
-
reads.push(readJsonlSource("file",
|
|
46760
|
+
reads.push(readJsonlSource("file", resolve30(options.cwd, options.file)));
|
|
46622
46761
|
} else {
|
|
46623
46762
|
if (projectRoot !== void 0) reads.push(readEngineRoutingRecords(kxmProjectRunEventsPath(projectRoot, options.env)));
|
|
46624
46763
|
reads.push(readJsonlSource("telemetry", telemetryPath(options.logsDir)));
|
|
@@ -46649,8 +46788,8 @@ function loadRoutingSources(options) {
|
|
|
46649
46788
|
|
|
46650
46789
|
// plugins/kxm/src/modes.ts
|
|
46651
46790
|
var import_yaml17 = __toESM(require_dist(), 1);
|
|
46652
|
-
import { existsSync as existsSync36, readFileSync as
|
|
46653
|
-
import { join as
|
|
46791
|
+
import { existsSync as existsSync36, readFileSync as readFileSync35 } from "node:fs";
|
|
46792
|
+
import { join as join45 } from "node:path";
|
|
46654
46793
|
var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
46655
46794
|
schema: "kxm.modes.v1",
|
|
46656
46795
|
majorModes: {
|
|
@@ -46713,12 +46852,12 @@ function loadModesConfig(projectRoot) {
|
|
|
46713
46852
|
if (!projectRoot) {
|
|
46714
46853
|
return DEFAULT_MODES_CONFIG;
|
|
46715
46854
|
}
|
|
46716
|
-
const modesPath =
|
|
46855
|
+
const modesPath = join45(projectRoot, ".kxm", "modes.yaml");
|
|
46717
46856
|
if (!existsSync36(modesPath)) {
|
|
46718
46857
|
return DEFAULT_MODES_CONFIG;
|
|
46719
46858
|
}
|
|
46720
46859
|
try {
|
|
46721
|
-
const raw =
|
|
46860
|
+
const raw = readFileSync35(modesPath, "utf8");
|
|
46722
46861
|
const parsed = (0, import_yaml17.parse)(raw);
|
|
46723
46862
|
if (parsed && parsed.schema === "kxm.modes.v1" && parsed.majorModes) {
|
|
46724
46863
|
return {
|
|
@@ -46804,11 +46943,11 @@ function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog
|
|
|
46804
46943
|
estimatedTokens: estimateTokens(baseSystemPromptChars)
|
|
46805
46944
|
});
|
|
46806
46945
|
for (const relPath of resolved.contextFiles) {
|
|
46807
|
-
const fullPath =
|
|
46946
|
+
const fullPath = join45(projectRoot, relPath);
|
|
46808
46947
|
let chars = 0;
|
|
46809
46948
|
if (existsSync36(fullPath)) {
|
|
46810
46949
|
try {
|
|
46811
|
-
chars =
|
|
46950
|
+
chars = readFileSync35(fullPath, "utf8").length;
|
|
46812
46951
|
} catch {
|
|
46813
46952
|
chars = 0;
|
|
46814
46953
|
}
|
|
@@ -46940,9 +47079,9 @@ ${divider}
|
|
|
46940
47079
|
|
|
46941
47080
|
// plugins/kxm/src/ssh-remote.ts
|
|
46942
47081
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
46943
|
-
import { existsSync as existsSync37, mkdirSync as
|
|
47082
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync29, readFileSync as readFileSync36, readdirSync as readdirSync13, rmSync as rmSync12, statSync as statSync5 } from "node:fs";
|
|
46944
47083
|
import { homedir as homedir8 } from "node:os";
|
|
46945
|
-
import { join as
|
|
47084
|
+
import { join as join46, resolve as resolve31 } from "node:path";
|
|
46946
47085
|
var MAX_SSH_OUTPUT_BYTES = 50 * 1024;
|
|
46947
47086
|
var MAX_SSH_OUTPUT_LINES = 2e3;
|
|
46948
47087
|
var DEFAULT_SOCKET_DIR = ".kxm/run/ssh-sockets";
|
|
@@ -46968,12 +47107,12 @@ function truncateSshOutput(raw) {
|
|
|
46968
47107
|
return { text, truncated };
|
|
46969
47108
|
}
|
|
46970
47109
|
function parseSshConfig(configPath) {
|
|
46971
|
-
const targetPath = configPath ??
|
|
47110
|
+
const targetPath = configPath ?? join46(homedir8(), ".ssh", "config");
|
|
46972
47111
|
if (!existsSync37(targetPath)) {
|
|
46973
47112
|
return [];
|
|
46974
47113
|
}
|
|
46975
47114
|
try {
|
|
46976
|
-
const content =
|
|
47115
|
+
const content = readFileSync36(targetPath, "utf-8");
|
|
46977
47116
|
const lines = content.split("\n");
|
|
46978
47117
|
const hosts = [];
|
|
46979
47118
|
let currentHosts = [];
|
|
@@ -47050,15 +47189,15 @@ function resolveSshHostG(host, execFn = spawnSync7) {
|
|
|
47050
47189
|
}
|
|
47051
47190
|
}
|
|
47052
47191
|
function ensureSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
47053
|
-
const resolved =
|
|
47192
|
+
const resolved = resolve31(socketDir);
|
|
47054
47193
|
if (!existsSync37(resolved)) {
|
|
47055
|
-
|
|
47194
|
+
mkdirSync29(resolved, { recursive: true, mode: 448 });
|
|
47056
47195
|
}
|
|
47057
47196
|
return resolved;
|
|
47058
47197
|
}
|
|
47059
47198
|
function buildSshArgs(options) {
|
|
47060
47199
|
const socketDir = ensureSocketDir(options.socketDir ?? DEFAULT_SOCKET_DIR);
|
|
47061
|
-
const controlPath =
|
|
47200
|
+
const controlPath = join46(socketDir, "%C");
|
|
47062
47201
|
const persist = options.controlPersist ?? DEFAULT_CONTROL_PERSIST;
|
|
47063
47202
|
const args = [
|
|
47064
47203
|
"-o",
|
|
@@ -47083,7 +47222,7 @@ function buildSshArgs(options) {
|
|
|
47083
47222
|
}
|
|
47084
47223
|
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
47085
47224
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
47086
|
-
const controlPath =
|
|
47225
|
+
const controlPath = join46(resolvedDir, "%C");
|
|
47087
47226
|
try {
|
|
47088
47227
|
const result = execFn("ssh", ["-O", "check", "-o", `ControlPath=${controlPath}`, host], {
|
|
47089
47228
|
encoding: "utf-8"
|
|
@@ -47095,7 +47234,7 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
47095
47234
|
}
|
|
47096
47235
|
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
47097
47236
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
47098
|
-
const controlPath =
|
|
47237
|
+
const controlPath = join46(resolvedDir, "%C");
|
|
47099
47238
|
try {
|
|
47100
47239
|
const result = execFn("ssh", ["-O", "stop", "-o", `ControlPath=${controlPath}`, host], {
|
|
47101
47240
|
encoding: "utf-8"
|
|
@@ -47540,9 +47679,9 @@ complete -c kxm -n "__fish_seen_subcommand_from goal" -a "create list get"
|
|
|
47540
47679
|
}
|
|
47541
47680
|
|
|
47542
47681
|
// plugins/kxm/src/completion-install.ts
|
|
47543
|
-
import { existsSync as existsSync38, mkdirSync as
|
|
47682
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync30, readFileSync as readFileSync37, writeFileSync as writeFileSync26 } from "node:fs";
|
|
47544
47683
|
import { homedir as homedir9 } from "node:os";
|
|
47545
|
-
import { basename as basename9, delimiter, dirname as
|
|
47684
|
+
import { basename as basename9, delimiter, dirname as dirname24, isAbsolute as isAbsolute10, join as join47, resolve as resolve32 } from "node:path";
|
|
47546
47685
|
var COMPLETION_MARKER = "# kxm completion";
|
|
47547
47686
|
var PATH_MARKER = "# kxm path";
|
|
47548
47687
|
function detectShell(env = process.env, platform = process.platform) {
|
|
@@ -47558,31 +47697,31 @@ function effectiveHome(options) {
|
|
|
47558
47697
|
const env = options.env ?? process.env;
|
|
47559
47698
|
if (options.homeDir) return options.homeDir;
|
|
47560
47699
|
const envHome = env.HOME?.trim() ?? env.USERPROFILE?.trim();
|
|
47561
|
-
return envHome && envHome.length > 0 ?
|
|
47700
|
+
return envHome && envHome.length > 0 ? resolve32(envHome) : homedir9();
|
|
47562
47701
|
}
|
|
47563
47702
|
function completionScriptPath(shell, options = {}) {
|
|
47564
47703
|
const env = options.env ?? process.env;
|
|
47565
47704
|
const explicit = options.configDir ?? env.KXM_USER_CONFIG_DIR?.trim();
|
|
47566
|
-
const base = explicit && explicit.length > 0 ?
|
|
47567
|
-
return
|
|
47705
|
+
const base = explicit && explicit.length > 0 ? resolve32(explicit) : resolve32(effectiveHome(options), ".config", "kxm");
|
|
47706
|
+
return join47(base, "completions", `kxm.${shell}`);
|
|
47568
47707
|
}
|
|
47569
47708
|
function bashRcCandidate(options) {
|
|
47570
47709
|
const home = effectiveHome(options);
|
|
47571
|
-
const candidates = [
|
|
47710
|
+
const candidates = [join47(home, ".bashrc"), join47(home, ".bash_profile")];
|
|
47572
47711
|
const existing = candidates.find((candidate) => existsSync38(candidate));
|
|
47573
47712
|
return existing ?? candidates[0];
|
|
47574
47713
|
}
|
|
47575
47714
|
function zshRcCandidate(options) {
|
|
47576
47715
|
const env = options.env ?? process.env;
|
|
47577
47716
|
const home = effectiveHome(options);
|
|
47578
|
-
if (env.ZDOTDIR?.trim()) return
|
|
47579
|
-
return
|
|
47717
|
+
if (env.ZDOTDIR?.trim()) return join47(resolve32(env.ZDOTDIR.trim()), ".zshrc");
|
|
47718
|
+
return join47(home, ".zshrc");
|
|
47580
47719
|
}
|
|
47581
47720
|
function fishCompletionTarget(shell, options) {
|
|
47582
47721
|
const env = options.env ?? process.env;
|
|
47583
47722
|
const home = effectiveHome(options);
|
|
47584
|
-
if (env.XDG_CONFIG_HOME?.trim()) return
|
|
47585
|
-
return
|
|
47723
|
+
if (env.XDG_CONFIG_HOME?.trim()) return join47(resolve32(env.XDG_CONFIG_HOME.trim()), "fish", "completions", "kxm.fish");
|
|
47724
|
+
return join47(home, ".config", "fish", "completions", "kxm.fish");
|
|
47586
47725
|
}
|
|
47587
47726
|
function completionRcTarget(shell, options = {}) {
|
|
47588
47727
|
if (shell === "fish") {
|
|
@@ -47615,15 +47754,15 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47615
47754
|
const { rcFile } = completionRcTarget(shell, options);
|
|
47616
47755
|
const script = generateShellCompletion(shell);
|
|
47617
47756
|
const existingScript = existsSync38(scriptPath);
|
|
47618
|
-
const existingScriptMatches = existingScript &&
|
|
47757
|
+
const existingScriptMatches = existingScript && readFileSync37(scriptPath, "utf8") === script;
|
|
47619
47758
|
let rcModified = false;
|
|
47620
47759
|
let alreadyInstalled = false;
|
|
47621
47760
|
if (shell === "fish") {
|
|
47622
47761
|
const fishTarget = fishCompletionTarget(shell, options);
|
|
47623
|
-
const fishInstalled = existsSync38(fishTarget) &&
|
|
47762
|
+
const fishInstalled = existsSync38(fishTarget) && readFileSync37(fishTarget, "utf8") === script;
|
|
47624
47763
|
alreadyInstalled = fishInstalled;
|
|
47625
47764
|
if (!options.dryRun && (!fishInstalled || options.overwrite)) {
|
|
47626
|
-
|
|
47765
|
+
mkdirSync30(resolve32(fishTarget, ".."), { recursive: true });
|
|
47627
47766
|
writeFileSync26(fishTarget, script, { encoding: "utf8" });
|
|
47628
47767
|
}
|
|
47629
47768
|
return {
|
|
@@ -47637,12 +47776,12 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47637
47776
|
}
|
|
47638
47777
|
if (rcFile) {
|
|
47639
47778
|
const line = sourceLine(shell, scriptPath);
|
|
47640
|
-
const rcContent = existsSync38(rcFile) ?
|
|
47779
|
+
const rcContent = existsSync38(rcFile) ? readFileSync37(rcFile, "utf8") : "";
|
|
47641
47780
|
alreadyInstalled = rcContent.includes(line) || rcContent.includes(`${COMPLETION_MARKER}`);
|
|
47642
47781
|
}
|
|
47643
47782
|
if (!options.dryRun) {
|
|
47644
47783
|
if (!existingScriptMatches || options.overwrite) {
|
|
47645
|
-
|
|
47784
|
+
mkdirSync30(resolve32(scriptPath, ".."), { recursive: true });
|
|
47646
47785
|
writeFileSync26(scriptPath, script, { encoding: "utf8" });
|
|
47647
47786
|
}
|
|
47648
47787
|
if (rcFile && !alreadyInstalled) {
|
|
@@ -47652,8 +47791,8 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47652
47791
|
${marker}
|
|
47653
47792
|
${line}
|
|
47654
47793
|
`;
|
|
47655
|
-
|
|
47656
|
-
writeFileSync26(rcFile, (existsSync38(rcFile) ?
|
|
47794
|
+
mkdirSync30(resolve32(rcFile, ".."), { recursive: true });
|
|
47795
|
+
writeFileSync26(rcFile, (existsSync38(rcFile) ? readFileSync37(rcFile, "utf8") : "") + stanza, { encoding: "utf8" });
|
|
47657
47796
|
rcModified = true;
|
|
47658
47797
|
}
|
|
47659
47798
|
}
|
|
@@ -47668,15 +47807,15 @@ ${line}
|
|
|
47668
47807
|
}
|
|
47669
47808
|
function kxmBinDir(env = process.env) {
|
|
47670
47809
|
const argv1 = env.KXM_ENTRY ?? process.argv[1];
|
|
47671
|
-
if (argv1 &&
|
|
47672
|
-
const dir =
|
|
47673
|
-
if (existsSync38(
|
|
47810
|
+
if (argv1 && isAbsolute10(argv1)) {
|
|
47811
|
+
const dir = dirname24(argv1);
|
|
47812
|
+
if (existsSync38(join47(dir, process.platform === "win32" ? "kxm.cmd" : "kxm"))) return dir;
|
|
47674
47813
|
}
|
|
47675
47814
|
const pathEnv = env.PATH ?? "";
|
|
47676
47815
|
for (const part of pathEnv.split(delimiter)) {
|
|
47677
47816
|
if (!part) continue;
|
|
47678
|
-
const candidate =
|
|
47679
|
-
if (existsSync38(candidate)) return
|
|
47817
|
+
const candidate = resolve32(part, process.platform === "win32" ? "kxm.cmd" : "kxm");
|
|
47818
|
+
if (existsSync38(candidate)) return resolve32(part);
|
|
47680
47819
|
}
|
|
47681
47820
|
return void 0;
|
|
47682
47821
|
}
|
|
@@ -47694,10 +47833,10 @@ function installPathEntry(shellInput, options = {}) {
|
|
|
47694
47833
|
}
|
|
47695
47834
|
const { rcFile } = completionRcTarget(shell, options);
|
|
47696
47835
|
const line = pathLine(binDir);
|
|
47697
|
-
const rcContent = existsSync38(rcFile ?? "") ?
|
|
47836
|
+
const rcContent = existsSync38(rcFile ?? "") ? readFileSync37(rcFile, "utf8") : "";
|
|
47698
47837
|
const alreadyInstalled = rcContent.includes(binDir) || (options.env?.PATH ?? process.env.PATH ?? "").split(delimiter).includes(binDir);
|
|
47699
47838
|
if (!options.dryRun && rcFile && !alreadyInstalled) {
|
|
47700
|
-
|
|
47839
|
+
mkdirSync30(dirname24(rcFile), { recursive: true });
|
|
47701
47840
|
writeFileSync26(rcFile, rcContent + `
|
|
47702
47841
|
${PATH_MARKER}
|
|
47703
47842
|
${line}
|
|
@@ -47708,8 +47847,8 @@ ${line}
|
|
|
47708
47847
|
|
|
47709
47848
|
// plugins/kxm/src/init-guide-setup.ts
|
|
47710
47849
|
var import_yaml18 = __toESM(require_dist(), 1);
|
|
47711
|
-
import { existsSync as existsSync39, mkdirSync as
|
|
47712
|
-
import { dirname as
|
|
47850
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync31, writeFileSync as writeFileSync27 } from "node:fs";
|
|
47851
|
+
import { dirname as dirname25, join as join48 } from "node:path";
|
|
47713
47852
|
var ADMITTED_GUIDE_BINDINGS = Object.freeze({
|
|
47714
47853
|
"anthropic/claude-fable-5.1": { harness: "claude", provider: "anthropic", model: "fable" },
|
|
47715
47854
|
"anthropic/fable": { harness: "claude", provider: "anthropic", model: "fable" },
|
|
@@ -48100,13 +48239,13 @@ function renderGuideSetupFiles(projectRoot, plan) {
|
|
|
48100
48239
|
const stage = roleStages.get(role);
|
|
48101
48240
|
if (!stage) continue;
|
|
48102
48241
|
files.push({
|
|
48103
|
-
path:
|
|
48242
|
+
path: join48(projectRoot, ".kxm", "agents", `${role}.yaml`),
|
|
48104
48243
|
content: (0, import_yaml18.stringify)(agentDocument(role, stage, binding))
|
|
48105
48244
|
});
|
|
48106
48245
|
}
|
|
48107
48246
|
for (const workflow of plan.workflows) {
|
|
48108
48247
|
files.push({
|
|
48109
|
-
path:
|
|
48248
|
+
path: join48(projectRoot, ".kxm", "workflows", `${workflow.slug}.yaml`),
|
|
48110
48249
|
content: (0, import_yaml18.stringify)(workflowDocument(workflow))
|
|
48111
48250
|
});
|
|
48112
48251
|
}
|
|
@@ -48123,8 +48262,8 @@ function mergeGuideRouteAdmission(projectRoot, plan) {
|
|
|
48123
48262
|
}
|
|
48124
48263
|
if (added.length === 0) return added;
|
|
48125
48264
|
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
48126
|
-
const path4 =
|
|
48127
|
-
|
|
48265
|
+
const path4 = join48(projectRoot, ".kxm", "routes.yaml");
|
|
48266
|
+
mkdirSync31(dirname25(path4), { recursive: true });
|
|
48128
48267
|
writeFileSync27(path4, (0, import_yaml18.stringify)(policy), "utf8");
|
|
48129
48268
|
return added;
|
|
48130
48269
|
}
|
|
@@ -48136,7 +48275,7 @@ function writeGuideSetupFiles(files) {
|
|
|
48136
48275
|
existed.push(file.path);
|
|
48137
48276
|
continue;
|
|
48138
48277
|
}
|
|
48139
|
-
|
|
48278
|
+
mkdirSync31(dirname25(file.path), { recursive: true });
|
|
48140
48279
|
writeFileSync27(file.path, file.content, "utf8");
|
|
48141
48280
|
written.push(file.path);
|
|
48142
48281
|
}
|
|
@@ -48200,7 +48339,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
48200
48339
|
detail: `release v${notice.latest} has no sha256 digest for ${name}; refusing to install`
|
|
48201
48340
|
};
|
|
48202
48341
|
}
|
|
48203
|
-
const releaseDir = mkdtempSync3(
|
|
48342
|
+
const releaseDir = mkdtempSync3(join49(tmpdir2(), "kxm-pkg-update-"));
|
|
48204
48343
|
try {
|
|
48205
48344
|
const planned = planKxmPackageUpdate(notice.source, notice.latest, releaseDir, notice.asset);
|
|
48206
48345
|
if (runtime.dryRun) {
|
|
@@ -48209,7 +48348,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
48209
48348
|
for (const step of planned) {
|
|
48210
48349
|
if (step.kind === "verify") {
|
|
48211
48350
|
if (!verifyReleaseAssetDigest(step.path, step.sha256)) {
|
|
48212
|
-
const actual = existsSync40(step.path) ? createHash16("sha256").update(
|
|
48351
|
+
const actual = existsSync40(step.path) ? createHash16("sha256").update(readFileSync38(step.path)).digest("hex") : "missing";
|
|
48213
48352
|
return {
|
|
48214
48353
|
ok: false,
|
|
48215
48354
|
error: "release_digest_mismatch",
|
|
@@ -48486,13 +48625,13 @@ async function cmdValidate(runtime, fileFlag) {
|
|
|
48486
48625
|
return 2;
|
|
48487
48626
|
}
|
|
48488
48627
|
const selectedFile = explicitFile || configuredFile;
|
|
48489
|
-
const file = selectedFile ?
|
|
48628
|
+
const file = selectedFile ? resolve33(runtime.cwd, selectedFile) : void 0;
|
|
48490
48629
|
if (file && !existsSync40(file)) {
|
|
48491
48630
|
printWorker(runtime, worker, { ok: false, command: "validate", error: "file_not_found", file }, `workflow file not found: ${file}`);
|
|
48492
48631
|
return 1;
|
|
48493
48632
|
}
|
|
48494
48633
|
try {
|
|
48495
|
-
const raw = file ?
|
|
48634
|
+
const raw = file ? readFileSync38(file, "utf8") : inline;
|
|
48496
48635
|
const warnings = [];
|
|
48497
48636
|
const definitions = parseWorkflowDefinitions(raw, runtime.env, (message) => warnings.push(message));
|
|
48498
48637
|
const secretEnvs = definitions.map((definition) => ({
|
|
@@ -48517,7 +48656,7 @@ async function cmdValidate(runtime, fileFlag) {
|
|
|
48517
48656
|
}
|
|
48518
48657
|
async function cmdArtifactsExist(runtime, pathFlag) {
|
|
48519
48658
|
const worker = gateOf(runtime, "artifacts-exist");
|
|
48520
|
-
const checked = verifyArtifactExists(runtime.dirs.assets,
|
|
48659
|
+
const checked = verifyArtifactExists(runtime.dirs.assets, resolve33(runtime.cwd, pathFlag));
|
|
48521
48660
|
if (!checked.ok) {
|
|
48522
48661
|
printWorker(
|
|
48523
48662
|
runtime,
|
|
@@ -48573,7 +48712,7 @@ async function cmdImprove(runtime, options = {}) {
|
|
|
48573
48712
|
print(runtime.io, runtime.json, { ok: false, command: "improve", error: "config_invalid", detail: message }, `config_invalid: ${message}`);
|
|
48574
48713
|
return 1;
|
|
48575
48714
|
}
|
|
48576
|
-
const candidatesDir = options.outDir ?
|
|
48715
|
+
const candidatesDir = options.outDir ? resolve33(runtime.cwd, options.outDir) : join49(root, ".kxm", "candidates");
|
|
48577
48716
|
const report2 = buildImprovementReport(loaded.records, {
|
|
48578
48717
|
candidatesDir,
|
|
48579
48718
|
projectRoot: root,
|
|
@@ -48582,7 +48721,7 @@ async function cmdImprove(runtime, options = {}) {
|
|
|
48582
48721
|
autoThreshold: config.improvement.autoThreshold,
|
|
48583
48722
|
halfLifeDays: config.improvement.telemetryHalfLifeDays
|
|
48584
48723
|
});
|
|
48585
|
-
const reportDir =
|
|
48724
|
+
const reportDir = join49(runtime.dirs.assets, "improvements");
|
|
48586
48725
|
const reportPath = writeImprovementReport(reportDir, report2, runtime.dryRun);
|
|
48587
48726
|
const text = [
|
|
48588
48727
|
"Sources:",
|
|
@@ -48728,7 +48867,7 @@ async function maybeOfferCompletionInstall(runtime) {
|
|
|
48728
48867
|
const { rcFile } = completionRcTarget(shell, { env: runtime.env });
|
|
48729
48868
|
if (rcFile && existsSync40(rcFile)) {
|
|
48730
48869
|
try {
|
|
48731
|
-
if (
|
|
48870
|
+
if (readFileSync38(rcFile, "utf8").includes(scriptPath)) return;
|
|
48732
48871
|
} catch {
|
|
48733
48872
|
}
|
|
48734
48873
|
}
|
|
@@ -48891,7 +49030,7 @@ async function cmdRoutingReport(runtime, options) {
|
|
|
48891
49030
|
let catalog;
|
|
48892
49031
|
if (includeEquivalentListCost) {
|
|
48893
49032
|
try {
|
|
48894
|
-
const pricesPath = options.prices ?
|
|
49033
|
+
const pricesPath = options.prices ? resolve33(runtime.cwd, options.prices) : join49(runtime.dirs.workspace, "prices.yaml");
|
|
48895
49034
|
catalog = loadPriceCatalog(pricesPath);
|
|
48896
49035
|
} catch {
|
|
48897
49036
|
}
|
|
@@ -49269,11 +49408,11 @@ function createProgram(ctx, result) {
|
|
|
49269
49408
|
maybeOfferGuideSetup
|
|
49270
49409
|
});
|
|
49271
49410
|
});
|
|
49272
|
-
addGlobalOptions(program2.command("backup").description("Create a verified SQLite backup of
|
|
49411
|
+
addGlobalOptions(program2.command("backup").description("Create a verified SQLite backup of this project's hub store and Runtime event store, with a hashed manifest")).option("--out <dir>", "Directory to write backup and manifest").option("--all-projects", "Also back up the shared Runtime registry and every project's event store on this machine").action(async function backupAction(options) {
|
|
49273
49412
|
result.code = await cmdBackup(runtimeFrom(ctx, this), options);
|
|
49274
49413
|
});
|
|
49275
|
-
addGlobalOptions(program2.command("restore <manifest>").description("Restore SQLite stores from a verified backup manifest")).action(async function restoreAction(manifest) {
|
|
49276
|
-
result.code = await cmdRestore(runtimeFrom(ctx, this), manifest);
|
|
49414
|
+
addGlobalOptions(program2.command("restore <manifest>").description("Restore this project's SQLite stores from a verified backup manifest; refuses while the Runtime or hub is running")).option("--all-projects", "Also restore the shared Runtime registry and other projects' event stores the backup holds").action(async function restoreAction(manifest, options) {
|
|
49415
|
+
result.code = await cmdRestore(runtimeFrom(ctx, this), manifest, options);
|
|
49277
49416
|
});
|
|
49278
49417
|
addGlobalOptions(program2.command("run").description("Create a KXM run (offline-first; kxm runs drive <runId> --simulated executes it model-free)").argument("[workflow]", "Workflow id to run").argument("[prompt...]", "Run prompt (events keep its hash; the full text is kept in a local 0600 sidecar file)").action(async function runAction(workflow2, promptParts) {
|
|
49279
49418
|
result.code = await cmdKxmRun(runtimeFrom(ctx, this), workflow2, promptParts);
|
|
@@ -49740,7 +49879,7 @@ async function runCli(argv, env = process.env, io = { stdout: (text) => process.
|
|
|
49740
49879
|
throw error;
|
|
49741
49880
|
}
|
|
49742
49881
|
}
|
|
49743
|
-
if (process.argv[1] &&
|
|
49882
|
+
if (process.argv[1] && resolve34(process.argv[1]) === fileURLToPath4(import.meta.url)) {
|
|
49744
49883
|
const code = await runCli(process.argv.slice(2));
|
|
49745
49884
|
process.exitCode = code;
|
|
49746
49885
|
}
|