@kontextmind/kxm 0.7.21 → 0.7.23
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 +925 -850
- package/plugins/kxm/dist/client.js +2 -2
- package/plugins/kxm/dist/extension.js +2 -2
- package/plugins/kxm/dist/mcp-server.js +106 -34
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/cli/hub.ts +2 -1
- package/plugins/kxm/src/cli.ts +3 -1
- package/plugins/kxm/src/client.ts +4 -2
- package/plugins/kxm/src/hub-env.ts +15 -0
- package/plugins/kxm/src/mcp-server.ts +5 -7
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 = resolve31.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 resolve31(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 resolve31(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: resolve31,
|
|
4205
4205
|
resolveComponent,
|
|
4206
4206
|
equal,
|
|
4207
4207
|
serialize,
|
|
@@ -14779,7 +14779,7 @@ var require_dist = __commonJS({
|
|
|
14779
14779
|
});
|
|
14780
14780
|
|
|
14781
14781
|
// plugins/kxm/src/cli.ts
|
|
14782
|
-
import { resolve as
|
|
14782
|
+
import { resolve as resolve30 } from "node:path";
|
|
14783
14783
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
14784
14784
|
|
|
14785
14785
|
// node_modules/commander/lib/error.js
|
|
@@ -19446,7 +19446,7 @@ var HubClient = class {
|
|
|
19446
19446
|
if (signal?.aborted) throw new MeshWaitError("aborted", messageId);
|
|
19447
19447
|
const message = await this.getMessage(messageId);
|
|
19448
19448
|
if (["replied", "cancelled", "expired", "error"].includes(message.status)) return message;
|
|
19449
|
-
await new Promise((
|
|
19449
|
+
await new Promise((resolve31, reject) => {
|
|
19450
19450
|
const onAbort = () => {
|
|
19451
19451
|
signal?.removeEventListener("abort", onAbort);
|
|
19452
19452
|
clearTimeout(timer);
|
|
@@ -19454,7 +19454,7 @@ var HubClient = class {
|
|
|
19454
19454
|
};
|
|
19455
19455
|
const timer = setTimeout(() => {
|
|
19456
19456
|
signal?.removeEventListener("abort", onAbort);
|
|
19457
|
-
|
|
19457
|
+
resolve31();
|
|
19458
19458
|
}, Math.min(500, Math.max(1, deadline - Date.now())));
|
|
19459
19459
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
19460
19460
|
if (signal?.aborted) onAbort();
|
|
@@ -19478,7 +19478,7 @@ var HubClient = class {
|
|
|
19478
19478
|
while (!this.stopped && this.agent) {
|
|
19479
19479
|
this.eventsAbort = new AbortController();
|
|
19480
19480
|
try {
|
|
19481
|
-
const response = await fetch(
|
|
19481
|
+
const response = await (this.options.fetchImpl ?? fetch)(
|
|
19482
19482
|
`${this.options.serverUrl.replace(/\/$/, "")}/v1/events?agentId=${encodeURIComponent(this.agent.id)}`,
|
|
19483
19483
|
{
|
|
19484
19484
|
headers: this.headers(),
|
|
@@ -19509,7 +19509,7 @@ var HubClient = class {
|
|
|
19509
19509
|
} catch (error) {
|
|
19510
19510
|
if (this.stopped || error instanceof Error && error.name === "AbortError") return;
|
|
19511
19511
|
}
|
|
19512
|
-
if (!this.stopped) await new Promise((
|
|
19512
|
+
if (!this.stopped) await new Promise((resolve31) => setTimeout(resolve31, this.options.reconnectMs));
|
|
19513
19513
|
}
|
|
19514
19514
|
}
|
|
19515
19515
|
headers(includeIdentity = true) {
|
|
@@ -19555,7 +19555,7 @@ var HubClient = class {
|
|
|
19555
19555
|
const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
|
|
19556
19556
|
let response;
|
|
19557
19557
|
try {
|
|
19558
|
-
response = await fetch(`${this.options.serverUrl.replace(/\/$/, "")}${path4}`, {
|
|
19558
|
+
response = await (this.options.fetchImpl ?? fetch)(`${this.options.serverUrl.replace(/\/$/, "")}${path4}`, {
|
|
19559
19559
|
...init,
|
|
19560
19560
|
signal,
|
|
19561
19561
|
headers: { ...this.headers(includeIdentity), ...init.headers ?? {} }
|
|
@@ -19590,14 +19590,88 @@ var HubClient = class {
|
|
|
19590
19590
|
}
|
|
19591
19591
|
};
|
|
19592
19592
|
|
|
19593
|
+
// plugins/kxm/src/hub-env.ts
|
|
19594
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
19595
|
+
import { homedir } from "node:os";
|
|
19596
|
+
import { dirname as dirname2, isAbsolute, join as join3, resolve } from "node:path";
|
|
19597
|
+
var HUB_ENV_SCHEMA = "kxm.hub-env.v1";
|
|
19598
|
+
var HubEnvError = class extends Error {
|
|
19599
|
+
constructor(message) {
|
|
19600
|
+
super(message);
|
|
19601
|
+
this.name = "HubEnvError";
|
|
19602
|
+
}
|
|
19603
|
+
};
|
|
19604
|
+
function resolveUserStateRoot(env) {
|
|
19605
|
+
const explicit = env.KXM_STATE_HOME?.trim();
|
|
19606
|
+
if (explicit) {
|
|
19607
|
+
if (!isAbsolute(explicit)) throw new HubEnvError("local_state_root_not_absolute");
|
|
19608
|
+
return resolve(explicit);
|
|
19609
|
+
}
|
|
19610
|
+
if (process.platform === "win32") {
|
|
19611
|
+
const localAppData = env.LOCALAPPDATA?.trim();
|
|
19612
|
+
const base2 = localAppData && isAbsolute(localAppData) ? localAppData : join3(homedir(), "AppData", "Local");
|
|
19613
|
+
return resolve(base2, "KXM");
|
|
19614
|
+
}
|
|
19615
|
+
if (process.platform === "darwin") return resolve(homedir(), "Library", "Application Support", "KXM");
|
|
19616
|
+
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
19617
|
+
const base = xdgState && isAbsolute(xdgState) ? xdgState : join3(homedir(), ".local", "state");
|
|
19618
|
+
return resolve(base, "kxm");
|
|
19619
|
+
}
|
|
19620
|
+
function hubEnvFile(env = process.env) {
|
|
19621
|
+
return join3(resolveUserStateRoot(env), "hub-env.json");
|
|
19622
|
+
}
|
|
19623
|
+
function readHubEnvRecord(env = process.env) {
|
|
19624
|
+
const file = hubEnvFile(env);
|
|
19625
|
+
if (!existsSync3(file)) return void 0;
|
|
19626
|
+
let parsed;
|
|
19627
|
+
try {
|
|
19628
|
+
parsed = JSON.parse(readFileSync2(file, "utf8"));
|
|
19629
|
+
} catch (error) {
|
|
19630
|
+
throw new HubEnvError(`hub env file is malformed at ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
19631
|
+
}
|
|
19632
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
19633
|
+
throw new HubEnvError(`hub env file is malformed at ${file}: expected a JSON object`);
|
|
19634
|
+
}
|
|
19635
|
+
const record = parsed;
|
|
19636
|
+
if (record.schema !== HUB_ENV_SCHEMA) {
|
|
19637
|
+
throw new HubEnvError(`hub env file at ${file} has unsupported schema ${String(record.schema)}`);
|
|
19638
|
+
}
|
|
19639
|
+
if (record.authToken !== void 0 && (typeof record.authToken !== "string" || record.authToken.trim().length === 0)) {
|
|
19640
|
+
throw new HubEnvError(`hub env file at ${file} has an invalid authToken`);
|
|
19641
|
+
}
|
|
19642
|
+
if (record.projectTokens !== void 0) {
|
|
19643
|
+
const tokens = record.projectTokens;
|
|
19644
|
+
if (!tokens || typeof tokens !== "object" || Array.isArray(tokens)) {
|
|
19645
|
+
throw new HubEnvError(`hub env file at ${file} has invalid projectTokens`);
|
|
19646
|
+
}
|
|
19647
|
+
for (const [project, token] of Object.entries(tokens)) {
|
|
19648
|
+
if (!project.trim() || typeof token !== "string" || !token.trim()) {
|
|
19649
|
+
throw new HubEnvError(`hub env file at ${file} has an empty project name or token`);
|
|
19650
|
+
}
|
|
19651
|
+
}
|
|
19652
|
+
}
|
|
19653
|
+
return {
|
|
19654
|
+
schema: HUB_ENV_SCHEMA,
|
|
19655
|
+
createdAt: typeof record.createdAt === "string" ? record.createdAt : "",
|
|
19656
|
+
...record.authToken !== void 0 ? { authToken: record.authToken } : {},
|
|
19657
|
+
...record.projectTokens !== void 0 ? { projectTokens: record.projectTokens } : {}
|
|
19658
|
+
};
|
|
19659
|
+
}
|
|
19660
|
+
function resolveClientHubAuthToken(env, project) {
|
|
19661
|
+
const envToken = env.KXM_AUTH_TOKEN?.trim();
|
|
19662
|
+
if (envToken) return envToken;
|
|
19663
|
+
const record = readHubEnvRecord(env);
|
|
19664
|
+
return record?.projectTokens?.[project]?.trim() || record?.authToken?.trim() || void 0;
|
|
19665
|
+
}
|
|
19666
|
+
|
|
19593
19667
|
// plugins/kxm/src/project-name.ts
|
|
19594
|
-
import { readFileSync as
|
|
19595
|
-
import { basename, join as
|
|
19668
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
19669
|
+
import { basename, join as join4 } from "node:path";
|
|
19596
19670
|
function defaultProjectName(cwd, env = process.env) {
|
|
19597
19671
|
const fromEnv = env.KXM_PROJECT?.trim();
|
|
19598
19672
|
if (fromEnv) return fromEnv;
|
|
19599
19673
|
try {
|
|
19600
|
-
const pkg = JSON.parse(
|
|
19674
|
+
const pkg = JSON.parse(readFileSync3(join4(cwd, "package.json"), "utf8"));
|
|
19601
19675
|
if (typeof pkg.name === "string" && pkg.name.trim().length > 0) return pkg.name.trim();
|
|
19602
19676
|
} catch {
|
|
19603
19677
|
}
|
|
@@ -19606,9 +19680,9 @@ function defaultProjectName(cwd, env = process.env) {
|
|
|
19606
19680
|
|
|
19607
19681
|
// plugins/kxm/src/commands.ts
|
|
19608
19682
|
import { createHash as createHash4, randomUUID as randomUUID2, timingSafeEqual } from "node:crypto";
|
|
19609
|
-
import { chmodSync, existsSync as
|
|
19610
|
-
import { homedir } from "node:os";
|
|
19611
|
-
import { dirname as
|
|
19683
|
+
import { chmodSync, existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
19684
|
+
import { homedir as homedir2 } from "node:os";
|
|
19685
|
+
import { dirname as dirname3, join as join5, resolve as resolve2 } from "node:path";
|
|
19612
19686
|
function requiredString(value, name) {
|
|
19613
19687
|
if (typeof value !== "string" || value.trim() === "") throw new Error(`${name} is required`);
|
|
19614
19688
|
return value.trim();
|
|
@@ -20356,18 +20430,18 @@ function parseSessionToken(token) {
|
|
|
20356
20430
|
return void 0;
|
|
20357
20431
|
}
|
|
20358
20432
|
function resolveUserConfigDirectory(overrideDir) {
|
|
20359
|
-
if (overrideDir) return
|
|
20360
|
-
return
|
|
20433
|
+
if (overrideDir) return resolve2(overrideDir);
|
|
20434
|
+
return resolve2(process.env.KXM_USER_CONFIG_DIR?.trim() || join5(homedir2(), ".config", "kxm"));
|
|
20361
20435
|
}
|
|
20362
20436
|
function sessionTokenPath(userConfigDir) {
|
|
20363
|
-
return
|
|
20437
|
+
return join5(resolveUserConfigDirectory(userConfigDir), "session.token");
|
|
20364
20438
|
}
|
|
20365
20439
|
function persistSessionTokenToDisk(token, options) {
|
|
20366
20440
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
20367
|
-
const dir =
|
|
20368
|
-
|
|
20441
|
+
const dir = dirname3(filePath);
|
|
20442
|
+
mkdirSync3(dir, { recursive: true, mode: 448 });
|
|
20369
20443
|
const mode = options?.mode ?? 384;
|
|
20370
|
-
|
|
20444
|
+
writeFileSync3(filePath, `${token.trim()}
|
|
20371
20445
|
`, { encoding: "utf8", mode });
|
|
20372
20446
|
try {
|
|
20373
20447
|
chmodSync(filePath, mode);
|
|
@@ -20377,9 +20451,9 @@ function persistSessionTokenToDisk(token, options) {
|
|
|
20377
20451
|
}
|
|
20378
20452
|
function readSessionTokenFromDisk(options) {
|
|
20379
20453
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
20380
|
-
if (!
|
|
20454
|
+
if (!existsSync4(filePath)) return void 0;
|
|
20381
20455
|
try {
|
|
20382
|
-
const token =
|
|
20456
|
+
const token = readFileSync4(filePath, "utf8").trim();
|
|
20383
20457
|
if (!token) return void 0;
|
|
20384
20458
|
const payload = parseSessionToken(token);
|
|
20385
20459
|
if (!payload) return void 0;
|
|
@@ -20390,7 +20464,7 @@ function readSessionTokenFromDisk(options) {
|
|
|
20390
20464
|
}
|
|
20391
20465
|
function clearSessionTokenFromDisk(options) {
|
|
20392
20466
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
20393
|
-
if (!
|
|
20467
|
+
if (!existsSync4(filePath)) return false;
|
|
20394
20468
|
try {
|
|
20395
20469
|
unlinkSync(filePath);
|
|
20396
20470
|
return true;
|
|
@@ -20489,10 +20563,10 @@ function enforceToolPolicy(commandName, env = process.env, options) {
|
|
|
20489
20563
|
return { allowed: true };
|
|
20490
20564
|
}
|
|
20491
20565
|
const tokenFile = sessionTokenPath(env.KXM_USER_CONFIG_DIR);
|
|
20492
|
-
if (
|
|
20566
|
+
if (existsSync4(tokenFile)) {
|
|
20493
20567
|
let tokenRaw;
|
|
20494
20568
|
try {
|
|
20495
|
-
tokenRaw =
|
|
20569
|
+
tokenRaw = readFileSync4(tokenFile, "utf8").trim();
|
|
20496
20570
|
} catch {
|
|
20497
20571
|
return { allowed: false, error: "session_token_invalid", detail: "Session token file on disk could not be read" };
|
|
20498
20572
|
}
|
|
@@ -20516,8 +20590,8 @@ function enforceToolPolicy(commandName, env = process.env, options) {
|
|
|
20516
20590
|
var import__ = __toESM(require__(), 1);
|
|
20517
20591
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
20518
20592
|
import { createHash as createHash6 } from "node:crypto";
|
|
20519
|
-
import { existsSync as
|
|
20520
|
-
import { basename as basename2, dirname as
|
|
20593
|
+
import { existsSync as existsSync6, lstatSync, readFileSync as readFileSync5, readdirSync, realpathSync } from "node:fs";
|
|
20594
|
+
import { basename as basename2, dirname as dirname4, extname, isAbsolute as isAbsolute2, join as join6, relative, resolve as resolve3, sep } from "node:path";
|
|
20521
20595
|
|
|
20522
20596
|
// plugins/kxm/src/restricted-yaml.mjs
|
|
20523
20597
|
var import_yaml = __toESM(require_dist(), 1);
|
|
@@ -20845,7 +20919,7 @@ function resolveVnextTemplateBaseline(value) {
|
|
|
20845
20919
|
|
|
20846
20920
|
// plugins/kxm/src/vnext-harness.ts
|
|
20847
20921
|
import { spawnSync } from "node:child_process";
|
|
20848
|
-
import { existsSync as
|
|
20922
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
20849
20923
|
import { win32 as win32Path } from "node:path";
|
|
20850
20924
|
|
|
20851
20925
|
// plugins/kxm/src/vnext-oneshot-process.ts
|
|
@@ -20871,7 +20945,7 @@ function defaultSpawn(command, args, options) {
|
|
|
20871
20945
|
if (options.signal?.aborted) {
|
|
20872
20946
|
return Promise.resolve({ stdout: "", stderr: "", code: null, started: false, observedChildExit: false, error: new Error("process_aborted") });
|
|
20873
20947
|
}
|
|
20874
|
-
return new Promise((
|
|
20948
|
+
return new Promise((resolve31) => {
|
|
20875
20949
|
const stdout = [];
|
|
20876
20950
|
const stderr = [];
|
|
20877
20951
|
let outputBytes = 0;
|
|
@@ -20902,7 +20976,7 @@ function defaultSpawn(command, args, options) {
|
|
|
20902
20976
|
const started = Boolean(child?.pid);
|
|
20903
20977
|
if (started && !observedChildExit) error ??= new Error("process_exit_unobserved");
|
|
20904
20978
|
const unverifiedDescendants = stopping || started && !observedChildExit;
|
|
20905
|
-
|
|
20979
|
+
resolve31({
|
|
20906
20980
|
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
20907
20981
|
stderr: Buffer.concat(stderr).toString("utf8"),
|
|
20908
20982
|
code,
|
|
@@ -21394,7 +21468,7 @@ function findWinNpmInnerExe(cliId, options = {}) {
|
|
|
21394
21468
|
if ((options.platform ?? process.platform) !== "win32") return void 0;
|
|
21395
21469
|
const segments = WIN_NPM_INNER_EXE[cliId];
|
|
21396
21470
|
if (!segments) return void 0;
|
|
21397
|
-
const exists = options.existsSync ??
|
|
21471
|
+
const exists = options.existsSync ?? existsSync5;
|
|
21398
21472
|
const pathEnv = options.pathEnv ?? process.env.PATH ?? "";
|
|
21399
21473
|
for (const dir of pathEnv.split(";").filter(Boolean)) {
|
|
21400
21474
|
if (!exists(win32Path.join(dir, `${cliId}.cmd`))) continue;
|
|
@@ -21912,7 +21986,7 @@ var VnextConfigError = class extends Error {
|
|
|
21912
21986
|
}
|
|
21913
21987
|
};
|
|
21914
21988
|
function defaultVnextSchemaDir() {
|
|
21915
|
-
return
|
|
21989
|
+
return join6(findKxmRepoRoot(import.meta.url), "schemas", "vnext");
|
|
21916
21990
|
}
|
|
21917
21991
|
var DEFAULT_SCHEMA_DIR = defaultVnextSchemaDir();
|
|
21918
21992
|
var RESOURCE_SCHEMA = Object.freeze({
|
|
@@ -21960,7 +22034,7 @@ function parseRestrictedYaml2(input, label = "<yaml>", limits = VNEXT_YAML_LIMIT
|
|
|
21960
22034
|
}
|
|
21961
22035
|
}
|
|
21962
22036
|
function readJsonObject(file) {
|
|
21963
|
-
const parsed = JSON.parse(
|
|
22037
|
+
const parsed = JSON.parse(readFileSync5(file, "utf8"));
|
|
21964
22038
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`${file} is not a JSON object`);
|
|
21965
22039
|
return parsed;
|
|
21966
22040
|
}
|
|
@@ -21977,12 +22051,12 @@ var VnextSchemaRegistry = class {
|
|
|
21977
22051
|
permissionDiffValidator;
|
|
21978
22052
|
runEventValidator;
|
|
21979
22053
|
constructor(schemasDir = DEFAULT_SCHEMA_DIR) {
|
|
21980
|
-
this.schemasDir =
|
|
22054
|
+
this.schemasDir = resolve3(schemasDir);
|
|
21981
22055
|
this.ajv = new import__.Ajv2020({ allErrors: true, strict: true, strictRequired: false });
|
|
21982
|
-
const common = readJsonObject(
|
|
22056
|
+
const common = readJsonObject(join6(this.schemasDir, "common.schema.json"));
|
|
21983
22057
|
this.ajv.addSchema(common);
|
|
21984
22058
|
for (const definition of Object.values(RESOURCE_SCHEMA)) {
|
|
21985
|
-
this.ajv.addSchema(readJsonObject(
|
|
22059
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, definition.file)));
|
|
21986
22060
|
}
|
|
21987
22061
|
const localBindingsFile = "local-repository-bindings.schema.json";
|
|
21988
22062
|
const templateProvenanceFile = "template-provenance.schema.json";
|
|
@@ -21992,14 +22066,14 @@ var VnextSchemaRegistry = class {
|
|
|
21992
22066
|
const migrationReceiptFile = "migration-receipt.schema.json";
|
|
21993
22067
|
const permissionDiffFile = "permission-diff.schema.json";
|
|
21994
22068
|
const runEventFile = "run-event.schema.json";
|
|
21995
|
-
this.ajv.addSchema(readJsonObject(
|
|
21996
|
-
this.ajv.addSchema(readJsonObject(
|
|
21997
|
-
this.ajv.addSchema(readJsonObject(
|
|
21998
|
-
this.ajv.addSchema(readJsonObject(
|
|
21999
|
-
this.ajv.addSchema(readJsonObject(
|
|
22000
|
-
this.ajv.addSchema(readJsonObject(
|
|
22001
|
-
this.ajv.addSchema(readJsonObject(
|
|
22002
|
-
this.ajv.addSchema(readJsonObject(
|
|
22069
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, localBindingsFile)));
|
|
22070
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, templateProvenanceFile)));
|
|
22071
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, initOperationFile)));
|
|
22072
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, migrationPlanFile)));
|
|
22073
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, migrationDecisionFile)));
|
|
22074
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, migrationReceiptFile)));
|
|
22075
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, permissionDiffFile)));
|
|
22076
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, runEventFile)));
|
|
22003
22077
|
for (const [kind, definition] of Object.entries(RESOURCE_SCHEMA)) {
|
|
22004
22078
|
const validator = this.ajv.getSchema(`https://schemas.kxm.dev/vnext/${definition.file}`);
|
|
22005
22079
|
if (!validator) throw new Error(`schema did not compile: ${definition.file}`);
|
|
@@ -22075,7 +22149,7 @@ function schemaIssue(file, error) {
|
|
|
22075
22149
|
return issue2("schema", `schema_${error.keyword}`, file, `${location} ${error.message ?? "is invalid"}${suffix}`);
|
|
22076
22150
|
}
|
|
22077
22151
|
function canonicalHostPath(path4) {
|
|
22078
|
-
const resolved =
|
|
22152
|
+
const resolved = resolve3(path4);
|
|
22079
22153
|
try {
|
|
22080
22154
|
return realpathSync.native(resolved);
|
|
22081
22155
|
} catch {
|
|
@@ -22089,20 +22163,20 @@ function sameHostPath(left, right) {
|
|
|
22089
22163
|
}
|
|
22090
22164
|
function containedHostPath(root, candidate) {
|
|
22091
22165
|
const path4 = relative(root, candidate);
|
|
22092
|
-
return path4 === "" || !
|
|
22166
|
+
return path4 === "" || !isAbsolute2(path4) && path4 !== ".." && !path4.startsWith(`..${sep}`);
|
|
22093
22167
|
}
|
|
22094
22168
|
function portableBindingIssue(root, pathHint, repositoryId) {
|
|
22095
22169
|
let current = root;
|
|
22096
22170
|
for (const segment of pathHint === "." ? [] : pathHint.split("/")) {
|
|
22097
|
-
current =
|
|
22098
|
-
if (!
|
|
22171
|
+
current = join6(current, segment);
|
|
22172
|
+
if (!existsSync6(current)) break;
|
|
22099
22173
|
const stat = lstatSync(current);
|
|
22100
22174
|
if (stat.isSymbolicLink()) {
|
|
22101
22175
|
return issue2("path", "repository_binding_path_link", ".kxm/project.yaml", `portable pathHint for ${repositoryId} traverses a symbolic link or junction`);
|
|
22102
22176
|
}
|
|
22103
22177
|
}
|
|
22104
|
-
const binding =
|
|
22105
|
-
if (
|
|
22178
|
+
const binding = resolve3(root, ...pathHint.split("/"));
|
|
22179
|
+
if (existsSync6(binding)) {
|
|
22106
22180
|
const realRoot = canonicalHostPath(root);
|
|
22107
22181
|
const realBinding = canonicalHostPath(binding);
|
|
22108
22182
|
if (!containedHostPath(realRoot, realBinding)) {
|
|
@@ -22139,10 +22213,10 @@ function readResource(registry, root, file, logicalPath, kind, id, containmentRo
|
|
|
22139
22213
|
fail2("discovery", "resource_missing", label, "resource does not exist");
|
|
22140
22214
|
}
|
|
22141
22215
|
if (stat.isSymbolicLink()) fail2("path", "resource_symlink", label, "configuration resources must not be symbolic links");
|
|
22142
|
-
const boundary =
|
|
22143
|
-
let parent =
|
|
22216
|
+
const boundary = resolve3(containmentRoot);
|
|
22217
|
+
let parent = dirname4(file);
|
|
22144
22218
|
while (parent !== boundary) {
|
|
22145
|
-
if (parent ===
|
|
22219
|
+
if (parent === dirname4(parent)) fail2("path", "resource_outside_project", label, "resource escapes the project root");
|
|
22146
22220
|
let parentStat;
|
|
22147
22221
|
try {
|
|
22148
22222
|
parentStat = lstatSync(parent);
|
|
@@ -22150,33 +22224,33 @@ function readResource(registry, root, file, logicalPath, kind, id, containmentRo
|
|
|
22150
22224
|
fail2("discovery", "resource_parent_missing", label, "resource parent does not exist");
|
|
22151
22225
|
}
|
|
22152
22226
|
if (parentStat.isSymbolicLink()) fail2("path", "resource_parent_symlink", label, "configuration resource parents must not be symbolic links");
|
|
22153
|
-
parent =
|
|
22227
|
+
parent = dirname4(parent);
|
|
22154
22228
|
}
|
|
22155
22229
|
if (!stat.isFile()) fail2("path", "resource_not_file", label, "configuration resource must be a regular file");
|
|
22156
|
-
const value = parseRestrictedYaml2(
|
|
22230
|
+
const value = parseRestrictedYaml2(readFileSync5(file), label);
|
|
22157
22231
|
const issues = registry.validate(kind, value, label);
|
|
22158
22232
|
if (issues.length > 0) throw new VnextConfigError(issues);
|
|
22159
22233
|
return { kind, ...id === void 0 ? {} : { id }, file, logicalPath, value };
|
|
22160
22234
|
}
|
|
22161
22235
|
function readTemplateProvenance(registry, root) {
|
|
22162
|
-
const file =
|
|
22163
|
-
if (!
|
|
22236
|
+
const file = join6(root, ".kxm", "template-provenance.yaml");
|
|
22237
|
+
if (!existsSync6(file)) return void 0;
|
|
22164
22238
|
const label = ".kxm/template-provenance.yaml";
|
|
22165
22239
|
const stat = lstatSync(file);
|
|
22166
22240
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
22167
22241
|
fail2("path", "resource_not_file", label, "template provenance must be a regular file, not a link or directory");
|
|
22168
22242
|
}
|
|
22169
|
-
const configRoot =
|
|
22170
|
-
let parent =
|
|
22243
|
+
const configRoot = join6(root, ".kxm");
|
|
22244
|
+
let parent = dirname4(file);
|
|
22171
22245
|
while (parent !== root) {
|
|
22172
22246
|
const parentStat = lstatSync(parent);
|
|
22173
22247
|
if (parentStat.isSymbolicLink() || !parentStat.isDirectory()) {
|
|
22174
22248
|
fail2("path", "resource_parent_symlink", label, "template provenance parents must be regular directories");
|
|
22175
22249
|
}
|
|
22176
22250
|
if (parent === configRoot) break;
|
|
22177
|
-
parent =
|
|
22251
|
+
parent = dirname4(parent);
|
|
22178
22252
|
}
|
|
22179
|
-
const value = parseRestrictedYaml2(
|
|
22253
|
+
const value = parseRestrictedYaml2(readFileSync5(file), label);
|
|
22180
22254
|
const issues = registry.validateTemplateProvenance(value, label);
|
|
22181
22255
|
if (issues.length > 0) throw new VnextConfigError(issues);
|
|
22182
22256
|
if (!resolveVnextTemplateBaseline(value)) {
|
|
@@ -22207,7 +22281,7 @@ function readTemplateProvenance(registry, root) {
|
|
|
22207
22281
|
}
|
|
22208
22282
|
function listNamedResources(registry, root, directory, logicalDirectory, kind) {
|
|
22209
22283
|
const resources = /* @__PURE__ */ new Map();
|
|
22210
|
-
if (!
|
|
22284
|
+
if (!existsSync6(directory)) return resources;
|
|
22211
22285
|
const stat = lstatSync(directory);
|
|
22212
22286
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
22213
22287
|
fail2("path", "resource_directory_invalid", displayPath(root, directory), "resource directory must be a regular directory");
|
|
@@ -22216,27 +22290,27 @@ function listNamedResources(registry, root, directory, logicalDirectory, kind) {
|
|
|
22216
22290
|
const entries = readdirSync(directory, { withFileTypes: true }).sort((left, right) => compareCodeUnits3(left.name, right.name));
|
|
22217
22291
|
for (const entry of entries) {
|
|
22218
22292
|
if (entry.isDirectory()) {
|
|
22219
|
-
issues.push(issue2("path", "nested_resource_directory", displayPath(root,
|
|
22293
|
+
issues.push(issue2("path", "nested_resource_directory", displayPath(root, join6(directory, entry.name)), "nested resource directories are not allowed"));
|
|
22220
22294
|
continue;
|
|
22221
22295
|
}
|
|
22222
22296
|
if (!entry.name.toLowerCase().endsWith(".yaml") && !entry.name.toLowerCase().endsWith(".yml")) continue;
|
|
22223
22297
|
if (!entry.isFile() || extname(entry.name) !== ".yaml") {
|
|
22224
|
-
issues.push(issue2("path", "resource_filename_invalid", displayPath(root,
|
|
22298
|
+
issues.push(issue2("path", "resource_filename_invalid", displayPath(root, join6(directory, entry.name)), "resource must be a regular file with the exact .yaml extension"));
|
|
22225
22299
|
continue;
|
|
22226
22300
|
}
|
|
22227
22301
|
const id = basename2(entry.name, ".yaml");
|
|
22228
22302
|
if (kind === "model" && id === "inventory") continue;
|
|
22229
22303
|
if (!resourceIdentifier(id)) {
|
|
22230
|
-
issues.push(issue2("path", "resource_id_invalid", displayPath(root,
|
|
22304
|
+
issues.push(issue2("path", "resource_id_invalid", displayPath(root, join6(directory, entry.name)), `filename-derived identity ${id} is invalid or platform-reserved`));
|
|
22231
22305
|
continue;
|
|
22232
22306
|
}
|
|
22233
22307
|
const collision = [...resources.keys()].find((candidate) => candidate.toLocaleLowerCase("en-US") === id.toLocaleLowerCase("en-US"));
|
|
22234
22308
|
if (collision) {
|
|
22235
|
-
issues.push(issue2("path", "resource_id_collision", displayPath(root,
|
|
22309
|
+
issues.push(issue2("path", "resource_id_collision", displayPath(root, join6(directory, entry.name)), `${id} case-folds to existing ${collision}`));
|
|
22236
22310
|
continue;
|
|
22237
22311
|
}
|
|
22238
22312
|
try {
|
|
22239
|
-
const resource = readResource(registry, root,
|
|
22313
|
+
const resource = readResource(registry, root, join6(directory, entry.name), `${logicalDirectory}/${id}.yaml`, kind, id);
|
|
22240
22314
|
resources.set(id, resource);
|
|
22241
22315
|
} catch (error) {
|
|
22242
22316
|
if (error instanceof VnextConfigError) issues.push(...error.issues);
|
|
@@ -22557,8 +22631,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
22557
22631
|
const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
|
|
22558
22632
|
if (maxWriteRepositories > writable) issues.push(issue2("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
|
|
22559
22633
|
}
|
|
22560
|
-
const
|
|
22561
|
-
const minimumPassed =
|
|
22634
|
+
const join50 = objectValue(step.join);
|
|
22635
|
+
const minimumPassed = join50 && typeof join50.minimumPassed === "number" ? join50.minimumPassed : void 0;
|
|
22562
22636
|
if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue2("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
|
|
22563
22637
|
const distinctBy = names(assignment?.distinctBy);
|
|
22564
22638
|
if (distinctBy.length > 0) {
|
|
@@ -22772,11 +22846,11 @@ function validateBundle(project, repositories, agents, models, workflows, enviro
|
|
|
22772
22846
|
if (!workflows.has(defaultWorkflow)) issues.push(issue2("reference", "default_workflow_unknown", project.logicalPath, `default workflow ${defaultWorkflow} does not exist`));
|
|
22773
22847
|
for (const workflow of workflows.values()) validateWorkflow(workflow, agents, models, repositoryIds, gates, issues);
|
|
22774
22848
|
if (projectRoot) {
|
|
22775
|
-
const writerRolePath =
|
|
22849
|
+
const writerRolePath = join6(projectRoot, ".kxm", "roles", "writer.yaml");
|
|
22776
22850
|
const implementerAgent = agents.get("implementer") ?? agents.get("writer");
|
|
22777
|
-
if (
|
|
22851
|
+
if (existsSync6(writerRolePath) && implementerAgent) {
|
|
22778
22852
|
try {
|
|
22779
|
-
const rawRole = parseRestrictedYaml2(
|
|
22853
|
+
const rawRole = parseRestrictedYaml2(readFileSync5(writerRolePath, "utf8"));
|
|
22780
22854
|
const roleObj = objectValue(rawRole);
|
|
22781
22855
|
const rosterEntries = valuesOf(roleObj ?? {}, "roster").map((candidate) => objectValue(candidate)).filter((entry) => Boolean(entry));
|
|
22782
22856
|
const enabledRosterModels = rosterEntries.filter((entry) => entry.enabled !== false).map((entry) => stringValue(entry.model)).filter((m2) => Boolean(m2));
|
|
@@ -22822,8 +22896,8 @@ function gitEnvironment() {
|
|
|
22822
22896
|
return Object.fromEntries(Object.entries(process.env).filter(([name]) => !name.toUpperCase().startsWith("GIT_")));
|
|
22823
22897
|
}
|
|
22824
22898
|
function discoverGitRoot(start = process.cwd()) {
|
|
22825
|
-
let current =
|
|
22826
|
-
if (
|
|
22899
|
+
let current = resolve3(start);
|
|
22900
|
+
if (existsSync6(current) && !lstatSync(current).isDirectory()) current = dirname4(current);
|
|
22827
22901
|
const result = spawnSync2("git", ["-C", current, "rev-parse", "--show-toplevel"], {
|
|
22828
22902
|
encoding: "utf8",
|
|
22829
22903
|
env: gitEnvironment(),
|
|
@@ -22831,12 +22905,12 @@ function discoverGitRoot(start = process.cwd()) {
|
|
|
22831
22905
|
windowsHide: true
|
|
22832
22906
|
});
|
|
22833
22907
|
if (result.status !== 0 || result.error || !result.stdout.trim()) return void 0;
|
|
22834
|
-
const root =
|
|
22835
|
-
return
|
|
22908
|
+
const root = resolve3(result.stdout.trim());
|
|
22909
|
+
return existsSync6(root) && lstatSync(root).isDirectory() ? root : void 0;
|
|
22836
22910
|
}
|
|
22837
22911
|
function discoverVnextProjectRoot(start = process.cwd()) {
|
|
22838
22912
|
const gitRoot = discoverGitRoot(start);
|
|
22839
|
-
return gitRoot &&
|
|
22913
|
+
return gitRoot && existsSync6(join6(gitRoot, ".kxm", "project.yaml")) ? gitRoot : void 0;
|
|
22840
22914
|
}
|
|
22841
22915
|
function assertNoRegisteredGates(options) {
|
|
22842
22916
|
if ("registeredGates" in options) {
|
|
@@ -22845,7 +22919,7 @@ function assertNoRegisteredGates(options) {
|
|
|
22845
22919
|
}
|
|
22846
22920
|
function loadVnextProject(projectRoot, options = {}) {
|
|
22847
22921
|
assertNoRegisteredGates(options);
|
|
22848
|
-
const root =
|
|
22922
|
+
const root = resolve3(projectRoot);
|
|
22849
22923
|
let migrationReceipt;
|
|
22850
22924
|
if (legacyConfigFilesAt(root).length > 0 && options.allowUnreceiptedLegacyConfig !== true) {
|
|
22851
22925
|
const receiptCheck = readVnextMigrationReceipt(root, options);
|
|
@@ -22853,7 +22927,7 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22853
22927
|
migrationReceipt = receiptCheck.receipt;
|
|
22854
22928
|
}
|
|
22855
22929
|
const registry = new VnextSchemaRegistry(options.schemasDir);
|
|
22856
|
-
const project = readResource(registry, root,
|
|
22930
|
+
const project = readResource(registry, root, join6(root, ".kxm", "project.yaml"), ".kxm/project.yaml", "project");
|
|
22857
22931
|
const earlyIssues = [];
|
|
22858
22932
|
validatePortablePaths(project, earlyIssues);
|
|
22859
22933
|
const templateProvenance = readTemplateProvenance(registry, root);
|
|
@@ -22875,16 +22949,16 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22875
22949
|
}
|
|
22876
22950
|
}
|
|
22877
22951
|
if (earlyIssues.length > 0) throw new VnextConfigError(earlyIssues);
|
|
22878
|
-
const agents = listNamedResources(registry, root,
|
|
22879
|
-
const models = listNamedResources(registry, root,
|
|
22880
|
-
const workflows = listNamedResources(registry, root,
|
|
22881
|
-
const gatePath =
|
|
22882
|
-
const gateRegistry =
|
|
22952
|
+
const agents = listNamedResources(registry, root, join6(root, ".kxm", "agents"), ".kxm/agents", "agent");
|
|
22953
|
+
const models = listNamedResources(registry, root, join6(root, ".kxm", "models"), ".kxm/models", "model");
|
|
22954
|
+
const workflows = listNamedResources(registry, root, join6(root, ".kxm", "workflows"), ".kxm/workflows", "workflow");
|
|
22955
|
+
const gatePath = join6(root, ".kxm", "gates.yaml");
|
|
22956
|
+
const gateRegistry = existsSync6(gatePath) ? readResource(registry, root, gatePath, ".kxm/gates.yaml", "gate-registry") : void 0;
|
|
22883
22957
|
const environments = [];
|
|
22884
22958
|
const repositories = /* @__PURE__ */ new Map();
|
|
22885
22959
|
const loadIssues = [];
|
|
22886
|
-
const projectEnvironment =
|
|
22887
|
-
if (
|
|
22960
|
+
const projectEnvironment = join6(root, ".kxm", "project", "env.yaml");
|
|
22961
|
+
if (existsSync6(projectEnvironment)) {
|
|
22888
22962
|
try {
|
|
22889
22963
|
environments.push(readResource(registry, root, projectEnvironment, ".kxm/project/env.yaml", "environment"));
|
|
22890
22964
|
} catch (error) {
|
|
@@ -22902,7 +22976,7 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22902
22976
|
if (!repositoryId) continue;
|
|
22903
22977
|
const hasLocalBinding = Object.hasOwn(options.repositoryBindings ?? {}, repositoryId);
|
|
22904
22978
|
const localBinding = options.repositoryBindings?.[repositoryId];
|
|
22905
|
-
if (hasLocalBinding && (!localBinding || !
|
|
22979
|
+
if (hasLocalBinding && (!localBinding || !isAbsolute2(localBinding))) {
|
|
22906
22980
|
loadIssues.push(issue2("path", "repository_binding_not_absolute", ".kxm/project.yaml", `host-local binding for ${repositoryId} must be absolute`));
|
|
22907
22981
|
continue;
|
|
22908
22982
|
}
|
|
@@ -22921,12 +22995,12 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22921
22995
|
continue;
|
|
22922
22996
|
}
|
|
22923
22997
|
}
|
|
22924
|
-
const binding = hasLocalBinding && localBinding ?
|
|
22998
|
+
const binding = hasLocalBinding && localBinding ? resolve3(localBinding) : role === "control" ? root : pathHint && portablePath(pathHint) ? resolve3(root, ...pathHint.split("/")) : void 0;
|
|
22925
22999
|
if (!binding) {
|
|
22926
23000
|
if (required) loadIssues.push(issue2("discovery", "repository_binding_missing", ".kxm/project.yaml", `required repository ${repositoryId} has no portable pathHint or host-local binding`));
|
|
22927
23001
|
continue;
|
|
22928
23002
|
}
|
|
22929
|
-
if (!
|
|
23003
|
+
if (!existsSync6(binding)) {
|
|
22930
23004
|
if (required || hasLocalBinding) loadIssues.push(issue2("discovery", "repository_binding_unavailable", ".kxm/project.yaml", `${hasLocalBinding ? "explicit" : "required"} repository binding ${repositoryId} is unavailable`));
|
|
22931
23005
|
continue;
|
|
22932
23006
|
}
|
|
@@ -22949,9 +23023,9 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22949
23023
|
continue;
|
|
22950
23024
|
}
|
|
22951
23025
|
seenBindings.set(foldedBinding, repositoryId);
|
|
22952
|
-
const repositoryFile =
|
|
23026
|
+
const repositoryFile = join6(binding, ".kxm", "repo", "repo.yaml");
|
|
22953
23027
|
let definitionValidated = false;
|
|
22954
|
-
if (
|
|
23028
|
+
if (existsSync6(repositoryFile)) {
|
|
22955
23029
|
try {
|
|
22956
23030
|
const resource = readResource(registry, root, repositoryFile, `.kxm/repositories/${repositoryId}/repo.yaml`, "repository", repositoryId, binding);
|
|
22957
23031
|
if (resource.value.repositoryId !== repositoryId) {
|
|
@@ -22967,8 +23041,8 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22967
23041
|
} else if (required || hasLocalBinding) {
|
|
22968
23042
|
loadIssues.push(issue2("discovery", "repository_definition_missing", `.kxm/repositories/${repositoryId}/repo.yaml`, `${hasLocalBinding ? "explicit" : "required"} repository ${repositoryId} has no repo.yaml`));
|
|
22969
23043
|
}
|
|
22970
|
-
const environmentFile =
|
|
22971
|
-
if (
|
|
23044
|
+
const environmentFile = join6(binding, ".kxm", "repo", "env.yaml");
|
|
23045
|
+
if (existsSync6(environmentFile)) {
|
|
22972
23046
|
if (!definitionValidated) {
|
|
22973
23047
|
loadIssues.push(issue2("reference", "repository_environment_without_definition", `.kxm/repositories/${repositoryId}/env.yaml`, `repository ${repositoryId} environment requires a validated matching repo.yaml`));
|
|
22974
23048
|
} else {
|
|
@@ -23036,7 +23110,7 @@ function verifyVnextMigrationReceiptTarget(root, receipt, resources, configRevis
|
|
|
23036
23110
|
}
|
|
23037
23111
|
function relativePortable(root, absolute) {
|
|
23038
23112
|
const rel = relative(root, absolute);
|
|
23039
|
-
if (!rel ||
|
|
23113
|
+
if (!rel || isAbsolute2(rel) || rel === ".." || rel.startsWith(`..${sep}`)) return void 0;
|
|
23040
23114
|
return rel.split(sep).join("/");
|
|
23041
23115
|
}
|
|
23042
23116
|
function legacyInputsAt(root) {
|
|
@@ -23046,21 +23120,21 @@ function legacyInputsAt(root) {
|
|
|
23046
23120
|
".kxm/config/workflows",
|
|
23047
23121
|
".kxm/state/kxm.db"
|
|
23048
23122
|
];
|
|
23049
|
-
return candidates.filter((candidate) =>
|
|
23123
|
+
return candidates.filter((candidate) => existsSync6(join6(root, ...candidate.split("/"))));
|
|
23050
23124
|
}
|
|
23051
23125
|
var VNEXT_MIGRATION_RECEIPT_PATH = ".kxm/migration-receipt.yaml";
|
|
23052
23126
|
var LEGACY_CONFIG_FILES = [".kxm/config/agents.json", ".kxm/config/gates.json"];
|
|
23053
23127
|
function legacyConfigFilesAt(root) {
|
|
23054
23128
|
const files = [];
|
|
23055
23129
|
for (const component of [".kxm", ".kxm/config"]) {
|
|
23056
|
-
const absolute =
|
|
23057
|
-
if (
|
|
23130
|
+
const absolute = join6(root, ...component.split("/"));
|
|
23131
|
+
if (existsSync6(absolute) && lstatSync(absolute).isSymbolicLink()) return [component];
|
|
23058
23132
|
}
|
|
23059
23133
|
for (const candidate of LEGACY_CONFIG_FILES) {
|
|
23060
|
-
if (
|
|
23134
|
+
if (existsSync6(join6(root, ...candidate.split("/")))) files.push(candidate);
|
|
23061
23135
|
}
|
|
23062
|
-
const workflowsDir =
|
|
23063
|
-
if (
|
|
23136
|
+
const workflowsDir = join6(root, ".kxm", "config", "workflows");
|
|
23137
|
+
if (existsSync6(workflowsDir)) {
|
|
23064
23138
|
const stat = lstatSync(workflowsDir);
|
|
23065
23139
|
if (stat.isSymbolicLink()) {
|
|
23066
23140
|
files.push(".kxm/config/workflows");
|
|
@@ -23075,9 +23149,9 @@ function legacyConfigFilesAt(root) {
|
|
|
23075
23149
|
return files;
|
|
23076
23150
|
}
|
|
23077
23151
|
function hashFileRecord(root, relativePath) {
|
|
23078
|
-
const absolute =
|
|
23079
|
-
if (!
|
|
23080
|
-
const bytes =
|
|
23152
|
+
const absolute = join6(root, ...relativePath.split("/"));
|
|
23153
|
+
if (!existsSync6(absolute)) return void 0;
|
|
23154
|
+
const bytes = readFileSync5(absolute);
|
|
23081
23155
|
return {
|
|
23082
23156
|
path: relativePath,
|
|
23083
23157
|
sha256: `sha256:${createHash6("sha256").update(bytes).digest("hex")}`,
|
|
@@ -23089,9 +23163,9 @@ function migrationReceiptSelfHash(receipt) {
|
|
|
23089
23163
|
return `sha256:${createHash6("sha256").update(vnextCanonicalJson(unsigned), "utf8").digest("hex")}`;
|
|
23090
23164
|
}
|
|
23091
23165
|
function readVnextMigrationReceipt(root, options = {}) {
|
|
23092
|
-
const receiptPath =
|
|
23166
|
+
const receiptPath = join6(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
|
|
23093
23167
|
const legacyFiles = legacyConfigFilesAt(root);
|
|
23094
|
-
if (!
|
|
23168
|
+
if (!existsSync6(receiptPath)) {
|
|
23095
23169
|
return {
|
|
23096
23170
|
issues: legacyFiles.map((file) => issue2("semantic", "legacy_vnext_conflict", file, "legacy and vNext configuration cannot coexist before an accepted migration receipt"))
|
|
23097
23171
|
};
|
|
@@ -23102,7 +23176,7 @@ function readVnextMigrationReceipt(root, options = {}) {
|
|
|
23102
23176
|
}
|
|
23103
23177
|
let receipt;
|
|
23104
23178
|
try {
|
|
23105
|
-
receipt = parseRestrictedYaml2(
|
|
23179
|
+
receipt = parseRestrictedYaml2(readFileSync5(receiptPath), VNEXT_MIGRATION_RECEIPT_PATH);
|
|
23106
23180
|
} catch (error) {
|
|
23107
23181
|
if (error instanceof VnextConfigError) return { issues: [...error.issues] };
|
|
23108
23182
|
throw error;
|
|
@@ -23135,14 +23209,14 @@ function readVnextMigrationReceipt(root, options = {}) {
|
|
|
23135
23209
|
return issues.length > 0 ? { issues } : { receipt, issues: [] };
|
|
23136
23210
|
}
|
|
23137
23211
|
function discoverLegacyRoot(start) {
|
|
23138
|
-
let initial =
|
|
23139
|
-
if (
|
|
23212
|
+
let initial = resolve3(start);
|
|
23213
|
+
if (existsSync6(initial) && !lstatSync(initial).isDirectory()) initial = dirname4(initial);
|
|
23140
23214
|
const candidate = discoverGitRoot(initial) ?? initial;
|
|
23141
23215
|
const inputs = legacyInputsAt(candidate);
|
|
23142
23216
|
return inputs.length > 0 ? { root: candidate, inputs } : void 0;
|
|
23143
23217
|
}
|
|
23144
23218
|
function planVnextInitialization(start = process.cwd(), options = {}) {
|
|
23145
|
-
const inspectedFrom =
|
|
23219
|
+
const inspectedFrom = resolve3(start);
|
|
23146
23220
|
const projectRoot = discoverVnextProjectRoot(inspectedFrom);
|
|
23147
23221
|
if (projectRoot) {
|
|
23148
23222
|
try {
|
|
@@ -23163,7 +23237,7 @@ function planVnextInitialization(start = process.cwd(), options = {}) {
|
|
|
23163
23237
|
}
|
|
23164
23238
|
const gitRoot = discoverGitRoot(inspectedFrom);
|
|
23165
23239
|
const candidateRoot = gitRoot ?? inspectedFrom;
|
|
23166
|
-
if (
|
|
23240
|
+
if (existsSync6(join6(candidateRoot, ".kxm"))) {
|
|
23167
23241
|
return {
|
|
23168
23242
|
mode: "repair",
|
|
23169
23243
|
inspectedFrom,
|
|
@@ -23179,13 +23253,13 @@ function planVnextInitialization(start = process.cwd(), options = {}) {
|
|
|
23179
23253
|
// plugins/kxm/src/vnext-runtime-supervisor.ts
|
|
23180
23254
|
import { spawn as spawn2 } from "node:child_process";
|
|
23181
23255
|
import { createHash as createHash11, createHmac, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
23182
|
-
import { chmodSync as chmodSync4, existsSync as
|
|
23183
|
-
import { dirname as
|
|
23256
|
+
import { chmodSync as chmodSync4, existsSync as existsSync12, lstatSync as lstatSync6, mkdirSync as mkdirSync8, readFileSync as readFileSync11, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
|
|
23257
|
+
import { dirname as dirname8, isAbsolute as isAbsolute5, join as join12 } from "node:path";
|
|
23184
23258
|
|
|
23185
23259
|
// plugins/kxm/src/vnext-runtime-store.ts
|
|
23186
23260
|
import { createHash as createHash9, randomUUID as randomUUID4 } from "node:crypto";
|
|
23187
|
-
import { existsSync as
|
|
23188
|
-
import { dirname as
|
|
23261
|
+
import { existsSync as existsSync9, lstatSync as lstatSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync8, realpathSync as realpathSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
23262
|
+
import { dirname as dirname7, join as join9, resolve as resolve6 } from "node:path";
|
|
23189
23263
|
|
|
23190
23264
|
// plugins/kxm/src/vnext-bindings.ts
|
|
23191
23265
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
@@ -23193,18 +23267,18 @@ import { createHash as createHash7, randomUUID as randomUUID3 } from "node:crypt
|
|
|
23193
23267
|
import {
|
|
23194
23268
|
chmodSync as chmodSync2,
|
|
23195
23269
|
closeSync,
|
|
23196
|
-
existsSync as
|
|
23270
|
+
existsSync as existsSync7,
|
|
23197
23271
|
fsyncSync,
|
|
23198
23272
|
lstatSync as lstatSync2,
|
|
23199
|
-
mkdirSync as
|
|
23273
|
+
mkdirSync as mkdirSync4,
|
|
23200
23274
|
openSync,
|
|
23201
|
-
readFileSync as
|
|
23275
|
+
readFileSync as readFileSync6,
|
|
23202
23276
|
realpathSync as realpathSync2,
|
|
23203
|
-
renameSync,
|
|
23204
|
-
rmSync,
|
|
23205
|
-
writeFileSync as
|
|
23277
|
+
renameSync as renameSync2,
|
|
23278
|
+
rmSync as rmSync2,
|
|
23279
|
+
writeFileSync as writeFileSync4
|
|
23206
23280
|
} from "node:fs";
|
|
23207
|
-
import { homedir as
|
|
23281
|
+
import { homedir as homedir3 } from "node:os";
|
|
23208
23282
|
|
|
23209
23283
|
// plugins/kxm/src/sqlite.ts
|
|
23210
23284
|
import { createRequire } from "node:module";
|
|
@@ -23246,7 +23320,7 @@ var DatabaseSync = class {
|
|
|
23246
23320
|
};
|
|
23247
23321
|
|
|
23248
23322
|
// plugins/kxm/src/vnext-bindings.ts
|
|
23249
|
-
import { dirname as
|
|
23323
|
+
import { dirname as dirname5, isAbsolute as isAbsolute3, join as join7, parse, relative as relative2, resolve as resolve4, sep as sep2 } from "node:path";
|
|
23250
23324
|
var MAX_BINDING_RECORD_BYTES = 256 * 1024;
|
|
23251
23325
|
var BINDING_LABEL = "Runtime-local repository bindings";
|
|
23252
23326
|
var activeLocks = /* @__PURE__ */ new WeakSet();
|
|
@@ -23257,7 +23331,7 @@ function bindingError(phase, code, message) {
|
|
|
23257
23331
|
throw new VnextConfigError([bindingIssue(phase, code, message)]);
|
|
23258
23332
|
}
|
|
23259
23333
|
function canonicalHostPath2(path4) {
|
|
23260
|
-
const absolute =
|
|
23334
|
+
const absolute = resolve4(path4);
|
|
23261
23335
|
try {
|
|
23262
23336
|
return realpathSync2.native(absolute);
|
|
23263
23337
|
} catch {
|
|
@@ -23272,21 +23346,21 @@ function sameHostPath2(left, right, platform = process.platform) {
|
|
|
23272
23346
|
function vnextUserStateRoot(options = {}) {
|
|
23273
23347
|
const env = options.env ?? process.env;
|
|
23274
23348
|
const platform = options.platform ?? process.platform;
|
|
23275
|
-
const home = options.homeDir ??
|
|
23349
|
+
const home = options.homeDir ?? homedir3();
|
|
23276
23350
|
const explicit = options.stateRoot ?? env.KXM_STATE_HOME?.trim();
|
|
23277
23351
|
if (explicit) {
|
|
23278
|
-
if (!
|
|
23279
|
-
return
|
|
23352
|
+
if (!isAbsolute3(explicit)) bindingError("path", "local_state_root_not_absolute", "KXM_STATE_HOME must be an absolute host-local path");
|
|
23353
|
+
return resolve4(explicit);
|
|
23280
23354
|
}
|
|
23281
23355
|
if (platform === "win32") {
|
|
23282
23356
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
23283
|
-
const base2 = localAppData &&
|
|
23284
|
-
return
|
|
23357
|
+
const base2 = localAppData && isAbsolute3(localAppData) ? localAppData : join7(home, "AppData", "Local");
|
|
23358
|
+
return resolve4(base2, "KXM");
|
|
23285
23359
|
}
|
|
23286
|
-
if (platform === "darwin") return
|
|
23360
|
+
if (platform === "darwin") return resolve4(home, "Library", "Application Support", "KXM");
|
|
23287
23361
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
23288
|
-
const base = xdgState &&
|
|
23289
|
-
return
|
|
23362
|
+
const base = xdgState && isAbsolute3(xdgState) ? xdgState : join7(home, ".local", "state");
|
|
23363
|
+
return resolve4(base, "kxm");
|
|
23290
23364
|
}
|
|
23291
23365
|
function projectBindingKey(projectRoot, platform = process.platform) {
|
|
23292
23366
|
const canonical2 = canonicalHostPath2(projectRoot);
|
|
@@ -23295,10 +23369,10 @@ function projectBindingKey(projectRoot, platform = process.platform) {
|
|
|
23295
23369
|
}
|
|
23296
23370
|
function vnextLocalBindingFile(projectRoot, options = {}) {
|
|
23297
23371
|
const stateRoot = vnextUserStateRoot(options);
|
|
23298
|
-
return
|
|
23372
|
+
return join7(stateRoot, "projects", projectBindingKey(projectRoot, options.platform), "repository-bindings.json");
|
|
23299
23373
|
}
|
|
23300
23374
|
function checkedDirectory(path4, description) {
|
|
23301
|
-
if (!
|
|
23375
|
+
if (!existsSync7(path4)) return false;
|
|
23302
23376
|
const stat = lstatSync2(path4);
|
|
23303
23377
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23304
23378
|
bindingError("path", "local_binding_directory_invalid", `${description} must be a regular directory, not a link or file`);
|
|
@@ -23306,8 +23380,8 @@ function checkedDirectory(path4, description) {
|
|
|
23306
23380
|
return true;
|
|
23307
23381
|
}
|
|
23308
23382
|
function existingBindingDirectory(file, stateRoot) {
|
|
23309
|
-
const projects =
|
|
23310
|
-
const project =
|
|
23383
|
+
const projects = join7(stateRoot, "projects");
|
|
23384
|
+
const project = dirname5(file);
|
|
23311
23385
|
if (!checkedDirectory(stateRoot, "local state root")) return false;
|
|
23312
23386
|
if (!checkedDirectory(projects, "local projects directory")) return false;
|
|
23313
23387
|
return checkedDirectory(project, "local project binding directory");
|
|
@@ -23330,10 +23404,10 @@ function asRecord2(value, file, projectRoot, schemasDir) {
|
|
|
23330
23404
|
};
|
|
23331
23405
|
}
|
|
23332
23406
|
function readVnextLocalBindings(projectRoot, options = {}) {
|
|
23333
|
-
const root =
|
|
23407
|
+
const root = resolve4(projectRoot);
|
|
23334
23408
|
const stateRoot = vnextUserStateRoot(options);
|
|
23335
23409
|
const file = vnextLocalBindingFile(root, options);
|
|
23336
|
-
if (!existingBindingDirectory(file, stateRoot) || !
|
|
23410
|
+
if (!existingBindingDirectory(file, stateRoot) || !existsSync7(file)) return void 0;
|
|
23337
23411
|
const stat = lstatSync2(file);
|
|
23338
23412
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
23339
23413
|
bindingError("path", "local_binding_file_invalid", "binding record must be a regular file, not a link or directory");
|
|
@@ -23341,12 +23415,12 @@ function readVnextLocalBindings(projectRoot, options = {}) {
|
|
|
23341
23415
|
if (stat.size > MAX_BINDING_RECORD_BYTES) {
|
|
23342
23416
|
bindingError("parse", "local_binding_file_too_large", `binding record exceeds ${MAX_BINDING_RECORD_BYTES} bytes`);
|
|
23343
23417
|
}
|
|
23344
|
-
const parsed = parseRestrictedYaml2(
|
|
23418
|
+
const parsed = parseRestrictedYaml2(readFileSync6(file), BINDING_LABEL);
|
|
23345
23419
|
return asRecord2(parsed, file, root, options.schemasDir);
|
|
23346
23420
|
}
|
|
23347
23421
|
function normalizedRecord(projectRoot, projectId, repositories, schemasDir) {
|
|
23348
23422
|
const normalizedRepositories = Object.fromEntries(Object.entries(repositories).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([repositoryId, path4]) => {
|
|
23349
|
-
if (!
|
|
23423
|
+
if (!isAbsolute3(path4)) bindingError("path", "repository_binding_not_absolute", `host-local binding for ${repositoryId} must be absolute`);
|
|
23350
23424
|
return [repositoryId, canonicalHostPath2(path4)];
|
|
23351
23425
|
}));
|
|
23352
23426
|
const value = {
|
|
@@ -23381,48 +23455,48 @@ function syncDirectory(path4) {
|
|
|
23381
23455
|
}
|
|
23382
23456
|
}
|
|
23383
23457
|
function createDirectoryIfMissing(path4) {
|
|
23384
|
-
if (
|
|
23458
|
+
if (existsSync7(path4)) return;
|
|
23385
23459
|
try {
|
|
23386
|
-
|
|
23387
|
-
syncDirectory(
|
|
23460
|
+
mkdirSync4(path4, { mode: 448 });
|
|
23461
|
+
syncDirectory(dirname5(path4));
|
|
23388
23462
|
} catch (error) {
|
|
23389
23463
|
if (error.code !== "EEXIST") throw error;
|
|
23390
23464
|
}
|
|
23391
23465
|
}
|
|
23392
23466
|
function ensureDurableDirectory(path4, description) {
|
|
23393
23467
|
const missing = [];
|
|
23394
|
-
let current =
|
|
23395
|
-
while (!
|
|
23468
|
+
let current = resolve4(path4);
|
|
23469
|
+
while (!existsSync7(current)) {
|
|
23396
23470
|
missing.push(current);
|
|
23397
|
-
const parent =
|
|
23471
|
+
const parent = dirname5(current);
|
|
23398
23472
|
if (parent === current) bindingError("path", "local_binding_directory_invalid", `${description} has no existing filesystem ancestor`);
|
|
23399
23473
|
current = parent;
|
|
23400
23474
|
}
|
|
23401
23475
|
checkedDirectory(current, `${description} ancestor`);
|
|
23402
23476
|
for (const directory of missing.reverse()) {
|
|
23403
|
-
|
|
23477
|
+
mkdirSync4(directory, { mode: 448 });
|
|
23404
23478
|
checkedDirectory(directory, description);
|
|
23405
|
-
syncDirectory(
|
|
23479
|
+
syncDirectory(dirname5(directory));
|
|
23406
23480
|
}
|
|
23407
23481
|
}
|
|
23408
23482
|
function ensureBindingDirectory(file, stateRoot) {
|
|
23409
23483
|
ensureDurableDirectory(stateRoot, "local state root");
|
|
23410
23484
|
checkedDirectory(stateRoot, "local state root");
|
|
23411
23485
|
syncDirectory(stateRoot);
|
|
23412
|
-
const projects =
|
|
23486
|
+
const projects = join7(stateRoot, "projects");
|
|
23413
23487
|
createDirectoryIfMissing(projects);
|
|
23414
23488
|
checkedDirectory(projects, "local projects directory");
|
|
23415
|
-
const project =
|
|
23489
|
+
const project = dirname5(file);
|
|
23416
23490
|
createDirectoryIfMissing(project);
|
|
23417
23491
|
checkedDirectory(project, "local project binding directory");
|
|
23418
23492
|
}
|
|
23419
23493
|
function assertNoLinkedDirectoryComponents(path4, description) {
|
|
23420
|
-
const absolute =
|
|
23494
|
+
const absolute = resolve4(path4);
|
|
23421
23495
|
const filesystemRoot = parse(absolute).root;
|
|
23422
23496
|
let current = filesystemRoot;
|
|
23423
23497
|
const remainder = relative2(filesystemRoot, absolute);
|
|
23424
23498
|
for (const segment of remainder.split(sep2).filter(Boolean)) {
|
|
23425
|
-
current =
|
|
23499
|
+
current = join7(current, segment);
|
|
23426
23500
|
const stat = lstatSync2(current);
|
|
23427
23501
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23428
23502
|
bindingError("path", "project_operation_lock_parent_invalid", `${description} contains a linked or non-directory component`);
|
|
@@ -23443,28 +23517,28 @@ function projectOperationLockFile(projectRoot) {
|
|
|
23443
23517
|
if (result.status !== 0 || result.error || !result.stdout.trim()) {
|
|
23444
23518
|
bindingError("discovery", "project_operation_lock_unavailable", "cannot resolve the authoritative Git metadata path for project locking");
|
|
23445
23519
|
}
|
|
23446
|
-
const gitDirectory =
|
|
23520
|
+
const gitDirectory = resolve4(result.stdout.trim());
|
|
23447
23521
|
assertNoLinkedDirectoryComponents(gitDirectory, "authoritative Git metadata path");
|
|
23448
23522
|
const gitStat = lstatSync2(gitDirectory);
|
|
23449
23523
|
if (gitStat.isSymbolicLink() || !gitStat.isDirectory()) {
|
|
23450
23524
|
bindingError("path", "project_operation_lock_parent_invalid", "authoritative Git metadata must resolve to a regular directory");
|
|
23451
23525
|
}
|
|
23452
|
-
const lockDirectory =
|
|
23453
|
-
if (
|
|
23526
|
+
const lockDirectory = join7(gitDirectory, "kxm");
|
|
23527
|
+
if (existsSync7(lockDirectory)) {
|
|
23454
23528
|
const stat = lstatSync2(lockDirectory);
|
|
23455
23529
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23456
23530
|
bindingError("path", "project_operation_lock_parent_invalid", "Git-local KXM lock directory must be regular, not a link or file");
|
|
23457
23531
|
}
|
|
23458
23532
|
} else {
|
|
23459
|
-
|
|
23533
|
+
mkdirSync4(lockDirectory, { mode: 448 });
|
|
23460
23534
|
syncDirectory(gitDirectory);
|
|
23461
23535
|
}
|
|
23462
|
-
return
|
|
23536
|
+
return join7(lockDirectory, "project-operation-lock.sqlite");
|
|
23463
23537
|
}
|
|
23464
23538
|
function withVnextLocalBindingLock(projectRoot, options, callback) {
|
|
23465
|
-
const root =
|
|
23539
|
+
const root = resolve4(projectRoot);
|
|
23466
23540
|
const file = projectOperationLockFile(root);
|
|
23467
|
-
if (
|
|
23541
|
+
if (existsSync7(file)) {
|
|
23468
23542
|
const stat = lstatSync2(file);
|
|
23469
23543
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
23470
23544
|
bindingError("path", "local_binding_lock_invalid", "project-operation lock must be a regular file, not a link or directory");
|
|
@@ -23497,7 +23571,7 @@ function withVnextLocalBindingLock(projectRoot, options, callback) {
|
|
|
23497
23571
|
}
|
|
23498
23572
|
}
|
|
23499
23573
|
function planVnextLocalBindings(projectRoot, projectId, repositories, options = {}) {
|
|
23500
|
-
const root =
|
|
23574
|
+
const root = resolve4(projectRoot);
|
|
23501
23575
|
const file = vnextLocalBindingFile(root, options);
|
|
23502
23576
|
const record = normalizedRecord(root, projectId, repositories, options.schemasDir);
|
|
23503
23577
|
const existing = readVnextLocalBindings(root, options);
|
|
@@ -23507,7 +23581,7 @@ function planVnextLocalBindings(projectRoot, projectId, repositories, options =
|
|
|
23507
23581
|
return { file, written: !existing || !recordsEqual(existing, record), record };
|
|
23508
23582
|
}
|
|
23509
23583
|
function writeVnextLocalBindings(projectRoot, projectId, repositories, options = {}, lock) {
|
|
23510
|
-
const root =
|
|
23584
|
+
const root = resolve4(projectRoot);
|
|
23511
23585
|
if (!lock) {
|
|
23512
23586
|
return withVnextLocalBindingLock(root, options, (acquired) => writeVnextLocalBindings(root, projectId, repositories, options, acquired));
|
|
23513
23587
|
}
|
|
@@ -23518,20 +23592,20 @@ function writeVnextLocalBindings(projectRoot, projectId, repositories, options =
|
|
|
23518
23592
|
const { file, record } = planned;
|
|
23519
23593
|
if (!planned.written) return planned;
|
|
23520
23594
|
ensureBindingDirectory(file, vnextUserStateRoot(options));
|
|
23521
|
-
const temporary =
|
|
23595
|
+
const temporary = join7(dirname5(file), `.repository-bindings-${process.pid}-${randomUUID3()}.tmp`);
|
|
23522
23596
|
let descriptor;
|
|
23523
23597
|
try {
|
|
23524
23598
|
descriptor = openSync(temporary, "wx", 384);
|
|
23525
|
-
|
|
23599
|
+
writeFileSync4(descriptor, `${JSON.stringify(record, null, 2)}
|
|
23526
23600
|
`, "utf8");
|
|
23527
23601
|
fsyncSync(descriptor);
|
|
23528
23602
|
closeSync(descriptor);
|
|
23529
23603
|
descriptor = void 0;
|
|
23530
|
-
|
|
23531
|
-
syncDirectory(
|
|
23604
|
+
renameSync2(temporary, file);
|
|
23605
|
+
syncDirectory(dirname5(file));
|
|
23532
23606
|
} finally {
|
|
23533
23607
|
if (descriptor !== void 0) closeSync(descriptor);
|
|
23534
|
-
|
|
23608
|
+
rmSync2(temporary, { force: true });
|
|
23535
23609
|
}
|
|
23536
23610
|
const verified = readVnextLocalBindings(root, options);
|
|
23537
23611
|
if (!verified || !recordsEqual(verified, record)) {
|
|
@@ -23545,22 +23619,22 @@ import { createHash as createHash8, randomBytes } from "node:crypto";
|
|
|
23545
23619
|
import {
|
|
23546
23620
|
chmodSync as chmodSync3,
|
|
23547
23621
|
copyFileSync,
|
|
23548
|
-
existsSync as
|
|
23622
|
+
existsSync as existsSync8,
|
|
23549
23623
|
lstatSync as lstatSync3,
|
|
23550
|
-
mkdirSync as
|
|
23624
|
+
mkdirSync as mkdirSync5,
|
|
23551
23625
|
readdirSync as readdirSync2,
|
|
23552
|
-
readFileSync as
|
|
23626
|
+
readFileSync as readFileSync7,
|
|
23553
23627
|
unlinkSync as unlinkSync2,
|
|
23554
|
-
writeFileSync as
|
|
23628
|
+
writeFileSync as writeFileSync5
|
|
23555
23629
|
} from "node:fs";
|
|
23556
|
-
import { basename as basename3, dirname as
|
|
23630
|
+
import { basename as basename3, dirname as dirname6, join as join8, resolve as resolve5 } from "node:path";
|
|
23557
23631
|
function databaseError(code, file, message) {
|
|
23558
23632
|
const issue3 = { phase: "semantic", code, file, message };
|
|
23559
23633
|
return new VnextConfigError([issue3]);
|
|
23560
23634
|
}
|
|
23561
23635
|
function checkedParent(path4, description) {
|
|
23562
|
-
const parent =
|
|
23563
|
-
if (!
|
|
23636
|
+
const parent = dirname6(path4);
|
|
23637
|
+
if (!existsSync8(parent)) mkdirSync5(parent, { recursive: true, mode: 448 });
|
|
23564
23638
|
const stat = lstatSync3(parent, { throwIfNoEntry: false });
|
|
23565
23639
|
if (!stat || stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23566
23640
|
throw databaseError("runtime_path_invalid", description, `${description} parent must be a regular directory, not a link`);
|
|
@@ -23702,18 +23776,18 @@ function checkIntegrity(database) {
|
|
|
23702
23776
|
return rows.length === 1 && rows[0]?.integrity_check === "ok";
|
|
23703
23777
|
}
|
|
23704
23778
|
function fileSha256(filePath) {
|
|
23705
|
-
const bytes =
|
|
23779
|
+
const bytes = readFileSync7(filePath);
|
|
23706
23780
|
return `sha256:${createHash8("sha256").update(bytes).digest("hex")}`;
|
|
23707
23781
|
}
|
|
23708
23782
|
function backupDatabaseFile(sourcePath, targetPath, storeId) {
|
|
23709
|
-
const resolvedSource =
|
|
23710
|
-
const resolvedTarget =
|
|
23783
|
+
const resolvedSource = resolve5(sourcePath);
|
|
23784
|
+
const resolvedTarget = resolve5(targetPath);
|
|
23711
23785
|
const sourceStat = lstatSync3(resolvedSource, { throwIfNoEntry: false });
|
|
23712
23786
|
if (!sourceStat || !sourceStat.isFile() || sourceStat.isSymbolicLink()) {
|
|
23713
23787
|
throw databaseError("runtime_path_invalid", resolvedSource, `source database ${resolvedSource} must be a regular file, not a link or directory`);
|
|
23714
23788
|
}
|
|
23715
23789
|
checkedParent(resolvedTarget, "backup target");
|
|
23716
|
-
if (
|
|
23790
|
+
if (existsSync8(resolvedTarget)) {
|
|
23717
23791
|
unlinkSync2(resolvedTarget);
|
|
23718
23792
|
}
|
|
23719
23793
|
const sourceDb = new DatabaseSync(resolvedSource);
|
|
@@ -23757,8 +23831,8 @@ function backupDatabaseFile(sourcePath, targetPath, storeId) {
|
|
|
23757
23831
|
};
|
|
23758
23832
|
}
|
|
23759
23833
|
function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVersion, maxSupportedVersion) {
|
|
23760
|
-
const resolvedBackup =
|
|
23761
|
-
const resolvedTarget =
|
|
23834
|
+
const resolvedBackup = resolve5(backupPath);
|
|
23835
|
+
const resolvedTarget = resolve5(targetPath);
|
|
23762
23836
|
const backupStat = lstatSync3(resolvedBackup, { throwIfNoEntry: false });
|
|
23763
23837
|
if (!backupStat || !backupStat.isFile() || backupStat.isSymbolicLink()) {
|
|
23764
23838
|
throw databaseError("runtime_path_invalid", resolvedBackup, `backup database ${resolvedBackup} must be a regular file, not a link or directory`);
|
|
@@ -23791,7 +23865,7 @@ function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVers
|
|
|
23791
23865
|
}
|
|
23792
23866
|
checkedParent(resolvedTarget, "restore target");
|
|
23793
23867
|
for (const file of [resolvedTarget, `${resolvedTarget}-wal`, `${resolvedTarget}-shm`]) {
|
|
23794
|
-
if (
|
|
23868
|
+
if (existsSync8(file)) {
|
|
23795
23869
|
try {
|
|
23796
23870
|
unlinkSync2(file);
|
|
23797
23871
|
} catch {
|
|
@@ -23821,29 +23895,29 @@ function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVers
|
|
|
23821
23895
|
};
|
|
23822
23896
|
}
|
|
23823
23897
|
function discoverProjectStores(projectRoot, options = {}) {
|
|
23824
|
-
const root =
|
|
23898
|
+
const root = resolve5(projectRoot);
|
|
23825
23899
|
const stores = [];
|
|
23826
|
-
const hubPath = options.hubDataPath ?
|
|
23827
|
-
if (
|
|
23900
|
+
const hubPath = options.hubDataPath ? resolve5(options.hubDataPath) : join8(root, ".kxm", "state", "kxm.db");
|
|
23901
|
+
if (existsSync8(hubPath)) {
|
|
23828
23902
|
stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: 3 });
|
|
23829
23903
|
}
|
|
23830
|
-
const registryPath =
|
|
23831
|
-
if (
|
|
23904
|
+
const registryPath = join8(root, ".kxm", "runtime", "registry.db");
|
|
23905
|
+
if (existsSync8(registryPath)) {
|
|
23832
23906
|
stores.push({ storeId: "registry", sourcePath: registryPath, maxSupportedVersion: 1 });
|
|
23833
23907
|
}
|
|
23834
|
-
const bindingsPath =
|
|
23835
|
-
if (
|
|
23908
|
+
const bindingsPath = join8(root, ".kxm", "runtime", "bindings.db");
|
|
23909
|
+
if (existsSync8(bindingsPath)) {
|
|
23836
23910
|
stores.push({ storeId: "binding-store", sourcePath: bindingsPath, maxSupportedVersion: 1 });
|
|
23837
23911
|
}
|
|
23838
|
-
const eventsDir =
|
|
23839
|
-
if (
|
|
23912
|
+
const eventsDir = join8(root, ".kxm", "runtime", "events");
|
|
23913
|
+
if (existsSync8(eventsDir)) {
|
|
23840
23914
|
const entries = readdirSync2(eventsDir, { withFileTypes: true });
|
|
23841
23915
|
for (const entry of entries) {
|
|
23842
23916
|
if (entry.isFile() && entry.name.endsWith(".db")) {
|
|
23843
23917
|
const key = entry.name.replace(/\.db$/, "");
|
|
23844
23918
|
stores.push({
|
|
23845
23919
|
storeId: `events:${key}`,
|
|
23846
|
-
sourcePath:
|
|
23920
|
+
sourcePath: join8(eventsDir, entry.name),
|
|
23847
23921
|
maxSupportedVersion: 3
|
|
23848
23922
|
});
|
|
23849
23923
|
}
|
|
@@ -23852,7 +23926,7 @@ function discoverProjectStores(projectRoot, options = {}) {
|
|
|
23852
23926
|
return stores;
|
|
23853
23927
|
}
|
|
23854
23928
|
function createBackup(options = {}) {
|
|
23855
|
-
const projectRoot = options.projectRoot ?
|
|
23929
|
+
const projectRoot = options.projectRoot ? resolve5(options.projectRoot) : process.cwd();
|
|
23856
23930
|
const stores = discoverProjectStores(projectRoot, {
|
|
23857
23931
|
...options.hubDataPath !== void 0 ? { hubDataPath: options.hubDataPath } : {}
|
|
23858
23932
|
});
|
|
@@ -23862,9 +23936,9 @@ function createBackup(options = {}) {
|
|
|
23862
23936
|
const now = /* @__PURE__ */ new Date();
|
|
23863
23937
|
const timestamp = now.toISOString().replace(/[:.]/g, "-");
|
|
23864
23938
|
const backupId = `bk_${randomBytes(8).toString("hex")}`;
|
|
23865
|
-
const outDir = options.outDir ?
|
|
23866
|
-
if (!
|
|
23867
|
-
|
|
23939
|
+
const outDir = options.outDir ? resolve5(options.outDir) : join8(projectRoot, ".kxm", "backups", `backup-${timestamp}`);
|
|
23940
|
+
if (!existsSync8(outDir)) {
|
|
23941
|
+
mkdirSync5(outDir, { recursive: true, mode: 448 });
|
|
23868
23942
|
}
|
|
23869
23943
|
const backedUpStores = [];
|
|
23870
23944
|
const usedFilenames = /* @__PURE__ */ new Set();
|
|
@@ -23875,7 +23949,7 @@ function createBackup(options = {}) {
|
|
|
23875
23949
|
filename = `${sanitizedId}-${filename}`;
|
|
23876
23950
|
}
|
|
23877
23951
|
usedFilenames.add(filename);
|
|
23878
|
-
const targetFile2 =
|
|
23952
|
+
const targetFile2 = join8(outDir, filename);
|
|
23879
23953
|
const record = backupDatabaseFile(store.sourcePath, targetFile2, store.storeId);
|
|
23880
23954
|
backedUpStores.push(record);
|
|
23881
23955
|
}
|
|
@@ -23890,24 +23964,24 @@ function createBackup(options = {}) {
|
|
|
23890
23964
|
const manifestSha256 = `sha256:${createHash8("sha256").update(manifestJson, "utf8").digest("hex")}`;
|
|
23891
23965
|
manifest.manifestSha256 = manifestSha256;
|
|
23892
23966
|
const finalJson = JSON.stringify(manifest, null, 2) + "\n";
|
|
23893
|
-
const manifestPath =
|
|
23894
|
-
|
|
23967
|
+
const manifestPath = join8(outDir, "manifest.json");
|
|
23968
|
+
writeFileSync5(manifestPath, finalJson, "utf8");
|
|
23895
23969
|
return { manifest, outDir };
|
|
23896
23970
|
}
|
|
23897
23971
|
function restoreBackup(manifestPathOrDir, options = {}) {
|
|
23898
|
-
let manifestPath =
|
|
23972
|
+
let manifestPath = resolve5(manifestPathOrDir);
|
|
23899
23973
|
const stat = lstatSync3(manifestPath, { throwIfNoEntry: false });
|
|
23900
23974
|
if (!stat) {
|
|
23901
23975
|
throw databaseError("runtime_path_invalid", manifestPath, `manifest path ${manifestPath} does not exist`);
|
|
23902
23976
|
}
|
|
23903
23977
|
if (stat.isDirectory()) {
|
|
23904
|
-
manifestPath =
|
|
23978
|
+
manifestPath = join8(manifestPath, "manifest.json");
|
|
23905
23979
|
}
|
|
23906
|
-
if (!
|
|
23980
|
+
if (!existsSync8(manifestPath)) {
|
|
23907
23981
|
throw databaseError("runtime_path_invalid", manifestPath, `backup manifest ${manifestPath} not found`);
|
|
23908
23982
|
}
|
|
23909
|
-
const manifestDir =
|
|
23910
|
-
const rawText =
|
|
23983
|
+
const manifestDir = dirname6(manifestPath);
|
|
23984
|
+
const rawText = readFileSync7(manifestPath, "utf8");
|
|
23911
23985
|
let manifest;
|
|
23912
23986
|
try {
|
|
23913
23987
|
manifest = JSON.parse(rawText);
|
|
@@ -23919,8 +23993,8 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23919
23993
|
}
|
|
23920
23994
|
const restoredStores = [];
|
|
23921
23995
|
for (const store of manifest.stores) {
|
|
23922
|
-
const backupFilePath =
|
|
23923
|
-
if (!
|
|
23996
|
+
const backupFilePath = join8(manifestDir, store.backupFile);
|
|
23997
|
+
if (!existsSync8(backupFilePath)) {
|
|
23924
23998
|
throw databaseError("restore_file_missing", backupFilePath, `backup file ${store.backupFile} missing from ${manifestDir}`);
|
|
23925
23999
|
}
|
|
23926
24000
|
const actualSha256 = fileSha256(backupFilePath);
|
|
@@ -23938,7 +24012,7 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23938
24012
|
let targetPath = store.sourcePath;
|
|
23939
24013
|
if (options.projectRoot && manifest.projectRoot && targetPath.startsWith(manifest.projectRoot)) {
|
|
23940
24014
|
const rel = targetPath.slice(manifest.projectRoot.length).replace(/^[\\/]+/, "");
|
|
23941
|
-
targetPath =
|
|
24015
|
+
targetPath = join8(resolve5(options.projectRoot), rel);
|
|
23942
24016
|
}
|
|
23943
24017
|
const result = restoreDatabaseFile(
|
|
23944
24018
|
backupFilePath,
|
|
@@ -23958,13 +24032,13 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23958
24032
|
|
|
23959
24033
|
// plugins/kxm/src/vnext-runtime-store.ts
|
|
23960
24034
|
function vnextRuntimePaths(options = {}) {
|
|
23961
|
-
const stateRoot = options.stateRoot ?
|
|
23962
|
-
const runtimeDir =
|
|
24035
|
+
const stateRoot = options.stateRoot ? resolve6(options.stateRoot) : vnextUserStateRoot({ ...options.env ? { env: options.env } : {}, ...options.homeDir ? { homeDir: options.homeDir } : {} });
|
|
24036
|
+
const runtimeDir = join9(stateRoot, "runtime");
|
|
23963
24037
|
return {
|
|
23964
24038
|
stateRoot,
|
|
23965
24039
|
runtimeDir,
|
|
23966
|
-
registryDb:
|
|
23967
|
-
projectsDir:
|
|
24040
|
+
registryDb: join9(runtimeDir, "registry.db"),
|
|
24041
|
+
projectsDir: join9(runtimeDir, "projects")
|
|
23968
24042
|
};
|
|
23969
24043
|
}
|
|
23970
24044
|
function runtimeIssue(phase, code, file, message) {
|
|
@@ -23976,9 +24050,9 @@ function runtimeError(code, file, message) {
|
|
|
23976
24050
|
function projectRuntimeKey(projectRoot) {
|
|
23977
24051
|
let canonical2;
|
|
23978
24052
|
try {
|
|
23979
|
-
canonical2 = realpathSync3.native(
|
|
24053
|
+
canonical2 = realpathSync3.native(resolve6(projectRoot));
|
|
23980
24054
|
} catch {
|
|
23981
|
-
canonical2 =
|
|
24055
|
+
canonical2 = resolve6(projectRoot);
|
|
23982
24056
|
}
|
|
23983
24057
|
const folded = process.platform === "win32" ? canonical2.toLocaleLowerCase("en-US") : canonical2;
|
|
23984
24058
|
return createHash9("sha256").update(folded, "utf8").digest("hex").slice(0, 24);
|
|
@@ -24012,7 +24086,7 @@ var VnextRuntimeRegistry = class {
|
|
|
24012
24086
|
path;
|
|
24013
24087
|
database;
|
|
24014
24088
|
constructor(path4) {
|
|
24015
|
-
this.path =
|
|
24089
|
+
this.path = resolve6(path4);
|
|
24016
24090
|
this.database = openDatabase(this.path, "runtime registry", {
|
|
24017
24091
|
schema: REGISTRY_SCHEMA,
|
|
24018
24092
|
version: VNEXT_REGISTRY_SCHEMA_VERSION,
|
|
@@ -24102,7 +24176,7 @@ var VnextRuntimeRegistry = class {
|
|
|
24102
24176
|
}
|
|
24103
24177
|
/** Register or revalidate a project's home binding. Home Runtime is immutable. */
|
|
24104
24178
|
registerProject(registration) {
|
|
24105
|
-
const projectRoot =
|
|
24179
|
+
const projectRoot = resolve6(registration.projectRoot);
|
|
24106
24180
|
const projectKey = projectRuntimeKey(projectRoot);
|
|
24107
24181
|
this.database.exec("BEGIN IMMEDIATE");
|
|
24108
24182
|
try {
|
|
@@ -24323,7 +24397,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
24323
24397
|
const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
|
|
24324
24398
|
const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
|
|
24325
24399
|
const assignments = compileAssignments(step, id, agent, sink);
|
|
24326
|
-
const
|
|
24400
|
+
const join50 = compileJoin(step, id, sink);
|
|
24327
24401
|
const requiredEvidence = compileEvidence(step, id, sink);
|
|
24328
24402
|
const transitions = compileTransitions(step, id, index, stepIndex, sink);
|
|
24329
24403
|
const outcomes = Object.keys(transitions).sort(compareCodeUnits4);
|
|
@@ -24351,7 +24425,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
24351
24425
|
transitions: orderedTransitions,
|
|
24352
24426
|
requiresPlanHash: requirePlanHash.includes(id),
|
|
24353
24427
|
assignments,
|
|
24354
|
-
join:
|
|
24428
|
+
join: join50
|
|
24355
24429
|
};
|
|
24356
24430
|
if (kind === "agent" || kind === "moa") {
|
|
24357
24431
|
if (!agent) return void 0;
|
|
@@ -24401,15 +24475,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
|
|
|
24401
24475
|
};
|
|
24402
24476
|
}
|
|
24403
24477
|
function compileJoin(step, stepId, sink) {
|
|
24404
|
-
const
|
|
24405
|
-
if (!
|
|
24406
|
-
const declared = stringValue2(
|
|
24478
|
+
const join50 = objectValue2(step.join);
|
|
24479
|
+
if (!join50) return { strategy: "all" };
|
|
24480
|
+
const declared = stringValue2(join50.strategy);
|
|
24407
24481
|
const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
|
|
24408
|
-
const minimumPassed = compileOptionalCount(
|
|
24482
|
+
const minimumPassed = compileOptionalCount(join50.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
|
|
24409
24483
|
const compiled = {
|
|
24410
24484
|
strategy,
|
|
24411
24485
|
...minimumPassed !== void 0 ? { minimumPassed } : {},
|
|
24412
|
-
...typeof
|
|
24486
|
+
...typeof join50.cancelRemaining === "boolean" ? { cancelRemaining: join50.cancelRemaining } : {}
|
|
24413
24487
|
};
|
|
24414
24488
|
return compiled;
|
|
24415
24489
|
}
|
|
@@ -24689,8 +24763,8 @@ var RECORD_LIMIT = 16 * 1024 * 1024;
|
|
|
24689
24763
|
// plugins/kxm/src/prices.ts
|
|
24690
24764
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
24691
24765
|
import { createHash as createHash10 } from "node:crypto";
|
|
24692
|
-
import { existsSync as
|
|
24693
|
-
import { join as
|
|
24766
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9, statSync } from "node:fs";
|
|
24767
|
+
import { join as join10 } from "node:path";
|
|
24694
24768
|
|
|
24695
24769
|
// plugins/kxm/src/price-calc.ts
|
|
24696
24770
|
var PRICES_SCHEMA = "kxm.prices.v1";
|
|
@@ -24842,11 +24916,11 @@ function parsePriceCatalog(text) {
|
|
|
24842
24916
|
return catalog;
|
|
24843
24917
|
}
|
|
24844
24918
|
function loadPriceCatalog(rootOrPath) {
|
|
24845
|
-
const candidatePath =
|
|
24846
|
-
if (!candidatePath || !
|
|
24919
|
+
const candidatePath = existsSync10(join10(rootOrPath, ".kxm", "prices.yaml")) ? join10(rootOrPath, ".kxm", "prices.yaml") : existsSync10(join10(rootOrPath, "prices.yaml")) ? join10(rootOrPath, "prices.yaml") : existsSync10(rootOrPath) && statSync(rootOrPath).isFile() ? rootOrPath : void 0;
|
|
24920
|
+
if (!candidatePath || !existsSync10(candidatePath)) {
|
|
24847
24921
|
return void 0;
|
|
24848
24922
|
}
|
|
24849
|
-
const content =
|
|
24923
|
+
const content = readFileSync9(candidatePath, "utf8");
|
|
24850
24924
|
return parsePriceCatalog(content);
|
|
24851
24925
|
}
|
|
24852
24926
|
function loadPriceCatalogForEstimate(options) {
|
|
@@ -24867,13 +24941,13 @@ var import_yaml5 = __toESM(require_dist(), 1);
|
|
|
24867
24941
|
|
|
24868
24942
|
// plugins/kxm/src/producers.ts
|
|
24869
24943
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
24870
|
-
import { existsSync as
|
|
24871
|
-
import { join as
|
|
24944
|
+
import { existsSync as existsSync11, readFileSync as readFileSync10, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7, readdirSync as readdirSync3 } from "node:fs";
|
|
24945
|
+
import { join as join11 } from "node:path";
|
|
24872
24946
|
var empty = () => ({ schema: "kxm.producers.v1", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), promoted: [], demoted: [], enabled: [], disabled: [], roles: {} });
|
|
24873
24947
|
function loadProducerPolicy(root) {
|
|
24874
|
-
const path4 =
|
|
24875
|
-
if (!
|
|
24876
|
-
const value = (0, import_yaml4.parse)(
|
|
24948
|
+
const path4 = join11(root, ".kxm", "producers.yaml");
|
|
24949
|
+
if (!existsSync11(path4)) return empty();
|
|
24950
|
+
const value = (0, import_yaml4.parse)(readFileSync10(path4, "utf8"));
|
|
24877
24951
|
if (value?.schema !== "kxm.producers.v1" || !Array.isArray(value.promoted) || !Array.isArray(value.demoted)) throw new Error("invalid .kxm/producers.yaml");
|
|
24878
24952
|
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")])) : {} };
|
|
24879
24953
|
}
|
|
@@ -24883,8 +24957,8 @@ function updateProducer(root, model, status) {
|
|
|
24883
24957
|
policy.demoted = policy.demoted.filter((x2) => x2 !== model);
|
|
24884
24958
|
policy[status].push(model);
|
|
24885
24959
|
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24886
|
-
|
|
24887
|
-
|
|
24960
|
+
mkdirSync7(join11(root, ".kxm"), { recursive: true });
|
|
24961
|
+
writeFileSync7(join11(root, ".kxm", "producers.yaml"), (0, import_yaml4.stringify)(policy), "utf8");
|
|
24888
24962
|
return policy;
|
|
24889
24963
|
}
|
|
24890
24964
|
function setModelState(root, model, state, role, removeRole2 = false) {
|
|
@@ -24894,10 +24968,10 @@ function setModelState(root, model, state, role, removeRole2 = false) {
|
|
|
24894
24968
|
policy[state].push(model);
|
|
24895
24969
|
if (role) {
|
|
24896
24970
|
if (!/^[a-z][a-z0-9_-]{0,63}$/i.test(role)) throw new Error("invalid role id");
|
|
24897
|
-
const rolePath =
|
|
24971
|
+
const rolePath = join11(root, ".kxm", "roles", `${role}.yaml`);
|
|
24898
24972
|
let roleFile = {};
|
|
24899
|
-
if (
|
|
24900
|
-
const parsed = (0, import_yaml4.parse)(
|
|
24973
|
+
if (existsSync11(rolePath)) {
|
|
24974
|
+
const parsed = (0, import_yaml4.parse)(readFileSync10(rolePath, "utf8"));
|
|
24901
24975
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) roleFile = parsed;
|
|
24902
24976
|
}
|
|
24903
24977
|
const roster = Array.isArray(roleFile.roster) ? roleFile.roster.filter((entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)) : [];
|
|
@@ -24908,42 +24982,42 @@ function setModelState(root, model, state, role, removeRole2 = false) {
|
|
|
24908
24982
|
roleFile.schema ??= "kxm.role.v1";
|
|
24909
24983
|
roleFile.id ??= role;
|
|
24910
24984
|
roleFile.roster = roster;
|
|
24911
|
-
|
|
24912
|
-
|
|
24985
|
+
mkdirSync7(join11(root, ".kxm", "roles"), { recursive: true });
|
|
24986
|
+
writeFileSync7(rolePath, (0, import_yaml4.stringify)(roleFile), "utf8");
|
|
24913
24987
|
}
|
|
24914
24988
|
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24915
|
-
|
|
24916
|
-
|
|
24989
|
+
mkdirSync7(join11(root, ".kxm"), { recursive: true });
|
|
24990
|
+
writeFileSync7(join11(root, ".kxm", "producers.yaml"), (0, import_yaml4.stringify)(policy), "utf8");
|
|
24917
24991
|
return policy;
|
|
24918
24992
|
}
|
|
24919
24993
|
function listRoleBindings(root) {
|
|
24920
|
-
const dir =
|
|
24994
|
+
const dir = join11(root, ".kxm", "roles");
|
|
24921
24995
|
const result = {};
|
|
24922
|
-
if (!
|
|
24996
|
+
if (!existsSync11(dir)) return result;
|
|
24923
24997
|
for (const file of readdirSync3(dir).filter((name) => name.endsWith(".yaml"))) {
|
|
24924
24998
|
const role = file.slice(0, -5);
|
|
24925
|
-
const value = (0, import_yaml4.parse)(
|
|
24999
|
+
const value = (0, import_yaml4.parse)(readFileSync10(join11(dir, file), "utf8"));
|
|
24926
25000
|
result[role] = (value.roster ?? []).map((entry) => entry.model).filter((model) => typeof model === "string");
|
|
24927
25001
|
}
|
|
24928
25002
|
return result;
|
|
24929
25003
|
}
|
|
24930
25004
|
function listInventoryModels(root) {
|
|
24931
|
-
const path4 =
|
|
24932
|
-
if (!
|
|
24933
|
-
const value = (0, import_yaml4.parse)(
|
|
25005
|
+
const path4 = join11(root, ".kxm", "models", "inventory.yaml");
|
|
25006
|
+
if (!existsSync11(path4)) return [];
|
|
25007
|
+
const value = (0, import_yaml4.parse)(readFileSync10(path4, "utf8"));
|
|
24934
25008
|
return (value.models ?? []).map((m2) => m2.id).filter((id) => typeof id === "string");
|
|
24935
25009
|
}
|
|
24936
25010
|
|
|
24937
25011
|
// plugins/kxm/src/artifacts-exist.ts
|
|
24938
25012
|
import { lstatSync as lstatSync5, realpathSync as realpathSync4, statSync as statSync2 } from "node:fs";
|
|
24939
|
-
import { isAbsolute as
|
|
25013
|
+
import { isAbsolute as isAbsolute4, relative as relative3, resolve as resolve7 } from "node:path";
|
|
24940
25014
|
function staysUnder(root, candidate) {
|
|
24941
25015
|
const child = relative3(root, candidate);
|
|
24942
|
-
return child === "" || !
|
|
25016
|
+
return child === "" || !isAbsolute4(child) && child !== ".." && !child.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`);
|
|
24943
25017
|
}
|
|
24944
25018
|
function verifyArtifactExists(rootInput, pathInput) {
|
|
24945
|
-
const lexicalRoot =
|
|
24946
|
-
const lexicalPath =
|
|
25019
|
+
const lexicalRoot = resolve7(rootInput);
|
|
25020
|
+
const lexicalPath = resolve7(pathInput);
|
|
24947
25021
|
if (!staysUnder(lexicalRoot, lexicalPath)) {
|
|
24948
25022
|
return { ok: false, error: "artifact_outside_workspace_assets", path: lexicalPath };
|
|
24949
25023
|
}
|
|
@@ -25563,7 +25637,7 @@ function formatRoutingReport(report2, options = {}) {
|
|
|
25563
25637
|
|
|
25564
25638
|
// plugins/kxm/src/vnext-runtime-supervisor.ts
|
|
25565
25639
|
function vnextSupervisorTokenFile(paths) {
|
|
25566
|
-
return
|
|
25640
|
+
return join12(paths.runtimeDir, "supervisor.token");
|
|
25567
25641
|
}
|
|
25568
25642
|
function readVnextSupervisorToken(paths) {
|
|
25569
25643
|
const file = vnextSupervisorTokenFile(paths);
|
|
@@ -25572,7 +25646,7 @@ function readVnextSupervisorToken(paths) {
|
|
|
25572
25646
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
25573
25647
|
throw runtimeError("runtime_path_invalid", file, "supervisor token file must be a regular file, not a link");
|
|
25574
25648
|
}
|
|
25575
|
-
const token =
|
|
25649
|
+
const token = readFileSync11(file, "utf8").trim();
|
|
25576
25650
|
return token.length >= 32 ? token : void 0;
|
|
25577
25651
|
}
|
|
25578
25652
|
function processAlive(pid) {
|
|
@@ -25586,11 +25660,11 @@ function processAlive(pid) {
|
|
|
25586
25660
|
var HEARTBEAT_STALE_MS = 15e3;
|
|
25587
25661
|
var SUPERVISOR_ERROR_MAX_AGE_MS = 3e4;
|
|
25588
25662
|
function supervisorErrorFile(paths) {
|
|
25589
|
-
return
|
|
25663
|
+
return join12(paths.runtimeDir, "supervisor.error");
|
|
25590
25664
|
}
|
|
25591
25665
|
function clearSupervisorError(paths) {
|
|
25592
25666
|
const file = supervisorErrorFile(paths);
|
|
25593
|
-
if (
|
|
25667
|
+
if (existsSync12(file)) rmSync3(file, { force: true });
|
|
25594
25668
|
}
|
|
25595
25669
|
function readRecentSupervisorError(paths) {
|
|
25596
25670
|
const file = supervisorErrorFile(paths);
|
|
@@ -25599,13 +25673,13 @@ function readRecentSupervisorError(paths) {
|
|
|
25599
25673
|
const ageMs = Date.now() - stat.mtimeMs;
|
|
25600
25674
|
if (ageMs > SUPERVISOR_ERROR_MAX_AGE_MS) return void 0;
|
|
25601
25675
|
try {
|
|
25602
|
-
return
|
|
25676
|
+
return readFileSync11(file, "utf8").trim();
|
|
25603
25677
|
} catch {
|
|
25604
25678
|
return void 0;
|
|
25605
25679
|
}
|
|
25606
25680
|
}
|
|
25607
25681
|
function vnextSupervisorStatus(paths) {
|
|
25608
|
-
if (!
|
|
25682
|
+
if (!existsSync12(paths.registryDb)) return { running: false };
|
|
25609
25683
|
const registry = new VnextRuntimeRegistry(paths.registryDb);
|
|
25610
25684
|
try {
|
|
25611
25685
|
const record = registry.supervisor();
|
|
@@ -25666,7 +25740,7 @@ async function ensureVnextSupervisor(options = {}) {
|
|
|
25666
25740
|
throw runtimeError("runtime_supervisor_unreachable", paths.registryDb, `runtime supervisor pid ${status.pid} is registered as running but cannot be probed`);
|
|
25667
25741
|
}
|
|
25668
25742
|
clearSupervisorError(paths);
|
|
25669
|
-
const scriptPath =
|
|
25743
|
+
const scriptPath = join12(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
|
|
25670
25744
|
const spawnImpl = options.spawnImpl ?? ((script, env) => {
|
|
25671
25745
|
const child = spawn2(process.execPath, [script], {
|
|
25672
25746
|
detached: true,
|
|
@@ -25719,7 +25793,7 @@ async function vnextRuntimeRequest(handle, method, path4, body) {
|
|
|
25719
25793
|
|
|
25720
25794
|
// plugins/kxm/src/cli/types.ts
|
|
25721
25795
|
import { spawn as spawn3 } from "node:child_process";
|
|
25722
|
-
import { join as
|
|
25796
|
+
import { join as join15, resolve as resolve9 } from "node:path";
|
|
25723
25797
|
|
|
25724
25798
|
// plugins/kxm/src/redact.ts
|
|
25725
25799
|
var SECRET_PATTERNS = [
|
|
@@ -25749,8 +25823,8 @@ function redactStringList(values, maxItems = 32) {
|
|
|
25749
25823
|
}
|
|
25750
25824
|
|
|
25751
25825
|
// plugins/kxm/src/telemetry.ts
|
|
25752
|
-
import { appendFileSync, mkdirSync as
|
|
25753
|
-
import { dirname as
|
|
25826
|
+
import { appendFileSync, mkdirSync as mkdirSync9, readFileSync as readFileSync12 } from "node:fs";
|
|
25827
|
+
import { dirname as dirname9, join as join13 } from "node:path";
|
|
25754
25828
|
var TELEMETRY_SCHEMA = "kxm.telemetry.v1";
|
|
25755
25829
|
function inferImprovementTarget(input) {
|
|
25756
25830
|
const explicit = input.env?.KXM_IMPROVE_TARGET?.trim();
|
|
@@ -25760,12 +25834,12 @@ function inferImprovementTarget(input) {
|
|
|
25760
25834
|
return project || workflowId ? "project" : "cli";
|
|
25761
25835
|
}
|
|
25762
25836
|
function appendTelemetry(path4, event) {
|
|
25763
|
-
|
|
25837
|
+
mkdirSync9(dirname9(path4), { recursive: true });
|
|
25764
25838
|
appendFileSync(path4, `${JSON.stringify(event)}
|
|
25765
25839
|
`, { encoding: "utf8", mode: 384 });
|
|
25766
25840
|
}
|
|
25767
25841
|
function telemetryPath(logsDir) {
|
|
25768
|
-
return
|
|
25842
|
+
return join13(logsDir, "telemetry.jsonl");
|
|
25769
25843
|
}
|
|
25770
25844
|
function makeTelemetryEvent(input) {
|
|
25771
25845
|
return {
|
|
@@ -25780,7 +25854,7 @@ function makeTelemetryEvent(input) {
|
|
|
25780
25854
|
function readRoutingRecords(path4) {
|
|
25781
25855
|
const records = [];
|
|
25782
25856
|
try {
|
|
25783
|
-
const raw =
|
|
25857
|
+
const raw = readFileSync12(path4, "utf8");
|
|
25784
25858
|
for (const line of raw.split(/\r?\n/)) {
|
|
25785
25859
|
if (!line.trim()) continue;
|
|
25786
25860
|
try {
|
|
@@ -25857,9 +25931,9 @@ function workerResult(worker, payload) {
|
|
|
25857
25931
|
}
|
|
25858
25932
|
|
|
25859
25933
|
// plugins/kxm/src/hub-binding.ts
|
|
25860
|
-
import { existsSync as
|
|
25861
|
-
import { homedir as
|
|
25862
|
-
import { dirname as
|
|
25934
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync13, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "node:fs";
|
|
25935
|
+
import { homedir as homedir4 } from "node:os";
|
|
25936
|
+
import { dirname as dirname10, isAbsolute as isAbsolute6, join as join14, resolve as resolve8 } from "node:path";
|
|
25863
25937
|
var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
25864
25938
|
var HUB_HEALTH_PROBE_MS = 300;
|
|
25865
25939
|
var HubBindingError = class extends Error {
|
|
@@ -25868,24 +25942,24 @@ var HubBindingError = class extends Error {
|
|
|
25868
25942
|
this.name = "HubBindingError";
|
|
25869
25943
|
}
|
|
25870
25944
|
};
|
|
25871
|
-
function
|
|
25945
|
+
function resolveUserStateRoot2(env) {
|
|
25872
25946
|
const explicit = env.KXM_STATE_HOME?.trim();
|
|
25873
25947
|
if (explicit) {
|
|
25874
|
-
if (!
|
|
25875
|
-
return
|
|
25948
|
+
if (!isAbsolute6(explicit)) throw new HubBindingError("local_state_root_not_absolute");
|
|
25949
|
+
return resolve8(explicit);
|
|
25876
25950
|
}
|
|
25877
25951
|
if (process.platform === "win32") {
|
|
25878
25952
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
25879
|
-
const base2 = localAppData &&
|
|
25880
|
-
return
|
|
25953
|
+
const base2 = localAppData && isAbsolute6(localAppData) ? localAppData : join14(homedir4(), "AppData", "Local");
|
|
25954
|
+
return resolve8(base2, "KXM");
|
|
25881
25955
|
}
|
|
25882
|
-
if (process.platform === "darwin") return
|
|
25956
|
+
if (process.platform === "darwin") return resolve8(homedir4(), "Library", "Application Support", "KXM");
|
|
25883
25957
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
25884
|
-
const base = xdgState &&
|
|
25885
|
-
return
|
|
25958
|
+
const base = xdgState && isAbsolute6(xdgState) ? xdgState : join14(homedir4(), ".local", "state");
|
|
25959
|
+
return resolve8(base, "kxm");
|
|
25886
25960
|
}
|
|
25887
25961
|
function hubBindingFile(env = process.env) {
|
|
25888
|
-
return
|
|
25962
|
+
return join14(resolveUserStateRoot2(env), "hub-binding.json");
|
|
25889
25963
|
}
|
|
25890
25964
|
function validateHubUrl(raw) {
|
|
25891
25965
|
let parsed;
|
|
@@ -25910,10 +25984,10 @@ function isAbortError(error) {
|
|
|
25910
25984
|
}
|
|
25911
25985
|
function readHubBinding(env = process.env) {
|
|
25912
25986
|
const file = hubBindingFile(env);
|
|
25913
|
-
if (!
|
|
25987
|
+
if (!existsSync13(file)) return void 0;
|
|
25914
25988
|
let parsed;
|
|
25915
25989
|
try {
|
|
25916
|
-
parsed = JSON.parse(
|
|
25990
|
+
parsed = JSON.parse(readFileSync13(file, "utf8"));
|
|
25917
25991
|
} catch {
|
|
25918
25992
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
25919
25993
|
}
|
|
@@ -25935,21 +26009,21 @@ function readHubBinding(env = process.env) {
|
|
|
25935
26009
|
}
|
|
25936
26010
|
function writeHubBinding(record, env = process.env) {
|
|
25937
26011
|
const file = hubBindingFile(env);
|
|
25938
|
-
|
|
25939
|
-
const temporary =
|
|
26012
|
+
mkdirSync10(dirname10(file), { recursive: true, mode: 448 });
|
|
26013
|
+
const temporary = join14(dirname10(file), `.hub-binding-${process.pid}.tmp`);
|
|
25940
26014
|
try {
|
|
25941
|
-
|
|
26015
|
+
writeFileSync9(temporary, `${JSON.stringify(record, null, 2)}
|
|
25942
26016
|
`, { encoding: "utf8", mode: 384 });
|
|
25943
|
-
|
|
26017
|
+
renameSync4(temporary, file);
|
|
25944
26018
|
} finally {
|
|
25945
|
-
|
|
26019
|
+
rmSync4(temporary, { force: true });
|
|
25946
26020
|
}
|
|
25947
26021
|
return file;
|
|
25948
26022
|
}
|
|
25949
26023
|
function removeHubBinding(env = process.env) {
|
|
25950
26024
|
const file = hubBindingFile(env);
|
|
25951
26025
|
try {
|
|
25952
|
-
|
|
26026
|
+
rmSync4(file);
|
|
25953
26027
|
return true;
|
|
25954
26028
|
} catch (error) {
|
|
25955
26029
|
if (error.code === "ENOENT") return false;
|
|
@@ -25983,7 +26057,7 @@ async function probeHubHealth(url, fetchImpl, timeoutMs = HUB_HEALTH_PROBE_MS) {
|
|
|
25983
26057
|
// plugins/kxm/src/cli/types.ts
|
|
25984
26058
|
function spawnScript(scriptName, extraEnv = {}) {
|
|
25985
26059
|
return new Promise((resolveExit) => {
|
|
25986
|
-
const child = spawn3(process.execPath, [
|
|
26060
|
+
const child = spawn3(process.execPath, [join15(findKxmRepoRoot(import.meta.url), "scripts", scriptName)], {
|
|
25987
26061
|
stdio: "inherit",
|
|
25988
26062
|
env: { ...process.env, ...extraEnv }
|
|
25989
26063
|
});
|
|
@@ -26067,16 +26141,16 @@ function redactCliValue(value, field = "") {
|
|
|
26067
26141
|
return value;
|
|
26068
26142
|
}
|
|
26069
26143
|
function workspaceDirs(cwd, workspaceFlag, env) {
|
|
26070
|
-
const workdir =
|
|
26071
|
-
const workspace =
|
|
26144
|
+
const workdir = resolve9(env.KXM_WORKDIR?.trim() || cwd);
|
|
26145
|
+
const workspace = resolve9(workdir, workspaceFlag || env.KXM_WORKSPACE_DIR?.trim() || ".kxm");
|
|
26072
26146
|
const derive = workspaceFlag !== void 0;
|
|
26073
26147
|
return {
|
|
26074
26148
|
workdir,
|
|
26075
26149
|
workspace,
|
|
26076
|
-
config: derive ?
|
|
26077
|
-
logs: derive ?
|
|
26078
|
-
assets: derive ?
|
|
26079
|
-
state: derive ?
|
|
26150
|
+
config: derive ? join15(workspace, "config") : resolve9(workdir, env.KXM_CONFIG_DIR?.trim() || join15(workspace, "config")),
|
|
26151
|
+
logs: derive ? join15(workspace, "logs") : resolve9(workdir, env.KXM_LOGS_DIR?.trim() || join15(workspace, "logs")),
|
|
26152
|
+
assets: derive ? join15(workspace, "assets") : resolve9(workdir, env.KXM_ASSETS_DIR?.trim() || join15(workspace, "assets")),
|
|
26153
|
+
state: derive ? join15(workspace, "state") : resolve9(workdir, env.KXM_STATE_DIR?.trim() || join15(workspace, "state"))
|
|
26080
26154
|
};
|
|
26081
26155
|
}
|
|
26082
26156
|
function maskEnvName(name) {
|
|
@@ -26144,20 +26218,20 @@ function workspaceEnv(runtime) {
|
|
|
26144
26218
|
// plugins/kxm/src/cli/roles.ts
|
|
26145
26219
|
var import_yaml8 = __toESM(require_dist(), 1);
|
|
26146
26220
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
26147
|
-
import { existsSync as
|
|
26148
|
-
import { join as
|
|
26221
|
+
import { existsSync as existsSync16, readFileSync as readFileSync16 } from "node:fs";
|
|
26222
|
+
import { join as join18, resolve as resolve12 } from "node:path";
|
|
26149
26223
|
import { createInterface } from "node:readline";
|
|
26150
26224
|
|
|
26151
26225
|
// plugins/kxm/src/role.ts
|
|
26152
26226
|
var import_yaml7 = __toESM(require_dist(), 1);
|
|
26153
|
-
import { existsSync as
|
|
26154
|
-
import { join as
|
|
26227
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync12, readdirSync as readdirSync4, readFileSync as readFileSync15, rmSync as rmSync5, writeFileSync as writeFileSync11 } from "node:fs";
|
|
26228
|
+
import { join as join17 } from "node:path";
|
|
26155
26229
|
|
|
26156
26230
|
// plugins/kxm/src/config.ts
|
|
26157
26231
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
26158
|
-
import { existsSync as
|
|
26159
|
-
import { homedir as
|
|
26160
|
-
import { dirname as
|
|
26232
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "node:fs";
|
|
26233
|
+
import { homedir as homedir5 } from "node:os";
|
|
26234
|
+
import { dirname as dirname11, join as join16, resolve as resolve10 } from "node:path";
|
|
26161
26235
|
var KXM_CONFIG_SCHEMA = "kxm.config.v1";
|
|
26162
26236
|
var DEFAULT_KXM_CONFIG = {
|
|
26163
26237
|
schema: KXM_CONFIG_SCHEMA,
|
|
@@ -26210,11 +26284,11 @@ var DEFAULT_KXM_CONFIG = {
|
|
|
26210
26284
|
}
|
|
26211
26285
|
};
|
|
26212
26286
|
function userConfigDirectory(overrideDir) {
|
|
26213
|
-
if (overrideDir) return
|
|
26214
|
-
return
|
|
26287
|
+
if (overrideDir) return resolve10(overrideDir);
|
|
26288
|
+
return resolve10(process.env.KXM_USER_CONFIG_DIR?.trim() || join16(homedir5(), ".config", "kxm"));
|
|
26215
26289
|
}
|
|
26216
26290
|
function repoConfigDirectory(repoRoot) {
|
|
26217
|
-
return
|
|
26291
|
+
return resolve10(repoRoot, ".kxm");
|
|
26218
26292
|
}
|
|
26219
26293
|
function deepMerge(target, source) {
|
|
26220
26294
|
const result = { ...target };
|
|
@@ -26234,14 +26308,14 @@ function normalizeHubConfig(raw) {
|
|
|
26234
26308
|
}
|
|
26235
26309
|
function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
|
|
26236
26310
|
const userDir = userConfigDirectory(options.userConfigDir);
|
|
26237
|
-
const userConfigFile =
|
|
26311
|
+
const userConfigFile = join16(userDir, "config.yaml");
|
|
26238
26312
|
const repoDir = repoConfigDirectory(repoRoot);
|
|
26239
|
-
const repoConfigFile =
|
|
26313
|
+
const repoConfigFile = join16(repoDir, "config.yaml");
|
|
26240
26314
|
let userRaw = {};
|
|
26241
26315
|
let userLoadedPath;
|
|
26242
|
-
if (
|
|
26316
|
+
if (existsSync14(userConfigFile)) {
|
|
26243
26317
|
try {
|
|
26244
|
-
const text =
|
|
26318
|
+
const text = readFileSync14(userConfigFile, "utf8");
|
|
26245
26319
|
userRaw = (0, import_yaml6.parse)(text) ?? {};
|
|
26246
26320
|
userLoadedPath = userConfigFile;
|
|
26247
26321
|
} catch (error) {
|
|
@@ -26250,9 +26324,9 @@ function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
|
|
|
26250
26324
|
}
|
|
26251
26325
|
let repoRaw = {};
|
|
26252
26326
|
let repoLoadedPath;
|
|
26253
|
-
if (
|
|
26327
|
+
if (existsSync14(repoConfigFile)) {
|
|
26254
26328
|
try {
|
|
26255
|
-
const text =
|
|
26329
|
+
const text = readFileSync14(repoConfigFile, "utf8");
|
|
26256
26330
|
repoRaw = (0, import_yaml6.parse)(text) ?? {};
|
|
26257
26331
|
repoLoadedPath = repoConfigFile;
|
|
26258
26332
|
} catch (error) {
|
|
@@ -26289,12 +26363,12 @@ function getKxmConfigValue(config, keyPath) {
|
|
|
26289
26363
|
}
|
|
26290
26364
|
function setKxmConfigValue(repoRoot, keyPath, value, options = {}) {
|
|
26291
26365
|
const scope = options.scope ?? "project";
|
|
26292
|
-
const targetFile2 = scope === "user" ?
|
|
26293
|
-
|
|
26366
|
+
const targetFile2 = scope === "user" ? join16(userConfigDirectory(options.userConfigDir), "config.yaml") : join16(repoConfigDirectory(repoRoot), "config.yaml");
|
|
26367
|
+
mkdirSync11(dirname11(targetFile2), { recursive: true });
|
|
26294
26368
|
let existing = {};
|
|
26295
|
-
if (
|
|
26369
|
+
if (existsSync14(targetFile2)) {
|
|
26296
26370
|
try {
|
|
26297
|
-
existing = (0, import_yaml6.parse)(
|
|
26371
|
+
existing = (0, import_yaml6.parse)(readFileSync14(targetFile2, "utf8")) ?? {};
|
|
26298
26372
|
} catch {
|
|
26299
26373
|
existing = {};
|
|
26300
26374
|
}
|
|
@@ -26312,7 +26386,7 @@ function setKxmConfigValue(repoRoot, keyPath, value, options = {}) {
|
|
|
26312
26386
|
cursor2 = cursor2[p];
|
|
26313
26387
|
}
|
|
26314
26388
|
cursor2[parts[parts.length - 1]] = value;
|
|
26315
|
-
|
|
26389
|
+
writeFileSync10(targetFile2, (0, import_yaml6.stringify)(existing).trim() + "\n", "utf8");
|
|
26316
26390
|
}
|
|
26317
26391
|
function formatKxmConfig(config) {
|
|
26318
26392
|
const display = {
|
|
@@ -26405,21 +26479,21 @@ var DEFAULT_ROLES = {
|
|
|
26405
26479
|
};
|
|
26406
26480
|
function rolesDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
26407
26481
|
if (scope === "global") {
|
|
26408
|
-
return
|
|
26482
|
+
return join17(userConfigDirectory(userConfigDir), "roles");
|
|
26409
26483
|
}
|
|
26410
|
-
return
|
|
26484
|
+
return join17(repoConfigDirectory(repoRoot), "roles");
|
|
26411
26485
|
}
|
|
26412
26486
|
function ensureRolesDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
26413
26487
|
const dir = rolesDirectory(scope, repoRoot, userConfigDir);
|
|
26414
|
-
if (!
|
|
26415
|
-
|
|
26488
|
+
if (!existsSync15(dir)) {
|
|
26489
|
+
mkdirSync12(dir, { recursive: true });
|
|
26416
26490
|
}
|
|
26417
26491
|
return dir;
|
|
26418
26492
|
}
|
|
26419
26493
|
function parseRoleFile(filePath) {
|
|
26420
|
-
if (!
|
|
26494
|
+
if (!existsSync15(filePath)) return void 0;
|
|
26421
26495
|
try {
|
|
26422
|
-
const raw =
|
|
26496
|
+
const raw = readFileSync15(filePath, "utf8");
|
|
26423
26497
|
const parsed = (0, import_yaml7.parse)(raw);
|
|
26424
26498
|
if (!parsed || typeof parsed !== "object" || parsed.schema !== KXM_ROLE_SCHEMA) {
|
|
26425
26499
|
return void 0;
|
|
@@ -26446,10 +26520,10 @@ function listRoles(options = {}) {
|
|
|
26446
26520
|
const globalDir = rolesDirectory("global", repoRoot, options.userConfigDir);
|
|
26447
26521
|
const localDir = rolesDirectory("local", repoRoot, options.userConfigDir);
|
|
26448
26522
|
const localRoles = /* @__PURE__ */ new Map();
|
|
26449
|
-
if (scopeFilter !== "global" &&
|
|
26523
|
+
if (scopeFilter !== "global" && existsSync15(localDir)) {
|
|
26450
26524
|
for (const entry of readdirSync4(localDir)) {
|
|
26451
26525
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
26452
|
-
const filePath =
|
|
26526
|
+
const filePath = join17(localDir, entry);
|
|
26453
26527
|
const parsed = parseRoleFile(filePath);
|
|
26454
26528
|
if (parsed) {
|
|
26455
26529
|
localRoles.set(parsed.id, { role: parsed, filePath });
|
|
@@ -26458,10 +26532,10 @@ function listRoles(options = {}) {
|
|
|
26458
26532
|
}
|
|
26459
26533
|
}
|
|
26460
26534
|
const globalRoles = /* @__PURE__ */ new Map();
|
|
26461
|
-
if (scopeFilter !== "local" &&
|
|
26535
|
+
if (scopeFilter !== "local" && existsSync15(globalDir)) {
|
|
26462
26536
|
for (const entry of readdirSync4(globalDir)) {
|
|
26463
26537
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
26464
|
-
const filePath =
|
|
26538
|
+
const filePath = join17(globalDir, entry);
|
|
26465
26539
|
const parsed = parseRoleFile(filePath);
|
|
26466
26540
|
if (parsed) {
|
|
26467
26541
|
globalRoles.set(parsed.id, { role: parsed, filePath });
|
|
@@ -26509,13 +26583,13 @@ function getRole(roleId, options = {}) {
|
|
|
26509
26583
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26510
26584
|
if (scope !== "global") {
|
|
26511
26585
|
const localDir = rolesDirectory("local", repoRoot, options.userConfigDir);
|
|
26512
|
-
const localFile =
|
|
26586
|
+
const localFile = join17(localDir, `${roleId}.yaml`);
|
|
26513
26587
|
const parsed = parseRoleFile(localFile);
|
|
26514
26588
|
if (parsed) return { role: parsed, scope: "local", filePath: localFile };
|
|
26515
26589
|
}
|
|
26516
26590
|
if (scope !== "local") {
|
|
26517
26591
|
const globalDir = rolesDirectory("global", repoRoot, options.userConfigDir);
|
|
26518
|
-
const globalFile =
|
|
26592
|
+
const globalFile = join17(globalDir, `${roleId}.yaml`);
|
|
26519
26593
|
const parsed = parseRoleFile(globalFile);
|
|
26520
26594
|
if (parsed) return { role: parsed, scope: "global", filePath: globalFile };
|
|
26521
26595
|
}
|
|
@@ -26525,22 +26599,22 @@ function addRole(role, options = {}) {
|
|
|
26525
26599
|
const scope = options.scope ?? "local";
|
|
26526
26600
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26527
26601
|
const dir = ensureRolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
26528
|
-
const filePath =
|
|
26529
|
-
if (
|
|
26602
|
+
const filePath = join17(dir, `${role.id}.yaml`);
|
|
26603
|
+
if (existsSync15(filePath) && !options.overwrite) {
|
|
26530
26604
|
throw new Error(`role_already_exists: role '${role.id}' already exists at ${filePath}`);
|
|
26531
26605
|
}
|
|
26532
|
-
|
|
26606
|
+
writeFileSync11(filePath, (0, import_yaml7.stringify)(role), "utf8");
|
|
26533
26607
|
return { id: role.id, filePath, scope };
|
|
26534
26608
|
}
|
|
26535
26609
|
function removeRole(roleId, options = {}) {
|
|
26536
26610
|
const scope = options.scope ?? "local";
|
|
26537
26611
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26538
26612
|
const dir = rolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
26539
|
-
const filePath =
|
|
26540
|
-
if (!
|
|
26613
|
+
const filePath = join17(dir, `${roleId}.yaml`);
|
|
26614
|
+
if (!existsSync15(filePath)) {
|
|
26541
26615
|
throw new Error(`role_not_found: role '${roleId}' not found in ${scope} directory (${filePath})`);
|
|
26542
26616
|
}
|
|
26543
|
-
|
|
26617
|
+
rmSync5(filePath);
|
|
26544
26618
|
return { id: roleId, removed: true, filePath, scope };
|
|
26545
26619
|
}
|
|
26546
26620
|
function modifyRole(roleId, updates, options = {}) {
|
|
@@ -26558,8 +26632,8 @@ function modifyRole(roleId, updates, options = {}) {
|
|
|
26558
26632
|
const scope = options.scope ?? target.scope;
|
|
26559
26633
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26560
26634
|
const dir = ensureRolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
26561
|
-
const filePath =
|
|
26562
|
-
|
|
26635
|
+
const filePath = join17(dir, `${roleId}.yaml`);
|
|
26636
|
+
writeFileSync11(filePath, (0, import_yaml7.stringify)(updated), "utf8");
|
|
26563
26637
|
return { id: roleId, role: updated, filePath, scope };
|
|
26564
26638
|
}
|
|
26565
26639
|
var KXM_ROLE_HOSTS_SCHEMA = "kxm.role-hosts.v1";
|
|
@@ -26607,18 +26681,18 @@ var DEFAULT_ROLE_SEATS = {
|
|
|
26607
26681
|
};
|
|
26608
26682
|
function findExistingRoleHostsFile(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
26609
26683
|
const dir = scope === "global" ? userConfigDirectory(userConfigDir) : repoConfigDirectory(repoRoot);
|
|
26610
|
-
const yamlPath =
|
|
26611
|
-
const ymlPath =
|
|
26612
|
-
const jsonPath =
|
|
26613
|
-
if (
|
|
26614
|
-
if (
|
|
26615
|
-
if (
|
|
26684
|
+
const yamlPath = join17(dir, "role-hosts.yaml");
|
|
26685
|
+
const ymlPath = join17(dir, "role-hosts.yml");
|
|
26686
|
+
const jsonPath = join17(dir, "role-hosts.json");
|
|
26687
|
+
if (existsSync15(yamlPath)) return { filePath: yamlPath, exists: true, format: "yaml" };
|
|
26688
|
+
if (existsSync15(ymlPath)) return { filePath: ymlPath, exists: true, format: "yaml" };
|
|
26689
|
+
if (existsSync15(jsonPath)) return { filePath: jsonPath, exists: true, format: "json" };
|
|
26616
26690
|
return { filePath: yamlPath, exists: false, format: "yaml" };
|
|
26617
26691
|
}
|
|
26618
26692
|
function parseRoleHostsFile(filePath) {
|
|
26619
|
-
if (!
|
|
26693
|
+
if (!existsSync15(filePath)) return void 0;
|
|
26620
26694
|
try {
|
|
26621
|
-
const raw =
|
|
26695
|
+
const raw = readFileSync15(filePath, "utf8");
|
|
26622
26696
|
const parsed = (0, import_yaml7.parse)(raw);
|
|
26623
26697
|
if (!parsed || typeof parsed !== "object") return void 0;
|
|
26624
26698
|
if (parsed.schema && parsed.schema !== KXM_ROLE_HOSTS_SCHEMA) return void 0;
|
|
@@ -26690,18 +26764,18 @@ function saveRoleHostsConfig(config, options = {}) {
|
|
|
26690
26764
|
const scope = options.scope ?? "local";
|
|
26691
26765
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26692
26766
|
const dir = scope === "global" ? userConfigDirectory(options.userConfigDir) : repoConfigDirectory(repoRoot);
|
|
26693
|
-
if (!
|
|
26694
|
-
|
|
26767
|
+
if (!existsSync15(dir)) {
|
|
26768
|
+
mkdirSync12(dir, { recursive: true });
|
|
26695
26769
|
}
|
|
26696
26770
|
const format = options.format ?? "yaml";
|
|
26697
|
-
const filePath =
|
|
26771
|
+
const filePath = join17(dir, format === "json" ? "role-hosts.json" : "role-hosts.yaml");
|
|
26698
26772
|
const payload = {
|
|
26699
26773
|
schema: KXM_ROLE_HOSTS_SCHEMA,
|
|
26700
26774
|
seats: config.seats ?? {},
|
|
26701
26775
|
...config.hostProviders && Object.keys(config.hostProviders).length > 0 ? { hostProviders: config.hostProviders } : {}
|
|
26702
26776
|
};
|
|
26703
26777
|
const content = format === "json" ? JSON.stringify(payload, null, 2) + "\n" : (0, import_yaml7.stringify)(payload);
|
|
26704
|
-
|
|
26778
|
+
writeFileSync11(filePath, content, "utf8");
|
|
26705
26779
|
return { filePath, scope };
|
|
26706
26780
|
}
|
|
26707
26781
|
function setRoleSeatHost(seatId, host, options = {}) {
|
|
@@ -26935,8 +27009,8 @@ async function cmdRoleAdd(runtime, roleId, options) {
|
|
|
26935
27009
|
}
|
|
26936
27010
|
let roleDef;
|
|
26937
27011
|
if (options.file) {
|
|
26938
|
-
const filePath =
|
|
26939
|
-
const content =
|
|
27012
|
+
const filePath = resolve12(runtime.cwd, options.file);
|
|
27013
|
+
const content = readFileSync16(filePath, "utf8");
|
|
26940
27014
|
roleDef = (0, import_yaml8.parse)(content);
|
|
26941
27015
|
roleDef.id = roleId;
|
|
26942
27016
|
} else {
|
|
@@ -27235,8 +27309,8 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
27235
27309
|
return 1;
|
|
27236
27310
|
}
|
|
27237
27311
|
}
|
|
27238
|
-
const dbPath =
|
|
27239
|
-
if (
|
|
27312
|
+
const dbPath = join18(runtime.cwd, ".kxm", "state", "kxm.db");
|
|
27313
|
+
if (existsSync16(dbPath)) {
|
|
27240
27314
|
try {
|
|
27241
27315
|
const database = new DatabaseSync(dbPath);
|
|
27242
27316
|
try {
|
|
@@ -27298,12 +27372,12 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
27298
27372
|
|
|
27299
27373
|
// plugins/kxm/src/cli/workflows.ts
|
|
27300
27374
|
import { createHmac as createHmac3, randomUUID as randomUUID7 } from "node:crypto";
|
|
27301
|
-
import { existsSync as
|
|
27302
|
-
import { join as
|
|
27375
|
+
import { existsSync as existsSync18, readFileSync as readFileSync18 } from "node:fs";
|
|
27376
|
+
import { join as join20, resolve as resolve15 } from "node:path";
|
|
27303
27377
|
|
|
27304
27378
|
// plugins/kxm/src/retrospective.ts
|
|
27305
|
-
import { mkdirSync as
|
|
27306
|
-
import { resolve as
|
|
27379
|
+
import { mkdirSync as mkdirSync13, renameSync as renameSync5, writeFileSync as writeFileSync12 } from "node:fs";
|
|
27380
|
+
import { resolve as resolve13 } from "node:path";
|
|
27307
27381
|
var MAX_RETROSPECTIVE_ENTRIES = 500;
|
|
27308
27382
|
var SAFE_RUN_ID = /^run_[A-Za-z0-9_-]{1,120}$/;
|
|
27309
27383
|
function durationMs(startedAt, completedAt) {
|
|
@@ -27515,19 +27589,19 @@ function renderRetrospectiveMarkdown(doc) {
|
|
|
27515
27589
|
}
|
|
27516
27590
|
function writeRetrospective(outDir, doc) {
|
|
27517
27591
|
if (!SAFE_RUN_ID.test(doc.runId)) throw new Error("invalid retrospective run id");
|
|
27518
|
-
|
|
27519
|
-
const root =
|
|
27520
|
-
const jsonPath =
|
|
27521
|
-
const mdPath =
|
|
27592
|
+
mkdirSync13(outDir, { recursive: true });
|
|
27593
|
+
const root = resolve13(outDir);
|
|
27594
|
+
const jsonPath = resolve13(root, `${doc.runId}.json`);
|
|
27595
|
+
const mdPath = resolve13(root, `${doc.runId}.md`);
|
|
27522
27596
|
const prefix = `${root}${process.platform === "win32" ? "\\" : "/"}`;
|
|
27523
27597
|
if (!jsonPath.startsWith(prefix) || !mdPath.startsWith(prefix)) throw new Error("retrospective path escaped output directory");
|
|
27524
27598
|
const jsonTmp = `${jsonPath}.tmp`;
|
|
27525
27599
|
const mdTmp = `${mdPath}.tmp`;
|
|
27526
|
-
|
|
27600
|
+
writeFileSync12(jsonTmp, `${JSON.stringify(doc, null, 2)}
|
|
27527
27601
|
`, { encoding: "utf8", mode: 384 });
|
|
27528
|
-
|
|
27529
|
-
|
|
27530
|
-
|
|
27602
|
+
writeFileSync12(mdTmp, renderRetrospectiveMarkdown(doc), { encoding: "utf8", mode: 384 });
|
|
27603
|
+
renameSync5(jsonTmp, jsonPath);
|
|
27604
|
+
renameSync5(mdTmp, mdPath);
|
|
27531
27605
|
return { jsonPath, mdPath };
|
|
27532
27606
|
}
|
|
27533
27607
|
|
|
@@ -27618,7 +27692,7 @@ async function watchGithubChecks(input) {
|
|
|
27618
27692
|
}
|
|
27619
27693
|
const fetchImpl = input.fetchImpl ?? fetch;
|
|
27620
27694
|
const now = input.now ?? Date.now;
|
|
27621
|
-
const sleep = input.sleep ?? ((ms) => new Promise((
|
|
27695
|
+
const sleep = input.sleep ?? ((ms) => new Promise((resolve31) => setTimeout(resolve31, ms)));
|
|
27622
27696
|
const deadline = now() + input.timeoutMs;
|
|
27623
27697
|
const headers = {
|
|
27624
27698
|
authorization: `Bearer ${token}`,
|
|
@@ -27717,8 +27791,8 @@ async function watchGithubChecks(input) {
|
|
|
27717
27791
|
|
|
27718
27792
|
// plugins/kxm/src/workflow-manager.ts
|
|
27719
27793
|
var import_yaml9 = __toESM(require_dist(), 1);
|
|
27720
|
-
import { existsSync as
|
|
27721
|
-
import { join as
|
|
27794
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync14, readdirSync as readdirSync5, readFileSync as readFileSync17, rmSync as rmSync6, writeFileSync as writeFileSync13 } from "node:fs";
|
|
27795
|
+
import { join as join19 } from "node:path";
|
|
27722
27796
|
var WORKFLOW_TEMPLATES = {
|
|
27723
27797
|
"implement-and-verify": {
|
|
27724
27798
|
schema: "kxm.workflow.v1",
|
|
@@ -27869,21 +27943,21 @@ var WORKFLOW_TEMPLATES = {
|
|
|
27869
27943
|
var DEFAULT_WORKFLOW_TEMPLATE = WORKFLOW_TEMPLATES["implement-and-verify"];
|
|
27870
27944
|
function workflowsDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
27871
27945
|
if (scope === "global") {
|
|
27872
|
-
return
|
|
27946
|
+
return join19(userConfigDirectory(userConfigDir), "workflows");
|
|
27873
27947
|
}
|
|
27874
|
-
return
|
|
27948
|
+
return join19(repoConfigDirectory(repoRoot), "workflows");
|
|
27875
27949
|
}
|
|
27876
27950
|
function ensureWorkflowsDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
27877
27951
|
const dir = workflowsDirectory(scope, repoRoot, userConfigDir);
|
|
27878
|
-
if (!
|
|
27879
|
-
|
|
27952
|
+
if (!existsSync17(dir)) {
|
|
27953
|
+
mkdirSync14(dir, { recursive: true });
|
|
27880
27954
|
}
|
|
27881
27955
|
return dir;
|
|
27882
27956
|
}
|
|
27883
27957
|
function parseWorkflowFile(filePath) {
|
|
27884
|
-
if (!
|
|
27958
|
+
if (!existsSync17(filePath)) return void 0;
|
|
27885
27959
|
try {
|
|
27886
|
-
const raw =
|
|
27960
|
+
const raw = readFileSync17(filePath, "utf8");
|
|
27887
27961
|
const parsed = (0, import_yaml9.parse)(raw);
|
|
27888
27962
|
if (!parsed || typeof parsed !== "object") return void 0;
|
|
27889
27963
|
return parsed;
|
|
@@ -27897,10 +27971,10 @@ function listWorkflowDefinitions(options = {}) {
|
|
|
27897
27971
|
const globalDir = workflowsDirectory("global", repoRoot, options.userConfigDir);
|
|
27898
27972
|
const localDir = workflowsDirectory("local", repoRoot, options.userConfigDir);
|
|
27899
27973
|
const localDefs = /* @__PURE__ */ new Map();
|
|
27900
|
-
if (scopeFilter !== "global" &&
|
|
27974
|
+
if (scopeFilter !== "global" && existsSync17(localDir)) {
|
|
27901
27975
|
for (const entry of readdirSync5(localDir)) {
|
|
27902
27976
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
27903
|
-
const filePath =
|
|
27977
|
+
const filePath = join19(localDir, entry);
|
|
27904
27978
|
const def = parseWorkflowFile(filePath);
|
|
27905
27979
|
if (def) {
|
|
27906
27980
|
const id = def.id || entry.replace(/\.ya?ml$/i, "");
|
|
@@ -27910,10 +27984,10 @@ function listWorkflowDefinitions(options = {}) {
|
|
|
27910
27984
|
}
|
|
27911
27985
|
}
|
|
27912
27986
|
const globalDefs = /* @__PURE__ */ new Map();
|
|
27913
|
-
if (scopeFilter !== "local" &&
|
|
27987
|
+
if (scopeFilter !== "local" && existsSync17(globalDir)) {
|
|
27914
27988
|
for (const entry of readdirSync5(globalDir)) {
|
|
27915
27989
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
27916
|
-
const filePath =
|
|
27990
|
+
const filePath = join19(globalDir, entry);
|
|
27917
27991
|
const def = parseWorkflowFile(filePath);
|
|
27918
27992
|
if (def) {
|
|
27919
27993
|
const id = def.id || entry.replace(/\.ya?ml$/i, "");
|
|
@@ -27969,13 +28043,13 @@ function getWorkflowDefinition(workflowId, options = {}) {
|
|
|
27969
28043
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
27970
28044
|
if (scope !== "global") {
|
|
27971
28045
|
const localDir = workflowsDirectory("local", repoRoot, options.userConfigDir);
|
|
27972
|
-
const localFile =
|
|
28046
|
+
const localFile = join19(localDir, `${workflowId}.yaml`);
|
|
27973
28047
|
const parsed = parseWorkflowFile(localFile);
|
|
27974
28048
|
if (parsed) return { workflow: parsed, scope: "local", filePath: localFile };
|
|
27975
28049
|
}
|
|
27976
28050
|
if (scope !== "local") {
|
|
27977
28051
|
const globalDir = workflowsDirectory("global", repoRoot, options.userConfigDir);
|
|
27978
|
-
const globalFile =
|
|
28052
|
+
const globalFile = join19(globalDir, `${workflowId}.yaml`);
|
|
27979
28053
|
const parsed = parseWorkflowFile(globalFile);
|
|
27980
28054
|
if (parsed) return { workflow: parsed, scope: "global", filePath: globalFile };
|
|
27981
28055
|
}
|
|
@@ -27985,23 +28059,23 @@ function addWorkflowDefinition(workflowId, content = DEFAULT_WORKFLOW_TEMPLATE,
|
|
|
27985
28059
|
const scope = options.scope ?? "local";
|
|
27986
28060
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
27987
28061
|
const dir = ensureWorkflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
27988
|
-
const filePath =
|
|
27989
|
-
if (
|
|
28062
|
+
const filePath = join19(dir, `${workflowId}.yaml`);
|
|
28063
|
+
if (existsSync17(filePath) && !options.overwrite) {
|
|
27990
28064
|
throw new Error(`workflow_already_exists: workflow '${workflowId}' already exists at ${filePath}`);
|
|
27991
28065
|
}
|
|
27992
28066
|
const payload = typeof content === "string" ? content : (0, import_yaml9.stringify)(content);
|
|
27993
|
-
|
|
28067
|
+
writeFileSync13(filePath, payload, "utf8");
|
|
27994
28068
|
return { id: workflowId, filePath, scope };
|
|
27995
28069
|
}
|
|
27996
28070
|
function removeWorkflowDefinition(workflowId, options = {}) {
|
|
27997
28071
|
const scope = options.scope ?? "local";
|
|
27998
28072
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
27999
28073
|
const dir = workflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
28000
|
-
const filePath =
|
|
28001
|
-
if (!
|
|
28074
|
+
const filePath = join19(dir, `${workflowId}.yaml`);
|
|
28075
|
+
if (!existsSync17(filePath)) {
|
|
28002
28076
|
throw new Error(`workflow_not_found: workflow '${workflowId}' not found in ${scope} directory (${filePath})`);
|
|
28003
28077
|
}
|
|
28004
|
-
|
|
28078
|
+
rmSync6(filePath);
|
|
28005
28079
|
return { id: workflowId, removed: true, filePath, scope };
|
|
28006
28080
|
}
|
|
28007
28081
|
function modifyWorkflowDefinition(workflowId, updates, options = {}) {
|
|
@@ -28016,15 +28090,15 @@ function modifyWorkflowDefinition(workflowId, updates, options = {}) {
|
|
|
28016
28090
|
const scope = options.scope ?? target.scope;
|
|
28017
28091
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
28018
28092
|
const dir = ensureWorkflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
28019
|
-
const filePath =
|
|
28020
|
-
|
|
28093
|
+
const filePath = join19(dir, `${workflowId}.yaml`);
|
|
28094
|
+
writeFileSync13(filePath, (0, import_yaml9.stringify)(updated), "utf8");
|
|
28021
28095
|
return { id: workflowId, workflow: updated, filePath, scope };
|
|
28022
28096
|
}
|
|
28023
28097
|
|
|
28024
28098
|
// plugins/kxm/src/cli/workflows.ts
|
|
28025
28099
|
var CLI_NAME = "kxm";
|
|
28026
28100
|
function localWorkflowSnapshot(dataPath, runId) {
|
|
28027
|
-
if (!
|
|
28101
|
+
if (!existsSync18(dataPath)) throw new Error("state_database_not_found");
|
|
28028
28102
|
const database = new DatabaseSync(dataPath, { readOnly: true });
|
|
28029
28103
|
try {
|
|
28030
28104
|
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();
|
|
@@ -28101,7 +28175,7 @@ function activeWorkflowDefinition(runtime, definitionId) {
|
|
|
28101
28175
|
let raw;
|
|
28102
28176
|
if (file) {
|
|
28103
28177
|
try {
|
|
28104
|
-
raw =
|
|
28178
|
+
raw = readFileSync18(resolve15(runtime.cwd, file), "utf8");
|
|
28105
28179
|
} catch {
|
|
28106
28180
|
throw new Error("workflow definition file is unavailable");
|
|
28107
28181
|
}
|
|
@@ -28182,8 +28256,8 @@ async function cmdWorkflowAdd(runtime, workflowId, options) {
|
|
|
28182
28256
|
}
|
|
28183
28257
|
}
|
|
28184
28258
|
if (options.file) {
|
|
28185
|
-
const filePath =
|
|
28186
|
-
content =
|
|
28259
|
+
const filePath = resolve15(runtime.cwd, options.file);
|
|
28260
|
+
content = readFileSync18(filePath, "utf8");
|
|
28187
28261
|
} else if (!content) {
|
|
28188
28262
|
content = {
|
|
28189
28263
|
schema: "kxm.workflow.v1",
|
|
@@ -28341,7 +28415,7 @@ async function cmdWorkflowStart(runtime, definitionIdArg, options) {
|
|
|
28341
28415
|
}
|
|
28342
28416
|
let payload;
|
|
28343
28417
|
try {
|
|
28344
|
-
const raw = payloadFlag.startsWith("@") ?
|
|
28418
|
+
const raw = payloadFlag.startsWith("@") ? readFileSync18(resolve15(runtime.cwd, payloadFlag.slice(1)), "utf8") : payloadFlag;
|
|
28345
28419
|
const value = JSON.parse(raw);
|
|
28346
28420
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("object required");
|
|
28347
28421
|
payload = value;
|
|
@@ -28408,7 +28482,7 @@ async function cmdWorkflowDegrade(runtime, runId, stageId, options) {
|
|
|
28408
28482
|
}
|
|
28409
28483
|
}
|
|
28410
28484
|
async function cmdWorkflowInspect(runtime, action, runId) {
|
|
28411
|
-
const dataPath =
|
|
28485
|
+
const dataPath = resolve15(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join20(runtime.dirs.state, "kxm.db"));
|
|
28412
28486
|
if (action === "get" && !runId) {
|
|
28413
28487
|
runtime.io.stderr(`Usage: ${CLI_NAME} workflow get <runId>
|
|
28414
28488
|
`);
|
|
@@ -28577,14 +28651,14 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28577
28651
|
return 2;
|
|
28578
28652
|
}
|
|
28579
28653
|
const snapshotFlag = String(options.input || "");
|
|
28580
|
-
const snapshotPath = snapshotFlag ?
|
|
28654
|
+
const snapshotPath = snapshotFlag ? resolve15(runtime.cwd, snapshotFlag) : "";
|
|
28581
28655
|
let snapshot;
|
|
28582
28656
|
try {
|
|
28583
28657
|
if (snapshotPath) {
|
|
28584
|
-
if (!
|
|
28585
|
-
snapshot = JSON.parse(
|
|
28658
|
+
if (!existsSync18(snapshotPath)) throw new Error("snapshot_missing");
|
|
28659
|
+
snapshot = JSON.parse(readFileSync18(snapshotPath, "utf8"));
|
|
28586
28660
|
} else {
|
|
28587
|
-
const dataPath =
|
|
28661
|
+
const dataPath = resolve15(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join20(runtime.dirs.state, "kxm.db"));
|
|
28588
28662
|
const local = localWorkflowSnapshot(dataPath, runId);
|
|
28589
28663
|
if (!local.runs[0]) throw new Error("workflow_not_found");
|
|
28590
28664
|
snapshot = { run: local.runs[0], journal: local.journal };
|
|
@@ -28596,8 +28670,8 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28596
28670
|
return 1;
|
|
28597
28671
|
}
|
|
28598
28672
|
const doc = buildRetrospective(snapshot.run, snapshot.journal);
|
|
28599
|
-
const outDir =
|
|
28600
|
-
const assetsRoot =
|
|
28673
|
+
const outDir = resolve15(runtime.cwd, String(options.outDir || join20(runtime.dirs.assets, "retrospectives")));
|
|
28674
|
+
const assetsRoot = resolve15(runtime.dirs.assets);
|
|
28601
28675
|
const assetsPrefix = `${assetsRoot}${process.platform === "win32" ? "\\" : "/"}`;
|
|
28602
28676
|
if (outDir !== assetsRoot && !outDir.startsWith(assetsPrefix)) {
|
|
28603
28677
|
print(runtime.io, runtime.json, { ok: false, command: "retrospective export", error: "output_outside_workspace_assets" }, "retrospectives must stay under the workspace assets directory");
|
|
@@ -28614,8 +28688,8 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28614
28688
|
|
|
28615
28689
|
// plugins/kxm/src/cli/tasks.ts
|
|
28616
28690
|
var import_yaml13 = __toESM(require_dist(), 1);
|
|
28617
|
-
import { existsSync as
|
|
28618
|
-
import { basename as basename6, join as
|
|
28691
|
+
import { existsSync as existsSync24, readFileSync as readFileSync23, readdirSync as readdirSync8 } from "node:fs";
|
|
28692
|
+
import { basename as basename6, join as join28, resolve as resolve21 } from "node:path";
|
|
28619
28693
|
|
|
28620
28694
|
// plugins/kxm/src/suggest.ts
|
|
28621
28695
|
var WORKFLOW_PATTERNS = [
|
|
@@ -28726,19 +28800,19 @@ function suggestWorkflowAndRoles(prompt, options = {}) {
|
|
|
28726
28800
|
// plugins/kxm/src/task-manager.ts
|
|
28727
28801
|
var import_yaml10 = __toESM(require_dist(), 1);
|
|
28728
28802
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
28729
|
-
import { existsSync as
|
|
28730
|
-
import { join as
|
|
28803
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync15, readFileSync as readFileSync19, readdirSync as readdirSync6, writeFileSync as writeFileSync14 } from "node:fs";
|
|
28804
|
+
import { join as join21, resolve as resolve16 } from "node:path";
|
|
28731
28805
|
var GOAL_SCHEMA = "kxm.goal.v1";
|
|
28732
28806
|
var TASK_SCHEMA = "kxm.task.v1";
|
|
28733
28807
|
function goalsDirectory(repoRoot) {
|
|
28734
|
-
return
|
|
28808
|
+
return resolve16(repoRoot, ".kxm", "goals");
|
|
28735
28809
|
}
|
|
28736
28810
|
function tasksDirectory(repoRoot) {
|
|
28737
|
-
return
|
|
28811
|
+
return resolve16(repoRoot, ".kxm", "tasks");
|
|
28738
28812
|
}
|
|
28739
28813
|
function createGoal(repoRoot, input) {
|
|
28740
28814
|
const dir = goalsDirectory(repoRoot);
|
|
28741
|
-
|
|
28815
|
+
mkdirSync15(dir, { recursive: true });
|
|
28742
28816
|
const id = `goal_${randomUUID8().replaceAll("-", "").slice(0, 12)}`;
|
|
28743
28817
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
28744
28818
|
const record = {
|
|
@@ -28752,19 +28826,19 @@ function createGoal(repoRoot, input) {
|
|
|
28752
28826
|
createdAt: now,
|
|
28753
28827
|
updatedAt: now
|
|
28754
28828
|
};
|
|
28755
|
-
const filePath =
|
|
28756
|
-
|
|
28829
|
+
const filePath = join21(dir, `${id}.yaml`);
|
|
28830
|
+
writeFileSync14(filePath, (0, import_yaml10.stringify)(record).trim() + "\n", "utf8");
|
|
28757
28831
|
return record;
|
|
28758
28832
|
}
|
|
28759
28833
|
function listGoals(repoRoot) {
|
|
28760
28834
|
const dir = goalsDirectory(repoRoot);
|
|
28761
|
-
if (!
|
|
28835
|
+
if (!existsSync19(dir)) return [];
|
|
28762
28836
|
const goals = [];
|
|
28763
28837
|
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
28764
28838
|
for (const entry of entries) {
|
|
28765
28839
|
if (entry.isFile() && (entry.name.endsWith(".yaml") || entry.name.endsWith(".yml"))) {
|
|
28766
28840
|
try {
|
|
28767
|
-
const text =
|
|
28841
|
+
const text = readFileSync19(join21(dir, entry.name), "utf8");
|
|
28768
28842
|
const doc = (0, import_yaml10.parse)(text);
|
|
28769
28843
|
if (doc && doc.schema === GOAL_SCHEMA) goals.push(doc);
|
|
28770
28844
|
} catch {
|
|
@@ -28775,7 +28849,7 @@ function listGoals(repoRoot) {
|
|
|
28775
28849
|
}
|
|
28776
28850
|
function createTask(repoRoot, input) {
|
|
28777
28851
|
const dir = tasksDirectory(repoRoot);
|
|
28778
|
-
|
|
28852
|
+
mkdirSync15(dir, { recursive: true });
|
|
28779
28853
|
const id = `task_${randomUUID8().replaceAll("-", "").slice(0, 12)}`;
|
|
28780
28854
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
28781
28855
|
const record = {
|
|
@@ -28797,19 +28871,19 @@ function createTask(repoRoot, input) {
|
|
|
28797
28871
|
createdAt: now,
|
|
28798
28872
|
updatedAt: now
|
|
28799
28873
|
};
|
|
28800
|
-
const filePath =
|
|
28801
|
-
|
|
28874
|
+
const filePath = join21(dir, `${id}.yaml`);
|
|
28875
|
+
writeFileSync14(filePath, (0, import_yaml10.stringify)(record).trim() + "\n", "utf8");
|
|
28802
28876
|
return record;
|
|
28803
28877
|
}
|
|
28804
28878
|
function listTasks(repoRoot, options = {}) {
|
|
28805
28879
|
const dir = tasksDirectory(repoRoot);
|
|
28806
|
-
if (!
|
|
28880
|
+
if (!existsSync19(dir)) return [];
|
|
28807
28881
|
const tasks = [];
|
|
28808
28882
|
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
28809
28883
|
for (const entry of entries) {
|
|
28810
28884
|
if (entry.isFile() && (entry.name.endsWith(".yaml") || entry.name.endsWith(".yml"))) {
|
|
28811
28885
|
try {
|
|
28812
|
-
const text =
|
|
28886
|
+
const text = readFileSync19(join21(dir, entry.name), "utf8");
|
|
28813
28887
|
const doc = (0, import_yaml10.parse)(text);
|
|
28814
28888
|
if (doc && doc.schema === TASK_SCHEMA) {
|
|
28815
28889
|
if (options.goalId && doc.goalId !== options.goalId) continue;
|
|
@@ -28824,10 +28898,10 @@ function listTasks(repoRoot, options = {}) {
|
|
|
28824
28898
|
}
|
|
28825
28899
|
function getTask(repoRoot, taskId) {
|
|
28826
28900
|
const dir = tasksDirectory(repoRoot);
|
|
28827
|
-
const filePath =
|
|
28828
|
-
if (!
|
|
28901
|
+
const filePath = join21(dir, `${taskId}.yaml`);
|
|
28902
|
+
if (!existsSync19(filePath)) return void 0;
|
|
28829
28903
|
try {
|
|
28830
|
-
const text =
|
|
28904
|
+
const text = readFileSync19(filePath, "utf8");
|
|
28831
28905
|
const doc = (0, import_yaml10.parse)(text);
|
|
28832
28906
|
return doc && doc.schema === TASK_SCHEMA ? doc : void 0;
|
|
28833
28907
|
} catch {
|
|
@@ -28842,8 +28916,8 @@ function updateTaskStatus(repoRoot, taskId, status, options = {}) {
|
|
|
28842
28916
|
task.status = status;
|
|
28843
28917
|
if (options.workflowRunId) task.workflowRunId = options.workflowRunId;
|
|
28844
28918
|
task.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
28845
|
-
const filePath =
|
|
28846
|
-
|
|
28919
|
+
const filePath = join21(tasksDirectory(repoRoot), `${taskId}.yaml`);
|
|
28920
|
+
writeFileSync14(filePath, (0, import_yaml10.stringify)(task).trim() + "\n", "utf8");
|
|
28847
28921
|
return task;
|
|
28848
28922
|
}
|
|
28849
28923
|
function syncTaskWithTracker(repoRoot, taskId, options = {}) {
|
|
@@ -28858,8 +28932,8 @@ function syncTaskWithTracker(repoRoot, taskId, options = {}) {
|
|
|
28858
28932
|
task.trackerSync.syncStatus = "synced";
|
|
28859
28933
|
task.trackerSync.lastSyncedAt = now;
|
|
28860
28934
|
task.updatedAt = now;
|
|
28861
|
-
const filePath =
|
|
28862
|
-
|
|
28935
|
+
const filePath = join21(tasksDirectory(repoRoot), `${taskId}.yaml`);
|
|
28936
|
+
writeFileSync14(filePath, (0, import_yaml10.stringify)(task).trim() + "\n", "utf8");
|
|
28863
28937
|
return task;
|
|
28864
28938
|
}
|
|
28865
28939
|
|
|
@@ -29625,13 +29699,13 @@ function createStudioServer(options = {}) {
|
|
|
29625
29699
|
}
|
|
29626
29700
|
|
|
29627
29701
|
// plugins/kxm/src/cli/vnext.ts
|
|
29628
|
-
import { join as
|
|
29702
|
+
import { join as join27, resolve as resolve20 } from "node:path";
|
|
29629
29703
|
import { createInterface as createInterface2 } from "node:readline";
|
|
29630
29704
|
|
|
29631
29705
|
// plugins/kxm/src/model-inventory.ts
|
|
29632
29706
|
var import_yaml11 = __toESM(require_dist(), 1);
|
|
29633
|
-
import { mkdirSync as
|
|
29634
|
-
import { join as
|
|
29707
|
+
import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync15 } from "node:fs";
|
|
29708
|
+
import { join as join22 } from "node:path";
|
|
29635
29709
|
var OR_URL = "https://openrouter.ai/api/v1/models";
|
|
29636
29710
|
var NOUS_URL = "https://inference-api.nousresearch.com/v1/models";
|
|
29637
29711
|
function price(value) {
|
|
@@ -29717,41 +29791,41 @@ async function refreshModelInventory(options) {
|
|
|
29717
29791
|
sources.nous = { url: nousUrl, ok: !nous.error, ...nous.error ? { error: nous.error } : {} };
|
|
29718
29792
|
for (const item of nous.data) add(item, "nous", "discount");
|
|
29719
29793
|
const inventory = { schema: "kxm.model-inventory.v1", fetchedAt, currency: "USD", sources, models: [...byId.values()].sort((a, b2) => a.id.localeCompare(b2.id)) };
|
|
29720
|
-
|
|
29721
|
-
|
|
29794
|
+
mkdirSync16(join22(options.outputRoot, ".kxm", "models"), { recursive: true });
|
|
29795
|
+
writeFileSync15(join22(options.outputRoot, ".kxm", "models", "inventory.yaml"), (0, import_yaml11.stringify)(inventory), "utf8");
|
|
29722
29796
|
return inventory;
|
|
29723
29797
|
}
|
|
29724
29798
|
|
|
29725
29799
|
// plugins/kxm/src/vnext-init.ts
|
|
29726
29800
|
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
29727
|
-
import { existsSync as
|
|
29728
|
-
import { basename as basename5, join as
|
|
29801
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
29802
|
+
import { basename as basename5, join as join25 } from "node:path";
|
|
29729
29803
|
|
|
29730
29804
|
// plugins/kxm/src/vnext-repair.ts
|
|
29731
29805
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
29732
29806
|
import {
|
|
29733
29807
|
chmodSync as chmodSync5,
|
|
29734
29808
|
closeSync as closeSync2,
|
|
29735
|
-
existsSync as
|
|
29809
|
+
existsSync as existsSync21,
|
|
29736
29810
|
fsyncSync as fsyncSync2,
|
|
29737
29811
|
linkSync,
|
|
29738
29812
|
lstatSync as lstatSync7,
|
|
29739
|
-
mkdirSync as
|
|
29813
|
+
mkdirSync as mkdirSync18,
|
|
29740
29814
|
openSync as openSync2,
|
|
29741
|
-
readFileSync as
|
|
29815
|
+
readFileSync as readFileSync21,
|
|
29742
29816
|
readdirSync as readdirSync7,
|
|
29743
|
-
renameSync as
|
|
29744
|
-
rmSync as
|
|
29745
|
-
writeFileSync as
|
|
29817
|
+
renameSync as renameSync6,
|
|
29818
|
+
rmSync as rmSync8,
|
|
29819
|
+
writeFileSync as writeFileSync17
|
|
29746
29820
|
} from "node:fs";
|
|
29747
|
-
import { dirname as
|
|
29821
|
+
import { dirname as dirname15, isAbsolute as isAbsolute7, join as join24, relative as relative4, resolve as resolve18 } from "node:path";
|
|
29748
29822
|
|
|
29749
29823
|
// plugins/kxm/src/vnext-permission.ts
|
|
29750
29824
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
29751
29825
|
import { createHash as createHash12 } from "node:crypto";
|
|
29752
|
-
import { existsSync as
|
|
29826
|
+
import { existsSync as existsSync20, mkdtempSync, mkdirSync as mkdirSync17, readFileSync as readFileSync20, rmSync as rmSync7, writeFileSync as writeFileSync16 } from "node:fs";
|
|
29753
29827
|
import { tmpdir } from "node:os";
|
|
29754
|
-
import { dirname as
|
|
29828
|
+
import { dirname as dirname14, join as join23, resolve as resolve17, sep as sep3 } from "node:path";
|
|
29755
29829
|
var PROSE_FIELDS = {
|
|
29756
29830
|
project: /* @__PURE__ */ new Set(["name", "description"]),
|
|
29757
29831
|
repository: /* @__PURE__ */ new Set(["description"]),
|
|
@@ -30272,8 +30346,8 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30272
30346
|
const tree = resolveTreeRevision(root, revision);
|
|
30273
30347
|
const listing = gitBuffer(root, ["ls-tree", "-r", "-z", "--name-only", tree]).toString("utf8");
|
|
30274
30348
|
const paths = listing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
30275
|
-
const shadow = mkdtempSync(
|
|
30276
|
-
const shadowResolved =
|
|
30349
|
+
const shadow = mkdtempSync(join23(tmpdir(), "kxm-permission-base-"));
|
|
30350
|
+
const shadowResolved = resolve17(shadow);
|
|
30277
30351
|
const shadowMembersDir = `.kxm-shadow-members-${createHash12("sha256").update(shadowResolved, "utf8").digest("hex").slice(0, 8)}`;
|
|
30278
30352
|
try {
|
|
30279
30353
|
for (const path4 of paths) {
|
|
@@ -30286,8 +30360,8 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30286
30360
|
message: "Git tree entry contains a traversal or non-portable segment"
|
|
30287
30361
|
}]);
|
|
30288
30362
|
}
|
|
30289
|
-
const absolute =
|
|
30290
|
-
const resolved =
|
|
30363
|
+
const absolute = join23(shadowResolved, ...segments);
|
|
30364
|
+
const resolved = resolve17(absolute);
|
|
30291
30365
|
if (!resolved.startsWith(`${shadowResolved}${sep3}`)) {
|
|
30292
30366
|
throw new VnextConfigError([{
|
|
30293
30367
|
phase: "path",
|
|
@@ -30297,11 +30371,11 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30297
30371
|
}]);
|
|
30298
30372
|
}
|
|
30299
30373
|
const content = gitBuffer(root, ["cat-file", "blob", `${tree}:${path4}`]);
|
|
30300
|
-
|
|
30301
|
-
|
|
30374
|
+
mkdirSync17(dirname14(absolute), { recursive: true });
|
|
30375
|
+
writeFileSync16(absolute, content);
|
|
30302
30376
|
}
|
|
30303
30377
|
initShadowGitRoot(shadowResolved);
|
|
30304
|
-
const baseProjectFile =
|
|
30378
|
+
const baseProjectFile = join23(shadowResolved, ".kxm", "project.yaml");
|
|
30305
30379
|
let baseProject;
|
|
30306
30380
|
try {
|
|
30307
30381
|
baseProject = loadBaseProjectDeclarations(baseProjectFile);
|
|
@@ -30331,8 +30405,8 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30331
30405
|
}]);
|
|
30332
30406
|
}
|
|
30333
30407
|
const boundPath = options.repositoryBindings?.[member.repositoryId];
|
|
30334
|
-
const memberWorktree = boundPath ?
|
|
30335
|
-
if (!memberWorktree || !
|
|
30408
|
+
const memberWorktree = boundPath ? resolve17(boundPath) : member.pathHint ? resolve17(root, ...member.pathHint.split("/")) : void 0;
|
|
30409
|
+
if (!memberWorktree || !existsSync20(memberWorktree)) {
|
|
30336
30410
|
if (member.required === false) continue;
|
|
30337
30411
|
throw new VnextConfigError([{
|
|
30338
30412
|
phase: "discovery",
|
|
@@ -30379,8 +30453,8 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30379
30453
|
const memberTree = git(memberWorktree, ["rev-parse", "--verify", "--quiet", `${pinnedCommit}^{tree}`]).trim();
|
|
30380
30454
|
const memberListing = gitBuffer(memberWorktree, ["ls-tree", "-r", "-z", "--name-only", memberTree]).toString("utf8");
|
|
30381
30455
|
const memberPaths = memberListing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
30382
|
-
const memberShadowRoot =
|
|
30383
|
-
if (!
|
|
30456
|
+
const memberShadowRoot = join23(shadowResolved, shadowMembersDir, member.repositoryId);
|
|
30457
|
+
if (!resolve17(memberShadowRoot).startsWith(`${resolve17(shadowResolved, shadowMembersDir)}${sep3}`)) {
|
|
30384
30458
|
throw new VnextConfigError([{
|
|
30385
30459
|
phase: "path",
|
|
30386
30460
|
code: "git_tree_path_invalid",
|
|
@@ -30393,14 +30467,14 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30393
30467
|
if (segments.some((segment) => segment === "" || segment === "." || segment === ".." || /[\\:]/.test(segment))) {
|
|
30394
30468
|
throw new VnextConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path4, message: "member Git tree entry contains a traversal or non-portable segment" }]);
|
|
30395
30469
|
}
|
|
30396
|
-
const absolute =
|
|
30397
|
-
const resolved =
|
|
30398
|
-
if (!resolved.startsWith(`${
|
|
30470
|
+
const absolute = join23(memberShadowRoot, ...segments);
|
|
30471
|
+
const resolved = resolve17(absolute);
|
|
30472
|
+
if (!resolved.startsWith(`${resolve17(memberShadowRoot)}${sep3}`)) {
|
|
30399
30473
|
throw new VnextConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path4, message: "member Git tree entry escapes the shadow root" }]);
|
|
30400
30474
|
}
|
|
30401
30475
|
const content = gitBuffer(memberWorktree, ["cat-file", "blob", `${memberTree}:${path4}`]);
|
|
30402
|
-
|
|
30403
|
-
|
|
30476
|
+
mkdirSync17(dirname14(absolute), { recursive: true });
|
|
30477
|
+
writeFileSync16(absolute, content);
|
|
30404
30478
|
}
|
|
30405
30479
|
initShadowGitRoot(memberShadowRoot);
|
|
30406
30480
|
shadowBindings[member.repositoryId] = memberShadowRoot;
|
|
@@ -30414,15 +30488,15 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30414
30488
|
throw error;
|
|
30415
30489
|
}
|
|
30416
30490
|
} finally {
|
|
30417
|
-
|
|
30491
|
+
rmSync7(shadow, { recursive: true, force: true });
|
|
30418
30492
|
}
|
|
30419
30493
|
}
|
|
30420
30494
|
function portableMemberPathHint(pathHint) {
|
|
30421
30495
|
return pathHint !== "." && vnextPortablePath(pathHint);
|
|
30422
30496
|
}
|
|
30423
30497
|
function loadBaseProjectDeclarations(projectFile) {
|
|
30424
|
-
if (!
|
|
30425
|
-
const value = parseRestrictedYaml2(
|
|
30498
|
+
if (!existsSync20(projectFile)) return [];
|
|
30499
|
+
const value = parseRestrictedYaml2(readFileSync20(projectFile, "utf8"), ".kxm/project.yaml");
|
|
30426
30500
|
const repositories = Array.isArray(value?.repositories) ? value.repositories : [];
|
|
30427
30501
|
const members = [];
|
|
30428
30502
|
for (const entry of repositories) {
|
|
@@ -30514,7 +30588,7 @@ function writeDurableNew(file, bytes, mode) {
|
|
|
30514
30588
|
let descriptor;
|
|
30515
30589
|
try {
|
|
30516
30590
|
descriptor = openSync2(file, "wx", mode);
|
|
30517
|
-
|
|
30591
|
+
writeFileSync17(descriptor, bytes);
|
|
30518
30592
|
fsyncSync2(descriptor);
|
|
30519
30593
|
closeSync2(descriptor);
|
|
30520
30594
|
descriptor = void 0;
|
|
@@ -30525,13 +30599,13 @@ function writeDurableNew(file, bytes, mode) {
|
|
|
30525
30599
|
} finally {
|
|
30526
30600
|
if (descriptor !== void 0) closeSync2(descriptor);
|
|
30527
30601
|
}
|
|
30528
|
-
syncDirectory2(
|
|
30602
|
+
syncDirectory2(dirname15(file));
|
|
30529
30603
|
}
|
|
30530
30604
|
function writeDurable(file, bytes, mode) {
|
|
30531
30605
|
let descriptor;
|
|
30532
30606
|
try {
|
|
30533
30607
|
descriptor = openSync2(file, "w", mode);
|
|
30534
|
-
|
|
30608
|
+
writeFileSync17(descriptor, bytes);
|
|
30535
30609
|
fsyncSync2(descriptor);
|
|
30536
30610
|
closeSync2(descriptor);
|
|
30537
30611
|
descriptor = void 0;
|
|
@@ -30542,53 +30616,53 @@ function writeDurable(file, bytes, mode) {
|
|
|
30542
30616
|
} finally {
|
|
30543
30617
|
if (descriptor !== void 0) closeSync2(descriptor);
|
|
30544
30618
|
}
|
|
30545
|
-
syncDirectory2(
|
|
30619
|
+
syncDirectory2(dirname15(file));
|
|
30546
30620
|
}
|
|
30547
30621
|
function sameHostPath3(left, right) {
|
|
30548
|
-
const first =
|
|
30549
|
-
const second =
|
|
30622
|
+
const first = resolve18(left);
|
|
30623
|
+
const second = resolve18(right);
|
|
30550
30624
|
return process.platform === "win32" ? first.toLocaleLowerCase("en-US") === second.toLocaleLowerCase("en-US") : first === second;
|
|
30551
30625
|
}
|
|
30552
30626
|
function transactionRoot(projectRoot) {
|
|
30553
|
-
return
|
|
30627
|
+
return join24(resolve18(projectRoot), TRANSACTION_NAME);
|
|
30554
30628
|
}
|
|
30555
30629
|
function operationFile(projectRoot) {
|
|
30556
|
-
return
|
|
30630
|
+
return join24(transactionRoot(projectRoot), OPERATION_FILE);
|
|
30557
30631
|
}
|
|
30558
30632
|
function targetFile(projectRoot, portablePath2) {
|
|
30559
|
-
return
|
|
30633
|
+
return join24(transactionRoot(projectRoot), "targets", ...portablePath2.split("/"));
|
|
30560
30634
|
}
|
|
30561
30635
|
function shadowRoot(projectRoot) {
|
|
30562
|
-
return
|
|
30636
|
+
return join24(transactionRoot(projectRoot), "shadow");
|
|
30563
30637
|
}
|
|
30564
30638
|
function backupFile(projectRoot, portablePath2) {
|
|
30565
|
-
return
|
|
30639
|
+
return join24(transactionRoot(projectRoot), "backups", ...portablePath2.split("/"));
|
|
30566
30640
|
}
|
|
30567
30641
|
function portableManagedPath(path4) {
|
|
30568
|
-
return path4.startsWith(".kxm/") && path4 !== VNEXT_TEMPLATE_PROVENANCE_PATH && path4.length <= 1024 && !path4.includes("\\") && !
|
|
30642
|
+
return path4.startsWith(".kxm/") && path4 !== VNEXT_TEMPLATE_PROVENANCE_PATH && path4.length <= 1024 && !path4.includes("\\") && !isAbsolute7(path4) && PORTABLE_PATH.test(path4) && !/[<>:"|?*]/.test(path4);
|
|
30569
30643
|
}
|
|
30570
30644
|
function readRegularBounded(file, label) {
|
|
30571
30645
|
const stat = lstatSync7(file);
|
|
30572
30646
|
if (stat.isSymbolicLink() || !stat.isFile()) fail3("repair_file_invalid", label, "managed file must be a regular file, not a link or directory", "path");
|
|
30573
30647
|
if (stat.size > MAX_MANAGED_FILE_BYTES) fail3("repair_file_too_large", label, `managed file exceeds ${MAX_MANAGED_FILE_BYTES} bytes`, "parse");
|
|
30574
|
-
return
|
|
30648
|
+
return readFileSync21(file);
|
|
30575
30649
|
}
|
|
30576
30650
|
function readOptionalManaged(projectRoot, path4) {
|
|
30577
|
-
const file =
|
|
30578
|
-
if (!
|
|
30579
|
-
let parent =
|
|
30580
|
-
const boundary =
|
|
30651
|
+
const file = join24(projectRoot, ...path4.split("/"));
|
|
30652
|
+
if (!existsSync21(file)) return void 0;
|
|
30653
|
+
let parent = dirname15(file);
|
|
30654
|
+
const boundary = resolve18(projectRoot);
|
|
30581
30655
|
while (parent !== boundary) {
|
|
30582
30656
|
const stat = lstatSync7(parent);
|
|
30583
30657
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_parent_invalid", path4, "managed file parents must be regular directories", "path");
|
|
30584
|
-
parent =
|
|
30658
|
+
parent = dirname15(parent);
|
|
30585
30659
|
}
|
|
30586
30660
|
return readRegularBounded(file, path4);
|
|
30587
30661
|
}
|
|
30588
30662
|
function readProjectAndProvenance(projectRoot, schemasDir) {
|
|
30589
|
-
const projectFile =
|
|
30590
|
-
const provenanceFile =
|
|
30591
|
-
if (!
|
|
30663
|
+
const projectFile = join24(projectRoot, ".kxm", "project.yaml");
|
|
30664
|
+
const provenanceFile = join24(projectRoot, ...VNEXT_TEMPLATE_PROVENANCE_PATH.split("/"));
|
|
30665
|
+
if (!existsSync21(projectFile) || !existsSync21(provenanceFile)) return void 0;
|
|
30592
30666
|
const projectBytes = readOptionalManaged(projectRoot, ".kxm/project.yaml");
|
|
30593
30667
|
const provenanceBytes = readOptionalManaged(projectRoot, VNEXT_TEMPLATE_PROVENANCE_PATH);
|
|
30594
30668
|
if (!projectBytes || !provenanceBytes) return void 0;
|
|
@@ -30624,7 +30698,7 @@ function readProjectAndProvenance(projectRoot, schemasDir) {
|
|
|
30624
30698
|
}
|
|
30625
30699
|
function planVnextTemplateRepair(projectRoot, options = {}) {
|
|
30626
30700
|
assertNoRegisteredGates(options);
|
|
30627
|
-
const root =
|
|
30701
|
+
const root = resolve18(projectRoot);
|
|
30628
30702
|
const source = readProjectAndProvenance(root, options.schemasDir);
|
|
30629
30703
|
if (!source) return void 0;
|
|
30630
30704
|
const target = renderVnextTemplate(
|
|
@@ -30752,14 +30826,14 @@ function operationPlanSha(operation) {
|
|
|
30752
30826
|
function writeOperation(projectRoot, operation) {
|
|
30753
30827
|
const root = transactionRoot(projectRoot);
|
|
30754
30828
|
const file = operationFile(projectRoot);
|
|
30755
|
-
const temporary =
|
|
30829
|
+
const temporary = join24(root, `.operation-${operation.operationId}-${randomUUID10()}.tmp`);
|
|
30756
30830
|
try {
|
|
30757
30831
|
writeDurableNew(temporary, Buffer.from(`${JSON.stringify(operation, null, 2)}
|
|
30758
30832
|
`, "utf8"), 384);
|
|
30759
|
-
|
|
30833
|
+
renameSync6(temporary, file);
|
|
30760
30834
|
syncDirectory2(root);
|
|
30761
30835
|
} finally {
|
|
30762
|
-
|
|
30836
|
+
rmSync8(temporary, { force: true });
|
|
30763
30837
|
}
|
|
30764
30838
|
}
|
|
30765
30839
|
function updatePhase(projectRoot, operation, phase) {
|
|
@@ -30769,11 +30843,11 @@ function updatePhase(projectRoot, operation, phase) {
|
|
|
30769
30843
|
}
|
|
30770
30844
|
function readOperation(projectRoot, schemasDir) {
|
|
30771
30845
|
const root = transactionRoot(projectRoot);
|
|
30772
|
-
if (!
|
|
30846
|
+
if (!existsSync21(root)) return void 0;
|
|
30773
30847
|
const stat = lstatSync7(root);
|
|
30774
30848
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("init_transaction_invalid", TRANSACTION_NAME, "initialization transaction must be a regular directory", "path");
|
|
30775
30849
|
const file = operationFile(projectRoot);
|
|
30776
|
-
if (!
|
|
30850
|
+
if (!existsSync21(file)) {
|
|
30777
30851
|
const entries = readdirSync7(root, { withFileTypes: true });
|
|
30778
30852
|
const recoverable = entries.every((entry) => entry.isFile() && /^\.operation-op_[a-f0-9]{32}-[a-f0-9-]{36}\.tmp$/.test(entry.name));
|
|
30779
30853
|
if (recoverable) return void 0;
|
|
@@ -30796,20 +30870,20 @@ function readOperation(projectRoot, schemasDir) {
|
|
|
30796
30870
|
seen.add(folded);
|
|
30797
30871
|
prior = entry.path;
|
|
30798
30872
|
}
|
|
30799
|
-
if (!
|
|
30873
|
+
if (!isAbsolute7(operation.projectRoot)) fail3("init_transaction_project_root_invalid", TRANSACTION_NAME, "operation project root must be absolute", "path");
|
|
30800
30874
|
validateOperationIntent(projectRoot, operation);
|
|
30801
30875
|
return operation;
|
|
30802
30876
|
}
|
|
30803
30877
|
function hasVnextInitTransaction(projectRoot) {
|
|
30804
|
-
return
|
|
30878
|
+
return existsSync21(transactionRoot(projectRoot));
|
|
30805
30879
|
}
|
|
30806
30880
|
function readTarget(projectRoot, path4) {
|
|
30807
|
-
return readOptionalManaged(
|
|
30881
|
+
return readOptionalManaged(join24(transactionRoot(projectRoot), "targets"), path4);
|
|
30808
30882
|
}
|
|
30809
30883
|
function writeTarget(projectRoot, path4, bytes) {
|
|
30810
30884
|
if (bytes.byteLength > MAX_MANAGED_FILE_BYTES) fail3("template_target_too_large", path4, `target exceeds ${MAX_MANAGED_FILE_BYTES} bytes`);
|
|
30811
30885
|
const file = targetFile(projectRoot, path4);
|
|
30812
|
-
|
|
30886
|
+
mkdirSync18(dirname15(file), { recursive: true, mode: 448 });
|
|
30813
30887
|
writeDurableNew(file, bytes, 384);
|
|
30814
30888
|
}
|
|
30815
30889
|
function writeAndVerifyBackups(projectRoot, operation) {
|
|
@@ -30821,7 +30895,7 @@ function writeAndVerifyBackups(projectRoot, operation) {
|
|
|
30821
30895
|
fail3("repair_preimage_changed", entry.path, "destination changed before transaction preparation; local bytes were preserved");
|
|
30822
30896
|
}
|
|
30823
30897
|
const file = backupFile(projectRoot, entry.path);
|
|
30824
|
-
|
|
30898
|
+
mkdirSync18(dirname15(file), { recursive: true, mode: 448 });
|
|
30825
30899
|
writeDurableNew(file, current, 384);
|
|
30826
30900
|
}
|
|
30827
30901
|
}
|
|
@@ -30836,7 +30910,7 @@ function writeKnownBackups(projectRoot, operation) {
|
|
|
30836
30910
|
fail3("init_transaction_backup_source_invalid", entry.path, "supported source template cannot reproduce the pinned preimage");
|
|
30837
30911
|
}
|
|
30838
30912
|
const file = backupFile(projectRoot, entry.path);
|
|
30839
|
-
|
|
30913
|
+
mkdirSync18(dirname15(file), { recursive: true, mode: 448 });
|
|
30840
30914
|
writeDurableNew(file, bytes, 384);
|
|
30841
30915
|
}
|
|
30842
30916
|
}
|
|
@@ -30844,7 +30918,7 @@ function verifyBackups(projectRoot, operation) {
|
|
|
30844
30918
|
if (operation.kind !== "repair") return;
|
|
30845
30919
|
for (const entry of operation.files) {
|
|
30846
30920
|
if (entry.observedSha256 === null) continue;
|
|
30847
|
-
const bytes = readOptionalManaged(
|
|
30921
|
+
const bytes = readOptionalManaged(join24(transactionRoot(projectRoot), "backups"), entry.path);
|
|
30848
30922
|
if (!bytes || vnextContentSha256(bytes) !== entry.observedSha256) {
|
|
30849
30923
|
fail3("init_transaction_backup_invalid", entry.path, "pinned preimage backup is missing or corrupt");
|
|
30850
30924
|
}
|
|
@@ -30878,10 +30952,10 @@ function sourceConfigFiles(projectRoot) {
|
|
|
30878
30952
|
".kxm/repo/repo.yaml",
|
|
30879
30953
|
".kxm/repo/env.yaml"
|
|
30880
30954
|
];
|
|
30881
|
-
const files = fixed.filter((path4) =>
|
|
30955
|
+
const files = fixed.filter((path4) => existsSync21(join24(projectRoot, ...path4.split("/"))));
|
|
30882
30956
|
for (const directory of ["agents", "models", "workflows"]) {
|
|
30883
|
-
const absolute =
|
|
30884
|
-
if (!
|
|
30957
|
+
const absolute = join24(projectRoot, ".kxm", directory);
|
|
30958
|
+
if (!existsSync21(absolute)) continue;
|
|
30885
30959
|
const stat = lstatSync7(absolute);
|
|
30886
30960
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_directory_invalid", `.kxm/${directory}`, "configuration directory must be regular", "path");
|
|
30887
30961
|
for (const entry of readdirSync7(absolute, { withFileTypes: true })) {
|
|
@@ -30902,24 +30976,24 @@ function absoluteMemberBindings(projectRoot, project, explicit = {}) {
|
|
|
30902
30976
|
const repository = candidate;
|
|
30903
30977
|
if (repository.role !== "member" || typeof repository.id !== "string" || Object.hasOwn(bindings, repository.id)) continue;
|
|
30904
30978
|
if (typeof repository.pathHint === "string") {
|
|
30905
|
-
const candidate2 =
|
|
30906
|
-
if (
|
|
30979
|
+
const candidate2 = resolve18(projectRoot, ...repository.pathHint.split("/"));
|
|
30980
|
+
if (existsSync21(candidate2)) bindings[repository.id] = candidate2;
|
|
30907
30981
|
}
|
|
30908
30982
|
}
|
|
30909
30983
|
return bindings;
|
|
30910
30984
|
}
|
|
30911
30985
|
function prepareShadow(projectRoot, operation, options) {
|
|
30912
30986
|
const shadow = shadowRoot(projectRoot);
|
|
30913
|
-
|
|
30987
|
+
mkdirSync18(shadow, { recursive: true, mode: 448 });
|
|
30914
30988
|
let total = 0;
|
|
30915
30989
|
if (operation.kind === "repair") {
|
|
30916
30990
|
for (const path4 of sourceConfigFiles(projectRoot)) {
|
|
30917
30991
|
const bytes = readOptionalManaged(projectRoot, path4);
|
|
30918
30992
|
if (!bytes) fail3("repair_snapshot_file_missing", path4, "configuration changed during shadow preparation");
|
|
30919
30993
|
total += bytes.byteLength;
|
|
30920
|
-
const source =
|
|
30921
|
-
const destination =
|
|
30922
|
-
|
|
30994
|
+
const source = join24(projectRoot, ...path4.split("/"));
|
|
30995
|
+
const destination = join24(shadow, ...path4.split("/"));
|
|
30996
|
+
mkdirSync18(dirname15(destination), { recursive: true, mode: 448 });
|
|
30923
30997
|
writeDurableNew(destination, bytes, lstatSync7(source).mode & 511);
|
|
30924
30998
|
if (total > MAX_MANAGED_TOTAL_BYTES) fail3("repair_snapshot_too_large", ".kxm", `configuration snapshot exceeds ${MAX_MANAGED_TOTAL_BYTES} bytes`, "parse");
|
|
30925
30999
|
}
|
|
@@ -30927,12 +31001,12 @@ function prepareShadow(projectRoot, operation, options) {
|
|
|
30927
31001
|
for (const entry of operation.files) {
|
|
30928
31002
|
const bytes = readTarget(projectRoot, entry.path);
|
|
30929
31003
|
if (!bytes) fail3("init_transaction_target_missing", entry.path, "pinned target artifact is missing");
|
|
30930
|
-
const destination =
|
|
30931
|
-
|
|
30932
|
-
const mode =
|
|
31004
|
+
const destination = join24(shadow, ...entry.path.split("/"));
|
|
31005
|
+
mkdirSync18(dirname15(destination), { recursive: true, mode: 448 });
|
|
31006
|
+
const mode = existsSync21(destination) ? lstatSync7(destination).mode & 511 : 420;
|
|
30933
31007
|
writeDurable(destination, bytes, mode);
|
|
30934
31008
|
}
|
|
30935
|
-
const project = parseRestrictedYaml2(
|
|
31009
|
+
const project = parseRestrictedYaml2(readFileSync21(join24(shadow, ".kxm", "project.yaml")), ".kxm/project.yaml");
|
|
30936
31010
|
const bound = absoluteMemberBindings(projectRoot, project, options.repositoryBindings);
|
|
30937
31011
|
loadVnextProject(shadow, { ...loaderOptions(options), repositoryBindings: bound });
|
|
30938
31012
|
const provenance = readProjectAndProvenance(shadow, options.schemasDir)?.provenance;
|
|
@@ -30941,7 +31015,7 @@ function prepareShadow(projectRoot, operation, options) {
|
|
|
30941
31015
|
}
|
|
30942
31016
|
}
|
|
30943
31017
|
function createOperation(projectRoot, kind, rendered, files, sourceTemplateRevision) {
|
|
30944
|
-
const root =
|
|
31018
|
+
const root = resolve18(projectRoot);
|
|
30945
31019
|
const operationWithoutHash = {
|
|
30946
31020
|
schema: "kxm.init-operation.v1",
|
|
30947
31021
|
operationId: `op_${randomUUID10().replaceAll("-", "")}`,
|
|
@@ -30970,8 +31044,8 @@ function prepareOperation(projectRoot, operation, rendered, options) {
|
|
|
30970
31044
|
const transaction = transactionRoot(projectRoot);
|
|
30971
31045
|
validateOperationRecord(operation, options.schemasDir);
|
|
30972
31046
|
validateOperationIntent(projectRoot, operation);
|
|
30973
|
-
if (
|
|
30974
|
-
|
|
31047
|
+
if (existsSync21(transaction)) fail3("init_transaction_exists", TRANSACTION_NAME, "an initialization transaction already exists and must be resumed");
|
|
31048
|
+
mkdirSync18(transaction, { mode: 448 });
|
|
30975
31049
|
syncDirectory2(projectRoot);
|
|
30976
31050
|
writeOperation(projectRoot, operation);
|
|
30977
31051
|
try {
|
|
@@ -30987,30 +31061,30 @@ function prepareOperation(projectRoot, operation, rendered, options) {
|
|
|
30987
31061
|
syncTreeDirectories(transaction);
|
|
30988
31062
|
return updatePhase(projectRoot, operation, "prepared");
|
|
30989
31063
|
} catch (error) {
|
|
30990
|
-
|
|
31064
|
+
rmSync8(transaction, { recursive: true, force: true });
|
|
30991
31065
|
throw error;
|
|
30992
31066
|
}
|
|
30993
31067
|
}
|
|
30994
31068
|
function ensureDestinationParents(projectRoot, path4) {
|
|
30995
|
-
const boundary =
|
|
31069
|
+
const boundary = resolve18(projectRoot);
|
|
30996
31070
|
const segments = path4.split("/").slice(0, -1);
|
|
30997
31071
|
let current = boundary;
|
|
30998
31072
|
for (const segment of segments) {
|
|
30999
|
-
current =
|
|
31000
|
-
if (!
|
|
31073
|
+
current = join24(current, segment);
|
|
31074
|
+
if (!existsSync21(current)) mkdirSync18(current, { mode: 448 });
|
|
31001
31075
|
const stat = lstatSync7(current);
|
|
31002
31076
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_destination_parent_invalid", path4, "destination parent must be a regular directory", "path");
|
|
31003
31077
|
}
|
|
31004
31078
|
}
|
|
31005
31079
|
function destinationSha(projectRoot, path4) {
|
|
31006
|
-
const file =
|
|
31007
|
-
if (!
|
|
31080
|
+
const file = join24(projectRoot, ...path4.split("/"));
|
|
31081
|
+
if (!existsSync21(file)) return void 0;
|
|
31008
31082
|
return vnextContentSha256(readRegularBounded(file, path4));
|
|
31009
31083
|
}
|
|
31010
31084
|
function requireConditionalLinkSupport(directory, operationId, path4) {
|
|
31011
31085
|
const nonce = randomUUID10();
|
|
31012
|
-
const source =
|
|
31013
|
-
const target =
|
|
31086
|
+
const source = join24(directory, `.kxm-repair-${operationId}-${nonce}.link-source`);
|
|
31087
|
+
const target = join24(directory, `.kxm-repair-${operationId}-${nonce}.link-target`);
|
|
31014
31088
|
try {
|
|
31015
31089
|
writeDurableNew(source, Buffer.from("kxm-link-probe\n", "utf8"), 384);
|
|
31016
31090
|
try {
|
|
@@ -31019,25 +31093,25 @@ function requireConditionalLinkSupport(directory, operationId, path4) {
|
|
|
31019
31093
|
fail3("repair_hard_link_unsupported", path4, "filesystem does not support the conditional hard-link install required for safe repair");
|
|
31020
31094
|
}
|
|
31021
31095
|
} finally {
|
|
31022
|
-
|
|
31023
|
-
|
|
31096
|
+
rmSync8(target, { force: true });
|
|
31097
|
+
rmSync8(source, { force: true });
|
|
31024
31098
|
syncDirectory2(directory);
|
|
31025
31099
|
}
|
|
31026
31100
|
}
|
|
31027
31101
|
function atomicInstallTarget(projectRoot, operation, entry) {
|
|
31028
|
-
const destination =
|
|
31102
|
+
const destination = join24(projectRoot, ...entry.path.split("/"));
|
|
31029
31103
|
ensureDestinationParents(projectRoot, entry.path);
|
|
31030
|
-
const directory =
|
|
31104
|
+
const directory = dirname15(destination);
|
|
31031
31105
|
const temporaryPrefix = `.kxm-repair-${operation.operationId}-`;
|
|
31032
31106
|
const pathKey = vnextContentSha256(entry.path).slice("sha256:".length, "sha256:".length + 16);
|
|
31033
|
-
const displaced =
|
|
31034
|
-
if (
|
|
31107
|
+
const displaced = join24(directory, `${temporaryPrefix}${pathKey}.preimage`);
|
|
31108
|
+
if (existsSync21(displaced)) {
|
|
31035
31109
|
const stat = lstatSync7(displaced);
|
|
31036
31110
|
if (stat.isSymbolicLink() || !stat.isFile()) fail3("repair_preimage_temporary_invalid", entry.path, "stale displaced preimage is not a regular file", "path");
|
|
31037
|
-
if (entry.observedSha256 === null || vnextContentSha256(
|
|
31111
|
+
if (entry.observedSha256 === null || vnextContentSha256(readFileSync21(displaced)) !== entry.observedSha256) {
|
|
31038
31112
|
fail3("repair_preimage_temporary_mismatch", entry.path, "stale displaced preimage does not match the pinned operation");
|
|
31039
31113
|
}
|
|
31040
|
-
if (!
|
|
31114
|
+
if (!existsSync21(destination)) {
|
|
31041
31115
|
try {
|
|
31042
31116
|
linkSync(displaced, destination);
|
|
31043
31117
|
} catch {
|
|
@@ -31045,14 +31119,14 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31045
31119
|
}
|
|
31046
31120
|
syncDirectory2(directory);
|
|
31047
31121
|
}
|
|
31048
|
-
|
|
31122
|
+
rmSync8(displaced, { force: true });
|
|
31049
31123
|
syncDirectory2(directory);
|
|
31050
31124
|
}
|
|
31051
31125
|
for (const candidate of readdirSync7(directory, { withFileTypes: true })) {
|
|
31052
31126
|
const owned = candidate.name.startsWith(temporaryPrefix) && (candidate.name.endsWith(".tmp") || candidate.name.endsWith(".link-source") || candidate.name.endsWith(".link-target"));
|
|
31053
31127
|
if (!owned) continue;
|
|
31054
31128
|
if (!candidate.isFile()) fail3("repair_temporary_invalid", entry.path, "stale operation temporary is not a regular file", "path");
|
|
31055
|
-
|
|
31129
|
+
rmSync8(join24(directory, candidate.name), { force: true });
|
|
31056
31130
|
}
|
|
31057
31131
|
const current = destinationSha(projectRoot, entry.path);
|
|
31058
31132
|
if (current === entry.targetSha256) return;
|
|
@@ -31062,22 +31136,22 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31062
31136
|
requireConditionalLinkSupport(directory, operation.operationId, entry.path);
|
|
31063
31137
|
const bytes = readTarget(projectRoot, entry.path);
|
|
31064
31138
|
if (!bytes) fail3("init_transaction_target_missing", entry.path, "pinned target artifact is missing");
|
|
31065
|
-
const temporary =
|
|
31066
|
-
const mode =
|
|
31139
|
+
const temporary = join24(directory, `${temporaryPrefix}${randomUUID10()}.tmp`);
|
|
31140
|
+
const mode = existsSync21(destination) ? lstatSync7(destination).mode & 511 : 420;
|
|
31067
31141
|
try {
|
|
31068
31142
|
writeDurableNew(temporary, bytes, mode);
|
|
31069
31143
|
if (entry.observedSha256 !== null) {
|
|
31070
|
-
|
|
31144
|
+
renameSync6(destination, displaced);
|
|
31071
31145
|
syncDirectory2(directory);
|
|
31072
|
-
if (vnextContentSha256(
|
|
31073
|
-
if (!
|
|
31146
|
+
if (vnextContentSha256(readFileSync21(displaced)) !== entry.observedSha256) {
|
|
31147
|
+
if (!existsSync21(destination)) {
|
|
31074
31148
|
try {
|
|
31075
31149
|
linkSync(displaced, destination);
|
|
31076
31150
|
} catch {
|
|
31077
31151
|
fail3("repair_preimage_restore_blocked", entry.path, "changed destination was displaced but could not be conditionally restored; its bytes remain in the operation preimage file");
|
|
31078
31152
|
}
|
|
31079
31153
|
syncDirectory2(directory);
|
|
31080
|
-
|
|
31154
|
+
rmSync8(displaced, { force: true });
|
|
31081
31155
|
syncDirectory2(directory);
|
|
31082
31156
|
}
|
|
31083
31157
|
fail3("repair_preimage_changed", entry.path, "destination changed at replacement time; concurrent bytes were preserved at the destination or in the operation preimage file");
|
|
@@ -31086,7 +31160,7 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31086
31160
|
try {
|
|
31087
31161
|
linkSync(temporary, destination);
|
|
31088
31162
|
} catch {
|
|
31089
|
-
if (!
|
|
31163
|
+
if (!existsSync21(destination) && existsSync21(displaced)) {
|
|
31090
31164
|
try {
|
|
31091
31165
|
linkSync(displaced, destination);
|
|
31092
31166
|
} catch {
|
|
@@ -31094,26 +31168,26 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31094
31168
|
}
|
|
31095
31169
|
syncDirectory2(directory);
|
|
31096
31170
|
}
|
|
31097
|
-
|
|
31171
|
+
rmSync8(displaced, { force: true });
|
|
31098
31172
|
syncDirectory2(directory);
|
|
31099
31173
|
fail3("repair_destination_recreated", entry.path, "destination was recreated concurrently or conditional install is unsupported; pinned target was not installed");
|
|
31100
31174
|
}
|
|
31101
31175
|
syncDirectory2(directory);
|
|
31102
|
-
|
|
31103
|
-
|
|
31176
|
+
rmSync8(temporary, { force: true });
|
|
31177
|
+
rmSync8(displaced, { force: true });
|
|
31104
31178
|
syncDirectory2(directory);
|
|
31105
31179
|
} finally {
|
|
31106
|
-
|
|
31180
|
+
rmSync8(temporary, { force: true });
|
|
31107
31181
|
}
|
|
31108
31182
|
if (destinationSha(projectRoot, entry.path) !== entry.targetSha256) fail3("repair_install_verification_failed", entry.path, "installed target hash does not match the pinned operation");
|
|
31109
31183
|
}
|
|
31110
31184
|
function installedCreateMatches(projectRoot, operation) {
|
|
31111
|
-
const configRoot =
|
|
31112
|
-
if (!
|
|
31185
|
+
const configRoot = join24(projectRoot, ".kxm");
|
|
31186
|
+
if (!existsSync21(configRoot)) return false;
|
|
31113
31187
|
const actual = [];
|
|
31114
31188
|
const visit2 = (directory) => {
|
|
31115
31189
|
for (const entry of readdirSync7(directory, { withFileTypes: true })) {
|
|
31116
|
-
const absolute =
|
|
31190
|
+
const absolute = join24(directory, entry.name);
|
|
31117
31191
|
if (entry.isSymbolicLink()) fail3("create_resume_link", relativeConfigPath(projectRoot, absolute), "created configuration must not contain links", "path");
|
|
31118
31192
|
if (entry.isDirectory()) visit2(absolute);
|
|
31119
31193
|
else if (entry.isFile()) actual.push(relativeConfigPath(projectRoot, absolute));
|
|
@@ -31126,15 +31200,15 @@ function installedCreateMatches(projectRoot, operation) {
|
|
|
31126
31200
|
return actual.length === expected.length && actual.every((path4, index) => path4 === expected[index]) && operation.files.every((entry) => destinationSha(projectRoot, entry.path) === entry.targetSha256);
|
|
31127
31201
|
}
|
|
31128
31202
|
function relativeConfigPath(projectRoot, file) {
|
|
31129
|
-
return relative4(
|
|
31203
|
+
return relative4(resolve18(projectRoot), file).replaceAll("\\", "/");
|
|
31130
31204
|
}
|
|
31131
31205
|
function syncTreeDirectories(root) {
|
|
31132
|
-
if (!
|
|
31206
|
+
if (!existsSync21(root)) return;
|
|
31133
31207
|
const directories = [];
|
|
31134
31208
|
const visit2 = (directory) => {
|
|
31135
31209
|
directories.push(directory);
|
|
31136
31210
|
for (const entry of readdirSync7(directory, { withFileTypes: true })) {
|
|
31137
|
-
if (entry.isDirectory()) visit2(
|
|
31211
|
+
if (entry.isDirectory()) visit2(join24(directory, entry.name));
|
|
31138
31212
|
}
|
|
31139
31213
|
};
|
|
31140
31214
|
visit2(root);
|
|
@@ -31142,13 +31216,13 @@ function syncTreeDirectories(root) {
|
|
|
31142
31216
|
}
|
|
31143
31217
|
function rebuildCreateShadow(projectRoot, operation, options) {
|
|
31144
31218
|
const shadow = shadowRoot(projectRoot);
|
|
31145
|
-
|
|
31219
|
+
rmSync8(shadow, { recursive: true, force: true });
|
|
31146
31220
|
prepareShadow(projectRoot, operation, options);
|
|
31147
31221
|
const stat = lstatSync7(shadow);
|
|
31148
31222
|
if (stat.isSymbolicLink() || !stat.isDirectory() || !installedCreateMatches(shadow, operation)) {
|
|
31149
31223
|
fail3("create_shadow_invalid", TRANSACTION_NAME, "reconstructed create shadow does not exactly match pinned target files", "path");
|
|
31150
31224
|
}
|
|
31151
|
-
syncTreeDirectories(
|
|
31225
|
+
syncTreeDirectories(join24(shadow, ".kxm"));
|
|
31152
31226
|
}
|
|
31153
31227
|
function applyOperation(projectRoot, original, options, resumed) {
|
|
31154
31228
|
assertNoRegisteredGates(options);
|
|
@@ -31158,10 +31232,10 @@ function applyOperation(projectRoot, original, options, resumed) {
|
|
|
31158
31232
|
verifyBackups(projectRoot, operation);
|
|
31159
31233
|
operation = updatePhase(projectRoot, operation, "applying");
|
|
31160
31234
|
if (operation.kind === "create") {
|
|
31161
|
-
const destination =
|
|
31162
|
-
if (!
|
|
31235
|
+
const destination = join24(projectRoot, ".kxm");
|
|
31236
|
+
if (!existsSync21(destination)) {
|
|
31163
31237
|
rebuildCreateShadow(projectRoot, operation, effectiveOptions);
|
|
31164
|
-
|
|
31238
|
+
renameSync6(join24(shadowRoot(projectRoot), ".kxm"), destination);
|
|
31165
31239
|
syncDirectory2(projectRoot);
|
|
31166
31240
|
} else if (!installedCreateMatches(projectRoot, operation)) {
|
|
31167
31241
|
fail3("create_resume_conflict", ".kxm", "existing project configuration does not match the pinned create operation");
|
|
@@ -31188,7 +31262,7 @@ function applyOperation(projectRoot, original, options, resumed) {
|
|
|
31188
31262
|
operation = updatePhase(projectRoot, operation, "verified");
|
|
31189
31263
|
if (options.testFaultAt === "verified") throw new Error("injected init fault after verification");
|
|
31190
31264
|
const files = operation.files.map((entry) => entry.path);
|
|
31191
|
-
syncTreeDirectories(
|
|
31265
|
+
syncTreeDirectories(join24(projectRoot, ".kxm"));
|
|
31192
31266
|
return { kind: operation.kind, resumed, bundle, files };
|
|
31193
31267
|
}
|
|
31194
31268
|
function prepareAndApplyVnextCreate(projectRoot, rendered, options = {}) {
|
|
@@ -31303,7 +31377,7 @@ function finishPreparingOperation(projectRoot, operation, options) {
|
|
|
31303
31377
|
const rendered = rendererForOperation(operation);
|
|
31304
31378
|
if (!rendered) fail3("init_transaction_renderer_unavailable", TRANSACTION_NAME, "this binary cannot reproduce the pinned pre-application target");
|
|
31305
31379
|
for (const directory of ["targets", "backups", "shadow"]) {
|
|
31306
|
-
|
|
31380
|
+
rmSync8(join24(transactionRoot(projectRoot), directory), { recursive: true, force: true });
|
|
31307
31381
|
}
|
|
31308
31382
|
for (const entry of operation.files) {
|
|
31309
31383
|
const bytes = rendered.files.get(entry.path);
|
|
@@ -31322,8 +31396,8 @@ function resumeVnextInitTransaction(projectRoot, options = {}) {
|
|
|
31322
31396
|
let operation = readOperation(projectRoot, options.schemasDir);
|
|
31323
31397
|
if (!operation) {
|
|
31324
31398
|
const root = transactionRoot(projectRoot);
|
|
31325
|
-
if (
|
|
31326
|
-
|
|
31399
|
+
if (existsSync21(root)) {
|
|
31400
|
+
rmSync8(root, { recursive: true, force: true });
|
|
31327
31401
|
syncDirectory2(projectRoot);
|
|
31328
31402
|
}
|
|
31329
31403
|
return void 0;
|
|
@@ -31338,10 +31412,10 @@ function commitVnextInitTransaction(projectRoot, schemasDir) {
|
|
|
31338
31412
|
fail3("init_transaction_not_verified", TRANSACTION_NAME, "initialization transaction cannot commit before installed state is verified");
|
|
31339
31413
|
}
|
|
31340
31414
|
const transaction = transactionRoot(projectRoot);
|
|
31341
|
-
const retired =
|
|
31342
|
-
|
|
31415
|
+
const retired = join24(projectRoot, `${TRANSACTION_NAME}-cleanup-${operation.operationId}-${randomUUID10()}`);
|
|
31416
|
+
renameSync6(transaction, retired);
|
|
31343
31417
|
syncDirectory2(projectRoot);
|
|
31344
|
-
|
|
31418
|
+
rmSync8(retired, { recursive: true, force: true });
|
|
31345
31419
|
syncDirectory2(projectRoot);
|
|
31346
31420
|
}
|
|
31347
31421
|
function inspectVnextInitTransaction(projectRoot, schemasDir) {
|
|
@@ -31447,7 +31521,7 @@ function validateBindingIdentities(bundle, persisted, explicit) {
|
|
|
31447
31521
|
}
|
|
31448
31522
|
function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock) {
|
|
31449
31523
|
const storeOptions = bindingStoreOptions(options);
|
|
31450
|
-
const persisted =
|
|
31524
|
+
const persisted = existsSync22(join25(gitRoot, ".kxm", "project.yaml")) ? readVnextLocalBindings(gitRoot, storeOptions) : void 0;
|
|
31451
31525
|
const repositoryBindings = Object.fromEntries([
|
|
31452
31526
|
...Object.entries(persisted?.repositories ?? {}),
|
|
31453
31527
|
...Object.entries(options.repositoryBindings ?? {})
|
|
@@ -31636,7 +31710,7 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31636
31710
|
const files = [...rendered.files.keys()];
|
|
31637
31711
|
if (options.dryRun) return { action: "planned", plan, projectRoot: gitRoot, files };
|
|
31638
31712
|
if (!mutationLock) throw new Error("project mutation lock is required to create configuration");
|
|
31639
|
-
if (
|
|
31713
|
+
if (existsSync22(join25(gitRoot, ".kxm"))) {
|
|
31640
31714
|
throw new VnextConfigError([initIssue("workspace_changed", ".kxm", "workspace changed after planning; existing .kxm state was not overwritten")]);
|
|
31641
31715
|
}
|
|
31642
31716
|
const created = prepareAndApplyVnextCreate(gitRoot, rendered, transactionOptions);
|
|
@@ -31668,8 +31742,8 @@ function initializeVnextProject(start = process.cwd(), options = {}) {
|
|
|
31668
31742
|
// plugins/kxm/src/vnext-migrate.ts
|
|
31669
31743
|
var import_yaml12 = __toESM(require_dist(), 1);
|
|
31670
31744
|
import { createHash as createHash13 } from "node:crypto";
|
|
31671
|
-
import { chmodSync as chmodSync6, closeSync as closeSync3, existsSync as
|
|
31672
|
-
import { join as
|
|
31745
|
+
import { chmodSync as chmodSync6, closeSync as closeSync3, existsSync as existsSync23, fsyncSync as fsyncSync3, lstatSync as lstatSync8, mkdirSync as mkdirSync19, openSync as openSync3, readFileSync as readFileSync22, renameSync as renameSync7, rmSync as rmSync9, writeFileSync as writeFileSync18 } from "node:fs";
|
|
31746
|
+
import { join as join26 } from "node:path";
|
|
31673
31747
|
var MAX_LEGACY_JSON_BYTES = 1024 * 1024;
|
|
31674
31748
|
var MAX_LEGACY_JSON_DEPTH = 32;
|
|
31675
31749
|
var MAX_LEGACY_JSON_NODES = 32768;
|
|
@@ -31838,12 +31912,12 @@ function readVnextLegacySources(root) {
|
|
|
31838
31912
|
throw new VnextConfigError([migrateIssue("discovery", "legacy_source_limit", ".kxm/config", `legacy configuration exceeds ${MAX_LEGACY_SOURCES} files`)]);
|
|
31839
31913
|
}
|
|
31840
31914
|
return files.map((path4) => {
|
|
31841
|
-
const absolute =
|
|
31915
|
+
const absolute = join26(root, ...path4.split("/"));
|
|
31842
31916
|
const stat = lstatSync8(absolute);
|
|
31843
31917
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
31844
31918
|
throw new VnextConfigError([migrateIssue("path", "legacy_source_invalid", path4, "legacy configuration must be a regular file, not a link")]);
|
|
31845
31919
|
}
|
|
31846
|
-
const buffer =
|
|
31920
|
+
const buffer = readFileSync22(absolute);
|
|
31847
31921
|
let text;
|
|
31848
31922
|
try {
|
|
31849
31923
|
text = new TextDecoder("utf-8", { fatal: true }).decode(buffer);
|
|
@@ -32916,11 +32990,11 @@ function planVnextMigration(projectRoot, options = {}) {
|
|
|
32916
32990
|
};
|
|
32917
32991
|
}
|
|
32918
32992
|
function readVnextMigrationDecisions(path4, schemasDir) {
|
|
32919
|
-
if (!
|
|
32993
|
+
if (!existsSync23(path4)) {
|
|
32920
32994
|
throw new VnextConfigError([migrateIssue("discovery", "decisions_missing", path4, "migration decisions file does not exist")]);
|
|
32921
32995
|
}
|
|
32922
32996
|
const registry = new VnextSchemaRegistry(schemasDir);
|
|
32923
|
-
const value = parseRestrictedYaml2(
|
|
32997
|
+
const value = parseRestrictedYaml2(readFileSync22(path4), path4);
|
|
32924
32998
|
const issues = registry.validateMigrationDecision(value, path4);
|
|
32925
32999
|
if (issues.length > 0) throw new VnextConfigError(issues);
|
|
32926
33000
|
return value;
|
|
@@ -32949,19 +33023,19 @@ function writeDurable2(path4, content) {
|
|
|
32949
33023
|
const descriptor = openSync3(temp, "wx", 384);
|
|
32950
33024
|
created = true;
|
|
32951
33025
|
try {
|
|
32952
|
-
|
|
33026
|
+
writeFileSync18(descriptor, content);
|
|
32953
33027
|
fsyncSync3(descriptor);
|
|
32954
33028
|
} finally {
|
|
32955
33029
|
closeSync3(descriptor);
|
|
32956
33030
|
}
|
|
32957
|
-
|
|
33031
|
+
renameSync7(temp, path4);
|
|
32958
33032
|
try {
|
|
32959
33033
|
chmodSync6(path4, 384);
|
|
32960
33034
|
} catch {
|
|
32961
33035
|
}
|
|
32962
|
-
syncDirectory3(
|
|
33036
|
+
syncDirectory3(join26(path4, ".."));
|
|
32963
33037
|
} finally {
|
|
32964
|
-
if (created &&
|
|
33038
|
+
if (created && existsSync23(temp)) rmSync9(temp, { force: true });
|
|
32965
33039
|
}
|
|
32966
33040
|
}
|
|
32967
33041
|
function applyVnextMigration(projectRoot, options = {}) {
|
|
@@ -32971,8 +33045,8 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
32971
33045
|
...options.schemasDir === void 0 ? {} : { schemasDir: options.schemasDir }
|
|
32972
33046
|
};
|
|
32973
33047
|
const execute = (lock) => {
|
|
32974
|
-
const receiptAbsolute =
|
|
32975
|
-
if (
|
|
33048
|
+
const receiptAbsolute = join26(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
|
|
33049
|
+
if (existsSync23(receiptAbsolute)) {
|
|
32976
33050
|
const stat = lstatSync8(receiptAbsolute);
|
|
32977
33051
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
32978
33052
|
throw new VnextConfigError([migrateIssue("path", "migration_receipt_invalid", VNEXT_MIGRATION_RECEIPT_PATH, "migration receipt must be a regular file, not a link")]);
|
|
@@ -33025,7 +33099,7 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33025
33099
|
return { action: "planned", projectRoot: root, files: [], plan: first.plan };
|
|
33026
33100
|
}
|
|
33027
33101
|
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") }));
|
|
33028
|
-
const collisions = files.filter((file) =>
|
|
33102
|
+
const collisions = files.filter((file) => existsSync23(join26(root, ...file.path.split("/"))));
|
|
33029
33103
|
if (collisions.length > 0) {
|
|
33030
33104
|
throw new VnextConfigError(collisions.map((file) => migrateIssue("semantic", "migration_target_exists", file.path, "target resource already exists; refusing to overwrite")));
|
|
33031
33105
|
}
|
|
@@ -33034,8 +33108,8 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33034
33108
|
const segments = file.path.split("/");
|
|
33035
33109
|
let current = root;
|
|
33036
33110
|
for (const segment of segments.slice(0, -1)) {
|
|
33037
|
-
current =
|
|
33038
|
-
if (!
|
|
33111
|
+
current = join26(current, segment);
|
|
33112
|
+
if (!existsSync23(current)) continue;
|
|
33039
33113
|
const stat = lstatSync8(current);
|
|
33040
33114
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
33041
33115
|
parentIssues.push(migrateIssue("path", "migration_target_parent_invalid", file.path, `migration target parent ${segment} must be a regular directory, not a link`));
|
|
@@ -33051,8 +33125,8 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33051
33125
|
const written = [];
|
|
33052
33126
|
try {
|
|
33053
33127
|
for (const file of files) {
|
|
33054
|
-
const absolute =
|
|
33055
|
-
|
|
33128
|
+
const absolute = join26(root, ...file.path.split("/"));
|
|
33129
|
+
mkdirSync19(join26(absolute, ".."), { recursive: true });
|
|
33056
33130
|
written.push(absolute);
|
|
33057
33131
|
writeDurable2(absolute, file.bytes);
|
|
33058
33132
|
}
|
|
@@ -33086,7 +33160,7 @@ ${bundle.configRevision}`).slice(7, 39)}`,
|
|
|
33086
33160
|
} catch (error) {
|
|
33087
33161
|
for (const absolute of written.reverse()) {
|
|
33088
33162
|
try {
|
|
33089
|
-
|
|
33163
|
+
rmSync9(absolute, { force: true });
|
|
33090
33164
|
} catch {
|
|
33091
33165
|
}
|
|
33092
33166
|
}
|
|
@@ -33098,8 +33172,8 @@ ${bundle.configRevision}`).slice(7, 39)}`,
|
|
|
33098
33172
|
}
|
|
33099
33173
|
function verifyVnextMigration(projectRoot, options = {}) {
|
|
33100
33174
|
const root = migrationGitRoot(projectRoot);
|
|
33101
|
-
const receiptAbsolute =
|
|
33102
|
-
if (!
|
|
33175
|
+
const receiptAbsolute = join26(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
|
|
33176
|
+
if (!existsSync23(receiptAbsolute)) {
|
|
33103
33177
|
return {
|
|
33104
33178
|
ok: false,
|
|
33105
33179
|
projectRoot: root,
|
|
@@ -33396,7 +33470,7 @@ async function cmdBackup(runtime, options) {
|
|
|
33396
33470
|
try {
|
|
33397
33471
|
const { manifest, outDir } = createBackup({
|
|
33398
33472
|
projectRoot: runtime.cwd,
|
|
33399
|
-
...options.out ? { outDir:
|
|
33473
|
+
...options.out ? { outDir: resolve20(runtime.cwd, options.out) } : {}
|
|
33400
33474
|
});
|
|
33401
33475
|
const payload = {
|
|
33402
33476
|
ok: true,
|
|
@@ -33408,7 +33482,7 @@ async function cmdBackup(runtime, options) {
|
|
|
33408
33482
|
const summary = [
|
|
33409
33483
|
`Created SQLite backup with ${manifest.stores.length} store(s):`,
|
|
33410
33484
|
...manifest.stores.map((s) => ` - ${s.storeId}: ${s.sourcePath} -> ${s.backupFile} (schema v${s.schemaVersion}, ${s.bytes} bytes, sha256 ${s.sha256.slice(0, 12)}...)`),
|
|
33411
|
-
`Manifest: ${
|
|
33485
|
+
`Manifest: ${join27(outDir, "manifest.json")}`
|
|
33412
33486
|
].join("\n");
|
|
33413
33487
|
print(runtime.io, runtime.json, payload, summary);
|
|
33414
33488
|
return 0;
|
|
@@ -33423,7 +33497,7 @@ async function cmdBackup(runtime, options) {
|
|
|
33423
33497
|
}
|
|
33424
33498
|
async function cmdRestore(runtime, manifestArg) {
|
|
33425
33499
|
try {
|
|
33426
|
-
const result = restoreBackup(
|
|
33500
|
+
const result = restoreBackup(resolve20(runtime.cwd, manifestArg), {
|
|
33427
33501
|
projectRoot: runtime.cwd
|
|
33428
33502
|
});
|
|
33429
33503
|
const payload = {
|
|
@@ -33683,7 +33757,7 @@ async function selectProducerModel(runtime, requested) {
|
|
|
33683
33757
|
if (runtime.json || !process.stdin.isTTY || models.length === 0) return void 0;
|
|
33684
33758
|
runtime.io.stdout(models.slice(0, 100).map((model, index2) => `${index2 + 1}. ${model}`).join("\n") + "\nSelect model number: ");
|
|
33685
33759
|
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
33686
|
-
const answer = await new Promise((
|
|
33760
|
+
const answer = await new Promise((resolve31) => rl.once("line", resolve31));
|
|
33687
33761
|
rl.close();
|
|
33688
33762
|
const index = Number.parseInt(answer.trim(), 10) - 1;
|
|
33689
33763
|
return Number.isInteger(index) && index >= 0 && index < models.length ? models[index] : void 0;
|
|
@@ -33709,7 +33783,7 @@ async function cmdModelsScreen(runtime) {
|
|
|
33709
33783
|
return 2;
|
|
33710
33784
|
}
|
|
33711
33785
|
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
33712
|
-
const ask = (q2) => new Promise((
|
|
33786
|
+
const ask = (q2) => new Promise((resolve31) => rl.question(q2, resolve31));
|
|
33713
33787
|
try {
|
|
33714
33788
|
while (true) {
|
|
33715
33789
|
const policy = loadProducerPolicy(runtime.dirs.workdir);
|
|
@@ -33973,12 +34047,12 @@ async function cmdStudioLayout(runtime, workflowPath) {
|
|
|
33973
34047
|
const projectRoot = discoverVnextProjectRoot(runtime.cwd) ?? runtime.cwd;
|
|
33974
34048
|
let filePath = workflowPath;
|
|
33975
34049
|
if (!filePath) {
|
|
33976
|
-
filePath =
|
|
34050
|
+
filePath = resolve21(projectRoot, ".kxm", "workflows", "default.yaml");
|
|
33977
34051
|
}
|
|
33978
34052
|
let yamlContent;
|
|
33979
34053
|
let workflowId = "default";
|
|
33980
|
-
if (
|
|
33981
|
-
yamlContent =
|
|
34054
|
+
if (existsSync24(filePath)) {
|
|
34055
|
+
yamlContent = readFileSync23(filePath, "utf8");
|
|
33982
34056
|
} else {
|
|
33983
34057
|
yamlContent = `schema: kxm.workflow.v1
|
|
33984
34058
|
description: Feature implementation workflow
|
|
@@ -34051,15 +34125,15 @@ async function cmdStudioServe(runtime, options) {
|
|
|
34051
34125
|
sessionToken,
|
|
34052
34126
|
planProvider: () => {
|
|
34053
34127
|
try {
|
|
34054
|
-
const wfDir =
|
|
34055
|
-
const defaultPath =
|
|
34056
|
-
let targetPath =
|
|
34057
|
-
if (!targetPath &&
|
|
34128
|
+
const wfDir = join28(runtime.cwd, ".kxm", "workflows");
|
|
34129
|
+
const defaultPath = join28(wfDir, "default.yaml");
|
|
34130
|
+
let targetPath = existsSync24(defaultPath) ? defaultPath : void 0;
|
|
34131
|
+
if (!targetPath && existsSync24(wfDir)) {
|
|
34058
34132
|
const yml = readdirSync8(wfDir).find((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
|
|
34059
|
-
if (yml) targetPath =
|
|
34133
|
+
if (yml) targetPath = join28(wfDir, yml);
|
|
34060
34134
|
}
|
|
34061
|
-
if (targetPath &&
|
|
34062
|
-
const raw =
|
|
34135
|
+
if (targetPath && existsSync24(targetPath)) {
|
|
34136
|
+
const raw = readFileSync23(targetPath, "utf8");
|
|
34063
34137
|
const parsed = (0, import_yaml13.parse)(raw);
|
|
34064
34138
|
const wfId = basename6(targetPath).replace(/\.(yaml|yml)$/, "");
|
|
34065
34139
|
return compileVnextWorkflow({ id: wfId, value: parsed });
|
|
@@ -34109,14 +34183,14 @@ Press Ctrl+C to stop.
|
|
|
34109
34183
|
}
|
|
34110
34184
|
|
|
34111
34185
|
// plugins/kxm/src/cli/context-skills.ts
|
|
34112
|
-
import { readFileSync as
|
|
34113
|
-
import { join as
|
|
34186
|
+
import { readFileSync as readFileSync26 } from "node:fs";
|
|
34187
|
+
import { join as join32, relative as relative5 } from "node:path";
|
|
34114
34188
|
|
|
34115
34189
|
// plugins/kxm/src/memory.ts
|
|
34116
34190
|
var import_yaml14 = __toESM(require_dist(), 1);
|
|
34117
34191
|
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
34118
|
-
import { existsSync as
|
|
34119
|
-
import { extname as extname2, join as
|
|
34192
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync20, readdirSync as readdirSync9, readFileSync as readFileSync24, writeFileSync as writeFileSync19 } from "node:fs";
|
|
34193
|
+
import { extname as extname2, join as join29, resolve as resolve22 } from "node:path";
|
|
34120
34194
|
var MEMORY_SCHEMA = "kxm.memory.v1";
|
|
34121
34195
|
var MEMORY_BRIEF_SCHEMA = "kxm.memory-brief.v1";
|
|
34122
34196
|
var MEMORY_MARKER_START = "<!-- kxm:memory:start -->";
|
|
@@ -34242,21 +34316,21 @@ ${yamlText}
|
|
|
34242
34316
|
`;
|
|
34243
34317
|
}
|
|
34244
34318
|
function memoryDirectories(repoRoot) {
|
|
34245
|
-
const root =
|
|
34246
|
-
const memoryDir =
|
|
34247
|
-
const candidatesDir =
|
|
34319
|
+
const root = resolve22(repoRoot);
|
|
34320
|
+
const memoryDir = join29(root, ".kxm", "memory");
|
|
34321
|
+
const candidatesDir = join29(memoryDir, "candidates");
|
|
34248
34322
|
return { memoryDir, candidatesDir };
|
|
34249
34323
|
}
|
|
34250
34324
|
function loadAuthoredMemory(repoRoot) {
|
|
34251
34325
|
const { memoryDir } = memoryDirectories(repoRoot);
|
|
34252
|
-
if (!
|
|
34326
|
+
if (!existsSync25(memoryDir)) return [];
|
|
34253
34327
|
const records = [];
|
|
34254
34328
|
const entries = readdirSync9(memoryDir, { withFileTypes: true });
|
|
34255
34329
|
for (const entry of entries) {
|
|
34256
34330
|
if (entry.isFile() && extname2(entry.name) === ".md") {
|
|
34257
|
-
const fullPath =
|
|
34331
|
+
const fullPath = join29(memoryDir, entry.name);
|
|
34258
34332
|
try {
|
|
34259
|
-
const text =
|
|
34333
|
+
const text = readFileSync24(fullPath, "utf8");
|
|
34260
34334
|
const record = parseMemoryRecord(text, entry.name);
|
|
34261
34335
|
if (record.lifecycle === "active") {
|
|
34262
34336
|
records.push(record);
|
|
@@ -34270,7 +34344,7 @@ function loadAuthoredMemory(repoRoot) {
|
|
|
34270
34344
|
}
|
|
34271
34345
|
function createMemoryNote(repoRoot, summary, options = {}) {
|
|
34272
34346
|
const { candidatesDir } = memoryDirectories(repoRoot);
|
|
34273
|
-
|
|
34347
|
+
mkdirSync20(candidatesDir, { recursive: true });
|
|
34274
34348
|
const scope = options.scope ?? "project";
|
|
34275
34349
|
if (!VALID_SCOPES.has(scope)) {
|
|
34276
34350
|
throw new Error(`invalid memory note scope: ${scope}; must be one of agent, project, run, operator`);
|
|
@@ -34295,8 +34369,8 @@ function createMemoryNote(repoRoot, summary, options = {}) {
|
|
|
34295
34369
|
evidenceRefs: [],
|
|
34296
34370
|
...options.body ? { body: options.body.trim() } : {}
|
|
34297
34371
|
};
|
|
34298
|
-
const targetPath =
|
|
34299
|
-
|
|
34372
|
+
const targetPath = join29(candidatesDir, `${id}.md`);
|
|
34373
|
+
writeFileSync19(targetPath, formatMemoryRecord(record), "utf8");
|
|
34300
34374
|
return { record, path: targetPath };
|
|
34301
34375
|
}
|
|
34302
34376
|
function generateMemoryBrief(repoRoot) {
|
|
@@ -34332,8 +34406,8 @@ function formatHarnessMemoryBlock(records) {
|
|
|
34332
34406
|
}
|
|
34333
34407
|
function updateHarnessDocument(filePath, block, defaultHeader) {
|
|
34334
34408
|
let original = "";
|
|
34335
|
-
if (
|
|
34336
|
-
original =
|
|
34409
|
+
if (existsSync25(filePath)) {
|
|
34410
|
+
original = readFileSync24(filePath, "utf8");
|
|
34337
34411
|
}
|
|
34338
34412
|
let updated = "";
|
|
34339
34413
|
if (original.includes(MEMORY_MARKER_START) && original.includes(MEMORY_MARKER_END)) {
|
|
@@ -34361,25 +34435,25 @@ ${block}
|
|
|
34361
34435
|
`;
|
|
34362
34436
|
}
|
|
34363
34437
|
if (updated !== original) {
|
|
34364
|
-
|
|
34438
|
+
writeFileSync19(filePath, updated, "utf8");
|
|
34365
34439
|
return true;
|
|
34366
34440
|
}
|
|
34367
34441
|
return false;
|
|
34368
34442
|
}
|
|
34369
34443
|
function syncHarnessMemory(repoRoot) {
|
|
34370
|
-
const root =
|
|
34444
|
+
const root = resolve22(repoRoot);
|
|
34371
34445
|
const records = loadAuthoredMemory(root);
|
|
34372
34446
|
const block = formatHarnessMemoryBlock(records);
|
|
34373
34447
|
const updated = [];
|
|
34374
34448
|
const created = [];
|
|
34375
|
-
const agentsPath =
|
|
34449
|
+
const agentsPath = join29(root, "AGENTS.md");
|
|
34376
34450
|
const agentsHeader = "# AGENTS\n\nFollow project instructions.\n";
|
|
34377
|
-
const agentsExisted =
|
|
34451
|
+
const agentsExisted = existsSync25(agentsPath);
|
|
34378
34452
|
if (updateHarnessDocument(agentsPath, block, agentsHeader)) {
|
|
34379
34453
|
if (agentsExisted) updated.push("AGENTS.md");
|
|
34380
34454
|
else created.push("AGENTS.md");
|
|
34381
34455
|
}
|
|
34382
|
-
const claudePath =
|
|
34456
|
+
const claudePath = join29(root, "CLAUDE.md");
|
|
34383
34457
|
const claudeHeader = `# KXM (Claude)
|
|
34384
34458
|
|
|
34385
34459
|
Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
@@ -34390,12 +34464,12 @@ you to implement. Default writer is native Grok CLI (\`grok --model grok-4.6\`).
|
|
|
34390
34464
|
If \`grok\` is logged out, fail closed; do not fall back to Pi. Your reviews are
|
|
34391
34465
|
artifacts, not hub \`peer-reply\` evidence.
|
|
34392
34466
|
`;
|
|
34393
|
-
const claudeExisted =
|
|
34467
|
+
const claudeExisted = existsSync25(claudePath);
|
|
34394
34468
|
if (updateHarnessDocument(claudePath, block, claudeHeader)) {
|
|
34395
34469
|
if (claudeExisted) updated.push("CLAUDE.md");
|
|
34396
34470
|
else created.push("CLAUDE.md");
|
|
34397
34471
|
}
|
|
34398
|
-
const geminiPath =
|
|
34472
|
+
const geminiPath = join29(root, "GEMINI.md");
|
|
34399
34473
|
const geminiHeader = `# KXM (Gemini / Antigravity)
|
|
34400
34474
|
|
|
34401
34475
|
Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
@@ -34404,7 +34478,7 @@ Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
|
34404
34478
|
Google / Antigravity CLI (\`agy\`) is an admitted native writer and experiment edit route
|
|
34405
34479
|
for Gemini models. Starting rotation remains Grok.
|
|
34406
34480
|
`;
|
|
34407
|
-
const geminiExisted =
|
|
34481
|
+
const geminiExisted = existsSync25(geminiPath);
|
|
34408
34482
|
if (updateHarnessDocument(geminiPath, block, geminiHeader)) {
|
|
34409
34483
|
if (geminiExisted) updated.push("GEMINI.md");
|
|
34410
34484
|
else created.push("GEMINI.md");
|
|
@@ -34415,8 +34489,8 @@ for Gemini models. Starting rotation remains Grok.
|
|
|
34415
34489
|
// plugins/kxm/src/skills.ts
|
|
34416
34490
|
var import_yaml15 = __toESM(require_dist(), 1);
|
|
34417
34491
|
import { createHash as createHash14 } from "node:crypto";
|
|
34418
|
-
import { existsSync as
|
|
34419
|
-
import { join as
|
|
34492
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync21, readdirSync as readdirSync10, readFileSync as readFileSync25, renameSync as renameSync8, rmSync as rmSync10, statSync as statSync3, writeFileSync as writeFileSync20 } from "node:fs";
|
|
34493
|
+
import { join as join30 } from "node:path";
|
|
34420
34494
|
var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
|
|
34421
34495
|
var SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
|
|
34422
34496
|
var SKILL_DECISION_SCHEMA = "kxm.skill-decision.v1";
|
|
@@ -34510,48 +34584,48 @@ var SkillLifecycle = class {
|
|
|
34510
34584
|
this.allowOptimizationEvals = options.allowOptimizationEvals === true;
|
|
34511
34585
|
}
|
|
34512
34586
|
dir(state) {
|
|
34513
|
-
return
|
|
34587
|
+
return join30(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
|
|
34514
34588
|
}
|
|
34515
34589
|
historyFile(id) {
|
|
34516
|
-
return
|
|
34590
|
+
return join30(this.root, "history", `${id}.jsonl`);
|
|
34517
34591
|
}
|
|
34518
34592
|
paths(state, id) {
|
|
34519
|
-
const dir =
|
|
34520
|
-
return { dir, metadata:
|
|
34593
|
+
const dir = join30(this.dir(state), id);
|
|
34594
|
+
return { dir, metadata: join30(dir, "metadata.json"), skill: join30(dir, "SKILL.md") };
|
|
34521
34595
|
}
|
|
34522
34596
|
appendHistory(id, record) {
|
|
34523
|
-
|
|
34597
|
+
mkdirSync21(join30(this.root, "history"), { recursive: true });
|
|
34524
34598
|
const line = `${JSON.stringify(record)}
|
|
34525
34599
|
`;
|
|
34526
|
-
if (
|
|
34527
|
-
const existing =
|
|
34600
|
+
if (existsSync26(this.historyFile(id))) {
|
|
34601
|
+
const existing = readFileSync25(this.historyFile(id), "utf8");
|
|
34528
34602
|
const lines = existing.split("\n").filter((entry) => entry.trim());
|
|
34529
|
-
|
|
34603
|
+
writeFileSync20(this.historyFile(id), [...lines.slice(-499), line.trim()].join("\n") + "\n");
|
|
34530
34604
|
} else {
|
|
34531
|
-
|
|
34605
|
+
writeFileSync20(this.historyFile(id), line);
|
|
34532
34606
|
}
|
|
34533
34607
|
}
|
|
34534
34608
|
history(id) {
|
|
34535
34609
|
const file = this.historyFile(id);
|
|
34536
|
-
if (!
|
|
34537
|
-
return
|
|
34610
|
+
if (!existsSync26(file)) return [];
|
|
34611
|
+
return readFileSync25(file, "utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
34538
34612
|
}
|
|
34539
34613
|
readMetadata(state, id) {
|
|
34540
34614
|
const { metadata } = this.paths(state, id);
|
|
34541
|
-
if (!
|
|
34615
|
+
if (!existsSync26(metadata)) {
|
|
34542
34616
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${state}`);
|
|
34543
34617
|
}
|
|
34544
|
-
return JSON.parse(
|
|
34618
|
+
return JSON.parse(readFileSync25(metadata, "utf8"));
|
|
34545
34619
|
}
|
|
34546
34620
|
move(from, to, id) {
|
|
34547
|
-
const fromDir =
|
|
34548
|
-
const toDir =
|
|
34549
|
-
if (!
|
|
34621
|
+
const fromDir = join30(this.dir(from), id);
|
|
34622
|
+
const toDir = join30(this.dir(to), id);
|
|
34623
|
+
if (!existsSync26(fromDir)) {
|
|
34550
34624
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${from}`);
|
|
34551
34625
|
}
|
|
34552
|
-
|
|
34553
|
-
if (
|
|
34554
|
-
|
|
34626
|
+
mkdirSync21(this.dir(to), { recursive: true });
|
|
34627
|
+
if (existsSync26(toDir)) rmSync10(toDir, { recursive: true, force: true });
|
|
34628
|
+
renameSync8(fromDir, toDir);
|
|
34555
34629
|
}
|
|
34556
34630
|
/** Submit a new skill candidate. Content is redacted of secret material at
|
|
34557
34631
|
* creation; the ID is derived from name + content hash. */
|
|
@@ -34593,7 +34667,7 @@ var SkillLifecycle = class {
|
|
|
34593
34667
|
const contentSha256 = skillContentSha256(content);
|
|
34594
34668
|
const id = skillIdFor(name, contentSha256);
|
|
34595
34669
|
const { dir, metadata, skill } = this.paths("candidate", id);
|
|
34596
|
-
if (
|
|
34670
|
+
if (existsSync26(metadata)) {
|
|
34597
34671
|
throw new SkillLifecycleError(
|
|
34598
34672
|
"skill_candidate_exists",
|
|
34599
34673
|
`identical candidate ${id} already exists; changed behavior requires changed content`
|
|
@@ -34612,9 +34686,9 @@ var SkillLifecycle = class {
|
|
|
34612
34686
|
createdAt: this.now(),
|
|
34613
34687
|
...input.supersedes ? { supersedes: input.supersedes } : {}
|
|
34614
34688
|
};
|
|
34615
|
-
|
|
34616
|
-
|
|
34617
|
-
|
|
34689
|
+
mkdirSync21(dir, { recursive: true });
|
|
34690
|
+
writeFileSync20(skill, content);
|
|
34691
|
+
writeFileSync20(metadata, `${JSON.stringify(record, null, 2)}
|
|
34618
34692
|
`);
|
|
34619
34693
|
this.appendHistory(id, { schema: "kxm.skill-history-event.v1", event: "candidate_created", by: createdBy, supersedes: input.supersedes, at: record.createdAt });
|
|
34620
34694
|
return record;
|
|
@@ -34703,18 +34777,18 @@ var SkillLifecycle = class {
|
|
|
34703
34777
|
};
|
|
34704
34778
|
const candidatePaths = this.paths("candidate", candidateId);
|
|
34705
34779
|
const promotedPaths = this.paths("promoted", candidateId);
|
|
34706
|
-
|
|
34707
|
-
const skillContent =
|
|
34708
|
-
const metadataContent =
|
|
34709
|
-
|
|
34710
|
-
|
|
34711
|
-
const patchesDir =
|
|
34712
|
-
|
|
34713
|
-
const patchPath =
|
|
34780
|
+
mkdirSync21(promotedPaths.dir, { recursive: true });
|
|
34781
|
+
const skillContent = readFileSync25(candidatePaths.skill, "utf8");
|
|
34782
|
+
const metadataContent = readFileSync25(candidatePaths.metadata, "utf8");
|
|
34783
|
+
writeFileSync20(promotedPaths.skill, skillContent);
|
|
34784
|
+
writeFileSync20(promotedPaths.metadata, metadataContent);
|
|
34785
|
+
const patchesDir = join30(this.root, "patches");
|
|
34786
|
+
mkdirSync21(patchesDir, { recursive: true });
|
|
34787
|
+
const patchPath = join30(patchesDir, `${candidateId}.patch`);
|
|
34714
34788
|
const relSkillPath = `.kxm/skills/promoted/${candidateId}/SKILL.md`;
|
|
34715
34789
|
const relMetaPath = `.kxm/skills/promoted/${candidateId}/metadata.json`;
|
|
34716
34790
|
const patch = `${createUnifiedPatch(relSkillPath, skillContent)}${createUnifiedPatch(relMetaPath, metadataContent)}`;
|
|
34717
|
-
|
|
34791
|
+
writeFileSync20(patchPath, patch, "utf8");
|
|
34718
34792
|
this.appendHistory(candidateId, record);
|
|
34719
34793
|
return { ...metadata, patch, patchPath };
|
|
34720
34794
|
}
|
|
@@ -34738,7 +34812,7 @@ var SkillLifecycle = class {
|
|
|
34738
34812
|
verify(state, id) {
|
|
34739
34813
|
const metadata = this.readMetadata(state, id);
|
|
34740
34814
|
const { skill } = this.paths(state, id);
|
|
34741
|
-
const content =
|
|
34815
|
+
const content = readFileSync25(skill, "utf8");
|
|
34742
34816
|
if (skillContentSha256(content) !== metadata.contentSha256) {
|
|
34743
34817
|
throw new SkillLifecycleError(
|
|
34744
34818
|
"skill_integrity_violation",
|
|
@@ -34756,7 +34830,7 @@ var SkillLifecycle = class {
|
|
|
34756
34830
|
}
|
|
34757
34831
|
list(state) {
|
|
34758
34832
|
const dir = this.dir(state);
|
|
34759
|
-
if (!
|
|
34833
|
+
if (!existsSync26(dir)) return [];
|
|
34760
34834
|
const ids = readdirSorted(dir);
|
|
34761
34835
|
return ids.map((id) => {
|
|
34762
34836
|
try {
|
|
@@ -34769,7 +34843,7 @@ var SkillLifecycle = class {
|
|
|
34769
34843
|
read(state, id) {
|
|
34770
34844
|
const metadata = this.readMetadata(state, id);
|
|
34771
34845
|
const { skill } = this.paths(state, id);
|
|
34772
|
-
return { metadata, content:
|
|
34846
|
+
return { metadata, content: readFileSync25(skill, "utf8") };
|
|
34773
34847
|
}
|
|
34774
34848
|
};
|
|
34775
34849
|
function boundedList(value, field) {
|
|
@@ -34784,18 +34858,18 @@ function boundedList(value, field) {
|
|
|
34784
34858
|
return [...new Set(refs)];
|
|
34785
34859
|
}
|
|
34786
34860
|
function readdirSorted(dir) {
|
|
34787
|
-
return readdirSync10(dir).filter((entry) => statSync3(
|
|
34861
|
+
return readdirSync10(dir).filter((entry) => statSync3(join30(dir, entry)).isDirectory()).sort();
|
|
34788
34862
|
}
|
|
34789
34863
|
|
|
34790
34864
|
// plugins/kxm/src/wiki.ts
|
|
34791
|
-
import { mkdirSync as
|
|
34792
|
-
import { join as
|
|
34865
|
+
import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync21 } from "node:fs";
|
|
34866
|
+
import { join as join31 } from "node:path";
|
|
34793
34867
|
function writeCompiledWiki(root, wiki) {
|
|
34794
34868
|
const written = [];
|
|
34795
34869
|
for (const [relativePath, content] of [...wiki.pages].sort(([left], [right]) => left.localeCompare(right))) {
|
|
34796
|
-
const absolute =
|
|
34797
|
-
|
|
34798
|
-
|
|
34870
|
+
const absolute = join31(root, relativePath);
|
|
34871
|
+
mkdirSync22(absolute.slice(0, absolute.lastIndexOf("/")), { recursive: true });
|
|
34872
|
+
writeFileSync21(absolute, content);
|
|
34799
34873
|
written.push(relativePath);
|
|
34800
34874
|
}
|
|
34801
34875
|
return written;
|
|
@@ -34961,7 +35035,7 @@ function skillStateFromFlag(value) {
|
|
|
34961
35035
|
throw new Error(`invalid skill state ${value}`);
|
|
34962
35036
|
}
|
|
34963
35037
|
function skillsRoot(runtime) {
|
|
34964
|
-
return
|
|
35038
|
+
return join32(runtime.dirs.workdir, ".kxm", "skills");
|
|
34965
35039
|
}
|
|
34966
35040
|
function csv(value) {
|
|
34967
35041
|
if (!value) return void 0;
|
|
@@ -34978,7 +35052,7 @@ async function cmdSkillsCreate(runtime, options) {
|
|
|
34978
35052
|
const metadata = lifecycle.create({
|
|
34979
35053
|
name: options.name,
|
|
34980
35054
|
description: options.description ?? "",
|
|
34981
|
-
content:
|
|
35055
|
+
content: readFileSync26(options.file, "utf8"),
|
|
34982
35056
|
createdBy: options.createdBy,
|
|
34983
35057
|
sources: {
|
|
34984
35058
|
runIds: csv(options.run) ?? [],
|
|
@@ -35136,8 +35210,8 @@ async function cmdMemorySync(runtime) {
|
|
|
35136
35210
|
|
|
35137
35211
|
// plugins/kxm/src/cli/hub.ts
|
|
35138
35212
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
35139
|
-
import { existsSync as
|
|
35140
|
-
import { join as
|
|
35213
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync26, readFileSync as readFileSync32, readdirSync as readdirSync12, rmSync as rmSync11, writeFileSync as writeFileSync24 } from "node:fs";
|
|
35214
|
+
import { join as join42, resolve as resolve25 } from "node:path";
|
|
35141
35215
|
|
|
35142
35216
|
// node_modules/marked/lib/marked.esm.js
|
|
35143
35217
|
function M() {
|
|
@@ -39299,10 +39373,10 @@ var TuiBase = class _TuiBase extends Container {
|
|
|
39299
39373
|
* @returns Promise containing the parsed RGB color, or undefined if it times out or fails to parse.
|
|
39300
39374
|
*/
|
|
39301
39375
|
queryTerminalBackgroundColor({ timeoutMs }) {
|
|
39302
|
-
return new Promise((
|
|
39376
|
+
return new Promise((resolve31) => {
|
|
39303
39377
|
const query = {
|
|
39304
39378
|
settled: false,
|
|
39305
|
-
resolve:
|
|
39379
|
+
resolve: resolve31,
|
|
39306
39380
|
timer: void 0
|
|
39307
39381
|
};
|
|
39308
39382
|
query.timer = setTimeout(() => {
|
|
@@ -39325,7 +39399,7 @@ var TuiBase = class _TuiBase extends Container {
|
|
|
39325
39399
|
* `CSI ? 997 ; 1 n` for dark or `CSI ? 997 ; 2 n` for light.
|
|
39326
39400
|
*/
|
|
39327
39401
|
queryTerminalColorScheme({ timeoutMs }) {
|
|
39328
|
-
return new Promise((
|
|
39402
|
+
return new Promise((resolve31) => {
|
|
39329
39403
|
let settled = false;
|
|
39330
39404
|
let timer;
|
|
39331
39405
|
let unsubscribe = () => {
|
|
@@ -39339,7 +39413,7 @@ var TuiBase = class _TuiBase extends Container {
|
|
|
39339
39413
|
timer = void 0;
|
|
39340
39414
|
}
|
|
39341
39415
|
unsubscribe();
|
|
39342
|
-
|
|
39416
|
+
resolve31(scheme);
|
|
39343
39417
|
};
|
|
39344
39418
|
unsubscribe = this.onTerminalColorSchemeChange(settle);
|
|
39345
39419
|
timer = setTimeout(() => settle(void 0), timeoutMs);
|
|
@@ -41070,19 +41144,19 @@ import * as path2 from "node:path";
|
|
|
41070
41144
|
|
|
41071
41145
|
// node_modules/@earendil-works/pi-tui/dist/native-module-path.js
|
|
41072
41146
|
import { createRequire as createRequire2 } from "node:module";
|
|
41073
|
-
import { dirname as
|
|
41147
|
+
import { dirname as dirname17, join as join33 } from "node:path";
|
|
41074
41148
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
41075
41149
|
var moduleRequire = createRequire2(import.meta.url);
|
|
41076
41150
|
var TUI_PACKAGE_NAME = "@earendil-works/pi-tui";
|
|
41077
41151
|
function getNativeModuleCandidates(nativePath, options = {}) {
|
|
41078
|
-
const moduleDir =
|
|
41152
|
+
const moduleDir = dirname17(fileURLToPath2(options.moduleUrl ?? import.meta.url));
|
|
41079
41153
|
const candidates = [];
|
|
41080
41154
|
try {
|
|
41081
41155
|
const packageEntry = (options.resolvePackage ?? moduleRequire.resolve)(TUI_PACKAGE_NAME);
|
|
41082
|
-
candidates.push(
|
|
41156
|
+
candidates.push(join33(dirname17(packageEntry), "..", nativePath));
|
|
41083
41157
|
} catch {
|
|
41084
41158
|
}
|
|
41085
|
-
candidates.push(
|
|
41159
|
+
candidates.push(join33(moduleDir, "..", nativePath), join33(moduleDir, nativePath), join33(dirname17(options.execPath ?? process.execPath), nativePath));
|
|
41086
41160
|
return Array.from(new Set(candidates));
|
|
41087
41161
|
}
|
|
41088
41162
|
|
|
@@ -41423,7 +41497,7 @@ var ProcessTerminal = class {
|
|
|
41423
41497
|
break;
|
|
41424
41498
|
if (now - lastDataTime >= idleMs)
|
|
41425
41499
|
break;
|
|
41426
|
-
await new Promise((
|
|
41500
|
+
await new Promise((resolve31) => setTimeout(resolve31, Math.min(idleMs, timeLeft)));
|
|
41427
41501
|
}
|
|
41428
41502
|
} finally {
|
|
41429
41503
|
process.stdin.removeListener("data", onData);
|
|
@@ -43538,8 +43612,8 @@ var TuiAltScreen = class extends TuiBase {
|
|
|
43538
43612
|
var MAX_RENDER_WRITE_CHARS = 1024 * 1024;
|
|
43539
43613
|
|
|
43540
43614
|
// plugins/kxm/src/tui.ts
|
|
43541
|
-
import { mkdirSync as
|
|
43542
|
-
import { join as
|
|
43615
|
+
import { mkdirSync as mkdirSync23 } from "node:fs";
|
|
43616
|
+
import { join as join37, resolve as resolve24, dirname as dirname18 } from "node:path";
|
|
43543
43617
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
43544
43618
|
|
|
43545
43619
|
// plugins/kxm/src/external-effects.ts
|
|
@@ -43550,9 +43624,9 @@ function slugifyBranchPart(text, maxLength = 40) {
|
|
|
43550
43624
|
}
|
|
43551
43625
|
|
|
43552
43626
|
// plugins/kxm/src/local-snapshot.ts
|
|
43553
|
-
import { existsSync as
|
|
43554
|
-
import { homedir as
|
|
43555
|
-
import { isAbsolute as
|
|
43627
|
+
import { existsSync as existsSync27, readdirSync as readdirSync11, readFileSync as readFileSync27 } from "node:fs";
|
|
43628
|
+
import { homedir as homedir6 } from "node:os";
|
|
43629
|
+
import { isAbsolute as isAbsolute8, join as join36, resolve as resolve23 } from "node:path";
|
|
43556
43630
|
function processExists2(pid) {
|
|
43557
43631
|
try {
|
|
43558
43632
|
process.kill(pid, 0);
|
|
@@ -43672,36 +43746,36 @@ function readOpenMessageMetadata(database) {
|
|
|
43672
43746
|
return messages;
|
|
43673
43747
|
}
|
|
43674
43748
|
function resolveKxmSnapshotPaths(cwd, env = process.env) {
|
|
43675
|
-
const stateDir = env.KXM_STATE_DIR?.trim() ||
|
|
43749
|
+
const stateDir = env.KXM_STATE_DIR?.trim() || join36(cwd, ".kxm", "state");
|
|
43676
43750
|
const configured = env.KXM_DATA_PATH?.trim();
|
|
43677
|
-
const dataPath = configured ?
|
|
43751
|
+
const dataPath = configured ? resolve23(cwd, configured) : join36(stateDir, "kxm.db");
|
|
43678
43752
|
return { dataPath, stateDir };
|
|
43679
43753
|
}
|
|
43680
43754
|
function resolveVnextStateRoot(stateDir, options) {
|
|
43681
|
-
if (options?.vnextStateRoot &&
|
|
43682
|
-
return
|
|
43755
|
+
if (options?.vnextStateRoot && existsSync27(options.vnextStateRoot)) {
|
|
43756
|
+
return resolve23(options.vnextStateRoot);
|
|
43683
43757
|
}
|
|
43684
|
-
if (
|
|
43758
|
+
if (existsSync27(join36(stateDir, "runtime", "registry.db")) || existsSync27(join36(stateDir, "runtime", "projects"))) {
|
|
43685
43759
|
return stateDir;
|
|
43686
43760
|
}
|
|
43687
43761
|
const env = options?.env ?? process.env;
|
|
43688
43762
|
const explicit = env.KXM_STATE_HOME?.trim() || env.KXM_USER_STATE_DIR?.trim() || env.KXM_STATE_ROOT?.trim();
|
|
43689
|
-
if (explicit &&
|
|
43690
|
-
return
|
|
43763
|
+
if (explicit && isAbsolute8(explicit) && existsSync27(resolve23(explicit))) {
|
|
43764
|
+
return resolve23(explicit);
|
|
43691
43765
|
}
|
|
43692
43766
|
let base;
|
|
43693
43767
|
if (process.platform === "win32") {
|
|
43694
43768
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
43695
|
-
base = localAppData &&
|
|
43696
|
-
base =
|
|
43769
|
+
base = localAppData && isAbsolute8(localAppData) ? localAppData : join36(homedir6(), "AppData", "Local");
|
|
43770
|
+
base = resolve23(base, "KXM");
|
|
43697
43771
|
} else if (process.platform === "darwin") {
|
|
43698
|
-
base =
|
|
43772
|
+
base = resolve23(homedir6(), "Library", "Application Support", "KXM");
|
|
43699
43773
|
} else {
|
|
43700
43774
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
43701
|
-
base = xdgState &&
|
|
43702
|
-
base =
|
|
43775
|
+
base = xdgState && isAbsolute8(xdgState) ? xdgState : join36(homedir6(), ".local", "state");
|
|
43776
|
+
base = resolve23(base, "kxm");
|
|
43703
43777
|
}
|
|
43704
|
-
if (
|
|
43778
|
+
if (existsSync27(base)) return base;
|
|
43705
43779
|
return void 0;
|
|
43706
43780
|
}
|
|
43707
43781
|
function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
@@ -43712,7 +43786,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43712
43786
|
let legacyRuns = [];
|
|
43713
43787
|
let legacyRunTotal = 0;
|
|
43714
43788
|
let plans = [];
|
|
43715
|
-
if (
|
|
43789
|
+
if (existsSync27(dataPath)) {
|
|
43716
43790
|
hasLegacy = true;
|
|
43717
43791
|
const database = new DatabaseSync(dataPath, { readOnly: true });
|
|
43718
43792
|
try {
|
|
@@ -43732,11 +43806,11 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43732
43806
|
let vnextRunTotal = 0;
|
|
43733
43807
|
const vnextStateRoot = resolveVnextStateRoot(stateDir, options);
|
|
43734
43808
|
if (vnextStateRoot) {
|
|
43735
|
-
const runtimeDir =
|
|
43736
|
-
const registryDbPath =
|
|
43737
|
-
const projectsDir =
|
|
43809
|
+
const runtimeDir = join36(vnextStateRoot, "runtime");
|
|
43810
|
+
const registryDbPath = join36(runtimeDir, "registry.db");
|
|
43811
|
+
const projectsDir = join36(runtimeDir, "projects");
|
|
43738
43812
|
const projectKeys = /* @__PURE__ */ new Set();
|
|
43739
|
-
if (
|
|
43813
|
+
if (existsSync27(registryDbPath)) {
|
|
43740
43814
|
hasVnext = true;
|
|
43741
43815
|
try {
|
|
43742
43816
|
const regDb = new DatabaseSync(registryDbPath, { readOnly: true });
|
|
@@ -43752,7 +43826,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43752
43826
|
} catch {
|
|
43753
43827
|
}
|
|
43754
43828
|
}
|
|
43755
|
-
if (
|
|
43829
|
+
if (existsSync27(projectsDir)) {
|
|
43756
43830
|
try {
|
|
43757
43831
|
for (const entry of readdirSync11(projectsDir, { withFileTypes: true })) {
|
|
43758
43832
|
if (entry.isDirectory()) {
|
|
@@ -43763,8 +43837,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43763
43837
|
}
|
|
43764
43838
|
}
|
|
43765
43839
|
for (const key of projectKeys) {
|
|
43766
|
-
const eventDbPath =
|
|
43767
|
-
if (
|
|
43840
|
+
const eventDbPath = join36(projectsDir, key, "run-events.db");
|
|
43841
|
+
if (existsSync27(eventDbPath)) {
|
|
43768
43842
|
hasVnext = true;
|
|
43769
43843
|
try {
|
|
43770
43844
|
const eventDb = new DatabaseSync(eventDbPath, { readOnly: true });
|
|
@@ -43794,10 +43868,10 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43794
43868
|
}
|
|
43795
43869
|
}
|
|
43796
43870
|
const pids = [];
|
|
43797
|
-
if (
|
|
43871
|
+
if (existsSync27(stateDir)) {
|
|
43798
43872
|
for (const file of readdirSync11(stateDir).filter((name) => name.endsWith(".pid"))) {
|
|
43799
43873
|
try {
|
|
43800
|
-
const record = JSON.parse(
|
|
43874
|
+
const record = JSON.parse(readFileSync27(join36(stateDir, file), "utf8"));
|
|
43801
43875
|
pids.push({
|
|
43802
43876
|
file,
|
|
43803
43877
|
...record.role ? { role: record.role } : {},
|
|
@@ -43836,8 +43910,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43836
43910
|
} else {
|
|
43837
43911
|
source = "legacy";
|
|
43838
43912
|
}
|
|
43839
|
-
const telemetryFile =
|
|
43840
|
-
const spend =
|
|
43913
|
+
const telemetryFile = join36(stateDir, "telemetry.jsonl");
|
|
43914
|
+
const spend = existsSync27(telemetryFile) ? readRoutingRecords(telemetryFile) : [];
|
|
43841
43915
|
return {
|
|
43842
43916
|
source,
|
|
43843
43917
|
agents: agents.sort((a, b2) => Number(b2.online) - Number(a.online) || a.name.localeCompare(b2.name)),
|
|
@@ -43971,11 +44045,11 @@ function spawnDegradeWorktree(repoRoot, runId, options) {
|
|
|
43971
44045
|
const cleanRunId = runId.replace(/^run_/, "");
|
|
43972
44046
|
const desc = options?.description ? slugifyBranchPart(options.description, 30) : "degrade";
|
|
43973
44047
|
const branchName = `kxm/run-${cleanRunId}-${desc}`;
|
|
43974
|
-
const relativeWtPath =
|
|
43975
|
-
const absoluteWtPath =
|
|
44048
|
+
const relativeWtPath = join37(".kxm", "worktrees", `run-${cleanRunId}-${desc}`);
|
|
44049
|
+
const absoluteWtPath = resolve24(repoRoot, relativeWtPath);
|
|
43976
44050
|
const jumpCommand = `cd "${absoluteWtPath}"`;
|
|
43977
44051
|
try {
|
|
43978
|
-
|
|
44052
|
+
mkdirSync23(dirname18(absoluteWtPath), { recursive: true });
|
|
43979
44053
|
const branchCheck = runner("git", ["rev-parse", "--verify", `refs/heads/${branchName}`]);
|
|
43980
44054
|
let wtRes;
|
|
43981
44055
|
if (branchCheck.status === 0) {
|
|
@@ -44374,11 +44448,11 @@ async function readJson(response) {
|
|
|
44374
44448
|
}
|
|
44375
44449
|
async function waitForReconnect(signal, milliseconds = 1e3) {
|
|
44376
44450
|
if (signal.aborted) return;
|
|
44377
|
-
await new Promise((
|
|
44451
|
+
await new Promise((resolve31) => {
|
|
44378
44452
|
const done = () => {
|
|
44379
44453
|
clearTimeout(timer);
|
|
44380
44454
|
signal.removeEventListener("abort", done);
|
|
44381
|
-
|
|
44455
|
+
resolve31();
|
|
44382
44456
|
};
|
|
44383
44457
|
const timer = setTimeout(done, milliseconds);
|
|
44384
44458
|
timer.unref();
|
|
@@ -44741,8 +44815,8 @@ async function runMeshTui(input) {
|
|
|
44741
44815
|
// plugins/kxm/src/session-work.ts
|
|
44742
44816
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
44743
44817
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
44744
|
-
import { existsSync as
|
|
44745
|
-
import { join as
|
|
44818
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync24, readFileSync as readFileSync28, renameSync as renameSync9, writeFileSync as writeFileSync22 } from "node:fs";
|
|
44819
|
+
import { join as join38 } from "node:path";
|
|
44746
44820
|
var MAX_SESSION_BRIEF_TASKS = 5;
|
|
44747
44821
|
var MAX_SESSION_BRIEF_PLANS = 5;
|
|
44748
44822
|
var SESSION_BRIEF_SCHEMA = "kxm.session-brief.v1";
|
|
@@ -44898,10 +44972,10 @@ function buildSessionBrief(snapshot, current, hub, ship, updateLatest, cost, ses
|
|
|
44898
44972
|
};
|
|
44899
44973
|
}
|
|
44900
44974
|
function readCachedSessionBrief(stateDir) {
|
|
44901
|
-
const file =
|
|
44975
|
+
const file = join38(stateDir, "session-brief.json");
|
|
44902
44976
|
try {
|
|
44903
|
-
if (!
|
|
44904
|
-
const raw =
|
|
44977
|
+
if (!existsSync28(file)) return void 0;
|
|
44978
|
+
const raw = readFileSync28(file, "utf8");
|
|
44905
44979
|
const parsed = JSON.parse(raw);
|
|
44906
44980
|
if (parsed && parsed.schema === "kxm.session-brief.v1" && typeof parsed.generatedAt === "string") {
|
|
44907
44981
|
const ageMs = Date.now() - Date.parse(parsed.generatedAt);
|
|
@@ -44916,18 +44990,18 @@ function readCachedSessionBrief(stateDir) {
|
|
|
44916
44990
|
}
|
|
44917
44991
|
function writeCachedSessionBrief(stateDir, brief) {
|
|
44918
44992
|
try {
|
|
44919
|
-
|
|
44920
|
-
const file =
|
|
44993
|
+
mkdirSync24(stateDir, { recursive: true, mode: 448 });
|
|
44994
|
+
const file = join38(stateDir, "session-brief.json");
|
|
44921
44995
|
const tmp = `${file}.tmp.${randomUUID13().slice(0, 8)}`;
|
|
44922
|
-
|
|
44923
|
-
|
|
44996
|
+
writeFileSync22(tmp, JSON.stringify(brief, null, 2), { encoding: "utf8", mode: 384 });
|
|
44997
|
+
renameSync9(tmp, file);
|
|
44924
44998
|
} catch {
|
|
44925
44999
|
}
|
|
44926
45000
|
}
|
|
44927
45001
|
function estimateSessionCost(stateDir) {
|
|
44928
45002
|
try {
|
|
44929
|
-
const telemetryFile =
|
|
44930
|
-
if (!
|
|
45003
|
+
const telemetryFile = join38(stateDir, "telemetry.jsonl");
|
|
45004
|
+
if (!existsSync28(telemetryFile)) return void 0;
|
|
44931
45005
|
const records = readRoutingRecords(telemetryFile);
|
|
44932
45006
|
if (records.length === 0) return void 0;
|
|
44933
45007
|
let totalCost = 0;
|
|
@@ -45095,11 +45169,11 @@ function formatSessionBriefText(brief) {
|
|
|
45095
45169
|
}
|
|
45096
45170
|
|
|
45097
45171
|
// plugins/kxm/src/kxm-install-kind.ts
|
|
45098
|
-
import { existsSync as
|
|
45099
|
-
import { dirname as
|
|
45172
|
+
import { existsSync as existsSync29, readFileSync as readFileSync29 } from "node:fs";
|
|
45173
|
+
import { dirname as dirname19, join as join39 } from "node:path";
|
|
45100
45174
|
function packageIsKxm(root) {
|
|
45101
45175
|
try {
|
|
45102
|
-
const pkg = JSON.parse(
|
|
45176
|
+
const pkg = JSON.parse(readFileSync29(join39(root, "package.json"), "utf8"));
|
|
45103
45177
|
return pkg.name === "@kontextmind/kxm";
|
|
45104
45178
|
} catch {
|
|
45105
45179
|
return false;
|
|
@@ -45148,12 +45222,12 @@ function report(kind, root) {
|
|
|
45148
45222
|
return { kind, root, instruction: installKindInstruction(kind, root) };
|
|
45149
45223
|
}
|
|
45150
45224
|
function classifyInstallRoot(probe) {
|
|
45151
|
-
const piGitRoot =
|
|
45225
|
+
const piGitRoot = join39(probe.homeDir, ".pi", "agent", "git");
|
|
45152
45226
|
if (isUnder(probe.repoRoot, piGitRoot, probe.platform)) return report("pi-git", probe.repoRoot);
|
|
45153
|
-
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() ||
|
|
45154
|
-
const pluginsRoot =
|
|
45227
|
+
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() || join39(probe.homeDir, ".claude");
|
|
45228
|
+
const pluginsRoot = join39(claudeHome, "plugins");
|
|
45155
45229
|
if (isUnder(probe.moduleDir, pluginsRoot, probe.platform)) return report("claude-marketplace", probe.moduleDir);
|
|
45156
|
-
const hasGit =
|
|
45230
|
+
const hasGit = existsSync29(join39(probe.repoRoot, ".git"));
|
|
45157
45231
|
if (hasGit && packageIsKxm(probe.repoRoot)) return report("source", probe.repoRoot);
|
|
45158
45232
|
if (isNpmPackageLayout(probe.repoRoot, probe.platform) && packageIsKxm(probe.repoRoot) && !hasGit) {
|
|
45159
45233
|
return report("npm-package", probe.repoRoot);
|
|
@@ -45167,21 +45241,21 @@ function resolveInstallKind(probe, npmGlobalRoot) {
|
|
|
45167
45241
|
if (typeof globalRoot !== "string" || globalRoot.trim() === "") {
|
|
45168
45242
|
return report("unknown", classified.root);
|
|
45169
45243
|
}
|
|
45170
|
-
const expected =
|
|
45244
|
+
const expected = dirname19(dirname19(classified.root));
|
|
45171
45245
|
if (sameHostPath2(globalRoot.trim(), expected, probe.platform)) return report("npm-global", classified.root);
|
|
45172
45246
|
return report("npm-local", classified.root);
|
|
45173
45247
|
}
|
|
45174
45248
|
|
|
45175
45249
|
// plugins/kxm/src/kxm-update-config.ts
|
|
45176
45250
|
var import_yaml16 = __toESM(require_dist(), 1);
|
|
45177
|
-
import { existsSync as
|
|
45178
|
-
import { join as
|
|
45251
|
+
import { existsSync as existsSync30, readFileSync as readFileSync30 } from "node:fs";
|
|
45252
|
+
import { join as join40 } from "node:path";
|
|
45179
45253
|
function loadKxmUpdateConfig(env = process.env) {
|
|
45180
|
-
const path4 =
|
|
45181
|
-
if (!
|
|
45254
|
+
const path4 = join40(vnextUserStateRoot({ env }), "update.yaml");
|
|
45255
|
+
if (!existsSync30(path4)) return { schema: KXM_UPDATE_SCHEMA, auto: false, source: "github" };
|
|
45182
45256
|
let parsed;
|
|
45183
45257
|
try {
|
|
45184
|
-
parsed = (0, import_yaml16.parse)(
|
|
45258
|
+
parsed = (0, import_yaml16.parse)(readFileSync30(path4, "utf8"));
|
|
45185
45259
|
} catch {
|
|
45186
45260
|
throw new KxmUpdateConfigError("update.yaml is not valid YAML");
|
|
45187
45261
|
}
|
|
@@ -45207,8 +45281,8 @@ function loadKxmUpdateConfig(env = process.env) {
|
|
|
45207
45281
|
}
|
|
45208
45282
|
|
|
45209
45283
|
// plugins/kxm/src/session.ts
|
|
45210
|
-
import { existsSync as
|
|
45211
|
-
import { join as
|
|
45284
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync25, readFileSync as readFileSync31, writeFileSync as writeFileSync23 } from "node:fs";
|
|
45285
|
+
import { join as join41 } from "node:path";
|
|
45212
45286
|
var SESSION_SCHEMA = "kxm.session.v1";
|
|
45213
45287
|
var SessionConfigError = class extends Error {
|
|
45214
45288
|
code = "session_config_invalid";
|
|
@@ -45218,12 +45292,12 @@ var SessionConfigError = class extends Error {
|
|
|
45218
45292
|
}
|
|
45219
45293
|
};
|
|
45220
45294
|
function workflowAssetDirs(assetsDir, workflowId) {
|
|
45221
|
-
const root =
|
|
45222
|
-
return [root,
|
|
45295
|
+
const root = join41(assetsDir, "workflows", workflowId);
|
|
45296
|
+
return [root, join41(root, "inputs"), join41(root, "outputs"), join41(root, "generated")];
|
|
45223
45297
|
}
|
|
45224
45298
|
function sessionAssetDirs(assetsDir, sessionId) {
|
|
45225
|
-
const root =
|
|
45226
|
-
return [root,
|
|
45299
|
+
const root = join41(assetsDir, "sessions", sessionId);
|
|
45300
|
+
return [root, join41(root, "inputs"), join41(root, "outputs")];
|
|
45227
45301
|
}
|
|
45228
45302
|
function rosterNames(configDir) {
|
|
45229
45303
|
return [...loadRosterMap(configDir).values()].map((row) => String(row.name));
|
|
@@ -45273,7 +45347,7 @@ function workerFromRosterRow(name, row, project) {
|
|
|
45273
45347
|
function loadRosterMap(configDir) {
|
|
45274
45348
|
const byName = /* @__PURE__ */ new Map();
|
|
45275
45349
|
for (const [file, key] of [["agents.json", "agents"], ["gates.json", "gates"]]) {
|
|
45276
|
-
const path4 =
|
|
45350
|
+
const path4 = join41(configDir, file);
|
|
45277
45351
|
for (const row of loadRoster(path4, key)) {
|
|
45278
45352
|
const name = String(row.name).trim();
|
|
45279
45353
|
const lowered = name.toLowerCase();
|
|
@@ -45287,10 +45361,10 @@ function loadRosterMap(configDir) {
|
|
|
45287
45361
|
return byName;
|
|
45288
45362
|
}
|
|
45289
45363
|
function loadRoster(path4, key) {
|
|
45290
|
-
if (!
|
|
45364
|
+
if (!existsSync31(path4)) return [];
|
|
45291
45365
|
let parsed;
|
|
45292
45366
|
try {
|
|
45293
|
-
parsed = JSON.parse(
|
|
45367
|
+
parsed = JSON.parse(readFileSync31(path4, "utf8"));
|
|
45294
45368
|
} catch (error) {
|
|
45295
45369
|
throw new SessionConfigError(
|
|
45296
45370
|
`${key} roster at ${path4} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -45315,7 +45389,7 @@ function loadRoster(path4, key) {
|
|
|
45315
45389
|
});
|
|
45316
45390
|
}
|
|
45317
45391
|
function createSession(input) {
|
|
45318
|
-
const assetDir = input.mode === "workflow" && input.workflowId ?
|
|
45392
|
+
const assetDir = input.mode === "workflow" && input.workflowId ? join41("assets", "workflows", input.workflowId) : join41("assets", "sessions", input.id);
|
|
45319
45393
|
return {
|
|
45320
45394
|
schema: SESSION_SCHEMA,
|
|
45321
45395
|
id: input.id,
|
|
@@ -45328,11 +45402,11 @@ function createSession(input) {
|
|
|
45328
45402
|
};
|
|
45329
45403
|
}
|
|
45330
45404
|
function writeSession(assetsDir, session, dryRun = false) {
|
|
45331
|
-
const dir =
|
|
45332
|
-
const path4 =
|
|
45405
|
+
const dir = join41(assetsDir, "sessions", session.id);
|
|
45406
|
+
const path4 = join41(dir, "session.json");
|
|
45333
45407
|
if (!dryRun) {
|
|
45334
|
-
|
|
45335
|
-
|
|
45408
|
+
mkdirSync25(dir, { recursive: true });
|
|
45409
|
+
writeFileSync23(path4, `${JSON.stringify(session, null, 2)}
|
|
45336
45410
|
`, { encoding: "utf8" });
|
|
45337
45411
|
}
|
|
45338
45412
|
return path4;
|
|
@@ -45340,8 +45414,8 @@ function writeSession(assetsDir, session, dryRun = false) {
|
|
|
45340
45414
|
|
|
45341
45415
|
// plugins/kxm/src/cli/hub.ts
|
|
45342
45416
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
45343
|
-
import { dirname as
|
|
45344
|
-
import { homedir as
|
|
45417
|
+
import { dirname as dirname20 } from "node:path";
|
|
45418
|
+
import { homedir as homedir7 } from "node:os";
|
|
45345
45419
|
async function hubGet(url, fetchImpl) {
|
|
45346
45420
|
try {
|
|
45347
45421
|
const response = await fetchImpl(url);
|
|
@@ -45359,23 +45433,23 @@ async function hubGet(url, fetchImpl) {
|
|
|
45359
45433
|
function installProbeFrom(runtime) {
|
|
45360
45434
|
const partial = runtime.io.installProbe ?? {};
|
|
45361
45435
|
return {
|
|
45362
|
-
moduleDir: partial.moduleDir ??
|
|
45363
|
-
repoRoot: partial.repoRoot ??
|
|
45364
|
-
homeDir: partial.homeDir ??
|
|
45436
|
+
moduleDir: partial.moduleDir ?? dirname20(fileURLToPath3(import.meta.url)),
|
|
45437
|
+
repoRoot: partial.repoRoot ?? resolve25("."),
|
|
45438
|
+
homeDir: partial.homeDir ?? homedir7(),
|
|
45365
45439
|
platform: partial.platform ?? process.platform,
|
|
45366
45440
|
env: partial.env ?? runtime.env
|
|
45367
45441
|
};
|
|
45368
45442
|
}
|
|
45369
45443
|
function warnIgnoredProjectUpdateYaml(runtime) {
|
|
45370
|
-
const projectFile =
|
|
45371
|
-
if (!
|
|
45372
|
-
const userFile =
|
|
45444
|
+
const projectFile = join42(runtime.dirs.workspace, "update.yaml");
|
|
45445
|
+
if (!existsSync32(projectFile)) return;
|
|
45446
|
+
const userFile = join42(vnextUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
45373
45447
|
runtime.io.stderr(`kxm: ignoring .kxm/update.yaml in ${runtime.dirs.workdir}; update settings are read only from ${userFile}
|
|
45374
45448
|
`);
|
|
45375
45449
|
}
|
|
45376
45450
|
async function refreshKxmUpdateNotice(runtime, config) {
|
|
45377
45451
|
const resolved = config ?? loadKxmUpdateConfig(runtime.env);
|
|
45378
|
-
const current = readInstalledKxmVersion(
|
|
45452
|
+
const current = readInstalledKxmVersion(resolve25("."));
|
|
45379
45453
|
const fetched = await fetchLatestKxmVersion(resolved.source, runtime.env, runtime.fetchImpl);
|
|
45380
45454
|
const notice = noticeFromVersions(current, fetched.latest, resolved, fetched.error, fetched.asset);
|
|
45381
45455
|
writeUpdateCache(runtime.dirs.state, notice);
|
|
@@ -45395,7 +45469,7 @@ async function cmdDash(runtime, options = {}) {
|
|
|
45395
45469
|
return 2;
|
|
45396
45470
|
}
|
|
45397
45471
|
const screen = requested;
|
|
45398
|
-
const dataPath =
|
|
45472
|
+
const dataPath = resolve25(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join42(runtime.dirs.state, "kxm.db"));
|
|
45399
45473
|
if (runtime.dryRun) {
|
|
45400
45474
|
print(runtime.io, runtime.json, {
|
|
45401
45475
|
ok: true,
|
|
@@ -45412,7 +45486,7 @@ async function cmdDash(runtime, options = {}) {
|
|
|
45412
45486
|
return 2;
|
|
45413
45487
|
}
|
|
45414
45488
|
const project = defaultProjectName(runtime.dirs.workdir, runtime.env) || "project";
|
|
45415
|
-
const authToken = runtime.env
|
|
45489
|
+
const authToken = resolveClientHubAuthToken(runtime.env, project);
|
|
45416
45490
|
return await runMeshTui({
|
|
45417
45491
|
serverUrl: runtime.serverUrl,
|
|
45418
45492
|
dataPath,
|
|
@@ -45441,7 +45515,7 @@ async function cmdHub(runtime) {
|
|
|
45441
45515
|
config = loadKxmUpdateConfig(runtime.env);
|
|
45442
45516
|
} catch (error) {
|
|
45443
45517
|
if (error instanceof KxmUpdateConfigError) {
|
|
45444
|
-
const yamlPath =
|
|
45518
|
+
const yamlPath = join42(vnextUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
45445
45519
|
runtime.io.stderr(`kxm: ${error.message}; update check skipped; fix or remove ${yamlPath}
|
|
45446
45520
|
`);
|
|
45447
45521
|
} else {
|
|
@@ -45577,7 +45651,7 @@ async function cmdWorker(runtime, options) {
|
|
|
45577
45651
|
return await (runtime.io.spawnWorker ?? ((launchEnv) => spawnScript("kxm-worker.mjs", launchEnv)))(extraEnv);
|
|
45578
45652
|
}
|
|
45579
45653
|
async function cmdStop(runtime, waitMsFlag) {
|
|
45580
|
-
const pids =
|
|
45654
|
+
const pids = existsSync32(runtime.dirs.state) ? readdirSync12(runtime.dirs.state).filter((name) => name.endsWith(".pid")) : [];
|
|
45581
45655
|
if (runtime.dryRun) {
|
|
45582
45656
|
print(runtime.io, runtime.json, { ok: true, command: "stop", dryRun: true, pidFiles: pids }, "would signal pid files");
|
|
45583
45657
|
return 0;
|
|
@@ -45592,7 +45666,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45592
45666
|
const orphans = [];
|
|
45593
45667
|
for (const file of pids) {
|
|
45594
45668
|
try {
|
|
45595
|
-
const record = JSON.parse(
|
|
45669
|
+
const record = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
|
|
45596
45670
|
const expectedControl = file === "hub.pid" ? "hub.stop" : file.startsWith("worker-") ? `${file.slice(0, -4)}.stop` : void 0;
|
|
45597
45671
|
const expectedRole = file === "hub.pid" ? "hub" : file.startsWith("worker-") ? "worker" : void 0;
|
|
45598
45672
|
if (record.version !== 1 || !Number.isInteger(record.pid) || record.pid <= 0 || !record.startedAt || !expectedControl || record.controlFile !== expectedControl || record.role !== expectedRole) {
|
|
@@ -45612,7 +45686,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45612
45686
|
ignored.push(file);
|
|
45613
45687
|
continue;
|
|
45614
45688
|
}
|
|
45615
|
-
|
|
45689
|
+
writeFileSync24(join42(runtime.dirs.state, record.controlFile), `${JSON.stringify({ startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {}, requestedAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
45616
45690
|
`, { encoding: "utf8", mode: 384 });
|
|
45617
45691
|
requested.push(file);
|
|
45618
45692
|
records.set(file, { pid: record.pid, startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {} });
|
|
@@ -45630,7 +45704,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45630
45704
|
while (Date.now() <= deadline && stopped.size < requested.length) {
|
|
45631
45705
|
for (const [file, record] of records) {
|
|
45632
45706
|
try {
|
|
45633
|
-
const current = JSON.parse(
|
|
45707
|
+
const current = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
|
|
45634
45708
|
if (current.pid !== record.pid || current.startedAt !== record.startedAt || current.generation !== record.generation || !processExists(record.pid)) stopped.add(file);
|
|
45635
45709
|
} catch {
|
|
45636
45710
|
stopped.add(file);
|
|
@@ -45643,7 +45717,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45643
45717
|
for (const file of orphans) {
|
|
45644
45718
|
while (Date.now() <= deadlineOrphans) {
|
|
45645
45719
|
try {
|
|
45646
|
-
const current = JSON.parse(
|
|
45720
|
+
const current = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
|
|
45647
45721
|
if (!Number.isInteger(current.serverPid) || !processExists(current.serverPid)) break;
|
|
45648
45722
|
} catch {
|
|
45649
45723
|
break;
|
|
@@ -45651,14 +45725,14 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45651
45725
|
await (runtime.io.sleep ?? ((ms) => new Promise((resolveSleep) => setTimeout(resolveSleep, ms))))(100);
|
|
45652
45726
|
}
|
|
45653
45727
|
try {
|
|
45654
|
-
const current = JSON.parse(
|
|
45728
|
+
const current = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
|
|
45655
45729
|
if (Number.isInteger(current.serverPid) && processExists(current.serverPid)) {
|
|
45656
45730
|
try {
|
|
45657
45731
|
process.kill(current.serverPid, "SIGKILL");
|
|
45658
45732
|
} catch {
|
|
45659
45733
|
}
|
|
45660
45734
|
}
|
|
45661
|
-
|
|
45735
|
+
rmSync11(join42(runtime.dirs.state, file), { force: true });
|
|
45662
45736
|
} catch {
|
|
45663
45737
|
}
|
|
45664
45738
|
stopped.add(file);
|
|
@@ -45669,11 +45743,11 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45669
45743
|
}
|
|
45670
45744
|
async function cmdSessionStatus(runtime) {
|
|
45671
45745
|
const stateDir = runtime.dirs.state;
|
|
45672
|
-
const names3 =
|
|
45746
|
+
const names3 = existsSync32(stateDir) ? readdirSync12(stateDir) : [];
|
|
45673
45747
|
const claims = [];
|
|
45674
45748
|
for (const file of names3.filter((name) => name.endsWith(".pid"))) {
|
|
45675
45749
|
try {
|
|
45676
|
-
const record = JSON.parse(
|
|
45750
|
+
const record = JSON.parse(readFileSync32(join42(stateDir, file), "utf8"));
|
|
45677
45751
|
claims.push({
|
|
45678
45752
|
file,
|
|
45679
45753
|
role: record.role,
|
|
@@ -45688,7 +45762,7 @@ async function cmdSessionStatus(runtime) {
|
|
|
45688
45762
|
const recoveries = [];
|
|
45689
45763
|
for (const file of names3.filter((name) => name.startsWith("worker-recovery-") && name.endsWith(".json"))) {
|
|
45690
45764
|
try {
|
|
45691
|
-
const envelope = JSON.parse(
|
|
45765
|
+
const envelope = JSON.parse(readFileSync32(join42(stateDir, file), "utf8"));
|
|
45692
45766
|
recoveries.push({
|
|
45693
45767
|
file,
|
|
45694
45768
|
reason: envelope.reason,
|
|
@@ -45793,7 +45867,7 @@ async function cmdSessionBrief(runtime, options = {}) {
|
|
|
45793
45867
|
print(runtime.io, runtime.json, { ok: true, command: "session brief", sessionToken }, sessionToken);
|
|
45794
45868
|
return 0;
|
|
45795
45869
|
}
|
|
45796
|
-
const dataPath =
|
|
45870
|
+
const dataPath = resolve25(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join42(runtime.dirs.state, "kxm.db"));
|
|
45797
45871
|
const env = {
|
|
45798
45872
|
...runtime.env,
|
|
45799
45873
|
KXM_STATE_DIR: runtime.dirs.state,
|
|
@@ -45869,7 +45943,7 @@ async function cmdSessionStart(runtime, options) {
|
|
|
45869
45943
|
...workflowId ? workflowAssetDirs(runtime.dirs.assets, workflowId) : []
|
|
45870
45944
|
];
|
|
45871
45945
|
if (!runtime.dryRun) {
|
|
45872
|
-
for (const directory of created)
|
|
45946
|
+
for (const directory of created) mkdirSync26(directory, { recursive: true });
|
|
45873
45947
|
writeSession(runtime.dirs.assets, session);
|
|
45874
45948
|
}
|
|
45875
45949
|
print(runtime.io, runtime.json, {
|
|
@@ -45885,15 +45959,15 @@ async function cmdSessionStart(runtime, options) {
|
|
|
45885
45959
|
// plugins/kxm/src/cli/system.ts
|
|
45886
45960
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
45887
45961
|
import { createHash as createHash16 } from "node:crypto";
|
|
45888
|
-
import { existsSync as
|
|
45962
|
+
import { existsSync as existsSync38, mkdtempSync as mkdtempSync2, readFileSync as readFileSync37, rmSync as rmSync13 } from "node:fs";
|
|
45889
45963
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
45890
|
-
import { join as
|
|
45964
|
+
import { join as join48, resolve as resolve29 } from "node:path";
|
|
45891
45965
|
import { createInterface as createInterface3 } from "node:readline";
|
|
45892
45966
|
|
|
45893
45967
|
// plugins/kxm/src/improve.ts
|
|
45894
45968
|
import { createHash as createHash15 } from "node:crypto";
|
|
45895
|
-
import { existsSync as
|
|
45896
|
-
import { join as
|
|
45969
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync27, writeFileSync as writeFileSync25 } from "node:fs";
|
|
45970
|
+
import { join as join43, relative as relative6, resolve as resolve26 } from "node:path";
|
|
45897
45971
|
var CANDIDATE_SCHEMA = "kxm.candidate.v1";
|
|
45898
45972
|
var IMPROVEMENT_REPORT_SCHEMA = "kxm.improvement-report.v2";
|
|
45899
45973
|
function classifyCandidateKind(stepId, agentRole) {
|
|
@@ -46064,8 +46138,8 @@ function groupRoutingRecords(records, options = {}) {
|
|
|
46064
46138
|
});
|
|
46065
46139
|
}
|
|
46066
46140
|
function buildImprovementReport(records, options = {}) {
|
|
46067
|
-
const projectRoot = options.projectRoot ?
|
|
46068
|
-
const candidatesDir = options.candidatesDir ?
|
|
46141
|
+
const projectRoot = options.projectRoot ? resolve26(options.projectRoot) : process.cwd();
|
|
46142
|
+
const candidatesDir = options.candidatesDir ? resolve26(options.candidatesDir) : join43(projectRoot, ".kxm", "candidates");
|
|
46069
46143
|
const groups = groupRoutingRecords(records, options);
|
|
46070
46144
|
const candidates = [];
|
|
46071
46145
|
for (const group of groups) {
|
|
@@ -46077,7 +46151,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46077
46151
|
group.workflowHash
|
|
46078
46152
|
);
|
|
46079
46153
|
const diffFileName = `${group.candidateId}.diff`;
|
|
46080
|
-
const diffFilePath =
|
|
46154
|
+
const diffFilePath = join43(candidatesDir, diffFileName);
|
|
46081
46155
|
const relDiffPath = relative6(projectRoot, diffFilePath).replace(/\\/g, "/");
|
|
46082
46156
|
const candidate = {
|
|
46083
46157
|
schema: CANDIDATE_SCHEMA,
|
|
@@ -46099,12 +46173,12 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46099
46173
|
createdAt: nowIso()
|
|
46100
46174
|
};
|
|
46101
46175
|
if (!options.dryRun) {
|
|
46102
|
-
if (!
|
|
46103
|
-
|
|
46176
|
+
if (!existsSync33(candidatesDir)) {
|
|
46177
|
+
mkdirSync27(candidatesDir, { recursive: true });
|
|
46104
46178
|
}
|
|
46105
|
-
|
|
46106
|
-
const jsonFilePath =
|
|
46107
|
-
|
|
46179
|
+
writeFileSync25(diffFilePath, diff, "utf8");
|
|
46180
|
+
const jsonFilePath = join43(candidatesDir, `${group.candidateId}.json`);
|
|
46181
|
+
writeFileSync25(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
|
|
46108
46182
|
}
|
|
46109
46183
|
candidates.push(candidate);
|
|
46110
46184
|
}
|
|
@@ -46119,10 +46193,10 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46119
46193
|
}
|
|
46120
46194
|
function writeImprovementReport(improvementsDir, report2, dryRun = false) {
|
|
46121
46195
|
const stamp = report2.createdAt.replace(/[:.]/g, "-");
|
|
46122
|
-
const path4 =
|
|
46196
|
+
const path4 = join43(improvementsDir, `${stamp}.json`);
|
|
46123
46197
|
if (!dryRun) {
|
|
46124
|
-
|
|
46125
|
-
|
|
46198
|
+
mkdirSync27(improvementsDir, { recursive: true });
|
|
46199
|
+
writeFileSync25(path4, `${JSON.stringify(report2, null, 2)}
|
|
46126
46200
|
`, { encoding: "utf8" });
|
|
46127
46201
|
}
|
|
46128
46202
|
return path4;
|
|
@@ -46162,8 +46236,8 @@ function formatImprovementReport(report2) {
|
|
|
46162
46236
|
|
|
46163
46237
|
// plugins/kxm/src/modes.ts
|
|
46164
46238
|
var import_yaml17 = __toESM(require_dist(), 1);
|
|
46165
|
-
import { existsSync as
|
|
46166
|
-
import { join as
|
|
46239
|
+
import { existsSync as existsSync34, readFileSync as readFileSync34 } from "node:fs";
|
|
46240
|
+
import { join as join44 } from "node:path";
|
|
46167
46241
|
var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
46168
46242
|
schema: "kxm.modes.v1",
|
|
46169
46243
|
majorModes: {
|
|
@@ -46226,12 +46300,12 @@ function loadModesConfig(projectRoot) {
|
|
|
46226
46300
|
if (!projectRoot) {
|
|
46227
46301
|
return DEFAULT_MODES_CONFIG;
|
|
46228
46302
|
}
|
|
46229
|
-
const modesPath =
|
|
46230
|
-
if (!
|
|
46303
|
+
const modesPath = join44(projectRoot, ".kxm", "modes.yaml");
|
|
46304
|
+
if (!existsSync34(modesPath)) {
|
|
46231
46305
|
return DEFAULT_MODES_CONFIG;
|
|
46232
46306
|
}
|
|
46233
46307
|
try {
|
|
46234
|
-
const raw =
|
|
46308
|
+
const raw = readFileSync34(modesPath, "utf8");
|
|
46235
46309
|
const parsed = (0, import_yaml17.parse)(raw);
|
|
46236
46310
|
if (parsed && parsed.schema === "kxm.modes.v1" && parsed.majorModes) {
|
|
46237
46311
|
return {
|
|
@@ -46317,11 +46391,11 @@ function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog
|
|
|
46317
46391
|
estimatedTokens: estimateTokens(baseSystemPromptChars)
|
|
46318
46392
|
});
|
|
46319
46393
|
for (const relPath of resolved.contextFiles) {
|
|
46320
|
-
const fullPath =
|
|
46394
|
+
const fullPath = join44(projectRoot, relPath);
|
|
46321
46395
|
let chars = 0;
|
|
46322
|
-
if (
|
|
46396
|
+
if (existsSync34(fullPath)) {
|
|
46323
46397
|
try {
|
|
46324
|
-
chars =
|
|
46398
|
+
chars = readFileSync34(fullPath, "utf8").length;
|
|
46325
46399
|
} catch {
|
|
46326
46400
|
chars = 0;
|
|
46327
46401
|
}
|
|
@@ -46453,9 +46527,9 @@ ${divider}
|
|
|
46453
46527
|
|
|
46454
46528
|
// plugins/kxm/src/ssh-remote.ts
|
|
46455
46529
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
46456
|
-
import { existsSync as
|
|
46457
|
-
import { homedir as
|
|
46458
|
-
import { join as
|
|
46530
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync28, readFileSync as readFileSync35, readdirSync as readdirSync13, rmSync as rmSync12, statSync as statSync5 } from "node:fs";
|
|
46531
|
+
import { homedir as homedir8 } from "node:os";
|
|
46532
|
+
import { join as join45, resolve as resolve27 } from "node:path";
|
|
46459
46533
|
var MAX_SSH_OUTPUT_BYTES = 50 * 1024;
|
|
46460
46534
|
var MAX_SSH_OUTPUT_LINES = 2e3;
|
|
46461
46535
|
var DEFAULT_SOCKET_DIR = ".kxm/run/ssh-sockets";
|
|
@@ -46481,12 +46555,12 @@ function truncateSshOutput(raw) {
|
|
|
46481
46555
|
return { text, truncated };
|
|
46482
46556
|
}
|
|
46483
46557
|
function parseSshConfig(configPath) {
|
|
46484
|
-
const targetPath = configPath ??
|
|
46485
|
-
if (!
|
|
46558
|
+
const targetPath = configPath ?? join45(homedir8(), ".ssh", "config");
|
|
46559
|
+
if (!existsSync35(targetPath)) {
|
|
46486
46560
|
return [];
|
|
46487
46561
|
}
|
|
46488
46562
|
try {
|
|
46489
|
-
const content =
|
|
46563
|
+
const content = readFileSync35(targetPath, "utf-8");
|
|
46490
46564
|
const lines = content.split("\n");
|
|
46491
46565
|
const hosts = [];
|
|
46492
46566
|
let currentHosts = [];
|
|
@@ -46563,15 +46637,15 @@ function resolveSshHostG(host, execFn = spawnSync7) {
|
|
|
46563
46637
|
}
|
|
46564
46638
|
}
|
|
46565
46639
|
function ensureSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
46566
|
-
const resolved =
|
|
46567
|
-
if (!
|
|
46568
|
-
|
|
46640
|
+
const resolved = resolve27(socketDir);
|
|
46641
|
+
if (!existsSync35(resolved)) {
|
|
46642
|
+
mkdirSync28(resolved, { recursive: true, mode: 448 });
|
|
46569
46643
|
}
|
|
46570
46644
|
return resolved;
|
|
46571
46645
|
}
|
|
46572
46646
|
function buildSshArgs(options) {
|
|
46573
46647
|
const socketDir = ensureSocketDir(options.socketDir ?? DEFAULT_SOCKET_DIR);
|
|
46574
|
-
const controlPath =
|
|
46648
|
+
const controlPath = join45(socketDir, "%C");
|
|
46575
46649
|
const persist = options.controlPersist ?? DEFAULT_CONTROL_PERSIST;
|
|
46576
46650
|
const args = [
|
|
46577
46651
|
"-o",
|
|
@@ -46596,7 +46670,7 @@ function buildSshArgs(options) {
|
|
|
46596
46670
|
}
|
|
46597
46671
|
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
46598
46672
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
46599
|
-
const controlPath =
|
|
46673
|
+
const controlPath = join45(resolvedDir, "%C");
|
|
46600
46674
|
try {
|
|
46601
46675
|
const result = execFn("ssh", ["-O", "check", "-o", `ControlPath=${controlPath}`, host], {
|
|
46602
46676
|
encoding: "utf-8"
|
|
@@ -46608,7 +46682,7 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
46608
46682
|
}
|
|
46609
46683
|
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
46610
46684
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
46611
|
-
const controlPath =
|
|
46685
|
+
const controlPath = join45(resolvedDir, "%C");
|
|
46612
46686
|
try {
|
|
46613
46687
|
const result = execFn("ssh", ["-O", "stop", "-o", `ControlPath=${controlPath}`, host], {
|
|
46614
46688
|
encoding: "utf-8"
|
|
@@ -47054,9 +47128,9 @@ complete -c kxm -n "__fish_seen_subcommand_from goal" -a "create list get"
|
|
|
47054
47128
|
}
|
|
47055
47129
|
|
|
47056
47130
|
// plugins/kxm/src/completion-install.ts
|
|
47057
|
-
import { existsSync as
|
|
47058
|
-
import { homedir as
|
|
47059
|
-
import { basename as basename9, delimiter, dirname as
|
|
47131
|
+
import { existsSync as existsSync36, mkdirSync as mkdirSync29, readFileSync as readFileSync36, writeFileSync as writeFileSync26 } from "node:fs";
|
|
47132
|
+
import { homedir as homedir9 } from "node:os";
|
|
47133
|
+
import { basename as basename9, delimiter, dirname as dirname22, isAbsolute as isAbsolute9, join as join46, resolve as resolve28 } from "node:path";
|
|
47060
47134
|
var COMPLETION_MARKER = "# kxm completion";
|
|
47061
47135
|
var PATH_MARKER = "# kxm path";
|
|
47062
47136
|
function detectShell(env = process.env, platform = process.platform) {
|
|
@@ -47072,31 +47146,31 @@ function effectiveHome(options) {
|
|
|
47072
47146
|
const env = options.env ?? process.env;
|
|
47073
47147
|
if (options.homeDir) return options.homeDir;
|
|
47074
47148
|
const envHome = env.HOME?.trim() ?? env.USERPROFILE?.trim();
|
|
47075
|
-
return envHome && envHome.length > 0 ?
|
|
47149
|
+
return envHome && envHome.length > 0 ? resolve28(envHome) : homedir9();
|
|
47076
47150
|
}
|
|
47077
47151
|
function completionScriptPath(shell, options = {}) {
|
|
47078
47152
|
const env = options.env ?? process.env;
|
|
47079
47153
|
const explicit = options.configDir ?? env.KXM_USER_CONFIG_DIR?.trim();
|
|
47080
|
-
const base = explicit && explicit.length > 0 ?
|
|
47081
|
-
return
|
|
47154
|
+
const base = explicit && explicit.length > 0 ? resolve28(explicit) : resolve28(effectiveHome(options), ".config", "kxm");
|
|
47155
|
+
return join46(base, "completions", `kxm.${shell}`);
|
|
47082
47156
|
}
|
|
47083
47157
|
function bashRcCandidate(options) {
|
|
47084
47158
|
const home = effectiveHome(options);
|
|
47085
|
-
const candidates = [
|
|
47086
|
-
const existing = candidates.find((candidate) =>
|
|
47159
|
+
const candidates = [join46(home, ".bashrc"), join46(home, ".bash_profile")];
|
|
47160
|
+
const existing = candidates.find((candidate) => existsSync36(candidate));
|
|
47087
47161
|
return existing ?? candidates[0];
|
|
47088
47162
|
}
|
|
47089
47163
|
function zshRcCandidate(options) {
|
|
47090
47164
|
const env = options.env ?? process.env;
|
|
47091
47165
|
const home = effectiveHome(options);
|
|
47092
|
-
if (env.ZDOTDIR?.trim()) return
|
|
47093
|
-
return
|
|
47166
|
+
if (env.ZDOTDIR?.trim()) return join46(resolve28(env.ZDOTDIR.trim()), ".zshrc");
|
|
47167
|
+
return join46(home, ".zshrc");
|
|
47094
47168
|
}
|
|
47095
47169
|
function fishCompletionTarget(shell, options) {
|
|
47096
47170
|
const env = options.env ?? process.env;
|
|
47097
47171
|
const home = effectiveHome(options);
|
|
47098
|
-
if (env.XDG_CONFIG_HOME?.trim()) return
|
|
47099
|
-
return
|
|
47172
|
+
if (env.XDG_CONFIG_HOME?.trim()) return join46(resolve28(env.XDG_CONFIG_HOME.trim()), "fish", "completions", "kxm.fish");
|
|
47173
|
+
return join46(home, ".config", "fish", "completions", "kxm.fish");
|
|
47100
47174
|
}
|
|
47101
47175
|
function completionRcTarget(shell, options = {}) {
|
|
47102
47176
|
if (shell === "fish") {
|
|
@@ -47128,17 +47202,17 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47128
47202
|
const scriptPath = completionScriptPath(shell, options);
|
|
47129
47203
|
const { rcFile } = completionRcTarget(shell, options);
|
|
47130
47204
|
const script = generateShellCompletion(shell);
|
|
47131
|
-
const existingScript =
|
|
47132
|
-
const existingScriptMatches = existingScript &&
|
|
47205
|
+
const existingScript = existsSync36(scriptPath);
|
|
47206
|
+
const existingScriptMatches = existingScript && readFileSync36(scriptPath, "utf8") === script;
|
|
47133
47207
|
let rcModified = false;
|
|
47134
47208
|
let alreadyInstalled = false;
|
|
47135
47209
|
if (shell === "fish") {
|
|
47136
47210
|
const fishTarget = fishCompletionTarget(shell, options);
|
|
47137
|
-
const fishInstalled =
|
|
47211
|
+
const fishInstalled = existsSync36(fishTarget) && readFileSync36(fishTarget, "utf8") === script;
|
|
47138
47212
|
alreadyInstalled = fishInstalled;
|
|
47139
47213
|
if (!options.dryRun && (!fishInstalled || options.overwrite)) {
|
|
47140
|
-
|
|
47141
|
-
|
|
47214
|
+
mkdirSync29(resolve28(fishTarget, ".."), { recursive: true });
|
|
47215
|
+
writeFileSync26(fishTarget, script, { encoding: "utf8" });
|
|
47142
47216
|
}
|
|
47143
47217
|
return {
|
|
47144
47218
|
ok: true,
|
|
@@ -47151,13 +47225,13 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47151
47225
|
}
|
|
47152
47226
|
if (rcFile) {
|
|
47153
47227
|
const line = sourceLine(shell, scriptPath);
|
|
47154
|
-
const rcContent =
|
|
47228
|
+
const rcContent = existsSync36(rcFile) ? readFileSync36(rcFile, "utf8") : "";
|
|
47155
47229
|
alreadyInstalled = rcContent.includes(line) || rcContent.includes(`${COMPLETION_MARKER}`);
|
|
47156
47230
|
}
|
|
47157
47231
|
if (!options.dryRun) {
|
|
47158
47232
|
if (!existingScriptMatches || options.overwrite) {
|
|
47159
|
-
|
|
47160
|
-
|
|
47233
|
+
mkdirSync29(resolve28(scriptPath, ".."), { recursive: true });
|
|
47234
|
+
writeFileSync26(scriptPath, script, { encoding: "utf8" });
|
|
47161
47235
|
}
|
|
47162
47236
|
if (rcFile && !alreadyInstalled) {
|
|
47163
47237
|
const line = sourceLine(shell, scriptPath);
|
|
@@ -47166,8 +47240,8 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47166
47240
|
${marker}
|
|
47167
47241
|
${line}
|
|
47168
47242
|
`;
|
|
47169
|
-
|
|
47170
|
-
|
|
47243
|
+
mkdirSync29(resolve28(rcFile, ".."), { recursive: true });
|
|
47244
|
+
writeFileSync26(rcFile, (existsSync36(rcFile) ? readFileSync36(rcFile, "utf8") : "") + stanza, { encoding: "utf8" });
|
|
47171
47245
|
rcModified = true;
|
|
47172
47246
|
}
|
|
47173
47247
|
}
|
|
@@ -47182,15 +47256,15 @@ ${line}
|
|
|
47182
47256
|
}
|
|
47183
47257
|
function kxmBinDir(env = process.env) {
|
|
47184
47258
|
const argv1 = env.KXM_ENTRY ?? process.argv[1];
|
|
47185
|
-
if (argv1 &&
|
|
47186
|
-
const dir =
|
|
47187
|
-
if (
|
|
47259
|
+
if (argv1 && isAbsolute9(argv1)) {
|
|
47260
|
+
const dir = dirname22(argv1);
|
|
47261
|
+
if (existsSync36(join46(dir, process.platform === "win32" ? "kxm.cmd" : "kxm"))) return dir;
|
|
47188
47262
|
}
|
|
47189
47263
|
const pathEnv = env.PATH ?? "";
|
|
47190
47264
|
for (const part of pathEnv.split(delimiter)) {
|
|
47191
47265
|
if (!part) continue;
|
|
47192
|
-
const candidate =
|
|
47193
|
-
if (
|
|
47266
|
+
const candidate = resolve28(part, process.platform === "win32" ? "kxm.cmd" : "kxm");
|
|
47267
|
+
if (existsSync36(candidate)) return resolve28(part);
|
|
47194
47268
|
}
|
|
47195
47269
|
return void 0;
|
|
47196
47270
|
}
|
|
@@ -47208,11 +47282,11 @@ function installPathEntry(shellInput, options = {}) {
|
|
|
47208
47282
|
}
|
|
47209
47283
|
const { rcFile } = completionRcTarget(shell, options);
|
|
47210
47284
|
const line = pathLine(binDir);
|
|
47211
|
-
const rcContent =
|
|
47285
|
+
const rcContent = existsSync36(rcFile ?? "") ? readFileSync36(rcFile, "utf8") : "";
|
|
47212
47286
|
const alreadyInstalled = rcContent.includes(binDir) || (options.env?.PATH ?? process.env.PATH ?? "").split(delimiter).includes(binDir);
|
|
47213
47287
|
if (!options.dryRun && rcFile && !alreadyInstalled) {
|
|
47214
|
-
|
|
47215
|
-
|
|
47288
|
+
mkdirSync29(dirname22(rcFile), { recursive: true });
|
|
47289
|
+
writeFileSync26(rcFile, rcContent + `
|
|
47216
47290
|
${PATH_MARKER}
|
|
47217
47291
|
${line}
|
|
47218
47292
|
`, { encoding: "utf8" });
|
|
@@ -47222,8 +47296,8 @@ ${line}
|
|
|
47222
47296
|
|
|
47223
47297
|
// plugins/kxm/src/init-guide-setup.ts
|
|
47224
47298
|
var import_yaml18 = __toESM(require_dist(), 1);
|
|
47225
|
-
import { existsSync as
|
|
47226
|
-
import { dirname as
|
|
47299
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync30, writeFileSync as writeFileSync27 } from "node:fs";
|
|
47300
|
+
import { dirname as dirname23, join as join47 } from "node:path";
|
|
47227
47301
|
var NATIVE_VENDOR_HARNESS = Object.freeze({
|
|
47228
47302
|
anthropic: "claude",
|
|
47229
47303
|
openai: "codex",
|
|
@@ -47622,13 +47696,13 @@ function renderGuideSetupFiles(projectRoot, plan) {
|
|
|
47622
47696
|
const stage = roleStages.get(role);
|
|
47623
47697
|
if (!stage) continue;
|
|
47624
47698
|
files.push({
|
|
47625
|
-
path:
|
|
47699
|
+
path: join47(projectRoot, ".kxm", "agents", `${role}.yaml`),
|
|
47626
47700
|
content: (0, import_yaml18.stringify)(agentDocument(role, stage, binding))
|
|
47627
47701
|
});
|
|
47628
47702
|
}
|
|
47629
47703
|
for (const workflow of plan.workflows) {
|
|
47630
47704
|
files.push({
|
|
47631
|
-
path:
|
|
47705
|
+
path: join47(projectRoot, ".kxm", "workflows", `${workflow.slug}.yaml`),
|
|
47632
47706
|
content: (0, import_yaml18.stringify)(workflowDocument(workflow))
|
|
47633
47707
|
});
|
|
47634
47708
|
}
|
|
@@ -47638,12 +47712,12 @@ function writeGuideSetupFiles(files) {
|
|
|
47638
47712
|
const written = [];
|
|
47639
47713
|
const existed = [];
|
|
47640
47714
|
for (const file of files) {
|
|
47641
|
-
if (
|
|
47715
|
+
if (existsSync37(file.path)) {
|
|
47642
47716
|
existed.push(file.path);
|
|
47643
47717
|
continue;
|
|
47644
47718
|
}
|
|
47645
|
-
|
|
47646
|
-
|
|
47719
|
+
mkdirSync30(dirname23(file.path), { recursive: true });
|
|
47720
|
+
writeFileSync27(file.path, file.content, "utf8");
|
|
47647
47721
|
written.push(file.path);
|
|
47648
47722
|
}
|
|
47649
47723
|
return { written, existed };
|
|
@@ -47706,7 +47780,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
47706
47780
|
detail: `release v${notice.latest} has no sha256 digest for ${name}; refusing to install`
|
|
47707
47781
|
};
|
|
47708
47782
|
}
|
|
47709
|
-
const releaseDir = mkdtempSync2(
|
|
47783
|
+
const releaseDir = mkdtempSync2(join48(tmpdir2(), "kxm-pkg-update-"));
|
|
47710
47784
|
try {
|
|
47711
47785
|
const planned = planKxmPackageUpdate(notice.source, notice.latest, releaseDir, notice.asset);
|
|
47712
47786
|
if (runtime.dryRun) {
|
|
@@ -47715,7 +47789,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
47715
47789
|
for (const step of planned) {
|
|
47716
47790
|
if (step.kind === "verify") {
|
|
47717
47791
|
if (!verifyReleaseAssetDigest(step.path, step.sha256)) {
|
|
47718
|
-
const actual =
|
|
47792
|
+
const actual = existsSync38(step.path) ? createHash16("sha256").update(readFileSync37(step.path)).digest("hex") : "missing";
|
|
47719
47793
|
return {
|
|
47720
47794
|
ok: false,
|
|
47721
47795
|
error: "release_digest_mismatch",
|
|
@@ -47732,7 +47806,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
47732
47806
|
}
|
|
47733
47807
|
return { ok: true, detail: `installed ${notice.latest} from ${notice.source}` };
|
|
47734
47808
|
} finally {
|
|
47735
|
-
|
|
47809
|
+
rmSync13(releaseDir, { recursive: true, force: true });
|
|
47736
47810
|
}
|
|
47737
47811
|
}
|
|
47738
47812
|
async function cmdExplain(runtime, options) {
|
|
@@ -47980,13 +48054,13 @@ async function cmdValidate(runtime, fileFlag) {
|
|
|
47980
48054
|
return 2;
|
|
47981
48055
|
}
|
|
47982
48056
|
const selectedFile = explicitFile || configuredFile;
|
|
47983
|
-
const file = selectedFile ?
|
|
47984
|
-
if (file && !
|
|
48057
|
+
const file = selectedFile ? resolve29(runtime.cwd, selectedFile) : void 0;
|
|
48058
|
+
if (file && !existsSync38(file)) {
|
|
47985
48059
|
printWorker(runtime, worker, { ok: false, command: "validate", error: "file_not_found", file }, `workflow file not found: ${file}`);
|
|
47986
48060
|
return 1;
|
|
47987
48061
|
}
|
|
47988
48062
|
try {
|
|
47989
|
-
const raw = file ?
|
|
48063
|
+
const raw = file ? readFileSync37(file, "utf8") : inline;
|
|
47990
48064
|
const warnings = [];
|
|
47991
48065
|
const definitions = parseWorkflowDefinitions(raw, runtime.env, (message) => warnings.push(message));
|
|
47992
48066
|
const secretEnvs = definitions.map((definition) => ({
|
|
@@ -48011,7 +48085,7 @@ async function cmdValidate(runtime, fileFlag) {
|
|
|
48011
48085
|
}
|
|
48012
48086
|
async function cmdArtifactsExist(runtime, pathFlag) {
|
|
48013
48087
|
const worker = gateOf(runtime, "artifacts-exist");
|
|
48014
|
-
const checked = verifyArtifactExists(runtime.dirs.assets,
|
|
48088
|
+
const checked = verifyArtifactExists(runtime.dirs.assets, resolve29(runtime.cwd, pathFlag));
|
|
48015
48089
|
if (!checked.ok) {
|
|
48016
48090
|
printWorker(
|
|
48017
48091
|
runtime,
|
|
@@ -48030,15 +48104,15 @@ async function cmdArtifactsExist(runtime, pathFlag) {
|
|
|
48030
48104
|
return 0;
|
|
48031
48105
|
}
|
|
48032
48106
|
async function cmdImprove(runtime, options = {}) {
|
|
48033
|
-
const file = options.file ?
|
|
48034
|
-
const routingRecords =
|
|
48035
|
-
const candidatesDir = options.outDir ?
|
|
48107
|
+
const file = options.file ? resolve29(runtime.cwd, options.file) : telemetryPath(runtime.dirs.logs);
|
|
48108
|
+
const routingRecords = existsSync38(file) ? readRoutingRecords(file).map((entry) => entry.routing) : [];
|
|
48109
|
+
const candidatesDir = options.outDir ? resolve29(runtime.cwd, options.outDir) : join48(runtime.cwd, ".kxm", "candidates");
|
|
48036
48110
|
const report2 = buildImprovementReport(routingRecords, {
|
|
48037
48111
|
candidatesDir,
|
|
48038
48112
|
projectRoot: runtime.cwd,
|
|
48039
48113
|
dryRun: runtime.dryRun
|
|
48040
48114
|
});
|
|
48041
|
-
const reportDir =
|
|
48115
|
+
const reportDir = join48(runtime.dirs.assets, "improvements");
|
|
48042
48116
|
const reportPath = writeImprovementReport(reportDir, report2, runtime.dryRun);
|
|
48043
48117
|
const text = formatImprovementReport(report2);
|
|
48044
48118
|
print(runtime.io, runtime.json, {
|
|
@@ -48170,9 +48244,9 @@ async function maybeOfferCompletionInstall(runtime) {
|
|
|
48170
48244
|
if (!pathNeeded) {
|
|
48171
48245
|
const scriptPath = completionScriptPath(shell, { env: runtime.env, configDir: runtime.env.KXM_USER_CONFIG_DIR });
|
|
48172
48246
|
const { rcFile } = completionRcTarget(shell, { env: runtime.env });
|
|
48173
|
-
if (rcFile &&
|
|
48247
|
+
if (rcFile && existsSync38(rcFile)) {
|
|
48174
48248
|
try {
|
|
48175
|
-
if (
|
|
48249
|
+
if (readFileSync37(rcFile, "utf8").includes(scriptPath)) return;
|
|
48176
48250
|
} catch {
|
|
48177
48251
|
}
|
|
48178
48252
|
}
|
|
@@ -48304,7 +48378,7 @@ async function cmdRoutingReport(runtime, options) {
|
|
|
48304
48378
|
let catalog;
|
|
48305
48379
|
if (includeEquivalentListCost) {
|
|
48306
48380
|
try {
|
|
48307
|
-
const pricesPath = options.prices ?
|
|
48381
|
+
const pricesPath = options.prices ? resolve29(runtime.cwd, options.prices) : join48(runtime.dirs.workspace, "prices.yaml");
|
|
48308
48382
|
catalog = loadPriceCatalog(pricesPath);
|
|
48309
48383
|
} catch {
|
|
48310
48384
|
}
|
|
@@ -48409,12 +48483,13 @@ async function ensureCliClient(runtime) {
|
|
|
48409
48483
|
const project = defaultProjectName(runtime.cwd, runtime.env);
|
|
48410
48484
|
const name = runtime.env.KXM_AGENT_NAME?.trim() || `cli-${process.pid}`;
|
|
48411
48485
|
const purpose = runtime.env.KXM_AGENT_PURPOSE?.trim() || "CLI agent client";
|
|
48412
|
-
const authToken = runtime.env
|
|
48486
|
+
const authToken = resolveClientHubAuthToken(runtime.env, project);
|
|
48413
48487
|
const client = new HubClient({
|
|
48414
48488
|
serverUrl,
|
|
48415
48489
|
name,
|
|
48416
48490
|
project,
|
|
48417
48491
|
purpose,
|
|
48492
|
+
fetchImpl: runtime.fetchImpl,
|
|
48418
48493
|
...authToken ? { authToken } : {}
|
|
48419
48494
|
});
|
|
48420
48495
|
await client.start(() => {
|
|
@@ -48997,7 +49072,7 @@ async function runCli(argv, env = process.env, io = { stdout: (text) => process.
|
|
|
48997
49072
|
throw error;
|
|
48998
49073
|
}
|
|
48999
49074
|
}
|
|
49000
|
-
if (process.argv[1] &&
|
|
49075
|
+
if (process.argv[1] && resolve30(process.argv[1]) === fileURLToPath4(import.meta.url)) {
|
|
49001
49076
|
const code = await runCli(process.argv.slice(2));
|
|
49002
49077
|
process.exitCode = code;
|
|
49003
49078
|
}
|