@kontextmind/kxm 0.7.96 → 0.7.98
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/.kxm/workflows/default.yaml +2 -0
- package/CHANGELOG.md +61 -2
- package/docs/concepts/architecture.md +1 -1
- package/docs/concepts/data-and-storage.md +1 -1
- package/docs/concepts/trust-model.md +3 -2
- package/docs/contracts/routing.md +1 -1
- package/docs/contributing/test-matrix.md +6 -5
- package/docs/glossary.md +1 -1
- package/docs/guides/peer-messaging.md +2 -2
- package/docs/guides/pi-workers.md +1 -1
- package/docs/guides/webhook-workflows.md +53 -18
- package/docs/operations/backup-and-restore.md +43 -24
- package/docs/operations/deploy.md +2 -2
- package/docs/operations/troubleshooting.md +3 -2
- package/docs/reference/cli-reference.md +65 -30
- package/docs/reference/config-reference.md +24 -13
- package/docs/reference/configuration.md +2 -2
- package/docs/reference/harness-routing.md +3 -3
- package/docs/reference/http-api.md +7 -7
- package/docs/reference/tools.md +1 -1
- package/docs/reference/workflow-definitions.md +2 -2
- package/docs/start/first-workflow.md +4 -4
- package/docs/start/quickstart-claude-code.md +2 -2
- package/docs/start/quickstart-pi.md +1 -1
- package/examples/workflow-signal.ts +4 -5
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/claude-hook.js +11 -1
- package/plugins/kxm/dist/cli.js +552 -228
- package/plugins/kxm/dist/client.js +3 -1
- package/plugins/kxm/dist/core.js +16 -3
- package/plugins/kxm/dist/extension.js +45 -13
- package/plugins/kxm/dist/mcp-server.js +20 -4
- package/plugins/kxm/dist/runtime-supervisor.js +232 -51
- package/plugins/kxm/dist/runtime.js +432 -95
- package/plugins/kxm/dist/server.js +122 -20
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +4 -3
- package/plugins/kxm/skills/kxm-project-setup/SKILL.md +3 -2
- package/plugins/kxm/skills/kxm-routing-improve/SKILL.md +3 -0
- package/plugins/kxm/skills/kxm-runs/SKILL.md +8 -7
- package/plugins/kxm/src/cli/project.ts +22 -13
- package/plugins/kxm/src/cli/system.ts +22 -1
- package/plugins/kxm/src/cli/workflows.ts +12 -7
- package/plugins/kxm/src/cli.ts +30 -8
- package/plugins/kxm/src/client.ts +4 -0
- package/plugins/kxm/src/commands.ts +23 -1
- package/plugins/kxm/src/database.ts +210 -36
- package/plugins/kxm/src/engine.ts +117 -2
- package/plugins/kxm/src/extension.ts +20 -14
- package/plugins/kxm/src/github-watch.ts +8 -5
- package/plugins/kxm/src/harness.ts +29 -0
- package/plugins/kxm/src/hub-env.ts +19 -1
- package/plugins/kxm/src/hub.ts +105 -21
- package/plugins/kxm/src/improve-sources.ts +2 -7
- package/plugins/kxm/src/init-guide-setup.ts +43 -28
- package/plugins/kxm/src/mcp-server.ts +9 -2
- package/plugins/kxm/src/oneshot-producer.ts +16 -8
- package/plugins/kxm/src/prices.ts +33 -2
- package/plugins/kxm/src/routing.ts +13 -7
- package/plugins/kxm/src/runtime-store.ts +23 -0
- package/plugins/kxm/src/studio-layout.ts +5 -4
- package/plugins/kxm/src/template.ts +31 -0
- package/plugins/kxm/src/workflow.ts +70 -1
- package/plugins/kxm/src/worktree-witness.ts +71 -0
- package/schemas/backup-manifest.schema.json +33 -0
- package/scripts/smoke-multi-pi.mjs +5 -1
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -164,10 +164,10 @@ var require_code = __commonJS({
|
|
|
164
164
|
function interpolate(x2) {
|
|
165
165
|
return typeof x2 == "number" || typeof x2 == "boolean" || x2 === null ? x2 : safeStringify(Array.isArray(x2) ? x2.join(",") : x2);
|
|
166
166
|
}
|
|
167
|
-
function
|
|
167
|
+
function stringify11(x2) {
|
|
168
168
|
return new _Code(safeStringify(x2));
|
|
169
169
|
}
|
|
170
|
-
exports.stringify =
|
|
170
|
+
exports.stringify = stringify11;
|
|
171
171
|
function safeStringify(x2) {
|
|
172
172
|
return JSON.stringify(x2).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
173
173
|
}
|
|
@@ -8918,7 +8918,7 @@ var require_stringify = __commonJS({
|
|
|
8918
8918
|
props.push(doc.directives.tagString(tag));
|
|
8919
8919
|
return props.join(" ");
|
|
8920
8920
|
}
|
|
8921
|
-
function
|
|
8921
|
+
function stringify11(item, ctx, onComment, onChompKeep) {
|
|
8922
8922
|
if (identity.isPair(item))
|
|
8923
8923
|
return item.toString(ctx, onComment, onChompKeep);
|
|
8924
8924
|
if (identity.isAlias(item)) {
|
|
@@ -8947,7 +8947,7 @@ var require_stringify = __commonJS({
|
|
|
8947
8947
|
${ctx.indent}${str}`;
|
|
8948
8948
|
}
|
|
8949
8949
|
exports.createStringifyContext = createStringifyContext;
|
|
8950
|
-
exports.stringify =
|
|
8950
|
+
exports.stringify = stringify11;
|
|
8951
8951
|
}
|
|
8952
8952
|
});
|
|
8953
8953
|
|
|
@@ -8957,7 +8957,7 @@ var require_stringifyPair = __commonJS({
|
|
|
8957
8957
|
"use strict";
|
|
8958
8958
|
var identity = require_identity();
|
|
8959
8959
|
var Scalar = require_Scalar();
|
|
8960
|
-
var
|
|
8960
|
+
var stringify11 = require_stringify();
|
|
8961
8961
|
var stringifyComment = require_stringifyComment();
|
|
8962
8962
|
function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
|
|
8963
8963
|
const { allNullValues, doc, indent, indentStep, options: { commentString, indentSeq, simpleKeys } } = ctx;
|
|
@@ -8979,7 +8979,7 @@ var require_stringifyPair = __commonJS({
|
|
|
8979
8979
|
});
|
|
8980
8980
|
let keyCommentDone = false;
|
|
8981
8981
|
let chompKeep = false;
|
|
8982
|
-
let str =
|
|
8982
|
+
let str = stringify11.stringify(key, ctx, () => keyCommentDone = true, () => chompKeep = true);
|
|
8983
8983
|
if (!explicitKey && !ctx.inFlow && str.length > 1024) {
|
|
8984
8984
|
if (simpleKeys)
|
|
8985
8985
|
throw new Error("With simple keys, single line scalar must not span more than 1024 characters");
|
|
@@ -9031,7 +9031,7 @@ ${indent}:`;
|
|
|
9031
9031
|
ctx.indent = ctx.indent.substring(2);
|
|
9032
9032
|
}
|
|
9033
9033
|
let valueCommentDone = false;
|
|
9034
|
-
const valueStr =
|
|
9034
|
+
const valueStr = stringify11.stringify(value, ctx, () => valueCommentDone = true, () => chompKeep = true);
|
|
9035
9035
|
let ws = " ";
|
|
9036
9036
|
if (keyComment || vsb || vcb) {
|
|
9037
9037
|
ws = vsb ? "\n" : "";
|
|
@@ -9172,7 +9172,7 @@ var require_addPairToJSMap = __commonJS({
|
|
|
9172
9172
|
"use strict";
|
|
9173
9173
|
var log = require_log();
|
|
9174
9174
|
var merge = require_merge();
|
|
9175
|
-
var
|
|
9175
|
+
var stringify11 = require_stringify();
|
|
9176
9176
|
var identity = require_identity();
|
|
9177
9177
|
var toJS = require_toJS();
|
|
9178
9178
|
function addPairToJSMap(ctx, map, { key, value }) {
|
|
@@ -9208,7 +9208,7 @@ var require_addPairToJSMap = __commonJS({
|
|
|
9208
9208
|
if (typeof jsKey !== "object")
|
|
9209
9209
|
return String(jsKey);
|
|
9210
9210
|
if (identity.isNode(key) && ctx?.doc) {
|
|
9211
|
-
const strCtx =
|
|
9211
|
+
const strCtx = stringify11.createStringifyContext(ctx.doc, {});
|
|
9212
9212
|
strCtx.anchors = /* @__PURE__ */ new Set();
|
|
9213
9213
|
for (const node of ctx.anchors.keys())
|
|
9214
9214
|
strCtx.anchors.add(node.anchor);
|
|
@@ -9275,12 +9275,12 @@ var require_stringifyCollection = __commonJS({
|
|
|
9275
9275
|
"node_modules/yaml/dist/stringify/stringifyCollection.js"(exports) {
|
|
9276
9276
|
"use strict";
|
|
9277
9277
|
var identity = require_identity();
|
|
9278
|
-
var
|
|
9278
|
+
var stringify11 = require_stringify();
|
|
9279
9279
|
var stringifyComment = require_stringifyComment();
|
|
9280
9280
|
function stringifyCollection(collection, ctx, options) {
|
|
9281
9281
|
const flow = ctx.inFlow ?? collection.flow;
|
|
9282
|
-
const
|
|
9283
|
-
return
|
|
9282
|
+
const stringify12 = flow ? stringifyFlowCollection : stringifyBlockCollection;
|
|
9283
|
+
return stringify12(collection, ctx, options);
|
|
9284
9284
|
}
|
|
9285
9285
|
function stringifyBlockCollection({ comment, items }, ctx, { blockItemPrefix, flowChars, itemIndent, onChompKeep, onComment }) {
|
|
9286
9286
|
const { indent, options: { commentString } } = ctx;
|
|
@@ -9305,7 +9305,7 @@ var require_stringifyCollection = __commonJS({
|
|
|
9305
9305
|
}
|
|
9306
9306
|
}
|
|
9307
9307
|
chompKeep = false;
|
|
9308
|
-
let str2 =
|
|
9308
|
+
let str2 = stringify11.stringify(item, itemCtx, () => comment2 = null, () => chompKeep = true);
|
|
9309
9309
|
if (comment2)
|
|
9310
9310
|
str2 += stringifyComment.lineComment(str2, itemIndent, commentString(comment2));
|
|
9311
9311
|
if (chompKeep && comment2)
|
|
@@ -9372,7 +9372,7 @@ ${indent}${line}` : "\n";
|
|
|
9372
9372
|
}
|
|
9373
9373
|
if (comment)
|
|
9374
9374
|
reqNewline = true;
|
|
9375
|
-
let str =
|
|
9375
|
+
let str = stringify11.stringify(item, itemCtx, () => comment = null);
|
|
9376
9376
|
reqNewline || (reqNewline = lines.length > linesAtValue || str.includes("\n"));
|
|
9377
9377
|
if (i < items.length - 1) {
|
|
9378
9378
|
str += ",";
|
|
@@ -10733,7 +10733,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
10733
10733
|
"node_modules/yaml/dist/stringify/stringifyDocument.js"(exports) {
|
|
10734
10734
|
"use strict";
|
|
10735
10735
|
var identity = require_identity();
|
|
10736
|
-
var
|
|
10736
|
+
var stringify11 = require_stringify();
|
|
10737
10737
|
var stringifyComment = require_stringifyComment();
|
|
10738
10738
|
function stringifyDocument(doc, options) {
|
|
10739
10739
|
const lines = [];
|
|
@@ -10748,7 +10748,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
10748
10748
|
}
|
|
10749
10749
|
if (hasDirectives)
|
|
10750
10750
|
lines.push("---");
|
|
10751
|
-
const ctx =
|
|
10751
|
+
const ctx = stringify11.createStringifyContext(doc, options);
|
|
10752
10752
|
const { commentString } = ctx.options;
|
|
10753
10753
|
if (doc.commentBefore) {
|
|
10754
10754
|
if (lines.length !== 1)
|
|
@@ -10770,7 +10770,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
10770
10770
|
contentComment = doc.contents.comment;
|
|
10771
10771
|
}
|
|
10772
10772
|
const onChompKeep = contentComment ? void 0 : () => chompKeep = true;
|
|
10773
|
-
let body =
|
|
10773
|
+
let body = stringify11.stringify(doc.contents, ctx, () => contentComment = null, onChompKeep);
|
|
10774
10774
|
if (contentComment)
|
|
10775
10775
|
body += stringifyComment.lineComment(body, "", commentString(contentComment));
|
|
10776
10776
|
if ((body[0] === "|" || body[0] === ">") && lines[lines.length - 1] === "---") {
|
|
@@ -10778,7 +10778,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
10778
10778
|
} else
|
|
10779
10779
|
lines.push(body);
|
|
10780
10780
|
} else {
|
|
10781
|
-
lines.push(
|
|
10781
|
+
lines.push(stringify11.stringify(doc.contents, ctx));
|
|
10782
10782
|
}
|
|
10783
10783
|
if (doc.directives?.docEnd) {
|
|
10784
10784
|
if (doc.comment) {
|
|
@@ -12914,7 +12914,7 @@ var require_cst_scalar = __commonJS({
|
|
|
12914
12914
|
var require_cst_stringify = __commonJS({
|
|
12915
12915
|
"node_modules/yaml/dist/parse/cst-stringify.js"(exports) {
|
|
12916
12916
|
"use strict";
|
|
12917
|
-
var
|
|
12917
|
+
var stringify11 = (cst) => "type" in cst ? stringifyToken(cst) : stringifyItem(cst);
|
|
12918
12918
|
function stringifyToken(token) {
|
|
12919
12919
|
switch (token.type) {
|
|
12920
12920
|
case "block-scalar": {
|
|
@@ -12967,7 +12967,7 @@ var require_cst_stringify = __commonJS({
|
|
|
12967
12967
|
res += stringifyToken(value);
|
|
12968
12968
|
return res;
|
|
12969
12969
|
}
|
|
12970
|
-
exports.stringify =
|
|
12970
|
+
exports.stringify = stringify11;
|
|
12971
12971
|
}
|
|
12972
12972
|
});
|
|
12973
12973
|
|
|
@@ -14697,7 +14697,7 @@ var require_public_api = __commonJS({
|
|
|
14697
14697
|
}
|
|
14698
14698
|
return doc.toJS(Object.assign({ reviver: _reviver }, options));
|
|
14699
14699
|
}
|
|
14700
|
-
function
|
|
14700
|
+
function stringify11(value, replacer, options) {
|
|
14701
14701
|
let _replacer = null;
|
|
14702
14702
|
if (typeof replacer === "function" || Array.isArray(replacer)) {
|
|
14703
14703
|
_replacer = replacer;
|
|
@@ -14722,7 +14722,7 @@ var require_public_api = __commonJS({
|
|
|
14722
14722
|
exports.parse = parse12;
|
|
14723
14723
|
exports.parseAllDocuments = parseAllDocuments;
|
|
14724
14724
|
exports.parseDocument = parseDocument2;
|
|
14725
|
-
exports.stringify =
|
|
14725
|
+
exports.stringify = stringify11;
|
|
14726
14726
|
}
|
|
14727
14727
|
});
|
|
14728
14728
|
|
|
@@ -18475,7 +18475,7 @@ function validateTerminalReceipt(value) {
|
|
|
18475
18475
|
}
|
|
18476
18476
|
|
|
18477
18477
|
// plugins/kxm/src/workflow.ts
|
|
18478
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
18478
|
+
import { createHash as createHash2, createHmac } from "node:crypto";
|
|
18479
18479
|
|
|
18480
18480
|
// plugins/kxm/src/redact.ts
|
|
18481
18481
|
var SECRET_PATTERNS = [
|
|
@@ -19123,6 +19123,37 @@ function parseOutcomeMap(stageId, raw) {
|
|
|
19123
19123
|
}
|
|
19124
19124
|
return map;
|
|
19125
19125
|
}
|
|
19126
|
+
var WORKFLOW_WEBHOOK_SIGNATURE_VERSION = "kxm-webhook-v1";
|
|
19127
|
+
function workflowWebhookSignedMaterial(scope, timestamp, deliveryId, body) {
|
|
19128
|
+
const fields = [
|
|
19129
|
+
WORKFLOW_WEBHOOK_SIGNATURE_VERSION,
|
|
19130
|
+
scope.runId === void 0 ? "start" : "signal",
|
|
19131
|
+
timestamp,
|
|
19132
|
+
deliveryId,
|
|
19133
|
+
scope.definitionId,
|
|
19134
|
+
scope.runId ?? "",
|
|
19135
|
+
scope.signalKey ?? ""
|
|
19136
|
+
];
|
|
19137
|
+
if (fields.some((field) => /[\r\n]/.test(field))) {
|
|
19138
|
+
throw new ProtocolError(400, "webhook signature fields must not contain line breaks", "webhook_signature_field_invalid");
|
|
19139
|
+
}
|
|
19140
|
+
return Buffer.concat([
|
|
19141
|
+
Buffer.from(`${fields.join("\n")}
|
|
19142
|
+
`, "utf8"),
|
|
19143
|
+
typeof body === "string" ? Buffer.from(body, "utf8") : Buffer.from(body)
|
|
19144
|
+
]);
|
|
19145
|
+
}
|
|
19146
|
+
function workflowWebhookSignature(secret, scope, timestamp, deliveryId, body) {
|
|
19147
|
+
return `sha256=${createHmac("sha256", secret).update(workflowWebhookSignedMaterial(scope, timestamp, deliveryId, body)).digest("hex")}`;
|
|
19148
|
+
}
|
|
19149
|
+
function workflowWebhookHeaders(input) {
|
|
19150
|
+
const timestamp = String(Math.floor((input.nowMs ?? Date.now()) / 1e3));
|
|
19151
|
+
return {
|
|
19152
|
+
"x-kxm-delivery-id": input.deliveryId,
|
|
19153
|
+
"x-kxm-timestamp": timestamp,
|
|
19154
|
+
"x-kxm-signature": workflowWebhookSignature(input.secret, input.scope, timestamp, input.deliveryId, input.body)
|
|
19155
|
+
};
|
|
19156
|
+
}
|
|
19126
19157
|
function resolveOutcomeRule(stage, outcomeKey) {
|
|
19127
19158
|
const raw = stage.on?.[outcomeKey];
|
|
19128
19159
|
return raw === void 0 ? void 0 : normalizeOutcomeValue(raw, `stage ${stage.id} on.${outcomeKey}`);
|
|
@@ -19552,7 +19583,9 @@ var HubClient = class {
|
|
|
19552
19583
|
options.workflowContext
|
|
19553
19584
|
)
|
|
19554
19585
|
} : {},
|
|
19555
|
-
...options.ttlMs ? { ttlMs: options.ttlMs } : {}
|
|
19586
|
+
...options.ttlMs ? { ttlMs: options.ttlMs } : {},
|
|
19587
|
+
...options.hops !== void 0 ? { hops: options.hops } : {},
|
|
19588
|
+
...options.maxHops !== void 0 ? { maxHops: options.maxHops } : {}
|
|
19556
19589
|
});
|
|
19557
19590
|
const completed2 = await this.awaitResponse(
|
|
19558
19591
|
message.id,
|
|
@@ -19946,6 +19979,24 @@ function resolveClientHubAuthToken(env, project) {
|
|
|
19946
19979
|
const record = readHubEnvRecord(env);
|
|
19947
19980
|
return record?.projectTokens?.[project]?.trim() || record?.authToken?.trim() || void 0;
|
|
19948
19981
|
}
|
|
19982
|
+
function resolveAgentHubAuthToken(env, project) {
|
|
19983
|
+
const envToken = env.KXM_AUTH_TOKEN?.trim();
|
|
19984
|
+
if (envToken) return envToken;
|
|
19985
|
+
const tokens = readHubEnvRecord(env)?.projectTokens;
|
|
19986
|
+
if (!tokens || !Object.hasOwn(tokens, project)) return void 0;
|
|
19987
|
+
return tokens[project]?.trim() || void 0;
|
|
19988
|
+
}
|
|
19989
|
+
var AgentProjectTokenMissingError = class extends Error {
|
|
19990
|
+
code = "project_token_missing";
|
|
19991
|
+
project;
|
|
19992
|
+
constructor(project) {
|
|
19993
|
+
super(
|
|
19994
|
+
`kxm has no project token for project ${project} on this machine. Set KXM_AUTH_TOKEN to that project's token, or add ${project} to the hub KXM_PROJECT_TOKENS (list every existing project too, because that variable replaces the saved map). An agent never uses the hub admin token.`
|
|
19995
|
+
);
|
|
19996
|
+
this.name = "AgentProjectTokenMissingError";
|
|
19997
|
+
this.project = project;
|
|
19998
|
+
}
|
|
19999
|
+
};
|
|
19949
20000
|
function resolveClientAdminAuthToken(env = process.env) {
|
|
19950
20001
|
const envToken = env.KXM_AUTH_TOKEN?.trim();
|
|
19951
20002
|
if (envToken) return envToken;
|
|
@@ -19971,6 +20022,13 @@ import { createHash as createHash4, randomUUID as randomUUID2, timingSafeEqual }
|
|
|
19971
20022
|
import { chmodSync, existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
19972
20023
|
import { homedir as homedir2 } from "node:os";
|
|
19973
20024
|
import { dirname as dirname3, join as join5, resolve as resolve2 } from "node:path";
|
|
20025
|
+
function forwardedHops(handling) {
|
|
20026
|
+
if (!handling?.length) return void 0;
|
|
20027
|
+
return {
|
|
20028
|
+
hops: Math.max(...handling.map((message) => message.hops)) + 1,
|
|
20029
|
+
maxHops: Math.min(...handling.map((message) => message.maxHops))
|
|
20030
|
+
};
|
|
20031
|
+
}
|
|
19974
20032
|
function requiredString(value, name) {
|
|
19975
20033
|
if (typeof value !== "string" || value.trim() === "") throw new Error(`${name} is required`);
|
|
19976
20034
|
return value.trim();
|
|
@@ -20100,12 +20158,13 @@ var AGENT_COMMANDS = [
|
|
|
20100
20158
|
required: ["target", "content"],
|
|
20101
20159
|
additionalProperties: false
|
|
20102
20160
|
},
|
|
20103
|
-
async execute(client, args) {
|
|
20161
|
+
async execute(client, args, context) {
|
|
20104
20162
|
const delivery = optionalString2(args.delivery);
|
|
20105
20163
|
const correlationId = optionalString2(args.correlationId);
|
|
20106
20164
|
const idempotencyKey = optionalString2(args.idempotencyKey);
|
|
20107
20165
|
const workflowContext = optionalWorkflowContext(args.workflowContext);
|
|
20108
20166
|
const message = await client.send({
|
|
20167
|
+
...forwardedHops(context?.handling),
|
|
20109
20168
|
target: requiredString(args.target, "target"),
|
|
20110
20169
|
content: requiredString(args.content, "content"),
|
|
20111
20170
|
...delivery ? { delivery } : {},
|
|
@@ -20183,6 +20242,7 @@ var AGENT_COMMANDS = [
|
|
|
20183
20242
|
const targets = Array.isArray(args.targets) ? args.targets.map((t) => requiredString(t, "target")) : [];
|
|
20184
20243
|
return {
|
|
20185
20244
|
responses: await client.fanout({
|
|
20245
|
+
...forwardedHops(context?.handling),
|
|
20186
20246
|
targets,
|
|
20187
20247
|
content: requiredString(args.content, "content"),
|
|
20188
20248
|
...optionalString2(args.correlationId) ? { correlationId: optionalString2(args.correlationId) } : {},
|
|
@@ -21159,6 +21219,35 @@ function coreTemplate(projectId, projectName, variant) {
|
|
|
21159
21219
|
}]
|
|
21160
21220
|
]);
|
|
21161
21221
|
if (variant === "v4-registry") {
|
|
21222
|
+
const coordinator = files.get(".kxm/agents/coordinator.yaml");
|
|
21223
|
+
if (coordinator) {
|
|
21224
|
+
files.set(".kxm/agents/coordinator.yaml", {
|
|
21225
|
+
...coordinator,
|
|
21226
|
+
harness: "claude",
|
|
21227
|
+
model: { provider: "anthropic", model: "fable" }
|
|
21228
|
+
});
|
|
21229
|
+
}
|
|
21230
|
+
const implementer = files.get(".kxm/agents/implementer.yaml");
|
|
21231
|
+
if (implementer) {
|
|
21232
|
+
files.set(".kxm/agents/implementer.yaml", {
|
|
21233
|
+
...implementer,
|
|
21234
|
+
harness: "grok",
|
|
21235
|
+
model: { provider: "xai", model: "grok-4.6" }
|
|
21236
|
+
});
|
|
21237
|
+
}
|
|
21238
|
+
const workflow = files.get(".kxm/workflows/default.yaml");
|
|
21239
|
+
if (workflow) {
|
|
21240
|
+
const limits = { ...workflow.limits };
|
|
21241
|
+
delete limits.maxAgentTimeMs;
|
|
21242
|
+
files.set(".kxm/workflows/default.yaml", { ...workflow, limits });
|
|
21243
|
+
}
|
|
21244
|
+
files.set(".kxm/routes.yaml", {
|
|
21245
|
+
schema: "kxm.routes.v2",
|
|
21246
|
+
updatedAt: "2026-09-23T00:00:00.000Z",
|
|
21247
|
+
admitted: ["anthropic/fable", "xai/grok-4.6"],
|
|
21248
|
+
disabled: [],
|
|
21249
|
+
roles: { implementer: ["xai/grok-4.6"] }
|
|
21250
|
+
});
|
|
21162
21251
|
files.set(".kxm/gates.yaml", {
|
|
21163
21252
|
schema: "kxm.gate-registry.v1",
|
|
21164
21253
|
gates: { test: { kind: "command", argv: ["npm", "test"], timeoutMs: 36e5 } }
|
|
@@ -21685,6 +21774,10 @@ var READ_ONLY_ONESHOT_ARGS = Object.freeze({
|
|
|
21685
21774
|
function oneShotReadOnlyArgs(harness) {
|
|
21686
21775
|
return Object.hasOwn(READ_ONLY_ONESHOT_ARGS, harness) ? READ_ONLY_ONESHOT_ARGS[harness] : void 0;
|
|
21687
21776
|
}
|
|
21777
|
+
var WRITER_ONESHOT_ARGS = Object.freeze({
|
|
21778
|
+
pi: Object.freeze(["-a", "--no-extensions", "--no-skills", "--no-prompt-templates", "--no-session"]),
|
|
21779
|
+
grok: Object.freeze(["--always-approve", "--no-subagents", "--disable-web-search"])
|
|
21780
|
+
});
|
|
21688
21781
|
var BUILTIN_HARNESSES = Object.freeze([
|
|
21689
21782
|
{
|
|
21690
21783
|
id: "pi",
|
|
@@ -22985,8 +23078,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
22985
23078
|
const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
|
|
22986
23079
|
if (maxWriteRepositories > writable) issues.push(issue2("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
|
|
22987
23080
|
}
|
|
22988
|
-
const
|
|
22989
|
-
const minimumPassed =
|
|
23081
|
+
const join49 = objectValue(step.join);
|
|
23082
|
+
const minimumPassed = join49 && typeof join49.minimumPassed === "number" ? join49.minimumPassed : void 0;
|
|
22990
23083
|
if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue2("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
|
|
22991
23084
|
const distinctBy = names(assignment?.distinctBy);
|
|
22992
23085
|
if (distinctBy.length > 0) {
|
|
@@ -23530,8 +23623,8 @@ function planKxmInitialization(start = process.cwd(), options = {}) {
|
|
|
23530
23623
|
|
|
23531
23624
|
// plugins/kxm/src/runtime-supervisor.ts
|
|
23532
23625
|
import { spawn as spawn2 } from "node:child_process";
|
|
23533
|
-
import { createHash as createHash13, createHmac, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
23534
|
-
import { chmodSync as chmodSync4, existsSync as existsSync16, lstatSync as lstatSync6, mkdirSync as mkdirSync11, readFileSync as readFileSync14, renameSync as renameSync5, rmSync as rmSync5, writeFileSync as
|
|
23626
|
+
import { createHash as createHash13, createHmac as createHmac2, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
23627
|
+
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";
|
|
23535
23628
|
import { dirname as dirname11, isAbsolute as isAbsolute6, join as join15 } from "node:path";
|
|
23536
23629
|
|
|
23537
23630
|
// plugins/kxm/src/runtime-store.ts
|
|
@@ -23539,25 +23632,6 @@ import { createHash as createHash10, randomUUID as randomUUID4 } from "node:cryp
|
|
|
23539
23632
|
import { existsSync as existsSync10, lstatSync as lstatSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync8, realpathSync as realpathSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
23540
23633
|
import { dirname as dirname7, join as join9, resolve as resolve7 } from "node:path";
|
|
23541
23634
|
|
|
23542
|
-
// plugins/kxm/src/bindings.ts
|
|
23543
|
-
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
23544
|
-
import { createHash as createHash7, randomUUID as randomUUID3 } from "node:crypto";
|
|
23545
|
-
import {
|
|
23546
|
-
chmodSync as chmodSync2,
|
|
23547
|
-
closeSync,
|
|
23548
|
-
existsSync as existsSync8,
|
|
23549
|
-
fsyncSync,
|
|
23550
|
-
lstatSync as lstatSync2,
|
|
23551
|
-
mkdirSync as mkdirSync4,
|
|
23552
|
-
openSync,
|
|
23553
|
-
readFileSync as readFileSync6,
|
|
23554
|
-
realpathSync as realpathSync2,
|
|
23555
|
-
renameSync as renameSync2,
|
|
23556
|
-
rmSync as rmSync2,
|
|
23557
|
-
writeFileSync as writeFileSync4
|
|
23558
|
-
} from "node:fs";
|
|
23559
|
-
import { homedir as homedir3 } from "node:os";
|
|
23560
|
-
|
|
23561
23635
|
// plugins/kxm/src/sqlite.ts
|
|
23562
23636
|
import { existsSync as existsSync7 } from "node:fs";
|
|
23563
23637
|
import { createRequire } from "node:module";
|
|
@@ -23607,6 +23681,23 @@ function openReadOnlyDatabase(path4) {
|
|
|
23607
23681
|
}
|
|
23608
23682
|
|
|
23609
23683
|
// plugins/kxm/src/bindings.ts
|
|
23684
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
23685
|
+
import { createHash as createHash7, randomUUID as randomUUID3 } from "node:crypto";
|
|
23686
|
+
import {
|
|
23687
|
+
chmodSync as chmodSync2,
|
|
23688
|
+
closeSync,
|
|
23689
|
+
existsSync as existsSync8,
|
|
23690
|
+
fsyncSync,
|
|
23691
|
+
lstatSync as lstatSync2,
|
|
23692
|
+
mkdirSync as mkdirSync4,
|
|
23693
|
+
openSync,
|
|
23694
|
+
readFileSync as readFileSync6,
|
|
23695
|
+
realpathSync as realpathSync2,
|
|
23696
|
+
renameSync as renameSync2,
|
|
23697
|
+
rmSync as rmSync2,
|
|
23698
|
+
writeFileSync as writeFileSync4
|
|
23699
|
+
} from "node:fs";
|
|
23700
|
+
import { homedir as homedir3 } from "node:os";
|
|
23610
23701
|
import { dirname as dirname5, isAbsolute as isAbsolute3, join as join7, parse, relative as relative2, resolve as resolve5, sep as sep2 } from "node:path";
|
|
23611
23702
|
var MAX_BINDING_RECORD_BYTES = 256 * 1024;
|
|
23612
23703
|
var BINDING_LABEL = "Runtime-local repository bindings";
|
|
@@ -24230,79 +24321,187 @@ var KXM_BACKUP_CEILINGS = {
|
|
|
24230
24321
|
events: 7
|
|
24231
24322
|
};
|
|
24232
24323
|
function kxmBackupCeiling(storeId) {
|
|
24324
|
+
if (storeId === "runtime-registry") return KXM_BACKUP_CEILINGS.registry;
|
|
24233
24325
|
if (storeId.startsWith("events:")) return KXM_BACKUP_CEILINGS.events;
|
|
24234
24326
|
return KXM_BACKUP_CEILINGS[storeId] ?? KXM_BACKUP_CEILINGS["hub-store"];
|
|
24235
24327
|
}
|
|
24236
|
-
function
|
|
24328
|
+
function pushStore(stores, storeId, sourcePath) {
|
|
24329
|
+
if (stores.some((store) => store.storeId === storeId || store.sourcePath === sourcePath)) return;
|
|
24330
|
+
stores.push({ storeId, sourcePath, maxSupportedVersion: kxmBackupCeiling(storeId) });
|
|
24331
|
+
}
|
|
24332
|
+
function discoverUserRuntime(env, stores, files) {
|
|
24333
|
+
let stateRoot;
|
|
24334
|
+
try {
|
|
24335
|
+
stateRoot = kxmUserStateRoot(env ? { env } : {});
|
|
24336
|
+
} catch {
|
|
24337
|
+
return;
|
|
24338
|
+
}
|
|
24339
|
+
const runtimeDir = join8(stateRoot, "runtime");
|
|
24340
|
+
const registryPath = join8(runtimeDir, "registry.db");
|
|
24341
|
+
if (existsSync9(registryPath)) {
|
|
24342
|
+
const storeId = stores.some((store) => store.storeId === "registry") ? "runtime-registry" : "registry";
|
|
24343
|
+
pushStore(stores, storeId, registryPath);
|
|
24344
|
+
}
|
|
24345
|
+
const projectsDir = join8(runtimeDir, "projects");
|
|
24346
|
+
if (!existsSync9(projectsDir)) return;
|
|
24347
|
+
let entries;
|
|
24348
|
+
try {
|
|
24349
|
+
entries = readdirSync2(projectsDir, { withFileTypes: true });
|
|
24350
|
+
} catch {
|
|
24351
|
+
return;
|
|
24352
|
+
}
|
|
24353
|
+
for (const entry of entries) {
|
|
24354
|
+
if (!entry.isDirectory()) continue;
|
|
24355
|
+
const dbPath = join8(projectsDir, entry.name, "run-events.db");
|
|
24356
|
+
if (!existsSync9(dbPath)) continue;
|
|
24357
|
+
const safe = entry.name.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
24358
|
+
let storeId = `events:${safe}`;
|
|
24359
|
+
if (stores.some((store) => store.storeId === storeId)) storeId = `events:runtime:${safe}`;
|
|
24360
|
+
pushStore(stores, storeId, dbPath);
|
|
24361
|
+
const sidecar = `${dbPath}.run-prompts.json`;
|
|
24362
|
+
if (existsSync9(sidecar)) {
|
|
24363
|
+
const id = `${storeId}:run-prompts`;
|
|
24364
|
+
if (!files.some((file) => file.id === id || file.sourcePath === sidecar)) {
|
|
24365
|
+
files.push({ id, sourcePath: sidecar });
|
|
24366
|
+
}
|
|
24367
|
+
}
|
|
24368
|
+
}
|
|
24369
|
+
}
|
|
24370
|
+
function discoverBackupSources(projectRoot, options = {}) {
|
|
24237
24371
|
const root = resolve6(projectRoot);
|
|
24238
24372
|
const stores = [];
|
|
24373
|
+
const files = [];
|
|
24239
24374
|
const hubPath = options.hubDataPath ? resolve6(options.hubDataPath) : join8(root, ".kxm", "state", "kxm.db");
|
|
24240
|
-
if (existsSync9(hubPath))
|
|
24241
|
-
stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: kxmBackupCeiling("hub-store") });
|
|
24242
|
-
}
|
|
24375
|
+
if (existsSync9(hubPath)) pushStore(stores, "hub-store", hubPath);
|
|
24243
24376
|
const registryPath = join8(root, ".kxm", "runtime", "registry.db");
|
|
24244
|
-
if (existsSync9(registryPath))
|
|
24245
|
-
stores.push({ storeId: "registry", sourcePath: registryPath, maxSupportedVersion: kxmBackupCeiling("registry") });
|
|
24246
|
-
}
|
|
24377
|
+
if (existsSync9(registryPath)) pushStore(stores, "registry", registryPath);
|
|
24247
24378
|
const bindingsPath = join8(root, ".kxm", "runtime", "bindings.db");
|
|
24248
|
-
if (existsSync9(bindingsPath))
|
|
24249
|
-
stores.push({ storeId: "binding-store", sourcePath: bindingsPath, maxSupportedVersion: kxmBackupCeiling("binding-store") });
|
|
24250
|
-
}
|
|
24379
|
+
if (existsSync9(bindingsPath)) pushStore(stores, "binding-store", bindingsPath);
|
|
24251
24380
|
const eventsDir = join8(root, ".kxm", "runtime", "events");
|
|
24252
24381
|
if (existsSync9(eventsDir)) {
|
|
24253
24382
|
const entries = readdirSync2(eventsDir, { withFileTypes: true });
|
|
24254
24383
|
for (const entry of entries) {
|
|
24255
24384
|
if (entry.isFile() && entry.name.endsWith(".db")) {
|
|
24256
|
-
const key = entry.name.replace(/\.db$/, "");
|
|
24257
|
-
stores.
|
|
24258
|
-
storeId: `events:${key}`,
|
|
24259
|
-
sourcePath: join8(eventsDir, entry.name),
|
|
24260
|
-
maxSupportedVersion: kxmBackupCeiling(`events:${key}`)
|
|
24261
|
-
});
|
|
24385
|
+
const key = entry.name.replace(/\.db$/, "").replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
24386
|
+
pushStore(stores, `events:${key}`, join8(eventsDir, entry.name));
|
|
24262
24387
|
}
|
|
24263
24388
|
}
|
|
24264
24389
|
}
|
|
24265
|
-
|
|
24390
|
+
discoverUserRuntime(options.env, stores, files);
|
|
24391
|
+
return { stores, files };
|
|
24392
|
+
}
|
|
24393
|
+
function backupPlainFile(sourcePath, targetPath, id) {
|
|
24394
|
+
const resolvedSource = resolve6(sourcePath);
|
|
24395
|
+
const sourceStat = lstatSync3(resolvedSource, { throwIfNoEntry: false });
|
|
24396
|
+
if (!sourceStat || !sourceStat.isFile() || sourceStat.isSymbolicLink()) {
|
|
24397
|
+
throw databaseError("runtime_path_invalid", resolvedSource, `backup file ${resolvedSource} must be a regular file, not a link or directory`);
|
|
24398
|
+
}
|
|
24399
|
+
checkedParent(targetPath, "backup target");
|
|
24400
|
+
if (existsSync9(targetPath)) unlinkSync2(targetPath);
|
|
24401
|
+
copyFileSync(resolvedSource, targetPath);
|
|
24402
|
+
try {
|
|
24403
|
+
chmodSync3(targetPath, 384);
|
|
24404
|
+
} catch {
|
|
24405
|
+
}
|
|
24406
|
+
return {
|
|
24407
|
+
id,
|
|
24408
|
+
sourcePath: resolvedSource,
|
|
24409
|
+
backupFile: basename3(targetPath),
|
|
24410
|
+
sha256: fileSha256(targetPath),
|
|
24411
|
+
bytes: sourceStat.size
|
|
24412
|
+
};
|
|
24413
|
+
}
|
|
24414
|
+
function backupFilename(sourcePath, id, used) {
|
|
24415
|
+
let filename = basename3(sourcePath);
|
|
24416
|
+
if (used.has(filename)) {
|
|
24417
|
+
filename = `${id.replace(/[^a-zA-Z0-9_.-]/g, "_")}-${filename}`;
|
|
24418
|
+
}
|
|
24419
|
+
used.add(filename);
|
|
24420
|
+
return filename;
|
|
24421
|
+
}
|
|
24422
|
+
function restorePlainFile(backupFilePath, targetPath) {
|
|
24423
|
+
checkedParent(targetPath, "restore target");
|
|
24424
|
+
if (existsSync9(targetPath)) unlinkSync2(targetPath);
|
|
24425
|
+
copyFileSync(backupFilePath, targetPath);
|
|
24426
|
+
try {
|
|
24427
|
+
chmodSync3(targetPath, 384);
|
|
24428
|
+
} catch {
|
|
24429
|
+
}
|
|
24430
|
+
}
|
|
24431
|
+
function backupDiscoverOptions(options) {
|
|
24432
|
+
return {
|
|
24433
|
+
...options.hubDataPath !== void 0 ? { hubDataPath: options.hubDataPath } : {},
|
|
24434
|
+
...options.env !== void 0 ? { env: options.env } : {}
|
|
24435
|
+
};
|
|
24266
24436
|
}
|
|
24267
24437
|
function planBackup(options = {}) {
|
|
24268
24438
|
const projectRoot = options.projectRoot ? resolve6(options.projectRoot) : process.cwd();
|
|
24269
|
-
const
|
|
24270
|
-
|
|
24271
|
-
});
|
|
24272
|
-
if (stores.length === 0) {
|
|
24439
|
+
const discovered = discoverBackupSources(projectRoot, backupDiscoverOptions(options));
|
|
24440
|
+
if (discovered.stores.length === 0) {
|
|
24273
24441
|
throw databaseError("backup_no_stores", projectRoot, "no existing SQLite stores found to backup");
|
|
24274
24442
|
}
|
|
24275
24443
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24276
24444
|
const timestamp = createdAt.replace(/[:.]/g, "-");
|
|
24277
24445
|
const outDir = options.outDir ? resolve6(options.outDir) : join8(projectRoot, ".kxm", "backups", `backup-${timestamp}`);
|
|
24278
24446
|
const usedFilenames = /* @__PURE__ */ new Set();
|
|
24279
|
-
const
|
|
24280
|
-
|
|
24281
|
-
|
|
24282
|
-
|
|
24283
|
-
|
|
24284
|
-
|
|
24285
|
-
|
|
24286
|
-
|
|
24287
|
-
|
|
24288
|
-
|
|
24447
|
+
const stores = discovered.stores.map((store) => ({
|
|
24448
|
+
storeId: store.storeId,
|
|
24449
|
+
sourcePath: store.sourcePath,
|
|
24450
|
+
backupFile: backupFilename(store.sourcePath, store.storeId, usedFilenames)
|
|
24451
|
+
}));
|
|
24452
|
+
const files = discovered.files.map((file) => ({
|
|
24453
|
+
id: file.id,
|
|
24454
|
+
sourcePath: file.sourcePath,
|
|
24455
|
+
backupFile: backupFilename(file.sourcePath, file.id, usedFilenames)
|
|
24456
|
+
}));
|
|
24457
|
+
return { projectRoot, outDir, createdAt, stores, files };
|
|
24289
24458
|
}
|
|
24290
24459
|
function createBackup(options = {}) {
|
|
24291
|
-
const { projectRoot, outDir, createdAt, stores } = planBackup(options);
|
|
24460
|
+
const { projectRoot, outDir, createdAt, stores, files } = planBackup(options);
|
|
24292
24461
|
const backupId = `bk_${randomBytes(8).toString("hex")}`;
|
|
24293
24462
|
if (!existsSync9(outDir)) {
|
|
24294
24463
|
mkdirSync5(outDir, { recursive: true, mode: 448 });
|
|
24295
24464
|
}
|
|
24296
24465
|
const backedUpStores = [];
|
|
24466
|
+
const backedUpFiles = [];
|
|
24467
|
+
const omitted = [];
|
|
24297
24468
|
for (const store of stores) {
|
|
24298
|
-
|
|
24469
|
+
try {
|
|
24470
|
+
backedUpStores.push(backupDatabaseFile(store.sourcePath, join8(outDir, store.backupFile), store.storeId));
|
|
24471
|
+
} catch {
|
|
24472
|
+
omitted.push(store.storeId);
|
|
24473
|
+
}
|
|
24474
|
+
}
|
|
24475
|
+
for (const file of files) {
|
|
24476
|
+
try {
|
|
24477
|
+
backedUpFiles.push(backupPlainFile(file.sourcePath, join8(outDir, file.backupFile), file.id));
|
|
24478
|
+
} catch {
|
|
24479
|
+
omitted.push(file.id);
|
|
24480
|
+
}
|
|
24481
|
+
}
|
|
24482
|
+
if (backedUpStores.length === 0) {
|
|
24483
|
+
throw databaseError("backup_no_stores", projectRoot, "no SQLite store could be copied");
|
|
24484
|
+
}
|
|
24485
|
+
const again = discoverBackupSources(projectRoot, backupDiscoverOptions(options));
|
|
24486
|
+
for (const store of again.stores) {
|
|
24487
|
+
if (!backedUpStores.some((copied) => copied.storeId === store.storeId) && !omitted.includes(store.storeId)) {
|
|
24488
|
+
omitted.push(store.storeId);
|
|
24489
|
+
}
|
|
24490
|
+
}
|
|
24491
|
+
for (const file of again.files) {
|
|
24492
|
+
if (!backedUpFiles.some((copied) => copied.id === file.id) && !omitted.includes(file.id)) {
|
|
24493
|
+
omitted.push(file.id);
|
|
24494
|
+
}
|
|
24299
24495
|
}
|
|
24300
24496
|
const manifest = {
|
|
24301
24497
|
schema: "kxm.backup-manifest.v1",
|
|
24302
24498
|
backupId,
|
|
24303
24499
|
createdAt,
|
|
24304
24500
|
projectRoot,
|
|
24305
|
-
stores: backedUpStores
|
|
24501
|
+
stores: backedUpStores,
|
|
24502
|
+
...backedUpFiles.length > 0 ? { files: backedUpFiles } : {},
|
|
24503
|
+
complete: omitted.length === 0,
|
|
24504
|
+
...omitted.length > 0 ? { omitted } : {}
|
|
24306
24505
|
};
|
|
24307
24506
|
const manifestJson = JSON.stringify(manifest, null, 2) + "\n";
|
|
24308
24507
|
const manifestSha256 = `sha256:${createHash9("sha256").update(manifestJson, "utf8").digest("hex")}`;
|
|
@@ -24335,6 +24534,9 @@ function planRestore(manifestPathOrDir, options = {}) {
|
|
|
24335
24534
|
if (manifest.schema !== "kxm.backup-manifest.v1" || !Array.isArray(manifest.stores) || manifest.stores.length === 0) {
|
|
24336
24535
|
throw databaseError("restore_manifest_invalid", manifestPath, "manifest is not a valid kxm.backup-manifest.v1 document");
|
|
24337
24536
|
}
|
|
24537
|
+
if (manifest.complete === false) {
|
|
24538
|
+
throw databaseError("restore_incomplete", manifestPath, "backup manifest is incomplete; refusing to restore a partial copy");
|
|
24539
|
+
}
|
|
24338
24540
|
const stores = [];
|
|
24339
24541
|
for (const store of manifest.stores) {
|
|
24340
24542
|
const backupFilePath = join8(manifestDir, store.backupFile);
|
|
@@ -24364,7 +24566,28 @@ function planRestore(manifestPathOrDir, options = {}) {
|
|
|
24364
24566
|
}
|
|
24365
24567
|
stores.push({ storeId: store.storeId, backupFilePath, targetPath, schemaVersion: store.schemaVersion, maxSupportedVersion });
|
|
24366
24568
|
}
|
|
24367
|
-
|
|
24569
|
+
const files = [];
|
|
24570
|
+
for (const file of manifest.files ?? []) {
|
|
24571
|
+
const backupFilePath = join8(manifestDir, file.backupFile);
|
|
24572
|
+
if (!existsSync9(backupFilePath)) {
|
|
24573
|
+
throw databaseError("restore_file_missing", backupFilePath, `backup file ${file.backupFile} missing from ${manifestDir}`);
|
|
24574
|
+
}
|
|
24575
|
+
const actualSha256 = fileSha256(backupFilePath);
|
|
24576
|
+
if (actualSha256 !== file.sha256) {
|
|
24577
|
+
throw databaseError(
|
|
24578
|
+
"restore_manifest_digest_mismatch",
|
|
24579
|
+
backupFilePath,
|
|
24580
|
+
`backup file ${file.backupFile} sha256 ${actualSha256} does not match manifest hash ${file.sha256}`
|
|
24581
|
+
);
|
|
24582
|
+
}
|
|
24583
|
+
let targetPath = file.sourcePath;
|
|
24584
|
+
if (options.projectRoot && manifest.projectRoot && targetPath.startsWith(manifest.projectRoot)) {
|
|
24585
|
+
const rel = targetPath.slice(manifest.projectRoot.length).replace(/^[\\/]+/, "");
|
|
24586
|
+
targetPath = join8(resolve6(options.projectRoot), rel);
|
|
24587
|
+
}
|
|
24588
|
+
files.push({ id: file.id, backupFilePath, targetPath });
|
|
24589
|
+
}
|
|
24590
|
+
return { manifestPath, backupId: manifest.backupId, stores, files };
|
|
24368
24591
|
}
|
|
24369
24592
|
function restoreBackup(manifestPathOrDir, options = {}) {
|
|
24370
24593
|
const plan = planRestore(manifestPathOrDir, options);
|
|
@@ -24375,6 +24598,9 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
24375
24598
|
store.schemaVersion,
|
|
24376
24599
|
store.maxSupportedVersion
|
|
24377
24600
|
));
|
|
24601
|
+
for (const file of plan.files) {
|
|
24602
|
+
restorePlainFile(file.backupFilePath, file.targetPath);
|
|
24603
|
+
}
|
|
24378
24604
|
return {
|
|
24379
24605
|
manifestPath: plan.manifestPath,
|
|
24380
24606
|
backupId: plan.backupId,
|
|
@@ -24409,6 +24635,20 @@ function projectRuntimeKey(projectRoot) {
|
|
|
24409
24635
|
const folded = process.platform === "win32" ? canonical2.toLocaleLowerCase("en-US") : canonical2;
|
|
24410
24636
|
return createHash10("sha256").update(folded, "utf8").digest("hex").slice(0, 24);
|
|
24411
24637
|
}
|
|
24638
|
+
function kxmProjectRunEventsPath(projectRoot, env) {
|
|
24639
|
+
return join9(kxmRuntimePaths({ env }).projectsDir, projectRuntimeKey(projectRoot), "run-events.db");
|
|
24640
|
+
}
|
|
24641
|
+
function projectRuntimeOwnsRun(projectRoot, runId, env) {
|
|
24642
|
+
const path4 = kxmProjectRunEventsPath(projectRoot, env);
|
|
24643
|
+
if (!existsSync10(path4)) return false;
|
|
24644
|
+
const database = new DatabaseSync(path4, { readOnly: true });
|
|
24645
|
+
try {
|
|
24646
|
+
database.exec("PRAGMA busy_timeout = 5000");
|
|
24647
|
+
return database.prepare("SELECT 1 FROM runs WHERE run_id = ?").get(runId) !== void 0;
|
|
24648
|
+
} finally {
|
|
24649
|
+
database.close();
|
|
24650
|
+
}
|
|
24651
|
+
}
|
|
24412
24652
|
var KXM_REGISTRY_SCHEMA_VERSION = 1;
|
|
24413
24653
|
var REGISTRY_TABLES = {
|
|
24414
24654
|
supervisor: ["singleton_id", "runtime_id", "pid", "port", "token_hash", "started_at", "heartbeat_at", "state"],
|
|
@@ -24875,7 +25115,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
24875
25115
|
const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
|
|
24876
25116
|
const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
|
|
24877
25117
|
const assignments = compileAssignments(step, id, agent, sink);
|
|
24878
|
-
const
|
|
25118
|
+
const join49 = compileJoin(step, id, sink);
|
|
24879
25119
|
const requiredEvidence = compileEvidence(step, id, sink);
|
|
24880
25120
|
const transitions = compileTransitions(step, id, index, stepIndex, sink);
|
|
24881
25121
|
const outcomes = Object.keys(transitions).sort(compareCodeUnits4);
|
|
@@ -24903,7 +25143,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
24903
25143
|
transitions: orderedTransitions,
|
|
24904
25144
|
requiresPlanHash: requirePlanHash.includes(id),
|
|
24905
25145
|
assignments,
|
|
24906
|
-
join:
|
|
25146
|
+
join: join49
|
|
24907
25147
|
};
|
|
24908
25148
|
if (kind === "agent" || kind === "moa") {
|
|
24909
25149
|
if (!agent) return void 0;
|
|
@@ -24953,15 +25193,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
|
|
|
24953
25193
|
};
|
|
24954
25194
|
}
|
|
24955
25195
|
function compileJoin(step, stepId, sink) {
|
|
24956
|
-
const
|
|
24957
|
-
if (!
|
|
24958
|
-
const declared = stringValue2(
|
|
25196
|
+
const join49 = objectValue2(step.join);
|
|
25197
|
+
if (!join49) return { strategy: "all" };
|
|
25198
|
+
const declared = stringValue2(join49.strategy);
|
|
24959
25199
|
const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
|
|
24960
|
-
const minimumPassed = compileOptionalCount(
|
|
25200
|
+
const minimumPassed = compileOptionalCount(join49.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
|
|
24961
25201
|
const compiled = {
|
|
24962
25202
|
strategy,
|
|
24963
25203
|
...minimumPassed !== void 0 ? { minimumPassed } : {},
|
|
24964
|
-
...typeof
|
|
25204
|
+
...typeof join49.cancelRemaining === "boolean" ? { cancelRemaining: join49.cancelRemaining } : {}
|
|
24965
25205
|
};
|
|
24966
25206
|
return compiled;
|
|
24967
25207
|
}
|
|
@@ -25241,7 +25481,7 @@ var RECORD_LIMIT = 16 * 1024 * 1024;
|
|
|
25241
25481
|
// plugins/kxm/src/prices.ts
|
|
25242
25482
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
25243
25483
|
import { createHash as createHash11 } from "node:crypto";
|
|
25244
|
-
import { existsSync as existsSync11, readFileSync as readFileSync9, statSync } from "node:fs";
|
|
25484
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9, statSync, writeFileSync as writeFileSync7 } from "node:fs";
|
|
25245
25485
|
import { join as join10 } from "node:path";
|
|
25246
25486
|
|
|
25247
25487
|
// plugins/kxm/src/price-calc.ts
|
|
@@ -25413,13 +25653,38 @@ function loadPriceCatalogForEstimate(options) {
|
|
|
25413
25653
|
}
|
|
25414
25654
|
return { catalog, unavailable: false, stale: false };
|
|
25415
25655
|
}
|
|
25656
|
+
function acknowledgePriceCatalog(projectRoot, now = /* @__PURE__ */ new Date()) {
|
|
25657
|
+
const path4 = join10(projectRoot, ".kxm", "prices.yaml");
|
|
25658
|
+
const loaded = loadPriceCatalog(projectRoot);
|
|
25659
|
+
if (!loaded) throw new Error("price catalog missing");
|
|
25660
|
+
const date = now.toISOString().slice(0, 10);
|
|
25661
|
+
const body = {
|
|
25662
|
+
schema: loaded.schema,
|
|
25663
|
+
date,
|
|
25664
|
+
currency: loaded.currency ?? "USD",
|
|
25665
|
+
models: loaded.models
|
|
25666
|
+
};
|
|
25667
|
+
const stamped = { ...body, sha256: hashPriceCatalog(body) };
|
|
25668
|
+
writeFileSync7(path4, (0, import_yaml3.stringify)({
|
|
25669
|
+
schema: stamped.schema,
|
|
25670
|
+
date: stamped.date,
|
|
25671
|
+
sha256: stamped.sha256,
|
|
25672
|
+
currency: stamped.currency ?? "USD",
|
|
25673
|
+
models: stamped.models
|
|
25674
|
+
}), "utf8");
|
|
25675
|
+
const again = loadPriceCatalog(projectRoot);
|
|
25676
|
+
if (!again || again.date !== date || again.sha256 !== stamped.sha256) {
|
|
25677
|
+
throw new Error("price catalog acknowledge failed verification");
|
|
25678
|
+
}
|
|
25679
|
+
return again;
|
|
25680
|
+
}
|
|
25416
25681
|
|
|
25417
25682
|
// plugins/kxm/src/engine.ts
|
|
25418
25683
|
var import_yaml7 = __toESM(require_dist(), 1);
|
|
25419
25684
|
|
|
25420
25685
|
// plugins/kxm/src/routes.ts
|
|
25421
25686
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
25422
|
-
import { existsSync as existsSync12, readFileSync as readFileSync10, mkdirSync as mkdirSync7, writeFileSync as
|
|
25687
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10, mkdirSync as mkdirSync7, writeFileSync as writeFileSync8, readdirSync as readdirSync3 } from "node:fs";
|
|
25423
25688
|
import { join as join11 } from "node:path";
|
|
25424
25689
|
var RETIRED_POLICY = ".kxm/producers.yaml";
|
|
25425
25690
|
var empty = () => ({ schema: "kxm.routes.v2", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), admitted: [], disabled: [], roles: {} });
|
|
@@ -25457,11 +25722,11 @@ function setRouteState(root, model, state, role, removeRole2 = false) {
|
|
|
25457
25722
|
roleFile.id ??= role;
|
|
25458
25723
|
roleFile.roster = roster;
|
|
25459
25724
|
mkdirSync7(join11(root, ".kxm", "roles"), { recursive: true });
|
|
25460
|
-
|
|
25725
|
+
writeFileSync8(rolePath, (0, import_yaml4.stringify)(roleFile), "utf8");
|
|
25461
25726
|
}
|
|
25462
25727
|
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
25463
25728
|
mkdirSync7(join11(root, ".kxm"), { recursive: true });
|
|
25464
|
-
|
|
25729
|
+
writeFileSync8(join11(root, ".kxm", "routes.yaml"), (0, import_yaml4.stringify)(policy), "utf8");
|
|
25465
25730
|
return policy;
|
|
25466
25731
|
}
|
|
25467
25732
|
function listRoleBindings(root) {
|
|
@@ -25485,7 +25750,7 @@ function listInventoryModels(root) {
|
|
|
25485
25750
|
// plugins/kxm/src/memory.ts
|
|
25486
25751
|
var import_yaml5 = __toESM(require_dist(), 1);
|
|
25487
25752
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
25488
|
-
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readdirSync as readdirSync4, readFileSync as readFileSync11, writeFileSync as
|
|
25753
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readdirSync as readdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "node:fs";
|
|
25489
25754
|
import { extname as extname2, join as join12, resolve as resolve8 } from "node:path";
|
|
25490
25755
|
var MEMORY_SCHEMA = "kxm.memory.v1";
|
|
25491
25756
|
var MEMORY_BRIEF_SCHEMA = "kxm.memory-brief.v1";
|
|
@@ -25667,7 +25932,7 @@ function createMemoryNote(repoRoot, summary, options = {}) {
|
|
|
25667
25932
|
const targetPath = join12(candidatesDir, `${id}.md`);
|
|
25668
25933
|
if (options.dryRun) return { record, path: targetPath };
|
|
25669
25934
|
mkdirSync8(candidatesDir, { recursive: true });
|
|
25670
|
-
|
|
25935
|
+
writeFileSync9(targetPath, formatMemoryRecord(record), "utf8");
|
|
25671
25936
|
return { record, path: targetPath };
|
|
25672
25937
|
}
|
|
25673
25938
|
function generateMemoryBrief(repoRoot) {
|
|
@@ -25751,7 +26016,7 @@ function syncHarnessMemory(repoRoot, options = {}) {
|
|
|
25751
26016
|
if (next === original) {
|
|
25752
26017
|
unchanged.push(name);
|
|
25753
26018
|
} else {
|
|
25754
|
-
if (!options.dryRun)
|
|
26019
|
+
if (!options.dryRun) writeFileSync9(join12(root, name), next, "utf8");
|
|
25755
26020
|
updated.push(name);
|
|
25756
26021
|
}
|
|
25757
26022
|
}
|
|
@@ -25761,7 +26026,7 @@ function syncHarnessMemory(repoRoot, options = {}) {
|
|
|
25761
26026
|
// plugins/kxm/src/skills.ts
|
|
25762
26027
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
25763
26028
|
import { createHash as createHash12 } from "node:crypto";
|
|
25764
|
-
import { existsSync as existsSync14, mkdirSync as mkdirSync9, readdirSync as readdirSync5, readFileSync as readFileSync12, renameSync as renameSync3, rmSync as rmSync3, statSync as statSync2, writeFileSync as
|
|
26029
|
+
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";
|
|
25765
26030
|
import { dirname as dirname9, join as join13 } from "node:path";
|
|
25766
26031
|
var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
|
|
25767
26032
|
var SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
|
|
@@ -25865,7 +26130,7 @@ var SkillLifecycle = class {
|
|
|
25865
26130
|
return;
|
|
25866
26131
|
}
|
|
25867
26132
|
mkdirSync9(dirname9(file), { recursive: true });
|
|
25868
|
-
|
|
26133
|
+
writeFileSync10(file, content);
|
|
25869
26134
|
}
|
|
25870
26135
|
dir(state) {
|
|
25871
26136
|
return join13(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
|
|
@@ -26502,6 +26767,8 @@ function compareRoutingRecords(records) {
|
|
|
26502
26767
|
const blocked = settled.filter((record) => record.finalOutcome === "blocked").length;
|
|
26503
26768
|
const failed2 = settled.filter((record) => record.finalOutcome === "failed").length;
|
|
26504
26769
|
const reworked = records.filter((record) => record.retries > 0 || record.transitions > 0).length;
|
|
26770
|
+
const missingCostRuns = records.filter((record) => typeof record.costUsd !== "number" || !Number.isFinite(record.costUsd)).length;
|
|
26771
|
+
const summedCost = records.reduce((sum, record) => sum + (typeof record.costUsd === "number" && Number.isFinite(record.costUsd) ? record.costUsd : 0), 0);
|
|
26505
26772
|
return {
|
|
26506
26773
|
behavioralSha256,
|
|
26507
26774
|
runs: records.length,
|
|
@@ -26509,7 +26776,8 @@ function compareRoutingRecords(records) {
|
|
|
26509
26776
|
blocked,
|
|
26510
26777
|
failed: failed2,
|
|
26511
26778
|
reworkRate: records.length === 0 ? 0 : Math.round(reworked / records.length * 100) / 100,
|
|
26512
|
-
totalCostUsd:
|
|
26779
|
+
totalCostUsd: missingCostRuns > 0 ? null : Math.round(summedCost * 1e4) / 1e4,
|
|
26780
|
+
missingCostRuns,
|
|
26513
26781
|
totalTokensIn: records.reduce((sum, record) => sum + (record.tokensIn ?? 0), 0),
|
|
26514
26782
|
totalTokensOut: records.reduce((sum, record) => sum + (record.tokensOut ?? 0), 0),
|
|
26515
26783
|
totalHumanInterventions: records.reduce((sum, record) => sum + record.humanInterventions, 0)
|
|
@@ -26643,7 +26911,7 @@ function generateRoutingReport(records, options = {}) {
|
|
|
26643
26911
|
medianContextTokens = contextVals.length % 2 !== 0 ? contextVals[mid] : Math.round((contextVals[mid - 1] + contextVals[mid]) / 2);
|
|
26644
26912
|
}
|
|
26645
26913
|
const meteredCostUsd = Math.round(meteredCostTotal * 1e4) / 1e4;
|
|
26646
|
-
const costPerAcceptedUsd = acceptedCount > 0 ? meteredCostUsd > 0 || unmeteredAttempts > 0 ? Math.round(meteredCostUsd / acceptedCount * 1e4) / 1e4 :
|
|
26914
|
+
const costPerAcceptedUsd = acceptedCount > 0 ? unknownCostAttempts > 0 ? null : meteredCostUsd > 0 || unmeteredAttempts > 0 ? Math.round(meteredCostUsd / acceptedCount * 1e4) / 1e4 : 0 : null;
|
|
26647
26915
|
const flagged = unknownCostAttempts > 0;
|
|
26648
26916
|
let equivalentListCostUsd = void 0;
|
|
26649
26917
|
if (options.includeEquivalentListCost && options.catalog) {
|
|
@@ -26800,7 +27068,7 @@ var ENGINE_ROUTING_METADATA_KEYS = /* @__PURE__ */ new Set(["workflowId", "askSh
|
|
|
26800
27068
|
var MAX_PRODUCER_ROUTING_METADATA_FIELDS = MAX_PROVIDER_METADATA_FIELDS - ENGINE_ROUTING_METADATA_KEYS.size;
|
|
26801
27069
|
|
|
26802
27070
|
// plugins/kxm/src/hub-binding.ts
|
|
26803
|
-
import { existsSync as existsSync15, mkdirSync as mkdirSync10, readFileSync as readFileSync13, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as
|
|
27071
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync10, readFileSync as readFileSync13, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as writeFileSync11 } from "node:fs";
|
|
26804
27072
|
import { homedir as homedir4 } from "node:os";
|
|
26805
27073
|
import { dirname as dirname10, isAbsolute as isAbsolute5, join as join14, resolve as resolve10 } from "node:path";
|
|
26806
27074
|
var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
@@ -26892,7 +27160,7 @@ function writeHubBinding(record, env = process.env) {
|
|
|
26892
27160
|
mkdirSync10(dirname10(file), { recursive: true, mode: 448 });
|
|
26893
27161
|
const temporary = join14(dirname10(file), `.hub-binding-${process.pid}.tmp`);
|
|
26894
27162
|
try {
|
|
26895
|
-
|
|
27163
|
+
writeFileSync11(temporary, `${JSON.stringify(record, null, 2)}
|
|
26896
27164
|
`, { encoding: "utf8", mode: 384 });
|
|
26897
27165
|
renameSync4(temporary, file);
|
|
26898
27166
|
} finally {
|
|
@@ -27026,7 +27294,7 @@ async function probeSupervisor(port, expectedRuntimeId, token, timeoutMs = 750)
|
|
|
27026
27294
|
}
|
|
27027
27295
|
}
|
|
27028
27296
|
function hashKxmTokenProof(token, nonce) {
|
|
27029
|
-
return
|
|
27297
|
+
return createHmac2("sha256", token).update(`kxm-runtime-token-proof\0${nonce}`, "utf8").digest("hex");
|
|
27030
27298
|
}
|
|
27031
27299
|
async function attachKxmSupervisor(options = {}) {
|
|
27032
27300
|
const paths = kxmRuntimePaths(options.stateRoot !== void 0 ? { stateRoot: options.stateRoot } : { ...options.env ? { env: options.env } : {} });
|
|
@@ -27406,12 +27674,12 @@ import { createInterface } from "node:readline";
|
|
|
27406
27674
|
|
|
27407
27675
|
// plugins/kxm/src/role.ts
|
|
27408
27676
|
var import_yaml9 = __toESM(require_dist(), 1);
|
|
27409
|
-
import { existsSync as existsSync18, mkdirSync as mkdirSync14, readdirSync as readdirSync6, readFileSync as readFileSync17, rmSync as rmSync6, writeFileSync as
|
|
27677
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync14, readdirSync as readdirSync6, readFileSync as readFileSync17, rmSync as rmSync6, writeFileSync as writeFileSync14 } from "node:fs";
|
|
27410
27678
|
import { join as join19 } from "node:path";
|
|
27411
27679
|
|
|
27412
27680
|
// plugins/kxm/src/config.ts
|
|
27413
27681
|
var import_yaml8 = __toESM(require_dist(), 1);
|
|
27414
|
-
import { existsSync as existsSync17, mkdirSync as mkdirSync13, readFileSync as readFileSync16, writeFileSync as
|
|
27682
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync13, readFileSync as readFileSync16, writeFileSync as writeFileSync13 } from "node:fs";
|
|
27415
27683
|
import { homedir as homedir5 } from "node:os";
|
|
27416
27684
|
import { dirname as dirname13, join as join18, resolve as resolve12 } from "node:path";
|
|
27417
27685
|
var KXM_CONFIG_SCHEMA = "kxm.config.v1";
|
|
@@ -27591,7 +27859,7 @@ function readConfigFile(targetFile2) {
|
|
|
27591
27859
|
}
|
|
27592
27860
|
function writeConfigFile(targetFile2, value) {
|
|
27593
27861
|
mkdirSync13(dirname13(targetFile2), { recursive: true });
|
|
27594
|
-
|
|
27862
|
+
writeFileSync13(targetFile2, (0, import_yaml8.stringify)(value).trim() + "\n", "utf8");
|
|
27595
27863
|
}
|
|
27596
27864
|
function setKxmConfigValue(repoRoot, keyPath, value, options = {}) {
|
|
27597
27865
|
const targetFile2 = kxmConfigFileForScope(repoRoot, options.scope ?? "project", options.userConfigDir);
|
|
@@ -27824,7 +28092,7 @@ function addRole(role, options = {}) {
|
|
|
27824
28092
|
if (existsSync18(filePath) && !options.overwrite) {
|
|
27825
28093
|
throw new Error(`role_already_exists: role '${role.id}' already exists at ${filePath}`);
|
|
27826
28094
|
}
|
|
27827
|
-
if (!options.dryRun)
|
|
28095
|
+
if (!options.dryRun) writeFileSync14(filePath, (0, import_yaml9.stringify)(role), "utf8");
|
|
27828
28096
|
return { id: role.id, filePath, scope };
|
|
27829
28097
|
}
|
|
27830
28098
|
function removeRole(roleId, options = {}) {
|
|
@@ -27855,7 +28123,7 @@ function modifyRole(roleId, updates, options = {}) {
|
|
|
27855
28123
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
27856
28124
|
const dir = options.dryRun ? rolesDirectory(scope, repoRoot, options.userConfigDir) : ensureRolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
27857
28125
|
const filePath = join19(dir, `${roleId}.yaml`);
|
|
27858
|
-
if (!options.dryRun)
|
|
28126
|
+
if (!options.dryRun) writeFileSync14(filePath, (0, import_yaml9.stringify)(updated), "utf8");
|
|
27859
28127
|
return { id: roleId, role: updated, filePath, scope };
|
|
27860
28128
|
}
|
|
27861
28129
|
var KXM_ROLE_HOSTS_SCHEMA = "kxm.role-hosts.v1";
|
|
@@ -27998,7 +28266,7 @@ function saveRoleHostsConfig(config, options = {}) {
|
|
|
27998
28266
|
...config.hostProviders && Object.keys(config.hostProviders).length > 0 ? { hostProviders: config.hostProviders } : {}
|
|
27999
28267
|
};
|
|
28000
28268
|
const content = format === "json" ? JSON.stringify(payload, null, 2) + "\n" : (0, import_yaml9.stringify)(payload);
|
|
28001
|
-
|
|
28269
|
+
writeFileSync14(filePath, content, "utf8");
|
|
28002
28270
|
return { filePath, scope };
|
|
28003
28271
|
}
|
|
28004
28272
|
function setRoleSeatHost(seatId, host, options = {}) {
|
|
@@ -28639,12 +28907,12 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
28639
28907
|
}
|
|
28640
28908
|
|
|
28641
28909
|
// plugins/kxm/src/cli/workflows.ts
|
|
28642
|
-
import {
|
|
28910
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
28643
28911
|
import { existsSync as existsSync21, readFileSync as readFileSync20 } from "node:fs";
|
|
28644
28912
|
import { join as join22, resolve as resolve17 } from "node:path";
|
|
28645
28913
|
|
|
28646
28914
|
// plugins/kxm/src/retrospective.ts
|
|
28647
|
-
import { mkdirSync as mkdirSync15, renameSync as renameSync6, writeFileSync as
|
|
28915
|
+
import { mkdirSync as mkdirSync15, renameSync as renameSync6, writeFileSync as writeFileSync15 } from "node:fs";
|
|
28648
28916
|
import { resolve as resolve15 } from "node:path";
|
|
28649
28917
|
var MAX_RETROSPECTIVE_ENTRIES = 500;
|
|
28650
28918
|
var SAFE_RUN_ID = /^run_[A-Za-z0-9_-]{1,120}$/;
|
|
@@ -28871,16 +29139,16 @@ function writeRetrospective(outDir, doc) {
|
|
|
28871
29139
|
if (!jsonPath.startsWith(prefix) || !mdPath.startsWith(prefix)) throw new Error("retrospective path escaped output directory");
|
|
28872
29140
|
const jsonTmp = `${jsonPath}.tmp`;
|
|
28873
29141
|
const mdTmp = `${mdPath}.tmp`;
|
|
28874
|
-
|
|
29142
|
+
writeFileSync15(jsonTmp, `${JSON.stringify(doc, null, 2)}
|
|
28875
29143
|
`, { encoding: "utf8", mode: 384 });
|
|
28876
|
-
|
|
29144
|
+
writeFileSync15(mdTmp, renderRetrospectiveMarkdown(doc), { encoding: "utf8", mode: 384 });
|
|
28877
29145
|
renameSync6(jsonTmp, jsonPath);
|
|
28878
29146
|
renameSync6(mdTmp, mdPath);
|
|
28879
29147
|
return { jsonPath, mdPath };
|
|
28880
29148
|
}
|
|
28881
29149
|
|
|
28882
29150
|
// plugins/kxm/src/github-watch.ts
|
|
28883
|
-
import {
|
|
29151
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
28884
29152
|
async function fetchWithTimeout(fetchImpl, input, init, timeoutMs) {
|
|
28885
29153
|
const controller = new AbortController();
|
|
28886
29154
|
const timer = setTimeout(() => controller.abort(), Math.max(1, timeoutMs));
|
|
@@ -28928,7 +29196,6 @@ function mapCheckConclusion(runs, required = []) {
|
|
|
28928
29196
|
}
|
|
28929
29197
|
async function postWorkflowSignal(input) {
|
|
28930
29198
|
const body = JSON.stringify({ status: input.status, summary: input.summary, evidence: input.evidence });
|
|
28931
|
-
const signature = `sha256=${createHmac2("sha256", input.signalSecret).update(body).digest("hex")}`;
|
|
28932
29199
|
const endpoint = [
|
|
28933
29200
|
input.serverUrl.replace(/\/$/, ""),
|
|
28934
29201
|
"v1/webhooks",
|
|
@@ -28942,8 +29209,12 @@ async function postWorkflowSignal(input) {
|
|
|
28942
29209
|
method: "POST",
|
|
28943
29210
|
headers: {
|
|
28944
29211
|
"content-type": "application/json",
|
|
28945
|
-
|
|
28946
|
-
|
|
29212
|
+
...workflowWebhookHeaders({
|
|
29213
|
+
secret: input.signalSecret,
|
|
29214
|
+
scope: { definitionId: input.definitionId, runId: input.runId, signalKey: input.signalKey },
|
|
29215
|
+
deliveryId: input.deliveryId,
|
|
29216
|
+
body
|
|
29217
|
+
})
|
|
28947
29218
|
},
|
|
28948
29219
|
body
|
|
28949
29220
|
}, input.timeoutMs ?? 15e3);
|
|
@@ -29065,7 +29336,7 @@ async function watchGithubChecks(input) {
|
|
|
29065
29336
|
|
|
29066
29337
|
// plugins/kxm/src/workflow-manager.ts
|
|
29067
29338
|
var import_yaml11 = __toESM(require_dist(), 1);
|
|
29068
|
-
import { existsSync as existsSync20, mkdirSync as mkdirSync16, readdirSync as readdirSync7, readFileSync as readFileSync19, rmSync as rmSync7, writeFileSync as
|
|
29339
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync16, readdirSync as readdirSync7, readFileSync as readFileSync19, rmSync as rmSync7, writeFileSync as writeFileSync16 } from "node:fs";
|
|
29069
29340
|
import { join as join21 } from "node:path";
|
|
29070
29341
|
var completed = () => ({ target: "$terminal", terminalStatus: "completed" });
|
|
29071
29342
|
var failed = () => ({ target: "$terminal", terminalStatus: "failed" });
|
|
@@ -29324,7 +29595,7 @@ function addWorkflowDefinition(workflowId, content = DEFAULT_WORKFLOW_TEMPLATE,
|
|
|
29324
29595
|
throw new Error(`workflow_already_exists: workflow '${workflowId}' already exists at ${filePath}`);
|
|
29325
29596
|
}
|
|
29326
29597
|
const payload = typeof content === "string" ? content : (0, import_yaml11.stringify)(content);
|
|
29327
|
-
if (!options.dryRun)
|
|
29598
|
+
if (!options.dryRun) writeFileSync16(filePath, payload, "utf8");
|
|
29328
29599
|
return { id: workflowId, filePath, scope };
|
|
29329
29600
|
}
|
|
29330
29601
|
function removeWorkflowDefinition(workflowId, options = {}) {
|
|
@@ -29352,7 +29623,7 @@ function modifyWorkflowDefinition(workflowId, updates, options = {}) {
|
|
|
29352
29623
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
29353
29624
|
const dir = options.dryRun ? workflowsDirectory(scope, repoRoot, options.userConfigDir) : ensureWorkflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
29354
29625
|
const filePath = join21(dir, `${workflowId}.yaml`);
|
|
29355
|
-
if (!options.dryRun)
|
|
29626
|
+
if (!options.dryRun) writeFileSync16(filePath, (0, import_yaml11.stringify)(updated), "utf8");
|
|
29356
29627
|
return { id: workflowId, workflow: updated, filePath, scope };
|
|
29357
29628
|
}
|
|
29358
29629
|
|
|
@@ -29373,13 +29644,16 @@ function localWorkflowSnapshot(dataPath, runId) {
|
|
|
29373
29644
|
async function postWorkflowStart(input) {
|
|
29374
29645
|
const payload = input.event && input.payload["event"] === void 0 ? { ...input.payload, event: input.event } : input.payload;
|
|
29375
29646
|
const body = JSON.stringify(payload);
|
|
29376
|
-
const signature = `sha256=${createHmac3("sha256", input.secret).update(body).digest("hex")}`;
|
|
29377
29647
|
const response = await input.fetchImpl(`${input.serverUrl.replace(/\/$/, "")}/v1/webhooks/${encodeURIComponent(input.definitionId)}`, {
|
|
29378
29648
|
method: "POST",
|
|
29379
29649
|
headers: {
|
|
29380
29650
|
"content-type": "application/json",
|
|
29381
|
-
|
|
29382
|
-
|
|
29651
|
+
...workflowWebhookHeaders({
|
|
29652
|
+
secret: input.secret,
|
|
29653
|
+
scope: { definitionId: input.definitionId },
|
|
29654
|
+
deliveryId: input.deliveryId,
|
|
29655
|
+
body
|
|
29656
|
+
}),
|
|
29383
29657
|
...input.event ? { "x-github-event": input.event } : {}
|
|
29384
29658
|
},
|
|
29385
29659
|
body
|
|
@@ -29393,7 +29667,7 @@ async function postWorkflowStart(input) {
|
|
|
29393
29667
|
if (!response.ok) throw new Error(`workflow_start_http_${response.status}`);
|
|
29394
29668
|
return {
|
|
29395
29669
|
status: response.status,
|
|
29396
|
-
...parsed.
|
|
29670
|
+
...parsed.runId ? { runId: parsed.runId } : {},
|
|
29397
29671
|
duplicate: parsed.duplicate === true
|
|
29398
29672
|
};
|
|
29399
29673
|
}
|
|
@@ -29798,7 +30072,7 @@ async function cmdSignal(runtime, runId, signalKey, status, summary, evidenceArg
|
|
|
29798
30072
|
}
|
|
29799
30073
|
const worker = gateOf(runtime, "signal");
|
|
29800
30074
|
const projectRoot = discoverKxmProjectRoot(runtime.cwd);
|
|
29801
|
-
if (projectRoot &&
|
|
30075
|
+
if (projectRoot && projectRuntimeOwnsRun(projectRoot, runId, runtime.env)) {
|
|
29802
30076
|
if (runtime.dryRun) {
|
|
29803
30077
|
printWorker(runtime, worker, { ok: true, command: "signal", dryRun: true, runId, signalKey, status, summary, evidence }, "would post signal to KXM run");
|
|
29804
30078
|
return 0;
|
|
@@ -30076,7 +30350,7 @@ function suggestWorkflowAndRoles(prompt, options = {}) {
|
|
|
30076
30350
|
// plugins/kxm/src/task-manager.ts
|
|
30077
30351
|
var import_yaml12 = __toESM(require_dist(), 1);
|
|
30078
30352
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
30079
|
-
import { existsSync as existsSync22, mkdirSync as mkdirSync17, readFileSync as readFileSync21, readdirSync as readdirSync8, writeFileSync as
|
|
30353
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync17, readFileSync as readFileSync21, readdirSync as readdirSync8, writeFileSync as writeFileSync17 } from "node:fs";
|
|
30080
30354
|
import { join as join23, resolve as resolve18 } from "node:path";
|
|
30081
30355
|
var GOAL_SCHEMA = "kxm.goal.v1";
|
|
30082
30356
|
var TASK_SCHEMA = "kxm.task.v1";
|
|
@@ -30108,7 +30382,7 @@ function createGoal(repoRoot, input, options = {}) {
|
|
|
30108
30382
|
};
|
|
30109
30383
|
if (options.dryRun) return record;
|
|
30110
30384
|
mkdirSync17(goalsDirectory(repoRoot), { recursive: true });
|
|
30111
|
-
|
|
30385
|
+
writeFileSync17(goalFilePath(repoRoot, id), (0, import_yaml12.stringify)(record).trim() + "\n", "utf8");
|
|
30112
30386
|
return record;
|
|
30113
30387
|
}
|
|
30114
30388
|
function listGoals(repoRoot) {
|
|
@@ -30152,7 +30426,7 @@ function createTask(repoRoot, input, options = {}) {
|
|
|
30152
30426
|
};
|
|
30153
30427
|
if (options.dryRun) return record;
|
|
30154
30428
|
mkdirSync17(tasksDirectory(repoRoot), { recursive: true });
|
|
30155
|
-
|
|
30429
|
+
writeFileSync17(taskFilePath(repoRoot, id), (0, import_yaml12.stringify)(record).trim() + "\n", "utf8");
|
|
30156
30430
|
return record;
|
|
30157
30431
|
}
|
|
30158
30432
|
function listTasks(repoRoot, options = {}) {
|
|
@@ -30196,7 +30470,7 @@ function updateTaskStatus(repoRoot, taskId, status, options = {}) {
|
|
|
30196
30470
|
task.status = status;
|
|
30197
30471
|
if (options.workflowRunId) task.workflowRunId = options.workflowRunId;
|
|
30198
30472
|
task.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
30199
|
-
if (!options.dryRun)
|
|
30473
|
+
if (!options.dryRun) writeFileSync17(taskFilePath(repoRoot, taskId), (0, import_yaml12.stringify)(task).trim() + "\n", "utf8");
|
|
30200
30474
|
return task;
|
|
30201
30475
|
}
|
|
30202
30476
|
function syncTaskWithTracker(repoRoot, taskId, options = {}) {
|
|
@@ -30211,7 +30485,7 @@ function syncTaskWithTracker(repoRoot, taskId, options = {}) {
|
|
|
30211
30485
|
task.trackerSync.syncStatus = "synced";
|
|
30212
30486
|
task.trackerSync.lastSyncedAt = now;
|
|
30213
30487
|
task.updatedAt = now;
|
|
30214
|
-
if (!options.dryRun)
|
|
30488
|
+
if (!options.dryRun) writeFileSync17(taskFilePath(repoRoot, taskId), (0, import_yaml12.stringify)(task).trim() + "\n", "utf8");
|
|
30215
30489
|
return task;
|
|
30216
30490
|
}
|
|
30217
30491
|
|
|
@@ -30492,13 +30766,14 @@ function createStudioServer(options = {}) {
|
|
|
30492
30766
|
}
|
|
30493
30767
|
return;
|
|
30494
30768
|
}
|
|
30495
|
-
res.writeHead(
|
|
30769
|
+
res.writeHead(501, { "Content-Type": "application/json" });
|
|
30496
30770
|
res.end(JSON.stringify({
|
|
30497
|
-
ok:
|
|
30771
|
+
ok: false,
|
|
30772
|
+
executed: false,
|
|
30498
30773
|
mutationId,
|
|
30499
30774
|
command,
|
|
30500
|
-
mappedToCli:
|
|
30501
|
-
|
|
30775
|
+
mappedToCli: false,
|
|
30776
|
+
error: "mutation_handler_missing"
|
|
30502
30777
|
}));
|
|
30503
30778
|
return;
|
|
30504
30779
|
}
|
|
@@ -30983,7 +31258,7 @@ import { createInterface as createInterface2 } from "node:readline";
|
|
|
30983
31258
|
|
|
30984
31259
|
// plugins/kxm/src/model-inventory.ts
|
|
30985
31260
|
var import_yaml13 = __toESM(require_dist(), 1);
|
|
30986
|
-
import { mkdirSync as mkdirSync18, writeFileSync as
|
|
31261
|
+
import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync18 } from "node:fs";
|
|
30987
31262
|
import { join as join24 } from "node:path";
|
|
30988
31263
|
var OR_URL = "https://openrouter.ai/api/v1/models";
|
|
30989
31264
|
var NOUS_URL = "https://inference-api.nousresearch.com/v1/models";
|
|
@@ -31071,7 +31346,7 @@ async function refreshModelInventory(options) {
|
|
|
31071
31346
|
for (const item of nous.data) add(item, "nous", "discount");
|
|
31072
31347
|
const inventory = { schema: "kxm.model-inventory.v1", fetchedAt, currency: "USD", sources, models: [...byId.values()].sort((a, b2) => a.id.localeCompare(b2.id)) };
|
|
31073
31348
|
mkdirSync18(join24(options.outputRoot, ".kxm", "models"), { recursive: true });
|
|
31074
|
-
|
|
31349
|
+
writeFileSync18(join24(options.outputRoot, ".kxm", "models", "inventory.yaml"), (0, import_yaml13.stringify)(inventory), "utf8");
|
|
31075
31350
|
return inventory;
|
|
31076
31351
|
}
|
|
31077
31352
|
|
|
@@ -31095,14 +31370,14 @@ import {
|
|
|
31095
31370
|
readdirSync as readdirSync9,
|
|
31096
31371
|
renameSync as renameSync7,
|
|
31097
31372
|
rmSync as rmSync9,
|
|
31098
|
-
writeFileSync as
|
|
31373
|
+
writeFileSync as writeFileSync20
|
|
31099
31374
|
} from "node:fs";
|
|
31100
31375
|
import { dirname as dirname17, isAbsolute as isAbsolute7, join as join26, relative as relative4, resolve as resolve20 } from "node:path";
|
|
31101
31376
|
|
|
31102
31377
|
// plugins/kxm/src/permission.ts
|
|
31103
31378
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
31104
31379
|
import { createHash as createHash14 } from "node:crypto";
|
|
31105
|
-
import { existsSync as existsSync23, mkdtempSync, mkdirSync as mkdirSync19, readFileSync as readFileSync22, rmSync as rmSync8, writeFileSync as
|
|
31380
|
+
import { existsSync as existsSync23, mkdtempSync, mkdirSync as mkdirSync19, readFileSync as readFileSync22, rmSync as rmSync8, writeFileSync as writeFileSync19 } from "node:fs";
|
|
31106
31381
|
import { tmpdir } from "node:os";
|
|
31107
31382
|
import { dirname as dirname16, join as join25, resolve as resolve19, sep as sep3 } from "node:path";
|
|
31108
31383
|
var PROSE_FIELDS = {
|
|
@@ -31651,7 +31926,7 @@ function loadKxmProjectAtRevision(root, revision, options = {}) {
|
|
|
31651
31926
|
}
|
|
31652
31927
|
const content = gitBuffer(root, ["cat-file", "blob", `${tree}:${path4}`]);
|
|
31653
31928
|
mkdirSync19(dirname16(absolute), { recursive: true });
|
|
31654
|
-
|
|
31929
|
+
writeFileSync19(absolute, content);
|
|
31655
31930
|
}
|
|
31656
31931
|
initShadowGitRoot(shadowResolved);
|
|
31657
31932
|
const baseProjectFile = join25(shadowResolved, ".kxm", "project.yaml");
|
|
@@ -31753,7 +32028,7 @@ function loadKxmProjectAtRevision(root, revision, options = {}) {
|
|
|
31753
32028
|
}
|
|
31754
32029
|
const content = gitBuffer(memberWorktree, ["cat-file", "blob", `${memberTree}:${path4}`]);
|
|
31755
32030
|
mkdirSync19(dirname16(absolute), { recursive: true });
|
|
31756
|
-
|
|
32031
|
+
writeFileSync19(absolute, content);
|
|
31757
32032
|
}
|
|
31758
32033
|
initShadowGitRoot(memberShadowRoot);
|
|
31759
32034
|
shadowBindings[member.repositoryId] = memberShadowRoot;
|
|
@@ -31867,7 +32142,7 @@ function writeDurableNew(file, bytes, mode) {
|
|
|
31867
32142
|
let descriptor;
|
|
31868
32143
|
try {
|
|
31869
32144
|
descriptor = openSync2(file, "wx", mode);
|
|
31870
|
-
|
|
32145
|
+
writeFileSync20(descriptor, bytes);
|
|
31871
32146
|
fsyncSync2(descriptor);
|
|
31872
32147
|
closeSync2(descriptor);
|
|
31873
32148
|
descriptor = void 0;
|
|
@@ -31884,7 +32159,7 @@ function writeDurable(file, bytes, mode) {
|
|
|
31884
32159
|
let descriptor;
|
|
31885
32160
|
try {
|
|
31886
32161
|
descriptor = openSync2(file, "w", mode);
|
|
31887
|
-
|
|
32162
|
+
writeFileSync20(descriptor, bytes);
|
|
31888
32163
|
fsyncSync2(descriptor);
|
|
31889
32164
|
closeSync2(descriptor);
|
|
31890
32165
|
descriptor = void 0;
|
|
@@ -33308,36 +33583,39 @@ async function cmdBackup(runtime, options) {
|
|
|
33308
33583
|
try {
|
|
33309
33584
|
const backupOptions = {
|
|
33310
33585
|
projectRoot: runtime.cwd,
|
|
33586
|
+
env: runtime.env,
|
|
33311
33587
|
...options.out ? { outDir: resolve21(runtime.cwd, options.out) } : {}
|
|
33312
33588
|
};
|
|
33313
33589
|
if (runtime.dryRun) {
|
|
33314
33590
|
const plan = planBackup(backupOptions);
|
|
33315
33591
|
printPlan(
|
|
33316
33592
|
runtime,
|
|
33317
|
-
{ command: "backup", outDir: plan.outDir, stores: plan.stores },
|
|
33593
|
+
{ command: "backup", outDir: plan.outDir, stores: plan.stores, files: plan.files },
|
|
33318
33594
|
[
|
|
33319
|
-
...plan.stores.map((
|
|
33595
|
+
...[...plan.stores, ...plan.files].map((entry) => ({ action: "write", target: join28(plan.outDir, entry.backupFile) })),
|
|
33320
33596
|
{ action: "write", target: join28(plan.outDir, "manifest.json") }
|
|
33321
33597
|
],
|
|
33322
|
-
`back up ${plan.stores.length} store(s) to ${plan.outDir} (sources are not opened, so their WAL is not checkpointed)`
|
|
33598
|
+
`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)`
|
|
33323
33599
|
);
|
|
33324
33600
|
return 0;
|
|
33325
33601
|
}
|
|
33326
33602
|
const { manifest, outDir } = createBackup(backupOptions);
|
|
33603
|
+
const complete = manifest.complete === true;
|
|
33327
33604
|
const payload = {
|
|
33328
|
-
ok:
|
|
33605
|
+
ok: complete,
|
|
33329
33606
|
command: "backup",
|
|
33330
33607
|
backupId: manifest.backupId,
|
|
33331
33608
|
outDir,
|
|
33332
33609
|
manifest
|
|
33333
33610
|
};
|
|
33334
33611
|
const summary = [
|
|
33335
|
-
`Created SQLite backup with ${manifest.stores.length} store(s):`,
|
|
33612
|
+
complete ? `Created SQLite backup with ${manifest.stores.length} store(s):` : `Backup is incomplete (${manifest.omitted?.length ?? 0} omitted); not ok:`,
|
|
33336
33613
|
...manifest.stores.map((s) => ` - ${s.storeId}: ${s.sourcePath} -> ${s.backupFile} (schema v${s.schemaVersion}, ${s.bytes} bytes, sha256 ${s.sha256.slice(0, 12)}...)`),
|
|
33614
|
+
...(manifest.omitted ?? []).map((id) => ` - omitted ${id}`),
|
|
33337
33615
|
`Manifest: ${join28(outDir, "manifest.json")}`
|
|
33338
33616
|
].join("\n");
|
|
33339
33617
|
print(runtime.io, runtime.json, payload, summary);
|
|
33340
|
-
return 0;
|
|
33618
|
+
return complete ? 0 : 1;
|
|
33341
33619
|
} catch (error) {
|
|
33342
33620
|
if (error instanceof KxmConfigError) {
|
|
33343
33621
|
print(runtime.io, runtime.json, { ok: false, command: "backup", error: "backup_failed", issues: error.issues }, `backup failed: ${error.message}`);
|
|
@@ -33357,13 +33635,17 @@ async function cmdRestore(runtime, manifestArg) {
|
|
|
33357
33635
|
command: "restore",
|
|
33358
33636
|
backupId: plan.backupId,
|
|
33359
33637
|
manifestPath: plan.manifestPath,
|
|
33360
|
-
stores: plan.stores.map(({ storeId, targetPath, schemaVersion }) => ({ storeId, targetPath, schemaVersion }))
|
|
33638
|
+
stores: plan.stores.map(({ storeId, targetPath, schemaVersion }) => ({ storeId, targetPath, schemaVersion })),
|
|
33639
|
+
files: plan.files.map(({ id, targetPath }) => ({ id, targetPath }))
|
|
33361
33640
|
},
|
|
33362
|
-
|
|
33363
|
-
|
|
33364
|
-
|
|
33365
|
-
|
|
33366
|
-
|
|
33641
|
+
[
|
|
33642
|
+
...plan.stores.flatMap((store) => [
|
|
33643
|
+
{ action: "write", target: store.targetPath },
|
|
33644
|
+
...[`${store.targetPath}-wal`, `${store.targetPath}-shm`].filter((file) => existsSync26(file)).map((file) => ({ action: "delete", target: file }))
|
|
33645
|
+
]),
|
|
33646
|
+
...plan.files.map((file) => ({ action: "write", target: file.targetPath }))
|
|
33647
|
+
],
|
|
33648
|
+
`restore ${plan.stores.length} store(s) and ${plan.files.length} file(s) from ${plan.manifestPath}; digests verified against the manifest`
|
|
33367
33649
|
);
|
|
33368
33650
|
return 0;
|
|
33369
33651
|
}
|
|
@@ -34340,14 +34622,14 @@ import { readFileSync as readFileSync26 } from "node:fs";
|
|
|
34340
34622
|
import { join as join31, relative as relative5, resolve as resolve23 } from "node:path";
|
|
34341
34623
|
|
|
34342
34624
|
// plugins/kxm/src/wiki.ts
|
|
34343
|
-
import { mkdirSync as mkdirSync22, writeFileSync as
|
|
34625
|
+
import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync21 } from "node:fs";
|
|
34344
34626
|
import { join as join30 } from "node:path";
|
|
34345
34627
|
function writeCompiledWiki(root, wiki) {
|
|
34346
34628
|
const written = [];
|
|
34347
34629
|
for (const [relativePath, content] of [...wiki.pages].sort(([left], [right]) => left.localeCompare(right))) {
|
|
34348
34630
|
const absolute = join30(root, relativePath);
|
|
34349
34631
|
mkdirSync22(absolute.slice(0, absolute.lastIndexOf("/")), { recursive: true });
|
|
34350
|
-
|
|
34632
|
+
writeFileSync21(absolute, content);
|
|
34351
34633
|
written.push(relativePath);
|
|
34352
34634
|
}
|
|
34353
34635
|
return written;
|
|
@@ -34739,7 +35021,7 @@ ${lines.join("\n")}`
|
|
|
34739
35021
|
|
|
34740
35022
|
// plugins/kxm/src/cli/hub.ts
|
|
34741
35023
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
34742
|
-
import { existsSync as existsSync33, mkdirSync as mkdirSync26, readFileSync as readFileSync32, readdirSync as readdirSync12, rmSync as rmSync11, writeFileSync as
|
|
35024
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync26, readFileSync as readFileSync32, readdirSync as readdirSync12, rmSync as rmSync11, writeFileSync as writeFileSync24 } from "node:fs";
|
|
34743
35025
|
import { join as join41, resolve as resolve26 } from "node:path";
|
|
34744
35026
|
|
|
34745
35027
|
// node_modules/marked/lib/marked.esm.js
|
|
@@ -44500,7 +44782,7 @@ async function runMeshTui(input) {
|
|
|
44500
44782
|
// plugins/kxm/src/session-work.ts
|
|
44501
44783
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
44502
44784
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
44503
|
-
import { existsSync as existsSync29, mkdirSync as mkdirSync24, readFileSync as readFileSync28, renameSync as renameSync8, writeFileSync as
|
|
44785
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync24, readFileSync as readFileSync28, renameSync as renameSync8, writeFileSync as writeFileSync22 } from "node:fs";
|
|
44504
44786
|
import { join as join37 } from "node:path";
|
|
44505
44787
|
var MAX_SESSION_BRIEF_TASKS = 5;
|
|
44506
44788
|
var MAX_SESSION_BRIEF_PLANS = 5;
|
|
@@ -44679,7 +44961,7 @@ function writeCachedSessionBrief(stateDir, brief) {
|
|
|
44679
44961
|
mkdirSync24(stateDir, { recursive: true, mode: 448 });
|
|
44680
44962
|
const file = join37(stateDir, "session-brief.json");
|
|
44681
44963
|
const tmp = `${file}.tmp.${randomUUID13().slice(0, 8)}`;
|
|
44682
|
-
|
|
44964
|
+
writeFileSync22(tmp, JSON.stringify(brief, null, 2), { encoding: "utf8", mode: 384 });
|
|
44683
44965
|
renameSync8(tmp, file);
|
|
44684
44966
|
} catch {
|
|
44685
44967
|
}
|
|
@@ -44967,7 +45249,7 @@ function loadKxmUpdateConfig(env = process.env) {
|
|
|
44967
45249
|
}
|
|
44968
45250
|
|
|
44969
45251
|
// plugins/kxm/src/session.ts
|
|
44970
|
-
import { existsSync as existsSync32, mkdirSync as mkdirSync25, readFileSync as readFileSync31, writeFileSync as
|
|
45252
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync25, readFileSync as readFileSync31, writeFileSync as writeFileSync23 } from "node:fs";
|
|
44971
45253
|
import { join as join40 } from "node:path";
|
|
44972
45254
|
var SESSION_SCHEMA = "kxm.session.v1";
|
|
44973
45255
|
var SessionConfigError = class extends Error {
|
|
@@ -45092,7 +45374,7 @@ function writeSession(assetsDir, session, dryRun = false) {
|
|
|
45092
45374
|
const path4 = join40(dir, "session.json");
|
|
45093
45375
|
if (!dryRun) {
|
|
45094
45376
|
mkdirSync25(dir, { recursive: true });
|
|
45095
|
-
|
|
45377
|
+
writeFileSync23(path4, `${JSON.stringify(session, null, 2)}
|
|
45096
45378
|
`, { encoding: "utf8" });
|
|
45097
45379
|
}
|
|
45098
45380
|
return path4;
|
|
@@ -45461,7 +45743,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45461
45743
|
ignored.push(file);
|
|
45462
45744
|
continue;
|
|
45463
45745
|
}
|
|
45464
|
-
|
|
45746
|
+
writeFileSync24(join41(runtime.dirs.state, record.controlFile), `${JSON.stringify({ startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {}, requestedAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
45465
45747
|
`, { encoding: "utf8", mode: 384 });
|
|
45466
45748
|
requested.push(file);
|
|
45467
45749
|
records.set(file, { pid: record.pid, startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {} });
|
|
@@ -45756,12 +46038,12 @@ import { spawnSync as spawnSync8 } from "node:child_process";
|
|
|
45756
46038
|
import { createHash as createHash16 } from "node:crypto";
|
|
45757
46039
|
import { existsSync as existsSync40, mkdtempSync as mkdtempSync3, readFileSync as readFileSync37, rmSync as rmSync13 } from "node:fs";
|
|
45758
46040
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
45759
|
-
import { join as
|
|
46041
|
+
import { join as join47, resolve as resolve31 } from "node:path";
|
|
45760
46042
|
import { createInterface as createInterface3 } from "node:readline";
|
|
45761
46043
|
|
|
45762
46044
|
// plugins/kxm/src/improve.ts
|
|
45763
46045
|
import { createHash as createHash15 } from "node:crypto";
|
|
45764
|
-
import { existsSync as existsSync34, mkdirSync as mkdirSync27, writeFileSync as
|
|
46046
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync27, writeFileSync as writeFileSync25 } from "node:fs";
|
|
45765
46047
|
import { join as join42, relative as relative6, resolve as resolve27 } from "node:path";
|
|
45766
46048
|
var CANDIDATE_SCHEMA = "kxm.candidate.v1";
|
|
45767
46049
|
var IMPROVEMENT_REPORT_SCHEMA = "kxm.improvement-report.v2";
|
|
@@ -46057,9 +46339,9 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46057
46339
|
if (!existsSync34(candidatesDir)) {
|
|
46058
46340
|
mkdirSync27(candidatesDir, { recursive: true });
|
|
46059
46341
|
}
|
|
46060
|
-
|
|
46342
|
+
writeFileSync25(diffFilePath, diff, "utf8");
|
|
46061
46343
|
const jsonFilePath = join42(candidatesDir, `${group.candidateId}.json`);
|
|
46062
|
-
|
|
46344
|
+
writeFileSync25(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
|
|
46063
46345
|
}
|
|
46064
46346
|
candidates.push(candidate);
|
|
46065
46347
|
}
|
|
@@ -46090,7 +46372,7 @@ function writeImprovementReport(improvementsDir, report2, dryRun = false) {
|
|
|
46090
46372
|
const path4 = join42(improvementsDir, `${stamp}.json`);
|
|
46091
46373
|
if (!dryRun) {
|
|
46092
46374
|
mkdirSync27(improvementsDir, { recursive: true });
|
|
46093
|
-
|
|
46375
|
+
writeFileSync25(path4, `${JSON.stringify(report2, null, 2)}
|
|
46094
46376
|
`, { encoding: "utf8" });
|
|
46095
46377
|
}
|
|
46096
46378
|
return path4;
|
|
@@ -46167,12 +46449,9 @@ function evaluatePromotionPolicy(candidate, policy = "manual_pr", options = {})
|
|
|
46167
46449
|
|
|
46168
46450
|
// plugins/kxm/src/improve-sources.ts
|
|
46169
46451
|
import { existsSync as existsSync35 } from "node:fs";
|
|
46170
|
-
import {
|
|
46452
|
+
import { resolve as resolve28 } from "node:path";
|
|
46171
46453
|
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";
|
|
46172
46454
|
var SIMULATED_HARNESS = "driver-simulated";
|
|
46173
|
-
function kxmProjectRunEventsPath(projectRoot, env) {
|
|
46174
|
-
return join43(kxmRuntimePaths({ env }).projectsDir, projectRuntimeKey(projectRoot), "run-events.db");
|
|
46175
|
-
}
|
|
46176
46455
|
function parsePayload(text) {
|
|
46177
46456
|
try {
|
|
46178
46457
|
const value = JSON.parse(text);
|
|
@@ -46313,7 +46592,7 @@ function loadRoutingSources(options) {
|
|
|
46313
46592
|
// plugins/kxm/src/modes.ts
|
|
46314
46593
|
var import_yaml16 = __toESM(require_dist(), 1);
|
|
46315
46594
|
import { existsSync as existsSync36, readFileSync as readFileSync34 } from "node:fs";
|
|
46316
|
-
import { join as
|
|
46595
|
+
import { join as join43 } from "node:path";
|
|
46317
46596
|
var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
46318
46597
|
schema: "kxm.modes.v1",
|
|
46319
46598
|
majorModes: {
|
|
@@ -46376,7 +46655,7 @@ function loadModesConfig(projectRoot) {
|
|
|
46376
46655
|
if (!projectRoot) {
|
|
46377
46656
|
return DEFAULT_MODES_CONFIG;
|
|
46378
46657
|
}
|
|
46379
|
-
const modesPath =
|
|
46658
|
+
const modesPath = join43(projectRoot, ".kxm", "modes.yaml");
|
|
46380
46659
|
if (!existsSync36(modesPath)) {
|
|
46381
46660
|
return DEFAULT_MODES_CONFIG;
|
|
46382
46661
|
}
|
|
@@ -46467,7 +46746,7 @@ function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog
|
|
|
46467
46746
|
estimatedTokens: estimateTokens(baseSystemPromptChars)
|
|
46468
46747
|
});
|
|
46469
46748
|
for (const relPath of resolved.contextFiles) {
|
|
46470
|
-
const fullPath =
|
|
46749
|
+
const fullPath = join43(projectRoot, relPath);
|
|
46471
46750
|
let chars = 0;
|
|
46472
46751
|
if (existsSync36(fullPath)) {
|
|
46473
46752
|
try {
|
|
@@ -46605,7 +46884,7 @@ ${divider}
|
|
|
46605
46884
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
46606
46885
|
import { existsSync as existsSync37, mkdirSync as mkdirSync28, readFileSync as readFileSync35, readdirSync as readdirSync13, rmSync as rmSync12, statSync as statSync5 } from "node:fs";
|
|
46607
46886
|
import { homedir as homedir8 } from "node:os";
|
|
46608
|
-
import { join as
|
|
46887
|
+
import { join as join44, resolve as resolve29 } from "node:path";
|
|
46609
46888
|
var MAX_SSH_OUTPUT_BYTES = 50 * 1024;
|
|
46610
46889
|
var MAX_SSH_OUTPUT_LINES = 2e3;
|
|
46611
46890
|
var DEFAULT_SOCKET_DIR = ".kxm/run/ssh-sockets";
|
|
@@ -46631,7 +46910,7 @@ function truncateSshOutput(raw) {
|
|
|
46631
46910
|
return { text, truncated };
|
|
46632
46911
|
}
|
|
46633
46912
|
function parseSshConfig(configPath) {
|
|
46634
|
-
const targetPath = configPath ??
|
|
46913
|
+
const targetPath = configPath ?? join44(homedir8(), ".ssh", "config");
|
|
46635
46914
|
if (!existsSync37(targetPath)) {
|
|
46636
46915
|
return [];
|
|
46637
46916
|
}
|
|
@@ -46721,7 +47000,7 @@ function ensureSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
|
46721
47000
|
}
|
|
46722
47001
|
function buildSshArgs(options) {
|
|
46723
47002
|
const socketDir = ensureSocketDir(options.socketDir ?? DEFAULT_SOCKET_DIR);
|
|
46724
|
-
const controlPath =
|
|
47003
|
+
const controlPath = join44(socketDir, "%C");
|
|
46725
47004
|
const persist = options.controlPersist ?? DEFAULT_CONTROL_PERSIST;
|
|
46726
47005
|
const args = [
|
|
46727
47006
|
"-o",
|
|
@@ -46746,7 +47025,7 @@ function buildSshArgs(options) {
|
|
|
46746
47025
|
}
|
|
46747
47026
|
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
46748
47027
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
46749
|
-
const controlPath =
|
|
47028
|
+
const controlPath = join44(resolvedDir, "%C");
|
|
46750
47029
|
try {
|
|
46751
47030
|
const result = execFn("ssh", ["-O", "check", "-o", `ControlPath=${controlPath}`, host], {
|
|
46752
47031
|
encoding: "utf-8"
|
|
@@ -46758,7 +47037,7 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
46758
47037
|
}
|
|
46759
47038
|
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
46760
47039
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
46761
|
-
const controlPath =
|
|
47040
|
+
const controlPath = join44(resolvedDir, "%C");
|
|
46762
47041
|
try {
|
|
46763
47042
|
const result = execFn("ssh", ["-O", "stop", "-o", `ControlPath=${controlPath}`, host], {
|
|
46764
47043
|
encoding: "utf-8"
|
|
@@ -47203,9 +47482,9 @@ complete -c kxm -n "__fish_seen_subcommand_from goal" -a "create list get"
|
|
|
47203
47482
|
}
|
|
47204
47483
|
|
|
47205
47484
|
// plugins/kxm/src/completion-install.ts
|
|
47206
|
-
import { existsSync as existsSync38, mkdirSync as mkdirSync29, readFileSync as readFileSync36, writeFileSync as
|
|
47485
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync29, readFileSync as readFileSync36, writeFileSync as writeFileSync26 } from "node:fs";
|
|
47207
47486
|
import { homedir as homedir9 } from "node:os";
|
|
47208
|
-
import { basename as basename9, delimiter, dirname as dirname23, isAbsolute as isAbsolute9, join as
|
|
47487
|
+
import { basename as basename9, delimiter, dirname as dirname23, isAbsolute as isAbsolute9, join as join45, resolve as resolve30 } from "node:path";
|
|
47209
47488
|
var COMPLETION_MARKER = "# kxm completion";
|
|
47210
47489
|
var PATH_MARKER = "# kxm path";
|
|
47211
47490
|
function detectShell(env = process.env, platform = process.platform) {
|
|
@@ -47227,25 +47506,25 @@ function completionScriptPath(shell, options = {}) {
|
|
|
47227
47506
|
const env = options.env ?? process.env;
|
|
47228
47507
|
const explicit = options.configDir ?? env.KXM_USER_CONFIG_DIR?.trim();
|
|
47229
47508
|
const base = explicit && explicit.length > 0 ? resolve30(explicit) : resolve30(effectiveHome(options), ".config", "kxm");
|
|
47230
|
-
return
|
|
47509
|
+
return join45(base, "completions", `kxm.${shell}`);
|
|
47231
47510
|
}
|
|
47232
47511
|
function bashRcCandidate(options) {
|
|
47233
47512
|
const home = effectiveHome(options);
|
|
47234
|
-
const candidates = [
|
|
47513
|
+
const candidates = [join45(home, ".bashrc"), join45(home, ".bash_profile")];
|
|
47235
47514
|
const existing = candidates.find((candidate) => existsSync38(candidate));
|
|
47236
47515
|
return existing ?? candidates[0];
|
|
47237
47516
|
}
|
|
47238
47517
|
function zshRcCandidate(options) {
|
|
47239
47518
|
const env = options.env ?? process.env;
|
|
47240
47519
|
const home = effectiveHome(options);
|
|
47241
|
-
if (env.ZDOTDIR?.trim()) return
|
|
47242
|
-
return
|
|
47520
|
+
if (env.ZDOTDIR?.trim()) return join45(resolve30(env.ZDOTDIR.trim()), ".zshrc");
|
|
47521
|
+
return join45(home, ".zshrc");
|
|
47243
47522
|
}
|
|
47244
47523
|
function fishCompletionTarget(shell, options) {
|
|
47245
47524
|
const env = options.env ?? process.env;
|
|
47246
47525
|
const home = effectiveHome(options);
|
|
47247
|
-
if (env.XDG_CONFIG_HOME?.trim()) return
|
|
47248
|
-
return
|
|
47526
|
+
if (env.XDG_CONFIG_HOME?.trim()) return join45(resolve30(env.XDG_CONFIG_HOME.trim()), "fish", "completions", "kxm.fish");
|
|
47527
|
+
return join45(home, ".config", "fish", "completions", "kxm.fish");
|
|
47249
47528
|
}
|
|
47250
47529
|
function completionRcTarget(shell, options = {}) {
|
|
47251
47530
|
if (shell === "fish") {
|
|
@@ -47287,7 +47566,7 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47287
47566
|
alreadyInstalled = fishInstalled;
|
|
47288
47567
|
if (!options.dryRun && (!fishInstalled || options.overwrite)) {
|
|
47289
47568
|
mkdirSync29(resolve30(fishTarget, ".."), { recursive: true });
|
|
47290
|
-
|
|
47569
|
+
writeFileSync26(fishTarget, script, { encoding: "utf8" });
|
|
47291
47570
|
}
|
|
47292
47571
|
return {
|
|
47293
47572
|
ok: true,
|
|
@@ -47306,7 +47585,7 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47306
47585
|
if (!options.dryRun) {
|
|
47307
47586
|
if (!existingScriptMatches || options.overwrite) {
|
|
47308
47587
|
mkdirSync29(resolve30(scriptPath, ".."), { recursive: true });
|
|
47309
|
-
|
|
47588
|
+
writeFileSync26(scriptPath, script, { encoding: "utf8" });
|
|
47310
47589
|
}
|
|
47311
47590
|
if (rcFile && !alreadyInstalled) {
|
|
47312
47591
|
const line = sourceLine(shell, scriptPath);
|
|
@@ -47316,7 +47595,7 @@ ${marker}
|
|
|
47316
47595
|
${line}
|
|
47317
47596
|
`;
|
|
47318
47597
|
mkdirSync29(resolve30(rcFile, ".."), { recursive: true });
|
|
47319
|
-
|
|
47598
|
+
writeFileSync26(rcFile, (existsSync38(rcFile) ? readFileSync36(rcFile, "utf8") : "") + stanza, { encoding: "utf8" });
|
|
47320
47599
|
rcModified = true;
|
|
47321
47600
|
}
|
|
47322
47601
|
}
|
|
@@ -47333,7 +47612,7 @@ function kxmBinDir(env = process.env) {
|
|
|
47333
47612
|
const argv1 = env.KXM_ENTRY ?? process.argv[1];
|
|
47334
47613
|
if (argv1 && isAbsolute9(argv1)) {
|
|
47335
47614
|
const dir = dirname23(argv1);
|
|
47336
|
-
if (existsSync38(
|
|
47615
|
+
if (existsSync38(join45(dir, process.platform === "win32" ? "kxm.cmd" : "kxm"))) return dir;
|
|
47337
47616
|
}
|
|
47338
47617
|
const pathEnv = env.PATH ?? "";
|
|
47339
47618
|
for (const part of pathEnv.split(delimiter)) {
|
|
@@ -47361,7 +47640,7 @@ function installPathEntry(shellInput, options = {}) {
|
|
|
47361
47640
|
const alreadyInstalled = rcContent.includes(binDir) || (options.env?.PATH ?? process.env.PATH ?? "").split(delimiter).includes(binDir);
|
|
47362
47641
|
if (!options.dryRun && rcFile && !alreadyInstalled) {
|
|
47363
47642
|
mkdirSync29(dirname23(rcFile), { recursive: true });
|
|
47364
|
-
|
|
47643
|
+
writeFileSync26(rcFile, rcContent + `
|
|
47365
47644
|
${PATH_MARKER}
|
|
47366
47645
|
${line}
|
|
47367
47646
|
`, { encoding: "utf8" });
|
|
@@ -47371,17 +47650,17 @@ ${line}
|
|
|
47371
47650
|
|
|
47372
47651
|
// plugins/kxm/src/init-guide-setup.ts
|
|
47373
47652
|
var import_yaml17 = __toESM(require_dist(), 1);
|
|
47374
|
-
import { existsSync as existsSync39, mkdirSync as mkdirSync30, writeFileSync as
|
|
47375
|
-
import { dirname as dirname24, join as
|
|
47376
|
-
var
|
|
47377
|
-
anthropic: "claude",
|
|
47378
|
-
|
|
47379
|
-
"
|
|
47380
|
-
xai: "grok",
|
|
47381
|
-
|
|
47382
|
-
|
|
47383
|
-
|
|
47384
|
-
|
|
47653
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync30, writeFileSync as writeFileSync27 } from "node:fs";
|
|
47654
|
+
import { dirname as dirname24, join as join46 } from "node:path";
|
|
47655
|
+
var ADMITTED_GUIDE_BINDINGS = Object.freeze({
|
|
47656
|
+
"anthropic/claude-fable-5.1": { harness: "claude", provider: "anthropic", model: "fable" },
|
|
47657
|
+
"anthropic/fable": { harness: "claude", provider: "anthropic", model: "fable" },
|
|
47658
|
+
"openai/gpt-5.6-sol": { harness: "codex", provider: "openai", model: "gpt-5.6-sol" },
|
|
47659
|
+
"x-ai/grok-4.6": { harness: "grok", provider: "xai", model: "grok-4.6" },
|
|
47660
|
+
"xai/grok-4.6": { harness: "grok", provider: "xai", model: "grok-4.6" },
|
|
47661
|
+
"google/gemini-3.8-flash": { harness: "pi", provider: "antigravity", model: "gemini-3.8-flash-high" },
|
|
47662
|
+
"google/gemini-3.8-flash-high": { harness: "pi", provider: "antigravity", model: "gemini-3.8-flash-high" },
|
|
47663
|
+
"qwen/qwen3-coder-plus": { harness: "pi", provider: "openrouter", model: "qwen/qwen3-coder-plus" }
|
|
47385
47664
|
});
|
|
47386
47665
|
var GUIDE_WORKFLOWS = [
|
|
47387
47666
|
{
|
|
@@ -47679,16 +47958,9 @@ function authenticatedHarnesses(inventory) {
|
|
|
47679
47958
|
}
|
|
47680
47959
|
function resolveCandidate(candidates, eligible) {
|
|
47681
47960
|
for (const candidate of candidates) {
|
|
47682
|
-
const
|
|
47683
|
-
if (
|
|
47684
|
-
|
|
47685
|
-
return { harness: nativeHarness, provider: NATIVE_HARNESS_PROVIDERS[nativeHarness], model: candidate.model };
|
|
47686
|
-
}
|
|
47687
|
-
continue;
|
|
47688
|
-
}
|
|
47689
|
-
if (eligible.has("pi")) {
|
|
47690
|
-
return { harness: "pi", provider: "openrouter", model: `${candidate.vendor}/${candidate.model}` };
|
|
47691
|
-
}
|
|
47961
|
+
const mapped = ADMITTED_GUIDE_BINDINGS[`${candidate.vendor}/${candidate.model}`];
|
|
47962
|
+
if (!mapped || !eligible.has(mapped.harness)) continue;
|
|
47963
|
+
return mapped;
|
|
47692
47964
|
}
|
|
47693
47965
|
return void 0;
|
|
47694
47966
|
}
|
|
@@ -47709,7 +47981,7 @@ function planGuideSetup(options) {
|
|
|
47709
47981
|
workflow: workflow.slug,
|
|
47710
47982
|
stage: stage.slug,
|
|
47711
47983
|
role: stage.role,
|
|
47712
|
-
reason: "no guide candidate has an authenticated harness (see `kxm harness list`)"
|
|
47984
|
+
reason: "no admitted guide candidate has an authenticated harness (see `kxm harness list`)"
|
|
47713
47985
|
});
|
|
47714
47986
|
covered = false;
|
|
47715
47987
|
continue;
|
|
@@ -47746,6 +48018,7 @@ function workflowDocument(workflow) {
|
|
|
47746
48018
|
id: stage.slug,
|
|
47747
48019
|
kind: "agent",
|
|
47748
48020
|
agent: stage.role,
|
|
48021
|
+
repositories: { control: isWriterRole(stage.role) ? "write" : "read" },
|
|
47749
48022
|
maxAttempts: 2,
|
|
47750
48023
|
on: {
|
|
47751
48024
|
passed: last ? { target: "$terminal", terminalStatus: "completed" } : workflow.stages[index + 1].slug,
|
|
@@ -47771,18 +48044,34 @@ function renderGuideSetupFiles(projectRoot, plan) {
|
|
|
47771
48044
|
const stage = roleStages.get(role);
|
|
47772
48045
|
if (!stage) continue;
|
|
47773
48046
|
files.push({
|
|
47774
|
-
path:
|
|
48047
|
+
path: join46(projectRoot, ".kxm", "agents", `${role}.yaml`),
|
|
47775
48048
|
content: (0, import_yaml17.stringify)(agentDocument(role, stage, binding))
|
|
47776
48049
|
});
|
|
47777
48050
|
}
|
|
47778
48051
|
for (const workflow of plan.workflows) {
|
|
47779
48052
|
files.push({
|
|
47780
|
-
path:
|
|
48053
|
+
path: join46(projectRoot, ".kxm", "workflows", `${workflow.slug}.yaml`),
|
|
47781
48054
|
content: (0, import_yaml17.stringify)(workflowDocument(workflow))
|
|
47782
48055
|
});
|
|
47783
48056
|
}
|
|
47784
48057
|
return files;
|
|
47785
48058
|
}
|
|
48059
|
+
function mergeGuideRouteAdmission(projectRoot, plan) {
|
|
48060
|
+
const policy = loadRoutePolicy(projectRoot);
|
|
48061
|
+
const added = [];
|
|
48062
|
+
for (const binding of plan.agents.values()) {
|
|
48063
|
+
const selector = `${binding.provider}/${binding.model}`;
|
|
48064
|
+
if (policy.disabled.includes(selector) || policy.admitted.includes(selector)) continue;
|
|
48065
|
+
policy.admitted.push(selector);
|
|
48066
|
+
added.push(selector);
|
|
48067
|
+
}
|
|
48068
|
+
if (added.length === 0) return added;
|
|
48069
|
+
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
48070
|
+
const path4 = join46(projectRoot, ".kxm", "routes.yaml");
|
|
48071
|
+
mkdirSync30(dirname24(path4), { recursive: true });
|
|
48072
|
+
writeFileSync27(path4, (0, import_yaml17.stringify)(policy), "utf8");
|
|
48073
|
+
return added;
|
|
48074
|
+
}
|
|
47786
48075
|
function writeGuideSetupFiles(files) {
|
|
47787
48076
|
const written = [];
|
|
47788
48077
|
const existed = [];
|
|
@@ -47792,7 +48081,7 @@ function writeGuideSetupFiles(files) {
|
|
|
47792
48081
|
continue;
|
|
47793
48082
|
}
|
|
47794
48083
|
mkdirSync30(dirname24(file.path), { recursive: true });
|
|
47795
|
-
|
|
48084
|
+
writeFileSync27(file.path, file.content, "utf8");
|
|
47796
48085
|
written.push(file.path);
|
|
47797
48086
|
}
|
|
47798
48087
|
return { written, existed };
|
|
@@ -47855,7 +48144,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
47855
48144
|
detail: `release v${notice.latest} has no sha256 digest for ${name}; refusing to install`
|
|
47856
48145
|
};
|
|
47857
48146
|
}
|
|
47858
|
-
const releaseDir = mkdtempSync3(
|
|
48147
|
+
const releaseDir = mkdtempSync3(join47(tmpdir2(), "kxm-pkg-update-"));
|
|
47859
48148
|
try {
|
|
47860
48149
|
const planned = planKxmPackageUpdate(notice.source, notice.latest, releaseDir, notice.asset);
|
|
47861
48150
|
if (runtime.dryRun) {
|
|
@@ -48228,7 +48517,7 @@ async function cmdImprove(runtime, options = {}) {
|
|
|
48228
48517
|
print(runtime.io, runtime.json, { ok: false, command: "improve", error: "config_invalid", detail: message }, `config_invalid: ${message}`);
|
|
48229
48518
|
return 1;
|
|
48230
48519
|
}
|
|
48231
|
-
const candidatesDir = options.outDir ? resolve31(runtime.cwd, options.outDir) :
|
|
48520
|
+
const candidatesDir = options.outDir ? resolve31(runtime.cwd, options.outDir) : join47(root, ".kxm", "candidates");
|
|
48232
48521
|
const report2 = buildImprovementReport(loaded.records, {
|
|
48233
48522
|
candidatesDir,
|
|
48234
48523
|
projectRoot: root,
|
|
@@ -48237,7 +48526,7 @@ async function cmdImprove(runtime, options = {}) {
|
|
|
48237
48526
|
autoThreshold: config.improvement.autoThreshold,
|
|
48238
48527
|
halfLifeDays: config.improvement.telemetryHalfLifeDays
|
|
48239
48528
|
});
|
|
48240
|
-
const reportDir =
|
|
48529
|
+
const reportDir = join47(runtime.dirs.assets, "improvements");
|
|
48241
48530
|
const reportPath = writeImprovementReport(reportDir, report2, runtime.dryRun);
|
|
48242
48531
|
const text = [
|
|
48243
48532
|
"Sources:",
|
|
@@ -48496,9 +48785,12 @@ Set up workflow-guide agents and workflows for authenticated harnesses (${harnes
|
|
|
48496
48785
|
const plan = planGuideSetup({ inventory, selected });
|
|
48497
48786
|
const files = renderGuideSetupFiles(runtime.cwd, plan);
|
|
48498
48787
|
const report2 = writeGuideSetupFiles(files);
|
|
48788
|
+
const admitted = mergeGuideRouteAdmission(runtime.cwd, plan);
|
|
48499
48789
|
for (const file of report2.written) runtime.io.stdout(`wrote ${file}
|
|
48500
48790
|
`);
|
|
48501
48791
|
for (const file of report2.existed) runtime.io.stdout(`kept existing ${file} (not overwritten)
|
|
48792
|
+
`);
|
|
48793
|
+
for (const selector of admitted) runtime.io.stdout(`admitted route ${selector}
|
|
48502
48794
|
`);
|
|
48503
48795
|
for (const skip of plan.skipped) {
|
|
48504
48796
|
runtime.io.stdout(`skipped ${skip.workflow}/${skip.role}: ${skip.reason}
|
|
@@ -48508,6 +48800,23 @@ Set up workflow-guide agents and workflows for authenticated harnesses (${harnes
|
|
|
48508
48800
|
runtime.io.stdout("inspect with `kxm workflow definitions`; guide candidates are dated research \u2014 verify before dispatch\n");
|
|
48509
48801
|
}
|
|
48510
48802
|
}
|
|
48803
|
+
async function cmdPricesAcknowledge(runtime) {
|
|
48804
|
+
try {
|
|
48805
|
+
const catalog = acknowledgePriceCatalog(runtime.cwd);
|
|
48806
|
+
print(runtime.io, runtime.json, {
|
|
48807
|
+
ok: true,
|
|
48808
|
+
command: "prices acknowledge",
|
|
48809
|
+
date: catalog.date,
|
|
48810
|
+
sha256: catalog.sha256,
|
|
48811
|
+
note: "stamped the existing list as today's estimate; vendor rates were not fetched"
|
|
48812
|
+
}, `price catalog stamped ${catalog.date} (list estimate only; vendor rates were not fetched)`);
|
|
48813
|
+
return 0;
|
|
48814
|
+
} catch (error) {
|
|
48815
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
48816
|
+
print(runtime.io, runtime.json, { ok: false, command: "prices acknowledge", error: "prices_acknowledge_failed", message }, `prices acknowledge failed: ${message}`);
|
|
48817
|
+
return 1;
|
|
48818
|
+
}
|
|
48819
|
+
}
|
|
48511
48820
|
async function cmdRoutingReport(runtime, options) {
|
|
48512
48821
|
let file;
|
|
48513
48822
|
let records;
|
|
@@ -48526,7 +48835,7 @@ async function cmdRoutingReport(runtime, options) {
|
|
|
48526
48835
|
let catalog;
|
|
48527
48836
|
if (includeEquivalentListCost) {
|
|
48528
48837
|
try {
|
|
48529
|
-
const pricesPath = options.prices ? resolve31(runtime.cwd, options.prices) :
|
|
48838
|
+
const pricesPath = options.prices ? resolve31(runtime.cwd, options.prices) : join47(runtime.dirs.workspace, "prices.yaml");
|
|
48530
48839
|
catalog = loadPriceCatalog(pricesPath);
|
|
48531
48840
|
} catch {
|
|
48532
48841
|
}
|
|
@@ -48754,14 +49063,15 @@ async function ensureCliClient(runtime) {
|
|
|
48754
49063
|
const project = defaultProjectName(runtime.cwd, runtime.env);
|
|
48755
49064
|
const name = runtime.env.KXM_AGENT_NAME?.trim() || `cli-${process.pid}`;
|
|
48756
49065
|
const purpose = runtime.env.KXM_AGENT_PURPOSE?.trim() || "CLI agent client";
|
|
48757
|
-
const authToken =
|
|
49066
|
+
const authToken = resolveAgentHubAuthToken(runtime.env, project);
|
|
49067
|
+
if (!authToken) throw new AgentProjectTokenMissingError(project);
|
|
48758
49068
|
const client = new HubClient({
|
|
48759
49069
|
serverUrl,
|
|
48760
49070
|
name,
|
|
48761
49071
|
project,
|
|
48762
49072
|
purpose,
|
|
48763
49073
|
fetchImpl: runtime.fetchImpl,
|
|
48764
|
-
|
|
49074
|
+
authToken
|
|
48765
49075
|
});
|
|
48766
49076
|
await client.start(() => {
|
|
48767
49077
|
});
|
|
@@ -48822,7 +49132,7 @@ async function dispatchAgentCliCommand(runtime, toolName, rawArgs) {
|
|
|
48822
49132
|
if (toolName === "kxm_workflow_wait") {
|
|
48823
49133
|
const runId = typeof args.runId === "string" ? args.runId : void 0;
|
|
48824
49134
|
const projectRoot = discoverKxmProjectRoot(runtime.cwd);
|
|
48825
|
-
if (runId && projectRoot &&
|
|
49135
|
+
if (runId && projectRoot && projectRuntimeOwnsRun(projectRoot, runId, runtime.env)) {
|
|
48826
49136
|
if (runtime.dryRun) {
|
|
48827
49137
|
print(runtime.io, runtime.json, { ok: true, command: "workflow wait", runId, dryRun: true }, `would wait for signal on KXM run ${runId}`);
|
|
48828
49138
|
return 0;
|
|
@@ -48857,6 +49167,15 @@ async function dispatchAgentCliCommand(runtime, toolName, rawArgs) {
|
|
|
48857
49167
|
return 0;
|
|
48858
49168
|
} catch (error) {
|
|
48859
49169
|
const message = error instanceof Error ? error.message : String(error);
|
|
49170
|
+
if (error instanceof AgentProjectTokenMissingError) {
|
|
49171
|
+
print(
|
|
49172
|
+
runtime.io,
|
|
49173
|
+
runtime.json,
|
|
49174
|
+
{ ok: false, error: error.code, project: error.project, nextAction: "export_kxm_auth_token", detail: message },
|
|
49175
|
+
message
|
|
49176
|
+
);
|
|
49177
|
+
return 2;
|
|
49178
|
+
}
|
|
48860
49179
|
print(runtime.io, runtime.json, { ok: false, error: "command_failed", detail: message }, `command failed: ${message}`);
|
|
48861
49180
|
return 1;
|
|
48862
49181
|
} finally {
|
|
@@ -48894,7 +49213,7 @@ function createProgram(ctx, result) {
|
|
|
48894
49213
|
maybeOfferGuideSetup
|
|
48895
49214
|
});
|
|
48896
49215
|
});
|
|
48897
|
-
addGlobalOptions(program2.command("backup").description("Create a verified SQLite backup of the project hub store
|
|
49216
|
+
addGlobalOptions(program2.command("backup").description("Create a verified SQLite backup of the project hub store and the Runtime stores under the user state root, with a hashed manifest")).option("--out <dir>", "Directory to write backup and manifest").action(async function backupAction(options) {
|
|
48898
49217
|
result.code = await cmdBackup(runtimeFrom(ctx, this), options);
|
|
48899
49218
|
});
|
|
48900
49219
|
addGlobalOptions(program2.command("restore <manifest>").description("Restore SQLite stores from a verified backup manifest")).action(async function restoreAction(manifest) {
|
|
@@ -48908,7 +49227,7 @@ function createProgram(ctx, result) {
|
|
|
48908
49227
|
addGlobalOptions(runCmd.command("status").description("Show the projected status of a run, including durable drive receipt state (open / receipt verified / unsettled / orphaned)")).argument("<runId>", "Run id").action(async function runStatusAction(runId) {
|
|
48909
49228
|
result.code = await cmdKxmRunStatus(runtimeFrom(ctx, this), runId);
|
|
48910
49229
|
});
|
|
48911
|
-
addGlobalOptions(runCmd.command("drive").description("Drive a run with live harness calls, or with the model-free simulation when --simulated is passed")).argument("<runId>", "Run id").option("--simulated", "Use the model-free simulation producer").option("--wait", "Wait until a drive receipt is recorded; exits 0 only for a VERIFIED COMPLETED settlement").option("--timeout-ms <n>", "Wait timeout in milliseconds (default 60000, max 600000)").action(async function runDriveAction(runId, options) {
|
|
49230
|
+
addGlobalOptions(runCmd.command("drive").description("Drive a run with live harness calls, or with the model-free simulation when --simulated is passed")).argument("<runId>", "Run id").option("--simulated", "Use the model-free simulation producer instead of a live model").option("--wait", "Wait until a drive receipt is recorded; exits 0 only for a VERIFIED COMPLETED settlement").option("--timeout-ms <n>", "Wait timeout in milliseconds (default 60000, max 600000)").action(async function runDriveAction(runId, options) {
|
|
48912
49231
|
result.code = await cmdKxmRunDrive(runtimeFrom(ctx, this), runId, options.simulated === true, {
|
|
48913
49232
|
wait: options.wait === true,
|
|
48914
49233
|
...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {}
|
|
@@ -48928,6 +49247,11 @@ function createProgram(ctx, result) {
|
|
|
48928
49247
|
addGlobalOptions(tenantCmd.command("status").description("Read hub metadata and authoritative Runtime run state as one labeled view")).action(async function tenantStatusAction() {
|
|
48929
49248
|
result.code = await cmdTenantStatus(runtimeFrom(ctx, this));
|
|
48930
49249
|
});
|
|
49250
|
+
const pricesCmd = addGlobalOptions(program2.command("prices").description("Stamp the local list-price catalog. Estimates stay unknown until today's stamp"));
|
|
49251
|
+
pricesCmd.helpCommand("help", "Show prices help");
|
|
49252
|
+
addGlobalOptions(pricesCmd.command("acknowledge").description("Stamp the existing .kxm/prices.yaml list as today's estimate without fetching vendor rates")).action(async function pricesAcknowledgeAction() {
|
|
49253
|
+
result.code = await cmdPricesAcknowledge(runtimeFrom(ctx, this));
|
|
49254
|
+
});
|
|
48931
49255
|
const modelsCmd = addGlobalOptions(program2.command("models").description("Manage model catalogs, roles, and route state"));
|
|
48932
49256
|
modelsCmd.action(async function modelsScreenAction() {
|
|
48933
49257
|
result.code = await cmdModelsScreen(runtimeFrom(ctx, this));
|
|
@@ -49138,7 +49462,7 @@ function createProgram(ctx, result) {
|
|
|
49138
49462
|
addGlobalOptions(github.command("watch").description("Poll required checks and post the signed signal")).option("--run-id <id>", "Workflow run ID").option("--stage-id <id>", "Waiting stage ID").option("--signal-key <key>", "Wait signal key").option("--repo <owner/name>", "GitHub repository").option("--pr <number>", "Pull request number").option("--required <names>", "Comma-separated required check names").option("--timeout-ms <ms>", "Watch timeout").option("--interval-ms <ms>", "Poll interval").option("--delivery-id <id>", "Stable callback delivery ID").action(async function watchAction(options) {
|
|
49139
49463
|
result.code = await cmdGithubWatch(runtimeFrom(ctx, this), options);
|
|
49140
49464
|
});
|
|
49141
|
-
const improve = addGlobalOptions(program2.command("improve").description("Propose coded-repeat candidates from this project's Runtime routing records and telemetry"));
|
|
49465
|
+
const improve = addGlobalOptions(program2.command("improve").description("Propose coded-repeat candidates from this project's Runtime routing records and telemetry. Proposals are not applied to the next run"));
|
|
49142
49466
|
improve.helpCommand("help", "Show improve help");
|
|
49143
49467
|
addGlobalOptions(improve.command("report", { isDefault: true }).description("Generate improvement report and candidates from routing records")).option("--file <path>", "Read only this routing-record JSONL instead of the project's Runtime store and telemetry").option("--out-dir <path>", "Directory for candidates (default .kxm/candidates)").action(async function improveReportAction(options) {
|
|
49144
49468
|
result.code = await cmdImprove(runtimeFrom(ctx, this), options);
|