@kontextmind/kxm 0.7.20 → 0.7.21
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/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +706 -695
- package/plugins/kxm/dist/extension.js +83 -65
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/runtime.js +212 -194
- package/plugins/kxm/dist/server.js +46 -26
- package/plugins/kxm/dist/vnext-runtime-supervisor.js +155 -137
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/cli/system.ts +3 -4
- package/plugins/kxm/src/cli/types.ts +2 -4
- package/plugins/kxm/src/cli/vnext.ts +1 -4
- package/plugins/kxm/src/cli.ts +2 -2
- package/plugins/kxm/src/hub-autostart.ts +4 -4
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/repo-root.ts +29 -0
- package/plugins/kxm/src/vnext-config.ts +5 -3
- package/plugins/kxm/src/vnext-runtime-supervisor.ts +3 -4
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -2987,7 +2987,7 @@ var require_compile = __commonJS({
|
|
|
2987
2987
|
const schOrFunc = root.refs[ref];
|
|
2988
2988
|
if (schOrFunc)
|
|
2989
2989
|
return schOrFunc;
|
|
2990
|
-
let _sch =
|
|
2990
|
+
let _sch = resolve30.call(this, root, ref);
|
|
2991
2991
|
if (_sch === void 0) {
|
|
2992
2992
|
const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
2993
2993
|
const { schemaId } = this.opts;
|
|
@@ -3014,7 +3014,7 @@ var require_compile = __commonJS({
|
|
|
3014
3014
|
function sameSchemaEnv(s1, s2) {
|
|
3015
3015
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
3016
3016
|
}
|
|
3017
|
-
function
|
|
3017
|
+
function resolve30(root, ref) {
|
|
3018
3018
|
let sch;
|
|
3019
3019
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3020
3020
|
ref = sch;
|
|
@@ -3839,7 +3839,7 @@ var require_fast_uri = __commonJS({
|
|
|
3839
3839
|
}
|
|
3840
3840
|
return uri;
|
|
3841
3841
|
}
|
|
3842
|
-
function
|
|
3842
|
+
function resolve30(baseURI, relativeURI, options) {
|
|
3843
3843
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3844
3844
|
const {
|
|
3845
3845
|
parsed: baseParsed,
|
|
@@ -4201,7 +4201,7 @@ var require_fast_uri = __commonJS({
|
|
|
4201
4201
|
var fastUri = {
|
|
4202
4202
|
SCHEMES,
|
|
4203
4203
|
normalize,
|
|
4204
|
-
resolve:
|
|
4204
|
+
resolve: resolve30,
|
|
4205
4205
|
resolveComponent,
|
|
4206
4206
|
equal,
|
|
4207
4207
|
serialize,
|
|
@@ -14779,8 +14779,8 @@ var require_dist = __commonJS({
|
|
|
14779
14779
|
});
|
|
14780
14780
|
|
|
14781
14781
|
// plugins/kxm/src/cli.ts
|
|
14782
|
-
import { resolve as
|
|
14783
|
-
import { fileURLToPath as
|
|
14782
|
+
import { resolve as resolve29 } from "node:path";
|
|
14783
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
14784
14784
|
|
|
14785
14785
|
// node_modules/commander/lib/error.js
|
|
14786
14786
|
var CommanderError = class extends Error {
|
|
@@ -18329,6 +18329,25 @@ function planKxmPackageUpdate(source, latest, releaseDir, asset) {
|
|
|
18329
18329
|
return steps;
|
|
18330
18330
|
}
|
|
18331
18331
|
|
|
18332
|
+
// plugins/kxm/src/repo-root.ts
|
|
18333
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
18334
|
+
import { dirname, join as join2 } from "node:path";
|
|
18335
|
+
import { fileURLToPath } from "node:url";
|
|
18336
|
+
var ROOT_MARKERS = ["scripts/kxm-hub.mjs", "scripts/kxm.mjs"];
|
|
18337
|
+
var MAX_WALK_DEPTH = 10;
|
|
18338
|
+
function findKxmRepoRoot(fromUrl = import.meta.url) {
|
|
18339
|
+
let dir = dirname(fileURLToPath(fromUrl));
|
|
18340
|
+
for (let depth = 0; depth < MAX_WALK_DEPTH; depth += 1) {
|
|
18341
|
+
if (ROOT_MARKERS.some((marker) => existsSync2(join2(dir, marker)))) return dir;
|
|
18342
|
+
const parent = dirname(dir);
|
|
18343
|
+
if (parent === dir) break;
|
|
18344
|
+
dir = parent;
|
|
18345
|
+
}
|
|
18346
|
+
throw new Error(
|
|
18347
|
+
`kxm: cannot locate the KXM repo root from ${fileURLToPath(fromUrl)} (walked ${MAX_WALK_DEPTH} levels looking for ${ROOT_MARKERS[0]})`
|
|
18348
|
+
);
|
|
18349
|
+
}
|
|
18350
|
+
|
|
18332
18351
|
// plugins/kxm/src/client.ts
|
|
18333
18352
|
import { createHash as createHash3 } from "node:crypto";
|
|
18334
18353
|
|
|
@@ -19427,7 +19446,7 @@ var HubClient = class {
|
|
|
19427
19446
|
if (signal?.aborted) throw new MeshWaitError("aborted", messageId);
|
|
19428
19447
|
const message = await this.getMessage(messageId);
|
|
19429
19448
|
if (["replied", "cancelled", "expired", "error"].includes(message.status)) return message;
|
|
19430
|
-
await new Promise((
|
|
19449
|
+
await new Promise((resolve30, reject) => {
|
|
19431
19450
|
const onAbort = () => {
|
|
19432
19451
|
signal?.removeEventListener("abort", onAbort);
|
|
19433
19452
|
clearTimeout(timer);
|
|
@@ -19435,7 +19454,7 @@ var HubClient = class {
|
|
|
19435
19454
|
};
|
|
19436
19455
|
const timer = setTimeout(() => {
|
|
19437
19456
|
signal?.removeEventListener("abort", onAbort);
|
|
19438
|
-
|
|
19457
|
+
resolve30();
|
|
19439
19458
|
}, Math.min(500, Math.max(1, deadline - Date.now())));
|
|
19440
19459
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
19441
19460
|
if (signal?.aborted) onAbort();
|
|
@@ -19490,7 +19509,7 @@ var HubClient = class {
|
|
|
19490
19509
|
} catch (error) {
|
|
19491
19510
|
if (this.stopped || error instanceof Error && error.name === "AbortError") return;
|
|
19492
19511
|
}
|
|
19493
|
-
if (!this.stopped) await new Promise((
|
|
19512
|
+
if (!this.stopped) await new Promise((resolve30) => setTimeout(resolve30, this.options.reconnectMs));
|
|
19494
19513
|
}
|
|
19495
19514
|
}
|
|
19496
19515
|
headers(includeIdentity = true) {
|
|
@@ -19573,12 +19592,12 @@ var HubClient = class {
|
|
|
19573
19592
|
|
|
19574
19593
|
// plugins/kxm/src/project-name.ts
|
|
19575
19594
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
19576
|
-
import { basename, join as
|
|
19595
|
+
import { basename, join as join3 } from "node:path";
|
|
19577
19596
|
function defaultProjectName(cwd, env = process.env) {
|
|
19578
19597
|
const fromEnv = env.KXM_PROJECT?.trim();
|
|
19579
19598
|
if (fromEnv) return fromEnv;
|
|
19580
19599
|
try {
|
|
19581
|
-
const pkg = JSON.parse(readFileSync2(
|
|
19600
|
+
const pkg = JSON.parse(readFileSync2(join3(cwd, "package.json"), "utf8"));
|
|
19582
19601
|
if (typeof pkg.name === "string" && pkg.name.trim().length > 0) return pkg.name.trim();
|
|
19583
19602
|
} catch {
|
|
19584
19603
|
}
|
|
@@ -19587,9 +19606,9 @@ function defaultProjectName(cwd, env = process.env) {
|
|
|
19587
19606
|
|
|
19588
19607
|
// plugins/kxm/src/commands.ts
|
|
19589
19608
|
import { createHash as createHash4, randomUUID as randomUUID2, timingSafeEqual } from "node:crypto";
|
|
19590
|
-
import { chmodSync, existsSync as
|
|
19609
|
+
import { chmodSync, existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
19591
19610
|
import { homedir } from "node:os";
|
|
19592
|
-
import { dirname, join as
|
|
19611
|
+
import { dirname as dirname2, join as join4, resolve } from "node:path";
|
|
19593
19612
|
function requiredString(value, name) {
|
|
19594
19613
|
if (typeof value !== "string" || value.trim() === "") throw new Error(`${name} is required`);
|
|
19595
19614
|
return value.trim();
|
|
@@ -20338,14 +20357,14 @@ function parseSessionToken(token) {
|
|
|
20338
20357
|
}
|
|
20339
20358
|
function resolveUserConfigDirectory(overrideDir) {
|
|
20340
20359
|
if (overrideDir) return resolve(overrideDir);
|
|
20341
|
-
return resolve(process.env.KXM_USER_CONFIG_DIR?.trim() ||
|
|
20360
|
+
return resolve(process.env.KXM_USER_CONFIG_DIR?.trim() || join4(homedir(), ".config", "kxm"));
|
|
20342
20361
|
}
|
|
20343
20362
|
function sessionTokenPath(userConfigDir) {
|
|
20344
|
-
return
|
|
20363
|
+
return join4(resolveUserConfigDirectory(userConfigDir), "session.token");
|
|
20345
20364
|
}
|
|
20346
20365
|
function persistSessionTokenToDisk(token, options) {
|
|
20347
20366
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
20348
|
-
const dir =
|
|
20367
|
+
const dir = dirname2(filePath);
|
|
20349
20368
|
mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
20350
20369
|
const mode = options?.mode ?? 384;
|
|
20351
20370
|
writeFileSync2(filePath, `${token.trim()}
|
|
@@ -20358,7 +20377,7 @@ function persistSessionTokenToDisk(token, options) {
|
|
|
20358
20377
|
}
|
|
20359
20378
|
function readSessionTokenFromDisk(options) {
|
|
20360
20379
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
20361
|
-
if (!
|
|
20380
|
+
if (!existsSync3(filePath)) return void 0;
|
|
20362
20381
|
try {
|
|
20363
20382
|
const token = readFileSync3(filePath, "utf8").trim();
|
|
20364
20383
|
if (!token) return void 0;
|
|
@@ -20371,7 +20390,7 @@ function readSessionTokenFromDisk(options) {
|
|
|
20371
20390
|
}
|
|
20372
20391
|
function clearSessionTokenFromDisk(options) {
|
|
20373
20392
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
20374
|
-
if (!
|
|
20393
|
+
if (!existsSync3(filePath)) return false;
|
|
20375
20394
|
try {
|
|
20376
20395
|
unlinkSync(filePath);
|
|
20377
20396
|
return true;
|
|
@@ -20470,7 +20489,7 @@ function enforceToolPolicy(commandName, env = process.env, options) {
|
|
|
20470
20489
|
return { allowed: true };
|
|
20471
20490
|
}
|
|
20472
20491
|
const tokenFile = sessionTokenPath(env.KXM_USER_CONFIG_DIR);
|
|
20473
|
-
if (
|
|
20492
|
+
if (existsSync3(tokenFile)) {
|
|
20474
20493
|
let tokenRaw;
|
|
20475
20494
|
try {
|
|
20476
20495
|
tokenRaw = readFileSync3(tokenFile, "utf8").trim();
|
|
@@ -20497,9 +20516,8 @@ function enforceToolPolicy(commandName, env = process.env, options) {
|
|
|
20497
20516
|
var import__ = __toESM(require__(), 1);
|
|
20498
20517
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
20499
20518
|
import { createHash as createHash6 } from "node:crypto";
|
|
20500
|
-
import { existsSync as
|
|
20501
|
-
import { basename as basename2, dirname as
|
|
20502
|
-
import { fileURLToPath } from "node:url";
|
|
20519
|
+
import { existsSync as existsSync5, lstatSync, readFileSync as readFileSync4, readdirSync, realpathSync } from "node:fs";
|
|
20520
|
+
import { basename as basename2, dirname as dirname3, extname, isAbsolute, join as join5, relative, resolve as resolve2, sep } from "node:path";
|
|
20503
20521
|
|
|
20504
20522
|
// plugins/kxm/src/restricted-yaml.mjs
|
|
20505
20523
|
var import_yaml = __toESM(require_dist(), 1);
|
|
@@ -20827,7 +20845,7 @@ function resolveVnextTemplateBaseline(value) {
|
|
|
20827
20845
|
|
|
20828
20846
|
// plugins/kxm/src/vnext-harness.ts
|
|
20829
20847
|
import { spawnSync } from "node:child_process";
|
|
20830
|
-
import { existsSync as
|
|
20848
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
20831
20849
|
import { win32 as win32Path } from "node:path";
|
|
20832
20850
|
|
|
20833
20851
|
// plugins/kxm/src/vnext-oneshot-process.ts
|
|
@@ -20853,7 +20871,7 @@ function defaultSpawn(command, args, options) {
|
|
|
20853
20871
|
if (options.signal?.aborted) {
|
|
20854
20872
|
return Promise.resolve({ stdout: "", stderr: "", code: null, started: false, observedChildExit: false, error: new Error("process_aborted") });
|
|
20855
20873
|
}
|
|
20856
|
-
return new Promise((
|
|
20874
|
+
return new Promise((resolve30) => {
|
|
20857
20875
|
const stdout = [];
|
|
20858
20876
|
const stderr = [];
|
|
20859
20877
|
let outputBytes = 0;
|
|
@@ -20884,7 +20902,7 @@ function defaultSpawn(command, args, options) {
|
|
|
20884
20902
|
const started = Boolean(child?.pid);
|
|
20885
20903
|
if (started && !observedChildExit) error ??= new Error("process_exit_unobserved");
|
|
20886
20904
|
const unverifiedDescendants = stopping || started && !observedChildExit;
|
|
20887
|
-
|
|
20905
|
+
resolve30({
|
|
20888
20906
|
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
20889
20907
|
stderr: Buffer.concat(stderr).toString("utf8"),
|
|
20890
20908
|
code,
|
|
@@ -21376,7 +21394,7 @@ function findWinNpmInnerExe(cliId, options = {}) {
|
|
|
21376
21394
|
if ((options.platform ?? process.platform) !== "win32") return void 0;
|
|
21377
21395
|
const segments = WIN_NPM_INNER_EXE[cliId];
|
|
21378
21396
|
if (!segments) return void 0;
|
|
21379
|
-
const exists = options.existsSync ??
|
|
21397
|
+
const exists = options.existsSync ?? existsSync4;
|
|
21380
21398
|
const pathEnv = options.pathEnv ?? process.env.PATH ?? "";
|
|
21381
21399
|
for (const dir of pathEnv.split(";").filter(Boolean)) {
|
|
21382
21400
|
if (!exists(win32Path.join(dir, `${cliId}.cmd`))) continue;
|
|
@@ -21893,8 +21911,10 @@ var VnextConfigError = class extends Error {
|
|
|
21893
21911
|
this.issues = sorted;
|
|
21894
21912
|
}
|
|
21895
21913
|
};
|
|
21896
|
-
|
|
21897
|
-
|
|
21914
|
+
function defaultVnextSchemaDir() {
|
|
21915
|
+
return join5(findKxmRepoRoot(import.meta.url), "schemas", "vnext");
|
|
21916
|
+
}
|
|
21917
|
+
var DEFAULT_SCHEMA_DIR = defaultVnextSchemaDir();
|
|
21898
21918
|
var RESOURCE_SCHEMA = Object.freeze({
|
|
21899
21919
|
project: { identity: "kxm.project.v1", file: "project.schema.json" },
|
|
21900
21920
|
repository: { identity: "kxm.repository.v1", file: "repository.schema.json" },
|
|
@@ -21959,10 +21979,10 @@ var VnextSchemaRegistry = class {
|
|
|
21959
21979
|
constructor(schemasDir = DEFAULT_SCHEMA_DIR) {
|
|
21960
21980
|
this.schemasDir = resolve2(schemasDir);
|
|
21961
21981
|
this.ajv = new import__.Ajv2020({ allErrors: true, strict: true, strictRequired: false });
|
|
21962
|
-
const common = readJsonObject(
|
|
21982
|
+
const common = readJsonObject(join5(this.schemasDir, "common.schema.json"));
|
|
21963
21983
|
this.ajv.addSchema(common);
|
|
21964
21984
|
for (const definition of Object.values(RESOURCE_SCHEMA)) {
|
|
21965
|
-
this.ajv.addSchema(readJsonObject(
|
|
21985
|
+
this.ajv.addSchema(readJsonObject(join5(this.schemasDir, definition.file)));
|
|
21966
21986
|
}
|
|
21967
21987
|
const localBindingsFile = "local-repository-bindings.schema.json";
|
|
21968
21988
|
const templateProvenanceFile = "template-provenance.schema.json";
|
|
@@ -21972,14 +21992,14 @@ var VnextSchemaRegistry = class {
|
|
|
21972
21992
|
const migrationReceiptFile = "migration-receipt.schema.json";
|
|
21973
21993
|
const permissionDiffFile = "permission-diff.schema.json";
|
|
21974
21994
|
const runEventFile = "run-event.schema.json";
|
|
21975
|
-
this.ajv.addSchema(readJsonObject(
|
|
21976
|
-
this.ajv.addSchema(readJsonObject(
|
|
21977
|
-
this.ajv.addSchema(readJsonObject(
|
|
21978
|
-
this.ajv.addSchema(readJsonObject(
|
|
21979
|
-
this.ajv.addSchema(readJsonObject(
|
|
21980
|
-
this.ajv.addSchema(readJsonObject(
|
|
21981
|
-
this.ajv.addSchema(readJsonObject(
|
|
21982
|
-
this.ajv.addSchema(readJsonObject(
|
|
21995
|
+
this.ajv.addSchema(readJsonObject(join5(this.schemasDir, localBindingsFile)));
|
|
21996
|
+
this.ajv.addSchema(readJsonObject(join5(this.schemasDir, templateProvenanceFile)));
|
|
21997
|
+
this.ajv.addSchema(readJsonObject(join5(this.schemasDir, initOperationFile)));
|
|
21998
|
+
this.ajv.addSchema(readJsonObject(join5(this.schemasDir, migrationPlanFile)));
|
|
21999
|
+
this.ajv.addSchema(readJsonObject(join5(this.schemasDir, migrationDecisionFile)));
|
|
22000
|
+
this.ajv.addSchema(readJsonObject(join5(this.schemasDir, migrationReceiptFile)));
|
|
22001
|
+
this.ajv.addSchema(readJsonObject(join5(this.schemasDir, permissionDiffFile)));
|
|
22002
|
+
this.ajv.addSchema(readJsonObject(join5(this.schemasDir, runEventFile)));
|
|
21983
22003
|
for (const [kind, definition] of Object.entries(RESOURCE_SCHEMA)) {
|
|
21984
22004
|
const validator = this.ajv.getSchema(`https://schemas.kxm.dev/vnext/${definition.file}`);
|
|
21985
22005
|
if (!validator) throw new Error(`schema did not compile: ${definition.file}`);
|
|
@@ -22074,15 +22094,15 @@ function containedHostPath(root, candidate) {
|
|
|
22074
22094
|
function portableBindingIssue(root, pathHint, repositoryId) {
|
|
22075
22095
|
let current = root;
|
|
22076
22096
|
for (const segment of pathHint === "." ? [] : pathHint.split("/")) {
|
|
22077
|
-
current =
|
|
22078
|
-
if (!
|
|
22097
|
+
current = join5(current, segment);
|
|
22098
|
+
if (!existsSync5(current)) break;
|
|
22079
22099
|
const stat = lstatSync(current);
|
|
22080
22100
|
if (stat.isSymbolicLink()) {
|
|
22081
22101
|
return issue2("path", "repository_binding_path_link", ".kxm/project.yaml", `portable pathHint for ${repositoryId} traverses a symbolic link or junction`);
|
|
22082
22102
|
}
|
|
22083
22103
|
}
|
|
22084
22104
|
const binding = resolve2(root, ...pathHint.split("/"));
|
|
22085
|
-
if (
|
|
22105
|
+
if (existsSync5(binding)) {
|
|
22086
22106
|
const realRoot = canonicalHostPath(root);
|
|
22087
22107
|
const realBinding = canonicalHostPath(binding);
|
|
22088
22108
|
if (!containedHostPath(realRoot, realBinding)) {
|
|
@@ -22120,9 +22140,9 @@ function readResource(registry, root, file, logicalPath, kind, id, containmentRo
|
|
|
22120
22140
|
}
|
|
22121
22141
|
if (stat.isSymbolicLink()) fail2("path", "resource_symlink", label, "configuration resources must not be symbolic links");
|
|
22122
22142
|
const boundary = resolve2(containmentRoot);
|
|
22123
|
-
let parent =
|
|
22143
|
+
let parent = dirname3(file);
|
|
22124
22144
|
while (parent !== boundary) {
|
|
22125
|
-
if (parent ===
|
|
22145
|
+
if (parent === dirname3(parent)) fail2("path", "resource_outside_project", label, "resource escapes the project root");
|
|
22126
22146
|
let parentStat;
|
|
22127
22147
|
try {
|
|
22128
22148
|
parentStat = lstatSync(parent);
|
|
@@ -22130,7 +22150,7 @@ function readResource(registry, root, file, logicalPath, kind, id, containmentRo
|
|
|
22130
22150
|
fail2("discovery", "resource_parent_missing", label, "resource parent does not exist");
|
|
22131
22151
|
}
|
|
22132
22152
|
if (parentStat.isSymbolicLink()) fail2("path", "resource_parent_symlink", label, "configuration resource parents must not be symbolic links");
|
|
22133
|
-
parent =
|
|
22153
|
+
parent = dirname3(parent);
|
|
22134
22154
|
}
|
|
22135
22155
|
if (!stat.isFile()) fail2("path", "resource_not_file", label, "configuration resource must be a regular file");
|
|
22136
22156
|
const value = parseRestrictedYaml2(readFileSync4(file), label);
|
|
@@ -22139,22 +22159,22 @@ function readResource(registry, root, file, logicalPath, kind, id, containmentRo
|
|
|
22139
22159
|
return { kind, ...id === void 0 ? {} : { id }, file, logicalPath, value };
|
|
22140
22160
|
}
|
|
22141
22161
|
function readTemplateProvenance(registry, root) {
|
|
22142
|
-
const file =
|
|
22143
|
-
if (!
|
|
22162
|
+
const file = join5(root, ".kxm", "template-provenance.yaml");
|
|
22163
|
+
if (!existsSync5(file)) return void 0;
|
|
22144
22164
|
const label = ".kxm/template-provenance.yaml";
|
|
22145
22165
|
const stat = lstatSync(file);
|
|
22146
22166
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
22147
22167
|
fail2("path", "resource_not_file", label, "template provenance must be a regular file, not a link or directory");
|
|
22148
22168
|
}
|
|
22149
|
-
const configRoot =
|
|
22150
|
-
let parent =
|
|
22169
|
+
const configRoot = join5(root, ".kxm");
|
|
22170
|
+
let parent = dirname3(file);
|
|
22151
22171
|
while (parent !== root) {
|
|
22152
22172
|
const parentStat = lstatSync(parent);
|
|
22153
22173
|
if (parentStat.isSymbolicLink() || !parentStat.isDirectory()) {
|
|
22154
22174
|
fail2("path", "resource_parent_symlink", label, "template provenance parents must be regular directories");
|
|
22155
22175
|
}
|
|
22156
22176
|
if (parent === configRoot) break;
|
|
22157
|
-
parent =
|
|
22177
|
+
parent = dirname3(parent);
|
|
22158
22178
|
}
|
|
22159
22179
|
const value = parseRestrictedYaml2(readFileSync4(file), label);
|
|
22160
22180
|
const issues = registry.validateTemplateProvenance(value, label);
|
|
@@ -22187,7 +22207,7 @@ function readTemplateProvenance(registry, root) {
|
|
|
22187
22207
|
}
|
|
22188
22208
|
function listNamedResources(registry, root, directory, logicalDirectory, kind) {
|
|
22189
22209
|
const resources = /* @__PURE__ */ new Map();
|
|
22190
|
-
if (!
|
|
22210
|
+
if (!existsSync5(directory)) return resources;
|
|
22191
22211
|
const stat = lstatSync(directory);
|
|
22192
22212
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
22193
22213
|
fail2("path", "resource_directory_invalid", displayPath(root, directory), "resource directory must be a regular directory");
|
|
@@ -22196,27 +22216,27 @@ function listNamedResources(registry, root, directory, logicalDirectory, kind) {
|
|
|
22196
22216
|
const entries = readdirSync(directory, { withFileTypes: true }).sort((left, right) => compareCodeUnits3(left.name, right.name));
|
|
22197
22217
|
for (const entry of entries) {
|
|
22198
22218
|
if (entry.isDirectory()) {
|
|
22199
|
-
issues.push(issue2("path", "nested_resource_directory", displayPath(root,
|
|
22219
|
+
issues.push(issue2("path", "nested_resource_directory", displayPath(root, join5(directory, entry.name)), "nested resource directories are not allowed"));
|
|
22200
22220
|
continue;
|
|
22201
22221
|
}
|
|
22202
22222
|
if (!entry.name.toLowerCase().endsWith(".yaml") && !entry.name.toLowerCase().endsWith(".yml")) continue;
|
|
22203
22223
|
if (!entry.isFile() || extname(entry.name) !== ".yaml") {
|
|
22204
|
-
issues.push(issue2("path", "resource_filename_invalid", displayPath(root,
|
|
22224
|
+
issues.push(issue2("path", "resource_filename_invalid", displayPath(root, join5(directory, entry.name)), "resource must be a regular file with the exact .yaml extension"));
|
|
22205
22225
|
continue;
|
|
22206
22226
|
}
|
|
22207
22227
|
const id = basename2(entry.name, ".yaml");
|
|
22208
22228
|
if (kind === "model" && id === "inventory") continue;
|
|
22209
22229
|
if (!resourceIdentifier(id)) {
|
|
22210
|
-
issues.push(issue2("path", "resource_id_invalid", displayPath(root,
|
|
22230
|
+
issues.push(issue2("path", "resource_id_invalid", displayPath(root, join5(directory, entry.name)), `filename-derived identity ${id} is invalid or platform-reserved`));
|
|
22211
22231
|
continue;
|
|
22212
22232
|
}
|
|
22213
22233
|
const collision = [...resources.keys()].find((candidate) => candidate.toLocaleLowerCase("en-US") === id.toLocaleLowerCase("en-US"));
|
|
22214
22234
|
if (collision) {
|
|
22215
|
-
issues.push(issue2("path", "resource_id_collision", displayPath(root,
|
|
22235
|
+
issues.push(issue2("path", "resource_id_collision", displayPath(root, join5(directory, entry.name)), `${id} case-folds to existing ${collision}`));
|
|
22216
22236
|
continue;
|
|
22217
22237
|
}
|
|
22218
22238
|
try {
|
|
22219
|
-
const resource = readResource(registry, root,
|
|
22239
|
+
const resource = readResource(registry, root, join5(directory, entry.name), `${logicalDirectory}/${id}.yaml`, kind, id);
|
|
22220
22240
|
resources.set(id, resource);
|
|
22221
22241
|
} catch (error) {
|
|
22222
22242
|
if (error instanceof VnextConfigError) issues.push(...error.issues);
|
|
@@ -22537,8 +22557,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
22537
22557
|
const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
|
|
22538
22558
|
if (maxWriteRepositories > writable) issues.push(issue2("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
|
|
22539
22559
|
}
|
|
22540
|
-
const
|
|
22541
|
-
const minimumPassed =
|
|
22560
|
+
const join49 = objectValue(step.join);
|
|
22561
|
+
const minimumPassed = join49 && typeof join49.minimumPassed === "number" ? join49.minimumPassed : void 0;
|
|
22542
22562
|
if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue2("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
|
|
22543
22563
|
const distinctBy = names(assignment?.distinctBy);
|
|
22544
22564
|
if (distinctBy.length > 0) {
|
|
@@ -22752,9 +22772,9 @@ function validateBundle(project, repositories, agents, models, workflows, enviro
|
|
|
22752
22772
|
if (!workflows.has(defaultWorkflow)) issues.push(issue2("reference", "default_workflow_unknown", project.logicalPath, `default workflow ${defaultWorkflow} does not exist`));
|
|
22753
22773
|
for (const workflow of workflows.values()) validateWorkflow(workflow, agents, models, repositoryIds, gates, issues);
|
|
22754
22774
|
if (projectRoot) {
|
|
22755
|
-
const writerRolePath =
|
|
22775
|
+
const writerRolePath = join5(projectRoot, ".kxm", "roles", "writer.yaml");
|
|
22756
22776
|
const implementerAgent = agents.get("implementer") ?? agents.get("writer");
|
|
22757
|
-
if (
|
|
22777
|
+
if (existsSync5(writerRolePath) && implementerAgent) {
|
|
22758
22778
|
try {
|
|
22759
22779
|
const rawRole = parseRestrictedYaml2(readFileSync4(writerRolePath, "utf8"));
|
|
22760
22780
|
const roleObj = objectValue(rawRole);
|
|
@@ -22803,7 +22823,7 @@ function gitEnvironment() {
|
|
|
22803
22823
|
}
|
|
22804
22824
|
function discoverGitRoot(start = process.cwd()) {
|
|
22805
22825
|
let current = resolve2(start);
|
|
22806
|
-
if (
|
|
22826
|
+
if (existsSync5(current) && !lstatSync(current).isDirectory()) current = dirname3(current);
|
|
22807
22827
|
const result = spawnSync2("git", ["-C", current, "rev-parse", "--show-toplevel"], {
|
|
22808
22828
|
encoding: "utf8",
|
|
22809
22829
|
env: gitEnvironment(),
|
|
@@ -22812,11 +22832,11 @@ function discoverGitRoot(start = process.cwd()) {
|
|
|
22812
22832
|
});
|
|
22813
22833
|
if (result.status !== 0 || result.error || !result.stdout.trim()) return void 0;
|
|
22814
22834
|
const root = resolve2(result.stdout.trim());
|
|
22815
|
-
return
|
|
22835
|
+
return existsSync5(root) && lstatSync(root).isDirectory() ? root : void 0;
|
|
22816
22836
|
}
|
|
22817
22837
|
function discoverVnextProjectRoot(start = process.cwd()) {
|
|
22818
22838
|
const gitRoot = discoverGitRoot(start);
|
|
22819
|
-
return gitRoot &&
|
|
22839
|
+
return gitRoot && existsSync5(join5(gitRoot, ".kxm", "project.yaml")) ? gitRoot : void 0;
|
|
22820
22840
|
}
|
|
22821
22841
|
function assertNoRegisteredGates(options) {
|
|
22822
22842
|
if ("registeredGates" in options) {
|
|
@@ -22833,7 +22853,7 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22833
22853
|
migrationReceipt = receiptCheck.receipt;
|
|
22834
22854
|
}
|
|
22835
22855
|
const registry = new VnextSchemaRegistry(options.schemasDir);
|
|
22836
|
-
const project = readResource(registry, root,
|
|
22856
|
+
const project = readResource(registry, root, join5(root, ".kxm", "project.yaml"), ".kxm/project.yaml", "project");
|
|
22837
22857
|
const earlyIssues = [];
|
|
22838
22858
|
validatePortablePaths(project, earlyIssues);
|
|
22839
22859
|
const templateProvenance = readTemplateProvenance(registry, root);
|
|
@@ -22855,16 +22875,16 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22855
22875
|
}
|
|
22856
22876
|
}
|
|
22857
22877
|
if (earlyIssues.length > 0) throw new VnextConfigError(earlyIssues);
|
|
22858
|
-
const agents = listNamedResources(registry, root,
|
|
22859
|
-
const models = listNamedResources(registry, root,
|
|
22860
|
-
const workflows = listNamedResources(registry, root,
|
|
22861
|
-
const gatePath =
|
|
22862
|
-
const gateRegistry =
|
|
22878
|
+
const agents = listNamedResources(registry, root, join5(root, ".kxm", "agents"), ".kxm/agents", "agent");
|
|
22879
|
+
const models = listNamedResources(registry, root, join5(root, ".kxm", "models"), ".kxm/models", "model");
|
|
22880
|
+
const workflows = listNamedResources(registry, root, join5(root, ".kxm", "workflows"), ".kxm/workflows", "workflow");
|
|
22881
|
+
const gatePath = join5(root, ".kxm", "gates.yaml");
|
|
22882
|
+
const gateRegistry = existsSync5(gatePath) ? readResource(registry, root, gatePath, ".kxm/gates.yaml", "gate-registry") : void 0;
|
|
22863
22883
|
const environments = [];
|
|
22864
22884
|
const repositories = /* @__PURE__ */ new Map();
|
|
22865
22885
|
const loadIssues = [];
|
|
22866
|
-
const projectEnvironment =
|
|
22867
|
-
if (
|
|
22886
|
+
const projectEnvironment = join5(root, ".kxm", "project", "env.yaml");
|
|
22887
|
+
if (existsSync5(projectEnvironment)) {
|
|
22868
22888
|
try {
|
|
22869
22889
|
environments.push(readResource(registry, root, projectEnvironment, ".kxm/project/env.yaml", "environment"));
|
|
22870
22890
|
} catch (error) {
|
|
@@ -22906,7 +22926,7 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22906
22926
|
if (required) loadIssues.push(issue2("discovery", "repository_binding_missing", ".kxm/project.yaml", `required repository ${repositoryId} has no portable pathHint or host-local binding`));
|
|
22907
22927
|
continue;
|
|
22908
22928
|
}
|
|
22909
|
-
if (!
|
|
22929
|
+
if (!existsSync5(binding)) {
|
|
22910
22930
|
if (required || hasLocalBinding) loadIssues.push(issue2("discovery", "repository_binding_unavailable", ".kxm/project.yaml", `${hasLocalBinding ? "explicit" : "required"} repository binding ${repositoryId} is unavailable`));
|
|
22911
22931
|
continue;
|
|
22912
22932
|
}
|
|
@@ -22929,9 +22949,9 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22929
22949
|
continue;
|
|
22930
22950
|
}
|
|
22931
22951
|
seenBindings.set(foldedBinding, repositoryId);
|
|
22932
|
-
const repositoryFile =
|
|
22952
|
+
const repositoryFile = join5(binding, ".kxm", "repo", "repo.yaml");
|
|
22933
22953
|
let definitionValidated = false;
|
|
22934
|
-
if (
|
|
22954
|
+
if (existsSync5(repositoryFile)) {
|
|
22935
22955
|
try {
|
|
22936
22956
|
const resource = readResource(registry, root, repositoryFile, `.kxm/repositories/${repositoryId}/repo.yaml`, "repository", repositoryId, binding);
|
|
22937
22957
|
if (resource.value.repositoryId !== repositoryId) {
|
|
@@ -22947,8 +22967,8 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22947
22967
|
} else if (required || hasLocalBinding) {
|
|
22948
22968
|
loadIssues.push(issue2("discovery", "repository_definition_missing", `.kxm/repositories/${repositoryId}/repo.yaml`, `${hasLocalBinding ? "explicit" : "required"} repository ${repositoryId} has no repo.yaml`));
|
|
22949
22969
|
}
|
|
22950
|
-
const environmentFile =
|
|
22951
|
-
if (
|
|
22970
|
+
const environmentFile = join5(binding, ".kxm", "repo", "env.yaml");
|
|
22971
|
+
if (existsSync5(environmentFile)) {
|
|
22952
22972
|
if (!definitionValidated) {
|
|
22953
22973
|
loadIssues.push(issue2("reference", "repository_environment_without_definition", `.kxm/repositories/${repositoryId}/env.yaml`, `repository ${repositoryId} environment requires a validated matching repo.yaml`));
|
|
22954
22974
|
} else {
|
|
@@ -23026,21 +23046,21 @@ function legacyInputsAt(root) {
|
|
|
23026
23046
|
".kxm/config/workflows",
|
|
23027
23047
|
".kxm/state/kxm.db"
|
|
23028
23048
|
];
|
|
23029
|
-
return candidates.filter((candidate) =>
|
|
23049
|
+
return candidates.filter((candidate) => existsSync5(join5(root, ...candidate.split("/"))));
|
|
23030
23050
|
}
|
|
23031
23051
|
var VNEXT_MIGRATION_RECEIPT_PATH = ".kxm/migration-receipt.yaml";
|
|
23032
23052
|
var LEGACY_CONFIG_FILES = [".kxm/config/agents.json", ".kxm/config/gates.json"];
|
|
23033
23053
|
function legacyConfigFilesAt(root) {
|
|
23034
23054
|
const files = [];
|
|
23035
23055
|
for (const component of [".kxm", ".kxm/config"]) {
|
|
23036
|
-
const absolute =
|
|
23037
|
-
if (
|
|
23056
|
+
const absolute = join5(root, ...component.split("/"));
|
|
23057
|
+
if (existsSync5(absolute) && lstatSync(absolute).isSymbolicLink()) return [component];
|
|
23038
23058
|
}
|
|
23039
23059
|
for (const candidate of LEGACY_CONFIG_FILES) {
|
|
23040
|
-
if (
|
|
23060
|
+
if (existsSync5(join5(root, ...candidate.split("/")))) files.push(candidate);
|
|
23041
23061
|
}
|
|
23042
|
-
const workflowsDir =
|
|
23043
|
-
if (
|
|
23062
|
+
const workflowsDir = join5(root, ".kxm", "config", "workflows");
|
|
23063
|
+
if (existsSync5(workflowsDir)) {
|
|
23044
23064
|
const stat = lstatSync(workflowsDir);
|
|
23045
23065
|
if (stat.isSymbolicLink()) {
|
|
23046
23066
|
files.push(".kxm/config/workflows");
|
|
@@ -23055,8 +23075,8 @@ function legacyConfigFilesAt(root) {
|
|
|
23055
23075
|
return files;
|
|
23056
23076
|
}
|
|
23057
23077
|
function hashFileRecord(root, relativePath) {
|
|
23058
|
-
const absolute =
|
|
23059
|
-
if (!
|
|
23078
|
+
const absolute = join5(root, ...relativePath.split("/"));
|
|
23079
|
+
if (!existsSync5(absolute)) return void 0;
|
|
23060
23080
|
const bytes = readFileSync4(absolute);
|
|
23061
23081
|
return {
|
|
23062
23082
|
path: relativePath,
|
|
@@ -23069,9 +23089,9 @@ function migrationReceiptSelfHash(receipt) {
|
|
|
23069
23089
|
return `sha256:${createHash6("sha256").update(vnextCanonicalJson(unsigned), "utf8").digest("hex")}`;
|
|
23070
23090
|
}
|
|
23071
23091
|
function readVnextMigrationReceipt(root, options = {}) {
|
|
23072
|
-
const receiptPath =
|
|
23092
|
+
const receiptPath = join5(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
|
|
23073
23093
|
const legacyFiles = legacyConfigFilesAt(root);
|
|
23074
|
-
if (!
|
|
23094
|
+
if (!existsSync5(receiptPath)) {
|
|
23075
23095
|
return {
|
|
23076
23096
|
issues: legacyFiles.map((file) => issue2("semantic", "legacy_vnext_conflict", file, "legacy and vNext configuration cannot coexist before an accepted migration receipt"))
|
|
23077
23097
|
};
|
|
@@ -23116,7 +23136,7 @@ function readVnextMigrationReceipt(root, options = {}) {
|
|
|
23116
23136
|
}
|
|
23117
23137
|
function discoverLegacyRoot(start) {
|
|
23118
23138
|
let initial = resolve2(start);
|
|
23119
|
-
if (
|
|
23139
|
+
if (existsSync5(initial) && !lstatSync(initial).isDirectory()) initial = dirname3(initial);
|
|
23120
23140
|
const candidate = discoverGitRoot(initial) ?? initial;
|
|
23121
23141
|
const inputs = legacyInputsAt(candidate);
|
|
23122
23142
|
return inputs.length > 0 ? { root: candidate, inputs } : void 0;
|
|
@@ -23143,7 +23163,7 @@ function planVnextInitialization(start = process.cwd(), options = {}) {
|
|
|
23143
23163
|
}
|
|
23144
23164
|
const gitRoot = discoverGitRoot(inspectedFrom);
|
|
23145
23165
|
const candidateRoot = gitRoot ?? inspectedFrom;
|
|
23146
|
-
if (
|
|
23166
|
+
if (existsSync5(join5(candidateRoot, ".kxm"))) {
|
|
23147
23167
|
return {
|
|
23148
23168
|
mode: "repair",
|
|
23149
23169
|
inspectedFrom,
|
|
@@ -23159,14 +23179,13 @@ function planVnextInitialization(start = process.cwd(), options = {}) {
|
|
|
23159
23179
|
// plugins/kxm/src/vnext-runtime-supervisor.ts
|
|
23160
23180
|
import { spawn as spawn2 } from "node:child_process";
|
|
23161
23181
|
import { createHash as createHash11, createHmac, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
23162
|
-
import { chmodSync as chmodSync4, existsSync as
|
|
23163
|
-
import { dirname as
|
|
23164
|
-
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
23182
|
+
import { chmodSync as chmodSync4, existsSync as existsSync11, lstatSync as lstatSync6, mkdirSync as mkdirSync7, readFileSync as readFileSync10, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
|
|
23183
|
+
import { dirname as dirname7, isAbsolute as isAbsolute4, join as join11 } from "node:path";
|
|
23165
23184
|
|
|
23166
23185
|
// plugins/kxm/src/vnext-runtime-store.ts
|
|
23167
23186
|
import { createHash as createHash9, randomUUID as randomUUID4 } from "node:crypto";
|
|
23168
|
-
import { existsSync as
|
|
23169
|
-
import { dirname as
|
|
23187
|
+
import { existsSync as existsSync8, lstatSync as lstatSync4, mkdirSync as mkdirSync5, readFileSync as readFileSync7, realpathSync as realpathSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
23188
|
+
import { dirname as dirname6, join as join8, resolve as resolve5 } from "node:path";
|
|
23170
23189
|
|
|
23171
23190
|
// plugins/kxm/src/vnext-bindings.ts
|
|
23172
23191
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
@@ -23174,7 +23193,7 @@ import { createHash as createHash7, randomUUID as randomUUID3 } from "node:crypt
|
|
|
23174
23193
|
import {
|
|
23175
23194
|
chmodSync as chmodSync2,
|
|
23176
23195
|
closeSync,
|
|
23177
|
-
existsSync as
|
|
23196
|
+
existsSync as existsSync6,
|
|
23178
23197
|
fsyncSync,
|
|
23179
23198
|
lstatSync as lstatSync2,
|
|
23180
23199
|
mkdirSync as mkdirSync3,
|
|
@@ -23227,7 +23246,7 @@ var DatabaseSync = class {
|
|
|
23227
23246
|
};
|
|
23228
23247
|
|
|
23229
23248
|
// plugins/kxm/src/vnext-bindings.ts
|
|
23230
|
-
import { dirname as
|
|
23249
|
+
import { dirname as dirname4, isAbsolute as isAbsolute2, join as join6, parse, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
|
|
23231
23250
|
var MAX_BINDING_RECORD_BYTES = 256 * 1024;
|
|
23232
23251
|
var BINDING_LABEL = "Runtime-local repository bindings";
|
|
23233
23252
|
var activeLocks = /* @__PURE__ */ new WeakSet();
|
|
@@ -23261,12 +23280,12 @@ function vnextUserStateRoot(options = {}) {
|
|
|
23261
23280
|
}
|
|
23262
23281
|
if (platform === "win32") {
|
|
23263
23282
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
23264
|
-
const base2 = localAppData && isAbsolute2(localAppData) ? localAppData :
|
|
23283
|
+
const base2 = localAppData && isAbsolute2(localAppData) ? localAppData : join6(home, "AppData", "Local");
|
|
23265
23284
|
return resolve3(base2, "KXM");
|
|
23266
23285
|
}
|
|
23267
23286
|
if (platform === "darwin") return resolve3(home, "Library", "Application Support", "KXM");
|
|
23268
23287
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
23269
|
-
const base = xdgState && isAbsolute2(xdgState) ? xdgState :
|
|
23288
|
+
const base = xdgState && isAbsolute2(xdgState) ? xdgState : join6(home, ".local", "state");
|
|
23270
23289
|
return resolve3(base, "kxm");
|
|
23271
23290
|
}
|
|
23272
23291
|
function projectBindingKey(projectRoot, platform = process.platform) {
|
|
@@ -23276,10 +23295,10 @@ function projectBindingKey(projectRoot, platform = process.platform) {
|
|
|
23276
23295
|
}
|
|
23277
23296
|
function vnextLocalBindingFile(projectRoot, options = {}) {
|
|
23278
23297
|
const stateRoot = vnextUserStateRoot(options);
|
|
23279
|
-
return
|
|
23298
|
+
return join6(stateRoot, "projects", projectBindingKey(projectRoot, options.platform), "repository-bindings.json");
|
|
23280
23299
|
}
|
|
23281
23300
|
function checkedDirectory(path4, description) {
|
|
23282
|
-
if (!
|
|
23301
|
+
if (!existsSync6(path4)) return false;
|
|
23283
23302
|
const stat = lstatSync2(path4);
|
|
23284
23303
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23285
23304
|
bindingError("path", "local_binding_directory_invalid", `${description} must be a regular directory, not a link or file`);
|
|
@@ -23287,8 +23306,8 @@ function checkedDirectory(path4, description) {
|
|
|
23287
23306
|
return true;
|
|
23288
23307
|
}
|
|
23289
23308
|
function existingBindingDirectory(file, stateRoot) {
|
|
23290
|
-
const projects =
|
|
23291
|
-
const project =
|
|
23309
|
+
const projects = join6(stateRoot, "projects");
|
|
23310
|
+
const project = dirname4(file);
|
|
23292
23311
|
if (!checkedDirectory(stateRoot, "local state root")) return false;
|
|
23293
23312
|
if (!checkedDirectory(projects, "local projects directory")) return false;
|
|
23294
23313
|
return checkedDirectory(project, "local project binding directory");
|
|
@@ -23314,7 +23333,7 @@ function readVnextLocalBindings(projectRoot, options = {}) {
|
|
|
23314
23333
|
const root = resolve3(projectRoot);
|
|
23315
23334
|
const stateRoot = vnextUserStateRoot(options);
|
|
23316
23335
|
const file = vnextLocalBindingFile(root, options);
|
|
23317
|
-
if (!existingBindingDirectory(file, stateRoot) || !
|
|
23336
|
+
if (!existingBindingDirectory(file, stateRoot) || !existsSync6(file)) return void 0;
|
|
23318
23337
|
const stat = lstatSync2(file);
|
|
23319
23338
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
23320
23339
|
bindingError("path", "local_binding_file_invalid", "binding record must be a regular file, not a link or directory");
|
|
@@ -23362,10 +23381,10 @@ function syncDirectory(path4) {
|
|
|
23362
23381
|
}
|
|
23363
23382
|
}
|
|
23364
23383
|
function createDirectoryIfMissing(path4) {
|
|
23365
|
-
if (
|
|
23384
|
+
if (existsSync6(path4)) return;
|
|
23366
23385
|
try {
|
|
23367
23386
|
mkdirSync3(path4, { mode: 448 });
|
|
23368
|
-
syncDirectory(
|
|
23387
|
+
syncDirectory(dirname4(path4));
|
|
23369
23388
|
} catch (error) {
|
|
23370
23389
|
if (error.code !== "EEXIST") throw error;
|
|
23371
23390
|
}
|
|
@@ -23373,9 +23392,9 @@ function createDirectoryIfMissing(path4) {
|
|
|
23373
23392
|
function ensureDurableDirectory(path4, description) {
|
|
23374
23393
|
const missing = [];
|
|
23375
23394
|
let current = resolve3(path4);
|
|
23376
|
-
while (!
|
|
23395
|
+
while (!existsSync6(current)) {
|
|
23377
23396
|
missing.push(current);
|
|
23378
|
-
const parent =
|
|
23397
|
+
const parent = dirname4(current);
|
|
23379
23398
|
if (parent === current) bindingError("path", "local_binding_directory_invalid", `${description} has no existing filesystem ancestor`);
|
|
23380
23399
|
current = parent;
|
|
23381
23400
|
}
|
|
@@ -23383,17 +23402,17 @@ function ensureDurableDirectory(path4, description) {
|
|
|
23383
23402
|
for (const directory of missing.reverse()) {
|
|
23384
23403
|
mkdirSync3(directory, { mode: 448 });
|
|
23385
23404
|
checkedDirectory(directory, description);
|
|
23386
|
-
syncDirectory(
|
|
23405
|
+
syncDirectory(dirname4(directory));
|
|
23387
23406
|
}
|
|
23388
23407
|
}
|
|
23389
23408
|
function ensureBindingDirectory(file, stateRoot) {
|
|
23390
23409
|
ensureDurableDirectory(stateRoot, "local state root");
|
|
23391
23410
|
checkedDirectory(stateRoot, "local state root");
|
|
23392
23411
|
syncDirectory(stateRoot);
|
|
23393
|
-
const projects =
|
|
23412
|
+
const projects = join6(stateRoot, "projects");
|
|
23394
23413
|
createDirectoryIfMissing(projects);
|
|
23395
23414
|
checkedDirectory(projects, "local projects directory");
|
|
23396
|
-
const project =
|
|
23415
|
+
const project = dirname4(file);
|
|
23397
23416
|
createDirectoryIfMissing(project);
|
|
23398
23417
|
checkedDirectory(project, "local project binding directory");
|
|
23399
23418
|
}
|
|
@@ -23403,7 +23422,7 @@ function assertNoLinkedDirectoryComponents(path4, description) {
|
|
|
23403
23422
|
let current = filesystemRoot;
|
|
23404
23423
|
const remainder = relative2(filesystemRoot, absolute);
|
|
23405
23424
|
for (const segment of remainder.split(sep2).filter(Boolean)) {
|
|
23406
|
-
current =
|
|
23425
|
+
current = join6(current, segment);
|
|
23407
23426
|
const stat = lstatSync2(current);
|
|
23408
23427
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23409
23428
|
bindingError("path", "project_operation_lock_parent_invalid", `${description} contains a linked or non-directory component`);
|
|
@@ -23430,8 +23449,8 @@ function projectOperationLockFile(projectRoot) {
|
|
|
23430
23449
|
if (gitStat.isSymbolicLink() || !gitStat.isDirectory()) {
|
|
23431
23450
|
bindingError("path", "project_operation_lock_parent_invalid", "authoritative Git metadata must resolve to a regular directory");
|
|
23432
23451
|
}
|
|
23433
|
-
const lockDirectory =
|
|
23434
|
-
if (
|
|
23452
|
+
const lockDirectory = join6(gitDirectory, "kxm");
|
|
23453
|
+
if (existsSync6(lockDirectory)) {
|
|
23435
23454
|
const stat = lstatSync2(lockDirectory);
|
|
23436
23455
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23437
23456
|
bindingError("path", "project_operation_lock_parent_invalid", "Git-local KXM lock directory must be regular, not a link or file");
|
|
@@ -23440,12 +23459,12 @@ function projectOperationLockFile(projectRoot) {
|
|
|
23440
23459
|
mkdirSync3(lockDirectory, { mode: 448 });
|
|
23441
23460
|
syncDirectory(gitDirectory);
|
|
23442
23461
|
}
|
|
23443
|
-
return
|
|
23462
|
+
return join6(lockDirectory, "project-operation-lock.sqlite");
|
|
23444
23463
|
}
|
|
23445
23464
|
function withVnextLocalBindingLock(projectRoot, options, callback) {
|
|
23446
23465
|
const root = resolve3(projectRoot);
|
|
23447
23466
|
const file = projectOperationLockFile(root);
|
|
23448
|
-
if (
|
|
23467
|
+
if (existsSync6(file)) {
|
|
23449
23468
|
const stat = lstatSync2(file);
|
|
23450
23469
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
23451
23470
|
bindingError("path", "local_binding_lock_invalid", "project-operation lock must be a regular file, not a link or directory");
|
|
@@ -23499,7 +23518,7 @@ function writeVnextLocalBindings(projectRoot, projectId, repositories, options =
|
|
|
23499
23518
|
const { file, record } = planned;
|
|
23500
23519
|
if (!planned.written) return planned;
|
|
23501
23520
|
ensureBindingDirectory(file, vnextUserStateRoot(options));
|
|
23502
|
-
const temporary =
|
|
23521
|
+
const temporary = join6(dirname4(file), `.repository-bindings-${process.pid}-${randomUUID3()}.tmp`);
|
|
23503
23522
|
let descriptor;
|
|
23504
23523
|
try {
|
|
23505
23524
|
descriptor = openSync(temporary, "wx", 384);
|
|
@@ -23509,7 +23528,7 @@ function writeVnextLocalBindings(projectRoot, projectId, repositories, options =
|
|
|
23509
23528
|
closeSync(descriptor);
|
|
23510
23529
|
descriptor = void 0;
|
|
23511
23530
|
renameSync(temporary, file);
|
|
23512
|
-
syncDirectory(
|
|
23531
|
+
syncDirectory(dirname4(file));
|
|
23513
23532
|
} finally {
|
|
23514
23533
|
if (descriptor !== void 0) closeSync(descriptor);
|
|
23515
23534
|
rmSync(temporary, { force: true });
|
|
@@ -23526,7 +23545,7 @@ import { createHash as createHash8, randomBytes } from "node:crypto";
|
|
|
23526
23545
|
import {
|
|
23527
23546
|
chmodSync as chmodSync3,
|
|
23528
23547
|
copyFileSync,
|
|
23529
|
-
existsSync as
|
|
23548
|
+
existsSync as existsSync7,
|
|
23530
23549
|
lstatSync as lstatSync3,
|
|
23531
23550
|
mkdirSync as mkdirSync4,
|
|
23532
23551
|
readdirSync as readdirSync2,
|
|
@@ -23534,14 +23553,14 @@ import {
|
|
|
23534
23553
|
unlinkSync as unlinkSync2,
|
|
23535
23554
|
writeFileSync as writeFileSync4
|
|
23536
23555
|
} from "node:fs";
|
|
23537
|
-
import { basename as basename3, dirname as
|
|
23556
|
+
import { basename as basename3, dirname as dirname5, join as join7, resolve as resolve4 } from "node:path";
|
|
23538
23557
|
function databaseError(code, file, message) {
|
|
23539
23558
|
const issue3 = { phase: "semantic", code, file, message };
|
|
23540
23559
|
return new VnextConfigError([issue3]);
|
|
23541
23560
|
}
|
|
23542
23561
|
function checkedParent(path4, description) {
|
|
23543
|
-
const parent =
|
|
23544
|
-
if (!
|
|
23562
|
+
const parent = dirname5(path4);
|
|
23563
|
+
if (!existsSync7(parent)) mkdirSync4(parent, { recursive: true, mode: 448 });
|
|
23545
23564
|
const stat = lstatSync3(parent, { throwIfNoEntry: false });
|
|
23546
23565
|
if (!stat || stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23547
23566
|
throw databaseError("runtime_path_invalid", description, `${description} parent must be a regular directory, not a link`);
|
|
@@ -23694,7 +23713,7 @@ function backupDatabaseFile(sourcePath, targetPath, storeId) {
|
|
|
23694
23713
|
throw databaseError("runtime_path_invalid", resolvedSource, `source database ${resolvedSource} must be a regular file, not a link or directory`);
|
|
23695
23714
|
}
|
|
23696
23715
|
checkedParent(resolvedTarget, "backup target");
|
|
23697
|
-
if (
|
|
23716
|
+
if (existsSync7(resolvedTarget)) {
|
|
23698
23717
|
unlinkSync2(resolvedTarget);
|
|
23699
23718
|
}
|
|
23700
23719
|
const sourceDb = new DatabaseSync(resolvedSource);
|
|
@@ -23772,7 +23791,7 @@ function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVers
|
|
|
23772
23791
|
}
|
|
23773
23792
|
checkedParent(resolvedTarget, "restore target");
|
|
23774
23793
|
for (const file of [resolvedTarget, `${resolvedTarget}-wal`, `${resolvedTarget}-shm`]) {
|
|
23775
|
-
if (
|
|
23794
|
+
if (existsSync7(file)) {
|
|
23776
23795
|
try {
|
|
23777
23796
|
unlinkSync2(file);
|
|
23778
23797
|
} catch {
|
|
@@ -23804,27 +23823,27 @@ function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVers
|
|
|
23804
23823
|
function discoverProjectStores(projectRoot, options = {}) {
|
|
23805
23824
|
const root = resolve4(projectRoot);
|
|
23806
23825
|
const stores = [];
|
|
23807
|
-
const hubPath = options.hubDataPath ? resolve4(options.hubDataPath) :
|
|
23808
|
-
if (
|
|
23826
|
+
const hubPath = options.hubDataPath ? resolve4(options.hubDataPath) : join7(root, ".kxm", "state", "kxm.db");
|
|
23827
|
+
if (existsSync7(hubPath)) {
|
|
23809
23828
|
stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: 3 });
|
|
23810
23829
|
}
|
|
23811
|
-
const registryPath =
|
|
23812
|
-
if (
|
|
23830
|
+
const registryPath = join7(root, ".kxm", "runtime", "registry.db");
|
|
23831
|
+
if (existsSync7(registryPath)) {
|
|
23813
23832
|
stores.push({ storeId: "registry", sourcePath: registryPath, maxSupportedVersion: 1 });
|
|
23814
23833
|
}
|
|
23815
|
-
const bindingsPath =
|
|
23816
|
-
if (
|
|
23834
|
+
const bindingsPath = join7(root, ".kxm", "runtime", "bindings.db");
|
|
23835
|
+
if (existsSync7(bindingsPath)) {
|
|
23817
23836
|
stores.push({ storeId: "binding-store", sourcePath: bindingsPath, maxSupportedVersion: 1 });
|
|
23818
23837
|
}
|
|
23819
|
-
const eventsDir =
|
|
23820
|
-
if (
|
|
23838
|
+
const eventsDir = join7(root, ".kxm", "runtime", "events");
|
|
23839
|
+
if (existsSync7(eventsDir)) {
|
|
23821
23840
|
const entries = readdirSync2(eventsDir, { withFileTypes: true });
|
|
23822
23841
|
for (const entry of entries) {
|
|
23823
23842
|
if (entry.isFile() && entry.name.endsWith(".db")) {
|
|
23824
23843
|
const key = entry.name.replace(/\.db$/, "");
|
|
23825
23844
|
stores.push({
|
|
23826
23845
|
storeId: `events:${key}`,
|
|
23827
|
-
sourcePath:
|
|
23846
|
+
sourcePath: join7(eventsDir, entry.name),
|
|
23828
23847
|
maxSupportedVersion: 3
|
|
23829
23848
|
});
|
|
23830
23849
|
}
|
|
@@ -23843,8 +23862,8 @@ function createBackup(options = {}) {
|
|
|
23843
23862
|
const now = /* @__PURE__ */ new Date();
|
|
23844
23863
|
const timestamp = now.toISOString().replace(/[:.]/g, "-");
|
|
23845
23864
|
const backupId = `bk_${randomBytes(8).toString("hex")}`;
|
|
23846
|
-
const outDir = options.outDir ? resolve4(options.outDir) :
|
|
23847
|
-
if (!
|
|
23865
|
+
const outDir = options.outDir ? resolve4(options.outDir) : join7(projectRoot, ".kxm", "backups", `backup-${timestamp}`);
|
|
23866
|
+
if (!existsSync7(outDir)) {
|
|
23848
23867
|
mkdirSync4(outDir, { recursive: true, mode: 448 });
|
|
23849
23868
|
}
|
|
23850
23869
|
const backedUpStores = [];
|
|
@@ -23856,7 +23875,7 @@ function createBackup(options = {}) {
|
|
|
23856
23875
|
filename = `${sanitizedId}-${filename}`;
|
|
23857
23876
|
}
|
|
23858
23877
|
usedFilenames.add(filename);
|
|
23859
|
-
const targetFile2 =
|
|
23878
|
+
const targetFile2 = join7(outDir, filename);
|
|
23860
23879
|
const record = backupDatabaseFile(store.sourcePath, targetFile2, store.storeId);
|
|
23861
23880
|
backedUpStores.push(record);
|
|
23862
23881
|
}
|
|
@@ -23871,7 +23890,7 @@ function createBackup(options = {}) {
|
|
|
23871
23890
|
const manifestSha256 = `sha256:${createHash8("sha256").update(manifestJson, "utf8").digest("hex")}`;
|
|
23872
23891
|
manifest.manifestSha256 = manifestSha256;
|
|
23873
23892
|
const finalJson = JSON.stringify(manifest, null, 2) + "\n";
|
|
23874
|
-
const manifestPath =
|
|
23893
|
+
const manifestPath = join7(outDir, "manifest.json");
|
|
23875
23894
|
writeFileSync4(manifestPath, finalJson, "utf8");
|
|
23876
23895
|
return { manifest, outDir };
|
|
23877
23896
|
}
|
|
@@ -23882,12 +23901,12 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23882
23901
|
throw databaseError("runtime_path_invalid", manifestPath, `manifest path ${manifestPath} does not exist`);
|
|
23883
23902
|
}
|
|
23884
23903
|
if (stat.isDirectory()) {
|
|
23885
|
-
manifestPath =
|
|
23904
|
+
manifestPath = join7(manifestPath, "manifest.json");
|
|
23886
23905
|
}
|
|
23887
|
-
if (!
|
|
23906
|
+
if (!existsSync7(manifestPath)) {
|
|
23888
23907
|
throw databaseError("runtime_path_invalid", manifestPath, `backup manifest ${manifestPath} not found`);
|
|
23889
23908
|
}
|
|
23890
|
-
const manifestDir =
|
|
23909
|
+
const manifestDir = dirname5(manifestPath);
|
|
23891
23910
|
const rawText = readFileSync6(manifestPath, "utf8");
|
|
23892
23911
|
let manifest;
|
|
23893
23912
|
try {
|
|
@@ -23900,8 +23919,8 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23900
23919
|
}
|
|
23901
23920
|
const restoredStores = [];
|
|
23902
23921
|
for (const store of manifest.stores) {
|
|
23903
|
-
const backupFilePath =
|
|
23904
|
-
if (!
|
|
23922
|
+
const backupFilePath = join7(manifestDir, store.backupFile);
|
|
23923
|
+
if (!existsSync7(backupFilePath)) {
|
|
23905
23924
|
throw databaseError("restore_file_missing", backupFilePath, `backup file ${store.backupFile} missing from ${manifestDir}`);
|
|
23906
23925
|
}
|
|
23907
23926
|
const actualSha256 = fileSha256(backupFilePath);
|
|
@@ -23919,7 +23938,7 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23919
23938
|
let targetPath = store.sourcePath;
|
|
23920
23939
|
if (options.projectRoot && manifest.projectRoot && targetPath.startsWith(manifest.projectRoot)) {
|
|
23921
23940
|
const rel = targetPath.slice(manifest.projectRoot.length).replace(/^[\\/]+/, "");
|
|
23922
|
-
targetPath =
|
|
23941
|
+
targetPath = join7(resolve4(options.projectRoot), rel);
|
|
23923
23942
|
}
|
|
23924
23943
|
const result = restoreDatabaseFile(
|
|
23925
23944
|
backupFilePath,
|
|
@@ -23940,12 +23959,12 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23940
23959
|
// plugins/kxm/src/vnext-runtime-store.ts
|
|
23941
23960
|
function vnextRuntimePaths(options = {}) {
|
|
23942
23961
|
const stateRoot = options.stateRoot ? resolve5(options.stateRoot) : vnextUserStateRoot({ ...options.env ? { env: options.env } : {}, ...options.homeDir ? { homeDir: options.homeDir } : {} });
|
|
23943
|
-
const runtimeDir =
|
|
23962
|
+
const runtimeDir = join8(stateRoot, "runtime");
|
|
23944
23963
|
return {
|
|
23945
23964
|
stateRoot,
|
|
23946
23965
|
runtimeDir,
|
|
23947
|
-
registryDb:
|
|
23948
|
-
projectsDir:
|
|
23966
|
+
registryDb: join8(runtimeDir, "registry.db"),
|
|
23967
|
+
projectsDir: join8(runtimeDir, "projects")
|
|
23949
23968
|
};
|
|
23950
23969
|
}
|
|
23951
23970
|
function runtimeIssue(phase, code, file, message) {
|
|
@@ -24304,7 +24323,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
24304
24323
|
const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
|
|
24305
24324
|
const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
|
|
24306
24325
|
const assignments = compileAssignments(step, id, agent, sink);
|
|
24307
|
-
const
|
|
24326
|
+
const join49 = compileJoin(step, id, sink);
|
|
24308
24327
|
const requiredEvidence = compileEvidence(step, id, sink);
|
|
24309
24328
|
const transitions = compileTransitions(step, id, index, stepIndex, sink);
|
|
24310
24329
|
const outcomes = Object.keys(transitions).sort(compareCodeUnits4);
|
|
@@ -24332,7 +24351,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
24332
24351
|
transitions: orderedTransitions,
|
|
24333
24352
|
requiresPlanHash: requirePlanHash.includes(id),
|
|
24334
24353
|
assignments,
|
|
24335
|
-
join:
|
|
24354
|
+
join: join49
|
|
24336
24355
|
};
|
|
24337
24356
|
if (kind === "agent" || kind === "moa") {
|
|
24338
24357
|
if (!agent) return void 0;
|
|
@@ -24382,15 +24401,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
|
|
|
24382
24401
|
};
|
|
24383
24402
|
}
|
|
24384
24403
|
function compileJoin(step, stepId, sink) {
|
|
24385
|
-
const
|
|
24386
|
-
if (!
|
|
24387
|
-
const declared = stringValue2(
|
|
24404
|
+
const join49 = objectValue2(step.join);
|
|
24405
|
+
if (!join49) return { strategy: "all" };
|
|
24406
|
+
const declared = stringValue2(join49.strategy);
|
|
24388
24407
|
const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
|
|
24389
|
-
const minimumPassed = compileOptionalCount(
|
|
24408
|
+
const minimumPassed = compileOptionalCount(join49.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
|
|
24390
24409
|
const compiled = {
|
|
24391
24410
|
strategy,
|
|
24392
24411
|
...minimumPassed !== void 0 ? { minimumPassed } : {},
|
|
24393
|
-
...typeof
|
|
24412
|
+
...typeof join49.cancelRemaining === "boolean" ? { cancelRemaining: join49.cancelRemaining } : {}
|
|
24394
24413
|
};
|
|
24395
24414
|
return compiled;
|
|
24396
24415
|
}
|
|
@@ -24670,8 +24689,8 @@ var RECORD_LIMIT = 16 * 1024 * 1024;
|
|
|
24670
24689
|
// plugins/kxm/src/prices.ts
|
|
24671
24690
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
24672
24691
|
import { createHash as createHash10 } from "node:crypto";
|
|
24673
|
-
import { existsSync as
|
|
24674
|
-
import { join as
|
|
24692
|
+
import { existsSync as existsSync9, readFileSync as readFileSync8, statSync } from "node:fs";
|
|
24693
|
+
import { join as join9 } from "node:path";
|
|
24675
24694
|
|
|
24676
24695
|
// plugins/kxm/src/price-calc.ts
|
|
24677
24696
|
var PRICES_SCHEMA = "kxm.prices.v1";
|
|
@@ -24823,8 +24842,8 @@ function parsePriceCatalog(text) {
|
|
|
24823
24842
|
return catalog;
|
|
24824
24843
|
}
|
|
24825
24844
|
function loadPriceCatalog(rootOrPath) {
|
|
24826
|
-
const candidatePath =
|
|
24827
|
-
if (!candidatePath || !
|
|
24845
|
+
const candidatePath = existsSync9(join9(rootOrPath, ".kxm", "prices.yaml")) ? join9(rootOrPath, ".kxm", "prices.yaml") : existsSync9(join9(rootOrPath, "prices.yaml")) ? join9(rootOrPath, "prices.yaml") : existsSync9(rootOrPath) && statSync(rootOrPath).isFile() ? rootOrPath : void 0;
|
|
24846
|
+
if (!candidatePath || !existsSync9(candidatePath)) {
|
|
24828
24847
|
return void 0;
|
|
24829
24848
|
}
|
|
24830
24849
|
const content = readFileSync8(candidatePath, "utf8");
|
|
@@ -24848,12 +24867,12 @@ var import_yaml5 = __toESM(require_dist(), 1);
|
|
|
24848
24867
|
|
|
24849
24868
|
// plugins/kxm/src/producers.ts
|
|
24850
24869
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
24851
|
-
import { existsSync as
|
|
24852
|
-
import { join as
|
|
24870
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readdirSync as readdirSync3 } from "node:fs";
|
|
24871
|
+
import { join as join10 } from "node:path";
|
|
24853
24872
|
var empty = () => ({ schema: "kxm.producers.v1", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), promoted: [], demoted: [], enabled: [], disabled: [], roles: {} });
|
|
24854
24873
|
function loadProducerPolicy(root) {
|
|
24855
|
-
const path4 =
|
|
24856
|
-
if (!
|
|
24874
|
+
const path4 = join10(root, ".kxm", "producers.yaml");
|
|
24875
|
+
if (!existsSync10(path4)) return empty();
|
|
24857
24876
|
const value = (0, import_yaml4.parse)(readFileSync9(path4, "utf8"));
|
|
24858
24877
|
if (value?.schema !== "kxm.producers.v1" || !Array.isArray(value.promoted) || !Array.isArray(value.demoted)) throw new Error("invalid .kxm/producers.yaml");
|
|
24859
24878
|
return { schema: "kxm.producers.v1", updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : (/* @__PURE__ */ new Date()).toISOString(), promoted: value.promoted.filter((x2) => typeof x2 === "string"), demoted: value.demoted.filter((x2) => typeof x2 === "string"), enabled: Array.isArray(value.enabled) ? value.enabled.filter((x2) => typeof x2 === "string") : [], disabled: Array.isArray(value.disabled) ? value.disabled.filter((x2) => typeof x2 === "string") : [], roles: value.roles && typeof value.roles === "object" ? Object.fromEntries(Object.entries(value.roles).filter(([, v2]) => Array.isArray(v2)).map(([k, v2]) => [k, v2.filter((x2) => typeof x2 === "string")])) : {} };
|
|
@@ -24864,8 +24883,8 @@ function updateProducer(root, model, status) {
|
|
|
24864
24883
|
policy.demoted = policy.demoted.filter((x2) => x2 !== model);
|
|
24865
24884
|
policy[status].push(model);
|
|
24866
24885
|
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24867
|
-
mkdirSync6(
|
|
24868
|
-
writeFileSync6(
|
|
24886
|
+
mkdirSync6(join10(root, ".kxm"), { recursive: true });
|
|
24887
|
+
writeFileSync6(join10(root, ".kxm", "producers.yaml"), (0, import_yaml4.stringify)(policy), "utf8");
|
|
24869
24888
|
return policy;
|
|
24870
24889
|
}
|
|
24871
24890
|
function setModelState(root, model, state, role, removeRole2 = false) {
|
|
@@ -24875,9 +24894,9 @@ function setModelState(root, model, state, role, removeRole2 = false) {
|
|
|
24875
24894
|
policy[state].push(model);
|
|
24876
24895
|
if (role) {
|
|
24877
24896
|
if (!/^[a-z][a-z0-9_-]{0,63}$/i.test(role)) throw new Error("invalid role id");
|
|
24878
|
-
const rolePath =
|
|
24897
|
+
const rolePath = join10(root, ".kxm", "roles", `${role}.yaml`);
|
|
24879
24898
|
let roleFile = {};
|
|
24880
|
-
if (
|
|
24899
|
+
if (existsSync10(rolePath)) {
|
|
24881
24900
|
const parsed = (0, import_yaml4.parse)(readFileSync9(rolePath, "utf8"));
|
|
24882
24901
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) roleFile = parsed;
|
|
24883
24902
|
}
|
|
@@ -24889,28 +24908,28 @@ function setModelState(root, model, state, role, removeRole2 = false) {
|
|
|
24889
24908
|
roleFile.schema ??= "kxm.role.v1";
|
|
24890
24909
|
roleFile.id ??= role;
|
|
24891
24910
|
roleFile.roster = roster;
|
|
24892
|
-
mkdirSync6(
|
|
24911
|
+
mkdirSync6(join10(root, ".kxm", "roles"), { recursive: true });
|
|
24893
24912
|
writeFileSync6(rolePath, (0, import_yaml4.stringify)(roleFile), "utf8");
|
|
24894
24913
|
}
|
|
24895
24914
|
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24896
|
-
mkdirSync6(
|
|
24897
|
-
writeFileSync6(
|
|
24915
|
+
mkdirSync6(join10(root, ".kxm"), { recursive: true });
|
|
24916
|
+
writeFileSync6(join10(root, ".kxm", "producers.yaml"), (0, import_yaml4.stringify)(policy), "utf8");
|
|
24898
24917
|
return policy;
|
|
24899
24918
|
}
|
|
24900
24919
|
function listRoleBindings(root) {
|
|
24901
|
-
const dir =
|
|
24920
|
+
const dir = join10(root, ".kxm", "roles");
|
|
24902
24921
|
const result = {};
|
|
24903
|
-
if (!
|
|
24922
|
+
if (!existsSync10(dir)) return result;
|
|
24904
24923
|
for (const file of readdirSync3(dir).filter((name) => name.endsWith(".yaml"))) {
|
|
24905
24924
|
const role = file.slice(0, -5);
|
|
24906
|
-
const value = (0, import_yaml4.parse)(readFileSync9(
|
|
24925
|
+
const value = (0, import_yaml4.parse)(readFileSync9(join10(dir, file), "utf8"));
|
|
24907
24926
|
result[role] = (value.roster ?? []).map((entry) => entry.model).filter((model) => typeof model === "string");
|
|
24908
24927
|
}
|
|
24909
24928
|
return result;
|
|
24910
24929
|
}
|
|
24911
24930
|
function listInventoryModels(root) {
|
|
24912
|
-
const path4 =
|
|
24913
|
-
if (!
|
|
24931
|
+
const path4 = join10(root, ".kxm", "models", "inventory.yaml");
|
|
24932
|
+
if (!existsSync10(path4)) return [];
|
|
24914
24933
|
const value = (0, import_yaml4.parse)(readFileSync9(path4, "utf8"));
|
|
24915
24934
|
return (value.models ?? []).map((m2) => m2.id).filter((id) => typeof id === "string");
|
|
24916
24935
|
}
|
|
@@ -25543,9 +25562,8 @@ function formatRoutingReport(report2, options = {}) {
|
|
|
25543
25562
|
}
|
|
25544
25563
|
|
|
25545
25564
|
// plugins/kxm/src/vnext-runtime-supervisor.ts
|
|
25546
|
-
var repoRoot = resolve7(fileURLToPath2(new URL("../../../", import.meta.url)));
|
|
25547
25565
|
function vnextSupervisorTokenFile(paths) {
|
|
25548
|
-
return
|
|
25566
|
+
return join11(paths.runtimeDir, "supervisor.token");
|
|
25549
25567
|
}
|
|
25550
25568
|
function readVnextSupervisorToken(paths) {
|
|
25551
25569
|
const file = vnextSupervisorTokenFile(paths);
|
|
@@ -25568,11 +25586,11 @@ function processAlive(pid) {
|
|
|
25568
25586
|
var HEARTBEAT_STALE_MS = 15e3;
|
|
25569
25587
|
var SUPERVISOR_ERROR_MAX_AGE_MS = 3e4;
|
|
25570
25588
|
function supervisorErrorFile(paths) {
|
|
25571
|
-
return
|
|
25589
|
+
return join11(paths.runtimeDir, "supervisor.error");
|
|
25572
25590
|
}
|
|
25573
25591
|
function clearSupervisorError(paths) {
|
|
25574
25592
|
const file = supervisorErrorFile(paths);
|
|
25575
|
-
if (
|
|
25593
|
+
if (existsSync11(file)) rmSync2(file, { force: true });
|
|
25576
25594
|
}
|
|
25577
25595
|
function readRecentSupervisorError(paths) {
|
|
25578
25596
|
const file = supervisorErrorFile(paths);
|
|
@@ -25587,7 +25605,7 @@ function readRecentSupervisorError(paths) {
|
|
|
25587
25605
|
}
|
|
25588
25606
|
}
|
|
25589
25607
|
function vnextSupervisorStatus(paths) {
|
|
25590
|
-
if (!
|
|
25608
|
+
if (!existsSync11(paths.registryDb)) return { running: false };
|
|
25591
25609
|
const registry = new VnextRuntimeRegistry(paths.registryDb);
|
|
25592
25610
|
try {
|
|
25593
25611
|
const record = registry.supervisor();
|
|
@@ -25648,7 +25666,7 @@ async function ensureVnextSupervisor(options = {}) {
|
|
|
25648
25666
|
throw runtimeError("runtime_supervisor_unreachable", paths.registryDb, `runtime supervisor pid ${status.pid} is registered as running but cannot be probed`);
|
|
25649
25667
|
}
|
|
25650
25668
|
clearSupervisorError(paths);
|
|
25651
|
-
const scriptPath =
|
|
25669
|
+
const scriptPath = join11(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
|
|
25652
25670
|
const spawnImpl = options.spawnImpl ?? ((script, env) => {
|
|
25653
25671
|
const child = spawn2(process.execPath, [script], {
|
|
25654
25672
|
detached: true,
|
|
@@ -25701,8 +25719,7 @@ async function vnextRuntimeRequest(handle, method, path4, body) {
|
|
|
25701
25719
|
|
|
25702
25720
|
// plugins/kxm/src/cli/types.ts
|
|
25703
25721
|
import { spawn as spawn3 } from "node:child_process";
|
|
25704
|
-
import { join as
|
|
25705
|
-
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
25722
|
+
import { join as join14, resolve as resolve8 } from "node:path";
|
|
25706
25723
|
|
|
25707
25724
|
// plugins/kxm/src/redact.ts
|
|
25708
25725
|
var SECRET_PATTERNS = [
|
|
@@ -25733,7 +25750,7 @@ function redactStringList(values, maxItems = 32) {
|
|
|
25733
25750
|
|
|
25734
25751
|
// plugins/kxm/src/telemetry.ts
|
|
25735
25752
|
import { appendFileSync, mkdirSync as mkdirSync8, readFileSync as readFileSync11 } from "node:fs";
|
|
25736
|
-
import { dirname as
|
|
25753
|
+
import { dirname as dirname8, join as join12 } from "node:path";
|
|
25737
25754
|
var TELEMETRY_SCHEMA = "kxm.telemetry.v1";
|
|
25738
25755
|
function inferImprovementTarget(input) {
|
|
25739
25756
|
const explicit = input.env?.KXM_IMPROVE_TARGET?.trim();
|
|
@@ -25743,12 +25760,12 @@ function inferImprovementTarget(input) {
|
|
|
25743
25760
|
return project || workflowId ? "project" : "cli";
|
|
25744
25761
|
}
|
|
25745
25762
|
function appendTelemetry(path4, event) {
|
|
25746
|
-
mkdirSync8(
|
|
25763
|
+
mkdirSync8(dirname8(path4), { recursive: true });
|
|
25747
25764
|
appendFileSync(path4, `${JSON.stringify(event)}
|
|
25748
25765
|
`, { encoding: "utf8", mode: 384 });
|
|
25749
25766
|
}
|
|
25750
25767
|
function telemetryPath(logsDir) {
|
|
25751
|
-
return
|
|
25768
|
+
return join12(logsDir, "telemetry.jsonl");
|
|
25752
25769
|
}
|
|
25753
25770
|
function makeTelemetryEvent(input) {
|
|
25754
25771
|
return {
|
|
@@ -25840,9 +25857,9 @@ function workerResult(worker, payload) {
|
|
|
25840
25857
|
}
|
|
25841
25858
|
|
|
25842
25859
|
// plugins/kxm/src/hub-binding.ts
|
|
25843
|
-
import { existsSync as
|
|
25860
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync12, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
|
|
25844
25861
|
import { homedir as homedir3 } from "node:os";
|
|
25845
|
-
import { dirname as
|
|
25862
|
+
import { dirname as dirname9, isAbsolute as isAbsolute5, join as join13, resolve as resolve7 } from "node:path";
|
|
25846
25863
|
var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
25847
25864
|
var HUB_HEALTH_PROBE_MS = 300;
|
|
25848
25865
|
var HubBindingError = class extends Error {
|
|
@@ -25855,20 +25872,20 @@ function resolveUserStateRoot(env) {
|
|
|
25855
25872
|
const explicit = env.KXM_STATE_HOME?.trim();
|
|
25856
25873
|
if (explicit) {
|
|
25857
25874
|
if (!isAbsolute5(explicit)) throw new HubBindingError("local_state_root_not_absolute");
|
|
25858
|
-
return
|
|
25875
|
+
return resolve7(explicit);
|
|
25859
25876
|
}
|
|
25860
25877
|
if (process.platform === "win32") {
|
|
25861
25878
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
25862
|
-
const base2 = localAppData && isAbsolute5(localAppData) ? localAppData :
|
|
25863
|
-
return
|
|
25879
|
+
const base2 = localAppData && isAbsolute5(localAppData) ? localAppData : join13(homedir3(), "AppData", "Local");
|
|
25880
|
+
return resolve7(base2, "KXM");
|
|
25864
25881
|
}
|
|
25865
|
-
if (process.platform === "darwin") return
|
|
25882
|
+
if (process.platform === "darwin") return resolve7(homedir3(), "Library", "Application Support", "KXM");
|
|
25866
25883
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
25867
|
-
const base = xdgState && isAbsolute5(xdgState) ? xdgState :
|
|
25868
|
-
return
|
|
25884
|
+
const base = xdgState && isAbsolute5(xdgState) ? xdgState : join13(homedir3(), ".local", "state");
|
|
25885
|
+
return resolve7(base, "kxm");
|
|
25869
25886
|
}
|
|
25870
25887
|
function hubBindingFile(env = process.env) {
|
|
25871
|
-
return
|
|
25888
|
+
return join13(resolveUserStateRoot(env), "hub-binding.json");
|
|
25872
25889
|
}
|
|
25873
25890
|
function validateHubUrl(raw) {
|
|
25874
25891
|
let parsed;
|
|
@@ -25893,7 +25910,7 @@ function isAbortError(error) {
|
|
|
25893
25910
|
}
|
|
25894
25911
|
function readHubBinding(env = process.env) {
|
|
25895
25912
|
const file = hubBindingFile(env);
|
|
25896
|
-
if (!
|
|
25913
|
+
if (!existsSync12(file)) return void 0;
|
|
25897
25914
|
let parsed;
|
|
25898
25915
|
try {
|
|
25899
25916
|
parsed = JSON.parse(readFileSync12(file, "utf8"));
|
|
@@ -25918,8 +25935,8 @@ function readHubBinding(env = process.env) {
|
|
|
25918
25935
|
}
|
|
25919
25936
|
function writeHubBinding(record, env = process.env) {
|
|
25920
25937
|
const file = hubBindingFile(env);
|
|
25921
|
-
mkdirSync9(
|
|
25922
|
-
const temporary =
|
|
25938
|
+
mkdirSync9(dirname9(file), { recursive: true, mode: 448 });
|
|
25939
|
+
const temporary = join13(dirname9(file), `.hub-binding-${process.pid}.tmp`);
|
|
25923
25940
|
try {
|
|
25924
25941
|
writeFileSync8(temporary, `${JSON.stringify(record, null, 2)}
|
|
25925
25942
|
`, { encoding: "utf8", mode: 384 });
|
|
@@ -25964,10 +25981,9 @@ async function probeHubHealth(url, fetchImpl, timeoutMs = HUB_HEALTH_PROBE_MS) {
|
|
|
25964
25981
|
}
|
|
25965
25982
|
|
|
25966
25983
|
// plugins/kxm/src/cli/types.ts
|
|
25967
|
-
var repoRoot2 = resolve9(fileURLToPath3(new URL("../../../../", import.meta.url)));
|
|
25968
25984
|
function spawnScript(scriptName, extraEnv = {}) {
|
|
25969
25985
|
return new Promise((resolveExit) => {
|
|
25970
|
-
const child = spawn3(process.execPath, [
|
|
25986
|
+
const child = spawn3(process.execPath, [join14(findKxmRepoRoot(import.meta.url), "scripts", scriptName)], {
|
|
25971
25987
|
stdio: "inherit",
|
|
25972
25988
|
env: { ...process.env, ...extraEnv }
|
|
25973
25989
|
});
|
|
@@ -26051,16 +26067,16 @@ function redactCliValue(value, field = "") {
|
|
|
26051
26067
|
return value;
|
|
26052
26068
|
}
|
|
26053
26069
|
function workspaceDirs(cwd, workspaceFlag, env) {
|
|
26054
|
-
const workdir =
|
|
26055
|
-
const workspace =
|
|
26070
|
+
const workdir = resolve8(env.KXM_WORKDIR?.trim() || cwd);
|
|
26071
|
+
const workspace = resolve8(workdir, workspaceFlag || env.KXM_WORKSPACE_DIR?.trim() || ".kxm");
|
|
26056
26072
|
const derive = workspaceFlag !== void 0;
|
|
26057
26073
|
return {
|
|
26058
26074
|
workdir,
|
|
26059
26075
|
workspace,
|
|
26060
|
-
config: derive ?
|
|
26061
|
-
logs: derive ?
|
|
26062
|
-
assets: derive ?
|
|
26063
|
-
state: derive ?
|
|
26076
|
+
config: derive ? join14(workspace, "config") : resolve8(workdir, env.KXM_CONFIG_DIR?.trim() || join14(workspace, "config")),
|
|
26077
|
+
logs: derive ? join14(workspace, "logs") : resolve8(workdir, env.KXM_LOGS_DIR?.trim() || join14(workspace, "logs")),
|
|
26078
|
+
assets: derive ? join14(workspace, "assets") : resolve8(workdir, env.KXM_ASSETS_DIR?.trim() || join14(workspace, "assets")),
|
|
26079
|
+
state: derive ? join14(workspace, "state") : resolve8(workdir, env.KXM_STATE_DIR?.trim() || join14(workspace, "state"))
|
|
26064
26080
|
};
|
|
26065
26081
|
}
|
|
26066
26082
|
function maskEnvName(name) {
|
|
@@ -26128,20 +26144,20 @@ function workspaceEnv(runtime) {
|
|
|
26128
26144
|
// plugins/kxm/src/cli/roles.ts
|
|
26129
26145
|
var import_yaml8 = __toESM(require_dist(), 1);
|
|
26130
26146
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
26131
|
-
import { existsSync as
|
|
26132
|
-
import { join as
|
|
26147
|
+
import { existsSync as existsSync15, readFileSync as readFileSync15 } from "node:fs";
|
|
26148
|
+
import { join as join17, resolve as resolve11 } from "node:path";
|
|
26133
26149
|
import { createInterface } from "node:readline";
|
|
26134
26150
|
|
|
26135
26151
|
// plugins/kxm/src/role.ts
|
|
26136
26152
|
var import_yaml7 = __toESM(require_dist(), 1);
|
|
26137
|
-
import { existsSync as
|
|
26138
|
-
import { join as
|
|
26153
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync11, readdirSync as readdirSync4, readFileSync as readFileSync14, rmSync as rmSync4, writeFileSync as writeFileSync10 } from "node:fs";
|
|
26154
|
+
import { join as join16 } from "node:path";
|
|
26139
26155
|
|
|
26140
26156
|
// plugins/kxm/src/config.ts
|
|
26141
26157
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
26142
|
-
import { existsSync as
|
|
26158
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "node:fs";
|
|
26143
26159
|
import { homedir as homedir4 } from "node:os";
|
|
26144
|
-
import { dirname as
|
|
26160
|
+
import { dirname as dirname10, join as join15, resolve as resolve9 } from "node:path";
|
|
26145
26161
|
var KXM_CONFIG_SCHEMA = "kxm.config.v1";
|
|
26146
26162
|
var DEFAULT_KXM_CONFIG = {
|
|
26147
26163
|
schema: KXM_CONFIG_SCHEMA,
|
|
@@ -26194,11 +26210,11 @@ var DEFAULT_KXM_CONFIG = {
|
|
|
26194
26210
|
}
|
|
26195
26211
|
};
|
|
26196
26212
|
function userConfigDirectory(overrideDir) {
|
|
26197
|
-
if (overrideDir) return
|
|
26198
|
-
return
|
|
26213
|
+
if (overrideDir) return resolve9(overrideDir);
|
|
26214
|
+
return resolve9(process.env.KXM_USER_CONFIG_DIR?.trim() || join15(homedir4(), ".config", "kxm"));
|
|
26199
26215
|
}
|
|
26200
|
-
function repoConfigDirectory(
|
|
26201
|
-
return
|
|
26216
|
+
function repoConfigDirectory(repoRoot) {
|
|
26217
|
+
return resolve9(repoRoot, ".kxm");
|
|
26202
26218
|
}
|
|
26203
26219
|
function deepMerge(target, source) {
|
|
26204
26220
|
const result = { ...target };
|
|
@@ -26216,14 +26232,14 @@ function normalizeHubConfig(raw) {
|
|
|
26216
26232
|
const autoStart = raw?.autoStart;
|
|
26217
26233
|
return { autoStart: autoStart === "off" || autoStart === "background" ? autoStart : DEFAULT_KXM_CONFIG.hub.autoStart };
|
|
26218
26234
|
}
|
|
26219
|
-
function loadKxmConfig(
|
|
26235
|
+
function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
|
|
26220
26236
|
const userDir = userConfigDirectory(options.userConfigDir);
|
|
26221
|
-
const userConfigFile =
|
|
26222
|
-
const repoDir = repoConfigDirectory(
|
|
26223
|
-
const repoConfigFile =
|
|
26237
|
+
const userConfigFile = join15(userDir, "config.yaml");
|
|
26238
|
+
const repoDir = repoConfigDirectory(repoRoot);
|
|
26239
|
+
const repoConfigFile = join15(repoDir, "config.yaml");
|
|
26224
26240
|
let userRaw = {};
|
|
26225
26241
|
let userLoadedPath;
|
|
26226
|
-
if (
|
|
26242
|
+
if (existsSync13(userConfigFile)) {
|
|
26227
26243
|
try {
|
|
26228
26244
|
const text = readFileSync13(userConfigFile, "utf8");
|
|
26229
26245
|
userRaw = (0, import_yaml6.parse)(text) ?? {};
|
|
@@ -26234,7 +26250,7 @@ function loadKxmConfig(repoRoot6 = process.cwd(), options = {}) {
|
|
|
26234
26250
|
}
|
|
26235
26251
|
let repoRaw = {};
|
|
26236
26252
|
let repoLoadedPath;
|
|
26237
|
-
if (
|
|
26253
|
+
if (existsSync13(repoConfigFile)) {
|
|
26238
26254
|
try {
|
|
26239
26255
|
const text = readFileSync13(repoConfigFile, "utf8");
|
|
26240
26256
|
repoRaw = (0, import_yaml6.parse)(text) ?? {};
|
|
@@ -26271,12 +26287,12 @@ function getKxmConfigValue(config, keyPath) {
|
|
|
26271
26287
|
}
|
|
26272
26288
|
return current;
|
|
26273
26289
|
}
|
|
26274
|
-
function setKxmConfigValue(
|
|
26290
|
+
function setKxmConfigValue(repoRoot, keyPath, value, options = {}) {
|
|
26275
26291
|
const scope = options.scope ?? "project";
|
|
26276
|
-
const targetFile2 = scope === "user" ?
|
|
26277
|
-
mkdirSync10(
|
|
26292
|
+
const targetFile2 = scope === "user" ? join15(userConfigDirectory(options.userConfigDir), "config.yaml") : join15(repoConfigDirectory(repoRoot), "config.yaml");
|
|
26293
|
+
mkdirSync10(dirname10(targetFile2), { recursive: true });
|
|
26278
26294
|
let existing = {};
|
|
26279
|
-
if (
|
|
26295
|
+
if (existsSync13(targetFile2)) {
|
|
26280
26296
|
try {
|
|
26281
26297
|
existing = (0, import_yaml6.parse)(readFileSync13(targetFile2, "utf8")) ?? {};
|
|
26282
26298
|
} catch {
|
|
@@ -26387,21 +26403,21 @@ var DEFAULT_ROLES = {
|
|
|
26387
26403
|
]
|
|
26388
26404
|
}
|
|
26389
26405
|
};
|
|
26390
|
-
function rolesDirectory(scope,
|
|
26406
|
+
function rolesDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
26391
26407
|
if (scope === "global") {
|
|
26392
|
-
return
|
|
26408
|
+
return join16(userConfigDirectory(userConfigDir), "roles");
|
|
26393
26409
|
}
|
|
26394
|
-
return
|
|
26410
|
+
return join16(repoConfigDirectory(repoRoot), "roles");
|
|
26395
26411
|
}
|
|
26396
|
-
function ensureRolesDirectory(scope,
|
|
26397
|
-
const dir = rolesDirectory(scope,
|
|
26398
|
-
if (!
|
|
26412
|
+
function ensureRolesDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
26413
|
+
const dir = rolesDirectory(scope, repoRoot, userConfigDir);
|
|
26414
|
+
if (!existsSync14(dir)) {
|
|
26399
26415
|
mkdirSync11(dir, { recursive: true });
|
|
26400
26416
|
}
|
|
26401
26417
|
return dir;
|
|
26402
26418
|
}
|
|
26403
26419
|
function parseRoleFile(filePath) {
|
|
26404
|
-
if (!
|
|
26420
|
+
if (!existsSync14(filePath)) return void 0;
|
|
26405
26421
|
try {
|
|
26406
26422
|
const raw = readFileSync14(filePath, "utf8");
|
|
26407
26423
|
const parsed = (0, import_yaml7.parse)(raw);
|
|
@@ -26426,14 +26442,14 @@ function parseRoleFile(filePath) {
|
|
|
26426
26442
|
}
|
|
26427
26443
|
function listRoles(options = {}) {
|
|
26428
26444
|
const scopeFilter = options.scope ?? "all";
|
|
26429
|
-
const
|
|
26430
|
-
const globalDir = rolesDirectory("global",
|
|
26431
|
-
const localDir = rolesDirectory("local",
|
|
26445
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26446
|
+
const globalDir = rolesDirectory("global", repoRoot, options.userConfigDir);
|
|
26447
|
+
const localDir = rolesDirectory("local", repoRoot, options.userConfigDir);
|
|
26432
26448
|
const localRoles = /* @__PURE__ */ new Map();
|
|
26433
|
-
if (scopeFilter !== "global" &&
|
|
26449
|
+
if (scopeFilter !== "global" && existsSync14(localDir)) {
|
|
26434
26450
|
for (const entry of readdirSync4(localDir)) {
|
|
26435
26451
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
26436
|
-
const filePath =
|
|
26452
|
+
const filePath = join16(localDir, entry);
|
|
26437
26453
|
const parsed = parseRoleFile(filePath);
|
|
26438
26454
|
if (parsed) {
|
|
26439
26455
|
localRoles.set(parsed.id, { role: parsed, filePath });
|
|
@@ -26442,10 +26458,10 @@ function listRoles(options = {}) {
|
|
|
26442
26458
|
}
|
|
26443
26459
|
}
|
|
26444
26460
|
const globalRoles = /* @__PURE__ */ new Map();
|
|
26445
|
-
if (scopeFilter !== "local" &&
|
|
26461
|
+
if (scopeFilter !== "local" && existsSync14(globalDir)) {
|
|
26446
26462
|
for (const entry of readdirSync4(globalDir)) {
|
|
26447
26463
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
26448
|
-
const filePath =
|
|
26464
|
+
const filePath = join16(globalDir, entry);
|
|
26449
26465
|
const parsed = parseRoleFile(filePath);
|
|
26450
26466
|
if (parsed) {
|
|
26451
26467
|
globalRoles.set(parsed.id, { role: parsed, filePath });
|
|
@@ -26490,16 +26506,16 @@ function listRoles(options = {}) {
|
|
|
26490
26506
|
}
|
|
26491
26507
|
function getRole(roleId, options = {}) {
|
|
26492
26508
|
const scope = options.scope ?? "all";
|
|
26493
|
-
const
|
|
26509
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26494
26510
|
if (scope !== "global") {
|
|
26495
|
-
const localDir = rolesDirectory("local",
|
|
26496
|
-
const localFile =
|
|
26511
|
+
const localDir = rolesDirectory("local", repoRoot, options.userConfigDir);
|
|
26512
|
+
const localFile = join16(localDir, `${roleId}.yaml`);
|
|
26497
26513
|
const parsed = parseRoleFile(localFile);
|
|
26498
26514
|
if (parsed) return { role: parsed, scope: "local", filePath: localFile };
|
|
26499
26515
|
}
|
|
26500
26516
|
if (scope !== "local") {
|
|
26501
|
-
const globalDir = rolesDirectory("global",
|
|
26502
|
-
const globalFile =
|
|
26517
|
+
const globalDir = rolesDirectory("global", repoRoot, options.userConfigDir);
|
|
26518
|
+
const globalFile = join16(globalDir, `${roleId}.yaml`);
|
|
26503
26519
|
const parsed = parseRoleFile(globalFile);
|
|
26504
26520
|
if (parsed) return { role: parsed, scope: "global", filePath: globalFile };
|
|
26505
26521
|
}
|
|
@@ -26507,10 +26523,10 @@ function getRole(roleId, options = {}) {
|
|
|
26507
26523
|
}
|
|
26508
26524
|
function addRole(role, options = {}) {
|
|
26509
26525
|
const scope = options.scope ?? "local";
|
|
26510
|
-
const
|
|
26511
|
-
const dir = ensureRolesDirectory(scope,
|
|
26512
|
-
const filePath =
|
|
26513
|
-
if (
|
|
26526
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26527
|
+
const dir = ensureRolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
26528
|
+
const filePath = join16(dir, `${role.id}.yaml`);
|
|
26529
|
+
if (existsSync14(filePath) && !options.overwrite) {
|
|
26514
26530
|
throw new Error(`role_already_exists: role '${role.id}' already exists at ${filePath}`);
|
|
26515
26531
|
}
|
|
26516
26532
|
writeFileSync10(filePath, (0, import_yaml7.stringify)(role), "utf8");
|
|
@@ -26518,10 +26534,10 @@ function addRole(role, options = {}) {
|
|
|
26518
26534
|
}
|
|
26519
26535
|
function removeRole(roleId, options = {}) {
|
|
26520
26536
|
const scope = options.scope ?? "local";
|
|
26521
|
-
const
|
|
26522
|
-
const dir = rolesDirectory(scope,
|
|
26523
|
-
const filePath =
|
|
26524
|
-
if (!
|
|
26537
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26538
|
+
const dir = rolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
26539
|
+
const filePath = join16(dir, `${roleId}.yaml`);
|
|
26540
|
+
if (!existsSync14(filePath)) {
|
|
26525
26541
|
throw new Error(`role_not_found: role '${roleId}' not found in ${scope} directory (${filePath})`);
|
|
26526
26542
|
}
|
|
26527
26543
|
rmSync4(filePath);
|
|
@@ -26540,9 +26556,9 @@ function modifyRole(roleId, updates, options = {}) {
|
|
|
26540
26556
|
// preserve identity
|
|
26541
26557
|
};
|
|
26542
26558
|
const scope = options.scope ?? target.scope;
|
|
26543
|
-
const
|
|
26544
|
-
const dir = ensureRolesDirectory(scope,
|
|
26545
|
-
const filePath =
|
|
26559
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26560
|
+
const dir = ensureRolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
26561
|
+
const filePath = join16(dir, `${roleId}.yaml`);
|
|
26546
26562
|
writeFileSync10(filePath, (0, import_yaml7.stringify)(updated), "utf8");
|
|
26547
26563
|
return { id: roleId, role: updated, filePath, scope };
|
|
26548
26564
|
}
|
|
@@ -26589,18 +26605,18 @@ var DEFAULT_ROLE_SEATS = {
|
|
|
26589
26605
|
requiredEvidenceKind: "test_run"
|
|
26590
26606
|
}
|
|
26591
26607
|
};
|
|
26592
|
-
function findExistingRoleHostsFile(scope,
|
|
26593
|
-
const dir = scope === "global" ? userConfigDirectory(userConfigDir) : repoConfigDirectory(
|
|
26594
|
-
const yamlPath =
|
|
26595
|
-
const ymlPath =
|
|
26596
|
-
const jsonPath =
|
|
26597
|
-
if (
|
|
26598
|
-
if (
|
|
26599
|
-
if (
|
|
26608
|
+
function findExistingRoleHostsFile(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
26609
|
+
const dir = scope === "global" ? userConfigDirectory(userConfigDir) : repoConfigDirectory(repoRoot);
|
|
26610
|
+
const yamlPath = join16(dir, "role-hosts.yaml");
|
|
26611
|
+
const ymlPath = join16(dir, "role-hosts.yml");
|
|
26612
|
+
const jsonPath = join16(dir, "role-hosts.json");
|
|
26613
|
+
if (existsSync14(yamlPath)) return { filePath: yamlPath, exists: true, format: "yaml" };
|
|
26614
|
+
if (existsSync14(ymlPath)) return { filePath: ymlPath, exists: true, format: "yaml" };
|
|
26615
|
+
if (existsSync14(jsonPath)) return { filePath: jsonPath, exists: true, format: "json" };
|
|
26600
26616
|
return { filePath: yamlPath, exists: false, format: "yaml" };
|
|
26601
26617
|
}
|
|
26602
26618
|
function parseRoleHostsFile(filePath) {
|
|
26603
|
-
if (!
|
|
26619
|
+
if (!existsSync14(filePath)) return void 0;
|
|
26604
26620
|
try {
|
|
26605
26621
|
const raw = readFileSync14(filePath, "utf8");
|
|
26606
26622
|
const parsed = (0, import_yaml7.parse)(raw);
|
|
@@ -26617,11 +26633,11 @@ function parseRoleHostsFile(filePath) {
|
|
|
26617
26633
|
}
|
|
26618
26634
|
function loadRoleHostsConfig(options = {}) {
|
|
26619
26635
|
const scopeFilter = options.scope ?? "all";
|
|
26620
|
-
const
|
|
26636
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26621
26637
|
let localConfig;
|
|
26622
26638
|
let localPath;
|
|
26623
26639
|
if (scopeFilter !== "global") {
|
|
26624
|
-
const localFound = findExistingRoleHostsFile("local",
|
|
26640
|
+
const localFound = findExistingRoleHostsFile("local", repoRoot, options.userConfigDir);
|
|
26625
26641
|
if (localFound.exists) {
|
|
26626
26642
|
localConfig = parseRoleHostsFile(localFound.filePath);
|
|
26627
26643
|
localPath = localFound.filePath;
|
|
@@ -26630,7 +26646,7 @@ function loadRoleHostsConfig(options = {}) {
|
|
|
26630
26646
|
let globalConfig;
|
|
26631
26647
|
let globalPath;
|
|
26632
26648
|
if (scopeFilter !== "local") {
|
|
26633
|
-
const globalFound = findExistingRoleHostsFile("global",
|
|
26649
|
+
const globalFound = findExistingRoleHostsFile("global", repoRoot, options.userConfigDir);
|
|
26634
26650
|
if (globalFound.exists) {
|
|
26635
26651
|
globalConfig = parseRoleHostsFile(globalFound.filePath);
|
|
26636
26652
|
globalPath = globalFound.filePath;
|
|
@@ -26672,13 +26688,13 @@ function loadRoleHostsConfig(options = {}) {
|
|
|
26672
26688
|
}
|
|
26673
26689
|
function saveRoleHostsConfig(config, options = {}) {
|
|
26674
26690
|
const scope = options.scope ?? "local";
|
|
26675
|
-
const
|
|
26676
|
-
const dir = scope === "global" ? userConfigDirectory(options.userConfigDir) : repoConfigDirectory(
|
|
26677
|
-
if (!
|
|
26691
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26692
|
+
const dir = scope === "global" ? userConfigDirectory(options.userConfigDir) : repoConfigDirectory(repoRoot);
|
|
26693
|
+
if (!existsSync14(dir)) {
|
|
26678
26694
|
mkdirSync11(dir, { recursive: true });
|
|
26679
26695
|
}
|
|
26680
26696
|
const format = options.format ?? "yaml";
|
|
26681
|
-
const filePath =
|
|
26697
|
+
const filePath = join16(dir, format === "json" ? "role-hosts.json" : "role-hosts.yaml");
|
|
26682
26698
|
const payload = {
|
|
26683
26699
|
schema: KXM_ROLE_HOSTS_SCHEMA,
|
|
26684
26700
|
seats: config.seats ?? {},
|
|
@@ -26919,7 +26935,7 @@ async function cmdRoleAdd(runtime, roleId, options) {
|
|
|
26919
26935
|
}
|
|
26920
26936
|
let roleDef;
|
|
26921
26937
|
if (options.file) {
|
|
26922
|
-
const filePath =
|
|
26938
|
+
const filePath = resolve11(runtime.cwd, options.file);
|
|
26923
26939
|
const content = readFileSync15(filePath, "utf8");
|
|
26924
26940
|
roleDef = (0, import_yaml8.parse)(content);
|
|
26925
26941
|
roleDef.id = roleId;
|
|
@@ -27219,8 +27235,8 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
27219
27235
|
return 1;
|
|
27220
27236
|
}
|
|
27221
27237
|
}
|
|
27222
|
-
const dbPath =
|
|
27223
|
-
if (
|
|
27238
|
+
const dbPath = join17(runtime.cwd, ".kxm", "state", "kxm.db");
|
|
27239
|
+
if (existsSync15(dbPath)) {
|
|
27224
27240
|
try {
|
|
27225
27241
|
const database = new DatabaseSync(dbPath);
|
|
27226
27242
|
try {
|
|
@@ -27282,12 +27298,12 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
27282
27298
|
|
|
27283
27299
|
// plugins/kxm/src/cli/workflows.ts
|
|
27284
27300
|
import { createHmac as createHmac3, randomUUID as randomUUID7 } from "node:crypto";
|
|
27285
|
-
import { existsSync as
|
|
27286
|
-
import { join as
|
|
27301
|
+
import { existsSync as existsSync17, readFileSync as readFileSync17 } from "node:fs";
|
|
27302
|
+
import { join as join19, resolve as resolve14 } from "node:path";
|
|
27287
27303
|
|
|
27288
27304
|
// plugins/kxm/src/retrospective.ts
|
|
27289
27305
|
import { mkdirSync as mkdirSync12, renameSync as renameSync4, writeFileSync as writeFileSync11 } from "node:fs";
|
|
27290
|
-
import { resolve as
|
|
27306
|
+
import { resolve as resolve12 } from "node:path";
|
|
27291
27307
|
var MAX_RETROSPECTIVE_ENTRIES = 500;
|
|
27292
27308
|
var SAFE_RUN_ID = /^run_[A-Za-z0-9_-]{1,120}$/;
|
|
27293
27309
|
function durationMs(startedAt, completedAt) {
|
|
@@ -27500,9 +27516,9 @@ function renderRetrospectiveMarkdown(doc) {
|
|
|
27500
27516
|
function writeRetrospective(outDir, doc) {
|
|
27501
27517
|
if (!SAFE_RUN_ID.test(doc.runId)) throw new Error("invalid retrospective run id");
|
|
27502
27518
|
mkdirSync12(outDir, { recursive: true });
|
|
27503
|
-
const root =
|
|
27504
|
-
const jsonPath =
|
|
27505
|
-
const mdPath =
|
|
27519
|
+
const root = resolve12(outDir);
|
|
27520
|
+
const jsonPath = resolve12(root, `${doc.runId}.json`);
|
|
27521
|
+
const mdPath = resolve12(root, `${doc.runId}.md`);
|
|
27506
27522
|
const prefix = `${root}${process.platform === "win32" ? "\\" : "/"}`;
|
|
27507
27523
|
if (!jsonPath.startsWith(prefix) || !mdPath.startsWith(prefix)) throw new Error("retrospective path escaped output directory");
|
|
27508
27524
|
const jsonTmp = `${jsonPath}.tmp`;
|
|
@@ -27602,7 +27618,7 @@ async function watchGithubChecks(input) {
|
|
|
27602
27618
|
}
|
|
27603
27619
|
const fetchImpl = input.fetchImpl ?? fetch;
|
|
27604
27620
|
const now = input.now ?? Date.now;
|
|
27605
|
-
const sleep = input.sleep ?? ((ms) => new Promise((
|
|
27621
|
+
const sleep = input.sleep ?? ((ms) => new Promise((resolve30) => setTimeout(resolve30, ms)));
|
|
27606
27622
|
const deadline = now() + input.timeoutMs;
|
|
27607
27623
|
const headers = {
|
|
27608
27624
|
authorization: `Bearer ${token}`,
|
|
@@ -27701,8 +27717,8 @@ async function watchGithubChecks(input) {
|
|
|
27701
27717
|
|
|
27702
27718
|
// plugins/kxm/src/workflow-manager.ts
|
|
27703
27719
|
var import_yaml9 = __toESM(require_dist(), 1);
|
|
27704
|
-
import { existsSync as
|
|
27705
|
-
import { join as
|
|
27720
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync13, readdirSync as readdirSync5, readFileSync as readFileSync16, rmSync as rmSync5, writeFileSync as writeFileSync12 } from "node:fs";
|
|
27721
|
+
import { join as join18 } from "node:path";
|
|
27706
27722
|
var WORKFLOW_TEMPLATES = {
|
|
27707
27723
|
"implement-and-verify": {
|
|
27708
27724
|
schema: "kxm.workflow.v1",
|
|
@@ -27851,21 +27867,21 @@ var WORKFLOW_TEMPLATES = {
|
|
|
27851
27867
|
}
|
|
27852
27868
|
};
|
|
27853
27869
|
var DEFAULT_WORKFLOW_TEMPLATE = WORKFLOW_TEMPLATES["implement-and-verify"];
|
|
27854
|
-
function workflowsDirectory(scope,
|
|
27870
|
+
function workflowsDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
27855
27871
|
if (scope === "global") {
|
|
27856
|
-
return
|
|
27872
|
+
return join18(userConfigDirectory(userConfigDir), "workflows");
|
|
27857
27873
|
}
|
|
27858
|
-
return
|
|
27874
|
+
return join18(repoConfigDirectory(repoRoot), "workflows");
|
|
27859
27875
|
}
|
|
27860
|
-
function ensureWorkflowsDirectory(scope,
|
|
27861
|
-
const dir = workflowsDirectory(scope,
|
|
27862
|
-
if (!
|
|
27876
|
+
function ensureWorkflowsDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
27877
|
+
const dir = workflowsDirectory(scope, repoRoot, userConfigDir);
|
|
27878
|
+
if (!existsSync16(dir)) {
|
|
27863
27879
|
mkdirSync13(dir, { recursive: true });
|
|
27864
27880
|
}
|
|
27865
27881
|
return dir;
|
|
27866
27882
|
}
|
|
27867
27883
|
function parseWorkflowFile(filePath) {
|
|
27868
|
-
if (!
|
|
27884
|
+
if (!existsSync16(filePath)) return void 0;
|
|
27869
27885
|
try {
|
|
27870
27886
|
const raw = readFileSync16(filePath, "utf8");
|
|
27871
27887
|
const parsed = (0, import_yaml9.parse)(raw);
|
|
@@ -27877,14 +27893,14 @@ function parseWorkflowFile(filePath) {
|
|
|
27877
27893
|
}
|
|
27878
27894
|
function listWorkflowDefinitions(options = {}) {
|
|
27879
27895
|
const scopeFilter = options.scope ?? "all";
|
|
27880
|
-
const
|
|
27881
|
-
const globalDir = workflowsDirectory("global",
|
|
27882
|
-
const localDir = workflowsDirectory("local",
|
|
27896
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
27897
|
+
const globalDir = workflowsDirectory("global", repoRoot, options.userConfigDir);
|
|
27898
|
+
const localDir = workflowsDirectory("local", repoRoot, options.userConfigDir);
|
|
27883
27899
|
const localDefs = /* @__PURE__ */ new Map();
|
|
27884
|
-
if (scopeFilter !== "global" &&
|
|
27900
|
+
if (scopeFilter !== "global" && existsSync16(localDir)) {
|
|
27885
27901
|
for (const entry of readdirSync5(localDir)) {
|
|
27886
27902
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
27887
|
-
const filePath =
|
|
27903
|
+
const filePath = join18(localDir, entry);
|
|
27888
27904
|
const def = parseWorkflowFile(filePath);
|
|
27889
27905
|
if (def) {
|
|
27890
27906
|
const id = def.id || entry.replace(/\.ya?ml$/i, "");
|
|
@@ -27894,10 +27910,10 @@ function listWorkflowDefinitions(options = {}) {
|
|
|
27894
27910
|
}
|
|
27895
27911
|
}
|
|
27896
27912
|
const globalDefs = /* @__PURE__ */ new Map();
|
|
27897
|
-
if (scopeFilter !== "local" &&
|
|
27913
|
+
if (scopeFilter !== "local" && existsSync16(globalDir)) {
|
|
27898
27914
|
for (const entry of readdirSync5(globalDir)) {
|
|
27899
27915
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
27900
|
-
const filePath =
|
|
27916
|
+
const filePath = join18(globalDir, entry);
|
|
27901
27917
|
const def = parseWorkflowFile(filePath);
|
|
27902
27918
|
if (def) {
|
|
27903
27919
|
const id = def.id || entry.replace(/\.ya?ml$/i, "");
|
|
@@ -27950,16 +27966,16 @@ function listWorkflowDefinitions(options = {}) {
|
|
|
27950
27966
|
}
|
|
27951
27967
|
function getWorkflowDefinition(workflowId, options = {}) {
|
|
27952
27968
|
const scope = options.scope ?? "all";
|
|
27953
|
-
const
|
|
27969
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
27954
27970
|
if (scope !== "global") {
|
|
27955
|
-
const localDir = workflowsDirectory("local",
|
|
27956
|
-
const localFile =
|
|
27971
|
+
const localDir = workflowsDirectory("local", repoRoot, options.userConfigDir);
|
|
27972
|
+
const localFile = join18(localDir, `${workflowId}.yaml`);
|
|
27957
27973
|
const parsed = parseWorkflowFile(localFile);
|
|
27958
27974
|
if (parsed) return { workflow: parsed, scope: "local", filePath: localFile };
|
|
27959
27975
|
}
|
|
27960
27976
|
if (scope !== "local") {
|
|
27961
|
-
const globalDir = workflowsDirectory("global",
|
|
27962
|
-
const globalFile =
|
|
27977
|
+
const globalDir = workflowsDirectory("global", repoRoot, options.userConfigDir);
|
|
27978
|
+
const globalFile = join18(globalDir, `${workflowId}.yaml`);
|
|
27963
27979
|
const parsed = parseWorkflowFile(globalFile);
|
|
27964
27980
|
if (parsed) return { workflow: parsed, scope: "global", filePath: globalFile };
|
|
27965
27981
|
}
|
|
@@ -27967,10 +27983,10 @@ function getWorkflowDefinition(workflowId, options = {}) {
|
|
|
27967
27983
|
}
|
|
27968
27984
|
function addWorkflowDefinition(workflowId, content = DEFAULT_WORKFLOW_TEMPLATE, options = {}) {
|
|
27969
27985
|
const scope = options.scope ?? "local";
|
|
27970
|
-
const
|
|
27971
|
-
const dir = ensureWorkflowsDirectory(scope,
|
|
27972
|
-
const filePath =
|
|
27973
|
-
if (
|
|
27986
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
27987
|
+
const dir = ensureWorkflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
27988
|
+
const filePath = join18(dir, `${workflowId}.yaml`);
|
|
27989
|
+
if (existsSync16(filePath) && !options.overwrite) {
|
|
27974
27990
|
throw new Error(`workflow_already_exists: workflow '${workflowId}' already exists at ${filePath}`);
|
|
27975
27991
|
}
|
|
27976
27992
|
const payload = typeof content === "string" ? content : (0, import_yaml9.stringify)(content);
|
|
@@ -27979,10 +27995,10 @@ function addWorkflowDefinition(workflowId, content = DEFAULT_WORKFLOW_TEMPLATE,
|
|
|
27979
27995
|
}
|
|
27980
27996
|
function removeWorkflowDefinition(workflowId, options = {}) {
|
|
27981
27997
|
const scope = options.scope ?? "local";
|
|
27982
|
-
const
|
|
27983
|
-
const dir = workflowsDirectory(scope,
|
|
27984
|
-
const filePath =
|
|
27985
|
-
if (!
|
|
27998
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
27999
|
+
const dir = workflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
28000
|
+
const filePath = join18(dir, `${workflowId}.yaml`);
|
|
28001
|
+
if (!existsSync16(filePath)) {
|
|
27986
28002
|
throw new Error(`workflow_not_found: workflow '${workflowId}' not found in ${scope} directory (${filePath})`);
|
|
27987
28003
|
}
|
|
27988
28004
|
rmSync5(filePath);
|
|
@@ -27998,9 +28014,9 @@ function modifyWorkflowDefinition(workflowId, updates, options = {}) {
|
|
|
27998
28014
|
...updates
|
|
27999
28015
|
};
|
|
28000
28016
|
const scope = options.scope ?? target.scope;
|
|
28001
|
-
const
|
|
28002
|
-
const dir = ensureWorkflowsDirectory(scope,
|
|
28003
|
-
const filePath =
|
|
28017
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
28018
|
+
const dir = ensureWorkflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
28019
|
+
const filePath = join18(dir, `${workflowId}.yaml`);
|
|
28004
28020
|
writeFileSync12(filePath, (0, import_yaml9.stringify)(updated), "utf8");
|
|
28005
28021
|
return { id: workflowId, workflow: updated, filePath, scope };
|
|
28006
28022
|
}
|
|
@@ -28008,7 +28024,7 @@ function modifyWorkflowDefinition(workflowId, updates, options = {}) {
|
|
|
28008
28024
|
// plugins/kxm/src/cli/workflows.ts
|
|
28009
28025
|
var CLI_NAME = "kxm";
|
|
28010
28026
|
function localWorkflowSnapshot(dataPath, runId) {
|
|
28011
|
-
if (!
|
|
28027
|
+
if (!existsSync17(dataPath)) throw new Error("state_database_not_found");
|
|
28012
28028
|
const database = new DatabaseSync(dataPath, { readOnly: true });
|
|
28013
28029
|
try {
|
|
28014
28030
|
const rows = runId ? database.prepare("SELECT record FROM workflow_runs WHERE id = ?").all(runId) : database.prepare("SELECT record FROM workflow_runs ORDER BY rowid DESC LIMIT 200").all();
|
|
@@ -28085,7 +28101,7 @@ function activeWorkflowDefinition(runtime, definitionId) {
|
|
|
28085
28101
|
let raw;
|
|
28086
28102
|
if (file) {
|
|
28087
28103
|
try {
|
|
28088
|
-
raw = readFileSync17(
|
|
28104
|
+
raw = readFileSync17(resolve14(runtime.cwd, file), "utf8");
|
|
28089
28105
|
} catch {
|
|
28090
28106
|
throw new Error("workflow definition file is unavailable");
|
|
28091
28107
|
}
|
|
@@ -28166,7 +28182,7 @@ async function cmdWorkflowAdd(runtime, workflowId, options) {
|
|
|
28166
28182
|
}
|
|
28167
28183
|
}
|
|
28168
28184
|
if (options.file) {
|
|
28169
|
-
const filePath =
|
|
28185
|
+
const filePath = resolve14(runtime.cwd, options.file);
|
|
28170
28186
|
content = readFileSync17(filePath, "utf8");
|
|
28171
28187
|
} else if (!content) {
|
|
28172
28188
|
content = {
|
|
@@ -28325,7 +28341,7 @@ async function cmdWorkflowStart(runtime, definitionIdArg, options) {
|
|
|
28325
28341
|
}
|
|
28326
28342
|
let payload;
|
|
28327
28343
|
try {
|
|
28328
|
-
const raw = payloadFlag.startsWith("@") ? readFileSync17(
|
|
28344
|
+
const raw = payloadFlag.startsWith("@") ? readFileSync17(resolve14(runtime.cwd, payloadFlag.slice(1)), "utf8") : payloadFlag;
|
|
28329
28345
|
const value = JSON.parse(raw);
|
|
28330
28346
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("object required");
|
|
28331
28347
|
payload = value;
|
|
@@ -28392,7 +28408,7 @@ async function cmdWorkflowDegrade(runtime, runId, stageId, options) {
|
|
|
28392
28408
|
}
|
|
28393
28409
|
}
|
|
28394
28410
|
async function cmdWorkflowInspect(runtime, action, runId) {
|
|
28395
|
-
const dataPath =
|
|
28411
|
+
const dataPath = resolve14(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join19(runtime.dirs.state, "kxm.db"));
|
|
28396
28412
|
if (action === "get" && !runId) {
|
|
28397
28413
|
runtime.io.stderr(`Usage: ${CLI_NAME} workflow get <runId>
|
|
28398
28414
|
`);
|
|
@@ -28561,14 +28577,14 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28561
28577
|
return 2;
|
|
28562
28578
|
}
|
|
28563
28579
|
const snapshotFlag = String(options.input || "");
|
|
28564
|
-
const snapshotPath = snapshotFlag ?
|
|
28580
|
+
const snapshotPath = snapshotFlag ? resolve14(runtime.cwd, snapshotFlag) : "";
|
|
28565
28581
|
let snapshot;
|
|
28566
28582
|
try {
|
|
28567
28583
|
if (snapshotPath) {
|
|
28568
|
-
if (!
|
|
28584
|
+
if (!existsSync17(snapshotPath)) throw new Error("snapshot_missing");
|
|
28569
28585
|
snapshot = JSON.parse(readFileSync17(snapshotPath, "utf8"));
|
|
28570
28586
|
} else {
|
|
28571
|
-
const dataPath =
|
|
28587
|
+
const dataPath = resolve14(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join19(runtime.dirs.state, "kxm.db"));
|
|
28572
28588
|
const local = localWorkflowSnapshot(dataPath, runId);
|
|
28573
28589
|
if (!local.runs[0]) throw new Error("workflow_not_found");
|
|
28574
28590
|
snapshot = { run: local.runs[0], journal: local.journal };
|
|
@@ -28580,8 +28596,8 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28580
28596
|
return 1;
|
|
28581
28597
|
}
|
|
28582
28598
|
const doc = buildRetrospective(snapshot.run, snapshot.journal);
|
|
28583
|
-
const outDir =
|
|
28584
|
-
const assetsRoot =
|
|
28599
|
+
const outDir = resolve14(runtime.cwd, String(options.outDir || join19(runtime.dirs.assets, "retrospectives")));
|
|
28600
|
+
const assetsRoot = resolve14(runtime.dirs.assets);
|
|
28585
28601
|
const assetsPrefix = `${assetsRoot}${process.platform === "win32" ? "\\" : "/"}`;
|
|
28586
28602
|
if (outDir !== assetsRoot && !outDir.startsWith(assetsPrefix)) {
|
|
28587
28603
|
print(runtime.io, runtime.json, { ok: false, command: "retrospective export", error: "output_outside_workspace_assets" }, "retrospectives must stay under the workspace assets directory");
|
|
@@ -28598,8 +28614,8 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28598
28614
|
|
|
28599
28615
|
// plugins/kxm/src/cli/tasks.ts
|
|
28600
28616
|
var import_yaml13 = __toESM(require_dist(), 1);
|
|
28601
|
-
import { existsSync as
|
|
28602
|
-
import { basename as basename6, join as
|
|
28617
|
+
import { existsSync as existsSync23, readFileSync as readFileSync22, readdirSync as readdirSync8 } from "node:fs";
|
|
28618
|
+
import { basename as basename6, join as join27, resolve as resolve20 } from "node:path";
|
|
28603
28619
|
|
|
28604
28620
|
// plugins/kxm/src/suggest.ts
|
|
28605
28621
|
var WORKFLOW_PATTERNS = [
|
|
@@ -28710,18 +28726,18 @@ function suggestWorkflowAndRoles(prompt, options = {}) {
|
|
|
28710
28726
|
// plugins/kxm/src/task-manager.ts
|
|
28711
28727
|
var import_yaml10 = __toESM(require_dist(), 1);
|
|
28712
28728
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
28713
|
-
import { existsSync as
|
|
28714
|
-
import { join as
|
|
28729
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync14, readFileSync as readFileSync18, readdirSync as readdirSync6, writeFileSync as writeFileSync13 } from "node:fs";
|
|
28730
|
+
import { join as join20, resolve as resolve15 } from "node:path";
|
|
28715
28731
|
var GOAL_SCHEMA = "kxm.goal.v1";
|
|
28716
28732
|
var TASK_SCHEMA = "kxm.task.v1";
|
|
28717
|
-
function goalsDirectory(
|
|
28718
|
-
return
|
|
28733
|
+
function goalsDirectory(repoRoot) {
|
|
28734
|
+
return resolve15(repoRoot, ".kxm", "goals");
|
|
28719
28735
|
}
|
|
28720
|
-
function tasksDirectory(
|
|
28721
|
-
return
|
|
28736
|
+
function tasksDirectory(repoRoot) {
|
|
28737
|
+
return resolve15(repoRoot, ".kxm", "tasks");
|
|
28722
28738
|
}
|
|
28723
|
-
function createGoal(
|
|
28724
|
-
const dir = goalsDirectory(
|
|
28739
|
+
function createGoal(repoRoot, input) {
|
|
28740
|
+
const dir = goalsDirectory(repoRoot);
|
|
28725
28741
|
mkdirSync14(dir, { recursive: true });
|
|
28726
28742
|
const id = `goal_${randomUUID8().replaceAll("-", "").slice(0, 12)}`;
|
|
28727
28743
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -28736,19 +28752,19 @@ function createGoal(repoRoot6, input) {
|
|
|
28736
28752
|
createdAt: now,
|
|
28737
28753
|
updatedAt: now
|
|
28738
28754
|
};
|
|
28739
|
-
const filePath =
|
|
28755
|
+
const filePath = join20(dir, `${id}.yaml`);
|
|
28740
28756
|
writeFileSync13(filePath, (0, import_yaml10.stringify)(record).trim() + "\n", "utf8");
|
|
28741
28757
|
return record;
|
|
28742
28758
|
}
|
|
28743
|
-
function listGoals(
|
|
28744
|
-
const dir = goalsDirectory(
|
|
28745
|
-
if (!
|
|
28759
|
+
function listGoals(repoRoot) {
|
|
28760
|
+
const dir = goalsDirectory(repoRoot);
|
|
28761
|
+
if (!existsSync18(dir)) return [];
|
|
28746
28762
|
const goals = [];
|
|
28747
28763
|
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
28748
28764
|
for (const entry of entries) {
|
|
28749
28765
|
if (entry.isFile() && (entry.name.endsWith(".yaml") || entry.name.endsWith(".yml"))) {
|
|
28750
28766
|
try {
|
|
28751
|
-
const text = readFileSync18(
|
|
28767
|
+
const text = readFileSync18(join20(dir, entry.name), "utf8");
|
|
28752
28768
|
const doc = (0, import_yaml10.parse)(text);
|
|
28753
28769
|
if (doc && doc.schema === GOAL_SCHEMA) goals.push(doc);
|
|
28754
28770
|
} catch {
|
|
@@ -28757,8 +28773,8 @@ function listGoals(repoRoot6) {
|
|
|
28757
28773
|
}
|
|
28758
28774
|
return goals.sort((a, b2) => a.createdAt.localeCompare(b2.createdAt));
|
|
28759
28775
|
}
|
|
28760
|
-
function createTask(
|
|
28761
|
-
const dir = tasksDirectory(
|
|
28776
|
+
function createTask(repoRoot, input) {
|
|
28777
|
+
const dir = tasksDirectory(repoRoot);
|
|
28762
28778
|
mkdirSync14(dir, { recursive: true });
|
|
28763
28779
|
const id = `task_${randomUUID8().replaceAll("-", "").slice(0, 12)}`;
|
|
28764
28780
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -28781,19 +28797,19 @@ function createTask(repoRoot6, input) {
|
|
|
28781
28797
|
createdAt: now,
|
|
28782
28798
|
updatedAt: now
|
|
28783
28799
|
};
|
|
28784
|
-
const filePath =
|
|
28800
|
+
const filePath = join20(dir, `${id}.yaml`);
|
|
28785
28801
|
writeFileSync13(filePath, (0, import_yaml10.stringify)(record).trim() + "\n", "utf8");
|
|
28786
28802
|
return record;
|
|
28787
28803
|
}
|
|
28788
|
-
function listTasks(
|
|
28789
|
-
const dir = tasksDirectory(
|
|
28790
|
-
if (!
|
|
28804
|
+
function listTasks(repoRoot, options = {}) {
|
|
28805
|
+
const dir = tasksDirectory(repoRoot);
|
|
28806
|
+
if (!existsSync18(dir)) return [];
|
|
28791
28807
|
const tasks = [];
|
|
28792
28808
|
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
28793
28809
|
for (const entry of entries) {
|
|
28794
28810
|
if (entry.isFile() && (entry.name.endsWith(".yaml") || entry.name.endsWith(".yml"))) {
|
|
28795
28811
|
try {
|
|
28796
|
-
const text = readFileSync18(
|
|
28812
|
+
const text = readFileSync18(join20(dir, entry.name), "utf8");
|
|
28797
28813
|
const doc = (0, import_yaml10.parse)(text);
|
|
28798
28814
|
if (doc && doc.schema === TASK_SCHEMA) {
|
|
28799
28815
|
if (options.goalId && doc.goalId !== options.goalId) continue;
|
|
@@ -28806,10 +28822,10 @@ function listTasks(repoRoot6, options = {}) {
|
|
|
28806
28822
|
}
|
|
28807
28823
|
return tasks.sort((a, b2) => a.createdAt.localeCompare(b2.createdAt));
|
|
28808
28824
|
}
|
|
28809
|
-
function getTask(
|
|
28810
|
-
const dir = tasksDirectory(
|
|
28811
|
-
const filePath =
|
|
28812
|
-
if (!
|
|
28825
|
+
function getTask(repoRoot, taskId) {
|
|
28826
|
+
const dir = tasksDirectory(repoRoot);
|
|
28827
|
+
const filePath = join20(dir, `${taskId}.yaml`);
|
|
28828
|
+
if (!existsSync18(filePath)) return void 0;
|
|
28813
28829
|
try {
|
|
28814
28830
|
const text = readFileSync18(filePath, "utf8");
|
|
28815
28831
|
const doc = (0, import_yaml10.parse)(text);
|
|
@@ -28818,20 +28834,20 @@ function getTask(repoRoot6, taskId) {
|
|
|
28818
28834
|
return void 0;
|
|
28819
28835
|
}
|
|
28820
28836
|
}
|
|
28821
|
-
function updateTaskStatus(
|
|
28822
|
-
const task = getTask(
|
|
28837
|
+
function updateTaskStatus(repoRoot, taskId, status, options = {}) {
|
|
28838
|
+
const task = getTask(repoRoot, taskId);
|
|
28823
28839
|
if (!task) {
|
|
28824
28840
|
throw new Error(`Task ${taskId} not found`);
|
|
28825
28841
|
}
|
|
28826
28842
|
task.status = status;
|
|
28827
28843
|
if (options.workflowRunId) task.workflowRunId = options.workflowRunId;
|
|
28828
28844
|
task.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
28829
|
-
const filePath =
|
|
28845
|
+
const filePath = join20(tasksDirectory(repoRoot), `${taskId}.yaml`);
|
|
28830
28846
|
writeFileSync13(filePath, (0, import_yaml10.stringify)(task).trim() + "\n", "utf8");
|
|
28831
28847
|
return task;
|
|
28832
28848
|
}
|
|
28833
|
-
function syncTaskWithTracker(
|
|
28834
|
-
const task = getTask(
|
|
28849
|
+
function syncTaskWithTracker(repoRoot, taskId, options = {}) {
|
|
28850
|
+
const task = getTask(repoRoot, taskId);
|
|
28835
28851
|
if (!task) {
|
|
28836
28852
|
throw new Error(`Task ${taskId} not found`);
|
|
28837
28853
|
}
|
|
@@ -28842,7 +28858,7 @@ function syncTaskWithTracker(repoRoot6, taskId, options = {}) {
|
|
|
28842
28858
|
task.trackerSync.syncStatus = "synced";
|
|
28843
28859
|
task.trackerSync.lastSyncedAt = now;
|
|
28844
28860
|
task.updatedAt = now;
|
|
28845
|
-
const filePath =
|
|
28861
|
+
const filePath = join20(tasksDirectory(repoRoot), `${taskId}.yaml`);
|
|
28846
28862
|
writeFileSync13(filePath, (0, import_yaml10.stringify)(task).trim() + "\n", "utf8");
|
|
28847
28863
|
return task;
|
|
28848
28864
|
}
|
|
@@ -29609,14 +29625,13 @@ function createStudioServer(options = {}) {
|
|
|
29609
29625
|
}
|
|
29610
29626
|
|
|
29611
29627
|
// plugins/kxm/src/cli/vnext.ts
|
|
29612
|
-
import { join as
|
|
29628
|
+
import { join as join26, resolve as resolve19 } from "node:path";
|
|
29613
29629
|
import { createInterface as createInterface2 } from "node:readline";
|
|
29614
|
-
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
29615
29630
|
|
|
29616
29631
|
// plugins/kxm/src/model-inventory.ts
|
|
29617
29632
|
var import_yaml11 = __toESM(require_dist(), 1);
|
|
29618
29633
|
import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync14 } from "node:fs";
|
|
29619
|
-
import { join as
|
|
29634
|
+
import { join as join21 } from "node:path";
|
|
29620
29635
|
var OR_URL = "https://openrouter.ai/api/v1/models";
|
|
29621
29636
|
var NOUS_URL = "https://inference-api.nousresearch.com/v1/models";
|
|
29622
29637
|
function price(value) {
|
|
@@ -29702,22 +29717,22 @@ async function refreshModelInventory(options) {
|
|
|
29702
29717
|
sources.nous = { url: nousUrl, ok: !nous.error, ...nous.error ? { error: nous.error } : {} };
|
|
29703
29718
|
for (const item of nous.data) add(item, "nous", "discount");
|
|
29704
29719
|
const inventory = { schema: "kxm.model-inventory.v1", fetchedAt, currency: "USD", sources, models: [...byId.values()].sort((a, b2) => a.id.localeCompare(b2.id)) };
|
|
29705
|
-
mkdirSync15(
|
|
29706
|
-
writeFileSync14(
|
|
29720
|
+
mkdirSync15(join21(options.outputRoot, ".kxm", "models"), { recursive: true });
|
|
29721
|
+
writeFileSync14(join21(options.outputRoot, ".kxm", "models", "inventory.yaml"), (0, import_yaml11.stringify)(inventory), "utf8");
|
|
29707
29722
|
return inventory;
|
|
29708
29723
|
}
|
|
29709
29724
|
|
|
29710
29725
|
// plugins/kxm/src/vnext-init.ts
|
|
29711
29726
|
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
29712
|
-
import { existsSync as
|
|
29713
|
-
import { basename as basename5, join as
|
|
29727
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
29728
|
+
import { basename as basename5, join as join24 } from "node:path";
|
|
29714
29729
|
|
|
29715
29730
|
// plugins/kxm/src/vnext-repair.ts
|
|
29716
29731
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
29717
29732
|
import {
|
|
29718
29733
|
chmodSync as chmodSync5,
|
|
29719
29734
|
closeSync as closeSync2,
|
|
29720
|
-
existsSync as
|
|
29735
|
+
existsSync as existsSync20,
|
|
29721
29736
|
fsyncSync as fsyncSync2,
|
|
29722
29737
|
linkSync,
|
|
29723
29738
|
lstatSync as lstatSync7,
|
|
@@ -29729,14 +29744,14 @@ import {
|
|
|
29729
29744
|
rmSync as rmSync7,
|
|
29730
29745
|
writeFileSync as writeFileSync16
|
|
29731
29746
|
} from "node:fs";
|
|
29732
|
-
import { dirname as
|
|
29747
|
+
import { dirname as dirname14, isAbsolute as isAbsolute6, join as join23, relative as relative4, resolve as resolve17 } from "node:path";
|
|
29733
29748
|
|
|
29734
29749
|
// plugins/kxm/src/vnext-permission.ts
|
|
29735
29750
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
29736
29751
|
import { createHash as createHash12 } from "node:crypto";
|
|
29737
|
-
import { existsSync as
|
|
29752
|
+
import { existsSync as existsSync19, mkdtempSync, mkdirSync as mkdirSync16, readFileSync as readFileSync19, rmSync as rmSync6, writeFileSync as writeFileSync15 } from "node:fs";
|
|
29738
29753
|
import { tmpdir } from "node:os";
|
|
29739
|
-
import { dirname as
|
|
29754
|
+
import { dirname as dirname13, join as join22, resolve as resolve16, sep as sep3 } from "node:path";
|
|
29740
29755
|
var PROSE_FIELDS = {
|
|
29741
29756
|
project: /* @__PURE__ */ new Set(["name", "description"]),
|
|
29742
29757
|
repository: /* @__PURE__ */ new Set(["description"]),
|
|
@@ -30257,8 +30272,8 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30257
30272
|
const tree = resolveTreeRevision(root, revision);
|
|
30258
30273
|
const listing = gitBuffer(root, ["ls-tree", "-r", "-z", "--name-only", tree]).toString("utf8");
|
|
30259
30274
|
const paths = listing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
30260
|
-
const shadow = mkdtempSync(
|
|
30261
|
-
const shadowResolved =
|
|
30275
|
+
const shadow = mkdtempSync(join22(tmpdir(), "kxm-permission-base-"));
|
|
30276
|
+
const shadowResolved = resolve16(shadow);
|
|
30262
30277
|
const shadowMembersDir = `.kxm-shadow-members-${createHash12("sha256").update(shadowResolved, "utf8").digest("hex").slice(0, 8)}`;
|
|
30263
30278
|
try {
|
|
30264
30279
|
for (const path4 of paths) {
|
|
@@ -30271,8 +30286,8 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30271
30286
|
message: "Git tree entry contains a traversal or non-portable segment"
|
|
30272
30287
|
}]);
|
|
30273
30288
|
}
|
|
30274
|
-
const absolute =
|
|
30275
|
-
const resolved =
|
|
30289
|
+
const absolute = join22(shadowResolved, ...segments);
|
|
30290
|
+
const resolved = resolve16(absolute);
|
|
30276
30291
|
if (!resolved.startsWith(`${shadowResolved}${sep3}`)) {
|
|
30277
30292
|
throw new VnextConfigError([{
|
|
30278
30293
|
phase: "path",
|
|
@@ -30282,11 +30297,11 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30282
30297
|
}]);
|
|
30283
30298
|
}
|
|
30284
30299
|
const content = gitBuffer(root, ["cat-file", "blob", `${tree}:${path4}`]);
|
|
30285
|
-
mkdirSync16(
|
|
30300
|
+
mkdirSync16(dirname13(absolute), { recursive: true });
|
|
30286
30301
|
writeFileSync15(absolute, content);
|
|
30287
30302
|
}
|
|
30288
30303
|
initShadowGitRoot(shadowResolved);
|
|
30289
|
-
const baseProjectFile =
|
|
30304
|
+
const baseProjectFile = join22(shadowResolved, ".kxm", "project.yaml");
|
|
30290
30305
|
let baseProject;
|
|
30291
30306
|
try {
|
|
30292
30307
|
baseProject = loadBaseProjectDeclarations(baseProjectFile);
|
|
@@ -30316,8 +30331,8 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30316
30331
|
}]);
|
|
30317
30332
|
}
|
|
30318
30333
|
const boundPath = options.repositoryBindings?.[member.repositoryId];
|
|
30319
|
-
const memberWorktree = boundPath ?
|
|
30320
|
-
if (!memberWorktree || !
|
|
30334
|
+
const memberWorktree = boundPath ? resolve16(boundPath) : member.pathHint ? resolve16(root, ...member.pathHint.split("/")) : void 0;
|
|
30335
|
+
if (!memberWorktree || !existsSync19(memberWorktree)) {
|
|
30321
30336
|
if (member.required === false) continue;
|
|
30322
30337
|
throw new VnextConfigError([{
|
|
30323
30338
|
phase: "discovery",
|
|
@@ -30364,8 +30379,8 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30364
30379
|
const memberTree = git(memberWorktree, ["rev-parse", "--verify", "--quiet", `${pinnedCommit}^{tree}`]).trim();
|
|
30365
30380
|
const memberListing = gitBuffer(memberWorktree, ["ls-tree", "-r", "-z", "--name-only", memberTree]).toString("utf8");
|
|
30366
30381
|
const memberPaths = memberListing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
30367
|
-
const memberShadowRoot =
|
|
30368
|
-
if (!
|
|
30382
|
+
const memberShadowRoot = join22(shadowResolved, shadowMembersDir, member.repositoryId);
|
|
30383
|
+
if (!resolve16(memberShadowRoot).startsWith(`${resolve16(shadowResolved, shadowMembersDir)}${sep3}`)) {
|
|
30369
30384
|
throw new VnextConfigError([{
|
|
30370
30385
|
phase: "path",
|
|
30371
30386
|
code: "git_tree_path_invalid",
|
|
@@ -30378,13 +30393,13 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30378
30393
|
if (segments.some((segment) => segment === "" || segment === "." || segment === ".." || /[\\:]/.test(segment))) {
|
|
30379
30394
|
throw new VnextConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path4, message: "member Git tree entry contains a traversal or non-portable segment" }]);
|
|
30380
30395
|
}
|
|
30381
|
-
const absolute =
|
|
30382
|
-
const resolved =
|
|
30383
|
-
if (!resolved.startsWith(`${
|
|
30396
|
+
const absolute = join22(memberShadowRoot, ...segments);
|
|
30397
|
+
const resolved = resolve16(absolute);
|
|
30398
|
+
if (!resolved.startsWith(`${resolve16(memberShadowRoot)}${sep3}`)) {
|
|
30384
30399
|
throw new VnextConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path4, message: "member Git tree entry escapes the shadow root" }]);
|
|
30385
30400
|
}
|
|
30386
30401
|
const content = gitBuffer(memberWorktree, ["cat-file", "blob", `${memberTree}:${path4}`]);
|
|
30387
|
-
mkdirSync16(
|
|
30402
|
+
mkdirSync16(dirname13(absolute), { recursive: true });
|
|
30388
30403
|
writeFileSync15(absolute, content);
|
|
30389
30404
|
}
|
|
30390
30405
|
initShadowGitRoot(memberShadowRoot);
|
|
@@ -30406,7 +30421,7 @@ function portableMemberPathHint(pathHint) {
|
|
|
30406
30421
|
return pathHint !== "." && vnextPortablePath(pathHint);
|
|
30407
30422
|
}
|
|
30408
30423
|
function loadBaseProjectDeclarations(projectFile) {
|
|
30409
|
-
if (!
|
|
30424
|
+
if (!existsSync19(projectFile)) return [];
|
|
30410
30425
|
const value = parseRestrictedYaml2(readFileSync19(projectFile, "utf8"), ".kxm/project.yaml");
|
|
30411
30426
|
const repositories = Array.isArray(value?.repositories) ? value.repositories : [];
|
|
30412
30427
|
const members = [];
|
|
@@ -30510,7 +30525,7 @@ function writeDurableNew(file, bytes, mode) {
|
|
|
30510
30525
|
} finally {
|
|
30511
30526
|
if (descriptor !== void 0) closeSync2(descriptor);
|
|
30512
30527
|
}
|
|
30513
|
-
syncDirectory2(
|
|
30528
|
+
syncDirectory2(dirname14(file));
|
|
30514
30529
|
}
|
|
30515
30530
|
function writeDurable(file, bytes, mode) {
|
|
30516
30531
|
let descriptor;
|
|
@@ -30527,27 +30542,27 @@ function writeDurable(file, bytes, mode) {
|
|
|
30527
30542
|
} finally {
|
|
30528
30543
|
if (descriptor !== void 0) closeSync2(descriptor);
|
|
30529
30544
|
}
|
|
30530
|
-
syncDirectory2(
|
|
30545
|
+
syncDirectory2(dirname14(file));
|
|
30531
30546
|
}
|
|
30532
30547
|
function sameHostPath3(left, right) {
|
|
30533
|
-
const first =
|
|
30534
|
-
const second =
|
|
30548
|
+
const first = resolve17(left);
|
|
30549
|
+
const second = resolve17(right);
|
|
30535
30550
|
return process.platform === "win32" ? first.toLocaleLowerCase("en-US") === second.toLocaleLowerCase("en-US") : first === second;
|
|
30536
30551
|
}
|
|
30537
30552
|
function transactionRoot(projectRoot) {
|
|
30538
|
-
return
|
|
30553
|
+
return join23(resolve17(projectRoot), TRANSACTION_NAME);
|
|
30539
30554
|
}
|
|
30540
30555
|
function operationFile(projectRoot) {
|
|
30541
|
-
return
|
|
30556
|
+
return join23(transactionRoot(projectRoot), OPERATION_FILE);
|
|
30542
30557
|
}
|
|
30543
30558
|
function targetFile(projectRoot, portablePath2) {
|
|
30544
|
-
return
|
|
30559
|
+
return join23(transactionRoot(projectRoot), "targets", ...portablePath2.split("/"));
|
|
30545
30560
|
}
|
|
30546
30561
|
function shadowRoot(projectRoot) {
|
|
30547
|
-
return
|
|
30562
|
+
return join23(transactionRoot(projectRoot), "shadow");
|
|
30548
30563
|
}
|
|
30549
30564
|
function backupFile(projectRoot, portablePath2) {
|
|
30550
|
-
return
|
|
30565
|
+
return join23(transactionRoot(projectRoot), "backups", ...portablePath2.split("/"));
|
|
30551
30566
|
}
|
|
30552
30567
|
function portableManagedPath(path4) {
|
|
30553
30568
|
return path4.startsWith(".kxm/") && path4 !== VNEXT_TEMPLATE_PROVENANCE_PATH && path4.length <= 1024 && !path4.includes("\\") && !isAbsolute6(path4) && PORTABLE_PATH.test(path4) && !/[<>:"|?*]/.test(path4);
|
|
@@ -30559,21 +30574,21 @@ function readRegularBounded(file, label) {
|
|
|
30559
30574
|
return readFileSync20(file);
|
|
30560
30575
|
}
|
|
30561
30576
|
function readOptionalManaged(projectRoot, path4) {
|
|
30562
|
-
const file =
|
|
30563
|
-
if (!
|
|
30564
|
-
let parent =
|
|
30565
|
-
const boundary =
|
|
30577
|
+
const file = join23(projectRoot, ...path4.split("/"));
|
|
30578
|
+
if (!existsSync20(file)) return void 0;
|
|
30579
|
+
let parent = dirname14(file);
|
|
30580
|
+
const boundary = resolve17(projectRoot);
|
|
30566
30581
|
while (parent !== boundary) {
|
|
30567
30582
|
const stat = lstatSync7(parent);
|
|
30568
30583
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_parent_invalid", path4, "managed file parents must be regular directories", "path");
|
|
30569
|
-
parent =
|
|
30584
|
+
parent = dirname14(parent);
|
|
30570
30585
|
}
|
|
30571
30586
|
return readRegularBounded(file, path4);
|
|
30572
30587
|
}
|
|
30573
30588
|
function readProjectAndProvenance(projectRoot, schemasDir) {
|
|
30574
|
-
const projectFile =
|
|
30575
|
-
const provenanceFile =
|
|
30576
|
-
if (!
|
|
30589
|
+
const projectFile = join23(projectRoot, ".kxm", "project.yaml");
|
|
30590
|
+
const provenanceFile = join23(projectRoot, ...VNEXT_TEMPLATE_PROVENANCE_PATH.split("/"));
|
|
30591
|
+
if (!existsSync20(projectFile) || !existsSync20(provenanceFile)) return void 0;
|
|
30577
30592
|
const projectBytes = readOptionalManaged(projectRoot, ".kxm/project.yaml");
|
|
30578
30593
|
const provenanceBytes = readOptionalManaged(projectRoot, VNEXT_TEMPLATE_PROVENANCE_PATH);
|
|
30579
30594
|
if (!projectBytes || !provenanceBytes) return void 0;
|
|
@@ -30609,7 +30624,7 @@ function readProjectAndProvenance(projectRoot, schemasDir) {
|
|
|
30609
30624
|
}
|
|
30610
30625
|
function planVnextTemplateRepair(projectRoot, options = {}) {
|
|
30611
30626
|
assertNoRegisteredGates(options);
|
|
30612
|
-
const root =
|
|
30627
|
+
const root = resolve17(projectRoot);
|
|
30613
30628
|
const source = readProjectAndProvenance(root, options.schemasDir);
|
|
30614
30629
|
if (!source) return void 0;
|
|
30615
30630
|
const target = renderVnextTemplate(
|
|
@@ -30737,7 +30752,7 @@ function operationPlanSha(operation) {
|
|
|
30737
30752
|
function writeOperation(projectRoot, operation) {
|
|
30738
30753
|
const root = transactionRoot(projectRoot);
|
|
30739
30754
|
const file = operationFile(projectRoot);
|
|
30740
|
-
const temporary =
|
|
30755
|
+
const temporary = join23(root, `.operation-${operation.operationId}-${randomUUID10()}.tmp`);
|
|
30741
30756
|
try {
|
|
30742
30757
|
writeDurableNew(temporary, Buffer.from(`${JSON.stringify(operation, null, 2)}
|
|
30743
30758
|
`, "utf8"), 384);
|
|
@@ -30754,11 +30769,11 @@ function updatePhase(projectRoot, operation, phase) {
|
|
|
30754
30769
|
}
|
|
30755
30770
|
function readOperation(projectRoot, schemasDir) {
|
|
30756
30771
|
const root = transactionRoot(projectRoot);
|
|
30757
|
-
if (!
|
|
30772
|
+
if (!existsSync20(root)) return void 0;
|
|
30758
30773
|
const stat = lstatSync7(root);
|
|
30759
30774
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("init_transaction_invalid", TRANSACTION_NAME, "initialization transaction must be a regular directory", "path");
|
|
30760
30775
|
const file = operationFile(projectRoot);
|
|
30761
|
-
if (!
|
|
30776
|
+
if (!existsSync20(file)) {
|
|
30762
30777
|
const entries = readdirSync7(root, { withFileTypes: true });
|
|
30763
30778
|
const recoverable = entries.every((entry) => entry.isFile() && /^\.operation-op_[a-f0-9]{32}-[a-f0-9-]{36}\.tmp$/.test(entry.name));
|
|
30764
30779
|
if (recoverable) return void 0;
|
|
@@ -30786,15 +30801,15 @@ function readOperation(projectRoot, schemasDir) {
|
|
|
30786
30801
|
return operation;
|
|
30787
30802
|
}
|
|
30788
30803
|
function hasVnextInitTransaction(projectRoot) {
|
|
30789
|
-
return
|
|
30804
|
+
return existsSync20(transactionRoot(projectRoot));
|
|
30790
30805
|
}
|
|
30791
30806
|
function readTarget(projectRoot, path4) {
|
|
30792
|
-
return readOptionalManaged(
|
|
30807
|
+
return readOptionalManaged(join23(transactionRoot(projectRoot), "targets"), path4);
|
|
30793
30808
|
}
|
|
30794
30809
|
function writeTarget(projectRoot, path4, bytes) {
|
|
30795
30810
|
if (bytes.byteLength > MAX_MANAGED_FILE_BYTES) fail3("template_target_too_large", path4, `target exceeds ${MAX_MANAGED_FILE_BYTES} bytes`);
|
|
30796
30811
|
const file = targetFile(projectRoot, path4);
|
|
30797
|
-
mkdirSync17(
|
|
30812
|
+
mkdirSync17(dirname14(file), { recursive: true, mode: 448 });
|
|
30798
30813
|
writeDurableNew(file, bytes, 384);
|
|
30799
30814
|
}
|
|
30800
30815
|
function writeAndVerifyBackups(projectRoot, operation) {
|
|
@@ -30806,7 +30821,7 @@ function writeAndVerifyBackups(projectRoot, operation) {
|
|
|
30806
30821
|
fail3("repair_preimage_changed", entry.path, "destination changed before transaction preparation; local bytes were preserved");
|
|
30807
30822
|
}
|
|
30808
30823
|
const file = backupFile(projectRoot, entry.path);
|
|
30809
|
-
mkdirSync17(
|
|
30824
|
+
mkdirSync17(dirname14(file), { recursive: true, mode: 448 });
|
|
30810
30825
|
writeDurableNew(file, current, 384);
|
|
30811
30826
|
}
|
|
30812
30827
|
}
|
|
@@ -30821,7 +30836,7 @@ function writeKnownBackups(projectRoot, operation) {
|
|
|
30821
30836
|
fail3("init_transaction_backup_source_invalid", entry.path, "supported source template cannot reproduce the pinned preimage");
|
|
30822
30837
|
}
|
|
30823
30838
|
const file = backupFile(projectRoot, entry.path);
|
|
30824
|
-
mkdirSync17(
|
|
30839
|
+
mkdirSync17(dirname14(file), { recursive: true, mode: 448 });
|
|
30825
30840
|
writeDurableNew(file, bytes, 384);
|
|
30826
30841
|
}
|
|
30827
30842
|
}
|
|
@@ -30829,7 +30844,7 @@ function verifyBackups(projectRoot, operation) {
|
|
|
30829
30844
|
if (operation.kind !== "repair") return;
|
|
30830
30845
|
for (const entry of operation.files) {
|
|
30831
30846
|
if (entry.observedSha256 === null) continue;
|
|
30832
|
-
const bytes = readOptionalManaged(
|
|
30847
|
+
const bytes = readOptionalManaged(join23(transactionRoot(projectRoot), "backups"), entry.path);
|
|
30833
30848
|
if (!bytes || vnextContentSha256(bytes) !== entry.observedSha256) {
|
|
30834
30849
|
fail3("init_transaction_backup_invalid", entry.path, "pinned preimage backup is missing or corrupt");
|
|
30835
30850
|
}
|
|
@@ -30863,10 +30878,10 @@ function sourceConfigFiles(projectRoot) {
|
|
|
30863
30878
|
".kxm/repo/repo.yaml",
|
|
30864
30879
|
".kxm/repo/env.yaml"
|
|
30865
30880
|
];
|
|
30866
|
-
const files = fixed.filter((path4) =>
|
|
30881
|
+
const files = fixed.filter((path4) => existsSync20(join23(projectRoot, ...path4.split("/"))));
|
|
30867
30882
|
for (const directory of ["agents", "models", "workflows"]) {
|
|
30868
|
-
const absolute =
|
|
30869
|
-
if (!
|
|
30883
|
+
const absolute = join23(projectRoot, ".kxm", directory);
|
|
30884
|
+
if (!existsSync20(absolute)) continue;
|
|
30870
30885
|
const stat = lstatSync7(absolute);
|
|
30871
30886
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_directory_invalid", `.kxm/${directory}`, "configuration directory must be regular", "path");
|
|
30872
30887
|
for (const entry of readdirSync7(absolute, { withFileTypes: true })) {
|
|
@@ -30887,8 +30902,8 @@ function absoluteMemberBindings(projectRoot, project, explicit = {}) {
|
|
|
30887
30902
|
const repository = candidate;
|
|
30888
30903
|
if (repository.role !== "member" || typeof repository.id !== "string" || Object.hasOwn(bindings, repository.id)) continue;
|
|
30889
30904
|
if (typeof repository.pathHint === "string") {
|
|
30890
|
-
const candidate2 =
|
|
30891
|
-
if (
|
|
30905
|
+
const candidate2 = resolve17(projectRoot, ...repository.pathHint.split("/"));
|
|
30906
|
+
if (existsSync20(candidate2)) bindings[repository.id] = candidate2;
|
|
30892
30907
|
}
|
|
30893
30908
|
}
|
|
30894
30909
|
return bindings;
|
|
@@ -30902,9 +30917,9 @@ function prepareShadow(projectRoot, operation, options) {
|
|
|
30902
30917
|
const bytes = readOptionalManaged(projectRoot, path4);
|
|
30903
30918
|
if (!bytes) fail3("repair_snapshot_file_missing", path4, "configuration changed during shadow preparation");
|
|
30904
30919
|
total += bytes.byteLength;
|
|
30905
|
-
const source =
|
|
30906
|
-
const destination =
|
|
30907
|
-
mkdirSync17(
|
|
30920
|
+
const source = join23(projectRoot, ...path4.split("/"));
|
|
30921
|
+
const destination = join23(shadow, ...path4.split("/"));
|
|
30922
|
+
mkdirSync17(dirname14(destination), { recursive: true, mode: 448 });
|
|
30908
30923
|
writeDurableNew(destination, bytes, lstatSync7(source).mode & 511);
|
|
30909
30924
|
if (total > MAX_MANAGED_TOTAL_BYTES) fail3("repair_snapshot_too_large", ".kxm", `configuration snapshot exceeds ${MAX_MANAGED_TOTAL_BYTES} bytes`, "parse");
|
|
30910
30925
|
}
|
|
@@ -30912,12 +30927,12 @@ function prepareShadow(projectRoot, operation, options) {
|
|
|
30912
30927
|
for (const entry of operation.files) {
|
|
30913
30928
|
const bytes = readTarget(projectRoot, entry.path);
|
|
30914
30929
|
if (!bytes) fail3("init_transaction_target_missing", entry.path, "pinned target artifact is missing");
|
|
30915
|
-
const destination =
|
|
30916
|
-
mkdirSync17(
|
|
30917
|
-
const mode =
|
|
30930
|
+
const destination = join23(shadow, ...entry.path.split("/"));
|
|
30931
|
+
mkdirSync17(dirname14(destination), { recursive: true, mode: 448 });
|
|
30932
|
+
const mode = existsSync20(destination) ? lstatSync7(destination).mode & 511 : 420;
|
|
30918
30933
|
writeDurable(destination, bytes, mode);
|
|
30919
30934
|
}
|
|
30920
|
-
const project = parseRestrictedYaml2(readFileSync20(
|
|
30935
|
+
const project = parseRestrictedYaml2(readFileSync20(join23(shadow, ".kxm", "project.yaml")), ".kxm/project.yaml");
|
|
30921
30936
|
const bound = absoluteMemberBindings(projectRoot, project, options.repositoryBindings);
|
|
30922
30937
|
loadVnextProject(shadow, { ...loaderOptions(options), repositoryBindings: bound });
|
|
30923
30938
|
const provenance = readProjectAndProvenance(shadow, options.schemasDir)?.provenance;
|
|
@@ -30926,7 +30941,7 @@ function prepareShadow(projectRoot, operation, options) {
|
|
|
30926
30941
|
}
|
|
30927
30942
|
}
|
|
30928
30943
|
function createOperation(projectRoot, kind, rendered, files, sourceTemplateRevision) {
|
|
30929
|
-
const root =
|
|
30944
|
+
const root = resolve17(projectRoot);
|
|
30930
30945
|
const operationWithoutHash = {
|
|
30931
30946
|
schema: "kxm.init-operation.v1",
|
|
30932
30947
|
operationId: `op_${randomUUID10().replaceAll("-", "")}`,
|
|
@@ -30955,7 +30970,7 @@ function prepareOperation(projectRoot, operation, rendered, options) {
|
|
|
30955
30970
|
const transaction = transactionRoot(projectRoot);
|
|
30956
30971
|
validateOperationRecord(operation, options.schemasDir);
|
|
30957
30972
|
validateOperationIntent(projectRoot, operation);
|
|
30958
|
-
if (
|
|
30973
|
+
if (existsSync20(transaction)) fail3("init_transaction_exists", TRANSACTION_NAME, "an initialization transaction already exists and must be resumed");
|
|
30959
30974
|
mkdirSync17(transaction, { mode: 448 });
|
|
30960
30975
|
syncDirectory2(projectRoot);
|
|
30961
30976
|
writeOperation(projectRoot, operation);
|
|
@@ -30977,25 +30992,25 @@ function prepareOperation(projectRoot, operation, rendered, options) {
|
|
|
30977
30992
|
}
|
|
30978
30993
|
}
|
|
30979
30994
|
function ensureDestinationParents(projectRoot, path4) {
|
|
30980
|
-
const boundary =
|
|
30995
|
+
const boundary = resolve17(projectRoot);
|
|
30981
30996
|
const segments = path4.split("/").slice(0, -1);
|
|
30982
30997
|
let current = boundary;
|
|
30983
30998
|
for (const segment of segments) {
|
|
30984
|
-
current =
|
|
30985
|
-
if (!
|
|
30999
|
+
current = join23(current, segment);
|
|
31000
|
+
if (!existsSync20(current)) mkdirSync17(current, { mode: 448 });
|
|
30986
31001
|
const stat = lstatSync7(current);
|
|
30987
31002
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_destination_parent_invalid", path4, "destination parent must be a regular directory", "path");
|
|
30988
31003
|
}
|
|
30989
31004
|
}
|
|
30990
31005
|
function destinationSha(projectRoot, path4) {
|
|
30991
|
-
const file =
|
|
30992
|
-
if (!
|
|
31006
|
+
const file = join23(projectRoot, ...path4.split("/"));
|
|
31007
|
+
if (!existsSync20(file)) return void 0;
|
|
30993
31008
|
return vnextContentSha256(readRegularBounded(file, path4));
|
|
30994
31009
|
}
|
|
30995
31010
|
function requireConditionalLinkSupport(directory, operationId, path4) {
|
|
30996
31011
|
const nonce = randomUUID10();
|
|
30997
|
-
const source =
|
|
30998
|
-
const target =
|
|
31012
|
+
const source = join23(directory, `.kxm-repair-${operationId}-${nonce}.link-source`);
|
|
31013
|
+
const target = join23(directory, `.kxm-repair-${operationId}-${nonce}.link-target`);
|
|
30999
31014
|
try {
|
|
31000
31015
|
writeDurableNew(source, Buffer.from("kxm-link-probe\n", "utf8"), 384);
|
|
31001
31016
|
try {
|
|
@@ -31010,19 +31025,19 @@ function requireConditionalLinkSupport(directory, operationId, path4) {
|
|
|
31010
31025
|
}
|
|
31011
31026
|
}
|
|
31012
31027
|
function atomicInstallTarget(projectRoot, operation, entry) {
|
|
31013
|
-
const destination =
|
|
31028
|
+
const destination = join23(projectRoot, ...entry.path.split("/"));
|
|
31014
31029
|
ensureDestinationParents(projectRoot, entry.path);
|
|
31015
|
-
const directory =
|
|
31030
|
+
const directory = dirname14(destination);
|
|
31016
31031
|
const temporaryPrefix = `.kxm-repair-${operation.operationId}-`;
|
|
31017
31032
|
const pathKey = vnextContentSha256(entry.path).slice("sha256:".length, "sha256:".length + 16);
|
|
31018
|
-
const displaced =
|
|
31019
|
-
if (
|
|
31033
|
+
const displaced = join23(directory, `${temporaryPrefix}${pathKey}.preimage`);
|
|
31034
|
+
if (existsSync20(displaced)) {
|
|
31020
31035
|
const stat = lstatSync7(displaced);
|
|
31021
31036
|
if (stat.isSymbolicLink() || !stat.isFile()) fail3("repair_preimage_temporary_invalid", entry.path, "stale displaced preimage is not a regular file", "path");
|
|
31022
31037
|
if (entry.observedSha256 === null || vnextContentSha256(readFileSync20(displaced)) !== entry.observedSha256) {
|
|
31023
31038
|
fail3("repair_preimage_temporary_mismatch", entry.path, "stale displaced preimage does not match the pinned operation");
|
|
31024
31039
|
}
|
|
31025
|
-
if (!
|
|
31040
|
+
if (!existsSync20(destination)) {
|
|
31026
31041
|
try {
|
|
31027
31042
|
linkSync(displaced, destination);
|
|
31028
31043
|
} catch {
|
|
@@ -31037,7 +31052,7 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31037
31052
|
const owned = candidate.name.startsWith(temporaryPrefix) && (candidate.name.endsWith(".tmp") || candidate.name.endsWith(".link-source") || candidate.name.endsWith(".link-target"));
|
|
31038
31053
|
if (!owned) continue;
|
|
31039
31054
|
if (!candidate.isFile()) fail3("repair_temporary_invalid", entry.path, "stale operation temporary is not a regular file", "path");
|
|
31040
|
-
rmSync7(
|
|
31055
|
+
rmSync7(join23(directory, candidate.name), { force: true });
|
|
31041
31056
|
}
|
|
31042
31057
|
const current = destinationSha(projectRoot, entry.path);
|
|
31043
31058
|
if (current === entry.targetSha256) return;
|
|
@@ -31047,15 +31062,15 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31047
31062
|
requireConditionalLinkSupport(directory, operation.operationId, entry.path);
|
|
31048
31063
|
const bytes = readTarget(projectRoot, entry.path);
|
|
31049
31064
|
if (!bytes) fail3("init_transaction_target_missing", entry.path, "pinned target artifact is missing");
|
|
31050
|
-
const temporary =
|
|
31051
|
-
const mode =
|
|
31065
|
+
const temporary = join23(directory, `${temporaryPrefix}${randomUUID10()}.tmp`);
|
|
31066
|
+
const mode = existsSync20(destination) ? lstatSync7(destination).mode & 511 : 420;
|
|
31052
31067
|
try {
|
|
31053
31068
|
writeDurableNew(temporary, bytes, mode);
|
|
31054
31069
|
if (entry.observedSha256 !== null) {
|
|
31055
31070
|
renameSync5(destination, displaced);
|
|
31056
31071
|
syncDirectory2(directory);
|
|
31057
31072
|
if (vnextContentSha256(readFileSync20(displaced)) !== entry.observedSha256) {
|
|
31058
|
-
if (!
|
|
31073
|
+
if (!existsSync20(destination)) {
|
|
31059
31074
|
try {
|
|
31060
31075
|
linkSync(displaced, destination);
|
|
31061
31076
|
} catch {
|
|
@@ -31071,7 +31086,7 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31071
31086
|
try {
|
|
31072
31087
|
linkSync(temporary, destination);
|
|
31073
31088
|
} catch {
|
|
31074
|
-
if (!
|
|
31089
|
+
if (!existsSync20(destination) && existsSync20(displaced)) {
|
|
31075
31090
|
try {
|
|
31076
31091
|
linkSync(displaced, destination);
|
|
31077
31092
|
} catch {
|
|
@@ -31093,12 +31108,12 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31093
31108
|
if (destinationSha(projectRoot, entry.path) !== entry.targetSha256) fail3("repair_install_verification_failed", entry.path, "installed target hash does not match the pinned operation");
|
|
31094
31109
|
}
|
|
31095
31110
|
function installedCreateMatches(projectRoot, operation) {
|
|
31096
|
-
const configRoot =
|
|
31097
|
-
if (!
|
|
31111
|
+
const configRoot = join23(projectRoot, ".kxm");
|
|
31112
|
+
if (!existsSync20(configRoot)) return false;
|
|
31098
31113
|
const actual = [];
|
|
31099
31114
|
const visit2 = (directory) => {
|
|
31100
31115
|
for (const entry of readdirSync7(directory, { withFileTypes: true })) {
|
|
31101
|
-
const absolute =
|
|
31116
|
+
const absolute = join23(directory, entry.name);
|
|
31102
31117
|
if (entry.isSymbolicLink()) fail3("create_resume_link", relativeConfigPath(projectRoot, absolute), "created configuration must not contain links", "path");
|
|
31103
31118
|
if (entry.isDirectory()) visit2(absolute);
|
|
31104
31119
|
else if (entry.isFile()) actual.push(relativeConfigPath(projectRoot, absolute));
|
|
@@ -31111,15 +31126,15 @@ function installedCreateMatches(projectRoot, operation) {
|
|
|
31111
31126
|
return actual.length === expected.length && actual.every((path4, index) => path4 === expected[index]) && operation.files.every((entry) => destinationSha(projectRoot, entry.path) === entry.targetSha256);
|
|
31112
31127
|
}
|
|
31113
31128
|
function relativeConfigPath(projectRoot, file) {
|
|
31114
|
-
return relative4(
|
|
31129
|
+
return relative4(resolve17(projectRoot), file).replaceAll("\\", "/");
|
|
31115
31130
|
}
|
|
31116
31131
|
function syncTreeDirectories(root) {
|
|
31117
|
-
if (!
|
|
31132
|
+
if (!existsSync20(root)) return;
|
|
31118
31133
|
const directories = [];
|
|
31119
31134
|
const visit2 = (directory) => {
|
|
31120
31135
|
directories.push(directory);
|
|
31121
31136
|
for (const entry of readdirSync7(directory, { withFileTypes: true })) {
|
|
31122
|
-
if (entry.isDirectory()) visit2(
|
|
31137
|
+
if (entry.isDirectory()) visit2(join23(directory, entry.name));
|
|
31123
31138
|
}
|
|
31124
31139
|
};
|
|
31125
31140
|
visit2(root);
|
|
@@ -31133,7 +31148,7 @@ function rebuildCreateShadow(projectRoot, operation, options) {
|
|
|
31133
31148
|
if (stat.isSymbolicLink() || !stat.isDirectory() || !installedCreateMatches(shadow, operation)) {
|
|
31134
31149
|
fail3("create_shadow_invalid", TRANSACTION_NAME, "reconstructed create shadow does not exactly match pinned target files", "path");
|
|
31135
31150
|
}
|
|
31136
|
-
syncTreeDirectories(
|
|
31151
|
+
syncTreeDirectories(join23(shadow, ".kxm"));
|
|
31137
31152
|
}
|
|
31138
31153
|
function applyOperation(projectRoot, original, options, resumed) {
|
|
31139
31154
|
assertNoRegisteredGates(options);
|
|
@@ -31143,10 +31158,10 @@ function applyOperation(projectRoot, original, options, resumed) {
|
|
|
31143
31158
|
verifyBackups(projectRoot, operation);
|
|
31144
31159
|
operation = updatePhase(projectRoot, operation, "applying");
|
|
31145
31160
|
if (operation.kind === "create") {
|
|
31146
|
-
const destination =
|
|
31147
|
-
if (!
|
|
31161
|
+
const destination = join23(projectRoot, ".kxm");
|
|
31162
|
+
if (!existsSync20(destination)) {
|
|
31148
31163
|
rebuildCreateShadow(projectRoot, operation, effectiveOptions);
|
|
31149
|
-
renameSync5(
|
|
31164
|
+
renameSync5(join23(shadowRoot(projectRoot), ".kxm"), destination);
|
|
31150
31165
|
syncDirectory2(projectRoot);
|
|
31151
31166
|
} else if (!installedCreateMatches(projectRoot, operation)) {
|
|
31152
31167
|
fail3("create_resume_conflict", ".kxm", "existing project configuration does not match the pinned create operation");
|
|
@@ -31173,7 +31188,7 @@ function applyOperation(projectRoot, original, options, resumed) {
|
|
|
31173
31188
|
operation = updatePhase(projectRoot, operation, "verified");
|
|
31174
31189
|
if (options.testFaultAt === "verified") throw new Error("injected init fault after verification");
|
|
31175
31190
|
const files = operation.files.map((entry) => entry.path);
|
|
31176
|
-
syncTreeDirectories(
|
|
31191
|
+
syncTreeDirectories(join23(projectRoot, ".kxm"));
|
|
31177
31192
|
return { kind: operation.kind, resumed, bundle, files };
|
|
31178
31193
|
}
|
|
31179
31194
|
function prepareAndApplyVnextCreate(projectRoot, rendered, options = {}) {
|
|
@@ -31288,7 +31303,7 @@ function finishPreparingOperation(projectRoot, operation, options) {
|
|
|
31288
31303
|
const rendered = rendererForOperation(operation);
|
|
31289
31304
|
if (!rendered) fail3("init_transaction_renderer_unavailable", TRANSACTION_NAME, "this binary cannot reproduce the pinned pre-application target");
|
|
31290
31305
|
for (const directory of ["targets", "backups", "shadow"]) {
|
|
31291
|
-
rmSync7(
|
|
31306
|
+
rmSync7(join23(transactionRoot(projectRoot), directory), { recursive: true, force: true });
|
|
31292
31307
|
}
|
|
31293
31308
|
for (const entry of operation.files) {
|
|
31294
31309
|
const bytes = rendered.files.get(entry.path);
|
|
@@ -31307,7 +31322,7 @@ function resumeVnextInitTransaction(projectRoot, options = {}) {
|
|
|
31307
31322
|
let operation = readOperation(projectRoot, options.schemasDir);
|
|
31308
31323
|
if (!operation) {
|
|
31309
31324
|
const root = transactionRoot(projectRoot);
|
|
31310
|
-
if (
|
|
31325
|
+
if (existsSync20(root)) {
|
|
31311
31326
|
rmSync7(root, { recursive: true, force: true });
|
|
31312
31327
|
syncDirectory2(projectRoot);
|
|
31313
31328
|
}
|
|
@@ -31323,7 +31338,7 @@ function commitVnextInitTransaction(projectRoot, schemasDir) {
|
|
|
31323
31338
|
fail3("init_transaction_not_verified", TRANSACTION_NAME, "initialization transaction cannot commit before installed state is verified");
|
|
31324
31339
|
}
|
|
31325
31340
|
const transaction = transactionRoot(projectRoot);
|
|
31326
|
-
const retired =
|
|
31341
|
+
const retired = join23(projectRoot, `${TRANSACTION_NAME}-cleanup-${operation.operationId}-${randomUUID10()}`);
|
|
31327
31342
|
renameSync5(transaction, retired);
|
|
31328
31343
|
syncDirectory2(projectRoot);
|
|
31329
31344
|
rmSync7(retired, { recursive: true, force: true });
|
|
@@ -31432,7 +31447,7 @@ function validateBindingIdentities(bundle, persisted, explicit) {
|
|
|
31432
31447
|
}
|
|
31433
31448
|
function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock) {
|
|
31434
31449
|
const storeOptions = bindingStoreOptions(options);
|
|
31435
|
-
const persisted =
|
|
31450
|
+
const persisted = existsSync21(join24(gitRoot, ".kxm", "project.yaml")) ? readVnextLocalBindings(gitRoot, storeOptions) : void 0;
|
|
31436
31451
|
const repositoryBindings = Object.fromEntries([
|
|
31437
31452
|
...Object.entries(persisted?.repositories ?? {}),
|
|
31438
31453
|
...Object.entries(options.repositoryBindings ?? {})
|
|
@@ -31621,7 +31636,7 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31621
31636
|
const files = [...rendered.files.keys()];
|
|
31622
31637
|
if (options.dryRun) return { action: "planned", plan, projectRoot: gitRoot, files };
|
|
31623
31638
|
if (!mutationLock) throw new Error("project mutation lock is required to create configuration");
|
|
31624
|
-
if (
|
|
31639
|
+
if (existsSync21(join24(gitRoot, ".kxm"))) {
|
|
31625
31640
|
throw new VnextConfigError([initIssue("workspace_changed", ".kxm", "workspace changed after planning; existing .kxm state was not overwritten")]);
|
|
31626
31641
|
}
|
|
31627
31642
|
const created = prepareAndApplyVnextCreate(gitRoot, rendered, transactionOptions);
|
|
@@ -31653,8 +31668,8 @@ function initializeVnextProject(start = process.cwd(), options = {}) {
|
|
|
31653
31668
|
// plugins/kxm/src/vnext-migrate.ts
|
|
31654
31669
|
var import_yaml12 = __toESM(require_dist(), 1);
|
|
31655
31670
|
import { createHash as createHash13 } from "node:crypto";
|
|
31656
|
-
import { chmodSync as chmodSync6, closeSync as closeSync3, existsSync as
|
|
31657
|
-
import { join as
|
|
31671
|
+
import { chmodSync as chmodSync6, closeSync as closeSync3, existsSync as existsSync22, fsyncSync as fsyncSync3, lstatSync as lstatSync8, mkdirSync as mkdirSync18, openSync as openSync3, readFileSync as readFileSync21, renameSync as renameSync6, rmSync as rmSync8, writeFileSync as writeFileSync17 } from "node:fs";
|
|
31672
|
+
import { join as join25 } from "node:path";
|
|
31658
31673
|
var MAX_LEGACY_JSON_BYTES = 1024 * 1024;
|
|
31659
31674
|
var MAX_LEGACY_JSON_DEPTH = 32;
|
|
31660
31675
|
var MAX_LEGACY_JSON_NODES = 32768;
|
|
@@ -31823,7 +31838,7 @@ function readVnextLegacySources(root) {
|
|
|
31823
31838
|
throw new VnextConfigError([migrateIssue("discovery", "legacy_source_limit", ".kxm/config", `legacy configuration exceeds ${MAX_LEGACY_SOURCES} files`)]);
|
|
31824
31839
|
}
|
|
31825
31840
|
return files.map((path4) => {
|
|
31826
|
-
const absolute =
|
|
31841
|
+
const absolute = join25(root, ...path4.split("/"));
|
|
31827
31842
|
const stat = lstatSync8(absolute);
|
|
31828
31843
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
31829
31844
|
throw new VnextConfigError([migrateIssue("path", "legacy_source_invalid", path4, "legacy configuration must be a regular file, not a link")]);
|
|
@@ -32901,7 +32916,7 @@ function planVnextMigration(projectRoot, options = {}) {
|
|
|
32901
32916
|
};
|
|
32902
32917
|
}
|
|
32903
32918
|
function readVnextMigrationDecisions(path4, schemasDir) {
|
|
32904
|
-
if (!
|
|
32919
|
+
if (!existsSync22(path4)) {
|
|
32905
32920
|
throw new VnextConfigError([migrateIssue("discovery", "decisions_missing", path4, "migration decisions file does not exist")]);
|
|
32906
32921
|
}
|
|
32907
32922
|
const registry = new VnextSchemaRegistry(schemasDir);
|
|
@@ -32944,9 +32959,9 @@ function writeDurable2(path4, content) {
|
|
|
32944
32959
|
chmodSync6(path4, 384);
|
|
32945
32960
|
} catch {
|
|
32946
32961
|
}
|
|
32947
|
-
syncDirectory3(
|
|
32962
|
+
syncDirectory3(join25(path4, ".."));
|
|
32948
32963
|
} finally {
|
|
32949
|
-
if (created &&
|
|
32964
|
+
if (created && existsSync22(temp)) rmSync8(temp, { force: true });
|
|
32950
32965
|
}
|
|
32951
32966
|
}
|
|
32952
32967
|
function applyVnextMigration(projectRoot, options = {}) {
|
|
@@ -32956,8 +32971,8 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
32956
32971
|
...options.schemasDir === void 0 ? {} : { schemasDir: options.schemasDir }
|
|
32957
32972
|
};
|
|
32958
32973
|
const execute = (lock) => {
|
|
32959
|
-
const receiptAbsolute =
|
|
32960
|
-
if (
|
|
32974
|
+
const receiptAbsolute = join25(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
|
|
32975
|
+
if (existsSync22(receiptAbsolute)) {
|
|
32961
32976
|
const stat = lstatSync8(receiptAbsolute);
|
|
32962
32977
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
32963
32978
|
throw new VnextConfigError([migrateIssue("path", "migration_receipt_invalid", VNEXT_MIGRATION_RECEIPT_PATH, "migration receipt must be a regular file, not a link")]);
|
|
@@ -33010,7 +33025,7 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33010
33025
|
return { action: "planned", projectRoot: root, files: [], plan: first.plan };
|
|
33011
33026
|
}
|
|
33012
33027
|
const files = [...first.resources.entries()].sort(([left], [right]) => compareCodeUnits6(left, right)).map(([path4, value]) => ({ path: path4, bytes: Buffer.from((0, import_yaml12.stringify)(value, { lineWidth: 0 }), "utf8") }));
|
|
33013
|
-
const collisions = files.filter((file) =>
|
|
33028
|
+
const collisions = files.filter((file) => existsSync22(join25(root, ...file.path.split("/"))));
|
|
33014
33029
|
if (collisions.length > 0) {
|
|
33015
33030
|
throw new VnextConfigError(collisions.map((file) => migrateIssue("semantic", "migration_target_exists", file.path, "target resource already exists; refusing to overwrite")));
|
|
33016
33031
|
}
|
|
@@ -33019,8 +33034,8 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33019
33034
|
const segments = file.path.split("/");
|
|
33020
33035
|
let current = root;
|
|
33021
33036
|
for (const segment of segments.slice(0, -1)) {
|
|
33022
|
-
current =
|
|
33023
|
-
if (!
|
|
33037
|
+
current = join25(current, segment);
|
|
33038
|
+
if (!existsSync22(current)) continue;
|
|
33024
33039
|
const stat = lstatSync8(current);
|
|
33025
33040
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
33026
33041
|
parentIssues.push(migrateIssue("path", "migration_target_parent_invalid", file.path, `migration target parent ${segment} must be a regular directory, not a link`));
|
|
@@ -33036,8 +33051,8 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33036
33051
|
const written = [];
|
|
33037
33052
|
try {
|
|
33038
33053
|
for (const file of files) {
|
|
33039
|
-
const absolute =
|
|
33040
|
-
mkdirSync18(
|
|
33054
|
+
const absolute = join25(root, ...file.path.split("/"));
|
|
33055
|
+
mkdirSync18(join25(absolute, ".."), { recursive: true });
|
|
33041
33056
|
written.push(absolute);
|
|
33042
33057
|
writeDurable2(absolute, file.bytes);
|
|
33043
33058
|
}
|
|
@@ -33083,8 +33098,8 @@ ${bundle.configRevision}`).slice(7, 39)}`,
|
|
|
33083
33098
|
}
|
|
33084
33099
|
function verifyVnextMigration(projectRoot, options = {}) {
|
|
33085
33100
|
const root = migrationGitRoot(projectRoot);
|
|
33086
|
-
const receiptAbsolute =
|
|
33087
|
-
if (!
|
|
33101
|
+
const receiptAbsolute = join25(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
|
|
33102
|
+
if (!existsSync22(receiptAbsolute)) {
|
|
33088
33103
|
return {
|
|
33089
33104
|
ok: false,
|
|
33090
33105
|
projectRoot: root,
|
|
@@ -33132,7 +33147,6 @@ function verifyVnextMigration(projectRoot, options = {}) {
|
|
|
33132
33147
|
|
|
33133
33148
|
// plugins/kxm/src/cli/vnext.ts
|
|
33134
33149
|
var vnextDriveCliSeams = {};
|
|
33135
|
-
var repoRoot3 = resolve20(fileURLToPath4(new URL("../../../../", import.meta.url)));
|
|
33136
33150
|
function initPlanPayload(plan) {
|
|
33137
33151
|
return {
|
|
33138
33152
|
mode: plan.mode,
|
|
@@ -33382,7 +33396,7 @@ async function cmdBackup(runtime, options) {
|
|
|
33382
33396
|
try {
|
|
33383
33397
|
const { manifest, outDir } = createBackup({
|
|
33384
33398
|
projectRoot: runtime.cwd,
|
|
33385
|
-
...options.out ? { outDir:
|
|
33399
|
+
...options.out ? { outDir: resolve19(runtime.cwd, options.out) } : {}
|
|
33386
33400
|
});
|
|
33387
33401
|
const payload = {
|
|
33388
33402
|
ok: true,
|
|
@@ -33394,7 +33408,7 @@ async function cmdBackup(runtime, options) {
|
|
|
33394
33408
|
const summary = [
|
|
33395
33409
|
`Created SQLite backup with ${manifest.stores.length} store(s):`,
|
|
33396
33410
|
...manifest.stores.map((s) => ` - ${s.storeId}: ${s.sourcePath} -> ${s.backupFile} (schema v${s.schemaVersion}, ${s.bytes} bytes, sha256 ${s.sha256.slice(0, 12)}...)`),
|
|
33397
|
-
`Manifest: ${
|
|
33411
|
+
`Manifest: ${join26(outDir, "manifest.json")}`
|
|
33398
33412
|
].join("\n");
|
|
33399
33413
|
print(runtime.io, runtime.json, payload, summary);
|
|
33400
33414
|
return 0;
|
|
@@ -33409,7 +33423,7 @@ async function cmdBackup(runtime, options) {
|
|
|
33409
33423
|
}
|
|
33410
33424
|
async function cmdRestore(runtime, manifestArg) {
|
|
33411
33425
|
try {
|
|
33412
|
-
const result = restoreBackup(
|
|
33426
|
+
const result = restoreBackup(resolve19(runtime.cwd, manifestArg), {
|
|
33413
33427
|
projectRoot: runtime.cwd
|
|
33414
33428
|
});
|
|
33415
33429
|
const payload = {
|
|
@@ -33669,7 +33683,7 @@ async function selectProducerModel(runtime, requested) {
|
|
|
33669
33683
|
if (runtime.json || !process.stdin.isTTY || models.length === 0) return void 0;
|
|
33670
33684
|
runtime.io.stdout(models.slice(0, 100).map((model, index2) => `${index2 + 1}. ${model}`).join("\n") + "\nSelect model number: ");
|
|
33671
33685
|
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
33672
|
-
const answer = await new Promise((
|
|
33686
|
+
const answer = await new Promise((resolve30) => rl.once("line", resolve30));
|
|
33673
33687
|
rl.close();
|
|
33674
33688
|
const index = Number.parseInt(answer.trim(), 10) - 1;
|
|
33675
33689
|
return Number.isInteger(index) && index >= 0 && index < models.length ? models[index] : void 0;
|
|
@@ -33695,7 +33709,7 @@ async function cmdModelsScreen(runtime) {
|
|
|
33695
33709
|
return 2;
|
|
33696
33710
|
}
|
|
33697
33711
|
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
33698
|
-
const ask = (q2) => new Promise((
|
|
33712
|
+
const ask = (q2) => new Promise((resolve30) => rl.question(q2, resolve30));
|
|
33699
33713
|
try {
|
|
33700
33714
|
while (true) {
|
|
33701
33715
|
const policy = loadProducerPolicy(runtime.dirs.workdir);
|
|
@@ -33959,11 +33973,11 @@ async function cmdStudioLayout(runtime, workflowPath) {
|
|
|
33959
33973
|
const projectRoot = discoverVnextProjectRoot(runtime.cwd) ?? runtime.cwd;
|
|
33960
33974
|
let filePath = workflowPath;
|
|
33961
33975
|
if (!filePath) {
|
|
33962
|
-
filePath =
|
|
33976
|
+
filePath = resolve20(projectRoot, ".kxm", "workflows", "default.yaml");
|
|
33963
33977
|
}
|
|
33964
33978
|
let yamlContent;
|
|
33965
33979
|
let workflowId = "default";
|
|
33966
|
-
if (
|
|
33980
|
+
if (existsSync23(filePath)) {
|
|
33967
33981
|
yamlContent = readFileSync22(filePath, "utf8");
|
|
33968
33982
|
} else {
|
|
33969
33983
|
yamlContent = `schema: kxm.workflow.v1
|
|
@@ -34037,14 +34051,14 @@ async function cmdStudioServe(runtime, options) {
|
|
|
34037
34051
|
sessionToken,
|
|
34038
34052
|
planProvider: () => {
|
|
34039
34053
|
try {
|
|
34040
|
-
const wfDir =
|
|
34041
|
-
const defaultPath =
|
|
34042
|
-
let targetPath =
|
|
34043
|
-
if (!targetPath &&
|
|
34054
|
+
const wfDir = join27(runtime.cwd, ".kxm", "workflows");
|
|
34055
|
+
const defaultPath = join27(wfDir, "default.yaml");
|
|
34056
|
+
let targetPath = existsSync23(defaultPath) ? defaultPath : void 0;
|
|
34057
|
+
if (!targetPath && existsSync23(wfDir)) {
|
|
34044
34058
|
const yml = readdirSync8(wfDir).find((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
|
|
34045
|
-
if (yml) targetPath =
|
|
34059
|
+
if (yml) targetPath = join27(wfDir, yml);
|
|
34046
34060
|
}
|
|
34047
|
-
if (targetPath &&
|
|
34061
|
+
if (targetPath && existsSync23(targetPath)) {
|
|
34048
34062
|
const raw = readFileSync22(targetPath, "utf8");
|
|
34049
34063
|
const parsed = (0, import_yaml13.parse)(raw);
|
|
34050
34064
|
const wfId = basename6(targetPath).replace(/\.(yaml|yml)$/, "");
|
|
@@ -34096,13 +34110,13 @@ Press Ctrl+C to stop.
|
|
|
34096
34110
|
|
|
34097
34111
|
// plugins/kxm/src/cli/context-skills.ts
|
|
34098
34112
|
import { readFileSync as readFileSync25 } from "node:fs";
|
|
34099
|
-
import { join as
|
|
34113
|
+
import { join as join31, relative as relative5 } from "node:path";
|
|
34100
34114
|
|
|
34101
34115
|
// plugins/kxm/src/memory.ts
|
|
34102
34116
|
var import_yaml14 = __toESM(require_dist(), 1);
|
|
34103
34117
|
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
34104
|
-
import { existsSync as
|
|
34105
|
-
import { extname as extname2, join as
|
|
34118
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync19, readdirSync as readdirSync9, readFileSync as readFileSync23, writeFileSync as writeFileSync18 } from "node:fs";
|
|
34119
|
+
import { extname as extname2, join as join28, resolve as resolve21 } from "node:path";
|
|
34106
34120
|
var MEMORY_SCHEMA = "kxm.memory.v1";
|
|
34107
34121
|
var MEMORY_BRIEF_SCHEMA = "kxm.memory-brief.v1";
|
|
34108
34122
|
var MEMORY_MARKER_START = "<!-- kxm:memory:start -->";
|
|
@@ -34227,20 +34241,20 @@ ${yamlText}
|
|
|
34227
34241
|
---
|
|
34228
34242
|
`;
|
|
34229
34243
|
}
|
|
34230
|
-
function memoryDirectories(
|
|
34231
|
-
const root =
|
|
34232
|
-
const memoryDir =
|
|
34233
|
-
const candidatesDir =
|
|
34244
|
+
function memoryDirectories(repoRoot) {
|
|
34245
|
+
const root = resolve21(repoRoot);
|
|
34246
|
+
const memoryDir = join28(root, ".kxm", "memory");
|
|
34247
|
+
const candidatesDir = join28(memoryDir, "candidates");
|
|
34234
34248
|
return { memoryDir, candidatesDir };
|
|
34235
34249
|
}
|
|
34236
|
-
function loadAuthoredMemory(
|
|
34237
|
-
const { memoryDir } = memoryDirectories(
|
|
34238
|
-
if (!
|
|
34250
|
+
function loadAuthoredMemory(repoRoot) {
|
|
34251
|
+
const { memoryDir } = memoryDirectories(repoRoot);
|
|
34252
|
+
if (!existsSync24(memoryDir)) return [];
|
|
34239
34253
|
const records = [];
|
|
34240
34254
|
const entries = readdirSync9(memoryDir, { withFileTypes: true });
|
|
34241
34255
|
for (const entry of entries) {
|
|
34242
34256
|
if (entry.isFile() && extname2(entry.name) === ".md") {
|
|
34243
|
-
const fullPath =
|
|
34257
|
+
const fullPath = join28(memoryDir, entry.name);
|
|
34244
34258
|
try {
|
|
34245
34259
|
const text = readFileSync23(fullPath, "utf8");
|
|
34246
34260
|
const record = parseMemoryRecord(text, entry.name);
|
|
@@ -34254,8 +34268,8 @@ function loadAuthoredMemory(repoRoot6) {
|
|
|
34254
34268
|
}
|
|
34255
34269
|
return records.sort((left, right) => left.id.localeCompare(right.id));
|
|
34256
34270
|
}
|
|
34257
|
-
function createMemoryNote(
|
|
34258
|
-
const { candidatesDir } = memoryDirectories(
|
|
34271
|
+
function createMemoryNote(repoRoot, summary, options = {}) {
|
|
34272
|
+
const { candidatesDir } = memoryDirectories(repoRoot);
|
|
34259
34273
|
mkdirSync19(candidatesDir, { recursive: true });
|
|
34260
34274
|
const scope = options.scope ?? "project";
|
|
34261
34275
|
if (!VALID_SCOPES.has(scope)) {
|
|
@@ -34281,12 +34295,12 @@ function createMemoryNote(repoRoot6, summary, options = {}) {
|
|
|
34281
34295
|
evidenceRefs: [],
|
|
34282
34296
|
...options.body ? { body: options.body.trim() } : {}
|
|
34283
34297
|
};
|
|
34284
|
-
const targetPath =
|
|
34298
|
+
const targetPath = join28(candidatesDir, `${id}.md`);
|
|
34285
34299
|
writeFileSync18(targetPath, formatMemoryRecord(record), "utf8");
|
|
34286
34300
|
return { record, path: targetPath };
|
|
34287
34301
|
}
|
|
34288
|
-
function generateMemoryBrief(
|
|
34289
|
-
const facts = loadAuthoredMemory(
|
|
34302
|
+
function generateMemoryBrief(repoRoot) {
|
|
34303
|
+
const facts = loadAuthoredMemory(repoRoot);
|
|
34290
34304
|
return {
|
|
34291
34305
|
schema: MEMORY_BRIEF_SCHEMA,
|
|
34292
34306
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -34318,7 +34332,7 @@ function formatHarnessMemoryBlock(records) {
|
|
|
34318
34332
|
}
|
|
34319
34333
|
function updateHarnessDocument(filePath, block, defaultHeader) {
|
|
34320
34334
|
let original = "";
|
|
34321
|
-
if (
|
|
34335
|
+
if (existsSync24(filePath)) {
|
|
34322
34336
|
original = readFileSync23(filePath, "utf8");
|
|
34323
34337
|
}
|
|
34324
34338
|
let updated = "";
|
|
@@ -34352,20 +34366,20 @@ ${block}
|
|
|
34352
34366
|
}
|
|
34353
34367
|
return false;
|
|
34354
34368
|
}
|
|
34355
|
-
function syncHarnessMemory(
|
|
34356
|
-
const root =
|
|
34369
|
+
function syncHarnessMemory(repoRoot) {
|
|
34370
|
+
const root = resolve21(repoRoot);
|
|
34357
34371
|
const records = loadAuthoredMemory(root);
|
|
34358
34372
|
const block = formatHarnessMemoryBlock(records);
|
|
34359
34373
|
const updated = [];
|
|
34360
34374
|
const created = [];
|
|
34361
|
-
const agentsPath =
|
|
34375
|
+
const agentsPath = join28(root, "AGENTS.md");
|
|
34362
34376
|
const agentsHeader = "# AGENTS\n\nFollow project instructions.\n";
|
|
34363
|
-
const agentsExisted =
|
|
34377
|
+
const agentsExisted = existsSync24(agentsPath);
|
|
34364
34378
|
if (updateHarnessDocument(agentsPath, block, agentsHeader)) {
|
|
34365
34379
|
if (agentsExisted) updated.push("AGENTS.md");
|
|
34366
34380
|
else created.push("AGENTS.md");
|
|
34367
34381
|
}
|
|
34368
|
-
const claudePath =
|
|
34382
|
+
const claudePath = join28(root, "CLAUDE.md");
|
|
34369
34383
|
const claudeHeader = `# KXM (Claude)
|
|
34370
34384
|
|
|
34371
34385
|
Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
@@ -34376,12 +34390,12 @@ you to implement. Default writer is native Grok CLI (\`grok --model grok-4.6\`).
|
|
|
34376
34390
|
If \`grok\` is logged out, fail closed; do not fall back to Pi. Your reviews are
|
|
34377
34391
|
artifacts, not hub \`peer-reply\` evidence.
|
|
34378
34392
|
`;
|
|
34379
|
-
const claudeExisted =
|
|
34393
|
+
const claudeExisted = existsSync24(claudePath);
|
|
34380
34394
|
if (updateHarnessDocument(claudePath, block, claudeHeader)) {
|
|
34381
34395
|
if (claudeExisted) updated.push("CLAUDE.md");
|
|
34382
34396
|
else created.push("CLAUDE.md");
|
|
34383
34397
|
}
|
|
34384
|
-
const geminiPath =
|
|
34398
|
+
const geminiPath = join28(root, "GEMINI.md");
|
|
34385
34399
|
const geminiHeader = `# KXM (Gemini / Antigravity)
|
|
34386
34400
|
|
|
34387
34401
|
Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
@@ -34390,7 +34404,7 @@ Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
|
34390
34404
|
Google / Antigravity CLI (\`agy\`) is an admitted native writer and experiment edit route
|
|
34391
34405
|
for Gemini models. Starting rotation remains Grok.
|
|
34392
34406
|
`;
|
|
34393
|
-
const geminiExisted =
|
|
34407
|
+
const geminiExisted = existsSync24(geminiPath);
|
|
34394
34408
|
if (updateHarnessDocument(geminiPath, block, geminiHeader)) {
|
|
34395
34409
|
if (geminiExisted) updated.push("GEMINI.md");
|
|
34396
34410
|
else created.push("GEMINI.md");
|
|
@@ -34401,8 +34415,8 @@ for Gemini models. Starting rotation remains Grok.
|
|
|
34401
34415
|
// plugins/kxm/src/skills.ts
|
|
34402
34416
|
var import_yaml15 = __toESM(require_dist(), 1);
|
|
34403
34417
|
import { createHash as createHash14 } from "node:crypto";
|
|
34404
|
-
import { existsSync as
|
|
34405
|
-
import { join as
|
|
34418
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync20, readdirSync as readdirSync10, readFileSync as readFileSync24, renameSync as renameSync7, rmSync as rmSync9, statSync as statSync3, writeFileSync as writeFileSync19 } from "node:fs";
|
|
34419
|
+
import { join as join29 } from "node:path";
|
|
34406
34420
|
var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
|
|
34407
34421
|
var SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
|
|
34408
34422
|
var SKILL_DECISION_SCHEMA = "kxm.skill-decision.v1";
|
|
@@ -34496,20 +34510,20 @@ var SkillLifecycle = class {
|
|
|
34496
34510
|
this.allowOptimizationEvals = options.allowOptimizationEvals === true;
|
|
34497
34511
|
}
|
|
34498
34512
|
dir(state) {
|
|
34499
|
-
return
|
|
34513
|
+
return join29(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
|
|
34500
34514
|
}
|
|
34501
34515
|
historyFile(id) {
|
|
34502
|
-
return
|
|
34516
|
+
return join29(this.root, "history", `${id}.jsonl`);
|
|
34503
34517
|
}
|
|
34504
34518
|
paths(state, id) {
|
|
34505
|
-
const dir =
|
|
34506
|
-
return { dir, metadata:
|
|
34519
|
+
const dir = join29(this.dir(state), id);
|
|
34520
|
+
return { dir, metadata: join29(dir, "metadata.json"), skill: join29(dir, "SKILL.md") };
|
|
34507
34521
|
}
|
|
34508
34522
|
appendHistory(id, record) {
|
|
34509
|
-
mkdirSync20(
|
|
34523
|
+
mkdirSync20(join29(this.root, "history"), { recursive: true });
|
|
34510
34524
|
const line = `${JSON.stringify(record)}
|
|
34511
34525
|
`;
|
|
34512
|
-
if (
|
|
34526
|
+
if (existsSync25(this.historyFile(id))) {
|
|
34513
34527
|
const existing = readFileSync24(this.historyFile(id), "utf8");
|
|
34514
34528
|
const lines = existing.split("\n").filter((entry) => entry.trim());
|
|
34515
34529
|
writeFileSync19(this.historyFile(id), [...lines.slice(-499), line.trim()].join("\n") + "\n");
|
|
@@ -34519,24 +34533,24 @@ var SkillLifecycle = class {
|
|
|
34519
34533
|
}
|
|
34520
34534
|
history(id) {
|
|
34521
34535
|
const file = this.historyFile(id);
|
|
34522
|
-
if (!
|
|
34536
|
+
if (!existsSync25(file)) return [];
|
|
34523
34537
|
return readFileSync24(file, "utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
34524
34538
|
}
|
|
34525
34539
|
readMetadata(state, id) {
|
|
34526
34540
|
const { metadata } = this.paths(state, id);
|
|
34527
|
-
if (!
|
|
34541
|
+
if (!existsSync25(metadata)) {
|
|
34528
34542
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${state}`);
|
|
34529
34543
|
}
|
|
34530
34544
|
return JSON.parse(readFileSync24(metadata, "utf8"));
|
|
34531
34545
|
}
|
|
34532
34546
|
move(from, to, id) {
|
|
34533
|
-
const fromDir =
|
|
34534
|
-
const toDir =
|
|
34535
|
-
if (!
|
|
34547
|
+
const fromDir = join29(this.dir(from), id);
|
|
34548
|
+
const toDir = join29(this.dir(to), id);
|
|
34549
|
+
if (!existsSync25(fromDir)) {
|
|
34536
34550
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${from}`);
|
|
34537
34551
|
}
|
|
34538
34552
|
mkdirSync20(this.dir(to), { recursive: true });
|
|
34539
|
-
if (
|
|
34553
|
+
if (existsSync25(toDir)) rmSync9(toDir, { recursive: true, force: true });
|
|
34540
34554
|
renameSync7(fromDir, toDir);
|
|
34541
34555
|
}
|
|
34542
34556
|
/** Submit a new skill candidate. Content is redacted of secret material at
|
|
@@ -34579,7 +34593,7 @@ var SkillLifecycle = class {
|
|
|
34579
34593
|
const contentSha256 = skillContentSha256(content);
|
|
34580
34594
|
const id = skillIdFor(name, contentSha256);
|
|
34581
34595
|
const { dir, metadata, skill } = this.paths("candidate", id);
|
|
34582
|
-
if (
|
|
34596
|
+
if (existsSync25(metadata)) {
|
|
34583
34597
|
throw new SkillLifecycleError(
|
|
34584
34598
|
"skill_candidate_exists",
|
|
34585
34599
|
`identical candidate ${id} already exists; changed behavior requires changed content`
|
|
@@ -34694,9 +34708,9 @@ var SkillLifecycle = class {
|
|
|
34694
34708
|
const metadataContent = readFileSync24(candidatePaths.metadata, "utf8");
|
|
34695
34709
|
writeFileSync19(promotedPaths.skill, skillContent);
|
|
34696
34710
|
writeFileSync19(promotedPaths.metadata, metadataContent);
|
|
34697
|
-
const patchesDir =
|
|
34711
|
+
const patchesDir = join29(this.root, "patches");
|
|
34698
34712
|
mkdirSync20(patchesDir, { recursive: true });
|
|
34699
|
-
const patchPath =
|
|
34713
|
+
const patchPath = join29(patchesDir, `${candidateId}.patch`);
|
|
34700
34714
|
const relSkillPath = `.kxm/skills/promoted/${candidateId}/SKILL.md`;
|
|
34701
34715
|
const relMetaPath = `.kxm/skills/promoted/${candidateId}/metadata.json`;
|
|
34702
34716
|
const patch = `${createUnifiedPatch(relSkillPath, skillContent)}${createUnifiedPatch(relMetaPath, metadataContent)}`;
|
|
@@ -34742,7 +34756,7 @@ var SkillLifecycle = class {
|
|
|
34742
34756
|
}
|
|
34743
34757
|
list(state) {
|
|
34744
34758
|
const dir = this.dir(state);
|
|
34745
|
-
if (!
|
|
34759
|
+
if (!existsSync25(dir)) return [];
|
|
34746
34760
|
const ids = readdirSorted(dir);
|
|
34747
34761
|
return ids.map((id) => {
|
|
34748
34762
|
try {
|
|
@@ -34770,16 +34784,16 @@ function boundedList(value, field) {
|
|
|
34770
34784
|
return [...new Set(refs)];
|
|
34771
34785
|
}
|
|
34772
34786
|
function readdirSorted(dir) {
|
|
34773
|
-
return readdirSync10(dir).filter((entry) => statSync3(
|
|
34787
|
+
return readdirSync10(dir).filter((entry) => statSync3(join29(dir, entry)).isDirectory()).sort();
|
|
34774
34788
|
}
|
|
34775
34789
|
|
|
34776
34790
|
// plugins/kxm/src/wiki.ts
|
|
34777
34791
|
import { mkdirSync as mkdirSync21, writeFileSync as writeFileSync20 } from "node:fs";
|
|
34778
|
-
import { join as
|
|
34792
|
+
import { join as join30 } from "node:path";
|
|
34779
34793
|
function writeCompiledWiki(root, wiki) {
|
|
34780
34794
|
const written = [];
|
|
34781
34795
|
for (const [relativePath, content] of [...wiki.pages].sort(([left], [right]) => left.localeCompare(right))) {
|
|
34782
|
-
const absolute =
|
|
34796
|
+
const absolute = join30(root, relativePath);
|
|
34783
34797
|
mkdirSync21(absolute.slice(0, absolute.lastIndexOf("/")), { recursive: true });
|
|
34784
34798
|
writeFileSync20(absolute, content);
|
|
34785
34799
|
written.push(relativePath);
|
|
@@ -34947,7 +34961,7 @@ function skillStateFromFlag(value) {
|
|
|
34947
34961
|
throw new Error(`invalid skill state ${value}`);
|
|
34948
34962
|
}
|
|
34949
34963
|
function skillsRoot(runtime) {
|
|
34950
|
-
return
|
|
34964
|
+
return join31(runtime.dirs.workdir, ".kxm", "skills");
|
|
34951
34965
|
}
|
|
34952
34966
|
function csv(value) {
|
|
34953
34967
|
if (!value) return void 0;
|
|
@@ -35122,8 +35136,8 @@ async function cmdMemorySync(runtime) {
|
|
|
35122
35136
|
|
|
35123
35137
|
// plugins/kxm/src/cli/hub.ts
|
|
35124
35138
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
35125
|
-
import { existsSync as
|
|
35126
|
-
import { join as
|
|
35139
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync25, readFileSync as readFileSync31, readdirSync as readdirSync12, rmSync as rmSync10, writeFileSync as writeFileSync23 } from "node:fs";
|
|
35140
|
+
import { join as join41, resolve as resolve24 } from "node:path";
|
|
35127
35141
|
|
|
35128
35142
|
// node_modules/marked/lib/marked.esm.js
|
|
35129
35143
|
function M() {
|
|
@@ -39285,10 +39299,10 @@ var TuiBase = class _TuiBase extends Container {
|
|
|
39285
39299
|
* @returns Promise containing the parsed RGB color, or undefined if it times out or fails to parse.
|
|
39286
39300
|
*/
|
|
39287
39301
|
queryTerminalBackgroundColor({ timeoutMs }) {
|
|
39288
|
-
return new Promise((
|
|
39302
|
+
return new Promise((resolve30) => {
|
|
39289
39303
|
const query = {
|
|
39290
39304
|
settled: false,
|
|
39291
|
-
resolve:
|
|
39305
|
+
resolve: resolve30,
|
|
39292
39306
|
timer: void 0
|
|
39293
39307
|
};
|
|
39294
39308
|
query.timer = setTimeout(() => {
|
|
@@ -39311,7 +39325,7 @@ var TuiBase = class _TuiBase extends Container {
|
|
|
39311
39325
|
* `CSI ? 997 ; 1 n` for dark or `CSI ? 997 ; 2 n` for light.
|
|
39312
39326
|
*/
|
|
39313
39327
|
queryTerminalColorScheme({ timeoutMs }) {
|
|
39314
|
-
return new Promise((
|
|
39328
|
+
return new Promise((resolve30) => {
|
|
39315
39329
|
let settled = false;
|
|
39316
39330
|
let timer;
|
|
39317
39331
|
let unsubscribe = () => {
|
|
@@ -39325,7 +39339,7 @@ var TuiBase = class _TuiBase extends Container {
|
|
|
39325
39339
|
timer = void 0;
|
|
39326
39340
|
}
|
|
39327
39341
|
unsubscribe();
|
|
39328
|
-
|
|
39342
|
+
resolve30(scheme);
|
|
39329
39343
|
};
|
|
39330
39344
|
unsubscribe = this.onTerminalColorSchemeChange(settle);
|
|
39331
39345
|
timer = setTimeout(() => settle(void 0), timeoutMs);
|
|
@@ -41056,19 +41070,19 @@ import * as path2 from "node:path";
|
|
|
41056
41070
|
|
|
41057
41071
|
// node_modules/@earendil-works/pi-tui/dist/native-module-path.js
|
|
41058
41072
|
import { createRequire as createRequire2 } from "node:module";
|
|
41059
|
-
import { dirname as dirname16, join as
|
|
41060
|
-
import { fileURLToPath as
|
|
41073
|
+
import { dirname as dirname16, join as join32 } from "node:path";
|
|
41074
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
41061
41075
|
var moduleRequire = createRequire2(import.meta.url);
|
|
41062
41076
|
var TUI_PACKAGE_NAME = "@earendil-works/pi-tui";
|
|
41063
41077
|
function getNativeModuleCandidates(nativePath, options = {}) {
|
|
41064
|
-
const moduleDir = dirname16(
|
|
41078
|
+
const moduleDir = dirname16(fileURLToPath2(options.moduleUrl ?? import.meta.url));
|
|
41065
41079
|
const candidates = [];
|
|
41066
41080
|
try {
|
|
41067
41081
|
const packageEntry = (options.resolvePackage ?? moduleRequire.resolve)(TUI_PACKAGE_NAME);
|
|
41068
|
-
candidates.push(
|
|
41082
|
+
candidates.push(join32(dirname16(packageEntry), "..", nativePath));
|
|
41069
41083
|
} catch {
|
|
41070
41084
|
}
|
|
41071
|
-
candidates.push(
|
|
41085
|
+
candidates.push(join32(moduleDir, "..", nativePath), join32(moduleDir, nativePath), join32(dirname16(options.execPath ?? process.execPath), nativePath));
|
|
41072
41086
|
return Array.from(new Set(candidates));
|
|
41073
41087
|
}
|
|
41074
41088
|
|
|
@@ -41409,7 +41423,7 @@ var ProcessTerminal = class {
|
|
|
41409
41423
|
break;
|
|
41410
41424
|
if (now - lastDataTime >= idleMs)
|
|
41411
41425
|
break;
|
|
41412
|
-
await new Promise((
|
|
41426
|
+
await new Promise((resolve30) => setTimeout(resolve30, Math.min(idleMs, timeLeft)));
|
|
41413
41427
|
}
|
|
41414
41428
|
} finally {
|
|
41415
41429
|
process.stdin.removeListener("data", onData);
|
|
@@ -43525,7 +43539,7 @@ var MAX_RENDER_WRITE_CHARS = 1024 * 1024;
|
|
|
43525
43539
|
|
|
43526
43540
|
// plugins/kxm/src/tui.ts
|
|
43527
43541
|
import { mkdirSync as mkdirSync22 } from "node:fs";
|
|
43528
|
-
import { join as
|
|
43542
|
+
import { join as join36, resolve as resolve23, dirname as dirname17 } from "node:path";
|
|
43529
43543
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
43530
43544
|
|
|
43531
43545
|
// plugins/kxm/src/external-effects.ts
|
|
@@ -43536,9 +43550,9 @@ function slugifyBranchPart(text, maxLength = 40) {
|
|
|
43536
43550
|
}
|
|
43537
43551
|
|
|
43538
43552
|
// plugins/kxm/src/local-snapshot.ts
|
|
43539
|
-
import { existsSync as
|
|
43553
|
+
import { existsSync as existsSync26, readdirSync as readdirSync11, readFileSync as readFileSync26 } from "node:fs";
|
|
43540
43554
|
import { homedir as homedir5 } from "node:os";
|
|
43541
|
-
import { isAbsolute as isAbsolute7, join as
|
|
43555
|
+
import { isAbsolute as isAbsolute7, join as join35, resolve as resolve22 } from "node:path";
|
|
43542
43556
|
function processExists2(pid) {
|
|
43543
43557
|
try {
|
|
43544
43558
|
process.kill(pid, 0);
|
|
@@ -43658,36 +43672,36 @@ function readOpenMessageMetadata(database) {
|
|
|
43658
43672
|
return messages;
|
|
43659
43673
|
}
|
|
43660
43674
|
function resolveKxmSnapshotPaths(cwd, env = process.env) {
|
|
43661
|
-
const stateDir = env.KXM_STATE_DIR?.trim() ||
|
|
43675
|
+
const stateDir = env.KXM_STATE_DIR?.trim() || join35(cwd, ".kxm", "state");
|
|
43662
43676
|
const configured = env.KXM_DATA_PATH?.trim();
|
|
43663
|
-
const dataPath = configured ?
|
|
43677
|
+
const dataPath = configured ? resolve22(cwd, configured) : join35(stateDir, "kxm.db");
|
|
43664
43678
|
return { dataPath, stateDir };
|
|
43665
43679
|
}
|
|
43666
43680
|
function resolveVnextStateRoot(stateDir, options) {
|
|
43667
|
-
if (options?.vnextStateRoot &&
|
|
43668
|
-
return
|
|
43681
|
+
if (options?.vnextStateRoot && existsSync26(options.vnextStateRoot)) {
|
|
43682
|
+
return resolve22(options.vnextStateRoot);
|
|
43669
43683
|
}
|
|
43670
|
-
if (
|
|
43684
|
+
if (existsSync26(join35(stateDir, "runtime", "registry.db")) || existsSync26(join35(stateDir, "runtime", "projects"))) {
|
|
43671
43685
|
return stateDir;
|
|
43672
43686
|
}
|
|
43673
43687
|
const env = options?.env ?? process.env;
|
|
43674
43688
|
const explicit = env.KXM_STATE_HOME?.trim() || env.KXM_USER_STATE_DIR?.trim() || env.KXM_STATE_ROOT?.trim();
|
|
43675
|
-
if (explicit && isAbsolute7(explicit) &&
|
|
43676
|
-
return
|
|
43689
|
+
if (explicit && isAbsolute7(explicit) && existsSync26(resolve22(explicit))) {
|
|
43690
|
+
return resolve22(explicit);
|
|
43677
43691
|
}
|
|
43678
43692
|
let base;
|
|
43679
43693
|
if (process.platform === "win32") {
|
|
43680
43694
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
43681
|
-
base = localAppData && isAbsolute7(localAppData) ? localAppData :
|
|
43682
|
-
base =
|
|
43695
|
+
base = localAppData && isAbsolute7(localAppData) ? localAppData : join35(homedir5(), "AppData", "Local");
|
|
43696
|
+
base = resolve22(base, "KXM");
|
|
43683
43697
|
} else if (process.platform === "darwin") {
|
|
43684
|
-
base =
|
|
43698
|
+
base = resolve22(homedir5(), "Library", "Application Support", "KXM");
|
|
43685
43699
|
} else {
|
|
43686
43700
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
43687
|
-
base = xdgState && isAbsolute7(xdgState) ? xdgState :
|
|
43688
|
-
base =
|
|
43701
|
+
base = xdgState && isAbsolute7(xdgState) ? xdgState : join35(homedir5(), ".local", "state");
|
|
43702
|
+
base = resolve22(base, "kxm");
|
|
43689
43703
|
}
|
|
43690
|
-
if (
|
|
43704
|
+
if (existsSync26(base)) return base;
|
|
43691
43705
|
return void 0;
|
|
43692
43706
|
}
|
|
43693
43707
|
function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
@@ -43698,7 +43712,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43698
43712
|
let legacyRuns = [];
|
|
43699
43713
|
let legacyRunTotal = 0;
|
|
43700
43714
|
let plans = [];
|
|
43701
|
-
if (
|
|
43715
|
+
if (existsSync26(dataPath)) {
|
|
43702
43716
|
hasLegacy = true;
|
|
43703
43717
|
const database = new DatabaseSync(dataPath, { readOnly: true });
|
|
43704
43718
|
try {
|
|
@@ -43718,11 +43732,11 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43718
43732
|
let vnextRunTotal = 0;
|
|
43719
43733
|
const vnextStateRoot = resolveVnextStateRoot(stateDir, options);
|
|
43720
43734
|
if (vnextStateRoot) {
|
|
43721
|
-
const runtimeDir =
|
|
43722
|
-
const registryDbPath =
|
|
43723
|
-
const projectsDir =
|
|
43735
|
+
const runtimeDir = join35(vnextStateRoot, "runtime");
|
|
43736
|
+
const registryDbPath = join35(runtimeDir, "registry.db");
|
|
43737
|
+
const projectsDir = join35(runtimeDir, "projects");
|
|
43724
43738
|
const projectKeys = /* @__PURE__ */ new Set();
|
|
43725
|
-
if (
|
|
43739
|
+
if (existsSync26(registryDbPath)) {
|
|
43726
43740
|
hasVnext = true;
|
|
43727
43741
|
try {
|
|
43728
43742
|
const regDb = new DatabaseSync(registryDbPath, { readOnly: true });
|
|
@@ -43738,7 +43752,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43738
43752
|
} catch {
|
|
43739
43753
|
}
|
|
43740
43754
|
}
|
|
43741
|
-
if (
|
|
43755
|
+
if (existsSync26(projectsDir)) {
|
|
43742
43756
|
try {
|
|
43743
43757
|
for (const entry of readdirSync11(projectsDir, { withFileTypes: true })) {
|
|
43744
43758
|
if (entry.isDirectory()) {
|
|
@@ -43749,8 +43763,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43749
43763
|
}
|
|
43750
43764
|
}
|
|
43751
43765
|
for (const key of projectKeys) {
|
|
43752
|
-
const eventDbPath =
|
|
43753
|
-
if (
|
|
43766
|
+
const eventDbPath = join35(projectsDir, key, "run-events.db");
|
|
43767
|
+
if (existsSync26(eventDbPath)) {
|
|
43754
43768
|
hasVnext = true;
|
|
43755
43769
|
try {
|
|
43756
43770
|
const eventDb = new DatabaseSync(eventDbPath, { readOnly: true });
|
|
@@ -43780,10 +43794,10 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43780
43794
|
}
|
|
43781
43795
|
}
|
|
43782
43796
|
const pids = [];
|
|
43783
|
-
if (
|
|
43797
|
+
if (existsSync26(stateDir)) {
|
|
43784
43798
|
for (const file of readdirSync11(stateDir).filter((name) => name.endsWith(".pid"))) {
|
|
43785
43799
|
try {
|
|
43786
|
-
const record = JSON.parse(readFileSync26(
|
|
43800
|
+
const record = JSON.parse(readFileSync26(join35(stateDir, file), "utf8"));
|
|
43787
43801
|
pids.push({
|
|
43788
43802
|
file,
|
|
43789
43803
|
...record.role ? { role: record.role } : {},
|
|
@@ -43822,8 +43836,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43822
43836
|
} else {
|
|
43823
43837
|
source = "legacy";
|
|
43824
43838
|
}
|
|
43825
|
-
const telemetryFile =
|
|
43826
|
-
const spend =
|
|
43839
|
+
const telemetryFile = join35(stateDir, "telemetry.jsonl");
|
|
43840
|
+
const spend = existsSync26(telemetryFile) ? readRoutingRecords(telemetryFile) : [];
|
|
43827
43841
|
return {
|
|
43828
43842
|
source,
|
|
43829
43843
|
agents: agents.sort((a, b2) => Number(b2.online) - Number(a.online) || a.name.localeCompare(b2.name)),
|
|
@@ -43938,10 +43952,10 @@ function copyToClipboard(text) {
|
|
|
43938
43952
|
return false;
|
|
43939
43953
|
}
|
|
43940
43954
|
}
|
|
43941
|
-
function spawnDegradeWorktree(
|
|
43955
|
+
function spawnDegradeWorktree(repoRoot, runId, options) {
|
|
43942
43956
|
const runner = options?.execFn ?? ((cmd, args) => {
|
|
43943
43957
|
const res = spawnSync5(cmd, args, {
|
|
43944
|
-
cwd:
|
|
43958
|
+
cwd: repoRoot,
|
|
43945
43959
|
encoding: "utf8",
|
|
43946
43960
|
windowsHide: true,
|
|
43947
43961
|
env: Object.fromEntries(
|
|
@@ -43957,8 +43971,8 @@ function spawnDegradeWorktree(repoRoot6, runId, options) {
|
|
|
43957
43971
|
const cleanRunId = runId.replace(/^run_/, "");
|
|
43958
43972
|
const desc = options?.description ? slugifyBranchPart(options.description, 30) : "degrade";
|
|
43959
43973
|
const branchName = `kxm/run-${cleanRunId}-${desc}`;
|
|
43960
|
-
const relativeWtPath =
|
|
43961
|
-
const absoluteWtPath =
|
|
43974
|
+
const relativeWtPath = join36(".kxm", "worktrees", `run-${cleanRunId}-${desc}`);
|
|
43975
|
+
const absoluteWtPath = resolve23(repoRoot, relativeWtPath);
|
|
43962
43976
|
const jumpCommand = `cd "${absoluteWtPath}"`;
|
|
43963
43977
|
try {
|
|
43964
43978
|
mkdirSync22(dirname17(absoluteWtPath), { recursive: true });
|
|
@@ -44360,11 +44374,11 @@ async function readJson(response) {
|
|
|
44360
44374
|
}
|
|
44361
44375
|
async function waitForReconnect(signal, milliseconds = 1e3) {
|
|
44362
44376
|
if (signal.aborted) return;
|
|
44363
|
-
await new Promise((
|
|
44377
|
+
await new Promise((resolve30) => {
|
|
44364
44378
|
const done = () => {
|
|
44365
44379
|
clearTimeout(timer);
|
|
44366
44380
|
signal.removeEventListener("abort", done);
|
|
44367
|
-
|
|
44381
|
+
resolve30();
|
|
44368
44382
|
};
|
|
44369
44383
|
const timer = setTimeout(done, milliseconds);
|
|
44370
44384
|
timer.unref();
|
|
@@ -44556,8 +44570,8 @@ async function runMeshTui(input) {
|
|
|
44556
44570
|
body: JSON.stringify({ signalKey: "operator-degrade", status: "degraded", summary: "Degraded to operator worktree from kxm dash" }),
|
|
44557
44571
|
signal: abort.signal
|
|
44558
44572
|
});
|
|
44559
|
-
const
|
|
44560
|
-
const degradeRes = spawnDegradeWorktree(
|
|
44573
|
+
const repoRoot = process.cwd();
|
|
44574
|
+
const degradeRes = spawnDegradeWorktree(repoRoot, targetId, {
|
|
44561
44575
|
description: "operator-degrade"
|
|
44562
44576
|
});
|
|
44563
44577
|
if (dashboard) {
|
|
@@ -44727,8 +44741,8 @@ async function runMeshTui(input) {
|
|
|
44727
44741
|
// plugins/kxm/src/session-work.ts
|
|
44728
44742
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
44729
44743
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
44730
|
-
import { existsSync as
|
|
44731
|
-
import { join as
|
|
44744
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync23, readFileSync as readFileSync27, renameSync as renameSync8, writeFileSync as writeFileSync21 } from "node:fs";
|
|
44745
|
+
import { join as join37 } from "node:path";
|
|
44732
44746
|
var MAX_SESSION_BRIEF_TASKS = 5;
|
|
44733
44747
|
var MAX_SESSION_BRIEF_PLANS = 5;
|
|
44734
44748
|
var SESSION_BRIEF_SCHEMA = "kxm.session-brief.v1";
|
|
@@ -44884,9 +44898,9 @@ function buildSessionBrief(snapshot, current, hub, ship, updateLatest, cost, ses
|
|
|
44884
44898
|
};
|
|
44885
44899
|
}
|
|
44886
44900
|
function readCachedSessionBrief(stateDir) {
|
|
44887
|
-
const file =
|
|
44901
|
+
const file = join37(stateDir, "session-brief.json");
|
|
44888
44902
|
try {
|
|
44889
|
-
if (!
|
|
44903
|
+
if (!existsSync27(file)) return void 0;
|
|
44890
44904
|
const raw = readFileSync27(file, "utf8");
|
|
44891
44905
|
const parsed = JSON.parse(raw);
|
|
44892
44906
|
if (parsed && parsed.schema === "kxm.session-brief.v1" && typeof parsed.generatedAt === "string") {
|
|
@@ -44903,7 +44917,7 @@ function readCachedSessionBrief(stateDir) {
|
|
|
44903
44917
|
function writeCachedSessionBrief(stateDir, brief) {
|
|
44904
44918
|
try {
|
|
44905
44919
|
mkdirSync23(stateDir, { recursive: true, mode: 448 });
|
|
44906
|
-
const file =
|
|
44920
|
+
const file = join37(stateDir, "session-brief.json");
|
|
44907
44921
|
const tmp = `${file}.tmp.${randomUUID13().slice(0, 8)}`;
|
|
44908
44922
|
writeFileSync21(tmp, JSON.stringify(brief, null, 2), { encoding: "utf8", mode: 384 });
|
|
44909
44923
|
renameSync8(tmp, file);
|
|
@@ -44912,8 +44926,8 @@ function writeCachedSessionBrief(stateDir, brief) {
|
|
|
44912
44926
|
}
|
|
44913
44927
|
function estimateSessionCost(stateDir) {
|
|
44914
44928
|
try {
|
|
44915
|
-
const telemetryFile =
|
|
44916
|
-
if (!
|
|
44929
|
+
const telemetryFile = join37(stateDir, "telemetry.jsonl");
|
|
44930
|
+
if (!existsSync27(telemetryFile)) return void 0;
|
|
44917
44931
|
const records = readRoutingRecords(telemetryFile);
|
|
44918
44932
|
if (records.length === 0) return void 0;
|
|
44919
44933
|
let totalCost = 0;
|
|
@@ -45081,11 +45095,11 @@ function formatSessionBriefText(brief) {
|
|
|
45081
45095
|
}
|
|
45082
45096
|
|
|
45083
45097
|
// plugins/kxm/src/kxm-install-kind.ts
|
|
45084
|
-
import { existsSync as
|
|
45085
|
-
import { dirname as dirname18, join as
|
|
45098
|
+
import { existsSync as existsSync28, readFileSync as readFileSync28 } from "node:fs";
|
|
45099
|
+
import { dirname as dirname18, join as join38 } from "node:path";
|
|
45086
45100
|
function packageIsKxm(root) {
|
|
45087
45101
|
try {
|
|
45088
|
-
const pkg = JSON.parse(readFileSync28(
|
|
45102
|
+
const pkg = JSON.parse(readFileSync28(join38(root, "package.json"), "utf8"));
|
|
45089
45103
|
return pkg.name === "@kontextmind/kxm";
|
|
45090
45104
|
} catch {
|
|
45091
45105
|
return false;
|
|
@@ -45107,8 +45121,8 @@ function lastSegments(path4) {
|
|
|
45107
45121
|
function segmentEq(left, right, platform) {
|
|
45108
45122
|
return platform === "win32" ? left.toLocaleLowerCase("en-US") === right.toLocaleLowerCase("en-US") : left === right;
|
|
45109
45123
|
}
|
|
45110
|
-
function isNpmPackageLayout(
|
|
45111
|
-
const last = lastSegments(
|
|
45124
|
+
function isNpmPackageLayout(repoRoot, platform) {
|
|
45125
|
+
const last = lastSegments(repoRoot);
|
|
45112
45126
|
const expected = ["node_modules", "@kontextmind", "kxm"];
|
|
45113
45127
|
return last.length === 3 && last.every((part, i) => segmentEq(part, expected[i], platform));
|
|
45114
45128
|
}
|
|
@@ -45134,12 +45148,12 @@ function report(kind, root) {
|
|
|
45134
45148
|
return { kind, root, instruction: installKindInstruction(kind, root) };
|
|
45135
45149
|
}
|
|
45136
45150
|
function classifyInstallRoot(probe) {
|
|
45137
|
-
const piGitRoot =
|
|
45151
|
+
const piGitRoot = join38(probe.homeDir, ".pi", "agent", "git");
|
|
45138
45152
|
if (isUnder(probe.repoRoot, piGitRoot, probe.platform)) return report("pi-git", probe.repoRoot);
|
|
45139
|
-
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() ||
|
|
45140
|
-
const pluginsRoot =
|
|
45153
|
+
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() || join38(probe.homeDir, ".claude");
|
|
45154
|
+
const pluginsRoot = join38(claudeHome, "plugins");
|
|
45141
45155
|
if (isUnder(probe.moduleDir, pluginsRoot, probe.platform)) return report("claude-marketplace", probe.moduleDir);
|
|
45142
|
-
const hasGit =
|
|
45156
|
+
const hasGit = existsSync28(join38(probe.repoRoot, ".git"));
|
|
45143
45157
|
if (hasGit && packageIsKxm(probe.repoRoot)) return report("source", probe.repoRoot);
|
|
45144
45158
|
if (isNpmPackageLayout(probe.repoRoot, probe.platform) && packageIsKxm(probe.repoRoot) && !hasGit) {
|
|
45145
45159
|
return report("npm-package", probe.repoRoot);
|
|
@@ -45160,11 +45174,11 @@ function resolveInstallKind(probe, npmGlobalRoot) {
|
|
|
45160
45174
|
|
|
45161
45175
|
// plugins/kxm/src/kxm-update-config.ts
|
|
45162
45176
|
var import_yaml16 = __toESM(require_dist(), 1);
|
|
45163
|
-
import { existsSync as
|
|
45164
|
-
import { join as
|
|
45177
|
+
import { existsSync as existsSync29, readFileSync as readFileSync29 } from "node:fs";
|
|
45178
|
+
import { join as join39 } from "node:path";
|
|
45165
45179
|
function loadKxmUpdateConfig(env = process.env) {
|
|
45166
|
-
const path4 =
|
|
45167
|
-
if (!
|
|
45180
|
+
const path4 = join39(vnextUserStateRoot({ env }), "update.yaml");
|
|
45181
|
+
if (!existsSync29(path4)) return { schema: KXM_UPDATE_SCHEMA, auto: false, source: "github" };
|
|
45168
45182
|
let parsed;
|
|
45169
45183
|
try {
|
|
45170
45184
|
parsed = (0, import_yaml16.parse)(readFileSync29(path4, "utf8"));
|
|
@@ -45193,8 +45207,8 @@ function loadKxmUpdateConfig(env = process.env) {
|
|
|
45193
45207
|
}
|
|
45194
45208
|
|
|
45195
45209
|
// plugins/kxm/src/session.ts
|
|
45196
|
-
import { existsSync as
|
|
45197
|
-
import { join as
|
|
45210
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync24, readFileSync as readFileSync30, writeFileSync as writeFileSync22 } from "node:fs";
|
|
45211
|
+
import { join as join40 } from "node:path";
|
|
45198
45212
|
var SESSION_SCHEMA = "kxm.session.v1";
|
|
45199
45213
|
var SessionConfigError = class extends Error {
|
|
45200
45214
|
code = "session_config_invalid";
|
|
@@ -45204,12 +45218,12 @@ var SessionConfigError = class extends Error {
|
|
|
45204
45218
|
}
|
|
45205
45219
|
};
|
|
45206
45220
|
function workflowAssetDirs(assetsDir, workflowId) {
|
|
45207
|
-
const root =
|
|
45208
|
-
return [root,
|
|
45221
|
+
const root = join40(assetsDir, "workflows", workflowId);
|
|
45222
|
+
return [root, join40(root, "inputs"), join40(root, "outputs"), join40(root, "generated")];
|
|
45209
45223
|
}
|
|
45210
45224
|
function sessionAssetDirs(assetsDir, sessionId) {
|
|
45211
|
-
const root =
|
|
45212
|
-
return [root,
|
|
45225
|
+
const root = join40(assetsDir, "sessions", sessionId);
|
|
45226
|
+
return [root, join40(root, "inputs"), join40(root, "outputs")];
|
|
45213
45227
|
}
|
|
45214
45228
|
function rosterNames(configDir) {
|
|
45215
45229
|
return [...loadRosterMap(configDir).values()].map((row) => String(row.name));
|
|
@@ -45259,7 +45273,7 @@ function workerFromRosterRow(name, row, project) {
|
|
|
45259
45273
|
function loadRosterMap(configDir) {
|
|
45260
45274
|
const byName = /* @__PURE__ */ new Map();
|
|
45261
45275
|
for (const [file, key] of [["agents.json", "agents"], ["gates.json", "gates"]]) {
|
|
45262
|
-
const path4 =
|
|
45276
|
+
const path4 = join40(configDir, file);
|
|
45263
45277
|
for (const row of loadRoster(path4, key)) {
|
|
45264
45278
|
const name = String(row.name).trim();
|
|
45265
45279
|
const lowered = name.toLowerCase();
|
|
@@ -45273,7 +45287,7 @@ function loadRosterMap(configDir) {
|
|
|
45273
45287
|
return byName;
|
|
45274
45288
|
}
|
|
45275
45289
|
function loadRoster(path4, key) {
|
|
45276
|
-
if (!
|
|
45290
|
+
if (!existsSync30(path4)) return [];
|
|
45277
45291
|
let parsed;
|
|
45278
45292
|
try {
|
|
45279
45293
|
parsed = JSON.parse(readFileSync30(path4, "utf8"));
|
|
@@ -45301,7 +45315,7 @@ function loadRoster(path4, key) {
|
|
|
45301
45315
|
});
|
|
45302
45316
|
}
|
|
45303
45317
|
function createSession(input) {
|
|
45304
|
-
const assetDir = input.mode === "workflow" && input.workflowId ?
|
|
45318
|
+
const assetDir = input.mode === "workflow" && input.workflowId ? join40("assets", "workflows", input.workflowId) : join40("assets", "sessions", input.id);
|
|
45305
45319
|
return {
|
|
45306
45320
|
schema: SESSION_SCHEMA,
|
|
45307
45321
|
id: input.id,
|
|
@@ -45314,8 +45328,8 @@ function createSession(input) {
|
|
|
45314
45328
|
};
|
|
45315
45329
|
}
|
|
45316
45330
|
function writeSession(assetsDir, session, dryRun = false) {
|
|
45317
|
-
const dir =
|
|
45318
|
-
const path4 =
|
|
45331
|
+
const dir = join40(assetsDir, "sessions", session.id);
|
|
45332
|
+
const path4 = join40(dir, "session.json");
|
|
45319
45333
|
if (!dryRun) {
|
|
45320
45334
|
mkdirSync24(dir, { recursive: true });
|
|
45321
45335
|
writeFileSync22(path4, `${JSON.stringify(session, null, 2)}
|
|
@@ -45325,7 +45339,7 @@ function writeSession(assetsDir, session, dryRun = false) {
|
|
|
45325
45339
|
}
|
|
45326
45340
|
|
|
45327
45341
|
// plugins/kxm/src/cli/hub.ts
|
|
45328
|
-
import { fileURLToPath as
|
|
45342
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
45329
45343
|
import { dirname as dirname19 } from "node:path";
|
|
45330
45344
|
import { homedir as homedir6 } from "node:os";
|
|
45331
45345
|
async function hubGet(url, fetchImpl) {
|
|
@@ -45345,23 +45359,23 @@ async function hubGet(url, fetchImpl) {
|
|
|
45345
45359
|
function installProbeFrom(runtime) {
|
|
45346
45360
|
const partial = runtime.io.installProbe ?? {};
|
|
45347
45361
|
return {
|
|
45348
|
-
moduleDir: partial.moduleDir ?? dirname19(
|
|
45349
|
-
repoRoot: partial.repoRoot ??
|
|
45362
|
+
moduleDir: partial.moduleDir ?? dirname19(fileURLToPath3(import.meta.url)),
|
|
45363
|
+
repoRoot: partial.repoRoot ?? resolve24("."),
|
|
45350
45364
|
homeDir: partial.homeDir ?? homedir6(),
|
|
45351
45365
|
platform: partial.platform ?? process.platform,
|
|
45352
45366
|
env: partial.env ?? runtime.env
|
|
45353
45367
|
};
|
|
45354
45368
|
}
|
|
45355
45369
|
function warnIgnoredProjectUpdateYaml(runtime) {
|
|
45356
|
-
const projectFile =
|
|
45357
|
-
if (!
|
|
45358
|
-
const userFile =
|
|
45370
|
+
const projectFile = join41(runtime.dirs.workspace, "update.yaml");
|
|
45371
|
+
if (!existsSync31(projectFile)) return;
|
|
45372
|
+
const userFile = join41(vnextUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
45359
45373
|
runtime.io.stderr(`kxm: ignoring .kxm/update.yaml in ${runtime.dirs.workdir}; update settings are read only from ${userFile}
|
|
45360
45374
|
`);
|
|
45361
45375
|
}
|
|
45362
45376
|
async function refreshKxmUpdateNotice(runtime, config) {
|
|
45363
45377
|
const resolved = config ?? loadKxmUpdateConfig(runtime.env);
|
|
45364
|
-
const current = readInstalledKxmVersion(
|
|
45378
|
+
const current = readInstalledKxmVersion(resolve24("."));
|
|
45365
45379
|
const fetched = await fetchLatestKxmVersion(resolved.source, runtime.env, runtime.fetchImpl);
|
|
45366
45380
|
const notice = noticeFromVersions(current, fetched.latest, resolved, fetched.error, fetched.asset);
|
|
45367
45381
|
writeUpdateCache(runtime.dirs.state, notice);
|
|
@@ -45381,7 +45395,7 @@ async function cmdDash(runtime, options = {}) {
|
|
|
45381
45395
|
return 2;
|
|
45382
45396
|
}
|
|
45383
45397
|
const screen = requested;
|
|
45384
|
-
const dataPath =
|
|
45398
|
+
const dataPath = resolve24(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join41(runtime.dirs.state, "kxm.db"));
|
|
45385
45399
|
if (runtime.dryRun) {
|
|
45386
45400
|
print(runtime.io, runtime.json, {
|
|
45387
45401
|
ok: true,
|
|
@@ -45427,7 +45441,7 @@ async function cmdHub(runtime) {
|
|
|
45427
45441
|
config = loadKxmUpdateConfig(runtime.env);
|
|
45428
45442
|
} catch (error) {
|
|
45429
45443
|
if (error instanceof KxmUpdateConfigError) {
|
|
45430
|
-
const yamlPath =
|
|
45444
|
+
const yamlPath = join41(vnextUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
45431
45445
|
runtime.io.stderr(`kxm: ${error.message}; update check skipped; fix or remove ${yamlPath}
|
|
45432
45446
|
`);
|
|
45433
45447
|
} else {
|
|
@@ -45563,7 +45577,7 @@ async function cmdWorker(runtime, options) {
|
|
|
45563
45577
|
return await (runtime.io.spawnWorker ?? ((launchEnv) => spawnScript("kxm-worker.mjs", launchEnv)))(extraEnv);
|
|
45564
45578
|
}
|
|
45565
45579
|
async function cmdStop(runtime, waitMsFlag) {
|
|
45566
|
-
const pids =
|
|
45580
|
+
const pids = existsSync31(runtime.dirs.state) ? readdirSync12(runtime.dirs.state).filter((name) => name.endsWith(".pid")) : [];
|
|
45567
45581
|
if (runtime.dryRun) {
|
|
45568
45582
|
print(runtime.io, runtime.json, { ok: true, command: "stop", dryRun: true, pidFiles: pids }, "would signal pid files");
|
|
45569
45583
|
return 0;
|
|
@@ -45578,7 +45592,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45578
45592
|
const orphans = [];
|
|
45579
45593
|
for (const file of pids) {
|
|
45580
45594
|
try {
|
|
45581
|
-
const record = JSON.parse(readFileSync31(
|
|
45595
|
+
const record = JSON.parse(readFileSync31(join41(runtime.dirs.state, file), "utf8"));
|
|
45582
45596
|
const expectedControl = file === "hub.pid" ? "hub.stop" : file.startsWith("worker-") ? `${file.slice(0, -4)}.stop` : void 0;
|
|
45583
45597
|
const expectedRole = file === "hub.pid" ? "hub" : file.startsWith("worker-") ? "worker" : void 0;
|
|
45584
45598
|
if (record.version !== 1 || !Number.isInteger(record.pid) || record.pid <= 0 || !record.startedAt || !expectedControl || record.controlFile !== expectedControl || record.role !== expectedRole) {
|
|
@@ -45598,7 +45612,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45598
45612
|
ignored.push(file);
|
|
45599
45613
|
continue;
|
|
45600
45614
|
}
|
|
45601
|
-
writeFileSync23(
|
|
45615
|
+
writeFileSync23(join41(runtime.dirs.state, record.controlFile), `${JSON.stringify({ startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {}, requestedAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
45602
45616
|
`, { encoding: "utf8", mode: 384 });
|
|
45603
45617
|
requested.push(file);
|
|
45604
45618
|
records.set(file, { pid: record.pid, startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {} });
|
|
@@ -45616,7 +45630,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45616
45630
|
while (Date.now() <= deadline && stopped.size < requested.length) {
|
|
45617
45631
|
for (const [file, record] of records) {
|
|
45618
45632
|
try {
|
|
45619
|
-
const current = JSON.parse(readFileSync31(
|
|
45633
|
+
const current = JSON.parse(readFileSync31(join41(runtime.dirs.state, file), "utf8"));
|
|
45620
45634
|
if (current.pid !== record.pid || current.startedAt !== record.startedAt || current.generation !== record.generation || !processExists(record.pid)) stopped.add(file);
|
|
45621
45635
|
} catch {
|
|
45622
45636
|
stopped.add(file);
|
|
@@ -45629,7 +45643,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45629
45643
|
for (const file of orphans) {
|
|
45630
45644
|
while (Date.now() <= deadlineOrphans) {
|
|
45631
45645
|
try {
|
|
45632
|
-
const current = JSON.parse(readFileSync31(
|
|
45646
|
+
const current = JSON.parse(readFileSync31(join41(runtime.dirs.state, file), "utf8"));
|
|
45633
45647
|
if (!Number.isInteger(current.serverPid) || !processExists(current.serverPid)) break;
|
|
45634
45648
|
} catch {
|
|
45635
45649
|
break;
|
|
@@ -45637,14 +45651,14 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45637
45651
|
await (runtime.io.sleep ?? ((ms) => new Promise((resolveSleep) => setTimeout(resolveSleep, ms))))(100);
|
|
45638
45652
|
}
|
|
45639
45653
|
try {
|
|
45640
|
-
const current = JSON.parse(readFileSync31(
|
|
45654
|
+
const current = JSON.parse(readFileSync31(join41(runtime.dirs.state, file), "utf8"));
|
|
45641
45655
|
if (Number.isInteger(current.serverPid) && processExists(current.serverPid)) {
|
|
45642
45656
|
try {
|
|
45643
45657
|
process.kill(current.serverPid, "SIGKILL");
|
|
45644
45658
|
} catch {
|
|
45645
45659
|
}
|
|
45646
45660
|
}
|
|
45647
|
-
rmSync10(
|
|
45661
|
+
rmSync10(join41(runtime.dirs.state, file), { force: true });
|
|
45648
45662
|
} catch {
|
|
45649
45663
|
}
|
|
45650
45664
|
stopped.add(file);
|
|
@@ -45655,11 +45669,11 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45655
45669
|
}
|
|
45656
45670
|
async function cmdSessionStatus(runtime) {
|
|
45657
45671
|
const stateDir = runtime.dirs.state;
|
|
45658
|
-
const names3 =
|
|
45672
|
+
const names3 = existsSync31(stateDir) ? readdirSync12(stateDir) : [];
|
|
45659
45673
|
const claims = [];
|
|
45660
45674
|
for (const file of names3.filter((name) => name.endsWith(".pid"))) {
|
|
45661
45675
|
try {
|
|
45662
|
-
const record = JSON.parse(readFileSync31(
|
|
45676
|
+
const record = JSON.parse(readFileSync31(join41(stateDir, file), "utf8"));
|
|
45663
45677
|
claims.push({
|
|
45664
45678
|
file,
|
|
45665
45679
|
role: record.role,
|
|
@@ -45674,7 +45688,7 @@ async function cmdSessionStatus(runtime) {
|
|
|
45674
45688
|
const recoveries = [];
|
|
45675
45689
|
for (const file of names3.filter((name) => name.startsWith("worker-recovery-") && name.endsWith(".json"))) {
|
|
45676
45690
|
try {
|
|
45677
|
-
const envelope = JSON.parse(readFileSync31(
|
|
45691
|
+
const envelope = JSON.parse(readFileSync31(join41(stateDir, file), "utf8"));
|
|
45678
45692
|
recoveries.push({
|
|
45679
45693
|
file,
|
|
45680
45694
|
reason: envelope.reason,
|
|
@@ -45779,7 +45793,7 @@ async function cmdSessionBrief(runtime, options = {}) {
|
|
|
45779
45793
|
print(runtime.io, runtime.json, { ok: true, command: "session brief", sessionToken }, sessionToken);
|
|
45780
45794
|
return 0;
|
|
45781
45795
|
}
|
|
45782
|
-
const dataPath =
|
|
45796
|
+
const dataPath = resolve24(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join41(runtime.dirs.state, "kxm.db"));
|
|
45783
45797
|
const env = {
|
|
45784
45798
|
...runtime.env,
|
|
45785
45799
|
KXM_STATE_DIR: runtime.dirs.state,
|
|
@@ -45871,16 +45885,15 @@ async function cmdSessionStart(runtime, options) {
|
|
|
45871
45885
|
// plugins/kxm/src/cli/system.ts
|
|
45872
45886
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
45873
45887
|
import { createHash as createHash16 } from "node:crypto";
|
|
45874
|
-
import { existsSync as
|
|
45888
|
+
import { existsSync as existsSync37, mkdtempSync as mkdtempSync2, readFileSync as readFileSync36, rmSync as rmSync12 } from "node:fs";
|
|
45875
45889
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
45876
|
-
import { join as
|
|
45890
|
+
import { join as join47, resolve as resolve28 } from "node:path";
|
|
45877
45891
|
import { createInterface as createInterface3 } from "node:readline";
|
|
45878
|
-
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
45879
45892
|
|
|
45880
45893
|
// plugins/kxm/src/improve.ts
|
|
45881
45894
|
import { createHash as createHash15 } from "node:crypto";
|
|
45882
|
-
import { existsSync as
|
|
45883
|
-
import { join as
|
|
45895
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync26, writeFileSync as writeFileSync24 } from "node:fs";
|
|
45896
|
+
import { join as join42, relative as relative6, resolve as resolve25 } from "node:path";
|
|
45884
45897
|
var CANDIDATE_SCHEMA = "kxm.candidate.v1";
|
|
45885
45898
|
var IMPROVEMENT_REPORT_SCHEMA = "kxm.improvement-report.v2";
|
|
45886
45899
|
function classifyCandidateKind(stepId, agentRole) {
|
|
@@ -46051,8 +46064,8 @@ function groupRoutingRecords(records, options = {}) {
|
|
|
46051
46064
|
});
|
|
46052
46065
|
}
|
|
46053
46066
|
function buildImprovementReport(records, options = {}) {
|
|
46054
|
-
const projectRoot = options.projectRoot ?
|
|
46055
|
-
const candidatesDir = options.candidatesDir ?
|
|
46067
|
+
const projectRoot = options.projectRoot ? resolve25(options.projectRoot) : process.cwd();
|
|
46068
|
+
const candidatesDir = options.candidatesDir ? resolve25(options.candidatesDir) : join42(projectRoot, ".kxm", "candidates");
|
|
46056
46069
|
const groups = groupRoutingRecords(records, options);
|
|
46057
46070
|
const candidates = [];
|
|
46058
46071
|
for (const group of groups) {
|
|
@@ -46064,7 +46077,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46064
46077
|
group.workflowHash
|
|
46065
46078
|
);
|
|
46066
46079
|
const diffFileName = `${group.candidateId}.diff`;
|
|
46067
|
-
const diffFilePath =
|
|
46080
|
+
const diffFilePath = join42(candidatesDir, diffFileName);
|
|
46068
46081
|
const relDiffPath = relative6(projectRoot, diffFilePath).replace(/\\/g, "/");
|
|
46069
46082
|
const candidate = {
|
|
46070
46083
|
schema: CANDIDATE_SCHEMA,
|
|
@@ -46086,11 +46099,11 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46086
46099
|
createdAt: nowIso()
|
|
46087
46100
|
};
|
|
46088
46101
|
if (!options.dryRun) {
|
|
46089
|
-
if (!
|
|
46102
|
+
if (!existsSync32(candidatesDir)) {
|
|
46090
46103
|
mkdirSync26(candidatesDir, { recursive: true });
|
|
46091
46104
|
}
|
|
46092
46105
|
writeFileSync24(diffFilePath, diff, "utf8");
|
|
46093
|
-
const jsonFilePath =
|
|
46106
|
+
const jsonFilePath = join42(candidatesDir, `${group.candidateId}.json`);
|
|
46094
46107
|
writeFileSync24(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
|
|
46095
46108
|
}
|
|
46096
46109
|
candidates.push(candidate);
|
|
@@ -46106,7 +46119,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46106
46119
|
}
|
|
46107
46120
|
function writeImprovementReport(improvementsDir, report2, dryRun = false) {
|
|
46108
46121
|
const stamp = report2.createdAt.replace(/[:.]/g, "-");
|
|
46109
|
-
const path4 =
|
|
46122
|
+
const path4 = join42(improvementsDir, `${stamp}.json`);
|
|
46110
46123
|
if (!dryRun) {
|
|
46111
46124
|
mkdirSync26(improvementsDir, { recursive: true });
|
|
46112
46125
|
writeFileSync24(path4, `${JSON.stringify(report2, null, 2)}
|
|
@@ -46149,8 +46162,8 @@ function formatImprovementReport(report2) {
|
|
|
46149
46162
|
|
|
46150
46163
|
// plugins/kxm/src/modes.ts
|
|
46151
46164
|
var import_yaml17 = __toESM(require_dist(), 1);
|
|
46152
|
-
import { existsSync as
|
|
46153
|
-
import { join as
|
|
46165
|
+
import { existsSync as existsSync33, readFileSync as readFileSync33 } from "node:fs";
|
|
46166
|
+
import { join as join43 } from "node:path";
|
|
46154
46167
|
var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
46155
46168
|
schema: "kxm.modes.v1",
|
|
46156
46169
|
majorModes: {
|
|
@@ -46213,8 +46226,8 @@ function loadModesConfig(projectRoot) {
|
|
|
46213
46226
|
if (!projectRoot) {
|
|
46214
46227
|
return DEFAULT_MODES_CONFIG;
|
|
46215
46228
|
}
|
|
46216
|
-
const modesPath =
|
|
46217
|
-
if (!
|
|
46229
|
+
const modesPath = join43(projectRoot, ".kxm", "modes.yaml");
|
|
46230
|
+
if (!existsSync33(modesPath)) {
|
|
46218
46231
|
return DEFAULT_MODES_CONFIG;
|
|
46219
46232
|
}
|
|
46220
46233
|
try {
|
|
@@ -46304,9 +46317,9 @@ function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog
|
|
|
46304
46317
|
estimatedTokens: estimateTokens(baseSystemPromptChars)
|
|
46305
46318
|
});
|
|
46306
46319
|
for (const relPath of resolved.contextFiles) {
|
|
46307
|
-
const fullPath =
|
|
46320
|
+
const fullPath = join43(projectRoot, relPath);
|
|
46308
46321
|
let chars = 0;
|
|
46309
|
-
if (
|
|
46322
|
+
if (existsSync33(fullPath)) {
|
|
46310
46323
|
try {
|
|
46311
46324
|
chars = readFileSync33(fullPath, "utf8").length;
|
|
46312
46325
|
} catch {
|
|
@@ -46440,9 +46453,9 @@ ${divider}
|
|
|
46440
46453
|
|
|
46441
46454
|
// plugins/kxm/src/ssh-remote.ts
|
|
46442
46455
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
46443
|
-
import { existsSync as
|
|
46456
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync27, readFileSync as readFileSync34, readdirSync as readdirSync13, rmSync as rmSync11, statSync as statSync5 } from "node:fs";
|
|
46444
46457
|
import { homedir as homedir7 } from "node:os";
|
|
46445
|
-
import { join as
|
|
46458
|
+
import { join as join44, resolve as resolve26 } from "node:path";
|
|
46446
46459
|
var MAX_SSH_OUTPUT_BYTES = 50 * 1024;
|
|
46447
46460
|
var MAX_SSH_OUTPUT_LINES = 2e3;
|
|
46448
46461
|
var DEFAULT_SOCKET_DIR = ".kxm/run/ssh-sockets";
|
|
@@ -46468,8 +46481,8 @@ function truncateSshOutput(raw) {
|
|
|
46468
46481
|
return { text, truncated };
|
|
46469
46482
|
}
|
|
46470
46483
|
function parseSshConfig(configPath) {
|
|
46471
|
-
const targetPath = configPath ??
|
|
46472
|
-
if (!
|
|
46484
|
+
const targetPath = configPath ?? join44(homedir7(), ".ssh", "config");
|
|
46485
|
+
if (!existsSync34(targetPath)) {
|
|
46473
46486
|
return [];
|
|
46474
46487
|
}
|
|
46475
46488
|
try {
|
|
@@ -46550,15 +46563,15 @@ function resolveSshHostG(host, execFn = spawnSync7) {
|
|
|
46550
46563
|
}
|
|
46551
46564
|
}
|
|
46552
46565
|
function ensureSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
46553
|
-
const resolved =
|
|
46554
|
-
if (!
|
|
46566
|
+
const resolved = resolve26(socketDir);
|
|
46567
|
+
if (!existsSync34(resolved)) {
|
|
46555
46568
|
mkdirSync27(resolved, { recursive: true, mode: 448 });
|
|
46556
46569
|
}
|
|
46557
46570
|
return resolved;
|
|
46558
46571
|
}
|
|
46559
46572
|
function buildSshArgs(options) {
|
|
46560
46573
|
const socketDir = ensureSocketDir(options.socketDir ?? DEFAULT_SOCKET_DIR);
|
|
46561
|
-
const controlPath =
|
|
46574
|
+
const controlPath = join44(socketDir, "%C");
|
|
46562
46575
|
const persist = options.controlPersist ?? DEFAULT_CONTROL_PERSIST;
|
|
46563
46576
|
const args = [
|
|
46564
46577
|
"-o",
|
|
@@ -46583,7 +46596,7 @@ function buildSshArgs(options) {
|
|
|
46583
46596
|
}
|
|
46584
46597
|
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
46585
46598
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
46586
|
-
const controlPath =
|
|
46599
|
+
const controlPath = join44(resolvedDir, "%C");
|
|
46587
46600
|
try {
|
|
46588
46601
|
const result = execFn("ssh", ["-O", "check", "-o", `ControlPath=${controlPath}`, host], {
|
|
46589
46602
|
encoding: "utf-8"
|
|
@@ -46595,7 +46608,7 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
46595
46608
|
}
|
|
46596
46609
|
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
46597
46610
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
46598
|
-
const controlPath =
|
|
46611
|
+
const controlPath = join44(resolvedDir, "%C");
|
|
46599
46612
|
try {
|
|
46600
46613
|
const result = execFn("ssh", ["-O", "stop", "-o", `ControlPath=${controlPath}`, host], {
|
|
46601
46614
|
encoding: "utf-8"
|
|
@@ -47041,9 +47054,9 @@ complete -c kxm -n "__fish_seen_subcommand_from goal" -a "create list get"
|
|
|
47041
47054
|
}
|
|
47042
47055
|
|
|
47043
47056
|
// plugins/kxm/src/completion-install.ts
|
|
47044
|
-
import { existsSync as
|
|
47057
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync28, readFileSync as readFileSync35, writeFileSync as writeFileSync25 } from "node:fs";
|
|
47045
47058
|
import { homedir as homedir8 } from "node:os";
|
|
47046
|
-
import { basename as basename9, delimiter, dirname as dirname21, isAbsolute as isAbsolute8, join as
|
|
47059
|
+
import { basename as basename9, delimiter, dirname as dirname21, isAbsolute as isAbsolute8, join as join45, resolve as resolve27 } from "node:path";
|
|
47047
47060
|
var COMPLETION_MARKER = "# kxm completion";
|
|
47048
47061
|
var PATH_MARKER = "# kxm path";
|
|
47049
47062
|
function detectShell(env = process.env, platform = process.platform) {
|
|
@@ -47059,31 +47072,31 @@ function effectiveHome(options) {
|
|
|
47059
47072
|
const env = options.env ?? process.env;
|
|
47060
47073
|
if (options.homeDir) return options.homeDir;
|
|
47061
47074
|
const envHome = env.HOME?.trim() ?? env.USERPROFILE?.trim();
|
|
47062
|
-
return envHome && envHome.length > 0 ?
|
|
47075
|
+
return envHome && envHome.length > 0 ? resolve27(envHome) : homedir8();
|
|
47063
47076
|
}
|
|
47064
47077
|
function completionScriptPath(shell, options = {}) {
|
|
47065
47078
|
const env = options.env ?? process.env;
|
|
47066
47079
|
const explicit = options.configDir ?? env.KXM_USER_CONFIG_DIR?.trim();
|
|
47067
|
-
const base = explicit && explicit.length > 0 ?
|
|
47068
|
-
return
|
|
47080
|
+
const base = explicit && explicit.length > 0 ? resolve27(explicit) : resolve27(effectiveHome(options), ".config", "kxm");
|
|
47081
|
+
return join45(base, "completions", `kxm.${shell}`);
|
|
47069
47082
|
}
|
|
47070
47083
|
function bashRcCandidate(options) {
|
|
47071
47084
|
const home = effectiveHome(options);
|
|
47072
|
-
const candidates = [
|
|
47073
|
-
const existing = candidates.find((candidate) =>
|
|
47085
|
+
const candidates = [join45(home, ".bashrc"), join45(home, ".bash_profile")];
|
|
47086
|
+
const existing = candidates.find((candidate) => existsSync35(candidate));
|
|
47074
47087
|
return existing ?? candidates[0];
|
|
47075
47088
|
}
|
|
47076
47089
|
function zshRcCandidate(options) {
|
|
47077
47090
|
const env = options.env ?? process.env;
|
|
47078
47091
|
const home = effectiveHome(options);
|
|
47079
|
-
if (env.ZDOTDIR?.trim()) return
|
|
47080
|
-
return
|
|
47092
|
+
if (env.ZDOTDIR?.trim()) return join45(resolve27(env.ZDOTDIR.trim()), ".zshrc");
|
|
47093
|
+
return join45(home, ".zshrc");
|
|
47081
47094
|
}
|
|
47082
47095
|
function fishCompletionTarget(shell, options) {
|
|
47083
47096
|
const env = options.env ?? process.env;
|
|
47084
47097
|
const home = effectiveHome(options);
|
|
47085
|
-
if (env.XDG_CONFIG_HOME?.trim()) return
|
|
47086
|
-
return
|
|
47098
|
+
if (env.XDG_CONFIG_HOME?.trim()) return join45(resolve27(env.XDG_CONFIG_HOME.trim()), "fish", "completions", "kxm.fish");
|
|
47099
|
+
return join45(home, ".config", "fish", "completions", "kxm.fish");
|
|
47087
47100
|
}
|
|
47088
47101
|
function completionRcTarget(shell, options = {}) {
|
|
47089
47102
|
if (shell === "fish") {
|
|
@@ -47115,16 +47128,16 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47115
47128
|
const scriptPath = completionScriptPath(shell, options);
|
|
47116
47129
|
const { rcFile } = completionRcTarget(shell, options);
|
|
47117
47130
|
const script = generateShellCompletion(shell);
|
|
47118
|
-
const existingScript =
|
|
47131
|
+
const existingScript = existsSync35(scriptPath);
|
|
47119
47132
|
const existingScriptMatches = existingScript && readFileSync35(scriptPath, "utf8") === script;
|
|
47120
47133
|
let rcModified = false;
|
|
47121
47134
|
let alreadyInstalled = false;
|
|
47122
47135
|
if (shell === "fish") {
|
|
47123
47136
|
const fishTarget = fishCompletionTarget(shell, options);
|
|
47124
|
-
const fishInstalled =
|
|
47137
|
+
const fishInstalled = existsSync35(fishTarget) && readFileSync35(fishTarget, "utf8") === script;
|
|
47125
47138
|
alreadyInstalled = fishInstalled;
|
|
47126
47139
|
if (!options.dryRun && (!fishInstalled || options.overwrite)) {
|
|
47127
|
-
mkdirSync28(
|
|
47140
|
+
mkdirSync28(resolve27(fishTarget, ".."), { recursive: true });
|
|
47128
47141
|
writeFileSync25(fishTarget, script, { encoding: "utf8" });
|
|
47129
47142
|
}
|
|
47130
47143
|
return {
|
|
@@ -47138,12 +47151,12 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47138
47151
|
}
|
|
47139
47152
|
if (rcFile) {
|
|
47140
47153
|
const line = sourceLine(shell, scriptPath);
|
|
47141
|
-
const rcContent =
|
|
47154
|
+
const rcContent = existsSync35(rcFile) ? readFileSync35(rcFile, "utf8") : "";
|
|
47142
47155
|
alreadyInstalled = rcContent.includes(line) || rcContent.includes(`${COMPLETION_MARKER}`);
|
|
47143
47156
|
}
|
|
47144
47157
|
if (!options.dryRun) {
|
|
47145
47158
|
if (!existingScriptMatches || options.overwrite) {
|
|
47146
|
-
mkdirSync28(
|
|
47159
|
+
mkdirSync28(resolve27(scriptPath, ".."), { recursive: true });
|
|
47147
47160
|
writeFileSync25(scriptPath, script, { encoding: "utf8" });
|
|
47148
47161
|
}
|
|
47149
47162
|
if (rcFile && !alreadyInstalled) {
|
|
@@ -47153,8 +47166,8 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47153
47166
|
${marker}
|
|
47154
47167
|
${line}
|
|
47155
47168
|
`;
|
|
47156
|
-
mkdirSync28(
|
|
47157
|
-
writeFileSync25(rcFile, (
|
|
47169
|
+
mkdirSync28(resolve27(rcFile, ".."), { recursive: true });
|
|
47170
|
+
writeFileSync25(rcFile, (existsSync35(rcFile) ? readFileSync35(rcFile, "utf8") : "") + stanza, { encoding: "utf8" });
|
|
47158
47171
|
rcModified = true;
|
|
47159
47172
|
}
|
|
47160
47173
|
}
|
|
@@ -47171,13 +47184,13 @@ function kxmBinDir(env = process.env) {
|
|
|
47171
47184
|
const argv1 = env.KXM_ENTRY ?? process.argv[1];
|
|
47172
47185
|
if (argv1 && isAbsolute8(argv1)) {
|
|
47173
47186
|
const dir = dirname21(argv1);
|
|
47174
|
-
if (
|
|
47187
|
+
if (existsSync35(join45(dir, process.platform === "win32" ? "kxm.cmd" : "kxm"))) return dir;
|
|
47175
47188
|
}
|
|
47176
47189
|
const pathEnv = env.PATH ?? "";
|
|
47177
47190
|
for (const part of pathEnv.split(delimiter)) {
|
|
47178
47191
|
if (!part) continue;
|
|
47179
|
-
const candidate =
|
|
47180
|
-
if (
|
|
47192
|
+
const candidate = resolve27(part, process.platform === "win32" ? "kxm.cmd" : "kxm");
|
|
47193
|
+
if (existsSync35(candidate)) return resolve27(part);
|
|
47181
47194
|
}
|
|
47182
47195
|
return void 0;
|
|
47183
47196
|
}
|
|
@@ -47195,7 +47208,7 @@ function installPathEntry(shellInput, options = {}) {
|
|
|
47195
47208
|
}
|
|
47196
47209
|
const { rcFile } = completionRcTarget(shell, options);
|
|
47197
47210
|
const line = pathLine(binDir);
|
|
47198
|
-
const rcContent =
|
|
47211
|
+
const rcContent = existsSync35(rcFile ?? "") ? readFileSync35(rcFile, "utf8") : "";
|
|
47199
47212
|
const alreadyInstalled = rcContent.includes(binDir) || (options.env?.PATH ?? process.env.PATH ?? "").split(delimiter).includes(binDir);
|
|
47200
47213
|
if (!options.dryRun && rcFile && !alreadyInstalled) {
|
|
47201
47214
|
mkdirSync28(dirname21(rcFile), { recursive: true });
|
|
@@ -47209,8 +47222,8 @@ ${line}
|
|
|
47209
47222
|
|
|
47210
47223
|
// plugins/kxm/src/init-guide-setup.ts
|
|
47211
47224
|
var import_yaml18 = __toESM(require_dist(), 1);
|
|
47212
|
-
import { existsSync as
|
|
47213
|
-
import { dirname as dirname22, join as
|
|
47225
|
+
import { existsSync as existsSync36, mkdirSync as mkdirSync29, writeFileSync as writeFileSync26 } from "node:fs";
|
|
47226
|
+
import { dirname as dirname22, join as join46 } from "node:path";
|
|
47214
47227
|
var NATIVE_VENDOR_HARNESS = Object.freeze({
|
|
47215
47228
|
anthropic: "claude",
|
|
47216
47229
|
openai: "codex",
|
|
@@ -47609,13 +47622,13 @@ function renderGuideSetupFiles(projectRoot, plan) {
|
|
|
47609
47622
|
const stage = roleStages.get(role);
|
|
47610
47623
|
if (!stage) continue;
|
|
47611
47624
|
files.push({
|
|
47612
|
-
path:
|
|
47625
|
+
path: join46(projectRoot, ".kxm", "agents", `${role}.yaml`),
|
|
47613
47626
|
content: (0, import_yaml18.stringify)(agentDocument(role, stage, binding))
|
|
47614
47627
|
});
|
|
47615
47628
|
}
|
|
47616
47629
|
for (const workflow of plan.workflows) {
|
|
47617
47630
|
files.push({
|
|
47618
|
-
path:
|
|
47631
|
+
path: join46(projectRoot, ".kxm", "workflows", `${workflow.slug}.yaml`),
|
|
47619
47632
|
content: (0, import_yaml18.stringify)(workflowDocument(workflow))
|
|
47620
47633
|
});
|
|
47621
47634
|
}
|
|
@@ -47625,7 +47638,7 @@ function writeGuideSetupFiles(files) {
|
|
|
47625
47638
|
const written = [];
|
|
47626
47639
|
const existed = [];
|
|
47627
47640
|
for (const file of files) {
|
|
47628
|
-
if (
|
|
47641
|
+
if (existsSync36(file.path)) {
|
|
47629
47642
|
existed.push(file.path);
|
|
47630
47643
|
continue;
|
|
47631
47644
|
}
|
|
@@ -47653,7 +47666,6 @@ function parseGuideSelection(input, catalog = GUIDE_WORKFLOWS) {
|
|
|
47653
47666
|
}
|
|
47654
47667
|
|
|
47655
47668
|
// plugins/kxm/src/cli/system.ts
|
|
47656
|
-
var repoRoot4 = resolve29(fileURLToPath7(new URL("../../../../", import.meta.url)));
|
|
47657
47669
|
function cliSpawn(runtime, command, args, extra) {
|
|
47658
47670
|
if (runtime.io.spawnSync) return runtime.io.spawnSync(command, args);
|
|
47659
47671
|
const result = spawnSync8(command, [...args], {
|
|
@@ -47694,7 +47706,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
47694
47706
|
detail: `release v${notice.latest} has no sha256 digest for ${name}; refusing to install`
|
|
47695
47707
|
};
|
|
47696
47708
|
}
|
|
47697
|
-
const releaseDir = mkdtempSync2(
|
|
47709
|
+
const releaseDir = mkdtempSync2(join47(tmpdir2(), "kxm-pkg-update-"));
|
|
47698
47710
|
try {
|
|
47699
47711
|
const planned = planKxmPackageUpdate(notice.source, notice.latest, releaseDir, notice.asset);
|
|
47700
47712
|
if (runtime.dryRun) {
|
|
@@ -47703,7 +47715,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
47703
47715
|
for (const step of planned) {
|
|
47704
47716
|
if (step.kind === "verify") {
|
|
47705
47717
|
if (!verifyReleaseAssetDigest(step.path, step.sha256)) {
|
|
47706
|
-
const actual =
|
|
47718
|
+
const actual = existsSync37(step.path) ? createHash16("sha256").update(readFileSync36(step.path)).digest("hex") : "missing";
|
|
47707
47719
|
return {
|
|
47708
47720
|
ok: false,
|
|
47709
47721
|
error: "release_digest_mismatch",
|
|
@@ -47822,7 +47834,7 @@ async function cmdUpdate(runtime, harness, options) {
|
|
|
47822
47834
|
warnIgnoredProjectUpdateYaml(runtime);
|
|
47823
47835
|
const probe = installProbeFrom(runtime);
|
|
47824
47836
|
const classified = classifyInstallRoot(probe);
|
|
47825
|
-
const current = readInstalledKxmVersion(
|
|
47837
|
+
const current = readInstalledKxmVersion(findKxmRepoRoot(import.meta.url));
|
|
47826
47838
|
let notice;
|
|
47827
47839
|
let kindReport = classified;
|
|
47828
47840
|
if (classified.kind === "source") {
|
|
@@ -47968,8 +47980,8 @@ async function cmdValidate(runtime, fileFlag) {
|
|
|
47968
47980
|
return 2;
|
|
47969
47981
|
}
|
|
47970
47982
|
const selectedFile = explicitFile || configuredFile;
|
|
47971
|
-
const file = selectedFile ?
|
|
47972
|
-
if (file && !
|
|
47983
|
+
const file = selectedFile ? resolve28(runtime.cwd, selectedFile) : void 0;
|
|
47984
|
+
if (file && !existsSync37(file)) {
|
|
47973
47985
|
printWorker(runtime, worker, { ok: false, command: "validate", error: "file_not_found", file }, `workflow file not found: ${file}`);
|
|
47974
47986
|
return 1;
|
|
47975
47987
|
}
|
|
@@ -47999,7 +48011,7 @@ async function cmdValidate(runtime, fileFlag) {
|
|
|
47999
48011
|
}
|
|
48000
48012
|
async function cmdArtifactsExist(runtime, pathFlag) {
|
|
48001
48013
|
const worker = gateOf(runtime, "artifacts-exist");
|
|
48002
|
-
const checked = verifyArtifactExists(runtime.dirs.assets,
|
|
48014
|
+
const checked = verifyArtifactExists(runtime.dirs.assets, resolve28(runtime.cwd, pathFlag));
|
|
48003
48015
|
if (!checked.ok) {
|
|
48004
48016
|
printWorker(
|
|
48005
48017
|
runtime,
|
|
@@ -48018,15 +48030,15 @@ async function cmdArtifactsExist(runtime, pathFlag) {
|
|
|
48018
48030
|
return 0;
|
|
48019
48031
|
}
|
|
48020
48032
|
async function cmdImprove(runtime, options = {}) {
|
|
48021
|
-
const file = options.file ?
|
|
48022
|
-
const routingRecords =
|
|
48023
|
-
const candidatesDir = options.outDir ?
|
|
48033
|
+
const file = options.file ? resolve28(runtime.cwd, options.file) : telemetryPath(runtime.dirs.logs);
|
|
48034
|
+
const routingRecords = existsSync37(file) ? readRoutingRecords(file).map((entry) => entry.routing) : [];
|
|
48035
|
+
const candidatesDir = options.outDir ? resolve28(runtime.cwd, options.outDir) : join47(runtime.cwd, ".kxm", "candidates");
|
|
48024
48036
|
const report2 = buildImprovementReport(routingRecords, {
|
|
48025
48037
|
candidatesDir,
|
|
48026
48038
|
projectRoot: runtime.cwd,
|
|
48027
48039
|
dryRun: runtime.dryRun
|
|
48028
48040
|
});
|
|
48029
|
-
const reportDir =
|
|
48041
|
+
const reportDir = join47(runtime.dirs.assets, "improvements");
|
|
48030
48042
|
const reportPath = writeImprovementReport(reportDir, report2, runtime.dryRun);
|
|
48031
48043
|
const text = formatImprovementReport(report2);
|
|
48032
48044
|
print(runtime.io, runtime.json, {
|
|
@@ -48158,7 +48170,7 @@ async function maybeOfferCompletionInstall(runtime) {
|
|
|
48158
48170
|
if (!pathNeeded) {
|
|
48159
48171
|
const scriptPath = completionScriptPath(shell, { env: runtime.env, configDir: runtime.env.KXM_USER_CONFIG_DIR });
|
|
48160
48172
|
const { rcFile } = completionRcTarget(shell, { env: runtime.env });
|
|
48161
|
-
if (rcFile &&
|
|
48173
|
+
if (rcFile && existsSync37(rcFile)) {
|
|
48162
48174
|
try {
|
|
48163
48175
|
if (readFileSync36(rcFile, "utf8").includes(scriptPath)) return;
|
|
48164
48176
|
} catch {
|
|
@@ -48292,7 +48304,7 @@ async function cmdRoutingReport(runtime, options) {
|
|
|
48292
48304
|
let catalog;
|
|
48293
48305
|
if (includeEquivalentListCost) {
|
|
48294
48306
|
try {
|
|
48295
|
-
const pricesPath = options.prices ?
|
|
48307
|
+
const pricesPath = options.prices ? resolve28(runtime.cwd, options.prices) : join47(runtime.dirs.workspace, "prices.yaml");
|
|
48296
48308
|
catalog = loadPriceCatalog(pricesPath);
|
|
48297
48309
|
} catch {
|
|
48298
48310
|
}
|
|
@@ -48376,7 +48388,6 @@ async function cmdRoutingBenchmark(runtime, options) {
|
|
|
48376
48388
|
|
|
48377
48389
|
// plugins/kxm/src/cli.ts
|
|
48378
48390
|
var CLI_NAME2 = "kxm";
|
|
48379
|
-
var repoRoot5 = resolve30(fileURLToPath8(new URL("../../../", import.meta.url)));
|
|
48380
48391
|
var USAGE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
48381
48392
|
"commander.help",
|
|
48382
48393
|
"commander.helpDisplayed",
|
|
@@ -48519,7 +48530,7 @@ function createProgram(ctx, result) {
|
|
|
48519
48530
|
};
|
|
48520
48531
|
};
|
|
48521
48532
|
const program2 = new Command(CLI_NAME2);
|
|
48522
|
-
program2.description("KontextMind local-first orchestration CLI").version(readInstalledKxmVersion(
|
|
48533
|
+
program2.description("KontextMind local-first orchestration CLI").version(readInstalledKxmVersion(findKxmRepoRoot(import.meta.url)), "-V, --version", "Print the installed kxm version").exitOverride().configureOutput({
|
|
48523
48534
|
writeOut: (text) => ctx.io.stdout(text),
|
|
48524
48535
|
writeErr: (text) => ctx.io.stderr(text)
|
|
48525
48536
|
}).helpCommand("help", "Show help");
|
|
@@ -48986,7 +48997,7 @@ async function runCli(argv, env = process.env, io = { stdout: (text) => process.
|
|
|
48986
48997
|
throw error;
|
|
48987
48998
|
}
|
|
48988
48999
|
}
|
|
48989
|
-
if (process.argv[1] &&
|
|
49000
|
+
if (process.argv[1] && resolve29(process.argv[1]) === fileURLToPath4(import.meta.url)) {
|
|
48990
49001
|
const code = await runCli(process.argv.slice(2));
|
|
48991
49002
|
process.exitCode = code;
|
|
48992
49003
|
}
|