@kontextmind/kxm 0.7.21 → 0.7.22
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 +924 -849
- package/plugins/kxm/dist/client.js +2 -2
- package/plugins/kxm/dist/extension.js +2 -2
- package/plugins/kxm/dist/mcp-server.js +3 -3
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/cli.ts +13 -1
- package/plugins/kxm/src/client.ts +4 -2
- package/plugins/kxm/src/mcp-server.ts +1 -1
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,82 @@ 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
|
+
|
|
19593
19661
|
// plugins/kxm/src/project-name.ts
|
|
19594
|
-
import { readFileSync as
|
|
19595
|
-
import { basename, join as
|
|
19662
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
19663
|
+
import { basename, join as join4 } from "node:path";
|
|
19596
19664
|
function defaultProjectName(cwd, env = process.env) {
|
|
19597
19665
|
const fromEnv = env.KXM_PROJECT?.trim();
|
|
19598
19666
|
if (fromEnv) return fromEnv;
|
|
19599
19667
|
try {
|
|
19600
|
-
const pkg = JSON.parse(
|
|
19668
|
+
const pkg = JSON.parse(readFileSync3(join4(cwd, "package.json"), "utf8"));
|
|
19601
19669
|
if (typeof pkg.name === "string" && pkg.name.trim().length > 0) return pkg.name.trim();
|
|
19602
19670
|
} catch {
|
|
19603
19671
|
}
|
|
@@ -19606,9 +19674,9 @@ function defaultProjectName(cwd, env = process.env) {
|
|
|
19606
19674
|
|
|
19607
19675
|
// plugins/kxm/src/commands.ts
|
|
19608
19676
|
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
|
|
19677
|
+
import { chmodSync, existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
19678
|
+
import { homedir as homedir2 } from "node:os";
|
|
19679
|
+
import { dirname as dirname3, join as join5, resolve as resolve2 } from "node:path";
|
|
19612
19680
|
function requiredString(value, name) {
|
|
19613
19681
|
if (typeof value !== "string" || value.trim() === "") throw new Error(`${name} is required`);
|
|
19614
19682
|
return value.trim();
|
|
@@ -20356,18 +20424,18 @@ function parseSessionToken(token) {
|
|
|
20356
20424
|
return void 0;
|
|
20357
20425
|
}
|
|
20358
20426
|
function resolveUserConfigDirectory(overrideDir) {
|
|
20359
|
-
if (overrideDir) return
|
|
20360
|
-
return
|
|
20427
|
+
if (overrideDir) return resolve2(overrideDir);
|
|
20428
|
+
return resolve2(process.env.KXM_USER_CONFIG_DIR?.trim() || join5(homedir2(), ".config", "kxm"));
|
|
20361
20429
|
}
|
|
20362
20430
|
function sessionTokenPath(userConfigDir) {
|
|
20363
|
-
return
|
|
20431
|
+
return join5(resolveUserConfigDirectory(userConfigDir), "session.token");
|
|
20364
20432
|
}
|
|
20365
20433
|
function persistSessionTokenToDisk(token, options) {
|
|
20366
20434
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
20367
|
-
const dir =
|
|
20368
|
-
|
|
20435
|
+
const dir = dirname3(filePath);
|
|
20436
|
+
mkdirSync3(dir, { recursive: true, mode: 448 });
|
|
20369
20437
|
const mode = options?.mode ?? 384;
|
|
20370
|
-
|
|
20438
|
+
writeFileSync3(filePath, `${token.trim()}
|
|
20371
20439
|
`, { encoding: "utf8", mode });
|
|
20372
20440
|
try {
|
|
20373
20441
|
chmodSync(filePath, mode);
|
|
@@ -20377,9 +20445,9 @@ function persistSessionTokenToDisk(token, options) {
|
|
|
20377
20445
|
}
|
|
20378
20446
|
function readSessionTokenFromDisk(options) {
|
|
20379
20447
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
20380
|
-
if (!
|
|
20448
|
+
if (!existsSync4(filePath)) return void 0;
|
|
20381
20449
|
try {
|
|
20382
|
-
const token =
|
|
20450
|
+
const token = readFileSync4(filePath, "utf8").trim();
|
|
20383
20451
|
if (!token) return void 0;
|
|
20384
20452
|
const payload = parseSessionToken(token);
|
|
20385
20453
|
if (!payload) return void 0;
|
|
@@ -20390,7 +20458,7 @@ function readSessionTokenFromDisk(options) {
|
|
|
20390
20458
|
}
|
|
20391
20459
|
function clearSessionTokenFromDisk(options) {
|
|
20392
20460
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
20393
|
-
if (!
|
|
20461
|
+
if (!existsSync4(filePath)) return false;
|
|
20394
20462
|
try {
|
|
20395
20463
|
unlinkSync(filePath);
|
|
20396
20464
|
return true;
|
|
@@ -20489,10 +20557,10 @@ function enforceToolPolicy(commandName, env = process.env, options) {
|
|
|
20489
20557
|
return { allowed: true };
|
|
20490
20558
|
}
|
|
20491
20559
|
const tokenFile = sessionTokenPath(env.KXM_USER_CONFIG_DIR);
|
|
20492
|
-
if (
|
|
20560
|
+
if (existsSync4(tokenFile)) {
|
|
20493
20561
|
let tokenRaw;
|
|
20494
20562
|
try {
|
|
20495
|
-
tokenRaw =
|
|
20563
|
+
tokenRaw = readFileSync4(tokenFile, "utf8").trim();
|
|
20496
20564
|
} catch {
|
|
20497
20565
|
return { allowed: false, error: "session_token_invalid", detail: "Session token file on disk could not be read" };
|
|
20498
20566
|
}
|
|
@@ -20516,8 +20584,8 @@ function enforceToolPolicy(commandName, env = process.env, options) {
|
|
|
20516
20584
|
var import__ = __toESM(require__(), 1);
|
|
20517
20585
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
20518
20586
|
import { createHash as createHash6 } from "node:crypto";
|
|
20519
|
-
import { existsSync as
|
|
20520
|
-
import { basename as basename2, dirname as
|
|
20587
|
+
import { existsSync as existsSync6, lstatSync, readFileSync as readFileSync5, readdirSync, realpathSync } from "node:fs";
|
|
20588
|
+
import { basename as basename2, dirname as dirname4, extname, isAbsolute as isAbsolute2, join as join6, relative, resolve as resolve3, sep } from "node:path";
|
|
20521
20589
|
|
|
20522
20590
|
// plugins/kxm/src/restricted-yaml.mjs
|
|
20523
20591
|
var import_yaml = __toESM(require_dist(), 1);
|
|
@@ -20845,7 +20913,7 @@ function resolveVnextTemplateBaseline(value) {
|
|
|
20845
20913
|
|
|
20846
20914
|
// plugins/kxm/src/vnext-harness.ts
|
|
20847
20915
|
import { spawnSync } from "node:child_process";
|
|
20848
|
-
import { existsSync as
|
|
20916
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
20849
20917
|
import { win32 as win32Path } from "node:path";
|
|
20850
20918
|
|
|
20851
20919
|
// plugins/kxm/src/vnext-oneshot-process.ts
|
|
@@ -20871,7 +20939,7 @@ function defaultSpawn(command, args, options) {
|
|
|
20871
20939
|
if (options.signal?.aborted) {
|
|
20872
20940
|
return Promise.resolve({ stdout: "", stderr: "", code: null, started: false, observedChildExit: false, error: new Error("process_aborted") });
|
|
20873
20941
|
}
|
|
20874
|
-
return new Promise((
|
|
20942
|
+
return new Promise((resolve31) => {
|
|
20875
20943
|
const stdout = [];
|
|
20876
20944
|
const stderr = [];
|
|
20877
20945
|
let outputBytes = 0;
|
|
@@ -20902,7 +20970,7 @@ function defaultSpawn(command, args, options) {
|
|
|
20902
20970
|
const started = Boolean(child?.pid);
|
|
20903
20971
|
if (started && !observedChildExit) error ??= new Error("process_exit_unobserved");
|
|
20904
20972
|
const unverifiedDescendants = stopping || started && !observedChildExit;
|
|
20905
|
-
|
|
20973
|
+
resolve31({
|
|
20906
20974
|
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
20907
20975
|
stderr: Buffer.concat(stderr).toString("utf8"),
|
|
20908
20976
|
code,
|
|
@@ -21394,7 +21462,7 @@ function findWinNpmInnerExe(cliId, options = {}) {
|
|
|
21394
21462
|
if ((options.platform ?? process.platform) !== "win32") return void 0;
|
|
21395
21463
|
const segments = WIN_NPM_INNER_EXE[cliId];
|
|
21396
21464
|
if (!segments) return void 0;
|
|
21397
|
-
const exists = options.existsSync ??
|
|
21465
|
+
const exists = options.existsSync ?? existsSync5;
|
|
21398
21466
|
const pathEnv = options.pathEnv ?? process.env.PATH ?? "";
|
|
21399
21467
|
for (const dir of pathEnv.split(";").filter(Boolean)) {
|
|
21400
21468
|
if (!exists(win32Path.join(dir, `${cliId}.cmd`))) continue;
|
|
@@ -21912,7 +21980,7 @@ var VnextConfigError = class extends Error {
|
|
|
21912
21980
|
}
|
|
21913
21981
|
};
|
|
21914
21982
|
function defaultVnextSchemaDir() {
|
|
21915
|
-
return
|
|
21983
|
+
return join6(findKxmRepoRoot(import.meta.url), "schemas", "vnext");
|
|
21916
21984
|
}
|
|
21917
21985
|
var DEFAULT_SCHEMA_DIR = defaultVnextSchemaDir();
|
|
21918
21986
|
var RESOURCE_SCHEMA = Object.freeze({
|
|
@@ -21960,7 +22028,7 @@ function parseRestrictedYaml2(input, label = "<yaml>", limits = VNEXT_YAML_LIMIT
|
|
|
21960
22028
|
}
|
|
21961
22029
|
}
|
|
21962
22030
|
function readJsonObject(file) {
|
|
21963
|
-
const parsed = JSON.parse(
|
|
22031
|
+
const parsed = JSON.parse(readFileSync5(file, "utf8"));
|
|
21964
22032
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`${file} is not a JSON object`);
|
|
21965
22033
|
return parsed;
|
|
21966
22034
|
}
|
|
@@ -21977,12 +22045,12 @@ var VnextSchemaRegistry = class {
|
|
|
21977
22045
|
permissionDiffValidator;
|
|
21978
22046
|
runEventValidator;
|
|
21979
22047
|
constructor(schemasDir = DEFAULT_SCHEMA_DIR) {
|
|
21980
|
-
this.schemasDir =
|
|
22048
|
+
this.schemasDir = resolve3(schemasDir);
|
|
21981
22049
|
this.ajv = new import__.Ajv2020({ allErrors: true, strict: true, strictRequired: false });
|
|
21982
|
-
const common = readJsonObject(
|
|
22050
|
+
const common = readJsonObject(join6(this.schemasDir, "common.schema.json"));
|
|
21983
22051
|
this.ajv.addSchema(common);
|
|
21984
22052
|
for (const definition of Object.values(RESOURCE_SCHEMA)) {
|
|
21985
|
-
this.ajv.addSchema(readJsonObject(
|
|
22053
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, definition.file)));
|
|
21986
22054
|
}
|
|
21987
22055
|
const localBindingsFile = "local-repository-bindings.schema.json";
|
|
21988
22056
|
const templateProvenanceFile = "template-provenance.schema.json";
|
|
@@ -21992,14 +22060,14 @@ var VnextSchemaRegistry = class {
|
|
|
21992
22060
|
const migrationReceiptFile = "migration-receipt.schema.json";
|
|
21993
22061
|
const permissionDiffFile = "permission-diff.schema.json";
|
|
21994
22062
|
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(
|
|
22063
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, localBindingsFile)));
|
|
22064
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, templateProvenanceFile)));
|
|
22065
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, initOperationFile)));
|
|
22066
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, migrationPlanFile)));
|
|
22067
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, migrationDecisionFile)));
|
|
22068
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, migrationReceiptFile)));
|
|
22069
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, permissionDiffFile)));
|
|
22070
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, runEventFile)));
|
|
22003
22071
|
for (const [kind, definition] of Object.entries(RESOURCE_SCHEMA)) {
|
|
22004
22072
|
const validator = this.ajv.getSchema(`https://schemas.kxm.dev/vnext/${definition.file}`);
|
|
22005
22073
|
if (!validator) throw new Error(`schema did not compile: ${definition.file}`);
|
|
@@ -22075,7 +22143,7 @@ function schemaIssue(file, error) {
|
|
|
22075
22143
|
return issue2("schema", `schema_${error.keyword}`, file, `${location} ${error.message ?? "is invalid"}${suffix}`);
|
|
22076
22144
|
}
|
|
22077
22145
|
function canonicalHostPath(path4) {
|
|
22078
|
-
const resolved =
|
|
22146
|
+
const resolved = resolve3(path4);
|
|
22079
22147
|
try {
|
|
22080
22148
|
return realpathSync.native(resolved);
|
|
22081
22149
|
} catch {
|
|
@@ -22089,20 +22157,20 @@ function sameHostPath(left, right) {
|
|
|
22089
22157
|
}
|
|
22090
22158
|
function containedHostPath(root, candidate) {
|
|
22091
22159
|
const path4 = relative(root, candidate);
|
|
22092
|
-
return path4 === "" || !
|
|
22160
|
+
return path4 === "" || !isAbsolute2(path4) && path4 !== ".." && !path4.startsWith(`..${sep}`);
|
|
22093
22161
|
}
|
|
22094
22162
|
function portableBindingIssue(root, pathHint, repositoryId) {
|
|
22095
22163
|
let current = root;
|
|
22096
22164
|
for (const segment of pathHint === "." ? [] : pathHint.split("/")) {
|
|
22097
|
-
current =
|
|
22098
|
-
if (!
|
|
22165
|
+
current = join6(current, segment);
|
|
22166
|
+
if (!existsSync6(current)) break;
|
|
22099
22167
|
const stat = lstatSync(current);
|
|
22100
22168
|
if (stat.isSymbolicLink()) {
|
|
22101
22169
|
return issue2("path", "repository_binding_path_link", ".kxm/project.yaml", `portable pathHint for ${repositoryId} traverses a symbolic link or junction`);
|
|
22102
22170
|
}
|
|
22103
22171
|
}
|
|
22104
|
-
const binding =
|
|
22105
|
-
if (
|
|
22172
|
+
const binding = resolve3(root, ...pathHint.split("/"));
|
|
22173
|
+
if (existsSync6(binding)) {
|
|
22106
22174
|
const realRoot = canonicalHostPath(root);
|
|
22107
22175
|
const realBinding = canonicalHostPath(binding);
|
|
22108
22176
|
if (!containedHostPath(realRoot, realBinding)) {
|
|
@@ -22139,10 +22207,10 @@ function readResource(registry, root, file, logicalPath, kind, id, containmentRo
|
|
|
22139
22207
|
fail2("discovery", "resource_missing", label, "resource does not exist");
|
|
22140
22208
|
}
|
|
22141
22209
|
if (stat.isSymbolicLink()) fail2("path", "resource_symlink", label, "configuration resources must not be symbolic links");
|
|
22142
|
-
const boundary =
|
|
22143
|
-
let parent =
|
|
22210
|
+
const boundary = resolve3(containmentRoot);
|
|
22211
|
+
let parent = dirname4(file);
|
|
22144
22212
|
while (parent !== boundary) {
|
|
22145
|
-
if (parent ===
|
|
22213
|
+
if (parent === dirname4(parent)) fail2("path", "resource_outside_project", label, "resource escapes the project root");
|
|
22146
22214
|
let parentStat;
|
|
22147
22215
|
try {
|
|
22148
22216
|
parentStat = lstatSync(parent);
|
|
@@ -22150,33 +22218,33 @@ function readResource(registry, root, file, logicalPath, kind, id, containmentRo
|
|
|
22150
22218
|
fail2("discovery", "resource_parent_missing", label, "resource parent does not exist");
|
|
22151
22219
|
}
|
|
22152
22220
|
if (parentStat.isSymbolicLink()) fail2("path", "resource_parent_symlink", label, "configuration resource parents must not be symbolic links");
|
|
22153
|
-
parent =
|
|
22221
|
+
parent = dirname4(parent);
|
|
22154
22222
|
}
|
|
22155
22223
|
if (!stat.isFile()) fail2("path", "resource_not_file", label, "configuration resource must be a regular file");
|
|
22156
|
-
const value = parseRestrictedYaml2(
|
|
22224
|
+
const value = parseRestrictedYaml2(readFileSync5(file), label);
|
|
22157
22225
|
const issues = registry.validate(kind, value, label);
|
|
22158
22226
|
if (issues.length > 0) throw new VnextConfigError(issues);
|
|
22159
22227
|
return { kind, ...id === void 0 ? {} : { id }, file, logicalPath, value };
|
|
22160
22228
|
}
|
|
22161
22229
|
function readTemplateProvenance(registry, root) {
|
|
22162
|
-
const file =
|
|
22163
|
-
if (!
|
|
22230
|
+
const file = join6(root, ".kxm", "template-provenance.yaml");
|
|
22231
|
+
if (!existsSync6(file)) return void 0;
|
|
22164
22232
|
const label = ".kxm/template-provenance.yaml";
|
|
22165
22233
|
const stat = lstatSync(file);
|
|
22166
22234
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
22167
22235
|
fail2("path", "resource_not_file", label, "template provenance must be a regular file, not a link or directory");
|
|
22168
22236
|
}
|
|
22169
|
-
const configRoot =
|
|
22170
|
-
let parent =
|
|
22237
|
+
const configRoot = join6(root, ".kxm");
|
|
22238
|
+
let parent = dirname4(file);
|
|
22171
22239
|
while (parent !== root) {
|
|
22172
22240
|
const parentStat = lstatSync(parent);
|
|
22173
22241
|
if (parentStat.isSymbolicLink() || !parentStat.isDirectory()) {
|
|
22174
22242
|
fail2("path", "resource_parent_symlink", label, "template provenance parents must be regular directories");
|
|
22175
22243
|
}
|
|
22176
22244
|
if (parent === configRoot) break;
|
|
22177
|
-
parent =
|
|
22245
|
+
parent = dirname4(parent);
|
|
22178
22246
|
}
|
|
22179
|
-
const value = parseRestrictedYaml2(
|
|
22247
|
+
const value = parseRestrictedYaml2(readFileSync5(file), label);
|
|
22180
22248
|
const issues = registry.validateTemplateProvenance(value, label);
|
|
22181
22249
|
if (issues.length > 0) throw new VnextConfigError(issues);
|
|
22182
22250
|
if (!resolveVnextTemplateBaseline(value)) {
|
|
@@ -22207,7 +22275,7 @@ function readTemplateProvenance(registry, root) {
|
|
|
22207
22275
|
}
|
|
22208
22276
|
function listNamedResources(registry, root, directory, logicalDirectory, kind) {
|
|
22209
22277
|
const resources = /* @__PURE__ */ new Map();
|
|
22210
|
-
if (!
|
|
22278
|
+
if (!existsSync6(directory)) return resources;
|
|
22211
22279
|
const stat = lstatSync(directory);
|
|
22212
22280
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
22213
22281
|
fail2("path", "resource_directory_invalid", displayPath(root, directory), "resource directory must be a regular directory");
|
|
@@ -22216,27 +22284,27 @@ function listNamedResources(registry, root, directory, logicalDirectory, kind) {
|
|
|
22216
22284
|
const entries = readdirSync(directory, { withFileTypes: true }).sort((left, right) => compareCodeUnits3(left.name, right.name));
|
|
22217
22285
|
for (const entry of entries) {
|
|
22218
22286
|
if (entry.isDirectory()) {
|
|
22219
|
-
issues.push(issue2("path", "nested_resource_directory", displayPath(root,
|
|
22287
|
+
issues.push(issue2("path", "nested_resource_directory", displayPath(root, join6(directory, entry.name)), "nested resource directories are not allowed"));
|
|
22220
22288
|
continue;
|
|
22221
22289
|
}
|
|
22222
22290
|
if (!entry.name.toLowerCase().endsWith(".yaml") && !entry.name.toLowerCase().endsWith(".yml")) continue;
|
|
22223
22291
|
if (!entry.isFile() || extname(entry.name) !== ".yaml") {
|
|
22224
|
-
issues.push(issue2("path", "resource_filename_invalid", displayPath(root,
|
|
22292
|
+
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
22293
|
continue;
|
|
22226
22294
|
}
|
|
22227
22295
|
const id = basename2(entry.name, ".yaml");
|
|
22228
22296
|
if (kind === "model" && id === "inventory") continue;
|
|
22229
22297
|
if (!resourceIdentifier(id)) {
|
|
22230
|
-
issues.push(issue2("path", "resource_id_invalid", displayPath(root,
|
|
22298
|
+
issues.push(issue2("path", "resource_id_invalid", displayPath(root, join6(directory, entry.name)), `filename-derived identity ${id} is invalid or platform-reserved`));
|
|
22231
22299
|
continue;
|
|
22232
22300
|
}
|
|
22233
22301
|
const collision = [...resources.keys()].find((candidate) => candidate.toLocaleLowerCase("en-US") === id.toLocaleLowerCase("en-US"));
|
|
22234
22302
|
if (collision) {
|
|
22235
|
-
issues.push(issue2("path", "resource_id_collision", displayPath(root,
|
|
22303
|
+
issues.push(issue2("path", "resource_id_collision", displayPath(root, join6(directory, entry.name)), `${id} case-folds to existing ${collision}`));
|
|
22236
22304
|
continue;
|
|
22237
22305
|
}
|
|
22238
22306
|
try {
|
|
22239
|
-
const resource = readResource(registry, root,
|
|
22307
|
+
const resource = readResource(registry, root, join6(directory, entry.name), `${logicalDirectory}/${id}.yaml`, kind, id);
|
|
22240
22308
|
resources.set(id, resource);
|
|
22241
22309
|
} catch (error) {
|
|
22242
22310
|
if (error instanceof VnextConfigError) issues.push(...error.issues);
|
|
@@ -22557,8 +22625,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
22557
22625
|
const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
|
|
22558
22626
|
if (maxWriteRepositories > writable) issues.push(issue2("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
|
|
22559
22627
|
}
|
|
22560
|
-
const
|
|
22561
|
-
const minimumPassed =
|
|
22628
|
+
const join50 = objectValue(step.join);
|
|
22629
|
+
const minimumPassed = join50 && typeof join50.minimumPassed === "number" ? join50.minimumPassed : void 0;
|
|
22562
22630
|
if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue2("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
|
|
22563
22631
|
const distinctBy = names(assignment?.distinctBy);
|
|
22564
22632
|
if (distinctBy.length > 0) {
|
|
@@ -22772,11 +22840,11 @@ function validateBundle(project, repositories, agents, models, workflows, enviro
|
|
|
22772
22840
|
if (!workflows.has(defaultWorkflow)) issues.push(issue2("reference", "default_workflow_unknown", project.logicalPath, `default workflow ${defaultWorkflow} does not exist`));
|
|
22773
22841
|
for (const workflow of workflows.values()) validateWorkflow(workflow, agents, models, repositoryIds, gates, issues);
|
|
22774
22842
|
if (projectRoot) {
|
|
22775
|
-
const writerRolePath =
|
|
22843
|
+
const writerRolePath = join6(projectRoot, ".kxm", "roles", "writer.yaml");
|
|
22776
22844
|
const implementerAgent = agents.get("implementer") ?? agents.get("writer");
|
|
22777
|
-
if (
|
|
22845
|
+
if (existsSync6(writerRolePath) && implementerAgent) {
|
|
22778
22846
|
try {
|
|
22779
|
-
const rawRole = parseRestrictedYaml2(
|
|
22847
|
+
const rawRole = parseRestrictedYaml2(readFileSync5(writerRolePath, "utf8"));
|
|
22780
22848
|
const roleObj = objectValue(rawRole);
|
|
22781
22849
|
const rosterEntries = valuesOf(roleObj ?? {}, "roster").map((candidate) => objectValue(candidate)).filter((entry) => Boolean(entry));
|
|
22782
22850
|
const enabledRosterModels = rosterEntries.filter((entry) => entry.enabled !== false).map((entry) => stringValue(entry.model)).filter((m2) => Boolean(m2));
|
|
@@ -22822,8 +22890,8 @@ function gitEnvironment() {
|
|
|
22822
22890
|
return Object.fromEntries(Object.entries(process.env).filter(([name]) => !name.toUpperCase().startsWith("GIT_")));
|
|
22823
22891
|
}
|
|
22824
22892
|
function discoverGitRoot(start = process.cwd()) {
|
|
22825
|
-
let current =
|
|
22826
|
-
if (
|
|
22893
|
+
let current = resolve3(start);
|
|
22894
|
+
if (existsSync6(current) && !lstatSync(current).isDirectory()) current = dirname4(current);
|
|
22827
22895
|
const result = spawnSync2("git", ["-C", current, "rev-parse", "--show-toplevel"], {
|
|
22828
22896
|
encoding: "utf8",
|
|
22829
22897
|
env: gitEnvironment(),
|
|
@@ -22831,12 +22899,12 @@ function discoverGitRoot(start = process.cwd()) {
|
|
|
22831
22899
|
windowsHide: true
|
|
22832
22900
|
});
|
|
22833
22901
|
if (result.status !== 0 || result.error || !result.stdout.trim()) return void 0;
|
|
22834
|
-
const root =
|
|
22835
|
-
return
|
|
22902
|
+
const root = resolve3(result.stdout.trim());
|
|
22903
|
+
return existsSync6(root) && lstatSync(root).isDirectory() ? root : void 0;
|
|
22836
22904
|
}
|
|
22837
22905
|
function discoverVnextProjectRoot(start = process.cwd()) {
|
|
22838
22906
|
const gitRoot = discoverGitRoot(start);
|
|
22839
|
-
return gitRoot &&
|
|
22907
|
+
return gitRoot && existsSync6(join6(gitRoot, ".kxm", "project.yaml")) ? gitRoot : void 0;
|
|
22840
22908
|
}
|
|
22841
22909
|
function assertNoRegisteredGates(options) {
|
|
22842
22910
|
if ("registeredGates" in options) {
|
|
@@ -22845,7 +22913,7 @@ function assertNoRegisteredGates(options) {
|
|
|
22845
22913
|
}
|
|
22846
22914
|
function loadVnextProject(projectRoot, options = {}) {
|
|
22847
22915
|
assertNoRegisteredGates(options);
|
|
22848
|
-
const root =
|
|
22916
|
+
const root = resolve3(projectRoot);
|
|
22849
22917
|
let migrationReceipt;
|
|
22850
22918
|
if (legacyConfigFilesAt(root).length > 0 && options.allowUnreceiptedLegacyConfig !== true) {
|
|
22851
22919
|
const receiptCheck = readVnextMigrationReceipt(root, options);
|
|
@@ -22853,7 +22921,7 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22853
22921
|
migrationReceipt = receiptCheck.receipt;
|
|
22854
22922
|
}
|
|
22855
22923
|
const registry = new VnextSchemaRegistry(options.schemasDir);
|
|
22856
|
-
const project = readResource(registry, root,
|
|
22924
|
+
const project = readResource(registry, root, join6(root, ".kxm", "project.yaml"), ".kxm/project.yaml", "project");
|
|
22857
22925
|
const earlyIssues = [];
|
|
22858
22926
|
validatePortablePaths(project, earlyIssues);
|
|
22859
22927
|
const templateProvenance = readTemplateProvenance(registry, root);
|
|
@@ -22875,16 +22943,16 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22875
22943
|
}
|
|
22876
22944
|
}
|
|
22877
22945
|
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 =
|
|
22946
|
+
const agents = listNamedResources(registry, root, join6(root, ".kxm", "agents"), ".kxm/agents", "agent");
|
|
22947
|
+
const models = listNamedResources(registry, root, join6(root, ".kxm", "models"), ".kxm/models", "model");
|
|
22948
|
+
const workflows = listNamedResources(registry, root, join6(root, ".kxm", "workflows"), ".kxm/workflows", "workflow");
|
|
22949
|
+
const gatePath = join6(root, ".kxm", "gates.yaml");
|
|
22950
|
+
const gateRegistry = existsSync6(gatePath) ? readResource(registry, root, gatePath, ".kxm/gates.yaml", "gate-registry") : void 0;
|
|
22883
22951
|
const environments = [];
|
|
22884
22952
|
const repositories = /* @__PURE__ */ new Map();
|
|
22885
22953
|
const loadIssues = [];
|
|
22886
|
-
const projectEnvironment =
|
|
22887
|
-
if (
|
|
22954
|
+
const projectEnvironment = join6(root, ".kxm", "project", "env.yaml");
|
|
22955
|
+
if (existsSync6(projectEnvironment)) {
|
|
22888
22956
|
try {
|
|
22889
22957
|
environments.push(readResource(registry, root, projectEnvironment, ".kxm/project/env.yaml", "environment"));
|
|
22890
22958
|
} catch (error) {
|
|
@@ -22902,7 +22970,7 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22902
22970
|
if (!repositoryId) continue;
|
|
22903
22971
|
const hasLocalBinding = Object.hasOwn(options.repositoryBindings ?? {}, repositoryId);
|
|
22904
22972
|
const localBinding = options.repositoryBindings?.[repositoryId];
|
|
22905
|
-
if (hasLocalBinding && (!localBinding || !
|
|
22973
|
+
if (hasLocalBinding && (!localBinding || !isAbsolute2(localBinding))) {
|
|
22906
22974
|
loadIssues.push(issue2("path", "repository_binding_not_absolute", ".kxm/project.yaml", `host-local binding for ${repositoryId} must be absolute`));
|
|
22907
22975
|
continue;
|
|
22908
22976
|
}
|
|
@@ -22921,12 +22989,12 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22921
22989
|
continue;
|
|
22922
22990
|
}
|
|
22923
22991
|
}
|
|
22924
|
-
const binding = hasLocalBinding && localBinding ?
|
|
22992
|
+
const binding = hasLocalBinding && localBinding ? resolve3(localBinding) : role === "control" ? root : pathHint && portablePath(pathHint) ? resolve3(root, ...pathHint.split("/")) : void 0;
|
|
22925
22993
|
if (!binding) {
|
|
22926
22994
|
if (required) loadIssues.push(issue2("discovery", "repository_binding_missing", ".kxm/project.yaml", `required repository ${repositoryId} has no portable pathHint or host-local binding`));
|
|
22927
22995
|
continue;
|
|
22928
22996
|
}
|
|
22929
|
-
if (!
|
|
22997
|
+
if (!existsSync6(binding)) {
|
|
22930
22998
|
if (required || hasLocalBinding) loadIssues.push(issue2("discovery", "repository_binding_unavailable", ".kxm/project.yaml", `${hasLocalBinding ? "explicit" : "required"} repository binding ${repositoryId} is unavailable`));
|
|
22931
22999
|
continue;
|
|
22932
23000
|
}
|
|
@@ -22949,9 +23017,9 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22949
23017
|
continue;
|
|
22950
23018
|
}
|
|
22951
23019
|
seenBindings.set(foldedBinding, repositoryId);
|
|
22952
|
-
const repositoryFile =
|
|
23020
|
+
const repositoryFile = join6(binding, ".kxm", "repo", "repo.yaml");
|
|
22953
23021
|
let definitionValidated = false;
|
|
22954
|
-
if (
|
|
23022
|
+
if (existsSync6(repositoryFile)) {
|
|
22955
23023
|
try {
|
|
22956
23024
|
const resource = readResource(registry, root, repositoryFile, `.kxm/repositories/${repositoryId}/repo.yaml`, "repository", repositoryId, binding);
|
|
22957
23025
|
if (resource.value.repositoryId !== repositoryId) {
|
|
@@ -22967,8 +23035,8 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22967
23035
|
} else if (required || hasLocalBinding) {
|
|
22968
23036
|
loadIssues.push(issue2("discovery", "repository_definition_missing", `.kxm/repositories/${repositoryId}/repo.yaml`, `${hasLocalBinding ? "explicit" : "required"} repository ${repositoryId} has no repo.yaml`));
|
|
22969
23037
|
}
|
|
22970
|
-
const environmentFile =
|
|
22971
|
-
if (
|
|
23038
|
+
const environmentFile = join6(binding, ".kxm", "repo", "env.yaml");
|
|
23039
|
+
if (existsSync6(environmentFile)) {
|
|
22972
23040
|
if (!definitionValidated) {
|
|
22973
23041
|
loadIssues.push(issue2("reference", "repository_environment_without_definition", `.kxm/repositories/${repositoryId}/env.yaml`, `repository ${repositoryId} environment requires a validated matching repo.yaml`));
|
|
22974
23042
|
} else {
|
|
@@ -23036,7 +23104,7 @@ function verifyVnextMigrationReceiptTarget(root, receipt, resources, configRevis
|
|
|
23036
23104
|
}
|
|
23037
23105
|
function relativePortable(root, absolute) {
|
|
23038
23106
|
const rel = relative(root, absolute);
|
|
23039
|
-
if (!rel ||
|
|
23107
|
+
if (!rel || isAbsolute2(rel) || rel === ".." || rel.startsWith(`..${sep}`)) return void 0;
|
|
23040
23108
|
return rel.split(sep).join("/");
|
|
23041
23109
|
}
|
|
23042
23110
|
function legacyInputsAt(root) {
|
|
@@ -23046,21 +23114,21 @@ function legacyInputsAt(root) {
|
|
|
23046
23114
|
".kxm/config/workflows",
|
|
23047
23115
|
".kxm/state/kxm.db"
|
|
23048
23116
|
];
|
|
23049
|
-
return candidates.filter((candidate) =>
|
|
23117
|
+
return candidates.filter((candidate) => existsSync6(join6(root, ...candidate.split("/"))));
|
|
23050
23118
|
}
|
|
23051
23119
|
var VNEXT_MIGRATION_RECEIPT_PATH = ".kxm/migration-receipt.yaml";
|
|
23052
23120
|
var LEGACY_CONFIG_FILES = [".kxm/config/agents.json", ".kxm/config/gates.json"];
|
|
23053
23121
|
function legacyConfigFilesAt(root) {
|
|
23054
23122
|
const files = [];
|
|
23055
23123
|
for (const component of [".kxm", ".kxm/config"]) {
|
|
23056
|
-
const absolute =
|
|
23057
|
-
if (
|
|
23124
|
+
const absolute = join6(root, ...component.split("/"));
|
|
23125
|
+
if (existsSync6(absolute) && lstatSync(absolute).isSymbolicLink()) return [component];
|
|
23058
23126
|
}
|
|
23059
23127
|
for (const candidate of LEGACY_CONFIG_FILES) {
|
|
23060
|
-
if (
|
|
23128
|
+
if (existsSync6(join6(root, ...candidate.split("/")))) files.push(candidate);
|
|
23061
23129
|
}
|
|
23062
|
-
const workflowsDir =
|
|
23063
|
-
if (
|
|
23130
|
+
const workflowsDir = join6(root, ".kxm", "config", "workflows");
|
|
23131
|
+
if (existsSync6(workflowsDir)) {
|
|
23064
23132
|
const stat = lstatSync(workflowsDir);
|
|
23065
23133
|
if (stat.isSymbolicLink()) {
|
|
23066
23134
|
files.push(".kxm/config/workflows");
|
|
@@ -23075,9 +23143,9 @@ function legacyConfigFilesAt(root) {
|
|
|
23075
23143
|
return files;
|
|
23076
23144
|
}
|
|
23077
23145
|
function hashFileRecord(root, relativePath) {
|
|
23078
|
-
const absolute =
|
|
23079
|
-
if (!
|
|
23080
|
-
const bytes =
|
|
23146
|
+
const absolute = join6(root, ...relativePath.split("/"));
|
|
23147
|
+
if (!existsSync6(absolute)) return void 0;
|
|
23148
|
+
const bytes = readFileSync5(absolute);
|
|
23081
23149
|
return {
|
|
23082
23150
|
path: relativePath,
|
|
23083
23151
|
sha256: `sha256:${createHash6("sha256").update(bytes).digest("hex")}`,
|
|
@@ -23089,9 +23157,9 @@ function migrationReceiptSelfHash(receipt) {
|
|
|
23089
23157
|
return `sha256:${createHash6("sha256").update(vnextCanonicalJson(unsigned), "utf8").digest("hex")}`;
|
|
23090
23158
|
}
|
|
23091
23159
|
function readVnextMigrationReceipt(root, options = {}) {
|
|
23092
|
-
const receiptPath =
|
|
23160
|
+
const receiptPath = join6(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
|
|
23093
23161
|
const legacyFiles = legacyConfigFilesAt(root);
|
|
23094
|
-
if (!
|
|
23162
|
+
if (!existsSync6(receiptPath)) {
|
|
23095
23163
|
return {
|
|
23096
23164
|
issues: legacyFiles.map((file) => issue2("semantic", "legacy_vnext_conflict", file, "legacy and vNext configuration cannot coexist before an accepted migration receipt"))
|
|
23097
23165
|
};
|
|
@@ -23102,7 +23170,7 @@ function readVnextMigrationReceipt(root, options = {}) {
|
|
|
23102
23170
|
}
|
|
23103
23171
|
let receipt;
|
|
23104
23172
|
try {
|
|
23105
|
-
receipt = parseRestrictedYaml2(
|
|
23173
|
+
receipt = parseRestrictedYaml2(readFileSync5(receiptPath), VNEXT_MIGRATION_RECEIPT_PATH);
|
|
23106
23174
|
} catch (error) {
|
|
23107
23175
|
if (error instanceof VnextConfigError) return { issues: [...error.issues] };
|
|
23108
23176
|
throw error;
|
|
@@ -23135,14 +23203,14 @@ function readVnextMigrationReceipt(root, options = {}) {
|
|
|
23135
23203
|
return issues.length > 0 ? { issues } : { receipt, issues: [] };
|
|
23136
23204
|
}
|
|
23137
23205
|
function discoverLegacyRoot(start) {
|
|
23138
|
-
let initial =
|
|
23139
|
-
if (
|
|
23206
|
+
let initial = resolve3(start);
|
|
23207
|
+
if (existsSync6(initial) && !lstatSync(initial).isDirectory()) initial = dirname4(initial);
|
|
23140
23208
|
const candidate = discoverGitRoot(initial) ?? initial;
|
|
23141
23209
|
const inputs = legacyInputsAt(candidate);
|
|
23142
23210
|
return inputs.length > 0 ? { root: candidate, inputs } : void 0;
|
|
23143
23211
|
}
|
|
23144
23212
|
function planVnextInitialization(start = process.cwd(), options = {}) {
|
|
23145
|
-
const inspectedFrom =
|
|
23213
|
+
const inspectedFrom = resolve3(start);
|
|
23146
23214
|
const projectRoot = discoverVnextProjectRoot(inspectedFrom);
|
|
23147
23215
|
if (projectRoot) {
|
|
23148
23216
|
try {
|
|
@@ -23163,7 +23231,7 @@ function planVnextInitialization(start = process.cwd(), options = {}) {
|
|
|
23163
23231
|
}
|
|
23164
23232
|
const gitRoot = discoverGitRoot(inspectedFrom);
|
|
23165
23233
|
const candidateRoot = gitRoot ?? inspectedFrom;
|
|
23166
|
-
if (
|
|
23234
|
+
if (existsSync6(join6(candidateRoot, ".kxm"))) {
|
|
23167
23235
|
return {
|
|
23168
23236
|
mode: "repair",
|
|
23169
23237
|
inspectedFrom,
|
|
@@ -23179,13 +23247,13 @@ function planVnextInitialization(start = process.cwd(), options = {}) {
|
|
|
23179
23247
|
// plugins/kxm/src/vnext-runtime-supervisor.ts
|
|
23180
23248
|
import { spawn as spawn2 } from "node:child_process";
|
|
23181
23249
|
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
|
|
23250
|
+
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";
|
|
23251
|
+
import { dirname as dirname8, isAbsolute as isAbsolute5, join as join12 } from "node:path";
|
|
23184
23252
|
|
|
23185
23253
|
// plugins/kxm/src/vnext-runtime-store.ts
|
|
23186
23254
|
import { createHash as createHash9, randomUUID as randomUUID4 } from "node:crypto";
|
|
23187
|
-
import { existsSync as
|
|
23188
|
-
import { dirname as
|
|
23255
|
+
import { existsSync as existsSync9, lstatSync as lstatSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync8, realpathSync as realpathSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
23256
|
+
import { dirname as dirname7, join as join9, resolve as resolve6 } from "node:path";
|
|
23189
23257
|
|
|
23190
23258
|
// plugins/kxm/src/vnext-bindings.ts
|
|
23191
23259
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
@@ -23193,18 +23261,18 @@ import { createHash as createHash7, randomUUID as randomUUID3 } from "node:crypt
|
|
|
23193
23261
|
import {
|
|
23194
23262
|
chmodSync as chmodSync2,
|
|
23195
23263
|
closeSync,
|
|
23196
|
-
existsSync as
|
|
23264
|
+
existsSync as existsSync7,
|
|
23197
23265
|
fsyncSync,
|
|
23198
23266
|
lstatSync as lstatSync2,
|
|
23199
|
-
mkdirSync as
|
|
23267
|
+
mkdirSync as mkdirSync4,
|
|
23200
23268
|
openSync,
|
|
23201
|
-
readFileSync as
|
|
23269
|
+
readFileSync as readFileSync6,
|
|
23202
23270
|
realpathSync as realpathSync2,
|
|
23203
|
-
renameSync,
|
|
23204
|
-
rmSync,
|
|
23205
|
-
writeFileSync as
|
|
23271
|
+
renameSync as renameSync2,
|
|
23272
|
+
rmSync as rmSync2,
|
|
23273
|
+
writeFileSync as writeFileSync4
|
|
23206
23274
|
} from "node:fs";
|
|
23207
|
-
import { homedir as
|
|
23275
|
+
import { homedir as homedir3 } from "node:os";
|
|
23208
23276
|
|
|
23209
23277
|
// plugins/kxm/src/sqlite.ts
|
|
23210
23278
|
import { createRequire } from "node:module";
|
|
@@ -23246,7 +23314,7 @@ var DatabaseSync = class {
|
|
|
23246
23314
|
};
|
|
23247
23315
|
|
|
23248
23316
|
// plugins/kxm/src/vnext-bindings.ts
|
|
23249
|
-
import { dirname as
|
|
23317
|
+
import { dirname as dirname5, isAbsolute as isAbsolute3, join as join7, parse, relative as relative2, resolve as resolve4, sep as sep2 } from "node:path";
|
|
23250
23318
|
var MAX_BINDING_RECORD_BYTES = 256 * 1024;
|
|
23251
23319
|
var BINDING_LABEL = "Runtime-local repository bindings";
|
|
23252
23320
|
var activeLocks = /* @__PURE__ */ new WeakSet();
|
|
@@ -23257,7 +23325,7 @@ function bindingError(phase, code, message) {
|
|
|
23257
23325
|
throw new VnextConfigError([bindingIssue(phase, code, message)]);
|
|
23258
23326
|
}
|
|
23259
23327
|
function canonicalHostPath2(path4) {
|
|
23260
|
-
const absolute =
|
|
23328
|
+
const absolute = resolve4(path4);
|
|
23261
23329
|
try {
|
|
23262
23330
|
return realpathSync2.native(absolute);
|
|
23263
23331
|
} catch {
|
|
@@ -23272,21 +23340,21 @@ function sameHostPath2(left, right, platform = process.platform) {
|
|
|
23272
23340
|
function vnextUserStateRoot(options = {}) {
|
|
23273
23341
|
const env = options.env ?? process.env;
|
|
23274
23342
|
const platform = options.platform ?? process.platform;
|
|
23275
|
-
const home = options.homeDir ??
|
|
23343
|
+
const home = options.homeDir ?? homedir3();
|
|
23276
23344
|
const explicit = options.stateRoot ?? env.KXM_STATE_HOME?.trim();
|
|
23277
23345
|
if (explicit) {
|
|
23278
|
-
if (!
|
|
23279
|
-
return
|
|
23346
|
+
if (!isAbsolute3(explicit)) bindingError("path", "local_state_root_not_absolute", "KXM_STATE_HOME must be an absolute host-local path");
|
|
23347
|
+
return resolve4(explicit);
|
|
23280
23348
|
}
|
|
23281
23349
|
if (platform === "win32") {
|
|
23282
23350
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
23283
|
-
const base2 = localAppData &&
|
|
23284
|
-
return
|
|
23351
|
+
const base2 = localAppData && isAbsolute3(localAppData) ? localAppData : join7(home, "AppData", "Local");
|
|
23352
|
+
return resolve4(base2, "KXM");
|
|
23285
23353
|
}
|
|
23286
|
-
if (platform === "darwin") return
|
|
23354
|
+
if (platform === "darwin") return resolve4(home, "Library", "Application Support", "KXM");
|
|
23287
23355
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
23288
|
-
const base = xdgState &&
|
|
23289
|
-
return
|
|
23356
|
+
const base = xdgState && isAbsolute3(xdgState) ? xdgState : join7(home, ".local", "state");
|
|
23357
|
+
return resolve4(base, "kxm");
|
|
23290
23358
|
}
|
|
23291
23359
|
function projectBindingKey(projectRoot, platform = process.platform) {
|
|
23292
23360
|
const canonical2 = canonicalHostPath2(projectRoot);
|
|
@@ -23295,10 +23363,10 @@ function projectBindingKey(projectRoot, platform = process.platform) {
|
|
|
23295
23363
|
}
|
|
23296
23364
|
function vnextLocalBindingFile(projectRoot, options = {}) {
|
|
23297
23365
|
const stateRoot = vnextUserStateRoot(options);
|
|
23298
|
-
return
|
|
23366
|
+
return join7(stateRoot, "projects", projectBindingKey(projectRoot, options.platform), "repository-bindings.json");
|
|
23299
23367
|
}
|
|
23300
23368
|
function checkedDirectory(path4, description) {
|
|
23301
|
-
if (!
|
|
23369
|
+
if (!existsSync7(path4)) return false;
|
|
23302
23370
|
const stat = lstatSync2(path4);
|
|
23303
23371
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23304
23372
|
bindingError("path", "local_binding_directory_invalid", `${description} must be a regular directory, not a link or file`);
|
|
@@ -23306,8 +23374,8 @@ function checkedDirectory(path4, description) {
|
|
|
23306
23374
|
return true;
|
|
23307
23375
|
}
|
|
23308
23376
|
function existingBindingDirectory(file, stateRoot) {
|
|
23309
|
-
const projects =
|
|
23310
|
-
const project =
|
|
23377
|
+
const projects = join7(stateRoot, "projects");
|
|
23378
|
+
const project = dirname5(file);
|
|
23311
23379
|
if (!checkedDirectory(stateRoot, "local state root")) return false;
|
|
23312
23380
|
if (!checkedDirectory(projects, "local projects directory")) return false;
|
|
23313
23381
|
return checkedDirectory(project, "local project binding directory");
|
|
@@ -23330,10 +23398,10 @@ function asRecord2(value, file, projectRoot, schemasDir) {
|
|
|
23330
23398
|
};
|
|
23331
23399
|
}
|
|
23332
23400
|
function readVnextLocalBindings(projectRoot, options = {}) {
|
|
23333
|
-
const root =
|
|
23401
|
+
const root = resolve4(projectRoot);
|
|
23334
23402
|
const stateRoot = vnextUserStateRoot(options);
|
|
23335
23403
|
const file = vnextLocalBindingFile(root, options);
|
|
23336
|
-
if (!existingBindingDirectory(file, stateRoot) || !
|
|
23404
|
+
if (!existingBindingDirectory(file, stateRoot) || !existsSync7(file)) return void 0;
|
|
23337
23405
|
const stat = lstatSync2(file);
|
|
23338
23406
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
23339
23407
|
bindingError("path", "local_binding_file_invalid", "binding record must be a regular file, not a link or directory");
|
|
@@ -23341,12 +23409,12 @@ function readVnextLocalBindings(projectRoot, options = {}) {
|
|
|
23341
23409
|
if (stat.size > MAX_BINDING_RECORD_BYTES) {
|
|
23342
23410
|
bindingError("parse", "local_binding_file_too_large", `binding record exceeds ${MAX_BINDING_RECORD_BYTES} bytes`);
|
|
23343
23411
|
}
|
|
23344
|
-
const parsed = parseRestrictedYaml2(
|
|
23412
|
+
const parsed = parseRestrictedYaml2(readFileSync6(file), BINDING_LABEL);
|
|
23345
23413
|
return asRecord2(parsed, file, root, options.schemasDir);
|
|
23346
23414
|
}
|
|
23347
23415
|
function normalizedRecord(projectRoot, projectId, repositories, schemasDir) {
|
|
23348
23416
|
const normalizedRepositories = Object.fromEntries(Object.entries(repositories).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([repositoryId, path4]) => {
|
|
23349
|
-
if (!
|
|
23417
|
+
if (!isAbsolute3(path4)) bindingError("path", "repository_binding_not_absolute", `host-local binding for ${repositoryId} must be absolute`);
|
|
23350
23418
|
return [repositoryId, canonicalHostPath2(path4)];
|
|
23351
23419
|
}));
|
|
23352
23420
|
const value = {
|
|
@@ -23381,48 +23449,48 @@ function syncDirectory(path4) {
|
|
|
23381
23449
|
}
|
|
23382
23450
|
}
|
|
23383
23451
|
function createDirectoryIfMissing(path4) {
|
|
23384
|
-
if (
|
|
23452
|
+
if (existsSync7(path4)) return;
|
|
23385
23453
|
try {
|
|
23386
|
-
|
|
23387
|
-
syncDirectory(
|
|
23454
|
+
mkdirSync4(path4, { mode: 448 });
|
|
23455
|
+
syncDirectory(dirname5(path4));
|
|
23388
23456
|
} catch (error) {
|
|
23389
23457
|
if (error.code !== "EEXIST") throw error;
|
|
23390
23458
|
}
|
|
23391
23459
|
}
|
|
23392
23460
|
function ensureDurableDirectory(path4, description) {
|
|
23393
23461
|
const missing = [];
|
|
23394
|
-
let current =
|
|
23395
|
-
while (!
|
|
23462
|
+
let current = resolve4(path4);
|
|
23463
|
+
while (!existsSync7(current)) {
|
|
23396
23464
|
missing.push(current);
|
|
23397
|
-
const parent =
|
|
23465
|
+
const parent = dirname5(current);
|
|
23398
23466
|
if (parent === current) bindingError("path", "local_binding_directory_invalid", `${description} has no existing filesystem ancestor`);
|
|
23399
23467
|
current = parent;
|
|
23400
23468
|
}
|
|
23401
23469
|
checkedDirectory(current, `${description} ancestor`);
|
|
23402
23470
|
for (const directory of missing.reverse()) {
|
|
23403
|
-
|
|
23471
|
+
mkdirSync4(directory, { mode: 448 });
|
|
23404
23472
|
checkedDirectory(directory, description);
|
|
23405
|
-
syncDirectory(
|
|
23473
|
+
syncDirectory(dirname5(directory));
|
|
23406
23474
|
}
|
|
23407
23475
|
}
|
|
23408
23476
|
function ensureBindingDirectory(file, stateRoot) {
|
|
23409
23477
|
ensureDurableDirectory(stateRoot, "local state root");
|
|
23410
23478
|
checkedDirectory(stateRoot, "local state root");
|
|
23411
23479
|
syncDirectory(stateRoot);
|
|
23412
|
-
const projects =
|
|
23480
|
+
const projects = join7(stateRoot, "projects");
|
|
23413
23481
|
createDirectoryIfMissing(projects);
|
|
23414
23482
|
checkedDirectory(projects, "local projects directory");
|
|
23415
|
-
const project =
|
|
23483
|
+
const project = dirname5(file);
|
|
23416
23484
|
createDirectoryIfMissing(project);
|
|
23417
23485
|
checkedDirectory(project, "local project binding directory");
|
|
23418
23486
|
}
|
|
23419
23487
|
function assertNoLinkedDirectoryComponents(path4, description) {
|
|
23420
|
-
const absolute =
|
|
23488
|
+
const absolute = resolve4(path4);
|
|
23421
23489
|
const filesystemRoot = parse(absolute).root;
|
|
23422
23490
|
let current = filesystemRoot;
|
|
23423
23491
|
const remainder = relative2(filesystemRoot, absolute);
|
|
23424
23492
|
for (const segment of remainder.split(sep2).filter(Boolean)) {
|
|
23425
|
-
current =
|
|
23493
|
+
current = join7(current, segment);
|
|
23426
23494
|
const stat = lstatSync2(current);
|
|
23427
23495
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23428
23496
|
bindingError("path", "project_operation_lock_parent_invalid", `${description} contains a linked or non-directory component`);
|
|
@@ -23443,28 +23511,28 @@ function projectOperationLockFile(projectRoot) {
|
|
|
23443
23511
|
if (result.status !== 0 || result.error || !result.stdout.trim()) {
|
|
23444
23512
|
bindingError("discovery", "project_operation_lock_unavailable", "cannot resolve the authoritative Git metadata path for project locking");
|
|
23445
23513
|
}
|
|
23446
|
-
const gitDirectory =
|
|
23514
|
+
const gitDirectory = resolve4(result.stdout.trim());
|
|
23447
23515
|
assertNoLinkedDirectoryComponents(gitDirectory, "authoritative Git metadata path");
|
|
23448
23516
|
const gitStat = lstatSync2(gitDirectory);
|
|
23449
23517
|
if (gitStat.isSymbolicLink() || !gitStat.isDirectory()) {
|
|
23450
23518
|
bindingError("path", "project_operation_lock_parent_invalid", "authoritative Git metadata must resolve to a regular directory");
|
|
23451
23519
|
}
|
|
23452
|
-
const lockDirectory =
|
|
23453
|
-
if (
|
|
23520
|
+
const lockDirectory = join7(gitDirectory, "kxm");
|
|
23521
|
+
if (existsSync7(lockDirectory)) {
|
|
23454
23522
|
const stat = lstatSync2(lockDirectory);
|
|
23455
23523
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23456
23524
|
bindingError("path", "project_operation_lock_parent_invalid", "Git-local KXM lock directory must be regular, not a link or file");
|
|
23457
23525
|
}
|
|
23458
23526
|
} else {
|
|
23459
|
-
|
|
23527
|
+
mkdirSync4(lockDirectory, { mode: 448 });
|
|
23460
23528
|
syncDirectory(gitDirectory);
|
|
23461
23529
|
}
|
|
23462
|
-
return
|
|
23530
|
+
return join7(lockDirectory, "project-operation-lock.sqlite");
|
|
23463
23531
|
}
|
|
23464
23532
|
function withVnextLocalBindingLock(projectRoot, options, callback) {
|
|
23465
|
-
const root =
|
|
23533
|
+
const root = resolve4(projectRoot);
|
|
23466
23534
|
const file = projectOperationLockFile(root);
|
|
23467
|
-
if (
|
|
23535
|
+
if (existsSync7(file)) {
|
|
23468
23536
|
const stat = lstatSync2(file);
|
|
23469
23537
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
23470
23538
|
bindingError("path", "local_binding_lock_invalid", "project-operation lock must be a regular file, not a link or directory");
|
|
@@ -23497,7 +23565,7 @@ function withVnextLocalBindingLock(projectRoot, options, callback) {
|
|
|
23497
23565
|
}
|
|
23498
23566
|
}
|
|
23499
23567
|
function planVnextLocalBindings(projectRoot, projectId, repositories, options = {}) {
|
|
23500
|
-
const root =
|
|
23568
|
+
const root = resolve4(projectRoot);
|
|
23501
23569
|
const file = vnextLocalBindingFile(root, options);
|
|
23502
23570
|
const record = normalizedRecord(root, projectId, repositories, options.schemasDir);
|
|
23503
23571
|
const existing = readVnextLocalBindings(root, options);
|
|
@@ -23507,7 +23575,7 @@ function planVnextLocalBindings(projectRoot, projectId, repositories, options =
|
|
|
23507
23575
|
return { file, written: !existing || !recordsEqual(existing, record), record };
|
|
23508
23576
|
}
|
|
23509
23577
|
function writeVnextLocalBindings(projectRoot, projectId, repositories, options = {}, lock) {
|
|
23510
|
-
const root =
|
|
23578
|
+
const root = resolve4(projectRoot);
|
|
23511
23579
|
if (!lock) {
|
|
23512
23580
|
return withVnextLocalBindingLock(root, options, (acquired) => writeVnextLocalBindings(root, projectId, repositories, options, acquired));
|
|
23513
23581
|
}
|
|
@@ -23518,20 +23586,20 @@ function writeVnextLocalBindings(projectRoot, projectId, repositories, options =
|
|
|
23518
23586
|
const { file, record } = planned;
|
|
23519
23587
|
if (!planned.written) return planned;
|
|
23520
23588
|
ensureBindingDirectory(file, vnextUserStateRoot(options));
|
|
23521
|
-
const temporary =
|
|
23589
|
+
const temporary = join7(dirname5(file), `.repository-bindings-${process.pid}-${randomUUID3()}.tmp`);
|
|
23522
23590
|
let descriptor;
|
|
23523
23591
|
try {
|
|
23524
23592
|
descriptor = openSync(temporary, "wx", 384);
|
|
23525
|
-
|
|
23593
|
+
writeFileSync4(descriptor, `${JSON.stringify(record, null, 2)}
|
|
23526
23594
|
`, "utf8");
|
|
23527
23595
|
fsyncSync(descriptor);
|
|
23528
23596
|
closeSync(descriptor);
|
|
23529
23597
|
descriptor = void 0;
|
|
23530
|
-
|
|
23531
|
-
syncDirectory(
|
|
23598
|
+
renameSync2(temporary, file);
|
|
23599
|
+
syncDirectory(dirname5(file));
|
|
23532
23600
|
} finally {
|
|
23533
23601
|
if (descriptor !== void 0) closeSync(descriptor);
|
|
23534
|
-
|
|
23602
|
+
rmSync2(temporary, { force: true });
|
|
23535
23603
|
}
|
|
23536
23604
|
const verified = readVnextLocalBindings(root, options);
|
|
23537
23605
|
if (!verified || !recordsEqual(verified, record)) {
|
|
@@ -23545,22 +23613,22 @@ import { createHash as createHash8, randomBytes } from "node:crypto";
|
|
|
23545
23613
|
import {
|
|
23546
23614
|
chmodSync as chmodSync3,
|
|
23547
23615
|
copyFileSync,
|
|
23548
|
-
existsSync as
|
|
23616
|
+
existsSync as existsSync8,
|
|
23549
23617
|
lstatSync as lstatSync3,
|
|
23550
|
-
mkdirSync as
|
|
23618
|
+
mkdirSync as mkdirSync5,
|
|
23551
23619
|
readdirSync as readdirSync2,
|
|
23552
|
-
readFileSync as
|
|
23620
|
+
readFileSync as readFileSync7,
|
|
23553
23621
|
unlinkSync as unlinkSync2,
|
|
23554
|
-
writeFileSync as
|
|
23622
|
+
writeFileSync as writeFileSync5
|
|
23555
23623
|
} from "node:fs";
|
|
23556
|
-
import { basename as basename3, dirname as
|
|
23624
|
+
import { basename as basename3, dirname as dirname6, join as join8, resolve as resolve5 } from "node:path";
|
|
23557
23625
|
function databaseError(code, file, message) {
|
|
23558
23626
|
const issue3 = { phase: "semantic", code, file, message };
|
|
23559
23627
|
return new VnextConfigError([issue3]);
|
|
23560
23628
|
}
|
|
23561
23629
|
function checkedParent(path4, description) {
|
|
23562
|
-
const parent =
|
|
23563
|
-
if (!
|
|
23630
|
+
const parent = dirname6(path4);
|
|
23631
|
+
if (!existsSync8(parent)) mkdirSync5(parent, { recursive: true, mode: 448 });
|
|
23564
23632
|
const stat = lstatSync3(parent, { throwIfNoEntry: false });
|
|
23565
23633
|
if (!stat || stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23566
23634
|
throw databaseError("runtime_path_invalid", description, `${description} parent must be a regular directory, not a link`);
|
|
@@ -23702,18 +23770,18 @@ function checkIntegrity(database) {
|
|
|
23702
23770
|
return rows.length === 1 && rows[0]?.integrity_check === "ok";
|
|
23703
23771
|
}
|
|
23704
23772
|
function fileSha256(filePath) {
|
|
23705
|
-
const bytes =
|
|
23773
|
+
const bytes = readFileSync7(filePath);
|
|
23706
23774
|
return `sha256:${createHash8("sha256").update(bytes).digest("hex")}`;
|
|
23707
23775
|
}
|
|
23708
23776
|
function backupDatabaseFile(sourcePath, targetPath, storeId) {
|
|
23709
|
-
const resolvedSource =
|
|
23710
|
-
const resolvedTarget =
|
|
23777
|
+
const resolvedSource = resolve5(sourcePath);
|
|
23778
|
+
const resolvedTarget = resolve5(targetPath);
|
|
23711
23779
|
const sourceStat = lstatSync3(resolvedSource, { throwIfNoEntry: false });
|
|
23712
23780
|
if (!sourceStat || !sourceStat.isFile() || sourceStat.isSymbolicLink()) {
|
|
23713
23781
|
throw databaseError("runtime_path_invalid", resolvedSource, `source database ${resolvedSource} must be a regular file, not a link or directory`);
|
|
23714
23782
|
}
|
|
23715
23783
|
checkedParent(resolvedTarget, "backup target");
|
|
23716
|
-
if (
|
|
23784
|
+
if (existsSync8(resolvedTarget)) {
|
|
23717
23785
|
unlinkSync2(resolvedTarget);
|
|
23718
23786
|
}
|
|
23719
23787
|
const sourceDb = new DatabaseSync(resolvedSource);
|
|
@@ -23757,8 +23825,8 @@ function backupDatabaseFile(sourcePath, targetPath, storeId) {
|
|
|
23757
23825
|
};
|
|
23758
23826
|
}
|
|
23759
23827
|
function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVersion, maxSupportedVersion) {
|
|
23760
|
-
const resolvedBackup =
|
|
23761
|
-
const resolvedTarget =
|
|
23828
|
+
const resolvedBackup = resolve5(backupPath);
|
|
23829
|
+
const resolvedTarget = resolve5(targetPath);
|
|
23762
23830
|
const backupStat = lstatSync3(resolvedBackup, { throwIfNoEntry: false });
|
|
23763
23831
|
if (!backupStat || !backupStat.isFile() || backupStat.isSymbolicLink()) {
|
|
23764
23832
|
throw databaseError("runtime_path_invalid", resolvedBackup, `backup database ${resolvedBackup} must be a regular file, not a link or directory`);
|
|
@@ -23791,7 +23859,7 @@ function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVers
|
|
|
23791
23859
|
}
|
|
23792
23860
|
checkedParent(resolvedTarget, "restore target");
|
|
23793
23861
|
for (const file of [resolvedTarget, `${resolvedTarget}-wal`, `${resolvedTarget}-shm`]) {
|
|
23794
|
-
if (
|
|
23862
|
+
if (existsSync8(file)) {
|
|
23795
23863
|
try {
|
|
23796
23864
|
unlinkSync2(file);
|
|
23797
23865
|
} catch {
|
|
@@ -23821,29 +23889,29 @@ function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVers
|
|
|
23821
23889
|
};
|
|
23822
23890
|
}
|
|
23823
23891
|
function discoverProjectStores(projectRoot, options = {}) {
|
|
23824
|
-
const root =
|
|
23892
|
+
const root = resolve5(projectRoot);
|
|
23825
23893
|
const stores = [];
|
|
23826
|
-
const hubPath = options.hubDataPath ?
|
|
23827
|
-
if (
|
|
23894
|
+
const hubPath = options.hubDataPath ? resolve5(options.hubDataPath) : join8(root, ".kxm", "state", "kxm.db");
|
|
23895
|
+
if (existsSync8(hubPath)) {
|
|
23828
23896
|
stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: 3 });
|
|
23829
23897
|
}
|
|
23830
|
-
const registryPath =
|
|
23831
|
-
if (
|
|
23898
|
+
const registryPath = join8(root, ".kxm", "runtime", "registry.db");
|
|
23899
|
+
if (existsSync8(registryPath)) {
|
|
23832
23900
|
stores.push({ storeId: "registry", sourcePath: registryPath, maxSupportedVersion: 1 });
|
|
23833
23901
|
}
|
|
23834
|
-
const bindingsPath =
|
|
23835
|
-
if (
|
|
23902
|
+
const bindingsPath = join8(root, ".kxm", "runtime", "bindings.db");
|
|
23903
|
+
if (existsSync8(bindingsPath)) {
|
|
23836
23904
|
stores.push({ storeId: "binding-store", sourcePath: bindingsPath, maxSupportedVersion: 1 });
|
|
23837
23905
|
}
|
|
23838
|
-
const eventsDir =
|
|
23839
|
-
if (
|
|
23906
|
+
const eventsDir = join8(root, ".kxm", "runtime", "events");
|
|
23907
|
+
if (existsSync8(eventsDir)) {
|
|
23840
23908
|
const entries = readdirSync2(eventsDir, { withFileTypes: true });
|
|
23841
23909
|
for (const entry of entries) {
|
|
23842
23910
|
if (entry.isFile() && entry.name.endsWith(".db")) {
|
|
23843
23911
|
const key = entry.name.replace(/\.db$/, "");
|
|
23844
23912
|
stores.push({
|
|
23845
23913
|
storeId: `events:${key}`,
|
|
23846
|
-
sourcePath:
|
|
23914
|
+
sourcePath: join8(eventsDir, entry.name),
|
|
23847
23915
|
maxSupportedVersion: 3
|
|
23848
23916
|
});
|
|
23849
23917
|
}
|
|
@@ -23852,7 +23920,7 @@ function discoverProjectStores(projectRoot, options = {}) {
|
|
|
23852
23920
|
return stores;
|
|
23853
23921
|
}
|
|
23854
23922
|
function createBackup(options = {}) {
|
|
23855
|
-
const projectRoot = options.projectRoot ?
|
|
23923
|
+
const projectRoot = options.projectRoot ? resolve5(options.projectRoot) : process.cwd();
|
|
23856
23924
|
const stores = discoverProjectStores(projectRoot, {
|
|
23857
23925
|
...options.hubDataPath !== void 0 ? { hubDataPath: options.hubDataPath } : {}
|
|
23858
23926
|
});
|
|
@@ -23862,9 +23930,9 @@ function createBackup(options = {}) {
|
|
|
23862
23930
|
const now = /* @__PURE__ */ new Date();
|
|
23863
23931
|
const timestamp = now.toISOString().replace(/[:.]/g, "-");
|
|
23864
23932
|
const backupId = `bk_${randomBytes(8).toString("hex")}`;
|
|
23865
|
-
const outDir = options.outDir ?
|
|
23866
|
-
if (!
|
|
23867
|
-
|
|
23933
|
+
const outDir = options.outDir ? resolve5(options.outDir) : join8(projectRoot, ".kxm", "backups", `backup-${timestamp}`);
|
|
23934
|
+
if (!existsSync8(outDir)) {
|
|
23935
|
+
mkdirSync5(outDir, { recursive: true, mode: 448 });
|
|
23868
23936
|
}
|
|
23869
23937
|
const backedUpStores = [];
|
|
23870
23938
|
const usedFilenames = /* @__PURE__ */ new Set();
|
|
@@ -23875,7 +23943,7 @@ function createBackup(options = {}) {
|
|
|
23875
23943
|
filename = `${sanitizedId}-${filename}`;
|
|
23876
23944
|
}
|
|
23877
23945
|
usedFilenames.add(filename);
|
|
23878
|
-
const targetFile2 =
|
|
23946
|
+
const targetFile2 = join8(outDir, filename);
|
|
23879
23947
|
const record = backupDatabaseFile(store.sourcePath, targetFile2, store.storeId);
|
|
23880
23948
|
backedUpStores.push(record);
|
|
23881
23949
|
}
|
|
@@ -23890,24 +23958,24 @@ function createBackup(options = {}) {
|
|
|
23890
23958
|
const manifestSha256 = `sha256:${createHash8("sha256").update(manifestJson, "utf8").digest("hex")}`;
|
|
23891
23959
|
manifest.manifestSha256 = manifestSha256;
|
|
23892
23960
|
const finalJson = JSON.stringify(manifest, null, 2) + "\n";
|
|
23893
|
-
const manifestPath =
|
|
23894
|
-
|
|
23961
|
+
const manifestPath = join8(outDir, "manifest.json");
|
|
23962
|
+
writeFileSync5(manifestPath, finalJson, "utf8");
|
|
23895
23963
|
return { manifest, outDir };
|
|
23896
23964
|
}
|
|
23897
23965
|
function restoreBackup(manifestPathOrDir, options = {}) {
|
|
23898
|
-
let manifestPath =
|
|
23966
|
+
let manifestPath = resolve5(manifestPathOrDir);
|
|
23899
23967
|
const stat = lstatSync3(manifestPath, { throwIfNoEntry: false });
|
|
23900
23968
|
if (!stat) {
|
|
23901
23969
|
throw databaseError("runtime_path_invalid", manifestPath, `manifest path ${manifestPath} does not exist`);
|
|
23902
23970
|
}
|
|
23903
23971
|
if (stat.isDirectory()) {
|
|
23904
|
-
manifestPath =
|
|
23972
|
+
manifestPath = join8(manifestPath, "manifest.json");
|
|
23905
23973
|
}
|
|
23906
|
-
if (!
|
|
23974
|
+
if (!existsSync8(manifestPath)) {
|
|
23907
23975
|
throw databaseError("runtime_path_invalid", manifestPath, `backup manifest ${manifestPath} not found`);
|
|
23908
23976
|
}
|
|
23909
|
-
const manifestDir =
|
|
23910
|
-
const rawText =
|
|
23977
|
+
const manifestDir = dirname6(manifestPath);
|
|
23978
|
+
const rawText = readFileSync7(manifestPath, "utf8");
|
|
23911
23979
|
let manifest;
|
|
23912
23980
|
try {
|
|
23913
23981
|
manifest = JSON.parse(rawText);
|
|
@@ -23919,8 +23987,8 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23919
23987
|
}
|
|
23920
23988
|
const restoredStores = [];
|
|
23921
23989
|
for (const store of manifest.stores) {
|
|
23922
|
-
const backupFilePath =
|
|
23923
|
-
if (!
|
|
23990
|
+
const backupFilePath = join8(manifestDir, store.backupFile);
|
|
23991
|
+
if (!existsSync8(backupFilePath)) {
|
|
23924
23992
|
throw databaseError("restore_file_missing", backupFilePath, `backup file ${store.backupFile} missing from ${manifestDir}`);
|
|
23925
23993
|
}
|
|
23926
23994
|
const actualSha256 = fileSha256(backupFilePath);
|
|
@@ -23938,7 +24006,7 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23938
24006
|
let targetPath = store.sourcePath;
|
|
23939
24007
|
if (options.projectRoot && manifest.projectRoot && targetPath.startsWith(manifest.projectRoot)) {
|
|
23940
24008
|
const rel = targetPath.slice(manifest.projectRoot.length).replace(/^[\\/]+/, "");
|
|
23941
|
-
targetPath =
|
|
24009
|
+
targetPath = join8(resolve5(options.projectRoot), rel);
|
|
23942
24010
|
}
|
|
23943
24011
|
const result = restoreDatabaseFile(
|
|
23944
24012
|
backupFilePath,
|
|
@@ -23958,13 +24026,13 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23958
24026
|
|
|
23959
24027
|
// plugins/kxm/src/vnext-runtime-store.ts
|
|
23960
24028
|
function vnextRuntimePaths(options = {}) {
|
|
23961
|
-
const stateRoot = options.stateRoot ?
|
|
23962
|
-
const runtimeDir =
|
|
24029
|
+
const stateRoot = options.stateRoot ? resolve6(options.stateRoot) : vnextUserStateRoot({ ...options.env ? { env: options.env } : {}, ...options.homeDir ? { homeDir: options.homeDir } : {} });
|
|
24030
|
+
const runtimeDir = join9(stateRoot, "runtime");
|
|
23963
24031
|
return {
|
|
23964
24032
|
stateRoot,
|
|
23965
24033
|
runtimeDir,
|
|
23966
|
-
registryDb:
|
|
23967
|
-
projectsDir:
|
|
24034
|
+
registryDb: join9(runtimeDir, "registry.db"),
|
|
24035
|
+
projectsDir: join9(runtimeDir, "projects")
|
|
23968
24036
|
};
|
|
23969
24037
|
}
|
|
23970
24038
|
function runtimeIssue(phase, code, file, message) {
|
|
@@ -23976,9 +24044,9 @@ function runtimeError(code, file, message) {
|
|
|
23976
24044
|
function projectRuntimeKey(projectRoot) {
|
|
23977
24045
|
let canonical2;
|
|
23978
24046
|
try {
|
|
23979
|
-
canonical2 = realpathSync3.native(
|
|
24047
|
+
canonical2 = realpathSync3.native(resolve6(projectRoot));
|
|
23980
24048
|
} catch {
|
|
23981
|
-
canonical2 =
|
|
24049
|
+
canonical2 = resolve6(projectRoot);
|
|
23982
24050
|
}
|
|
23983
24051
|
const folded = process.platform === "win32" ? canonical2.toLocaleLowerCase("en-US") : canonical2;
|
|
23984
24052
|
return createHash9("sha256").update(folded, "utf8").digest("hex").slice(0, 24);
|
|
@@ -24012,7 +24080,7 @@ var VnextRuntimeRegistry = class {
|
|
|
24012
24080
|
path;
|
|
24013
24081
|
database;
|
|
24014
24082
|
constructor(path4) {
|
|
24015
|
-
this.path =
|
|
24083
|
+
this.path = resolve6(path4);
|
|
24016
24084
|
this.database = openDatabase(this.path, "runtime registry", {
|
|
24017
24085
|
schema: REGISTRY_SCHEMA,
|
|
24018
24086
|
version: VNEXT_REGISTRY_SCHEMA_VERSION,
|
|
@@ -24102,7 +24170,7 @@ var VnextRuntimeRegistry = class {
|
|
|
24102
24170
|
}
|
|
24103
24171
|
/** Register or revalidate a project's home binding. Home Runtime is immutable. */
|
|
24104
24172
|
registerProject(registration) {
|
|
24105
|
-
const projectRoot =
|
|
24173
|
+
const projectRoot = resolve6(registration.projectRoot);
|
|
24106
24174
|
const projectKey = projectRuntimeKey(projectRoot);
|
|
24107
24175
|
this.database.exec("BEGIN IMMEDIATE");
|
|
24108
24176
|
try {
|
|
@@ -24323,7 +24391,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
24323
24391
|
const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
|
|
24324
24392
|
const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
|
|
24325
24393
|
const assignments = compileAssignments(step, id, agent, sink);
|
|
24326
|
-
const
|
|
24394
|
+
const join50 = compileJoin(step, id, sink);
|
|
24327
24395
|
const requiredEvidence = compileEvidence(step, id, sink);
|
|
24328
24396
|
const transitions = compileTransitions(step, id, index, stepIndex, sink);
|
|
24329
24397
|
const outcomes = Object.keys(transitions).sort(compareCodeUnits4);
|
|
@@ -24351,7 +24419,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
24351
24419
|
transitions: orderedTransitions,
|
|
24352
24420
|
requiresPlanHash: requirePlanHash.includes(id),
|
|
24353
24421
|
assignments,
|
|
24354
|
-
join:
|
|
24422
|
+
join: join50
|
|
24355
24423
|
};
|
|
24356
24424
|
if (kind === "agent" || kind === "moa") {
|
|
24357
24425
|
if (!agent) return void 0;
|
|
@@ -24401,15 +24469,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
|
|
|
24401
24469
|
};
|
|
24402
24470
|
}
|
|
24403
24471
|
function compileJoin(step, stepId, sink) {
|
|
24404
|
-
const
|
|
24405
|
-
if (!
|
|
24406
|
-
const declared = stringValue2(
|
|
24472
|
+
const join50 = objectValue2(step.join);
|
|
24473
|
+
if (!join50) return { strategy: "all" };
|
|
24474
|
+
const declared = stringValue2(join50.strategy);
|
|
24407
24475
|
const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
|
|
24408
|
-
const minimumPassed = compileOptionalCount(
|
|
24476
|
+
const minimumPassed = compileOptionalCount(join50.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
|
|
24409
24477
|
const compiled = {
|
|
24410
24478
|
strategy,
|
|
24411
24479
|
...minimumPassed !== void 0 ? { minimumPassed } : {},
|
|
24412
|
-
...typeof
|
|
24480
|
+
...typeof join50.cancelRemaining === "boolean" ? { cancelRemaining: join50.cancelRemaining } : {}
|
|
24413
24481
|
};
|
|
24414
24482
|
return compiled;
|
|
24415
24483
|
}
|
|
@@ -24689,8 +24757,8 @@ var RECORD_LIMIT = 16 * 1024 * 1024;
|
|
|
24689
24757
|
// plugins/kxm/src/prices.ts
|
|
24690
24758
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
24691
24759
|
import { createHash as createHash10 } from "node:crypto";
|
|
24692
|
-
import { existsSync as
|
|
24693
|
-
import { join as
|
|
24760
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9, statSync } from "node:fs";
|
|
24761
|
+
import { join as join10 } from "node:path";
|
|
24694
24762
|
|
|
24695
24763
|
// plugins/kxm/src/price-calc.ts
|
|
24696
24764
|
var PRICES_SCHEMA = "kxm.prices.v1";
|
|
@@ -24842,11 +24910,11 @@ function parsePriceCatalog(text) {
|
|
|
24842
24910
|
return catalog;
|
|
24843
24911
|
}
|
|
24844
24912
|
function loadPriceCatalog(rootOrPath) {
|
|
24845
|
-
const candidatePath =
|
|
24846
|
-
if (!candidatePath || !
|
|
24913
|
+
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;
|
|
24914
|
+
if (!candidatePath || !existsSync10(candidatePath)) {
|
|
24847
24915
|
return void 0;
|
|
24848
24916
|
}
|
|
24849
|
-
const content =
|
|
24917
|
+
const content = readFileSync9(candidatePath, "utf8");
|
|
24850
24918
|
return parsePriceCatalog(content);
|
|
24851
24919
|
}
|
|
24852
24920
|
function loadPriceCatalogForEstimate(options) {
|
|
@@ -24867,13 +24935,13 @@ var import_yaml5 = __toESM(require_dist(), 1);
|
|
|
24867
24935
|
|
|
24868
24936
|
// plugins/kxm/src/producers.ts
|
|
24869
24937
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
24870
|
-
import { existsSync as
|
|
24871
|
-
import { join as
|
|
24938
|
+
import { existsSync as existsSync11, readFileSync as readFileSync10, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7, readdirSync as readdirSync3 } from "node:fs";
|
|
24939
|
+
import { join as join11 } from "node:path";
|
|
24872
24940
|
var empty = () => ({ schema: "kxm.producers.v1", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), promoted: [], demoted: [], enabled: [], disabled: [], roles: {} });
|
|
24873
24941
|
function loadProducerPolicy(root) {
|
|
24874
|
-
const path4 =
|
|
24875
|
-
if (!
|
|
24876
|
-
const value = (0, import_yaml4.parse)(
|
|
24942
|
+
const path4 = join11(root, ".kxm", "producers.yaml");
|
|
24943
|
+
if (!existsSync11(path4)) return empty();
|
|
24944
|
+
const value = (0, import_yaml4.parse)(readFileSync10(path4, "utf8"));
|
|
24877
24945
|
if (value?.schema !== "kxm.producers.v1" || !Array.isArray(value.promoted) || !Array.isArray(value.demoted)) throw new Error("invalid .kxm/producers.yaml");
|
|
24878
24946
|
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
24947
|
}
|
|
@@ -24883,8 +24951,8 @@ function updateProducer(root, model, status) {
|
|
|
24883
24951
|
policy.demoted = policy.demoted.filter((x2) => x2 !== model);
|
|
24884
24952
|
policy[status].push(model);
|
|
24885
24953
|
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24886
|
-
|
|
24887
|
-
|
|
24954
|
+
mkdirSync7(join11(root, ".kxm"), { recursive: true });
|
|
24955
|
+
writeFileSync7(join11(root, ".kxm", "producers.yaml"), (0, import_yaml4.stringify)(policy), "utf8");
|
|
24888
24956
|
return policy;
|
|
24889
24957
|
}
|
|
24890
24958
|
function setModelState(root, model, state, role, removeRole2 = false) {
|
|
@@ -24894,10 +24962,10 @@ function setModelState(root, model, state, role, removeRole2 = false) {
|
|
|
24894
24962
|
policy[state].push(model);
|
|
24895
24963
|
if (role) {
|
|
24896
24964
|
if (!/^[a-z][a-z0-9_-]{0,63}$/i.test(role)) throw new Error("invalid role id");
|
|
24897
|
-
const rolePath =
|
|
24965
|
+
const rolePath = join11(root, ".kxm", "roles", `${role}.yaml`);
|
|
24898
24966
|
let roleFile = {};
|
|
24899
|
-
if (
|
|
24900
|
-
const parsed = (0, import_yaml4.parse)(
|
|
24967
|
+
if (existsSync11(rolePath)) {
|
|
24968
|
+
const parsed = (0, import_yaml4.parse)(readFileSync10(rolePath, "utf8"));
|
|
24901
24969
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) roleFile = parsed;
|
|
24902
24970
|
}
|
|
24903
24971
|
const roster = Array.isArray(roleFile.roster) ? roleFile.roster.filter((entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)) : [];
|
|
@@ -24908,42 +24976,42 @@ function setModelState(root, model, state, role, removeRole2 = false) {
|
|
|
24908
24976
|
roleFile.schema ??= "kxm.role.v1";
|
|
24909
24977
|
roleFile.id ??= role;
|
|
24910
24978
|
roleFile.roster = roster;
|
|
24911
|
-
|
|
24912
|
-
|
|
24979
|
+
mkdirSync7(join11(root, ".kxm", "roles"), { recursive: true });
|
|
24980
|
+
writeFileSync7(rolePath, (0, import_yaml4.stringify)(roleFile), "utf8");
|
|
24913
24981
|
}
|
|
24914
24982
|
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24915
|
-
|
|
24916
|
-
|
|
24983
|
+
mkdirSync7(join11(root, ".kxm"), { recursive: true });
|
|
24984
|
+
writeFileSync7(join11(root, ".kxm", "producers.yaml"), (0, import_yaml4.stringify)(policy), "utf8");
|
|
24917
24985
|
return policy;
|
|
24918
24986
|
}
|
|
24919
24987
|
function listRoleBindings(root) {
|
|
24920
|
-
const dir =
|
|
24988
|
+
const dir = join11(root, ".kxm", "roles");
|
|
24921
24989
|
const result = {};
|
|
24922
|
-
if (!
|
|
24990
|
+
if (!existsSync11(dir)) return result;
|
|
24923
24991
|
for (const file of readdirSync3(dir).filter((name) => name.endsWith(".yaml"))) {
|
|
24924
24992
|
const role = file.slice(0, -5);
|
|
24925
|
-
const value = (0, import_yaml4.parse)(
|
|
24993
|
+
const value = (0, import_yaml4.parse)(readFileSync10(join11(dir, file), "utf8"));
|
|
24926
24994
|
result[role] = (value.roster ?? []).map((entry) => entry.model).filter((model) => typeof model === "string");
|
|
24927
24995
|
}
|
|
24928
24996
|
return result;
|
|
24929
24997
|
}
|
|
24930
24998
|
function listInventoryModels(root) {
|
|
24931
|
-
const path4 =
|
|
24932
|
-
if (!
|
|
24933
|
-
const value = (0, import_yaml4.parse)(
|
|
24999
|
+
const path4 = join11(root, ".kxm", "models", "inventory.yaml");
|
|
25000
|
+
if (!existsSync11(path4)) return [];
|
|
25001
|
+
const value = (0, import_yaml4.parse)(readFileSync10(path4, "utf8"));
|
|
24934
25002
|
return (value.models ?? []).map((m2) => m2.id).filter((id) => typeof id === "string");
|
|
24935
25003
|
}
|
|
24936
25004
|
|
|
24937
25005
|
// plugins/kxm/src/artifacts-exist.ts
|
|
24938
25006
|
import { lstatSync as lstatSync5, realpathSync as realpathSync4, statSync as statSync2 } from "node:fs";
|
|
24939
|
-
import { isAbsolute as
|
|
25007
|
+
import { isAbsolute as isAbsolute4, relative as relative3, resolve as resolve7 } from "node:path";
|
|
24940
25008
|
function staysUnder(root, candidate) {
|
|
24941
25009
|
const child = relative3(root, candidate);
|
|
24942
|
-
return child === "" || !
|
|
25010
|
+
return child === "" || !isAbsolute4(child) && child !== ".." && !child.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`);
|
|
24943
25011
|
}
|
|
24944
25012
|
function verifyArtifactExists(rootInput, pathInput) {
|
|
24945
|
-
const lexicalRoot =
|
|
24946
|
-
const lexicalPath =
|
|
25013
|
+
const lexicalRoot = resolve7(rootInput);
|
|
25014
|
+
const lexicalPath = resolve7(pathInput);
|
|
24947
25015
|
if (!staysUnder(lexicalRoot, lexicalPath)) {
|
|
24948
25016
|
return { ok: false, error: "artifact_outside_workspace_assets", path: lexicalPath };
|
|
24949
25017
|
}
|
|
@@ -25563,7 +25631,7 @@ function formatRoutingReport(report2, options = {}) {
|
|
|
25563
25631
|
|
|
25564
25632
|
// plugins/kxm/src/vnext-runtime-supervisor.ts
|
|
25565
25633
|
function vnextSupervisorTokenFile(paths) {
|
|
25566
|
-
return
|
|
25634
|
+
return join12(paths.runtimeDir, "supervisor.token");
|
|
25567
25635
|
}
|
|
25568
25636
|
function readVnextSupervisorToken(paths) {
|
|
25569
25637
|
const file = vnextSupervisorTokenFile(paths);
|
|
@@ -25572,7 +25640,7 @@ function readVnextSupervisorToken(paths) {
|
|
|
25572
25640
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
25573
25641
|
throw runtimeError("runtime_path_invalid", file, "supervisor token file must be a regular file, not a link");
|
|
25574
25642
|
}
|
|
25575
|
-
const token =
|
|
25643
|
+
const token = readFileSync11(file, "utf8").trim();
|
|
25576
25644
|
return token.length >= 32 ? token : void 0;
|
|
25577
25645
|
}
|
|
25578
25646
|
function processAlive(pid) {
|
|
@@ -25586,11 +25654,11 @@ function processAlive(pid) {
|
|
|
25586
25654
|
var HEARTBEAT_STALE_MS = 15e3;
|
|
25587
25655
|
var SUPERVISOR_ERROR_MAX_AGE_MS = 3e4;
|
|
25588
25656
|
function supervisorErrorFile(paths) {
|
|
25589
|
-
return
|
|
25657
|
+
return join12(paths.runtimeDir, "supervisor.error");
|
|
25590
25658
|
}
|
|
25591
25659
|
function clearSupervisorError(paths) {
|
|
25592
25660
|
const file = supervisorErrorFile(paths);
|
|
25593
|
-
if (
|
|
25661
|
+
if (existsSync12(file)) rmSync3(file, { force: true });
|
|
25594
25662
|
}
|
|
25595
25663
|
function readRecentSupervisorError(paths) {
|
|
25596
25664
|
const file = supervisorErrorFile(paths);
|
|
@@ -25599,13 +25667,13 @@ function readRecentSupervisorError(paths) {
|
|
|
25599
25667
|
const ageMs = Date.now() - stat.mtimeMs;
|
|
25600
25668
|
if (ageMs > SUPERVISOR_ERROR_MAX_AGE_MS) return void 0;
|
|
25601
25669
|
try {
|
|
25602
|
-
return
|
|
25670
|
+
return readFileSync11(file, "utf8").trim();
|
|
25603
25671
|
} catch {
|
|
25604
25672
|
return void 0;
|
|
25605
25673
|
}
|
|
25606
25674
|
}
|
|
25607
25675
|
function vnextSupervisorStatus(paths) {
|
|
25608
|
-
if (!
|
|
25676
|
+
if (!existsSync12(paths.registryDb)) return { running: false };
|
|
25609
25677
|
const registry = new VnextRuntimeRegistry(paths.registryDb);
|
|
25610
25678
|
try {
|
|
25611
25679
|
const record = registry.supervisor();
|
|
@@ -25666,7 +25734,7 @@ async function ensureVnextSupervisor(options = {}) {
|
|
|
25666
25734
|
throw runtimeError("runtime_supervisor_unreachable", paths.registryDb, `runtime supervisor pid ${status.pid} is registered as running but cannot be probed`);
|
|
25667
25735
|
}
|
|
25668
25736
|
clearSupervisorError(paths);
|
|
25669
|
-
const scriptPath =
|
|
25737
|
+
const scriptPath = join12(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
|
|
25670
25738
|
const spawnImpl = options.spawnImpl ?? ((script, env) => {
|
|
25671
25739
|
const child = spawn2(process.execPath, [script], {
|
|
25672
25740
|
detached: true,
|
|
@@ -25719,7 +25787,7 @@ async function vnextRuntimeRequest(handle, method, path4, body) {
|
|
|
25719
25787
|
|
|
25720
25788
|
// plugins/kxm/src/cli/types.ts
|
|
25721
25789
|
import { spawn as spawn3 } from "node:child_process";
|
|
25722
|
-
import { join as
|
|
25790
|
+
import { join as join15, resolve as resolve9 } from "node:path";
|
|
25723
25791
|
|
|
25724
25792
|
// plugins/kxm/src/redact.ts
|
|
25725
25793
|
var SECRET_PATTERNS = [
|
|
@@ -25749,8 +25817,8 @@ function redactStringList(values, maxItems = 32) {
|
|
|
25749
25817
|
}
|
|
25750
25818
|
|
|
25751
25819
|
// plugins/kxm/src/telemetry.ts
|
|
25752
|
-
import { appendFileSync, mkdirSync as
|
|
25753
|
-
import { dirname as
|
|
25820
|
+
import { appendFileSync, mkdirSync as mkdirSync9, readFileSync as readFileSync12 } from "node:fs";
|
|
25821
|
+
import { dirname as dirname9, join as join13 } from "node:path";
|
|
25754
25822
|
var TELEMETRY_SCHEMA = "kxm.telemetry.v1";
|
|
25755
25823
|
function inferImprovementTarget(input) {
|
|
25756
25824
|
const explicit = input.env?.KXM_IMPROVE_TARGET?.trim();
|
|
@@ -25760,12 +25828,12 @@ function inferImprovementTarget(input) {
|
|
|
25760
25828
|
return project || workflowId ? "project" : "cli";
|
|
25761
25829
|
}
|
|
25762
25830
|
function appendTelemetry(path4, event) {
|
|
25763
|
-
|
|
25831
|
+
mkdirSync9(dirname9(path4), { recursive: true });
|
|
25764
25832
|
appendFileSync(path4, `${JSON.stringify(event)}
|
|
25765
25833
|
`, { encoding: "utf8", mode: 384 });
|
|
25766
25834
|
}
|
|
25767
25835
|
function telemetryPath(logsDir) {
|
|
25768
|
-
return
|
|
25836
|
+
return join13(logsDir, "telemetry.jsonl");
|
|
25769
25837
|
}
|
|
25770
25838
|
function makeTelemetryEvent(input) {
|
|
25771
25839
|
return {
|
|
@@ -25780,7 +25848,7 @@ function makeTelemetryEvent(input) {
|
|
|
25780
25848
|
function readRoutingRecords(path4) {
|
|
25781
25849
|
const records = [];
|
|
25782
25850
|
try {
|
|
25783
|
-
const raw =
|
|
25851
|
+
const raw = readFileSync12(path4, "utf8");
|
|
25784
25852
|
for (const line of raw.split(/\r?\n/)) {
|
|
25785
25853
|
if (!line.trim()) continue;
|
|
25786
25854
|
try {
|
|
@@ -25857,9 +25925,9 @@ function workerResult(worker, payload) {
|
|
|
25857
25925
|
}
|
|
25858
25926
|
|
|
25859
25927
|
// plugins/kxm/src/hub-binding.ts
|
|
25860
|
-
import { existsSync as
|
|
25861
|
-
import { homedir as
|
|
25862
|
-
import { dirname as
|
|
25928
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync13, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "node:fs";
|
|
25929
|
+
import { homedir as homedir4 } from "node:os";
|
|
25930
|
+
import { dirname as dirname10, isAbsolute as isAbsolute6, join as join14, resolve as resolve8 } from "node:path";
|
|
25863
25931
|
var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
25864
25932
|
var HUB_HEALTH_PROBE_MS = 300;
|
|
25865
25933
|
var HubBindingError = class extends Error {
|
|
@@ -25868,24 +25936,24 @@ var HubBindingError = class extends Error {
|
|
|
25868
25936
|
this.name = "HubBindingError";
|
|
25869
25937
|
}
|
|
25870
25938
|
};
|
|
25871
|
-
function
|
|
25939
|
+
function resolveUserStateRoot2(env) {
|
|
25872
25940
|
const explicit = env.KXM_STATE_HOME?.trim();
|
|
25873
25941
|
if (explicit) {
|
|
25874
|
-
if (!
|
|
25875
|
-
return
|
|
25942
|
+
if (!isAbsolute6(explicit)) throw new HubBindingError("local_state_root_not_absolute");
|
|
25943
|
+
return resolve8(explicit);
|
|
25876
25944
|
}
|
|
25877
25945
|
if (process.platform === "win32") {
|
|
25878
25946
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
25879
|
-
const base2 = localAppData &&
|
|
25880
|
-
return
|
|
25947
|
+
const base2 = localAppData && isAbsolute6(localAppData) ? localAppData : join14(homedir4(), "AppData", "Local");
|
|
25948
|
+
return resolve8(base2, "KXM");
|
|
25881
25949
|
}
|
|
25882
|
-
if (process.platform === "darwin") return
|
|
25950
|
+
if (process.platform === "darwin") return resolve8(homedir4(), "Library", "Application Support", "KXM");
|
|
25883
25951
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
25884
|
-
const base = xdgState &&
|
|
25885
|
-
return
|
|
25952
|
+
const base = xdgState && isAbsolute6(xdgState) ? xdgState : join14(homedir4(), ".local", "state");
|
|
25953
|
+
return resolve8(base, "kxm");
|
|
25886
25954
|
}
|
|
25887
25955
|
function hubBindingFile(env = process.env) {
|
|
25888
|
-
return
|
|
25956
|
+
return join14(resolveUserStateRoot2(env), "hub-binding.json");
|
|
25889
25957
|
}
|
|
25890
25958
|
function validateHubUrl(raw) {
|
|
25891
25959
|
let parsed;
|
|
@@ -25910,10 +25978,10 @@ function isAbortError(error) {
|
|
|
25910
25978
|
}
|
|
25911
25979
|
function readHubBinding(env = process.env) {
|
|
25912
25980
|
const file = hubBindingFile(env);
|
|
25913
|
-
if (!
|
|
25981
|
+
if (!existsSync13(file)) return void 0;
|
|
25914
25982
|
let parsed;
|
|
25915
25983
|
try {
|
|
25916
|
-
parsed = JSON.parse(
|
|
25984
|
+
parsed = JSON.parse(readFileSync13(file, "utf8"));
|
|
25917
25985
|
} catch {
|
|
25918
25986
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
25919
25987
|
}
|
|
@@ -25935,21 +26003,21 @@ function readHubBinding(env = process.env) {
|
|
|
25935
26003
|
}
|
|
25936
26004
|
function writeHubBinding(record, env = process.env) {
|
|
25937
26005
|
const file = hubBindingFile(env);
|
|
25938
|
-
|
|
25939
|
-
const temporary =
|
|
26006
|
+
mkdirSync10(dirname10(file), { recursive: true, mode: 448 });
|
|
26007
|
+
const temporary = join14(dirname10(file), `.hub-binding-${process.pid}.tmp`);
|
|
25940
26008
|
try {
|
|
25941
|
-
|
|
26009
|
+
writeFileSync9(temporary, `${JSON.stringify(record, null, 2)}
|
|
25942
26010
|
`, { encoding: "utf8", mode: 384 });
|
|
25943
|
-
|
|
26011
|
+
renameSync4(temporary, file);
|
|
25944
26012
|
} finally {
|
|
25945
|
-
|
|
26013
|
+
rmSync4(temporary, { force: true });
|
|
25946
26014
|
}
|
|
25947
26015
|
return file;
|
|
25948
26016
|
}
|
|
25949
26017
|
function removeHubBinding(env = process.env) {
|
|
25950
26018
|
const file = hubBindingFile(env);
|
|
25951
26019
|
try {
|
|
25952
|
-
|
|
26020
|
+
rmSync4(file);
|
|
25953
26021
|
return true;
|
|
25954
26022
|
} catch (error) {
|
|
25955
26023
|
if (error.code === "ENOENT") return false;
|
|
@@ -25983,7 +26051,7 @@ async function probeHubHealth(url, fetchImpl, timeoutMs = HUB_HEALTH_PROBE_MS) {
|
|
|
25983
26051
|
// plugins/kxm/src/cli/types.ts
|
|
25984
26052
|
function spawnScript(scriptName, extraEnv = {}) {
|
|
25985
26053
|
return new Promise((resolveExit) => {
|
|
25986
|
-
const child = spawn3(process.execPath, [
|
|
26054
|
+
const child = spawn3(process.execPath, [join15(findKxmRepoRoot(import.meta.url), "scripts", scriptName)], {
|
|
25987
26055
|
stdio: "inherit",
|
|
25988
26056
|
env: { ...process.env, ...extraEnv }
|
|
25989
26057
|
});
|
|
@@ -26067,16 +26135,16 @@ function redactCliValue(value, field = "") {
|
|
|
26067
26135
|
return value;
|
|
26068
26136
|
}
|
|
26069
26137
|
function workspaceDirs(cwd, workspaceFlag, env) {
|
|
26070
|
-
const workdir =
|
|
26071
|
-
const workspace =
|
|
26138
|
+
const workdir = resolve9(env.KXM_WORKDIR?.trim() || cwd);
|
|
26139
|
+
const workspace = resolve9(workdir, workspaceFlag || env.KXM_WORKSPACE_DIR?.trim() || ".kxm");
|
|
26072
26140
|
const derive = workspaceFlag !== void 0;
|
|
26073
26141
|
return {
|
|
26074
26142
|
workdir,
|
|
26075
26143
|
workspace,
|
|
26076
|
-
config: derive ?
|
|
26077
|
-
logs: derive ?
|
|
26078
|
-
assets: derive ?
|
|
26079
|
-
state: derive ?
|
|
26144
|
+
config: derive ? join15(workspace, "config") : resolve9(workdir, env.KXM_CONFIG_DIR?.trim() || join15(workspace, "config")),
|
|
26145
|
+
logs: derive ? join15(workspace, "logs") : resolve9(workdir, env.KXM_LOGS_DIR?.trim() || join15(workspace, "logs")),
|
|
26146
|
+
assets: derive ? join15(workspace, "assets") : resolve9(workdir, env.KXM_ASSETS_DIR?.trim() || join15(workspace, "assets")),
|
|
26147
|
+
state: derive ? join15(workspace, "state") : resolve9(workdir, env.KXM_STATE_DIR?.trim() || join15(workspace, "state"))
|
|
26080
26148
|
};
|
|
26081
26149
|
}
|
|
26082
26150
|
function maskEnvName(name) {
|
|
@@ -26144,20 +26212,20 @@ function workspaceEnv(runtime) {
|
|
|
26144
26212
|
// plugins/kxm/src/cli/roles.ts
|
|
26145
26213
|
var import_yaml8 = __toESM(require_dist(), 1);
|
|
26146
26214
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
26147
|
-
import { existsSync as
|
|
26148
|
-
import { join as
|
|
26215
|
+
import { existsSync as existsSync16, readFileSync as readFileSync16 } from "node:fs";
|
|
26216
|
+
import { join as join18, resolve as resolve12 } from "node:path";
|
|
26149
26217
|
import { createInterface } from "node:readline";
|
|
26150
26218
|
|
|
26151
26219
|
// plugins/kxm/src/role.ts
|
|
26152
26220
|
var import_yaml7 = __toESM(require_dist(), 1);
|
|
26153
|
-
import { existsSync as
|
|
26154
|
-
import { join as
|
|
26221
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync12, readdirSync as readdirSync4, readFileSync as readFileSync15, rmSync as rmSync5, writeFileSync as writeFileSync11 } from "node:fs";
|
|
26222
|
+
import { join as join17 } from "node:path";
|
|
26155
26223
|
|
|
26156
26224
|
// plugins/kxm/src/config.ts
|
|
26157
26225
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
26158
|
-
import { existsSync as
|
|
26159
|
-
import { homedir as
|
|
26160
|
-
import { dirname as
|
|
26226
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "node:fs";
|
|
26227
|
+
import { homedir as homedir5 } from "node:os";
|
|
26228
|
+
import { dirname as dirname11, join as join16, resolve as resolve10 } from "node:path";
|
|
26161
26229
|
var KXM_CONFIG_SCHEMA = "kxm.config.v1";
|
|
26162
26230
|
var DEFAULT_KXM_CONFIG = {
|
|
26163
26231
|
schema: KXM_CONFIG_SCHEMA,
|
|
@@ -26210,11 +26278,11 @@ var DEFAULT_KXM_CONFIG = {
|
|
|
26210
26278
|
}
|
|
26211
26279
|
};
|
|
26212
26280
|
function userConfigDirectory(overrideDir) {
|
|
26213
|
-
if (overrideDir) return
|
|
26214
|
-
return
|
|
26281
|
+
if (overrideDir) return resolve10(overrideDir);
|
|
26282
|
+
return resolve10(process.env.KXM_USER_CONFIG_DIR?.trim() || join16(homedir5(), ".config", "kxm"));
|
|
26215
26283
|
}
|
|
26216
26284
|
function repoConfigDirectory(repoRoot) {
|
|
26217
|
-
return
|
|
26285
|
+
return resolve10(repoRoot, ".kxm");
|
|
26218
26286
|
}
|
|
26219
26287
|
function deepMerge(target, source) {
|
|
26220
26288
|
const result = { ...target };
|
|
@@ -26234,14 +26302,14 @@ function normalizeHubConfig(raw) {
|
|
|
26234
26302
|
}
|
|
26235
26303
|
function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
|
|
26236
26304
|
const userDir = userConfigDirectory(options.userConfigDir);
|
|
26237
|
-
const userConfigFile =
|
|
26305
|
+
const userConfigFile = join16(userDir, "config.yaml");
|
|
26238
26306
|
const repoDir = repoConfigDirectory(repoRoot);
|
|
26239
|
-
const repoConfigFile =
|
|
26307
|
+
const repoConfigFile = join16(repoDir, "config.yaml");
|
|
26240
26308
|
let userRaw = {};
|
|
26241
26309
|
let userLoadedPath;
|
|
26242
|
-
if (
|
|
26310
|
+
if (existsSync14(userConfigFile)) {
|
|
26243
26311
|
try {
|
|
26244
|
-
const text =
|
|
26312
|
+
const text = readFileSync14(userConfigFile, "utf8");
|
|
26245
26313
|
userRaw = (0, import_yaml6.parse)(text) ?? {};
|
|
26246
26314
|
userLoadedPath = userConfigFile;
|
|
26247
26315
|
} catch (error) {
|
|
@@ -26250,9 +26318,9 @@ function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
|
|
|
26250
26318
|
}
|
|
26251
26319
|
let repoRaw = {};
|
|
26252
26320
|
let repoLoadedPath;
|
|
26253
|
-
if (
|
|
26321
|
+
if (existsSync14(repoConfigFile)) {
|
|
26254
26322
|
try {
|
|
26255
|
-
const text =
|
|
26323
|
+
const text = readFileSync14(repoConfigFile, "utf8");
|
|
26256
26324
|
repoRaw = (0, import_yaml6.parse)(text) ?? {};
|
|
26257
26325
|
repoLoadedPath = repoConfigFile;
|
|
26258
26326
|
} catch (error) {
|
|
@@ -26289,12 +26357,12 @@ function getKxmConfigValue(config, keyPath) {
|
|
|
26289
26357
|
}
|
|
26290
26358
|
function setKxmConfigValue(repoRoot, keyPath, value, options = {}) {
|
|
26291
26359
|
const scope = options.scope ?? "project";
|
|
26292
|
-
const targetFile2 = scope === "user" ?
|
|
26293
|
-
|
|
26360
|
+
const targetFile2 = scope === "user" ? join16(userConfigDirectory(options.userConfigDir), "config.yaml") : join16(repoConfigDirectory(repoRoot), "config.yaml");
|
|
26361
|
+
mkdirSync11(dirname11(targetFile2), { recursive: true });
|
|
26294
26362
|
let existing = {};
|
|
26295
|
-
if (
|
|
26363
|
+
if (existsSync14(targetFile2)) {
|
|
26296
26364
|
try {
|
|
26297
|
-
existing = (0, import_yaml6.parse)(
|
|
26365
|
+
existing = (0, import_yaml6.parse)(readFileSync14(targetFile2, "utf8")) ?? {};
|
|
26298
26366
|
} catch {
|
|
26299
26367
|
existing = {};
|
|
26300
26368
|
}
|
|
@@ -26312,7 +26380,7 @@ function setKxmConfigValue(repoRoot, keyPath, value, options = {}) {
|
|
|
26312
26380
|
cursor2 = cursor2[p];
|
|
26313
26381
|
}
|
|
26314
26382
|
cursor2[parts[parts.length - 1]] = value;
|
|
26315
|
-
|
|
26383
|
+
writeFileSync10(targetFile2, (0, import_yaml6.stringify)(existing).trim() + "\n", "utf8");
|
|
26316
26384
|
}
|
|
26317
26385
|
function formatKxmConfig(config) {
|
|
26318
26386
|
const display = {
|
|
@@ -26405,21 +26473,21 @@ var DEFAULT_ROLES = {
|
|
|
26405
26473
|
};
|
|
26406
26474
|
function rolesDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
26407
26475
|
if (scope === "global") {
|
|
26408
|
-
return
|
|
26476
|
+
return join17(userConfigDirectory(userConfigDir), "roles");
|
|
26409
26477
|
}
|
|
26410
|
-
return
|
|
26478
|
+
return join17(repoConfigDirectory(repoRoot), "roles");
|
|
26411
26479
|
}
|
|
26412
26480
|
function ensureRolesDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
26413
26481
|
const dir = rolesDirectory(scope, repoRoot, userConfigDir);
|
|
26414
|
-
if (!
|
|
26415
|
-
|
|
26482
|
+
if (!existsSync15(dir)) {
|
|
26483
|
+
mkdirSync12(dir, { recursive: true });
|
|
26416
26484
|
}
|
|
26417
26485
|
return dir;
|
|
26418
26486
|
}
|
|
26419
26487
|
function parseRoleFile(filePath) {
|
|
26420
|
-
if (!
|
|
26488
|
+
if (!existsSync15(filePath)) return void 0;
|
|
26421
26489
|
try {
|
|
26422
|
-
const raw =
|
|
26490
|
+
const raw = readFileSync15(filePath, "utf8");
|
|
26423
26491
|
const parsed = (0, import_yaml7.parse)(raw);
|
|
26424
26492
|
if (!parsed || typeof parsed !== "object" || parsed.schema !== KXM_ROLE_SCHEMA) {
|
|
26425
26493
|
return void 0;
|
|
@@ -26446,10 +26514,10 @@ function listRoles(options = {}) {
|
|
|
26446
26514
|
const globalDir = rolesDirectory("global", repoRoot, options.userConfigDir);
|
|
26447
26515
|
const localDir = rolesDirectory("local", repoRoot, options.userConfigDir);
|
|
26448
26516
|
const localRoles = /* @__PURE__ */ new Map();
|
|
26449
|
-
if (scopeFilter !== "global" &&
|
|
26517
|
+
if (scopeFilter !== "global" && existsSync15(localDir)) {
|
|
26450
26518
|
for (const entry of readdirSync4(localDir)) {
|
|
26451
26519
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
26452
|
-
const filePath =
|
|
26520
|
+
const filePath = join17(localDir, entry);
|
|
26453
26521
|
const parsed = parseRoleFile(filePath);
|
|
26454
26522
|
if (parsed) {
|
|
26455
26523
|
localRoles.set(parsed.id, { role: parsed, filePath });
|
|
@@ -26458,10 +26526,10 @@ function listRoles(options = {}) {
|
|
|
26458
26526
|
}
|
|
26459
26527
|
}
|
|
26460
26528
|
const globalRoles = /* @__PURE__ */ new Map();
|
|
26461
|
-
if (scopeFilter !== "local" &&
|
|
26529
|
+
if (scopeFilter !== "local" && existsSync15(globalDir)) {
|
|
26462
26530
|
for (const entry of readdirSync4(globalDir)) {
|
|
26463
26531
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
26464
|
-
const filePath =
|
|
26532
|
+
const filePath = join17(globalDir, entry);
|
|
26465
26533
|
const parsed = parseRoleFile(filePath);
|
|
26466
26534
|
if (parsed) {
|
|
26467
26535
|
globalRoles.set(parsed.id, { role: parsed, filePath });
|
|
@@ -26509,13 +26577,13 @@ function getRole(roleId, options = {}) {
|
|
|
26509
26577
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26510
26578
|
if (scope !== "global") {
|
|
26511
26579
|
const localDir = rolesDirectory("local", repoRoot, options.userConfigDir);
|
|
26512
|
-
const localFile =
|
|
26580
|
+
const localFile = join17(localDir, `${roleId}.yaml`);
|
|
26513
26581
|
const parsed = parseRoleFile(localFile);
|
|
26514
26582
|
if (parsed) return { role: parsed, scope: "local", filePath: localFile };
|
|
26515
26583
|
}
|
|
26516
26584
|
if (scope !== "local") {
|
|
26517
26585
|
const globalDir = rolesDirectory("global", repoRoot, options.userConfigDir);
|
|
26518
|
-
const globalFile =
|
|
26586
|
+
const globalFile = join17(globalDir, `${roleId}.yaml`);
|
|
26519
26587
|
const parsed = parseRoleFile(globalFile);
|
|
26520
26588
|
if (parsed) return { role: parsed, scope: "global", filePath: globalFile };
|
|
26521
26589
|
}
|
|
@@ -26525,22 +26593,22 @@ function addRole(role, options = {}) {
|
|
|
26525
26593
|
const scope = options.scope ?? "local";
|
|
26526
26594
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26527
26595
|
const dir = ensureRolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
26528
|
-
const filePath =
|
|
26529
|
-
if (
|
|
26596
|
+
const filePath = join17(dir, `${role.id}.yaml`);
|
|
26597
|
+
if (existsSync15(filePath) && !options.overwrite) {
|
|
26530
26598
|
throw new Error(`role_already_exists: role '${role.id}' already exists at ${filePath}`);
|
|
26531
26599
|
}
|
|
26532
|
-
|
|
26600
|
+
writeFileSync11(filePath, (0, import_yaml7.stringify)(role), "utf8");
|
|
26533
26601
|
return { id: role.id, filePath, scope };
|
|
26534
26602
|
}
|
|
26535
26603
|
function removeRole(roleId, options = {}) {
|
|
26536
26604
|
const scope = options.scope ?? "local";
|
|
26537
26605
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26538
26606
|
const dir = rolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
26539
|
-
const filePath =
|
|
26540
|
-
if (!
|
|
26607
|
+
const filePath = join17(dir, `${roleId}.yaml`);
|
|
26608
|
+
if (!existsSync15(filePath)) {
|
|
26541
26609
|
throw new Error(`role_not_found: role '${roleId}' not found in ${scope} directory (${filePath})`);
|
|
26542
26610
|
}
|
|
26543
|
-
|
|
26611
|
+
rmSync5(filePath);
|
|
26544
26612
|
return { id: roleId, removed: true, filePath, scope };
|
|
26545
26613
|
}
|
|
26546
26614
|
function modifyRole(roleId, updates, options = {}) {
|
|
@@ -26558,8 +26626,8 @@ function modifyRole(roleId, updates, options = {}) {
|
|
|
26558
26626
|
const scope = options.scope ?? target.scope;
|
|
26559
26627
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26560
26628
|
const dir = ensureRolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
26561
|
-
const filePath =
|
|
26562
|
-
|
|
26629
|
+
const filePath = join17(dir, `${roleId}.yaml`);
|
|
26630
|
+
writeFileSync11(filePath, (0, import_yaml7.stringify)(updated), "utf8");
|
|
26563
26631
|
return { id: roleId, role: updated, filePath, scope };
|
|
26564
26632
|
}
|
|
26565
26633
|
var KXM_ROLE_HOSTS_SCHEMA = "kxm.role-hosts.v1";
|
|
@@ -26607,18 +26675,18 @@ var DEFAULT_ROLE_SEATS = {
|
|
|
26607
26675
|
};
|
|
26608
26676
|
function findExistingRoleHostsFile(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
26609
26677
|
const dir = scope === "global" ? userConfigDirectory(userConfigDir) : repoConfigDirectory(repoRoot);
|
|
26610
|
-
const yamlPath =
|
|
26611
|
-
const ymlPath =
|
|
26612
|
-
const jsonPath =
|
|
26613
|
-
if (
|
|
26614
|
-
if (
|
|
26615
|
-
if (
|
|
26678
|
+
const yamlPath = join17(dir, "role-hosts.yaml");
|
|
26679
|
+
const ymlPath = join17(dir, "role-hosts.yml");
|
|
26680
|
+
const jsonPath = join17(dir, "role-hosts.json");
|
|
26681
|
+
if (existsSync15(yamlPath)) return { filePath: yamlPath, exists: true, format: "yaml" };
|
|
26682
|
+
if (existsSync15(ymlPath)) return { filePath: ymlPath, exists: true, format: "yaml" };
|
|
26683
|
+
if (existsSync15(jsonPath)) return { filePath: jsonPath, exists: true, format: "json" };
|
|
26616
26684
|
return { filePath: yamlPath, exists: false, format: "yaml" };
|
|
26617
26685
|
}
|
|
26618
26686
|
function parseRoleHostsFile(filePath) {
|
|
26619
|
-
if (!
|
|
26687
|
+
if (!existsSync15(filePath)) return void 0;
|
|
26620
26688
|
try {
|
|
26621
|
-
const raw =
|
|
26689
|
+
const raw = readFileSync15(filePath, "utf8");
|
|
26622
26690
|
const parsed = (0, import_yaml7.parse)(raw);
|
|
26623
26691
|
if (!parsed || typeof parsed !== "object") return void 0;
|
|
26624
26692
|
if (parsed.schema && parsed.schema !== KXM_ROLE_HOSTS_SCHEMA) return void 0;
|
|
@@ -26690,18 +26758,18 @@ function saveRoleHostsConfig(config, options = {}) {
|
|
|
26690
26758
|
const scope = options.scope ?? "local";
|
|
26691
26759
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26692
26760
|
const dir = scope === "global" ? userConfigDirectory(options.userConfigDir) : repoConfigDirectory(repoRoot);
|
|
26693
|
-
if (!
|
|
26694
|
-
|
|
26761
|
+
if (!existsSync15(dir)) {
|
|
26762
|
+
mkdirSync12(dir, { recursive: true });
|
|
26695
26763
|
}
|
|
26696
26764
|
const format = options.format ?? "yaml";
|
|
26697
|
-
const filePath =
|
|
26765
|
+
const filePath = join17(dir, format === "json" ? "role-hosts.json" : "role-hosts.yaml");
|
|
26698
26766
|
const payload = {
|
|
26699
26767
|
schema: KXM_ROLE_HOSTS_SCHEMA,
|
|
26700
26768
|
seats: config.seats ?? {},
|
|
26701
26769
|
...config.hostProviders && Object.keys(config.hostProviders).length > 0 ? { hostProviders: config.hostProviders } : {}
|
|
26702
26770
|
};
|
|
26703
26771
|
const content = format === "json" ? JSON.stringify(payload, null, 2) + "\n" : (0, import_yaml7.stringify)(payload);
|
|
26704
|
-
|
|
26772
|
+
writeFileSync11(filePath, content, "utf8");
|
|
26705
26773
|
return { filePath, scope };
|
|
26706
26774
|
}
|
|
26707
26775
|
function setRoleSeatHost(seatId, host, options = {}) {
|
|
@@ -26935,8 +27003,8 @@ async function cmdRoleAdd(runtime, roleId, options) {
|
|
|
26935
27003
|
}
|
|
26936
27004
|
let roleDef;
|
|
26937
27005
|
if (options.file) {
|
|
26938
|
-
const filePath =
|
|
26939
|
-
const content =
|
|
27006
|
+
const filePath = resolve12(runtime.cwd, options.file);
|
|
27007
|
+
const content = readFileSync16(filePath, "utf8");
|
|
26940
27008
|
roleDef = (0, import_yaml8.parse)(content);
|
|
26941
27009
|
roleDef.id = roleId;
|
|
26942
27010
|
} else {
|
|
@@ -27235,8 +27303,8 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
27235
27303
|
return 1;
|
|
27236
27304
|
}
|
|
27237
27305
|
}
|
|
27238
|
-
const dbPath =
|
|
27239
|
-
if (
|
|
27306
|
+
const dbPath = join18(runtime.cwd, ".kxm", "state", "kxm.db");
|
|
27307
|
+
if (existsSync16(dbPath)) {
|
|
27240
27308
|
try {
|
|
27241
27309
|
const database = new DatabaseSync(dbPath);
|
|
27242
27310
|
try {
|
|
@@ -27298,12 +27366,12 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
27298
27366
|
|
|
27299
27367
|
// plugins/kxm/src/cli/workflows.ts
|
|
27300
27368
|
import { createHmac as createHmac3, randomUUID as randomUUID7 } from "node:crypto";
|
|
27301
|
-
import { existsSync as
|
|
27302
|
-
import { join as
|
|
27369
|
+
import { existsSync as existsSync18, readFileSync as readFileSync18 } from "node:fs";
|
|
27370
|
+
import { join as join20, resolve as resolve15 } from "node:path";
|
|
27303
27371
|
|
|
27304
27372
|
// plugins/kxm/src/retrospective.ts
|
|
27305
|
-
import { mkdirSync as
|
|
27306
|
-
import { resolve as
|
|
27373
|
+
import { mkdirSync as mkdirSync13, renameSync as renameSync5, writeFileSync as writeFileSync12 } from "node:fs";
|
|
27374
|
+
import { resolve as resolve13 } from "node:path";
|
|
27307
27375
|
var MAX_RETROSPECTIVE_ENTRIES = 500;
|
|
27308
27376
|
var SAFE_RUN_ID = /^run_[A-Za-z0-9_-]{1,120}$/;
|
|
27309
27377
|
function durationMs(startedAt, completedAt) {
|
|
@@ -27515,19 +27583,19 @@ function renderRetrospectiveMarkdown(doc) {
|
|
|
27515
27583
|
}
|
|
27516
27584
|
function writeRetrospective(outDir, doc) {
|
|
27517
27585
|
if (!SAFE_RUN_ID.test(doc.runId)) throw new Error("invalid retrospective run id");
|
|
27518
|
-
|
|
27519
|
-
const root =
|
|
27520
|
-
const jsonPath =
|
|
27521
|
-
const mdPath =
|
|
27586
|
+
mkdirSync13(outDir, { recursive: true });
|
|
27587
|
+
const root = resolve13(outDir);
|
|
27588
|
+
const jsonPath = resolve13(root, `${doc.runId}.json`);
|
|
27589
|
+
const mdPath = resolve13(root, `${doc.runId}.md`);
|
|
27522
27590
|
const prefix = `${root}${process.platform === "win32" ? "\\" : "/"}`;
|
|
27523
27591
|
if (!jsonPath.startsWith(prefix) || !mdPath.startsWith(prefix)) throw new Error("retrospective path escaped output directory");
|
|
27524
27592
|
const jsonTmp = `${jsonPath}.tmp`;
|
|
27525
27593
|
const mdTmp = `${mdPath}.tmp`;
|
|
27526
|
-
|
|
27594
|
+
writeFileSync12(jsonTmp, `${JSON.stringify(doc, null, 2)}
|
|
27527
27595
|
`, { encoding: "utf8", mode: 384 });
|
|
27528
|
-
|
|
27529
|
-
|
|
27530
|
-
|
|
27596
|
+
writeFileSync12(mdTmp, renderRetrospectiveMarkdown(doc), { encoding: "utf8", mode: 384 });
|
|
27597
|
+
renameSync5(jsonTmp, jsonPath);
|
|
27598
|
+
renameSync5(mdTmp, mdPath);
|
|
27531
27599
|
return { jsonPath, mdPath };
|
|
27532
27600
|
}
|
|
27533
27601
|
|
|
@@ -27618,7 +27686,7 @@ async function watchGithubChecks(input) {
|
|
|
27618
27686
|
}
|
|
27619
27687
|
const fetchImpl = input.fetchImpl ?? fetch;
|
|
27620
27688
|
const now = input.now ?? Date.now;
|
|
27621
|
-
const sleep = input.sleep ?? ((ms) => new Promise((
|
|
27689
|
+
const sleep = input.sleep ?? ((ms) => new Promise((resolve31) => setTimeout(resolve31, ms)));
|
|
27622
27690
|
const deadline = now() + input.timeoutMs;
|
|
27623
27691
|
const headers = {
|
|
27624
27692
|
authorization: `Bearer ${token}`,
|
|
@@ -27717,8 +27785,8 @@ async function watchGithubChecks(input) {
|
|
|
27717
27785
|
|
|
27718
27786
|
// plugins/kxm/src/workflow-manager.ts
|
|
27719
27787
|
var import_yaml9 = __toESM(require_dist(), 1);
|
|
27720
|
-
import { existsSync as
|
|
27721
|
-
import { join as
|
|
27788
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync14, readdirSync as readdirSync5, readFileSync as readFileSync17, rmSync as rmSync6, writeFileSync as writeFileSync13 } from "node:fs";
|
|
27789
|
+
import { join as join19 } from "node:path";
|
|
27722
27790
|
var WORKFLOW_TEMPLATES = {
|
|
27723
27791
|
"implement-and-verify": {
|
|
27724
27792
|
schema: "kxm.workflow.v1",
|
|
@@ -27869,21 +27937,21 @@ var WORKFLOW_TEMPLATES = {
|
|
|
27869
27937
|
var DEFAULT_WORKFLOW_TEMPLATE = WORKFLOW_TEMPLATES["implement-and-verify"];
|
|
27870
27938
|
function workflowsDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
27871
27939
|
if (scope === "global") {
|
|
27872
|
-
return
|
|
27940
|
+
return join19(userConfigDirectory(userConfigDir), "workflows");
|
|
27873
27941
|
}
|
|
27874
|
-
return
|
|
27942
|
+
return join19(repoConfigDirectory(repoRoot), "workflows");
|
|
27875
27943
|
}
|
|
27876
27944
|
function ensureWorkflowsDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
27877
27945
|
const dir = workflowsDirectory(scope, repoRoot, userConfigDir);
|
|
27878
|
-
if (!
|
|
27879
|
-
|
|
27946
|
+
if (!existsSync17(dir)) {
|
|
27947
|
+
mkdirSync14(dir, { recursive: true });
|
|
27880
27948
|
}
|
|
27881
27949
|
return dir;
|
|
27882
27950
|
}
|
|
27883
27951
|
function parseWorkflowFile(filePath) {
|
|
27884
|
-
if (!
|
|
27952
|
+
if (!existsSync17(filePath)) return void 0;
|
|
27885
27953
|
try {
|
|
27886
|
-
const raw =
|
|
27954
|
+
const raw = readFileSync17(filePath, "utf8");
|
|
27887
27955
|
const parsed = (0, import_yaml9.parse)(raw);
|
|
27888
27956
|
if (!parsed || typeof parsed !== "object") return void 0;
|
|
27889
27957
|
return parsed;
|
|
@@ -27897,10 +27965,10 @@ function listWorkflowDefinitions(options = {}) {
|
|
|
27897
27965
|
const globalDir = workflowsDirectory("global", repoRoot, options.userConfigDir);
|
|
27898
27966
|
const localDir = workflowsDirectory("local", repoRoot, options.userConfigDir);
|
|
27899
27967
|
const localDefs = /* @__PURE__ */ new Map();
|
|
27900
|
-
if (scopeFilter !== "global" &&
|
|
27968
|
+
if (scopeFilter !== "global" && existsSync17(localDir)) {
|
|
27901
27969
|
for (const entry of readdirSync5(localDir)) {
|
|
27902
27970
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
27903
|
-
const filePath =
|
|
27971
|
+
const filePath = join19(localDir, entry);
|
|
27904
27972
|
const def = parseWorkflowFile(filePath);
|
|
27905
27973
|
if (def) {
|
|
27906
27974
|
const id = def.id || entry.replace(/\.ya?ml$/i, "");
|
|
@@ -27910,10 +27978,10 @@ function listWorkflowDefinitions(options = {}) {
|
|
|
27910
27978
|
}
|
|
27911
27979
|
}
|
|
27912
27980
|
const globalDefs = /* @__PURE__ */ new Map();
|
|
27913
|
-
if (scopeFilter !== "local" &&
|
|
27981
|
+
if (scopeFilter !== "local" && existsSync17(globalDir)) {
|
|
27914
27982
|
for (const entry of readdirSync5(globalDir)) {
|
|
27915
27983
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
27916
|
-
const filePath =
|
|
27984
|
+
const filePath = join19(globalDir, entry);
|
|
27917
27985
|
const def = parseWorkflowFile(filePath);
|
|
27918
27986
|
if (def) {
|
|
27919
27987
|
const id = def.id || entry.replace(/\.ya?ml$/i, "");
|
|
@@ -27969,13 +28037,13 @@ function getWorkflowDefinition(workflowId, options = {}) {
|
|
|
27969
28037
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
27970
28038
|
if (scope !== "global") {
|
|
27971
28039
|
const localDir = workflowsDirectory("local", repoRoot, options.userConfigDir);
|
|
27972
|
-
const localFile =
|
|
28040
|
+
const localFile = join19(localDir, `${workflowId}.yaml`);
|
|
27973
28041
|
const parsed = parseWorkflowFile(localFile);
|
|
27974
28042
|
if (parsed) return { workflow: parsed, scope: "local", filePath: localFile };
|
|
27975
28043
|
}
|
|
27976
28044
|
if (scope !== "local") {
|
|
27977
28045
|
const globalDir = workflowsDirectory("global", repoRoot, options.userConfigDir);
|
|
27978
|
-
const globalFile =
|
|
28046
|
+
const globalFile = join19(globalDir, `${workflowId}.yaml`);
|
|
27979
28047
|
const parsed = parseWorkflowFile(globalFile);
|
|
27980
28048
|
if (parsed) return { workflow: parsed, scope: "global", filePath: globalFile };
|
|
27981
28049
|
}
|
|
@@ -27985,23 +28053,23 @@ function addWorkflowDefinition(workflowId, content = DEFAULT_WORKFLOW_TEMPLATE,
|
|
|
27985
28053
|
const scope = options.scope ?? "local";
|
|
27986
28054
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
27987
28055
|
const dir = ensureWorkflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
27988
|
-
const filePath =
|
|
27989
|
-
if (
|
|
28056
|
+
const filePath = join19(dir, `${workflowId}.yaml`);
|
|
28057
|
+
if (existsSync17(filePath) && !options.overwrite) {
|
|
27990
28058
|
throw new Error(`workflow_already_exists: workflow '${workflowId}' already exists at ${filePath}`);
|
|
27991
28059
|
}
|
|
27992
28060
|
const payload = typeof content === "string" ? content : (0, import_yaml9.stringify)(content);
|
|
27993
|
-
|
|
28061
|
+
writeFileSync13(filePath, payload, "utf8");
|
|
27994
28062
|
return { id: workflowId, filePath, scope };
|
|
27995
28063
|
}
|
|
27996
28064
|
function removeWorkflowDefinition(workflowId, options = {}) {
|
|
27997
28065
|
const scope = options.scope ?? "local";
|
|
27998
28066
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
27999
28067
|
const dir = workflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
28000
|
-
const filePath =
|
|
28001
|
-
if (!
|
|
28068
|
+
const filePath = join19(dir, `${workflowId}.yaml`);
|
|
28069
|
+
if (!existsSync17(filePath)) {
|
|
28002
28070
|
throw new Error(`workflow_not_found: workflow '${workflowId}' not found in ${scope} directory (${filePath})`);
|
|
28003
28071
|
}
|
|
28004
|
-
|
|
28072
|
+
rmSync6(filePath);
|
|
28005
28073
|
return { id: workflowId, removed: true, filePath, scope };
|
|
28006
28074
|
}
|
|
28007
28075
|
function modifyWorkflowDefinition(workflowId, updates, options = {}) {
|
|
@@ -28016,15 +28084,15 @@ function modifyWorkflowDefinition(workflowId, updates, options = {}) {
|
|
|
28016
28084
|
const scope = options.scope ?? target.scope;
|
|
28017
28085
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
28018
28086
|
const dir = ensureWorkflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
28019
|
-
const filePath =
|
|
28020
|
-
|
|
28087
|
+
const filePath = join19(dir, `${workflowId}.yaml`);
|
|
28088
|
+
writeFileSync13(filePath, (0, import_yaml9.stringify)(updated), "utf8");
|
|
28021
28089
|
return { id: workflowId, workflow: updated, filePath, scope };
|
|
28022
28090
|
}
|
|
28023
28091
|
|
|
28024
28092
|
// plugins/kxm/src/cli/workflows.ts
|
|
28025
28093
|
var CLI_NAME = "kxm";
|
|
28026
28094
|
function localWorkflowSnapshot(dataPath, runId) {
|
|
28027
|
-
if (!
|
|
28095
|
+
if (!existsSync18(dataPath)) throw new Error("state_database_not_found");
|
|
28028
28096
|
const database = new DatabaseSync(dataPath, { readOnly: true });
|
|
28029
28097
|
try {
|
|
28030
28098
|
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 +28169,7 @@ function activeWorkflowDefinition(runtime, definitionId) {
|
|
|
28101
28169
|
let raw;
|
|
28102
28170
|
if (file) {
|
|
28103
28171
|
try {
|
|
28104
|
-
raw =
|
|
28172
|
+
raw = readFileSync18(resolve15(runtime.cwd, file), "utf8");
|
|
28105
28173
|
} catch {
|
|
28106
28174
|
throw new Error("workflow definition file is unavailable");
|
|
28107
28175
|
}
|
|
@@ -28182,8 +28250,8 @@ async function cmdWorkflowAdd(runtime, workflowId, options) {
|
|
|
28182
28250
|
}
|
|
28183
28251
|
}
|
|
28184
28252
|
if (options.file) {
|
|
28185
|
-
const filePath =
|
|
28186
|
-
content =
|
|
28253
|
+
const filePath = resolve15(runtime.cwd, options.file);
|
|
28254
|
+
content = readFileSync18(filePath, "utf8");
|
|
28187
28255
|
} else if (!content) {
|
|
28188
28256
|
content = {
|
|
28189
28257
|
schema: "kxm.workflow.v1",
|
|
@@ -28341,7 +28409,7 @@ async function cmdWorkflowStart(runtime, definitionIdArg, options) {
|
|
|
28341
28409
|
}
|
|
28342
28410
|
let payload;
|
|
28343
28411
|
try {
|
|
28344
|
-
const raw = payloadFlag.startsWith("@") ?
|
|
28412
|
+
const raw = payloadFlag.startsWith("@") ? readFileSync18(resolve15(runtime.cwd, payloadFlag.slice(1)), "utf8") : payloadFlag;
|
|
28345
28413
|
const value = JSON.parse(raw);
|
|
28346
28414
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("object required");
|
|
28347
28415
|
payload = value;
|
|
@@ -28408,7 +28476,7 @@ async function cmdWorkflowDegrade(runtime, runId, stageId, options) {
|
|
|
28408
28476
|
}
|
|
28409
28477
|
}
|
|
28410
28478
|
async function cmdWorkflowInspect(runtime, action, runId) {
|
|
28411
|
-
const dataPath =
|
|
28479
|
+
const dataPath = resolve15(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join20(runtime.dirs.state, "kxm.db"));
|
|
28412
28480
|
if (action === "get" && !runId) {
|
|
28413
28481
|
runtime.io.stderr(`Usage: ${CLI_NAME} workflow get <runId>
|
|
28414
28482
|
`);
|
|
@@ -28577,14 +28645,14 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28577
28645
|
return 2;
|
|
28578
28646
|
}
|
|
28579
28647
|
const snapshotFlag = String(options.input || "");
|
|
28580
|
-
const snapshotPath = snapshotFlag ?
|
|
28648
|
+
const snapshotPath = snapshotFlag ? resolve15(runtime.cwd, snapshotFlag) : "";
|
|
28581
28649
|
let snapshot;
|
|
28582
28650
|
try {
|
|
28583
28651
|
if (snapshotPath) {
|
|
28584
|
-
if (!
|
|
28585
|
-
snapshot = JSON.parse(
|
|
28652
|
+
if (!existsSync18(snapshotPath)) throw new Error("snapshot_missing");
|
|
28653
|
+
snapshot = JSON.parse(readFileSync18(snapshotPath, "utf8"));
|
|
28586
28654
|
} else {
|
|
28587
|
-
const dataPath =
|
|
28655
|
+
const dataPath = resolve15(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join20(runtime.dirs.state, "kxm.db"));
|
|
28588
28656
|
const local = localWorkflowSnapshot(dataPath, runId);
|
|
28589
28657
|
if (!local.runs[0]) throw new Error("workflow_not_found");
|
|
28590
28658
|
snapshot = { run: local.runs[0], journal: local.journal };
|
|
@@ -28596,8 +28664,8 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28596
28664
|
return 1;
|
|
28597
28665
|
}
|
|
28598
28666
|
const doc = buildRetrospective(snapshot.run, snapshot.journal);
|
|
28599
|
-
const outDir =
|
|
28600
|
-
const assetsRoot =
|
|
28667
|
+
const outDir = resolve15(runtime.cwd, String(options.outDir || join20(runtime.dirs.assets, "retrospectives")));
|
|
28668
|
+
const assetsRoot = resolve15(runtime.dirs.assets);
|
|
28601
28669
|
const assetsPrefix = `${assetsRoot}${process.platform === "win32" ? "\\" : "/"}`;
|
|
28602
28670
|
if (outDir !== assetsRoot && !outDir.startsWith(assetsPrefix)) {
|
|
28603
28671
|
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 +28682,8 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28614
28682
|
|
|
28615
28683
|
// plugins/kxm/src/cli/tasks.ts
|
|
28616
28684
|
var import_yaml13 = __toESM(require_dist(), 1);
|
|
28617
|
-
import { existsSync as
|
|
28618
|
-
import { basename as basename6, join as
|
|
28685
|
+
import { existsSync as existsSync24, readFileSync as readFileSync23, readdirSync as readdirSync8 } from "node:fs";
|
|
28686
|
+
import { basename as basename6, join as join28, resolve as resolve21 } from "node:path";
|
|
28619
28687
|
|
|
28620
28688
|
// plugins/kxm/src/suggest.ts
|
|
28621
28689
|
var WORKFLOW_PATTERNS = [
|
|
@@ -28726,19 +28794,19 @@ function suggestWorkflowAndRoles(prompt, options = {}) {
|
|
|
28726
28794
|
// plugins/kxm/src/task-manager.ts
|
|
28727
28795
|
var import_yaml10 = __toESM(require_dist(), 1);
|
|
28728
28796
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
28729
|
-
import { existsSync as
|
|
28730
|
-
import { join as
|
|
28797
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync15, readFileSync as readFileSync19, readdirSync as readdirSync6, writeFileSync as writeFileSync14 } from "node:fs";
|
|
28798
|
+
import { join as join21, resolve as resolve16 } from "node:path";
|
|
28731
28799
|
var GOAL_SCHEMA = "kxm.goal.v1";
|
|
28732
28800
|
var TASK_SCHEMA = "kxm.task.v1";
|
|
28733
28801
|
function goalsDirectory(repoRoot) {
|
|
28734
|
-
return
|
|
28802
|
+
return resolve16(repoRoot, ".kxm", "goals");
|
|
28735
28803
|
}
|
|
28736
28804
|
function tasksDirectory(repoRoot) {
|
|
28737
|
-
return
|
|
28805
|
+
return resolve16(repoRoot, ".kxm", "tasks");
|
|
28738
28806
|
}
|
|
28739
28807
|
function createGoal(repoRoot, input) {
|
|
28740
28808
|
const dir = goalsDirectory(repoRoot);
|
|
28741
|
-
|
|
28809
|
+
mkdirSync15(dir, { recursive: true });
|
|
28742
28810
|
const id = `goal_${randomUUID8().replaceAll("-", "").slice(0, 12)}`;
|
|
28743
28811
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
28744
28812
|
const record = {
|
|
@@ -28752,19 +28820,19 @@ function createGoal(repoRoot, input) {
|
|
|
28752
28820
|
createdAt: now,
|
|
28753
28821
|
updatedAt: now
|
|
28754
28822
|
};
|
|
28755
|
-
const filePath =
|
|
28756
|
-
|
|
28823
|
+
const filePath = join21(dir, `${id}.yaml`);
|
|
28824
|
+
writeFileSync14(filePath, (0, import_yaml10.stringify)(record).trim() + "\n", "utf8");
|
|
28757
28825
|
return record;
|
|
28758
28826
|
}
|
|
28759
28827
|
function listGoals(repoRoot) {
|
|
28760
28828
|
const dir = goalsDirectory(repoRoot);
|
|
28761
|
-
if (!
|
|
28829
|
+
if (!existsSync19(dir)) return [];
|
|
28762
28830
|
const goals = [];
|
|
28763
28831
|
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
28764
28832
|
for (const entry of entries) {
|
|
28765
28833
|
if (entry.isFile() && (entry.name.endsWith(".yaml") || entry.name.endsWith(".yml"))) {
|
|
28766
28834
|
try {
|
|
28767
|
-
const text =
|
|
28835
|
+
const text = readFileSync19(join21(dir, entry.name), "utf8");
|
|
28768
28836
|
const doc = (0, import_yaml10.parse)(text);
|
|
28769
28837
|
if (doc && doc.schema === GOAL_SCHEMA) goals.push(doc);
|
|
28770
28838
|
} catch {
|
|
@@ -28775,7 +28843,7 @@ function listGoals(repoRoot) {
|
|
|
28775
28843
|
}
|
|
28776
28844
|
function createTask(repoRoot, input) {
|
|
28777
28845
|
const dir = tasksDirectory(repoRoot);
|
|
28778
|
-
|
|
28846
|
+
mkdirSync15(dir, { recursive: true });
|
|
28779
28847
|
const id = `task_${randomUUID8().replaceAll("-", "").slice(0, 12)}`;
|
|
28780
28848
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
28781
28849
|
const record = {
|
|
@@ -28797,19 +28865,19 @@ function createTask(repoRoot, input) {
|
|
|
28797
28865
|
createdAt: now,
|
|
28798
28866
|
updatedAt: now
|
|
28799
28867
|
};
|
|
28800
|
-
const filePath =
|
|
28801
|
-
|
|
28868
|
+
const filePath = join21(dir, `${id}.yaml`);
|
|
28869
|
+
writeFileSync14(filePath, (0, import_yaml10.stringify)(record).trim() + "\n", "utf8");
|
|
28802
28870
|
return record;
|
|
28803
28871
|
}
|
|
28804
28872
|
function listTasks(repoRoot, options = {}) {
|
|
28805
28873
|
const dir = tasksDirectory(repoRoot);
|
|
28806
|
-
if (!
|
|
28874
|
+
if (!existsSync19(dir)) return [];
|
|
28807
28875
|
const tasks = [];
|
|
28808
28876
|
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
28809
28877
|
for (const entry of entries) {
|
|
28810
28878
|
if (entry.isFile() && (entry.name.endsWith(".yaml") || entry.name.endsWith(".yml"))) {
|
|
28811
28879
|
try {
|
|
28812
|
-
const text =
|
|
28880
|
+
const text = readFileSync19(join21(dir, entry.name), "utf8");
|
|
28813
28881
|
const doc = (0, import_yaml10.parse)(text);
|
|
28814
28882
|
if (doc && doc.schema === TASK_SCHEMA) {
|
|
28815
28883
|
if (options.goalId && doc.goalId !== options.goalId) continue;
|
|
@@ -28824,10 +28892,10 @@ function listTasks(repoRoot, options = {}) {
|
|
|
28824
28892
|
}
|
|
28825
28893
|
function getTask(repoRoot, taskId) {
|
|
28826
28894
|
const dir = tasksDirectory(repoRoot);
|
|
28827
|
-
const filePath =
|
|
28828
|
-
if (!
|
|
28895
|
+
const filePath = join21(dir, `${taskId}.yaml`);
|
|
28896
|
+
if (!existsSync19(filePath)) return void 0;
|
|
28829
28897
|
try {
|
|
28830
|
-
const text =
|
|
28898
|
+
const text = readFileSync19(filePath, "utf8");
|
|
28831
28899
|
const doc = (0, import_yaml10.parse)(text);
|
|
28832
28900
|
return doc && doc.schema === TASK_SCHEMA ? doc : void 0;
|
|
28833
28901
|
} catch {
|
|
@@ -28842,8 +28910,8 @@ function updateTaskStatus(repoRoot, taskId, status, options = {}) {
|
|
|
28842
28910
|
task.status = status;
|
|
28843
28911
|
if (options.workflowRunId) task.workflowRunId = options.workflowRunId;
|
|
28844
28912
|
task.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
28845
|
-
const filePath =
|
|
28846
|
-
|
|
28913
|
+
const filePath = join21(tasksDirectory(repoRoot), `${taskId}.yaml`);
|
|
28914
|
+
writeFileSync14(filePath, (0, import_yaml10.stringify)(task).trim() + "\n", "utf8");
|
|
28847
28915
|
return task;
|
|
28848
28916
|
}
|
|
28849
28917
|
function syncTaskWithTracker(repoRoot, taskId, options = {}) {
|
|
@@ -28858,8 +28926,8 @@ function syncTaskWithTracker(repoRoot, taskId, options = {}) {
|
|
|
28858
28926
|
task.trackerSync.syncStatus = "synced";
|
|
28859
28927
|
task.trackerSync.lastSyncedAt = now;
|
|
28860
28928
|
task.updatedAt = now;
|
|
28861
|
-
const filePath =
|
|
28862
|
-
|
|
28929
|
+
const filePath = join21(tasksDirectory(repoRoot), `${taskId}.yaml`);
|
|
28930
|
+
writeFileSync14(filePath, (0, import_yaml10.stringify)(task).trim() + "\n", "utf8");
|
|
28863
28931
|
return task;
|
|
28864
28932
|
}
|
|
28865
28933
|
|
|
@@ -29625,13 +29693,13 @@ function createStudioServer(options = {}) {
|
|
|
29625
29693
|
}
|
|
29626
29694
|
|
|
29627
29695
|
// plugins/kxm/src/cli/vnext.ts
|
|
29628
|
-
import { join as
|
|
29696
|
+
import { join as join27, resolve as resolve20 } from "node:path";
|
|
29629
29697
|
import { createInterface as createInterface2 } from "node:readline";
|
|
29630
29698
|
|
|
29631
29699
|
// plugins/kxm/src/model-inventory.ts
|
|
29632
29700
|
var import_yaml11 = __toESM(require_dist(), 1);
|
|
29633
|
-
import { mkdirSync as
|
|
29634
|
-
import { join as
|
|
29701
|
+
import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync15 } from "node:fs";
|
|
29702
|
+
import { join as join22 } from "node:path";
|
|
29635
29703
|
var OR_URL = "https://openrouter.ai/api/v1/models";
|
|
29636
29704
|
var NOUS_URL = "https://inference-api.nousresearch.com/v1/models";
|
|
29637
29705
|
function price(value) {
|
|
@@ -29717,41 +29785,41 @@ async function refreshModelInventory(options) {
|
|
|
29717
29785
|
sources.nous = { url: nousUrl, ok: !nous.error, ...nous.error ? { error: nous.error } : {} };
|
|
29718
29786
|
for (const item of nous.data) add(item, "nous", "discount");
|
|
29719
29787
|
const inventory = { schema: "kxm.model-inventory.v1", fetchedAt, currency: "USD", sources, models: [...byId.values()].sort((a, b2) => a.id.localeCompare(b2.id)) };
|
|
29720
|
-
|
|
29721
|
-
|
|
29788
|
+
mkdirSync16(join22(options.outputRoot, ".kxm", "models"), { recursive: true });
|
|
29789
|
+
writeFileSync15(join22(options.outputRoot, ".kxm", "models", "inventory.yaml"), (0, import_yaml11.stringify)(inventory), "utf8");
|
|
29722
29790
|
return inventory;
|
|
29723
29791
|
}
|
|
29724
29792
|
|
|
29725
29793
|
// plugins/kxm/src/vnext-init.ts
|
|
29726
29794
|
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
29727
|
-
import { existsSync as
|
|
29728
|
-
import { basename as basename5, join as
|
|
29795
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
29796
|
+
import { basename as basename5, join as join25 } from "node:path";
|
|
29729
29797
|
|
|
29730
29798
|
// plugins/kxm/src/vnext-repair.ts
|
|
29731
29799
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
29732
29800
|
import {
|
|
29733
29801
|
chmodSync as chmodSync5,
|
|
29734
29802
|
closeSync as closeSync2,
|
|
29735
|
-
existsSync as
|
|
29803
|
+
existsSync as existsSync21,
|
|
29736
29804
|
fsyncSync as fsyncSync2,
|
|
29737
29805
|
linkSync,
|
|
29738
29806
|
lstatSync as lstatSync7,
|
|
29739
|
-
mkdirSync as
|
|
29807
|
+
mkdirSync as mkdirSync18,
|
|
29740
29808
|
openSync as openSync2,
|
|
29741
|
-
readFileSync as
|
|
29809
|
+
readFileSync as readFileSync21,
|
|
29742
29810
|
readdirSync as readdirSync7,
|
|
29743
|
-
renameSync as
|
|
29744
|
-
rmSync as
|
|
29745
|
-
writeFileSync as
|
|
29811
|
+
renameSync as renameSync6,
|
|
29812
|
+
rmSync as rmSync8,
|
|
29813
|
+
writeFileSync as writeFileSync17
|
|
29746
29814
|
} from "node:fs";
|
|
29747
|
-
import { dirname as
|
|
29815
|
+
import { dirname as dirname15, isAbsolute as isAbsolute7, join as join24, relative as relative4, resolve as resolve18 } from "node:path";
|
|
29748
29816
|
|
|
29749
29817
|
// plugins/kxm/src/vnext-permission.ts
|
|
29750
29818
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
29751
29819
|
import { createHash as createHash12 } from "node:crypto";
|
|
29752
|
-
import { existsSync as
|
|
29820
|
+
import { existsSync as existsSync20, mkdtempSync, mkdirSync as mkdirSync17, readFileSync as readFileSync20, rmSync as rmSync7, writeFileSync as writeFileSync16 } from "node:fs";
|
|
29753
29821
|
import { tmpdir } from "node:os";
|
|
29754
|
-
import { dirname as
|
|
29822
|
+
import { dirname as dirname14, join as join23, resolve as resolve17, sep as sep3 } from "node:path";
|
|
29755
29823
|
var PROSE_FIELDS = {
|
|
29756
29824
|
project: /* @__PURE__ */ new Set(["name", "description"]),
|
|
29757
29825
|
repository: /* @__PURE__ */ new Set(["description"]),
|
|
@@ -30272,8 +30340,8 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30272
30340
|
const tree = resolveTreeRevision(root, revision);
|
|
30273
30341
|
const listing = gitBuffer(root, ["ls-tree", "-r", "-z", "--name-only", tree]).toString("utf8");
|
|
30274
30342
|
const paths = listing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
30275
|
-
const shadow = mkdtempSync(
|
|
30276
|
-
const shadowResolved =
|
|
30343
|
+
const shadow = mkdtempSync(join23(tmpdir(), "kxm-permission-base-"));
|
|
30344
|
+
const shadowResolved = resolve17(shadow);
|
|
30277
30345
|
const shadowMembersDir = `.kxm-shadow-members-${createHash12("sha256").update(shadowResolved, "utf8").digest("hex").slice(0, 8)}`;
|
|
30278
30346
|
try {
|
|
30279
30347
|
for (const path4 of paths) {
|
|
@@ -30286,8 +30354,8 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30286
30354
|
message: "Git tree entry contains a traversal or non-portable segment"
|
|
30287
30355
|
}]);
|
|
30288
30356
|
}
|
|
30289
|
-
const absolute =
|
|
30290
|
-
const resolved =
|
|
30357
|
+
const absolute = join23(shadowResolved, ...segments);
|
|
30358
|
+
const resolved = resolve17(absolute);
|
|
30291
30359
|
if (!resolved.startsWith(`${shadowResolved}${sep3}`)) {
|
|
30292
30360
|
throw new VnextConfigError([{
|
|
30293
30361
|
phase: "path",
|
|
@@ -30297,11 +30365,11 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30297
30365
|
}]);
|
|
30298
30366
|
}
|
|
30299
30367
|
const content = gitBuffer(root, ["cat-file", "blob", `${tree}:${path4}`]);
|
|
30300
|
-
|
|
30301
|
-
|
|
30368
|
+
mkdirSync17(dirname14(absolute), { recursive: true });
|
|
30369
|
+
writeFileSync16(absolute, content);
|
|
30302
30370
|
}
|
|
30303
30371
|
initShadowGitRoot(shadowResolved);
|
|
30304
|
-
const baseProjectFile =
|
|
30372
|
+
const baseProjectFile = join23(shadowResolved, ".kxm", "project.yaml");
|
|
30305
30373
|
let baseProject;
|
|
30306
30374
|
try {
|
|
30307
30375
|
baseProject = loadBaseProjectDeclarations(baseProjectFile);
|
|
@@ -30331,8 +30399,8 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30331
30399
|
}]);
|
|
30332
30400
|
}
|
|
30333
30401
|
const boundPath = options.repositoryBindings?.[member.repositoryId];
|
|
30334
|
-
const memberWorktree = boundPath ?
|
|
30335
|
-
if (!memberWorktree || !
|
|
30402
|
+
const memberWorktree = boundPath ? resolve17(boundPath) : member.pathHint ? resolve17(root, ...member.pathHint.split("/")) : void 0;
|
|
30403
|
+
if (!memberWorktree || !existsSync20(memberWorktree)) {
|
|
30336
30404
|
if (member.required === false) continue;
|
|
30337
30405
|
throw new VnextConfigError([{
|
|
30338
30406
|
phase: "discovery",
|
|
@@ -30379,8 +30447,8 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30379
30447
|
const memberTree = git(memberWorktree, ["rev-parse", "--verify", "--quiet", `${pinnedCommit}^{tree}`]).trim();
|
|
30380
30448
|
const memberListing = gitBuffer(memberWorktree, ["ls-tree", "-r", "-z", "--name-only", memberTree]).toString("utf8");
|
|
30381
30449
|
const memberPaths = memberListing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
30382
|
-
const memberShadowRoot =
|
|
30383
|
-
if (!
|
|
30450
|
+
const memberShadowRoot = join23(shadowResolved, shadowMembersDir, member.repositoryId);
|
|
30451
|
+
if (!resolve17(memberShadowRoot).startsWith(`${resolve17(shadowResolved, shadowMembersDir)}${sep3}`)) {
|
|
30384
30452
|
throw new VnextConfigError([{
|
|
30385
30453
|
phase: "path",
|
|
30386
30454
|
code: "git_tree_path_invalid",
|
|
@@ -30393,14 +30461,14 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30393
30461
|
if (segments.some((segment) => segment === "" || segment === "." || segment === ".." || /[\\:]/.test(segment))) {
|
|
30394
30462
|
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
30463
|
}
|
|
30396
|
-
const absolute =
|
|
30397
|
-
const resolved =
|
|
30398
|
-
if (!resolved.startsWith(`${
|
|
30464
|
+
const absolute = join23(memberShadowRoot, ...segments);
|
|
30465
|
+
const resolved = resolve17(absolute);
|
|
30466
|
+
if (!resolved.startsWith(`${resolve17(memberShadowRoot)}${sep3}`)) {
|
|
30399
30467
|
throw new VnextConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path4, message: "member Git tree entry escapes the shadow root" }]);
|
|
30400
30468
|
}
|
|
30401
30469
|
const content = gitBuffer(memberWorktree, ["cat-file", "blob", `${memberTree}:${path4}`]);
|
|
30402
|
-
|
|
30403
|
-
|
|
30470
|
+
mkdirSync17(dirname14(absolute), { recursive: true });
|
|
30471
|
+
writeFileSync16(absolute, content);
|
|
30404
30472
|
}
|
|
30405
30473
|
initShadowGitRoot(memberShadowRoot);
|
|
30406
30474
|
shadowBindings[member.repositoryId] = memberShadowRoot;
|
|
@@ -30414,15 +30482,15 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30414
30482
|
throw error;
|
|
30415
30483
|
}
|
|
30416
30484
|
} finally {
|
|
30417
|
-
|
|
30485
|
+
rmSync7(shadow, { recursive: true, force: true });
|
|
30418
30486
|
}
|
|
30419
30487
|
}
|
|
30420
30488
|
function portableMemberPathHint(pathHint) {
|
|
30421
30489
|
return pathHint !== "." && vnextPortablePath(pathHint);
|
|
30422
30490
|
}
|
|
30423
30491
|
function loadBaseProjectDeclarations(projectFile) {
|
|
30424
|
-
if (!
|
|
30425
|
-
const value = parseRestrictedYaml2(
|
|
30492
|
+
if (!existsSync20(projectFile)) return [];
|
|
30493
|
+
const value = parseRestrictedYaml2(readFileSync20(projectFile, "utf8"), ".kxm/project.yaml");
|
|
30426
30494
|
const repositories = Array.isArray(value?.repositories) ? value.repositories : [];
|
|
30427
30495
|
const members = [];
|
|
30428
30496
|
for (const entry of repositories) {
|
|
@@ -30514,7 +30582,7 @@ function writeDurableNew(file, bytes, mode) {
|
|
|
30514
30582
|
let descriptor;
|
|
30515
30583
|
try {
|
|
30516
30584
|
descriptor = openSync2(file, "wx", mode);
|
|
30517
|
-
|
|
30585
|
+
writeFileSync17(descriptor, bytes);
|
|
30518
30586
|
fsyncSync2(descriptor);
|
|
30519
30587
|
closeSync2(descriptor);
|
|
30520
30588
|
descriptor = void 0;
|
|
@@ -30525,13 +30593,13 @@ function writeDurableNew(file, bytes, mode) {
|
|
|
30525
30593
|
} finally {
|
|
30526
30594
|
if (descriptor !== void 0) closeSync2(descriptor);
|
|
30527
30595
|
}
|
|
30528
|
-
syncDirectory2(
|
|
30596
|
+
syncDirectory2(dirname15(file));
|
|
30529
30597
|
}
|
|
30530
30598
|
function writeDurable(file, bytes, mode) {
|
|
30531
30599
|
let descriptor;
|
|
30532
30600
|
try {
|
|
30533
30601
|
descriptor = openSync2(file, "w", mode);
|
|
30534
|
-
|
|
30602
|
+
writeFileSync17(descriptor, bytes);
|
|
30535
30603
|
fsyncSync2(descriptor);
|
|
30536
30604
|
closeSync2(descriptor);
|
|
30537
30605
|
descriptor = void 0;
|
|
@@ -30542,53 +30610,53 @@ function writeDurable(file, bytes, mode) {
|
|
|
30542
30610
|
} finally {
|
|
30543
30611
|
if (descriptor !== void 0) closeSync2(descriptor);
|
|
30544
30612
|
}
|
|
30545
|
-
syncDirectory2(
|
|
30613
|
+
syncDirectory2(dirname15(file));
|
|
30546
30614
|
}
|
|
30547
30615
|
function sameHostPath3(left, right) {
|
|
30548
|
-
const first =
|
|
30549
|
-
const second =
|
|
30616
|
+
const first = resolve18(left);
|
|
30617
|
+
const second = resolve18(right);
|
|
30550
30618
|
return process.platform === "win32" ? first.toLocaleLowerCase("en-US") === second.toLocaleLowerCase("en-US") : first === second;
|
|
30551
30619
|
}
|
|
30552
30620
|
function transactionRoot(projectRoot) {
|
|
30553
|
-
return
|
|
30621
|
+
return join24(resolve18(projectRoot), TRANSACTION_NAME);
|
|
30554
30622
|
}
|
|
30555
30623
|
function operationFile(projectRoot) {
|
|
30556
|
-
return
|
|
30624
|
+
return join24(transactionRoot(projectRoot), OPERATION_FILE);
|
|
30557
30625
|
}
|
|
30558
30626
|
function targetFile(projectRoot, portablePath2) {
|
|
30559
|
-
return
|
|
30627
|
+
return join24(transactionRoot(projectRoot), "targets", ...portablePath2.split("/"));
|
|
30560
30628
|
}
|
|
30561
30629
|
function shadowRoot(projectRoot) {
|
|
30562
|
-
return
|
|
30630
|
+
return join24(transactionRoot(projectRoot), "shadow");
|
|
30563
30631
|
}
|
|
30564
30632
|
function backupFile(projectRoot, portablePath2) {
|
|
30565
|
-
return
|
|
30633
|
+
return join24(transactionRoot(projectRoot), "backups", ...portablePath2.split("/"));
|
|
30566
30634
|
}
|
|
30567
30635
|
function portableManagedPath(path4) {
|
|
30568
|
-
return path4.startsWith(".kxm/") && path4 !== VNEXT_TEMPLATE_PROVENANCE_PATH && path4.length <= 1024 && !path4.includes("\\") && !
|
|
30636
|
+
return path4.startsWith(".kxm/") && path4 !== VNEXT_TEMPLATE_PROVENANCE_PATH && path4.length <= 1024 && !path4.includes("\\") && !isAbsolute7(path4) && PORTABLE_PATH.test(path4) && !/[<>:"|?*]/.test(path4);
|
|
30569
30637
|
}
|
|
30570
30638
|
function readRegularBounded(file, label) {
|
|
30571
30639
|
const stat = lstatSync7(file);
|
|
30572
30640
|
if (stat.isSymbolicLink() || !stat.isFile()) fail3("repair_file_invalid", label, "managed file must be a regular file, not a link or directory", "path");
|
|
30573
30641
|
if (stat.size > MAX_MANAGED_FILE_BYTES) fail3("repair_file_too_large", label, `managed file exceeds ${MAX_MANAGED_FILE_BYTES} bytes`, "parse");
|
|
30574
|
-
return
|
|
30642
|
+
return readFileSync21(file);
|
|
30575
30643
|
}
|
|
30576
30644
|
function readOptionalManaged(projectRoot, path4) {
|
|
30577
|
-
const file =
|
|
30578
|
-
if (!
|
|
30579
|
-
let parent =
|
|
30580
|
-
const boundary =
|
|
30645
|
+
const file = join24(projectRoot, ...path4.split("/"));
|
|
30646
|
+
if (!existsSync21(file)) return void 0;
|
|
30647
|
+
let parent = dirname15(file);
|
|
30648
|
+
const boundary = resolve18(projectRoot);
|
|
30581
30649
|
while (parent !== boundary) {
|
|
30582
30650
|
const stat = lstatSync7(parent);
|
|
30583
30651
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_parent_invalid", path4, "managed file parents must be regular directories", "path");
|
|
30584
|
-
parent =
|
|
30652
|
+
parent = dirname15(parent);
|
|
30585
30653
|
}
|
|
30586
30654
|
return readRegularBounded(file, path4);
|
|
30587
30655
|
}
|
|
30588
30656
|
function readProjectAndProvenance(projectRoot, schemasDir) {
|
|
30589
|
-
const projectFile =
|
|
30590
|
-
const provenanceFile =
|
|
30591
|
-
if (!
|
|
30657
|
+
const projectFile = join24(projectRoot, ".kxm", "project.yaml");
|
|
30658
|
+
const provenanceFile = join24(projectRoot, ...VNEXT_TEMPLATE_PROVENANCE_PATH.split("/"));
|
|
30659
|
+
if (!existsSync21(projectFile) || !existsSync21(provenanceFile)) return void 0;
|
|
30592
30660
|
const projectBytes = readOptionalManaged(projectRoot, ".kxm/project.yaml");
|
|
30593
30661
|
const provenanceBytes = readOptionalManaged(projectRoot, VNEXT_TEMPLATE_PROVENANCE_PATH);
|
|
30594
30662
|
if (!projectBytes || !provenanceBytes) return void 0;
|
|
@@ -30624,7 +30692,7 @@ function readProjectAndProvenance(projectRoot, schemasDir) {
|
|
|
30624
30692
|
}
|
|
30625
30693
|
function planVnextTemplateRepair(projectRoot, options = {}) {
|
|
30626
30694
|
assertNoRegisteredGates(options);
|
|
30627
|
-
const root =
|
|
30695
|
+
const root = resolve18(projectRoot);
|
|
30628
30696
|
const source = readProjectAndProvenance(root, options.schemasDir);
|
|
30629
30697
|
if (!source) return void 0;
|
|
30630
30698
|
const target = renderVnextTemplate(
|
|
@@ -30752,14 +30820,14 @@ function operationPlanSha(operation) {
|
|
|
30752
30820
|
function writeOperation(projectRoot, operation) {
|
|
30753
30821
|
const root = transactionRoot(projectRoot);
|
|
30754
30822
|
const file = operationFile(projectRoot);
|
|
30755
|
-
const temporary =
|
|
30823
|
+
const temporary = join24(root, `.operation-${operation.operationId}-${randomUUID10()}.tmp`);
|
|
30756
30824
|
try {
|
|
30757
30825
|
writeDurableNew(temporary, Buffer.from(`${JSON.stringify(operation, null, 2)}
|
|
30758
30826
|
`, "utf8"), 384);
|
|
30759
|
-
|
|
30827
|
+
renameSync6(temporary, file);
|
|
30760
30828
|
syncDirectory2(root);
|
|
30761
30829
|
} finally {
|
|
30762
|
-
|
|
30830
|
+
rmSync8(temporary, { force: true });
|
|
30763
30831
|
}
|
|
30764
30832
|
}
|
|
30765
30833
|
function updatePhase(projectRoot, operation, phase) {
|
|
@@ -30769,11 +30837,11 @@ function updatePhase(projectRoot, operation, phase) {
|
|
|
30769
30837
|
}
|
|
30770
30838
|
function readOperation(projectRoot, schemasDir) {
|
|
30771
30839
|
const root = transactionRoot(projectRoot);
|
|
30772
|
-
if (!
|
|
30840
|
+
if (!existsSync21(root)) return void 0;
|
|
30773
30841
|
const stat = lstatSync7(root);
|
|
30774
30842
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("init_transaction_invalid", TRANSACTION_NAME, "initialization transaction must be a regular directory", "path");
|
|
30775
30843
|
const file = operationFile(projectRoot);
|
|
30776
|
-
if (!
|
|
30844
|
+
if (!existsSync21(file)) {
|
|
30777
30845
|
const entries = readdirSync7(root, { withFileTypes: true });
|
|
30778
30846
|
const recoverable = entries.every((entry) => entry.isFile() && /^\.operation-op_[a-f0-9]{32}-[a-f0-9-]{36}\.tmp$/.test(entry.name));
|
|
30779
30847
|
if (recoverable) return void 0;
|
|
@@ -30796,20 +30864,20 @@ function readOperation(projectRoot, schemasDir) {
|
|
|
30796
30864
|
seen.add(folded);
|
|
30797
30865
|
prior = entry.path;
|
|
30798
30866
|
}
|
|
30799
|
-
if (!
|
|
30867
|
+
if (!isAbsolute7(operation.projectRoot)) fail3("init_transaction_project_root_invalid", TRANSACTION_NAME, "operation project root must be absolute", "path");
|
|
30800
30868
|
validateOperationIntent(projectRoot, operation);
|
|
30801
30869
|
return operation;
|
|
30802
30870
|
}
|
|
30803
30871
|
function hasVnextInitTransaction(projectRoot) {
|
|
30804
|
-
return
|
|
30872
|
+
return existsSync21(transactionRoot(projectRoot));
|
|
30805
30873
|
}
|
|
30806
30874
|
function readTarget(projectRoot, path4) {
|
|
30807
|
-
return readOptionalManaged(
|
|
30875
|
+
return readOptionalManaged(join24(transactionRoot(projectRoot), "targets"), path4);
|
|
30808
30876
|
}
|
|
30809
30877
|
function writeTarget(projectRoot, path4, bytes) {
|
|
30810
30878
|
if (bytes.byteLength > MAX_MANAGED_FILE_BYTES) fail3("template_target_too_large", path4, `target exceeds ${MAX_MANAGED_FILE_BYTES} bytes`);
|
|
30811
30879
|
const file = targetFile(projectRoot, path4);
|
|
30812
|
-
|
|
30880
|
+
mkdirSync18(dirname15(file), { recursive: true, mode: 448 });
|
|
30813
30881
|
writeDurableNew(file, bytes, 384);
|
|
30814
30882
|
}
|
|
30815
30883
|
function writeAndVerifyBackups(projectRoot, operation) {
|
|
@@ -30821,7 +30889,7 @@ function writeAndVerifyBackups(projectRoot, operation) {
|
|
|
30821
30889
|
fail3("repair_preimage_changed", entry.path, "destination changed before transaction preparation; local bytes were preserved");
|
|
30822
30890
|
}
|
|
30823
30891
|
const file = backupFile(projectRoot, entry.path);
|
|
30824
|
-
|
|
30892
|
+
mkdirSync18(dirname15(file), { recursive: true, mode: 448 });
|
|
30825
30893
|
writeDurableNew(file, current, 384);
|
|
30826
30894
|
}
|
|
30827
30895
|
}
|
|
@@ -30836,7 +30904,7 @@ function writeKnownBackups(projectRoot, operation) {
|
|
|
30836
30904
|
fail3("init_transaction_backup_source_invalid", entry.path, "supported source template cannot reproduce the pinned preimage");
|
|
30837
30905
|
}
|
|
30838
30906
|
const file = backupFile(projectRoot, entry.path);
|
|
30839
|
-
|
|
30907
|
+
mkdirSync18(dirname15(file), { recursive: true, mode: 448 });
|
|
30840
30908
|
writeDurableNew(file, bytes, 384);
|
|
30841
30909
|
}
|
|
30842
30910
|
}
|
|
@@ -30844,7 +30912,7 @@ function verifyBackups(projectRoot, operation) {
|
|
|
30844
30912
|
if (operation.kind !== "repair") return;
|
|
30845
30913
|
for (const entry of operation.files) {
|
|
30846
30914
|
if (entry.observedSha256 === null) continue;
|
|
30847
|
-
const bytes = readOptionalManaged(
|
|
30915
|
+
const bytes = readOptionalManaged(join24(transactionRoot(projectRoot), "backups"), entry.path);
|
|
30848
30916
|
if (!bytes || vnextContentSha256(bytes) !== entry.observedSha256) {
|
|
30849
30917
|
fail3("init_transaction_backup_invalid", entry.path, "pinned preimage backup is missing or corrupt");
|
|
30850
30918
|
}
|
|
@@ -30878,10 +30946,10 @@ function sourceConfigFiles(projectRoot) {
|
|
|
30878
30946
|
".kxm/repo/repo.yaml",
|
|
30879
30947
|
".kxm/repo/env.yaml"
|
|
30880
30948
|
];
|
|
30881
|
-
const files = fixed.filter((path4) =>
|
|
30949
|
+
const files = fixed.filter((path4) => existsSync21(join24(projectRoot, ...path4.split("/"))));
|
|
30882
30950
|
for (const directory of ["agents", "models", "workflows"]) {
|
|
30883
|
-
const absolute =
|
|
30884
|
-
if (!
|
|
30951
|
+
const absolute = join24(projectRoot, ".kxm", directory);
|
|
30952
|
+
if (!existsSync21(absolute)) continue;
|
|
30885
30953
|
const stat = lstatSync7(absolute);
|
|
30886
30954
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_directory_invalid", `.kxm/${directory}`, "configuration directory must be regular", "path");
|
|
30887
30955
|
for (const entry of readdirSync7(absolute, { withFileTypes: true })) {
|
|
@@ -30902,24 +30970,24 @@ function absoluteMemberBindings(projectRoot, project, explicit = {}) {
|
|
|
30902
30970
|
const repository = candidate;
|
|
30903
30971
|
if (repository.role !== "member" || typeof repository.id !== "string" || Object.hasOwn(bindings, repository.id)) continue;
|
|
30904
30972
|
if (typeof repository.pathHint === "string") {
|
|
30905
|
-
const candidate2 =
|
|
30906
|
-
if (
|
|
30973
|
+
const candidate2 = resolve18(projectRoot, ...repository.pathHint.split("/"));
|
|
30974
|
+
if (existsSync21(candidate2)) bindings[repository.id] = candidate2;
|
|
30907
30975
|
}
|
|
30908
30976
|
}
|
|
30909
30977
|
return bindings;
|
|
30910
30978
|
}
|
|
30911
30979
|
function prepareShadow(projectRoot, operation, options) {
|
|
30912
30980
|
const shadow = shadowRoot(projectRoot);
|
|
30913
|
-
|
|
30981
|
+
mkdirSync18(shadow, { recursive: true, mode: 448 });
|
|
30914
30982
|
let total = 0;
|
|
30915
30983
|
if (operation.kind === "repair") {
|
|
30916
30984
|
for (const path4 of sourceConfigFiles(projectRoot)) {
|
|
30917
30985
|
const bytes = readOptionalManaged(projectRoot, path4);
|
|
30918
30986
|
if (!bytes) fail3("repair_snapshot_file_missing", path4, "configuration changed during shadow preparation");
|
|
30919
30987
|
total += bytes.byteLength;
|
|
30920
|
-
const source =
|
|
30921
|
-
const destination =
|
|
30922
|
-
|
|
30988
|
+
const source = join24(projectRoot, ...path4.split("/"));
|
|
30989
|
+
const destination = join24(shadow, ...path4.split("/"));
|
|
30990
|
+
mkdirSync18(dirname15(destination), { recursive: true, mode: 448 });
|
|
30923
30991
|
writeDurableNew(destination, bytes, lstatSync7(source).mode & 511);
|
|
30924
30992
|
if (total > MAX_MANAGED_TOTAL_BYTES) fail3("repair_snapshot_too_large", ".kxm", `configuration snapshot exceeds ${MAX_MANAGED_TOTAL_BYTES} bytes`, "parse");
|
|
30925
30993
|
}
|
|
@@ -30927,12 +30995,12 @@ function prepareShadow(projectRoot, operation, options) {
|
|
|
30927
30995
|
for (const entry of operation.files) {
|
|
30928
30996
|
const bytes = readTarget(projectRoot, entry.path);
|
|
30929
30997
|
if (!bytes) fail3("init_transaction_target_missing", entry.path, "pinned target artifact is missing");
|
|
30930
|
-
const destination =
|
|
30931
|
-
|
|
30932
|
-
const mode =
|
|
30998
|
+
const destination = join24(shadow, ...entry.path.split("/"));
|
|
30999
|
+
mkdirSync18(dirname15(destination), { recursive: true, mode: 448 });
|
|
31000
|
+
const mode = existsSync21(destination) ? lstatSync7(destination).mode & 511 : 420;
|
|
30933
31001
|
writeDurable(destination, bytes, mode);
|
|
30934
31002
|
}
|
|
30935
|
-
const project = parseRestrictedYaml2(
|
|
31003
|
+
const project = parseRestrictedYaml2(readFileSync21(join24(shadow, ".kxm", "project.yaml")), ".kxm/project.yaml");
|
|
30936
31004
|
const bound = absoluteMemberBindings(projectRoot, project, options.repositoryBindings);
|
|
30937
31005
|
loadVnextProject(shadow, { ...loaderOptions(options), repositoryBindings: bound });
|
|
30938
31006
|
const provenance = readProjectAndProvenance(shadow, options.schemasDir)?.provenance;
|
|
@@ -30941,7 +31009,7 @@ function prepareShadow(projectRoot, operation, options) {
|
|
|
30941
31009
|
}
|
|
30942
31010
|
}
|
|
30943
31011
|
function createOperation(projectRoot, kind, rendered, files, sourceTemplateRevision) {
|
|
30944
|
-
const root =
|
|
31012
|
+
const root = resolve18(projectRoot);
|
|
30945
31013
|
const operationWithoutHash = {
|
|
30946
31014
|
schema: "kxm.init-operation.v1",
|
|
30947
31015
|
operationId: `op_${randomUUID10().replaceAll("-", "")}`,
|
|
@@ -30970,8 +31038,8 @@ function prepareOperation(projectRoot, operation, rendered, options) {
|
|
|
30970
31038
|
const transaction = transactionRoot(projectRoot);
|
|
30971
31039
|
validateOperationRecord(operation, options.schemasDir);
|
|
30972
31040
|
validateOperationIntent(projectRoot, operation);
|
|
30973
|
-
if (
|
|
30974
|
-
|
|
31041
|
+
if (existsSync21(transaction)) fail3("init_transaction_exists", TRANSACTION_NAME, "an initialization transaction already exists and must be resumed");
|
|
31042
|
+
mkdirSync18(transaction, { mode: 448 });
|
|
30975
31043
|
syncDirectory2(projectRoot);
|
|
30976
31044
|
writeOperation(projectRoot, operation);
|
|
30977
31045
|
try {
|
|
@@ -30987,30 +31055,30 @@ function prepareOperation(projectRoot, operation, rendered, options) {
|
|
|
30987
31055
|
syncTreeDirectories(transaction);
|
|
30988
31056
|
return updatePhase(projectRoot, operation, "prepared");
|
|
30989
31057
|
} catch (error) {
|
|
30990
|
-
|
|
31058
|
+
rmSync8(transaction, { recursive: true, force: true });
|
|
30991
31059
|
throw error;
|
|
30992
31060
|
}
|
|
30993
31061
|
}
|
|
30994
31062
|
function ensureDestinationParents(projectRoot, path4) {
|
|
30995
|
-
const boundary =
|
|
31063
|
+
const boundary = resolve18(projectRoot);
|
|
30996
31064
|
const segments = path4.split("/").slice(0, -1);
|
|
30997
31065
|
let current = boundary;
|
|
30998
31066
|
for (const segment of segments) {
|
|
30999
|
-
current =
|
|
31000
|
-
if (!
|
|
31067
|
+
current = join24(current, segment);
|
|
31068
|
+
if (!existsSync21(current)) mkdirSync18(current, { mode: 448 });
|
|
31001
31069
|
const stat = lstatSync7(current);
|
|
31002
31070
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_destination_parent_invalid", path4, "destination parent must be a regular directory", "path");
|
|
31003
31071
|
}
|
|
31004
31072
|
}
|
|
31005
31073
|
function destinationSha(projectRoot, path4) {
|
|
31006
|
-
const file =
|
|
31007
|
-
if (!
|
|
31074
|
+
const file = join24(projectRoot, ...path4.split("/"));
|
|
31075
|
+
if (!existsSync21(file)) return void 0;
|
|
31008
31076
|
return vnextContentSha256(readRegularBounded(file, path4));
|
|
31009
31077
|
}
|
|
31010
31078
|
function requireConditionalLinkSupport(directory, operationId, path4) {
|
|
31011
31079
|
const nonce = randomUUID10();
|
|
31012
|
-
const source =
|
|
31013
|
-
const target =
|
|
31080
|
+
const source = join24(directory, `.kxm-repair-${operationId}-${nonce}.link-source`);
|
|
31081
|
+
const target = join24(directory, `.kxm-repair-${operationId}-${nonce}.link-target`);
|
|
31014
31082
|
try {
|
|
31015
31083
|
writeDurableNew(source, Buffer.from("kxm-link-probe\n", "utf8"), 384);
|
|
31016
31084
|
try {
|
|
@@ -31019,25 +31087,25 @@ function requireConditionalLinkSupport(directory, operationId, path4) {
|
|
|
31019
31087
|
fail3("repair_hard_link_unsupported", path4, "filesystem does not support the conditional hard-link install required for safe repair");
|
|
31020
31088
|
}
|
|
31021
31089
|
} finally {
|
|
31022
|
-
|
|
31023
|
-
|
|
31090
|
+
rmSync8(target, { force: true });
|
|
31091
|
+
rmSync8(source, { force: true });
|
|
31024
31092
|
syncDirectory2(directory);
|
|
31025
31093
|
}
|
|
31026
31094
|
}
|
|
31027
31095
|
function atomicInstallTarget(projectRoot, operation, entry) {
|
|
31028
|
-
const destination =
|
|
31096
|
+
const destination = join24(projectRoot, ...entry.path.split("/"));
|
|
31029
31097
|
ensureDestinationParents(projectRoot, entry.path);
|
|
31030
|
-
const directory =
|
|
31098
|
+
const directory = dirname15(destination);
|
|
31031
31099
|
const temporaryPrefix = `.kxm-repair-${operation.operationId}-`;
|
|
31032
31100
|
const pathKey = vnextContentSha256(entry.path).slice("sha256:".length, "sha256:".length + 16);
|
|
31033
|
-
const displaced =
|
|
31034
|
-
if (
|
|
31101
|
+
const displaced = join24(directory, `${temporaryPrefix}${pathKey}.preimage`);
|
|
31102
|
+
if (existsSync21(displaced)) {
|
|
31035
31103
|
const stat = lstatSync7(displaced);
|
|
31036
31104
|
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(
|
|
31105
|
+
if (entry.observedSha256 === null || vnextContentSha256(readFileSync21(displaced)) !== entry.observedSha256) {
|
|
31038
31106
|
fail3("repair_preimage_temporary_mismatch", entry.path, "stale displaced preimage does not match the pinned operation");
|
|
31039
31107
|
}
|
|
31040
|
-
if (!
|
|
31108
|
+
if (!existsSync21(destination)) {
|
|
31041
31109
|
try {
|
|
31042
31110
|
linkSync(displaced, destination);
|
|
31043
31111
|
} catch {
|
|
@@ -31045,14 +31113,14 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31045
31113
|
}
|
|
31046
31114
|
syncDirectory2(directory);
|
|
31047
31115
|
}
|
|
31048
|
-
|
|
31116
|
+
rmSync8(displaced, { force: true });
|
|
31049
31117
|
syncDirectory2(directory);
|
|
31050
31118
|
}
|
|
31051
31119
|
for (const candidate of readdirSync7(directory, { withFileTypes: true })) {
|
|
31052
31120
|
const owned = candidate.name.startsWith(temporaryPrefix) && (candidate.name.endsWith(".tmp") || candidate.name.endsWith(".link-source") || candidate.name.endsWith(".link-target"));
|
|
31053
31121
|
if (!owned) continue;
|
|
31054
31122
|
if (!candidate.isFile()) fail3("repair_temporary_invalid", entry.path, "stale operation temporary is not a regular file", "path");
|
|
31055
|
-
|
|
31123
|
+
rmSync8(join24(directory, candidate.name), { force: true });
|
|
31056
31124
|
}
|
|
31057
31125
|
const current = destinationSha(projectRoot, entry.path);
|
|
31058
31126
|
if (current === entry.targetSha256) return;
|
|
@@ -31062,22 +31130,22 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31062
31130
|
requireConditionalLinkSupport(directory, operation.operationId, entry.path);
|
|
31063
31131
|
const bytes = readTarget(projectRoot, entry.path);
|
|
31064
31132
|
if (!bytes) fail3("init_transaction_target_missing", entry.path, "pinned target artifact is missing");
|
|
31065
|
-
const temporary =
|
|
31066
|
-
const mode =
|
|
31133
|
+
const temporary = join24(directory, `${temporaryPrefix}${randomUUID10()}.tmp`);
|
|
31134
|
+
const mode = existsSync21(destination) ? lstatSync7(destination).mode & 511 : 420;
|
|
31067
31135
|
try {
|
|
31068
31136
|
writeDurableNew(temporary, bytes, mode);
|
|
31069
31137
|
if (entry.observedSha256 !== null) {
|
|
31070
|
-
|
|
31138
|
+
renameSync6(destination, displaced);
|
|
31071
31139
|
syncDirectory2(directory);
|
|
31072
|
-
if (vnextContentSha256(
|
|
31073
|
-
if (!
|
|
31140
|
+
if (vnextContentSha256(readFileSync21(displaced)) !== entry.observedSha256) {
|
|
31141
|
+
if (!existsSync21(destination)) {
|
|
31074
31142
|
try {
|
|
31075
31143
|
linkSync(displaced, destination);
|
|
31076
31144
|
} catch {
|
|
31077
31145
|
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
31146
|
}
|
|
31079
31147
|
syncDirectory2(directory);
|
|
31080
|
-
|
|
31148
|
+
rmSync8(displaced, { force: true });
|
|
31081
31149
|
syncDirectory2(directory);
|
|
31082
31150
|
}
|
|
31083
31151
|
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 +31154,7 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31086
31154
|
try {
|
|
31087
31155
|
linkSync(temporary, destination);
|
|
31088
31156
|
} catch {
|
|
31089
|
-
if (!
|
|
31157
|
+
if (!existsSync21(destination) && existsSync21(displaced)) {
|
|
31090
31158
|
try {
|
|
31091
31159
|
linkSync(displaced, destination);
|
|
31092
31160
|
} catch {
|
|
@@ -31094,26 +31162,26 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31094
31162
|
}
|
|
31095
31163
|
syncDirectory2(directory);
|
|
31096
31164
|
}
|
|
31097
|
-
|
|
31165
|
+
rmSync8(displaced, { force: true });
|
|
31098
31166
|
syncDirectory2(directory);
|
|
31099
31167
|
fail3("repair_destination_recreated", entry.path, "destination was recreated concurrently or conditional install is unsupported; pinned target was not installed");
|
|
31100
31168
|
}
|
|
31101
31169
|
syncDirectory2(directory);
|
|
31102
|
-
|
|
31103
|
-
|
|
31170
|
+
rmSync8(temporary, { force: true });
|
|
31171
|
+
rmSync8(displaced, { force: true });
|
|
31104
31172
|
syncDirectory2(directory);
|
|
31105
31173
|
} finally {
|
|
31106
|
-
|
|
31174
|
+
rmSync8(temporary, { force: true });
|
|
31107
31175
|
}
|
|
31108
31176
|
if (destinationSha(projectRoot, entry.path) !== entry.targetSha256) fail3("repair_install_verification_failed", entry.path, "installed target hash does not match the pinned operation");
|
|
31109
31177
|
}
|
|
31110
31178
|
function installedCreateMatches(projectRoot, operation) {
|
|
31111
|
-
const configRoot =
|
|
31112
|
-
if (!
|
|
31179
|
+
const configRoot = join24(projectRoot, ".kxm");
|
|
31180
|
+
if (!existsSync21(configRoot)) return false;
|
|
31113
31181
|
const actual = [];
|
|
31114
31182
|
const visit2 = (directory) => {
|
|
31115
31183
|
for (const entry of readdirSync7(directory, { withFileTypes: true })) {
|
|
31116
|
-
const absolute =
|
|
31184
|
+
const absolute = join24(directory, entry.name);
|
|
31117
31185
|
if (entry.isSymbolicLink()) fail3("create_resume_link", relativeConfigPath(projectRoot, absolute), "created configuration must not contain links", "path");
|
|
31118
31186
|
if (entry.isDirectory()) visit2(absolute);
|
|
31119
31187
|
else if (entry.isFile()) actual.push(relativeConfigPath(projectRoot, absolute));
|
|
@@ -31126,15 +31194,15 @@ function installedCreateMatches(projectRoot, operation) {
|
|
|
31126
31194
|
return actual.length === expected.length && actual.every((path4, index) => path4 === expected[index]) && operation.files.every((entry) => destinationSha(projectRoot, entry.path) === entry.targetSha256);
|
|
31127
31195
|
}
|
|
31128
31196
|
function relativeConfigPath(projectRoot, file) {
|
|
31129
|
-
return relative4(
|
|
31197
|
+
return relative4(resolve18(projectRoot), file).replaceAll("\\", "/");
|
|
31130
31198
|
}
|
|
31131
31199
|
function syncTreeDirectories(root) {
|
|
31132
|
-
if (!
|
|
31200
|
+
if (!existsSync21(root)) return;
|
|
31133
31201
|
const directories = [];
|
|
31134
31202
|
const visit2 = (directory) => {
|
|
31135
31203
|
directories.push(directory);
|
|
31136
31204
|
for (const entry of readdirSync7(directory, { withFileTypes: true })) {
|
|
31137
|
-
if (entry.isDirectory()) visit2(
|
|
31205
|
+
if (entry.isDirectory()) visit2(join24(directory, entry.name));
|
|
31138
31206
|
}
|
|
31139
31207
|
};
|
|
31140
31208
|
visit2(root);
|
|
@@ -31142,13 +31210,13 @@ function syncTreeDirectories(root) {
|
|
|
31142
31210
|
}
|
|
31143
31211
|
function rebuildCreateShadow(projectRoot, operation, options) {
|
|
31144
31212
|
const shadow = shadowRoot(projectRoot);
|
|
31145
|
-
|
|
31213
|
+
rmSync8(shadow, { recursive: true, force: true });
|
|
31146
31214
|
prepareShadow(projectRoot, operation, options);
|
|
31147
31215
|
const stat = lstatSync7(shadow);
|
|
31148
31216
|
if (stat.isSymbolicLink() || !stat.isDirectory() || !installedCreateMatches(shadow, operation)) {
|
|
31149
31217
|
fail3("create_shadow_invalid", TRANSACTION_NAME, "reconstructed create shadow does not exactly match pinned target files", "path");
|
|
31150
31218
|
}
|
|
31151
|
-
syncTreeDirectories(
|
|
31219
|
+
syncTreeDirectories(join24(shadow, ".kxm"));
|
|
31152
31220
|
}
|
|
31153
31221
|
function applyOperation(projectRoot, original, options, resumed) {
|
|
31154
31222
|
assertNoRegisteredGates(options);
|
|
@@ -31158,10 +31226,10 @@ function applyOperation(projectRoot, original, options, resumed) {
|
|
|
31158
31226
|
verifyBackups(projectRoot, operation);
|
|
31159
31227
|
operation = updatePhase(projectRoot, operation, "applying");
|
|
31160
31228
|
if (operation.kind === "create") {
|
|
31161
|
-
const destination =
|
|
31162
|
-
if (!
|
|
31229
|
+
const destination = join24(projectRoot, ".kxm");
|
|
31230
|
+
if (!existsSync21(destination)) {
|
|
31163
31231
|
rebuildCreateShadow(projectRoot, operation, effectiveOptions);
|
|
31164
|
-
|
|
31232
|
+
renameSync6(join24(shadowRoot(projectRoot), ".kxm"), destination);
|
|
31165
31233
|
syncDirectory2(projectRoot);
|
|
31166
31234
|
} else if (!installedCreateMatches(projectRoot, operation)) {
|
|
31167
31235
|
fail3("create_resume_conflict", ".kxm", "existing project configuration does not match the pinned create operation");
|
|
@@ -31188,7 +31256,7 @@ function applyOperation(projectRoot, original, options, resumed) {
|
|
|
31188
31256
|
operation = updatePhase(projectRoot, operation, "verified");
|
|
31189
31257
|
if (options.testFaultAt === "verified") throw new Error("injected init fault after verification");
|
|
31190
31258
|
const files = operation.files.map((entry) => entry.path);
|
|
31191
|
-
syncTreeDirectories(
|
|
31259
|
+
syncTreeDirectories(join24(projectRoot, ".kxm"));
|
|
31192
31260
|
return { kind: operation.kind, resumed, bundle, files };
|
|
31193
31261
|
}
|
|
31194
31262
|
function prepareAndApplyVnextCreate(projectRoot, rendered, options = {}) {
|
|
@@ -31303,7 +31371,7 @@ function finishPreparingOperation(projectRoot, operation, options) {
|
|
|
31303
31371
|
const rendered = rendererForOperation(operation);
|
|
31304
31372
|
if (!rendered) fail3("init_transaction_renderer_unavailable", TRANSACTION_NAME, "this binary cannot reproduce the pinned pre-application target");
|
|
31305
31373
|
for (const directory of ["targets", "backups", "shadow"]) {
|
|
31306
|
-
|
|
31374
|
+
rmSync8(join24(transactionRoot(projectRoot), directory), { recursive: true, force: true });
|
|
31307
31375
|
}
|
|
31308
31376
|
for (const entry of operation.files) {
|
|
31309
31377
|
const bytes = rendered.files.get(entry.path);
|
|
@@ -31322,8 +31390,8 @@ function resumeVnextInitTransaction(projectRoot, options = {}) {
|
|
|
31322
31390
|
let operation = readOperation(projectRoot, options.schemasDir);
|
|
31323
31391
|
if (!operation) {
|
|
31324
31392
|
const root = transactionRoot(projectRoot);
|
|
31325
|
-
if (
|
|
31326
|
-
|
|
31393
|
+
if (existsSync21(root)) {
|
|
31394
|
+
rmSync8(root, { recursive: true, force: true });
|
|
31327
31395
|
syncDirectory2(projectRoot);
|
|
31328
31396
|
}
|
|
31329
31397
|
return void 0;
|
|
@@ -31338,10 +31406,10 @@ function commitVnextInitTransaction(projectRoot, schemasDir) {
|
|
|
31338
31406
|
fail3("init_transaction_not_verified", TRANSACTION_NAME, "initialization transaction cannot commit before installed state is verified");
|
|
31339
31407
|
}
|
|
31340
31408
|
const transaction = transactionRoot(projectRoot);
|
|
31341
|
-
const retired =
|
|
31342
|
-
|
|
31409
|
+
const retired = join24(projectRoot, `${TRANSACTION_NAME}-cleanup-${operation.operationId}-${randomUUID10()}`);
|
|
31410
|
+
renameSync6(transaction, retired);
|
|
31343
31411
|
syncDirectory2(projectRoot);
|
|
31344
|
-
|
|
31412
|
+
rmSync8(retired, { recursive: true, force: true });
|
|
31345
31413
|
syncDirectory2(projectRoot);
|
|
31346
31414
|
}
|
|
31347
31415
|
function inspectVnextInitTransaction(projectRoot, schemasDir) {
|
|
@@ -31447,7 +31515,7 @@ function validateBindingIdentities(bundle, persisted, explicit) {
|
|
|
31447
31515
|
}
|
|
31448
31516
|
function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock) {
|
|
31449
31517
|
const storeOptions = bindingStoreOptions(options);
|
|
31450
|
-
const persisted =
|
|
31518
|
+
const persisted = existsSync22(join25(gitRoot, ".kxm", "project.yaml")) ? readVnextLocalBindings(gitRoot, storeOptions) : void 0;
|
|
31451
31519
|
const repositoryBindings = Object.fromEntries([
|
|
31452
31520
|
...Object.entries(persisted?.repositories ?? {}),
|
|
31453
31521
|
...Object.entries(options.repositoryBindings ?? {})
|
|
@@ -31636,7 +31704,7 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31636
31704
|
const files = [...rendered.files.keys()];
|
|
31637
31705
|
if (options.dryRun) return { action: "planned", plan, projectRoot: gitRoot, files };
|
|
31638
31706
|
if (!mutationLock) throw new Error("project mutation lock is required to create configuration");
|
|
31639
|
-
if (
|
|
31707
|
+
if (existsSync22(join25(gitRoot, ".kxm"))) {
|
|
31640
31708
|
throw new VnextConfigError([initIssue("workspace_changed", ".kxm", "workspace changed after planning; existing .kxm state was not overwritten")]);
|
|
31641
31709
|
}
|
|
31642
31710
|
const created = prepareAndApplyVnextCreate(gitRoot, rendered, transactionOptions);
|
|
@@ -31668,8 +31736,8 @@ function initializeVnextProject(start = process.cwd(), options = {}) {
|
|
|
31668
31736
|
// plugins/kxm/src/vnext-migrate.ts
|
|
31669
31737
|
var import_yaml12 = __toESM(require_dist(), 1);
|
|
31670
31738
|
import { createHash as createHash13 } from "node:crypto";
|
|
31671
|
-
import { chmodSync as chmodSync6, closeSync as closeSync3, existsSync as
|
|
31672
|
-
import { join as
|
|
31739
|
+
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";
|
|
31740
|
+
import { join as join26 } from "node:path";
|
|
31673
31741
|
var MAX_LEGACY_JSON_BYTES = 1024 * 1024;
|
|
31674
31742
|
var MAX_LEGACY_JSON_DEPTH = 32;
|
|
31675
31743
|
var MAX_LEGACY_JSON_NODES = 32768;
|
|
@@ -31838,12 +31906,12 @@ function readVnextLegacySources(root) {
|
|
|
31838
31906
|
throw new VnextConfigError([migrateIssue("discovery", "legacy_source_limit", ".kxm/config", `legacy configuration exceeds ${MAX_LEGACY_SOURCES} files`)]);
|
|
31839
31907
|
}
|
|
31840
31908
|
return files.map((path4) => {
|
|
31841
|
-
const absolute =
|
|
31909
|
+
const absolute = join26(root, ...path4.split("/"));
|
|
31842
31910
|
const stat = lstatSync8(absolute);
|
|
31843
31911
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
31844
31912
|
throw new VnextConfigError([migrateIssue("path", "legacy_source_invalid", path4, "legacy configuration must be a regular file, not a link")]);
|
|
31845
31913
|
}
|
|
31846
|
-
const buffer =
|
|
31914
|
+
const buffer = readFileSync22(absolute);
|
|
31847
31915
|
let text;
|
|
31848
31916
|
try {
|
|
31849
31917
|
text = new TextDecoder("utf-8", { fatal: true }).decode(buffer);
|
|
@@ -32916,11 +32984,11 @@ function planVnextMigration(projectRoot, options = {}) {
|
|
|
32916
32984
|
};
|
|
32917
32985
|
}
|
|
32918
32986
|
function readVnextMigrationDecisions(path4, schemasDir) {
|
|
32919
|
-
if (!
|
|
32987
|
+
if (!existsSync23(path4)) {
|
|
32920
32988
|
throw new VnextConfigError([migrateIssue("discovery", "decisions_missing", path4, "migration decisions file does not exist")]);
|
|
32921
32989
|
}
|
|
32922
32990
|
const registry = new VnextSchemaRegistry(schemasDir);
|
|
32923
|
-
const value = parseRestrictedYaml2(
|
|
32991
|
+
const value = parseRestrictedYaml2(readFileSync22(path4), path4);
|
|
32924
32992
|
const issues = registry.validateMigrationDecision(value, path4);
|
|
32925
32993
|
if (issues.length > 0) throw new VnextConfigError(issues);
|
|
32926
32994
|
return value;
|
|
@@ -32949,19 +33017,19 @@ function writeDurable2(path4, content) {
|
|
|
32949
33017
|
const descriptor = openSync3(temp, "wx", 384);
|
|
32950
33018
|
created = true;
|
|
32951
33019
|
try {
|
|
32952
|
-
|
|
33020
|
+
writeFileSync18(descriptor, content);
|
|
32953
33021
|
fsyncSync3(descriptor);
|
|
32954
33022
|
} finally {
|
|
32955
33023
|
closeSync3(descriptor);
|
|
32956
33024
|
}
|
|
32957
|
-
|
|
33025
|
+
renameSync7(temp, path4);
|
|
32958
33026
|
try {
|
|
32959
33027
|
chmodSync6(path4, 384);
|
|
32960
33028
|
} catch {
|
|
32961
33029
|
}
|
|
32962
|
-
syncDirectory3(
|
|
33030
|
+
syncDirectory3(join26(path4, ".."));
|
|
32963
33031
|
} finally {
|
|
32964
|
-
if (created &&
|
|
33032
|
+
if (created && existsSync23(temp)) rmSync9(temp, { force: true });
|
|
32965
33033
|
}
|
|
32966
33034
|
}
|
|
32967
33035
|
function applyVnextMigration(projectRoot, options = {}) {
|
|
@@ -32971,8 +33039,8 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
32971
33039
|
...options.schemasDir === void 0 ? {} : { schemasDir: options.schemasDir }
|
|
32972
33040
|
};
|
|
32973
33041
|
const execute = (lock) => {
|
|
32974
|
-
const receiptAbsolute =
|
|
32975
|
-
if (
|
|
33042
|
+
const receiptAbsolute = join26(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
|
|
33043
|
+
if (existsSync23(receiptAbsolute)) {
|
|
32976
33044
|
const stat = lstatSync8(receiptAbsolute);
|
|
32977
33045
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
32978
33046
|
throw new VnextConfigError([migrateIssue("path", "migration_receipt_invalid", VNEXT_MIGRATION_RECEIPT_PATH, "migration receipt must be a regular file, not a link")]);
|
|
@@ -33025,7 +33093,7 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33025
33093
|
return { action: "planned", projectRoot: root, files: [], plan: first.plan };
|
|
33026
33094
|
}
|
|
33027
33095
|
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) =>
|
|
33096
|
+
const collisions = files.filter((file) => existsSync23(join26(root, ...file.path.split("/"))));
|
|
33029
33097
|
if (collisions.length > 0) {
|
|
33030
33098
|
throw new VnextConfigError(collisions.map((file) => migrateIssue("semantic", "migration_target_exists", file.path, "target resource already exists; refusing to overwrite")));
|
|
33031
33099
|
}
|
|
@@ -33034,8 +33102,8 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33034
33102
|
const segments = file.path.split("/");
|
|
33035
33103
|
let current = root;
|
|
33036
33104
|
for (const segment of segments.slice(0, -1)) {
|
|
33037
|
-
current =
|
|
33038
|
-
if (!
|
|
33105
|
+
current = join26(current, segment);
|
|
33106
|
+
if (!existsSync23(current)) continue;
|
|
33039
33107
|
const stat = lstatSync8(current);
|
|
33040
33108
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
33041
33109
|
parentIssues.push(migrateIssue("path", "migration_target_parent_invalid", file.path, `migration target parent ${segment} must be a regular directory, not a link`));
|
|
@@ -33051,8 +33119,8 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33051
33119
|
const written = [];
|
|
33052
33120
|
try {
|
|
33053
33121
|
for (const file of files) {
|
|
33054
|
-
const absolute =
|
|
33055
|
-
|
|
33122
|
+
const absolute = join26(root, ...file.path.split("/"));
|
|
33123
|
+
mkdirSync19(join26(absolute, ".."), { recursive: true });
|
|
33056
33124
|
written.push(absolute);
|
|
33057
33125
|
writeDurable2(absolute, file.bytes);
|
|
33058
33126
|
}
|
|
@@ -33086,7 +33154,7 @@ ${bundle.configRevision}`).slice(7, 39)}`,
|
|
|
33086
33154
|
} catch (error) {
|
|
33087
33155
|
for (const absolute of written.reverse()) {
|
|
33088
33156
|
try {
|
|
33089
|
-
|
|
33157
|
+
rmSync9(absolute, { force: true });
|
|
33090
33158
|
} catch {
|
|
33091
33159
|
}
|
|
33092
33160
|
}
|
|
@@ -33098,8 +33166,8 @@ ${bundle.configRevision}`).slice(7, 39)}`,
|
|
|
33098
33166
|
}
|
|
33099
33167
|
function verifyVnextMigration(projectRoot, options = {}) {
|
|
33100
33168
|
const root = migrationGitRoot(projectRoot);
|
|
33101
|
-
const receiptAbsolute =
|
|
33102
|
-
if (!
|
|
33169
|
+
const receiptAbsolute = join26(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
|
|
33170
|
+
if (!existsSync23(receiptAbsolute)) {
|
|
33103
33171
|
return {
|
|
33104
33172
|
ok: false,
|
|
33105
33173
|
projectRoot: root,
|
|
@@ -33396,7 +33464,7 @@ async function cmdBackup(runtime, options) {
|
|
|
33396
33464
|
try {
|
|
33397
33465
|
const { manifest, outDir } = createBackup({
|
|
33398
33466
|
projectRoot: runtime.cwd,
|
|
33399
|
-
...options.out ? { outDir:
|
|
33467
|
+
...options.out ? { outDir: resolve20(runtime.cwd, options.out) } : {}
|
|
33400
33468
|
});
|
|
33401
33469
|
const payload = {
|
|
33402
33470
|
ok: true,
|
|
@@ -33408,7 +33476,7 @@ async function cmdBackup(runtime, options) {
|
|
|
33408
33476
|
const summary = [
|
|
33409
33477
|
`Created SQLite backup with ${manifest.stores.length} store(s):`,
|
|
33410
33478
|
...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: ${
|
|
33479
|
+
`Manifest: ${join27(outDir, "manifest.json")}`
|
|
33412
33480
|
].join("\n");
|
|
33413
33481
|
print(runtime.io, runtime.json, payload, summary);
|
|
33414
33482
|
return 0;
|
|
@@ -33423,7 +33491,7 @@ async function cmdBackup(runtime, options) {
|
|
|
33423
33491
|
}
|
|
33424
33492
|
async function cmdRestore(runtime, manifestArg) {
|
|
33425
33493
|
try {
|
|
33426
|
-
const result = restoreBackup(
|
|
33494
|
+
const result = restoreBackup(resolve20(runtime.cwd, manifestArg), {
|
|
33427
33495
|
projectRoot: runtime.cwd
|
|
33428
33496
|
});
|
|
33429
33497
|
const payload = {
|
|
@@ -33683,7 +33751,7 @@ async function selectProducerModel(runtime, requested) {
|
|
|
33683
33751
|
if (runtime.json || !process.stdin.isTTY || models.length === 0) return void 0;
|
|
33684
33752
|
runtime.io.stdout(models.slice(0, 100).map((model, index2) => `${index2 + 1}. ${model}`).join("\n") + "\nSelect model number: ");
|
|
33685
33753
|
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
33686
|
-
const answer = await new Promise((
|
|
33754
|
+
const answer = await new Promise((resolve31) => rl.once("line", resolve31));
|
|
33687
33755
|
rl.close();
|
|
33688
33756
|
const index = Number.parseInt(answer.trim(), 10) - 1;
|
|
33689
33757
|
return Number.isInteger(index) && index >= 0 && index < models.length ? models[index] : void 0;
|
|
@@ -33709,7 +33777,7 @@ async function cmdModelsScreen(runtime) {
|
|
|
33709
33777
|
return 2;
|
|
33710
33778
|
}
|
|
33711
33779
|
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
33712
|
-
const ask = (q2) => new Promise((
|
|
33780
|
+
const ask = (q2) => new Promise((resolve31) => rl.question(q2, resolve31));
|
|
33713
33781
|
try {
|
|
33714
33782
|
while (true) {
|
|
33715
33783
|
const policy = loadProducerPolicy(runtime.dirs.workdir);
|
|
@@ -33973,12 +34041,12 @@ async function cmdStudioLayout(runtime, workflowPath) {
|
|
|
33973
34041
|
const projectRoot = discoverVnextProjectRoot(runtime.cwd) ?? runtime.cwd;
|
|
33974
34042
|
let filePath = workflowPath;
|
|
33975
34043
|
if (!filePath) {
|
|
33976
|
-
filePath =
|
|
34044
|
+
filePath = resolve21(projectRoot, ".kxm", "workflows", "default.yaml");
|
|
33977
34045
|
}
|
|
33978
34046
|
let yamlContent;
|
|
33979
34047
|
let workflowId = "default";
|
|
33980
|
-
if (
|
|
33981
|
-
yamlContent =
|
|
34048
|
+
if (existsSync24(filePath)) {
|
|
34049
|
+
yamlContent = readFileSync23(filePath, "utf8");
|
|
33982
34050
|
} else {
|
|
33983
34051
|
yamlContent = `schema: kxm.workflow.v1
|
|
33984
34052
|
description: Feature implementation workflow
|
|
@@ -34051,15 +34119,15 @@ async function cmdStudioServe(runtime, options) {
|
|
|
34051
34119
|
sessionToken,
|
|
34052
34120
|
planProvider: () => {
|
|
34053
34121
|
try {
|
|
34054
|
-
const wfDir =
|
|
34055
|
-
const defaultPath =
|
|
34056
|
-
let targetPath =
|
|
34057
|
-
if (!targetPath &&
|
|
34122
|
+
const wfDir = join28(runtime.cwd, ".kxm", "workflows");
|
|
34123
|
+
const defaultPath = join28(wfDir, "default.yaml");
|
|
34124
|
+
let targetPath = existsSync24(defaultPath) ? defaultPath : void 0;
|
|
34125
|
+
if (!targetPath && existsSync24(wfDir)) {
|
|
34058
34126
|
const yml = readdirSync8(wfDir).find((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
|
|
34059
|
-
if (yml) targetPath =
|
|
34127
|
+
if (yml) targetPath = join28(wfDir, yml);
|
|
34060
34128
|
}
|
|
34061
|
-
if (targetPath &&
|
|
34062
|
-
const raw =
|
|
34129
|
+
if (targetPath && existsSync24(targetPath)) {
|
|
34130
|
+
const raw = readFileSync23(targetPath, "utf8");
|
|
34063
34131
|
const parsed = (0, import_yaml13.parse)(raw);
|
|
34064
34132
|
const wfId = basename6(targetPath).replace(/\.(yaml|yml)$/, "");
|
|
34065
34133
|
return compileVnextWorkflow({ id: wfId, value: parsed });
|
|
@@ -34109,14 +34177,14 @@ Press Ctrl+C to stop.
|
|
|
34109
34177
|
}
|
|
34110
34178
|
|
|
34111
34179
|
// plugins/kxm/src/cli/context-skills.ts
|
|
34112
|
-
import { readFileSync as
|
|
34113
|
-
import { join as
|
|
34180
|
+
import { readFileSync as readFileSync26 } from "node:fs";
|
|
34181
|
+
import { join as join32, relative as relative5 } from "node:path";
|
|
34114
34182
|
|
|
34115
34183
|
// plugins/kxm/src/memory.ts
|
|
34116
34184
|
var import_yaml14 = __toESM(require_dist(), 1);
|
|
34117
34185
|
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
34118
|
-
import { existsSync as
|
|
34119
|
-
import { extname as extname2, join as
|
|
34186
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync20, readdirSync as readdirSync9, readFileSync as readFileSync24, writeFileSync as writeFileSync19 } from "node:fs";
|
|
34187
|
+
import { extname as extname2, join as join29, resolve as resolve22 } from "node:path";
|
|
34120
34188
|
var MEMORY_SCHEMA = "kxm.memory.v1";
|
|
34121
34189
|
var MEMORY_BRIEF_SCHEMA = "kxm.memory-brief.v1";
|
|
34122
34190
|
var MEMORY_MARKER_START = "<!-- kxm:memory:start -->";
|
|
@@ -34242,21 +34310,21 @@ ${yamlText}
|
|
|
34242
34310
|
`;
|
|
34243
34311
|
}
|
|
34244
34312
|
function memoryDirectories(repoRoot) {
|
|
34245
|
-
const root =
|
|
34246
|
-
const memoryDir =
|
|
34247
|
-
const candidatesDir =
|
|
34313
|
+
const root = resolve22(repoRoot);
|
|
34314
|
+
const memoryDir = join29(root, ".kxm", "memory");
|
|
34315
|
+
const candidatesDir = join29(memoryDir, "candidates");
|
|
34248
34316
|
return { memoryDir, candidatesDir };
|
|
34249
34317
|
}
|
|
34250
34318
|
function loadAuthoredMemory(repoRoot) {
|
|
34251
34319
|
const { memoryDir } = memoryDirectories(repoRoot);
|
|
34252
|
-
if (!
|
|
34320
|
+
if (!existsSync25(memoryDir)) return [];
|
|
34253
34321
|
const records = [];
|
|
34254
34322
|
const entries = readdirSync9(memoryDir, { withFileTypes: true });
|
|
34255
34323
|
for (const entry of entries) {
|
|
34256
34324
|
if (entry.isFile() && extname2(entry.name) === ".md") {
|
|
34257
|
-
const fullPath =
|
|
34325
|
+
const fullPath = join29(memoryDir, entry.name);
|
|
34258
34326
|
try {
|
|
34259
|
-
const text =
|
|
34327
|
+
const text = readFileSync24(fullPath, "utf8");
|
|
34260
34328
|
const record = parseMemoryRecord(text, entry.name);
|
|
34261
34329
|
if (record.lifecycle === "active") {
|
|
34262
34330
|
records.push(record);
|
|
@@ -34270,7 +34338,7 @@ function loadAuthoredMemory(repoRoot) {
|
|
|
34270
34338
|
}
|
|
34271
34339
|
function createMemoryNote(repoRoot, summary, options = {}) {
|
|
34272
34340
|
const { candidatesDir } = memoryDirectories(repoRoot);
|
|
34273
|
-
|
|
34341
|
+
mkdirSync20(candidatesDir, { recursive: true });
|
|
34274
34342
|
const scope = options.scope ?? "project";
|
|
34275
34343
|
if (!VALID_SCOPES.has(scope)) {
|
|
34276
34344
|
throw new Error(`invalid memory note scope: ${scope}; must be one of agent, project, run, operator`);
|
|
@@ -34295,8 +34363,8 @@ function createMemoryNote(repoRoot, summary, options = {}) {
|
|
|
34295
34363
|
evidenceRefs: [],
|
|
34296
34364
|
...options.body ? { body: options.body.trim() } : {}
|
|
34297
34365
|
};
|
|
34298
|
-
const targetPath =
|
|
34299
|
-
|
|
34366
|
+
const targetPath = join29(candidatesDir, `${id}.md`);
|
|
34367
|
+
writeFileSync19(targetPath, formatMemoryRecord(record), "utf8");
|
|
34300
34368
|
return { record, path: targetPath };
|
|
34301
34369
|
}
|
|
34302
34370
|
function generateMemoryBrief(repoRoot) {
|
|
@@ -34332,8 +34400,8 @@ function formatHarnessMemoryBlock(records) {
|
|
|
34332
34400
|
}
|
|
34333
34401
|
function updateHarnessDocument(filePath, block, defaultHeader) {
|
|
34334
34402
|
let original = "";
|
|
34335
|
-
if (
|
|
34336
|
-
original =
|
|
34403
|
+
if (existsSync25(filePath)) {
|
|
34404
|
+
original = readFileSync24(filePath, "utf8");
|
|
34337
34405
|
}
|
|
34338
34406
|
let updated = "";
|
|
34339
34407
|
if (original.includes(MEMORY_MARKER_START) && original.includes(MEMORY_MARKER_END)) {
|
|
@@ -34361,25 +34429,25 @@ ${block}
|
|
|
34361
34429
|
`;
|
|
34362
34430
|
}
|
|
34363
34431
|
if (updated !== original) {
|
|
34364
|
-
|
|
34432
|
+
writeFileSync19(filePath, updated, "utf8");
|
|
34365
34433
|
return true;
|
|
34366
34434
|
}
|
|
34367
34435
|
return false;
|
|
34368
34436
|
}
|
|
34369
34437
|
function syncHarnessMemory(repoRoot) {
|
|
34370
|
-
const root =
|
|
34438
|
+
const root = resolve22(repoRoot);
|
|
34371
34439
|
const records = loadAuthoredMemory(root);
|
|
34372
34440
|
const block = formatHarnessMemoryBlock(records);
|
|
34373
34441
|
const updated = [];
|
|
34374
34442
|
const created = [];
|
|
34375
|
-
const agentsPath =
|
|
34443
|
+
const agentsPath = join29(root, "AGENTS.md");
|
|
34376
34444
|
const agentsHeader = "# AGENTS\n\nFollow project instructions.\n";
|
|
34377
|
-
const agentsExisted =
|
|
34445
|
+
const agentsExisted = existsSync25(agentsPath);
|
|
34378
34446
|
if (updateHarnessDocument(agentsPath, block, agentsHeader)) {
|
|
34379
34447
|
if (agentsExisted) updated.push("AGENTS.md");
|
|
34380
34448
|
else created.push("AGENTS.md");
|
|
34381
34449
|
}
|
|
34382
|
-
const claudePath =
|
|
34450
|
+
const claudePath = join29(root, "CLAUDE.md");
|
|
34383
34451
|
const claudeHeader = `# KXM (Claude)
|
|
34384
34452
|
|
|
34385
34453
|
Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
@@ -34390,12 +34458,12 @@ you to implement. Default writer is native Grok CLI (\`grok --model grok-4.6\`).
|
|
|
34390
34458
|
If \`grok\` is logged out, fail closed; do not fall back to Pi. Your reviews are
|
|
34391
34459
|
artifacts, not hub \`peer-reply\` evidence.
|
|
34392
34460
|
`;
|
|
34393
|
-
const claudeExisted =
|
|
34461
|
+
const claudeExisted = existsSync25(claudePath);
|
|
34394
34462
|
if (updateHarnessDocument(claudePath, block, claudeHeader)) {
|
|
34395
34463
|
if (claudeExisted) updated.push("CLAUDE.md");
|
|
34396
34464
|
else created.push("CLAUDE.md");
|
|
34397
34465
|
}
|
|
34398
|
-
const geminiPath =
|
|
34466
|
+
const geminiPath = join29(root, "GEMINI.md");
|
|
34399
34467
|
const geminiHeader = `# KXM (Gemini / Antigravity)
|
|
34400
34468
|
|
|
34401
34469
|
Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
@@ -34404,7 +34472,7 @@ Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
|
34404
34472
|
Google / Antigravity CLI (\`agy\`) is an admitted native writer and experiment edit route
|
|
34405
34473
|
for Gemini models. Starting rotation remains Grok.
|
|
34406
34474
|
`;
|
|
34407
|
-
const geminiExisted =
|
|
34475
|
+
const geminiExisted = existsSync25(geminiPath);
|
|
34408
34476
|
if (updateHarnessDocument(geminiPath, block, geminiHeader)) {
|
|
34409
34477
|
if (geminiExisted) updated.push("GEMINI.md");
|
|
34410
34478
|
else created.push("GEMINI.md");
|
|
@@ -34415,8 +34483,8 @@ for Gemini models. Starting rotation remains Grok.
|
|
|
34415
34483
|
// plugins/kxm/src/skills.ts
|
|
34416
34484
|
var import_yaml15 = __toESM(require_dist(), 1);
|
|
34417
34485
|
import { createHash as createHash14 } from "node:crypto";
|
|
34418
|
-
import { existsSync as
|
|
34419
|
-
import { join as
|
|
34486
|
+
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";
|
|
34487
|
+
import { join as join30 } from "node:path";
|
|
34420
34488
|
var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
|
|
34421
34489
|
var SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
|
|
34422
34490
|
var SKILL_DECISION_SCHEMA = "kxm.skill-decision.v1";
|
|
@@ -34510,48 +34578,48 @@ var SkillLifecycle = class {
|
|
|
34510
34578
|
this.allowOptimizationEvals = options.allowOptimizationEvals === true;
|
|
34511
34579
|
}
|
|
34512
34580
|
dir(state) {
|
|
34513
|
-
return
|
|
34581
|
+
return join30(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
|
|
34514
34582
|
}
|
|
34515
34583
|
historyFile(id) {
|
|
34516
|
-
return
|
|
34584
|
+
return join30(this.root, "history", `${id}.jsonl`);
|
|
34517
34585
|
}
|
|
34518
34586
|
paths(state, id) {
|
|
34519
|
-
const dir =
|
|
34520
|
-
return { dir, metadata:
|
|
34587
|
+
const dir = join30(this.dir(state), id);
|
|
34588
|
+
return { dir, metadata: join30(dir, "metadata.json"), skill: join30(dir, "SKILL.md") };
|
|
34521
34589
|
}
|
|
34522
34590
|
appendHistory(id, record) {
|
|
34523
|
-
|
|
34591
|
+
mkdirSync21(join30(this.root, "history"), { recursive: true });
|
|
34524
34592
|
const line = `${JSON.stringify(record)}
|
|
34525
34593
|
`;
|
|
34526
|
-
if (
|
|
34527
|
-
const existing =
|
|
34594
|
+
if (existsSync26(this.historyFile(id))) {
|
|
34595
|
+
const existing = readFileSync25(this.historyFile(id), "utf8");
|
|
34528
34596
|
const lines = existing.split("\n").filter((entry) => entry.trim());
|
|
34529
|
-
|
|
34597
|
+
writeFileSync20(this.historyFile(id), [...lines.slice(-499), line.trim()].join("\n") + "\n");
|
|
34530
34598
|
} else {
|
|
34531
|
-
|
|
34599
|
+
writeFileSync20(this.historyFile(id), line);
|
|
34532
34600
|
}
|
|
34533
34601
|
}
|
|
34534
34602
|
history(id) {
|
|
34535
34603
|
const file = this.historyFile(id);
|
|
34536
|
-
if (!
|
|
34537
|
-
return
|
|
34604
|
+
if (!existsSync26(file)) return [];
|
|
34605
|
+
return readFileSync25(file, "utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
34538
34606
|
}
|
|
34539
34607
|
readMetadata(state, id) {
|
|
34540
34608
|
const { metadata } = this.paths(state, id);
|
|
34541
|
-
if (!
|
|
34609
|
+
if (!existsSync26(metadata)) {
|
|
34542
34610
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${state}`);
|
|
34543
34611
|
}
|
|
34544
|
-
return JSON.parse(
|
|
34612
|
+
return JSON.parse(readFileSync25(metadata, "utf8"));
|
|
34545
34613
|
}
|
|
34546
34614
|
move(from, to, id) {
|
|
34547
|
-
const fromDir =
|
|
34548
|
-
const toDir =
|
|
34549
|
-
if (!
|
|
34615
|
+
const fromDir = join30(this.dir(from), id);
|
|
34616
|
+
const toDir = join30(this.dir(to), id);
|
|
34617
|
+
if (!existsSync26(fromDir)) {
|
|
34550
34618
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${from}`);
|
|
34551
34619
|
}
|
|
34552
|
-
|
|
34553
|
-
if (
|
|
34554
|
-
|
|
34620
|
+
mkdirSync21(this.dir(to), { recursive: true });
|
|
34621
|
+
if (existsSync26(toDir)) rmSync10(toDir, { recursive: true, force: true });
|
|
34622
|
+
renameSync8(fromDir, toDir);
|
|
34555
34623
|
}
|
|
34556
34624
|
/** Submit a new skill candidate. Content is redacted of secret material at
|
|
34557
34625
|
* creation; the ID is derived from name + content hash. */
|
|
@@ -34593,7 +34661,7 @@ var SkillLifecycle = class {
|
|
|
34593
34661
|
const contentSha256 = skillContentSha256(content);
|
|
34594
34662
|
const id = skillIdFor(name, contentSha256);
|
|
34595
34663
|
const { dir, metadata, skill } = this.paths("candidate", id);
|
|
34596
|
-
if (
|
|
34664
|
+
if (existsSync26(metadata)) {
|
|
34597
34665
|
throw new SkillLifecycleError(
|
|
34598
34666
|
"skill_candidate_exists",
|
|
34599
34667
|
`identical candidate ${id} already exists; changed behavior requires changed content`
|
|
@@ -34612,9 +34680,9 @@ var SkillLifecycle = class {
|
|
|
34612
34680
|
createdAt: this.now(),
|
|
34613
34681
|
...input.supersedes ? { supersedes: input.supersedes } : {}
|
|
34614
34682
|
};
|
|
34615
|
-
|
|
34616
|
-
|
|
34617
|
-
|
|
34683
|
+
mkdirSync21(dir, { recursive: true });
|
|
34684
|
+
writeFileSync20(skill, content);
|
|
34685
|
+
writeFileSync20(metadata, `${JSON.stringify(record, null, 2)}
|
|
34618
34686
|
`);
|
|
34619
34687
|
this.appendHistory(id, { schema: "kxm.skill-history-event.v1", event: "candidate_created", by: createdBy, supersedes: input.supersedes, at: record.createdAt });
|
|
34620
34688
|
return record;
|
|
@@ -34703,18 +34771,18 @@ var SkillLifecycle = class {
|
|
|
34703
34771
|
};
|
|
34704
34772
|
const candidatePaths = this.paths("candidate", candidateId);
|
|
34705
34773
|
const promotedPaths = this.paths("promoted", candidateId);
|
|
34706
|
-
|
|
34707
|
-
const skillContent =
|
|
34708
|
-
const metadataContent =
|
|
34709
|
-
|
|
34710
|
-
|
|
34711
|
-
const patchesDir =
|
|
34712
|
-
|
|
34713
|
-
const patchPath =
|
|
34774
|
+
mkdirSync21(promotedPaths.dir, { recursive: true });
|
|
34775
|
+
const skillContent = readFileSync25(candidatePaths.skill, "utf8");
|
|
34776
|
+
const metadataContent = readFileSync25(candidatePaths.metadata, "utf8");
|
|
34777
|
+
writeFileSync20(promotedPaths.skill, skillContent);
|
|
34778
|
+
writeFileSync20(promotedPaths.metadata, metadataContent);
|
|
34779
|
+
const patchesDir = join30(this.root, "patches");
|
|
34780
|
+
mkdirSync21(patchesDir, { recursive: true });
|
|
34781
|
+
const patchPath = join30(patchesDir, `${candidateId}.patch`);
|
|
34714
34782
|
const relSkillPath = `.kxm/skills/promoted/${candidateId}/SKILL.md`;
|
|
34715
34783
|
const relMetaPath = `.kxm/skills/promoted/${candidateId}/metadata.json`;
|
|
34716
34784
|
const patch = `${createUnifiedPatch(relSkillPath, skillContent)}${createUnifiedPatch(relMetaPath, metadataContent)}`;
|
|
34717
|
-
|
|
34785
|
+
writeFileSync20(patchPath, patch, "utf8");
|
|
34718
34786
|
this.appendHistory(candidateId, record);
|
|
34719
34787
|
return { ...metadata, patch, patchPath };
|
|
34720
34788
|
}
|
|
@@ -34738,7 +34806,7 @@ var SkillLifecycle = class {
|
|
|
34738
34806
|
verify(state, id) {
|
|
34739
34807
|
const metadata = this.readMetadata(state, id);
|
|
34740
34808
|
const { skill } = this.paths(state, id);
|
|
34741
|
-
const content =
|
|
34809
|
+
const content = readFileSync25(skill, "utf8");
|
|
34742
34810
|
if (skillContentSha256(content) !== metadata.contentSha256) {
|
|
34743
34811
|
throw new SkillLifecycleError(
|
|
34744
34812
|
"skill_integrity_violation",
|
|
@@ -34756,7 +34824,7 @@ var SkillLifecycle = class {
|
|
|
34756
34824
|
}
|
|
34757
34825
|
list(state) {
|
|
34758
34826
|
const dir = this.dir(state);
|
|
34759
|
-
if (!
|
|
34827
|
+
if (!existsSync26(dir)) return [];
|
|
34760
34828
|
const ids = readdirSorted(dir);
|
|
34761
34829
|
return ids.map((id) => {
|
|
34762
34830
|
try {
|
|
@@ -34769,7 +34837,7 @@ var SkillLifecycle = class {
|
|
|
34769
34837
|
read(state, id) {
|
|
34770
34838
|
const metadata = this.readMetadata(state, id);
|
|
34771
34839
|
const { skill } = this.paths(state, id);
|
|
34772
|
-
return { metadata, content:
|
|
34840
|
+
return { metadata, content: readFileSync25(skill, "utf8") };
|
|
34773
34841
|
}
|
|
34774
34842
|
};
|
|
34775
34843
|
function boundedList(value, field) {
|
|
@@ -34784,18 +34852,18 @@ function boundedList(value, field) {
|
|
|
34784
34852
|
return [...new Set(refs)];
|
|
34785
34853
|
}
|
|
34786
34854
|
function readdirSorted(dir) {
|
|
34787
|
-
return readdirSync10(dir).filter((entry) => statSync3(
|
|
34855
|
+
return readdirSync10(dir).filter((entry) => statSync3(join30(dir, entry)).isDirectory()).sort();
|
|
34788
34856
|
}
|
|
34789
34857
|
|
|
34790
34858
|
// plugins/kxm/src/wiki.ts
|
|
34791
|
-
import { mkdirSync as
|
|
34792
|
-
import { join as
|
|
34859
|
+
import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync21 } from "node:fs";
|
|
34860
|
+
import { join as join31 } from "node:path";
|
|
34793
34861
|
function writeCompiledWiki(root, wiki) {
|
|
34794
34862
|
const written = [];
|
|
34795
34863
|
for (const [relativePath, content] of [...wiki.pages].sort(([left], [right]) => left.localeCompare(right))) {
|
|
34796
|
-
const absolute =
|
|
34797
|
-
|
|
34798
|
-
|
|
34864
|
+
const absolute = join31(root, relativePath);
|
|
34865
|
+
mkdirSync22(absolute.slice(0, absolute.lastIndexOf("/")), { recursive: true });
|
|
34866
|
+
writeFileSync21(absolute, content);
|
|
34799
34867
|
written.push(relativePath);
|
|
34800
34868
|
}
|
|
34801
34869
|
return written;
|
|
@@ -34961,7 +35029,7 @@ function skillStateFromFlag(value) {
|
|
|
34961
35029
|
throw new Error(`invalid skill state ${value}`);
|
|
34962
35030
|
}
|
|
34963
35031
|
function skillsRoot(runtime) {
|
|
34964
|
-
return
|
|
35032
|
+
return join32(runtime.dirs.workdir, ".kxm", "skills");
|
|
34965
35033
|
}
|
|
34966
35034
|
function csv(value) {
|
|
34967
35035
|
if (!value) return void 0;
|
|
@@ -34978,7 +35046,7 @@ async function cmdSkillsCreate(runtime, options) {
|
|
|
34978
35046
|
const metadata = lifecycle.create({
|
|
34979
35047
|
name: options.name,
|
|
34980
35048
|
description: options.description ?? "",
|
|
34981
|
-
content:
|
|
35049
|
+
content: readFileSync26(options.file, "utf8"),
|
|
34982
35050
|
createdBy: options.createdBy,
|
|
34983
35051
|
sources: {
|
|
34984
35052
|
runIds: csv(options.run) ?? [],
|
|
@@ -35136,8 +35204,8 @@ async function cmdMemorySync(runtime) {
|
|
|
35136
35204
|
|
|
35137
35205
|
// plugins/kxm/src/cli/hub.ts
|
|
35138
35206
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
35139
|
-
import { existsSync as
|
|
35140
|
-
import { join as
|
|
35207
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync26, readFileSync as readFileSync32, readdirSync as readdirSync12, rmSync as rmSync11, writeFileSync as writeFileSync24 } from "node:fs";
|
|
35208
|
+
import { join as join42, resolve as resolve25 } from "node:path";
|
|
35141
35209
|
|
|
35142
35210
|
// node_modules/marked/lib/marked.esm.js
|
|
35143
35211
|
function M() {
|
|
@@ -39299,10 +39367,10 @@ var TuiBase = class _TuiBase extends Container {
|
|
|
39299
39367
|
* @returns Promise containing the parsed RGB color, or undefined if it times out or fails to parse.
|
|
39300
39368
|
*/
|
|
39301
39369
|
queryTerminalBackgroundColor({ timeoutMs }) {
|
|
39302
|
-
return new Promise((
|
|
39370
|
+
return new Promise((resolve31) => {
|
|
39303
39371
|
const query = {
|
|
39304
39372
|
settled: false,
|
|
39305
|
-
resolve:
|
|
39373
|
+
resolve: resolve31,
|
|
39306
39374
|
timer: void 0
|
|
39307
39375
|
};
|
|
39308
39376
|
query.timer = setTimeout(() => {
|
|
@@ -39325,7 +39393,7 @@ var TuiBase = class _TuiBase extends Container {
|
|
|
39325
39393
|
* `CSI ? 997 ; 1 n` for dark or `CSI ? 997 ; 2 n` for light.
|
|
39326
39394
|
*/
|
|
39327
39395
|
queryTerminalColorScheme({ timeoutMs }) {
|
|
39328
|
-
return new Promise((
|
|
39396
|
+
return new Promise((resolve31) => {
|
|
39329
39397
|
let settled = false;
|
|
39330
39398
|
let timer;
|
|
39331
39399
|
let unsubscribe = () => {
|
|
@@ -39339,7 +39407,7 @@ var TuiBase = class _TuiBase extends Container {
|
|
|
39339
39407
|
timer = void 0;
|
|
39340
39408
|
}
|
|
39341
39409
|
unsubscribe();
|
|
39342
|
-
|
|
39410
|
+
resolve31(scheme);
|
|
39343
39411
|
};
|
|
39344
39412
|
unsubscribe = this.onTerminalColorSchemeChange(settle);
|
|
39345
39413
|
timer = setTimeout(() => settle(void 0), timeoutMs);
|
|
@@ -41070,19 +41138,19 @@ import * as path2 from "node:path";
|
|
|
41070
41138
|
|
|
41071
41139
|
// node_modules/@earendil-works/pi-tui/dist/native-module-path.js
|
|
41072
41140
|
import { createRequire as createRequire2 } from "node:module";
|
|
41073
|
-
import { dirname as
|
|
41141
|
+
import { dirname as dirname17, join as join33 } from "node:path";
|
|
41074
41142
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
41075
41143
|
var moduleRequire = createRequire2(import.meta.url);
|
|
41076
41144
|
var TUI_PACKAGE_NAME = "@earendil-works/pi-tui";
|
|
41077
41145
|
function getNativeModuleCandidates(nativePath, options = {}) {
|
|
41078
|
-
const moduleDir =
|
|
41146
|
+
const moduleDir = dirname17(fileURLToPath2(options.moduleUrl ?? import.meta.url));
|
|
41079
41147
|
const candidates = [];
|
|
41080
41148
|
try {
|
|
41081
41149
|
const packageEntry = (options.resolvePackage ?? moduleRequire.resolve)(TUI_PACKAGE_NAME);
|
|
41082
|
-
candidates.push(
|
|
41150
|
+
candidates.push(join33(dirname17(packageEntry), "..", nativePath));
|
|
41083
41151
|
} catch {
|
|
41084
41152
|
}
|
|
41085
|
-
candidates.push(
|
|
41153
|
+
candidates.push(join33(moduleDir, "..", nativePath), join33(moduleDir, nativePath), join33(dirname17(options.execPath ?? process.execPath), nativePath));
|
|
41086
41154
|
return Array.from(new Set(candidates));
|
|
41087
41155
|
}
|
|
41088
41156
|
|
|
@@ -41423,7 +41491,7 @@ var ProcessTerminal = class {
|
|
|
41423
41491
|
break;
|
|
41424
41492
|
if (now - lastDataTime >= idleMs)
|
|
41425
41493
|
break;
|
|
41426
|
-
await new Promise((
|
|
41494
|
+
await new Promise((resolve31) => setTimeout(resolve31, Math.min(idleMs, timeLeft)));
|
|
41427
41495
|
}
|
|
41428
41496
|
} finally {
|
|
41429
41497
|
process.stdin.removeListener("data", onData);
|
|
@@ -43538,8 +43606,8 @@ var TuiAltScreen = class extends TuiBase {
|
|
|
43538
43606
|
var MAX_RENDER_WRITE_CHARS = 1024 * 1024;
|
|
43539
43607
|
|
|
43540
43608
|
// plugins/kxm/src/tui.ts
|
|
43541
|
-
import { mkdirSync as
|
|
43542
|
-
import { join as
|
|
43609
|
+
import { mkdirSync as mkdirSync23 } from "node:fs";
|
|
43610
|
+
import { join as join37, resolve as resolve24, dirname as dirname18 } from "node:path";
|
|
43543
43611
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
43544
43612
|
|
|
43545
43613
|
// plugins/kxm/src/external-effects.ts
|
|
@@ -43550,9 +43618,9 @@ function slugifyBranchPart(text, maxLength = 40) {
|
|
|
43550
43618
|
}
|
|
43551
43619
|
|
|
43552
43620
|
// plugins/kxm/src/local-snapshot.ts
|
|
43553
|
-
import { existsSync as
|
|
43554
|
-
import { homedir as
|
|
43555
|
-
import { isAbsolute as
|
|
43621
|
+
import { existsSync as existsSync27, readdirSync as readdirSync11, readFileSync as readFileSync27 } from "node:fs";
|
|
43622
|
+
import { homedir as homedir6 } from "node:os";
|
|
43623
|
+
import { isAbsolute as isAbsolute8, join as join36, resolve as resolve23 } from "node:path";
|
|
43556
43624
|
function processExists2(pid) {
|
|
43557
43625
|
try {
|
|
43558
43626
|
process.kill(pid, 0);
|
|
@@ -43672,36 +43740,36 @@ function readOpenMessageMetadata(database) {
|
|
|
43672
43740
|
return messages;
|
|
43673
43741
|
}
|
|
43674
43742
|
function resolveKxmSnapshotPaths(cwd, env = process.env) {
|
|
43675
|
-
const stateDir = env.KXM_STATE_DIR?.trim() ||
|
|
43743
|
+
const stateDir = env.KXM_STATE_DIR?.trim() || join36(cwd, ".kxm", "state");
|
|
43676
43744
|
const configured = env.KXM_DATA_PATH?.trim();
|
|
43677
|
-
const dataPath = configured ?
|
|
43745
|
+
const dataPath = configured ? resolve23(cwd, configured) : join36(stateDir, "kxm.db");
|
|
43678
43746
|
return { dataPath, stateDir };
|
|
43679
43747
|
}
|
|
43680
43748
|
function resolveVnextStateRoot(stateDir, options) {
|
|
43681
|
-
if (options?.vnextStateRoot &&
|
|
43682
|
-
return
|
|
43749
|
+
if (options?.vnextStateRoot && existsSync27(options.vnextStateRoot)) {
|
|
43750
|
+
return resolve23(options.vnextStateRoot);
|
|
43683
43751
|
}
|
|
43684
|
-
if (
|
|
43752
|
+
if (existsSync27(join36(stateDir, "runtime", "registry.db")) || existsSync27(join36(stateDir, "runtime", "projects"))) {
|
|
43685
43753
|
return stateDir;
|
|
43686
43754
|
}
|
|
43687
43755
|
const env = options?.env ?? process.env;
|
|
43688
43756
|
const explicit = env.KXM_STATE_HOME?.trim() || env.KXM_USER_STATE_DIR?.trim() || env.KXM_STATE_ROOT?.trim();
|
|
43689
|
-
if (explicit &&
|
|
43690
|
-
return
|
|
43757
|
+
if (explicit && isAbsolute8(explicit) && existsSync27(resolve23(explicit))) {
|
|
43758
|
+
return resolve23(explicit);
|
|
43691
43759
|
}
|
|
43692
43760
|
let base;
|
|
43693
43761
|
if (process.platform === "win32") {
|
|
43694
43762
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
43695
|
-
base = localAppData &&
|
|
43696
|
-
base =
|
|
43763
|
+
base = localAppData && isAbsolute8(localAppData) ? localAppData : join36(homedir6(), "AppData", "Local");
|
|
43764
|
+
base = resolve23(base, "KXM");
|
|
43697
43765
|
} else if (process.platform === "darwin") {
|
|
43698
|
-
base =
|
|
43766
|
+
base = resolve23(homedir6(), "Library", "Application Support", "KXM");
|
|
43699
43767
|
} else {
|
|
43700
43768
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
43701
|
-
base = xdgState &&
|
|
43702
|
-
base =
|
|
43769
|
+
base = xdgState && isAbsolute8(xdgState) ? xdgState : join36(homedir6(), ".local", "state");
|
|
43770
|
+
base = resolve23(base, "kxm");
|
|
43703
43771
|
}
|
|
43704
|
-
if (
|
|
43772
|
+
if (existsSync27(base)) return base;
|
|
43705
43773
|
return void 0;
|
|
43706
43774
|
}
|
|
43707
43775
|
function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
@@ -43712,7 +43780,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43712
43780
|
let legacyRuns = [];
|
|
43713
43781
|
let legacyRunTotal = 0;
|
|
43714
43782
|
let plans = [];
|
|
43715
|
-
if (
|
|
43783
|
+
if (existsSync27(dataPath)) {
|
|
43716
43784
|
hasLegacy = true;
|
|
43717
43785
|
const database = new DatabaseSync(dataPath, { readOnly: true });
|
|
43718
43786
|
try {
|
|
@@ -43732,11 +43800,11 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43732
43800
|
let vnextRunTotal = 0;
|
|
43733
43801
|
const vnextStateRoot = resolveVnextStateRoot(stateDir, options);
|
|
43734
43802
|
if (vnextStateRoot) {
|
|
43735
|
-
const runtimeDir =
|
|
43736
|
-
const registryDbPath =
|
|
43737
|
-
const projectsDir =
|
|
43803
|
+
const runtimeDir = join36(vnextStateRoot, "runtime");
|
|
43804
|
+
const registryDbPath = join36(runtimeDir, "registry.db");
|
|
43805
|
+
const projectsDir = join36(runtimeDir, "projects");
|
|
43738
43806
|
const projectKeys = /* @__PURE__ */ new Set();
|
|
43739
|
-
if (
|
|
43807
|
+
if (existsSync27(registryDbPath)) {
|
|
43740
43808
|
hasVnext = true;
|
|
43741
43809
|
try {
|
|
43742
43810
|
const regDb = new DatabaseSync(registryDbPath, { readOnly: true });
|
|
@@ -43752,7 +43820,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43752
43820
|
} catch {
|
|
43753
43821
|
}
|
|
43754
43822
|
}
|
|
43755
|
-
if (
|
|
43823
|
+
if (existsSync27(projectsDir)) {
|
|
43756
43824
|
try {
|
|
43757
43825
|
for (const entry of readdirSync11(projectsDir, { withFileTypes: true })) {
|
|
43758
43826
|
if (entry.isDirectory()) {
|
|
@@ -43763,8 +43831,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43763
43831
|
}
|
|
43764
43832
|
}
|
|
43765
43833
|
for (const key of projectKeys) {
|
|
43766
|
-
const eventDbPath =
|
|
43767
|
-
if (
|
|
43834
|
+
const eventDbPath = join36(projectsDir, key, "run-events.db");
|
|
43835
|
+
if (existsSync27(eventDbPath)) {
|
|
43768
43836
|
hasVnext = true;
|
|
43769
43837
|
try {
|
|
43770
43838
|
const eventDb = new DatabaseSync(eventDbPath, { readOnly: true });
|
|
@@ -43794,10 +43862,10 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43794
43862
|
}
|
|
43795
43863
|
}
|
|
43796
43864
|
const pids = [];
|
|
43797
|
-
if (
|
|
43865
|
+
if (existsSync27(stateDir)) {
|
|
43798
43866
|
for (const file of readdirSync11(stateDir).filter((name) => name.endsWith(".pid"))) {
|
|
43799
43867
|
try {
|
|
43800
|
-
const record = JSON.parse(
|
|
43868
|
+
const record = JSON.parse(readFileSync27(join36(stateDir, file), "utf8"));
|
|
43801
43869
|
pids.push({
|
|
43802
43870
|
file,
|
|
43803
43871
|
...record.role ? { role: record.role } : {},
|
|
@@ -43836,8 +43904,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43836
43904
|
} else {
|
|
43837
43905
|
source = "legacy";
|
|
43838
43906
|
}
|
|
43839
|
-
const telemetryFile =
|
|
43840
|
-
const spend =
|
|
43907
|
+
const telemetryFile = join36(stateDir, "telemetry.jsonl");
|
|
43908
|
+
const spend = existsSync27(telemetryFile) ? readRoutingRecords(telemetryFile) : [];
|
|
43841
43909
|
return {
|
|
43842
43910
|
source,
|
|
43843
43911
|
agents: agents.sort((a, b2) => Number(b2.online) - Number(a.online) || a.name.localeCompare(b2.name)),
|
|
@@ -43971,11 +44039,11 @@ function spawnDegradeWorktree(repoRoot, runId, options) {
|
|
|
43971
44039
|
const cleanRunId = runId.replace(/^run_/, "");
|
|
43972
44040
|
const desc = options?.description ? slugifyBranchPart(options.description, 30) : "degrade";
|
|
43973
44041
|
const branchName = `kxm/run-${cleanRunId}-${desc}`;
|
|
43974
|
-
const relativeWtPath =
|
|
43975
|
-
const absoluteWtPath =
|
|
44042
|
+
const relativeWtPath = join37(".kxm", "worktrees", `run-${cleanRunId}-${desc}`);
|
|
44043
|
+
const absoluteWtPath = resolve24(repoRoot, relativeWtPath);
|
|
43976
44044
|
const jumpCommand = `cd "${absoluteWtPath}"`;
|
|
43977
44045
|
try {
|
|
43978
|
-
|
|
44046
|
+
mkdirSync23(dirname18(absoluteWtPath), { recursive: true });
|
|
43979
44047
|
const branchCheck = runner("git", ["rev-parse", "--verify", `refs/heads/${branchName}`]);
|
|
43980
44048
|
let wtRes;
|
|
43981
44049
|
if (branchCheck.status === 0) {
|
|
@@ -44374,11 +44442,11 @@ async function readJson(response) {
|
|
|
44374
44442
|
}
|
|
44375
44443
|
async function waitForReconnect(signal, milliseconds = 1e3) {
|
|
44376
44444
|
if (signal.aborted) return;
|
|
44377
|
-
await new Promise((
|
|
44445
|
+
await new Promise((resolve31) => {
|
|
44378
44446
|
const done = () => {
|
|
44379
44447
|
clearTimeout(timer);
|
|
44380
44448
|
signal.removeEventListener("abort", done);
|
|
44381
|
-
|
|
44449
|
+
resolve31();
|
|
44382
44450
|
};
|
|
44383
44451
|
const timer = setTimeout(done, milliseconds);
|
|
44384
44452
|
timer.unref();
|
|
@@ -44741,8 +44809,8 @@ async function runMeshTui(input) {
|
|
|
44741
44809
|
// plugins/kxm/src/session-work.ts
|
|
44742
44810
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
44743
44811
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
44744
|
-
import { existsSync as
|
|
44745
|
-
import { join as
|
|
44812
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync24, readFileSync as readFileSync28, renameSync as renameSync9, writeFileSync as writeFileSync22 } from "node:fs";
|
|
44813
|
+
import { join as join38 } from "node:path";
|
|
44746
44814
|
var MAX_SESSION_BRIEF_TASKS = 5;
|
|
44747
44815
|
var MAX_SESSION_BRIEF_PLANS = 5;
|
|
44748
44816
|
var SESSION_BRIEF_SCHEMA = "kxm.session-brief.v1";
|
|
@@ -44898,10 +44966,10 @@ function buildSessionBrief(snapshot, current, hub, ship, updateLatest, cost, ses
|
|
|
44898
44966
|
};
|
|
44899
44967
|
}
|
|
44900
44968
|
function readCachedSessionBrief(stateDir) {
|
|
44901
|
-
const file =
|
|
44969
|
+
const file = join38(stateDir, "session-brief.json");
|
|
44902
44970
|
try {
|
|
44903
|
-
if (!
|
|
44904
|
-
const raw =
|
|
44971
|
+
if (!existsSync28(file)) return void 0;
|
|
44972
|
+
const raw = readFileSync28(file, "utf8");
|
|
44905
44973
|
const parsed = JSON.parse(raw);
|
|
44906
44974
|
if (parsed && parsed.schema === "kxm.session-brief.v1" && typeof parsed.generatedAt === "string") {
|
|
44907
44975
|
const ageMs = Date.now() - Date.parse(parsed.generatedAt);
|
|
@@ -44916,18 +44984,18 @@ function readCachedSessionBrief(stateDir) {
|
|
|
44916
44984
|
}
|
|
44917
44985
|
function writeCachedSessionBrief(stateDir, brief) {
|
|
44918
44986
|
try {
|
|
44919
|
-
|
|
44920
|
-
const file =
|
|
44987
|
+
mkdirSync24(stateDir, { recursive: true, mode: 448 });
|
|
44988
|
+
const file = join38(stateDir, "session-brief.json");
|
|
44921
44989
|
const tmp = `${file}.tmp.${randomUUID13().slice(0, 8)}`;
|
|
44922
|
-
|
|
44923
|
-
|
|
44990
|
+
writeFileSync22(tmp, JSON.stringify(brief, null, 2), { encoding: "utf8", mode: 384 });
|
|
44991
|
+
renameSync9(tmp, file);
|
|
44924
44992
|
} catch {
|
|
44925
44993
|
}
|
|
44926
44994
|
}
|
|
44927
44995
|
function estimateSessionCost(stateDir) {
|
|
44928
44996
|
try {
|
|
44929
|
-
const telemetryFile =
|
|
44930
|
-
if (!
|
|
44997
|
+
const telemetryFile = join38(stateDir, "telemetry.jsonl");
|
|
44998
|
+
if (!existsSync28(telemetryFile)) return void 0;
|
|
44931
44999
|
const records = readRoutingRecords(telemetryFile);
|
|
44932
45000
|
if (records.length === 0) return void 0;
|
|
44933
45001
|
let totalCost = 0;
|
|
@@ -45095,11 +45163,11 @@ function formatSessionBriefText(brief) {
|
|
|
45095
45163
|
}
|
|
45096
45164
|
|
|
45097
45165
|
// plugins/kxm/src/kxm-install-kind.ts
|
|
45098
|
-
import { existsSync as
|
|
45099
|
-
import { dirname as
|
|
45166
|
+
import { existsSync as existsSync29, readFileSync as readFileSync29 } from "node:fs";
|
|
45167
|
+
import { dirname as dirname19, join as join39 } from "node:path";
|
|
45100
45168
|
function packageIsKxm(root) {
|
|
45101
45169
|
try {
|
|
45102
|
-
const pkg = JSON.parse(
|
|
45170
|
+
const pkg = JSON.parse(readFileSync29(join39(root, "package.json"), "utf8"));
|
|
45103
45171
|
return pkg.name === "@kontextmind/kxm";
|
|
45104
45172
|
} catch {
|
|
45105
45173
|
return false;
|
|
@@ -45148,12 +45216,12 @@ function report(kind, root) {
|
|
|
45148
45216
|
return { kind, root, instruction: installKindInstruction(kind, root) };
|
|
45149
45217
|
}
|
|
45150
45218
|
function classifyInstallRoot(probe) {
|
|
45151
|
-
const piGitRoot =
|
|
45219
|
+
const piGitRoot = join39(probe.homeDir, ".pi", "agent", "git");
|
|
45152
45220
|
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 =
|
|
45221
|
+
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() || join39(probe.homeDir, ".claude");
|
|
45222
|
+
const pluginsRoot = join39(claudeHome, "plugins");
|
|
45155
45223
|
if (isUnder(probe.moduleDir, pluginsRoot, probe.platform)) return report("claude-marketplace", probe.moduleDir);
|
|
45156
|
-
const hasGit =
|
|
45224
|
+
const hasGit = existsSync29(join39(probe.repoRoot, ".git"));
|
|
45157
45225
|
if (hasGit && packageIsKxm(probe.repoRoot)) return report("source", probe.repoRoot);
|
|
45158
45226
|
if (isNpmPackageLayout(probe.repoRoot, probe.platform) && packageIsKxm(probe.repoRoot) && !hasGit) {
|
|
45159
45227
|
return report("npm-package", probe.repoRoot);
|
|
@@ -45167,21 +45235,21 @@ function resolveInstallKind(probe, npmGlobalRoot) {
|
|
|
45167
45235
|
if (typeof globalRoot !== "string" || globalRoot.trim() === "") {
|
|
45168
45236
|
return report("unknown", classified.root);
|
|
45169
45237
|
}
|
|
45170
|
-
const expected =
|
|
45238
|
+
const expected = dirname19(dirname19(classified.root));
|
|
45171
45239
|
if (sameHostPath2(globalRoot.trim(), expected, probe.platform)) return report("npm-global", classified.root);
|
|
45172
45240
|
return report("npm-local", classified.root);
|
|
45173
45241
|
}
|
|
45174
45242
|
|
|
45175
45243
|
// plugins/kxm/src/kxm-update-config.ts
|
|
45176
45244
|
var import_yaml16 = __toESM(require_dist(), 1);
|
|
45177
|
-
import { existsSync as
|
|
45178
|
-
import { join as
|
|
45245
|
+
import { existsSync as existsSync30, readFileSync as readFileSync30 } from "node:fs";
|
|
45246
|
+
import { join as join40 } from "node:path";
|
|
45179
45247
|
function loadKxmUpdateConfig(env = process.env) {
|
|
45180
|
-
const path4 =
|
|
45181
|
-
if (!
|
|
45248
|
+
const path4 = join40(vnextUserStateRoot({ env }), "update.yaml");
|
|
45249
|
+
if (!existsSync30(path4)) return { schema: KXM_UPDATE_SCHEMA, auto: false, source: "github" };
|
|
45182
45250
|
let parsed;
|
|
45183
45251
|
try {
|
|
45184
|
-
parsed = (0, import_yaml16.parse)(
|
|
45252
|
+
parsed = (0, import_yaml16.parse)(readFileSync30(path4, "utf8"));
|
|
45185
45253
|
} catch {
|
|
45186
45254
|
throw new KxmUpdateConfigError("update.yaml is not valid YAML");
|
|
45187
45255
|
}
|
|
@@ -45207,8 +45275,8 @@ function loadKxmUpdateConfig(env = process.env) {
|
|
|
45207
45275
|
}
|
|
45208
45276
|
|
|
45209
45277
|
// plugins/kxm/src/session.ts
|
|
45210
|
-
import { existsSync as
|
|
45211
|
-
import { join as
|
|
45278
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync25, readFileSync as readFileSync31, writeFileSync as writeFileSync23 } from "node:fs";
|
|
45279
|
+
import { join as join41 } from "node:path";
|
|
45212
45280
|
var SESSION_SCHEMA = "kxm.session.v1";
|
|
45213
45281
|
var SessionConfigError = class extends Error {
|
|
45214
45282
|
code = "session_config_invalid";
|
|
@@ -45218,12 +45286,12 @@ var SessionConfigError = class extends Error {
|
|
|
45218
45286
|
}
|
|
45219
45287
|
};
|
|
45220
45288
|
function workflowAssetDirs(assetsDir, workflowId) {
|
|
45221
|
-
const root =
|
|
45222
|
-
return [root,
|
|
45289
|
+
const root = join41(assetsDir, "workflows", workflowId);
|
|
45290
|
+
return [root, join41(root, "inputs"), join41(root, "outputs"), join41(root, "generated")];
|
|
45223
45291
|
}
|
|
45224
45292
|
function sessionAssetDirs(assetsDir, sessionId) {
|
|
45225
|
-
const root =
|
|
45226
|
-
return [root,
|
|
45293
|
+
const root = join41(assetsDir, "sessions", sessionId);
|
|
45294
|
+
return [root, join41(root, "inputs"), join41(root, "outputs")];
|
|
45227
45295
|
}
|
|
45228
45296
|
function rosterNames(configDir) {
|
|
45229
45297
|
return [...loadRosterMap(configDir).values()].map((row) => String(row.name));
|
|
@@ -45273,7 +45341,7 @@ function workerFromRosterRow(name, row, project) {
|
|
|
45273
45341
|
function loadRosterMap(configDir) {
|
|
45274
45342
|
const byName = /* @__PURE__ */ new Map();
|
|
45275
45343
|
for (const [file, key] of [["agents.json", "agents"], ["gates.json", "gates"]]) {
|
|
45276
|
-
const path4 =
|
|
45344
|
+
const path4 = join41(configDir, file);
|
|
45277
45345
|
for (const row of loadRoster(path4, key)) {
|
|
45278
45346
|
const name = String(row.name).trim();
|
|
45279
45347
|
const lowered = name.toLowerCase();
|
|
@@ -45287,10 +45355,10 @@ function loadRosterMap(configDir) {
|
|
|
45287
45355
|
return byName;
|
|
45288
45356
|
}
|
|
45289
45357
|
function loadRoster(path4, key) {
|
|
45290
|
-
if (!
|
|
45358
|
+
if (!existsSync31(path4)) return [];
|
|
45291
45359
|
let parsed;
|
|
45292
45360
|
try {
|
|
45293
|
-
parsed = JSON.parse(
|
|
45361
|
+
parsed = JSON.parse(readFileSync31(path4, "utf8"));
|
|
45294
45362
|
} catch (error) {
|
|
45295
45363
|
throw new SessionConfigError(
|
|
45296
45364
|
`${key} roster at ${path4} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -45315,7 +45383,7 @@ function loadRoster(path4, key) {
|
|
|
45315
45383
|
});
|
|
45316
45384
|
}
|
|
45317
45385
|
function createSession(input) {
|
|
45318
|
-
const assetDir = input.mode === "workflow" && input.workflowId ?
|
|
45386
|
+
const assetDir = input.mode === "workflow" && input.workflowId ? join41("assets", "workflows", input.workflowId) : join41("assets", "sessions", input.id);
|
|
45319
45387
|
return {
|
|
45320
45388
|
schema: SESSION_SCHEMA,
|
|
45321
45389
|
id: input.id,
|
|
@@ -45328,11 +45396,11 @@ function createSession(input) {
|
|
|
45328
45396
|
};
|
|
45329
45397
|
}
|
|
45330
45398
|
function writeSession(assetsDir, session, dryRun = false) {
|
|
45331
|
-
const dir =
|
|
45332
|
-
const path4 =
|
|
45399
|
+
const dir = join41(assetsDir, "sessions", session.id);
|
|
45400
|
+
const path4 = join41(dir, "session.json");
|
|
45333
45401
|
if (!dryRun) {
|
|
45334
|
-
|
|
45335
|
-
|
|
45402
|
+
mkdirSync25(dir, { recursive: true });
|
|
45403
|
+
writeFileSync23(path4, `${JSON.stringify(session, null, 2)}
|
|
45336
45404
|
`, { encoding: "utf8" });
|
|
45337
45405
|
}
|
|
45338
45406
|
return path4;
|
|
@@ -45340,8 +45408,8 @@ function writeSession(assetsDir, session, dryRun = false) {
|
|
|
45340
45408
|
|
|
45341
45409
|
// plugins/kxm/src/cli/hub.ts
|
|
45342
45410
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
45343
|
-
import { dirname as
|
|
45344
|
-
import { homedir as
|
|
45411
|
+
import { dirname as dirname20 } from "node:path";
|
|
45412
|
+
import { homedir as homedir7 } from "node:os";
|
|
45345
45413
|
async function hubGet(url, fetchImpl) {
|
|
45346
45414
|
try {
|
|
45347
45415
|
const response = await fetchImpl(url);
|
|
@@ -45359,23 +45427,23 @@ async function hubGet(url, fetchImpl) {
|
|
|
45359
45427
|
function installProbeFrom(runtime) {
|
|
45360
45428
|
const partial = runtime.io.installProbe ?? {};
|
|
45361
45429
|
return {
|
|
45362
|
-
moduleDir: partial.moduleDir ??
|
|
45363
|
-
repoRoot: partial.repoRoot ??
|
|
45364
|
-
homeDir: partial.homeDir ??
|
|
45430
|
+
moduleDir: partial.moduleDir ?? dirname20(fileURLToPath3(import.meta.url)),
|
|
45431
|
+
repoRoot: partial.repoRoot ?? resolve25("."),
|
|
45432
|
+
homeDir: partial.homeDir ?? homedir7(),
|
|
45365
45433
|
platform: partial.platform ?? process.platform,
|
|
45366
45434
|
env: partial.env ?? runtime.env
|
|
45367
45435
|
};
|
|
45368
45436
|
}
|
|
45369
45437
|
function warnIgnoredProjectUpdateYaml(runtime) {
|
|
45370
|
-
const projectFile =
|
|
45371
|
-
if (!
|
|
45372
|
-
const userFile =
|
|
45438
|
+
const projectFile = join42(runtime.dirs.workspace, "update.yaml");
|
|
45439
|
+
if (!existsSync32(projectFile)) return;
|
|
45440
|
+
const userFile = join42(vnextUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
45373
45441
|
runtime.io.stderr(`kxm: ignoring .kxm/update.yaml in ${runtime.dirs.workdir}; update settings are read only from ${userFile}
|
|
45374
45442
|
`);
|
|
45375
45443
|
}
|
|
45376
45444
|
async function refreshKxmUpdateNotice(runtime, config) {
|
|
45377
45445
|
const resolved = config ?? loadKxmUpdateConfig(runtime.env);
|
|
45378
|
-
const current = readInstalledKxmVersion(
|
|
45446
|
+
const current = readInstalledKxmVersion(resolve25("."));
|
|
45379
45447
|
const fetched = await fetchLatestKxmVersion(resolved.source, runtime.env, runtime.fetchImpl);
|
|
45380
45448
|
const notice = noticeFromVersions(current, fetched.latest, resolved, fetched.error, fetched.asset);
|
|
45381
45449
|
writeUpdateCache(runtime.dirs.state, notice);
|
|
@@ -45395,7 +45463,7 @@ async function cmdDash(runtime, options = {}) {
|
|
|
45395
45463
|
return 2;
|
|
45396
45464
|
}
|
|
45397
45465
|
const screen = requested;
|
|
45398
|
-
const dataPath =
|
|
45466
|
+
const dataPath = resolve25(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join42(runtime.dirs.state, "kxm.db"));
|
|
45399
45467
|
if (runtime.dryRun) {
|
|
45400
45468
|
print(runtime.io, runtime.json, {
|
|
45401
45469
|
ok: true,
|
|
@@ -45441,7 +45509,7 @@ async function cmdHub(runtime) {
|
|
|
45441
45509
|
config = loadKxmUpdateConfig(runtime.env);
|
|
45442
45510
|
} catch (error) {
|
|
45443
45511
|
if (error instanceof KxmUpdateConfigError) {
|
|
45444
|
-
const yamlPath =
|
|
45512
|
+
const yamlPath = join42(vnextUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
45445
45513
|
runtime.io.stderr(`kxm: ${error.message}; update check skipped; fix or remove ${yamlPath}
|
|
45446
45514
|
`);
|
|
45447
45515
|
} else {
|
|
@@ -45577,7 +45645,7 @@ async function cmdWorker(runtime, options) {
|
|
|
45577
45645
|
return await (runtime.io.spawnWorker ?? ((launchEnv) => spawnScript("kxm-worker.mjs", launchEnv)))(extraEnv);
|
|
45578
45646
|
}
|
|
45579
45647
|
async function cmdStop(runtime, waitMsFlag) {
|
|
45580
|
-
const pids =
|
|
45648
|
+
const pids = existsSync32(runtime.dirs.state) ? readdirSync12(runtime.dirs.state).filter((name) => name.endsWith(".pid")) : [];
|
|
45581
45649
|
if (runtime.dryRun) {
|
|
45582
45650
|
print(runtime.io, runtime.json, { ok: true, command: "stop", dryRun: true, pidFiles: pids }, "would signal pid files");
|
|
45583
45651
|
return 0;
|
|
@@ -45592,7 +45660,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45592
45660
|
const orphans = [];
|
|
45593
45661
|
for (const file of pids) {
|
|
45594
45662
|
try {
|
|
45595
|
-
const record = JSON.parse(
|
|
45663
|
+
const record = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
|
|
45596
45664
|
const expectedControl = file === "hub.pid" ? "hub.stop" : file.startsWith("worker-") ? `${file.slice(0, -4)}.stop` : void 0;
|
|
45597
45665
|
const expectedRole = file === "hub.pid" ? "hub" : file.startsWith("worker-") ? "worker" : void 0;
|
|
45598
45666
|
if (record.version !== 1 || !Number.isInteger(record.pid) || record.pid <= 0 || !record.startedAt || !expectedControl || record.controlFile !== expectedControl || record.role !== expectedRole) {
|
|
@@ -45612,7 +45680,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45612
45680
|
ignored.push(file);
|
|
45613
45681
|
continue;
|
|
45614
45682
|
}
|
|
45615
|
-
|
|
45683
|
+
writeFileSync24(join42(runtime.dirs.state, record.controlFile), `${JSON.stringify({ startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {}, requestedAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
45616
45684
|
`, { encoding: "utf8", mode: 384 });
|
|
45617
45685
|
requested.push(file);
|
|
45618
45686
|
records.set(file, { pid: record.pid, startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {} });
|
|
@@ -45630,7 +45698,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45630
45698
|
while (Date.now() <= deadline && stopped.size < requested.length) {
|
|
45631
45699
|
for (const [file, record] of records) {
|
|
45632
45700
|
try {
|
|
45633
|
-
const current = JSON.parse(
|
|
45701
|
+
const current = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
|
|
45634
45702
|
if (current.pid !== record.pid || current.startedAt !== record.startedAt || current.generation !== record.generation || !processExists(record.pid)) stopped.add(file);
|
|
45635
45703
|
} catch {
|
|
45636
45704
|
stopped.add(file);
|
|
@@ -45643,7 +45711,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45643
45711
|
for (const file of orphans) {
|
|
45644
45712
|
while (Date.now() <= deadlineOrphans) {
|
|
45645
45713
|
try {
|
|
45646
|
-
const current = JSON.parse(
|
|
45714
|
+
const current = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
|
|
45647
45715
|
if (!Number.isInteger(current.serverPid) || !processExists(current.serverPid)) break;
|
|
45648
45716
|
} catch {
|
|
45649
45717
|
break;
|
|
@@ -45651,14 +45719,14 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45651
45719
|
await (runtime.io.sleep ?? ((ms) => new Promise((resolveSleep) => setTimeout(resolveSleep, ms))))(100);
|
|
45652
45720
|
}
|
|
45653
45721
|
try {
|
|
45654
|
-
const current = JSON.parse(
|
|
45722
|
+
const current = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
|
|
45655
45723
|
if (Number.isInteger(current.serverPid) && processExists(current.serverPid)) {
|
|
45656
45724
|
try {
|
|
45657
45725
|
process.kill(current.serverPid, "SIGKILL");
|
|
45658
45726
|
} catch {
|
|
45659
45727
|
}
|
|
45660
45728
|
}
|
|
45661
|
-
|
|
45729
|
+
rmSync11(join42(runtime.dirs.state, file), { force: true });
|
|
45662
45730
|
} catch {
|
|
45663
45731
|
}
|
|
45664
45732
|
stopped.add(file);
|
|
@@ -45669,11 +45737,11 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45669
45737
|
}
|
|
45670
45738
|
async function cmdSessionStatus(runtime) {
|
|
45671
45739
|
const stateDir = runtime.dirs.state;
|
|
45672
|
-
const names3 =
|
|
45740
|
+
const names3 = existsSync32(stateDir) ? readdirSync12(stateDir) : [];
|
|
45673
45741
|
const claims = [];
|
|
45674
45742
|
for (const file of names3.filter((name) => name.endsWith(".pid"))) {
|
|
45675
45743
|
try {
|
|
45676
|
-
const record = JSON.parse(
|
|
45744
|
+
const record = JSON.parse(readFileSync32(join42(stateDir, file), "utf8"));
|
|
45677
45745
|
claims.push({
|
|
45678
45746
|
file,
|
|
45679
45747
|
role: record.role,
|
|
@@ -45688,7 +45756,7 @@ async function cmdSessionStatus(runtime) {
|
|
|
45688
45756
|
const recoveries = [];
|
|
45689
45757
|
for (const file of names3.filter((name) => name.startsWith("worker-recovery-") && name.endsWith(".json"))) {
|
|
45690
45758
|
try {
|
|
45691
|
-
const envelope = JSON.parse(
|
|
45759
|
+
const envelope = JSON.parse(readFileSync32(join42(stateDir, file), "utf8"));
|
|
45692
45760
|
recoveries.push({
|
|
45693
45761
|
file,
|
|
45694
45762
|
reason: envelope.reason,
|
|
@@ -45793,7 +45861,7 @@ async function cmdSessionBrief(runtime, options = {}) {
|
|
|
45793
45861
|
print(runtime.io, runtime.json, { ok: true, command: "session brief", sessionToken }, sessionToken);
|
|
45794
45862
|
return 0;
|
|
45795
45863
|
}
|
|
45796
|
-
const dataPath =
|
|
45864
|
+
const dataPath = resolve25(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join42(runtime.dirs.state, "kxm.db"));
|
|
45797
45865
|
const env = {
|
|
45798
45866
|
...runtime.env,
|
|
45799
45867
|
KXM_STATE_DIR: runtime.dirs.state,
|
|
@@ -45869,7 +45937,7 @@ async function cmdSessionStart(runtime, options) {
|
|
|
45869
45937
|
...workflowId ? workflowAssetDirs(runtime.dirs.assets, workflowId) : []
|
|
45870
45938
|
];
|
|
45871
45939
|
if (!runtime.dryRun) {
|
|
45872
|
-
for (const directory of created)
|
|
45940
|
+
for (const directory of created) mkdirSync26(directory, { recursive: true });
|
|
45873
45941
|
writeSession(runtime.dirs.assets, session);
|
|
45874
45942
|
}
|
|
45875
45943
|
print(runtime.io, runtime.json, {
|
|
@@ -45885,15 +45953,15 @@ async function cmdSessionStart(runtime, options) {
|
|
|
45885
45953
|
// plugins/kxm/src/cli/system.ts
|
|
45886
45954
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
45887
45955
|
import { createHash as createHash16 } from "node:crypto";
|
|
45888
|
-
import { existsSync as
|
|
45956
|
+
import { existsSync as existsSync38, mkdtempSync as mkdtempSync2, readFileSync as readFileSync37, rmSync as rmSync13 } from "node:fs";
|
|
45889
45957
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
45890
|
-
import { join as
|
|
45958
|
+
import { join as join48, resolve as resolve29 } from "node:path";
|
|
45891
45959
|
import { createInterface as createInterface3 } from "node:readline";
|
|
45892
45960
|
|
|
45893
45961
|
// plugins/kxm/src/improve.ts
|
|
45894
45962
|
import { createHash as createHash15 } from "node:crypto";
|
|
45895
|
-
import { existsSync as
|
|
45896
|
-
import { join as
|
|
45963
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync27, writeFileSync as writeFileSync25 } from "node:fs";
|
|
45964
|
+
import { join as join43, relative as relative6, resolve as resolve26 } from "node:path";
|
|
45897
45965
|
var CANDIDATE_SCHEMA = "kxm.candidate.v1";
|
|
45898
45966
|
var IMPROVEMENT_REPORT_SCHEMA = "kxm.improvement-report.v2";
|
|
45899
45967
|
function classifyCandidateKind(stepId, agentRole) {
|
|
@@ -46064,8 +46132,8 @@ function groupRoutingRecords(records, options = {}) {
|
|
|
46064
46132
|
});
|
|
46065
46133
|
}
|
|
46066
46134
|
function buildImprovementReport(records, options = {}) {
|
|
46067
|
-
const projectRoot = options.projectRoot ?
|
|
46068
|
-
const candidatesDir = options.candidatesDir ?
|
|
46135
|
+
const projectRoot = options.projectRoot ? resolve26(options.projectRoot) : process.cwd();
|
|
46136
|
+
const candidatesDir = options.candidatesDir ? resolve26(options.candidatesDir) : join43(projectRoot, ".kxm", "candidates");
|
|
46069
46137
|
const groups = groupRoutingRecords(records, options);
|
|
46070
46138
|
const candidates = [];
|
|
46071
46139
|
for (const group of groups) {
|
|
@@ -46077,7 +46145,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46077
46145
|
group.workflowHash
|
|
46078
46146
|
);
|
|
46079
46147
|
const diffFileName = `${group.candidateId}.diff`;
|
|
46080
|
-
const diffFilePath =
|
|
46148
|
+
const diffFilePath = join43(candidatesDir, diffFileName);
|
|
46081
46149
|
const relDiffPath = relative6(projectRoot, diffFilePath).replace(/\\/g, "/");
|
|
46082
46150
|
const candidate = {
|
|
46083
46151
|
schema: CANDIDATE_SCHEMA,
|
|
@@ -46099,12 +46167,12 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46099
46167
|
createdAt: nowIso()
|
|
46100
46168
|
};
|
|
46101
46169
|
if (!options.dryRun) {
|
|
46102
|
-
if (!
|
|
46103
|
-
|
|
46170
|
+
if (!existsSync33(candidatesDir)) {
|
|
46171
|
+
mkdirSync27(candidatesDir, { recursive: true });
|
|
46104
46172
|
}
|
|
46105
|
-
|
|
46106
|
-
const jsonFilePath =
|
|
46107
|
-
|
|
46173
|
+
writeFileSync25(diffFilePath, diff, "utf8");
|
|
46174
|
+
const jsonFilePath = join43(candidatesDir, `${group.candidateId}.json`);
|
|
46175
|
+
writeFileSync25(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
|
|
46108
46176
|
}
|
|
46109
46177
|
candidates.push(candidate);
|
|
46110
46178
|
}
|
|
@@ -46119,10 +46187,10 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46119
46187
|
}
|
|
46120
46188
|
function writeImprovementReport(improvementsDir, report2, dryRun = false) {
|
|
46121
46189
|
const stamp = report2.createdAt.replace(/[:.]/g, "-");
|
|
46122
|
-
const path4 =
|
|
46190
|
+
const path4 = join43(improvementsDir, `${stamp}.json`);
|
|
46123
46191
|
if (!dryRun) {
|
|
46124
|
-
|
|
46125
|
-
|
|
46192
|
+
mkdirSync27(improvementsDir, { recursive: true });
|
|
46193
|
+
writeFileSync25(path4, `${JSON.stringify(report2, null, 2)}
|
|
46126
46194
|
`, { encoding: "utf8" });
|
|
46127
46195
|
}
|
|
46128
46196
|
return path4;
|
|
@@ -46162,8 +46230,8 @@ function formatImprovementReport(report2) {
|
|
|
46162
46230
|
|
|
46163
46231
|
// plugins/kxm/src/modes.ts
|
|
46164
46232
|
var import_yaml17 = __toESM(require_dist(), 1);
|
|
46165
|
-
import { existsSync as
|
|
46166
|
-
import { join as
|
|
46233
|
+
import { existsSync as existsSync34, readFileSync as readFileSync34 } from "node:fs";
|
|
46234
|
+
import { join as join44 } from "node:path";
|
|
46167
46235
|
var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
46168
46236
|
schema: "kxm.modes.v1",
|
|
46169
46237
|
majorModes: {
|
|
@@ -46226,12 +46294,12 @@ function loadModesConfig(projectRoot) {
|
|
|
46226
46294
|
if (!projectRoot) {
|
|
46227
46295
|
return DEFAULT_MODES_CONFIG;
|
|
46228
46296
|
}
|
|
46229
|
-
const modesPath =
|
|
46230
|
-
if (!
|
|
46297
|
+
const modesPath = join44(projectRoot, ".kxm", "modes.yaml");
|
|
46298
|
+
if (!existsSync34(modesPath)) {
|
|
46231
46299
|
return DEFAULT_MODES_CONFIG;
|
|
46232
46300
|
}
|
|
46233
46301
|
try {
|
|
46234
|
-
const raw =
|
|
46302
|
+
const raw = readFileSync34(modesPath, "utf8");
|
|
46235
46303
|
const parsed = (0, import_yaml17.parse)(raw);
|
|
46236
46304
|
if (parsed && parsed.schema === "kxm.modes.v1" && parsed.majorModes) {
|
|
46237
46305
|
return {
|
|
@@ -46317,11 +46385,11 @@ function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog
|
|
|
46317
46385
|
estimatedTokens: estimateTokens(baseSystemPromptChars)
|
|
46318
46386
|
});
|
|
46319
46387
|
for (const relPath of resolved.contextFiles) {
|
|
46320
|
-
const fullPath =
|
|
46388
|
+
const fullPath = join44(projectRoot, relPath);
|
|
46321
46389
|
let chars = 0;
|
|
46322
|
-
if (
|
|
46390
|
+
if (existsSync34(fullPath)) {
|
|
46323
46391
|
try {
|
|
46324
|
-
chars =
|
|
46392
|
+
chars = readFileSync34(fullPath, "utf8").length;
|
|
46325
46393
|
} catch {
|
|
46326
46394
|
chars = 0;
|
|
46327
46395
|
}
|
|
@@ -46453,9 +46521,9 @@ ${divider}
|
|
|
46453
46521
|
|
|
46454
46522
|
// plugins/kxm/src/ssh-remote.ts
|
|
46455
46523
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
46456
|
-
import { existsSync as
|
|
46457
|
-
import { homedir as
|
|
46458
|
-
import { join as
|
|
46524
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync28, readFileSync as readFileSync35, readdirSync as readdirSync13, rmSync as rmSync12, statSync as statSync5 } from "node:fs";
|
|
46525
|
+
import { homedir as homedir8 } from "node:os";
|
|
46526
|
+
import { join as join45, resolve as resolve27 } from "node:path";
|
|
46459
46527
|
var MAX_SSH_OUTPUT_BYTES = 50 * 1024;
|
|
46460
46528
|
var MAX_SSH_OUTPUT_LINES = 2e3;
|
|
46461
46529
|
var DEFAULT_SOCKET_DIR = ".kxm/run/ssh-sockets";
|
|
@@ -46481,12 +46549,12 @@ function truncateSshOutput(raw) {
|
|
|
46481
46549
|
return { text, truncated };
|
|
46482
46550
|
}
|
|
46483
46551
|
function parseSshConfig(configPath) {
|
|
46484
|
-
const targetPath = configPath ??
|
|
46485
|
-
if (!
|
|
46552
|
+
const targetPath = configPath ?? join45(homedir8(), ".ssh", "config");
|
|
46553
|
+
if (!existsSync35(targetPath)) {
|
|
46486
46554
|
return [];
|
|
46487
46555
|
}
|
|
46488
46556
|
try {
|
|
46489
|
-
const content =
|
|
46557
|
+
const content = readFileSync35(targetPath, "utf-8");
|
|
46490
46558
|
const lines = content.split("\n");
|
|
46491
46559
|
const hosts = [];
|
|
46492
46560
|
let currentHosts = [];
|
|
@@ -46563,15 +46631,15 @@ function resolveSshHostG(host, execFn = spawnSync7) {
|
|
|
46563
46631
|
}
|
|
46564
46632
|
}
|
|
46565
46633
|
function ensureSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
46566
|
-
const resolved =
|
|
46567
|
-
if (!
|
|
46568
|
-
|
|
46634
|
+
const resolved = resolve27(socketDir);
|
|
46635
|
+
if (!existsSync35(resolved)) {
|
|
46636
|
+
mkdirSync28(resolved, { recursive: true, mode: 448 });
|
|
46569
46637
|
}
|
|
46570
46638
|
return resolved;
|
|
46571
46639
|
}
|
|
46572
46640
|
function buildSshArgs(options) {
|
|
46573
46641
|
const socketDir = ensureSocketDir(options.socketDir ?? DEFAULT_SOCKET_DIR);
|
|
46574
|
-
const controlPath =
|
|
46642
|
+
const controlPath = join45(socketDir, "%C");
|
|
46575
46643
|
const persist = options.controlPersist ?? DEFAULT_CONTROL_PERSIST;
|
|
46576
46644
|
const args = [
|
|
46577
46645
|
"-o",
|
|
@@ -46596,7 +46664,7 @@ function buildSshArgs(options) {
|
|
|
46596
46664
|
}
|
|
46597
46665
|
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
46598
46666
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
46599
|
-
const controlPath =
|
|
46667
|
+
const controlPath = join45(resolvedDir, "%C");
|
|
46600
46668
|
try {
|
|
46601
46669
|
const result = execFn("ssh", ["-O", "check", "-o", `ControlPath=${controlPath}`, host], {
|
|
46602
46670
|
encoding: "utf-8"
|
|
@@ -46608,7 +46676,7 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
46608
46676
|
}
|
|
46609
46677
|
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
46610
46678
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
46611
|
-
const controlPath =
|
|
46679
|
+
const controlPath = join45(resolvedDir, "%C");
|
|
46612
46680
|
try {
|
|
46613
46681
|
const result = execFn("ssh", ["-O", "stop", "-o", `ControlPath=${controlPath}`, host], {
|
|
46614
46682
|
encoding: "utf-8"
|
|
@@ -47054,9 +47122,9 @@ complete -c kxm -n "__fish_seen_subcommand_from goal" -a "create list get"
|
|
|
47054
47122
|
}
|
|
47055
47123
|
|
|
47056
47124
|
// plugins/kxm/src/completion-install.ts
|
|
47057
|
-
import { existsSync as
|
|
47058
|
-
import { homedir as
|
|
47059
|
-
import { basename as basename9, delimiter, dirname as
|
|
47125
|
+
import { existsSync as existsSync36, mkdirSync as mkdirSync29, readFileSync as readFileSync36, writeFileSync as writeFileSync26 } from "node:fs";
|
|
47126
|
+
import { homedir as homedir9 } from "node:os";
|
|
47127
|
+
import { basename as basename9, delimiter, dirname as dirname22, isAbsolute as isAbsolute9, join as join46, resolve as resolve28 } from "node:path";
|
|
47060
47128
|
var COMPLETION_MARKER = "# kxm completion";
|
|
47061
47129
|
var PATH_MARKER = "# kxm path";
|
|
47062
47130
|
function detectShell(env = process.env, platform = process.platform) {
|
|
@@ -47072,31 +47140,31 @@ function effectiveHome(options) {
|
|
|
47072
47140
|
const env = options.env ?? process.env;
|
|
47073
47141
|
if (options.homeDir) return options.homeDir;
|
|
47074
47142
|
const envHome = env.HOME?.trim() ?? env.USERPROFILE?.trim();
|
|
47075
|
-
return envHome && envHome.length > 0 ?
|
|
47143
|
+
return envHome && envHome.length > 0 ? resolve28(envHome) : homedir9();
|
|
47076
47144
|
}
|
|
47077
47145
|
function completionScriptPath(shell, options = {}) {
|
|
47078
47146
|
const env = options.env ?? process.env;
|
|
47079
47147
|
const explicit = options.configDir ?? env.KXM_USER_CONFIG_DIR?.trim();
|
|
47080
|
-
const base = explicit && explicit.length > 0 ?
|
|
47081
|
-
return
|
|
47148
|
+
const base = explicit && explicit.length > 0 ? resolve28(explicit) : resolve28(effectiveHome(options), ".config", "kxm");
|
|
47149
|
+
return join46(base, "completions", `kxm.${shell}`);
|
|
47082
47150
|
}
|
|
47083
47151
|
function bashRcCandidate(options) {
|
|
47084
47152
|
const home = effectiveHome(options);
|
|
47085
|
-
const candidates = [
|
|
47086
|
-
const existing = candidates.find((candidate) =>
|
|
47153
|
+
const candidates = [join46(home, ".bashrc"), join46(home, ".bash_profile")];
|
|
47154
|
+
const existing = candidates.find((candidate) => existsSync36(candidate));
|
|
47087
47155
|
return existing ?? candidates[0];
|
|
47088
47156
|
}
|
|
47089
47157
|
function zshRcCandidate(options) {
|
|
47090
47158
|
const env = options.env ?? process.env;
|
|
47091
47159
|
const home = effectiveHome(options);
|
|
47092
|
-
if (env.ZDOTDIR?.trim()) return
|
|
47093
|
-
return
|
|
47160
|
+
if (env.ZDOTDIR?.trim()) return join46(resolve28(env.ZDOTDIR.trim()), ".zshrc");
|
|
47161
|
+
return join46(home, ".zshrc");
|
|
47094
47162
|
}
|
|
47095
47163
|
function fishCompletionTarget(shell, options) {
|
|
47096
47164
|
const env = options.env ?? process.env;
|
|
47097
47165
|
const home = effectiveHome(options);
|
|
47098
|
-
if (env.XDG_CONFIG_HOME?.trim()) return
|
|
47099
|
-
return
|
|
47166
|
+
if (env.XDG_CONFIG_HOME?.trim()) return join46(resolve28(env.XDG_CONFIG_HOME.trim()), "fish", "completions", "kxm.fish");
|
|
47167
|
+
return join46(home, ".config", "fish", "completions", "kxm.fish");
|
|
47100
47168
|
}
|
|
47101
47169
|
function completionRcTarget(shell, options = {}) {
|
|
47102
47170
|
if (shell === "fish") {
|
|
@@ -47128,17 +47196,17 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47128
47196
|
const scriptPath = completionScriptPath(shell, options);
|
|
47129
47197
|
const { rcFile } = completionRcTarget(shell, options);
|
|
47130
47198
|
const script = generateShellCompletion(shell);
|
|
47131
|
-
const existingScript =
|
|
47132
|
-
const existingScriptMatches = existingScript &&
|
|
47199
|
+
const existingScript = existsSync36(scriptPath);
|
|
47200
|
+
const existingScriptMatches = existingScript && readFileSync36(scriptPath, "utf8") === script;
|
|
47133
47201
|
let rcModified = false;
|
|
47134
47202
|
let alreadyInstalled = false;
|
|
47135
47203
|
if (shell === "fish") {
|
|
47136
47204
|
const fishTarget = fishCompletionTarget(shell, options);
|
|
47137
|
-
const fishInstalled =
|
|
47205
|
+
const fishInstalled = existsSync36(fishTarget) && readFileSync36(fishTarget, "utf8") === script;
|
|
47138
47206
|
alreadyInstalled = fishInstalled;
|
|
47139
47207
|
if (!options.dryRun && (!fishInstalled || options.overwrite)) {
|
|
47140
|
-
|
|
47141
|
-
|
|
47208
|
+
mkdirSync29(resolve28(fishTarget, ".."), { recursive: true });
|
|
47209
|
+
writeFileSync26(fishTarget, script, { encoding: "utf8" });
|
|
47142
47210
|
}
|
|
47143
47211
|
return {
|
|
47144
47212
|
ok: true,
|
|
@@ -47151,13 +47219,13 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47151
47219
|
}
|
|
47152
47220
|
if (rcFile) {
|
|
47153
47221
|
const line = sourceLine(shell, scriptPath);
|
|
47154
|
-
const rcContent =
|
|
47222
|
+
const rcContent = existsSync36(rcFile) ? readFileSync36(rcFile, "utf8") : "";
|
|
47155
47223
|
alreadyInstalled = rcContent.includes(line) || rcContent.includes(`${COMPLETION_MARKER}`);
|
|
47156
47224
|
}
|
|
47157
47225
|
if (!options.dryRun) {
|
|
47158
47226
|
if (!existingScriptMatches || options.overwrite) {
|
|
47159
|
-
|
|
47160
|
-
|
|
47227
|
+
mkdirSync29(resolve28(scriptPath, ".."), { recursive: true });
|
|
47228
|
+
writeFileSync26(scriptPath, script, { encoding: "utf8" });
|
|
47161
47229
|
}
|
|
47162
47230
|
if (rcFile && !alreadyInstalled) {
|
|
47163
47231
|
const line = sourceLine(shell, scriptPath);
|
|
@@ -47166,8 +47234,8 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47166
47234
|
${marker}
|
|
47167
47235
|
${line}
|
|
47168
47236
|
`;
|
|
47169
|
-
|
|
47170
|
-
|
|
47237
|
+
mkdirSync29(resolve28(rcFile, ".."), { recursive: true });
|
|
47238
|
+
writeFileSync26(rcFile, (existsSync36(rcFile) ? readFileSync36(rcFile, "utf8") : "") + stanza, { encoding: "utf8" });
|
|
47171
47239
|
rcModified = true;
|
|
47172
47240
|
}
|
|
47173
47241
|
}
|
|
@@ -47182,15 +47250,15 @@ ${line}
|
|
|
47182
47250
|
}
|
|
47183
47251
|
function kxmBinDir(env = process.env) {
|
|
47184
47252
|
const argv1 = env.KXM_ENTRY ?? process.argv[1];
|
|
47185
|
-
if (argv1 &&
|
|
47186
|
-
const dir =
|
|
47187
|
-
if (
|
|
47253
|
+
if (argv1 && isAbsolute9(argv1)) {
|
|
47254
|
+
const dir = dirname22(argv1);
|
|
47255
|
+
if (existsSync36(join46(dir, process.platform === "win32" ? "kxm.cmd" : "kxm"))) return dir;
|
|
47188
47256
|
}
|
|
47189
47257
|
const pathEnv = env.PATH ?? "";
|
|
47190
47258
|
for (const part of pathEnv.split(delimiter)) {
|
|
47191
47259
|
if (!part) continue;
|
|
47192
|
-
const candidate =
|
|
47193
|
-
if (
|
|
47260
|
+
const candidate = resolve28(part, process.platform === "win32" ? "kxm.cmd" : "kxm");
|
|
47261
|
+
if (existsSync36(candidate)) return resolve28(part);
|
|
47194
47262
|
}
|
|
47195
47263
|
return void 0;
|
|
47196
47264
|
}
|
|
@@ -47208,11 +47276,11 @@ function installPathEntry(shellInput, options = {}) {
|
|
|
47208
47276
|
}
|
|
47209
47277
|
const { rcFile } = completionRcTarget(shell, options);
|
|
47210
47278
|
const line = pathLine(binDir);
|
|
47211
|
-
const rcContent =
|
|
47279
|
+
const rcContent = existsSync36(rcFile ?? "") ? readFileSync36(rcFile, "utf8") : "";
|
|
47212
47280
|
const alreadyInstalled = rcContent.includes(binDir) || (options.env?.PATH ?? process.env.PATH ?? "").split(delimiter).includes(binDir);
|
|
47213
47281
|
if (!options.dryRun && rcFile && !alreadyInstalled) {
|
|
47214
|
-
|
|
47215
|
-
|
|
47282
|
+
mkdirSync29(dirname22(rcFile), { recursive: true });
|
|
47283
|
+
writeFileSync26(rcFile, rcContent + `
|
|
47216
47284
|
${PATH_MARKER}
|
|
47217
47285
|
${line}
|
|
47218
47286
|
`, { encoding: "utf8" });
|
|
@@ -47222,8 +47290,8 @@ ${line}
|
|
|
47222
47290
|
|
|
47223
47291
|
// plugins/kxm/src/init-guide-setup.ts
|
|
47224
47292
|
var import_yaml18 = __toESM(require_dist(), 1);
|
|
47225
|
-
import { existsSync as
|
|
47226
|
-
import { dirname as
|
|
47293
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync30, writeFileSync as writeFileSync27 } from "node:fs";
|
|
47294
|
+
import { dirname as dirname23, join as join47 } from "node:path";
|
|
47227
47295
|
var NATIVE_VENDOR_HARNESS = Object.freeze({
|
|
47228
47296
|
anthropic: "claude",
|
|
47229
47297
|
openai: "codex",
|
|
@@ -47622,13 +47690,13 @@ function renderGuideSetupFiles(projectRoot, plan) {
|
|
|
47622
47690
|
const stage = roleStages.get(role);
|
|
47623
47691
|
if (!stage) continue;
|
|
47624
47692
|
files.push({
|
|
47625
|
-
path:
|
|
47693
|
+
path: join47(projectRoot, ".kxm", "agents", `${role}.yaml`),
|
|
47626
47694
|
content: (0, import_yaml18.stringify)(agentDocument(role, stage, binding))
|
|
47627
47695
|
});
|
|
47628
47696
|
}
|
|
47629
47697
|
for (const workflow of plan.workflows) {
|
|
47630
47698
|
files.push({
|
|
47631
|
-
path:
|
|
47699
|
+
path: join47(projectRoot, ".kxm", "workflows", `${workflow.slug}.yaml`),
|
|
47632
47700
|
content: (0, import_yaml18.stringify)(workflowDocument(workflow))
|
|
47633
47701
|
});
|
|
47634
47702
|
}
|
|
@@ -47638,12 +47706,12 @@ function writeGuideSetupFiles(files) {
|
|
|
47638
47706
|
const written = [];
|
|
47639
47707
|
const existed = [];
|
|
47640
47708
|
for (const file of files) {
|
|
47641
|
-
if (
|
|
47709
|
+
if (existsSync37(file.path)) {
|
|
47642
47710
|
existed.push(file.path);
|
|
47643
47711
|
continue;
|
|
47644
47712
|
}
|
|
47645
|
-
|
|
47646
|
-
|
|
47713
|
+
mkdirSync30(dirname23(file.path), { recursive: true });
|
|
47714
|
+
writeFileSync27(file.path, file.content, "utf8");
|
|
47647
47715
|
written.push(file.path);
|
|
47648
47716
|
}
|
|
47649
47717
|
return { written, existed };
|
|
@@ -47706,7 +47774,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
47706
47774
|
detail: `release v${notice.latest} has no sha256 digest for ${name}; refusing to install`
|
|
47707
47775
|
};
|
|
47708
47776
|
}
|
|
47709
|
-
const releaseDir = mkdtempSync2(
|
|
47777
|
+
const releaseDir = mkdtempSync2(join48(tmpdir2(), "kxm-pkg-update-"));
|
|
47710
47778
|
try {
|
|
47711
47779
|
const planned = planKxmPackageUpdate(notice.source, notice.latest, releaseDir, notice.asset);
|
|
47712
47780
|
if (runtime.dryRun) {
|
|
@@ -47715,7 +47783,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
47715
47783
|
for (const step of planned) {
|
|
47716
47784
|
if (step.kind === "verify") {
|
|
47717
47785
|
if (!verifyReleaseAssetDigest(step.path, step.sha256)) {
|
|
47718
|
-
const actual =
|
|
47786
|
+
const actual = existsSync38(step.path) ? createHash16("sha256").update(readFileSync37(step.path)).digest("hex") : "missing";
|
|
47719
47787
|
return {
|
|
47720
47788
|
ok: false,
|
|
47721
47789
|
error: "release_digest_mismatch",
|
|
@@ -47732,7 +47800,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
47732
47800
|
}
|
|
47733
47801
|
return { ok: true, detail: `installed ${notice.latest} from ${notice.source}` };
|
|
47734
47802
|
} finally {
|
|
47735
|
-
|
|
47803
|
+
rmSync13(releaseDir, { recursive: true, force: true });
|
|
47736
47804
|
}
|
|
47737
47805
|
}
|
|
47738
47806
|
async function cmdExplain(runtime, options) {
|
|
@@ -47980,13 +48048,13 @@ async function cmdValidate(runtime, fileFlag) {
|
|
|
47980
48048
|
return 2;
|
|
47981
48049
|
}
|
|
47982
48050
|
const selectedFile = explicitFile || configuredFile;
|
|
47983
|
-
const file = selectedFile ?
|
|
47984
|
-
if (file && !
|
|
48051
|
+
const file = selectedFile ? resolve29(runtime.cwd, selectedFile) : void 0;
|
|
48052
|
+
if (file && !existsSync38(file)) {
|
|
47985
48053
|
printWorker(runtime, worker, { ok: false, command: "validate", error: "file_not_found", file }, `workflow file not found: ${file}`);
|
|
47986
48054
|
return 1;
|
|
47987
48055
|
}
|
|
47988
48056
|
try {
|
|
47989
|
-
const raw = file ?
|
|
48057
|
+
const raw = file ? readFileSync37(file, "utf8") : inline;
|
|
47990
48058
|
const warnings = [];
|
|
47991
48059
|
const definitions = parseWorkflowDefinitions(raw, runtime.env, (message) => warnings.push(message));
|
|
47992
48060
|
const secretEnvs = definitions.map((definition) => ({
|
|
@@ -48011,7 +48079,7 @@ async function cmdValidate(runtime, fileFlag) {
|
|
|
48011
48079
|
}
|
|
48012
48080
|
async function cmdArtifactsExist(runtime, pathFlag) {
|
|
48013
48081
|
const worker = gateOf(runtime, "artifacts-exist");
|
|
48014
|
-
const checked = verifyArtifactExists(runtime.dirs.assets,
|
|
48082
|
+
const checked = verifyArtifactExists(runtime.dirs.assets, resolve29(runtime.cwd, pathFlag));
|
|
48015
48083
|
if (!checked.ok) {
|
|
48016
48084
|
printWorker(
|
|
48017
48085
|
runtime,
|
|
@@ -48030,15 +48098,15 @@ async function cmdArtifactsExist(runtime, pathFlag) {
|
|
|
48030
48098
|
return 0;
|
|
48031
48099
|
}
|
|
48032
48100
|
async function cmdImprove(runtime, options = {}) {
|
|
48033
|
-
const file = options.file ?
|
|
48034
|
-
const routingRecords =
|
|
48035
|
-
const candidatesDir = options.outDir ?
|
|
48101
|
+
const file = options.file ? resolve29(runtime.cwd, options.file) : telemetryPath(runtime.dirs.logs);
|
|
48102
|
+
const routingRecords = existsSync38(file) ? readRoutingRecords(file).map((entry) => entry.routing) : [];
|
|
48103
|
+
const candidatesDir = options.outDir ? resolve29(runtime.cwd, options.outDir) : join48(runtime.cwd, ".kxm", "candidates");
|
|
48036
48104
|
const report2 = buildImprovementReport(routingRecords, {
|
|
48037
48105
|
candidatesDir,
|
|
48038
48106
|
projectRoot: runtime.cwd,
|
|
48039
48107
|
dryRun: runtime.dryRun
|
|
48040
48108
|
});
|
|
48041
|
-
const reportDir =
|
|
48109
|
+
const reportDir = join48(runtime.dirs.assets, "improvements");
|
|
48042
48110
|
const reportPath = writeImprovementReport(reportDir, report2, runtime.dryRun);
|
|
48043
48111
|
const text = formatImprovementReport(report2);
|
|
48044
48112
|
print(runtime.io, runtime.json, {
|
|
@@ -48170,9 +48238,9 @@ async function maybeOfferCompletionInstall(runtime) {
|
|
|
48170
48238
|
if (!pathNeeded) {
|
|
48171
48239
|
const scriptPath = completionScriptPath(shell, { env: runtime.env, configDir: runtime.env.KXM_USER_CONFIG_DIR });
|
|
48172
48240
|
const { rcFile } = completionRcTarget(shell, { env: runtime.env });
|
|
48173
|
-
if (rcFile &&
|
|
48241
|
+
if (rcFile && existsSync38(rcFile)) {
|
|
48174
48242
|
try {
|
|
48175
|
-
if (
|
|
48243
|
+
if (readFileSync37(rcFile, "utf8").includes(scriptPath)) return;
|
|
48176
48244
|
} catch {
|
|
48177
48245
|
}
|
|
48178
48246
|
}
|
|
@@ -48304,7 +48372,7 @@ async function cmdRoutingReport(runtime, options) {
|
|
|
48304
48372
|
let catalog;
|
|
48305
48373
|
if (includeEquivalentListCost) {
|
|
48306
48374
|
try {
|
|
48307
|
-
const pricesPath = options.prices ?
|
|
48375
|
+
const pricesPath = options.prices ? resolve29(runtime.cwd, options.prices) : join48(runtime.dirs.workspace, "prices.yaml");
|
|
48308
48376
|
catalog = loadPriceCatalog(pricesPath);
|
|
48309
48377
|
} catch {
|
|
48310
48378
|
}
|
|
@@ -48388,6 +48456,12 @@ async function cmdRoutingBenchmark(runtime, options) {
|
|
|
48388
48456
|
|
|
48389
48457
|
// plugins/kxm/src/cli.ts
|
|
48390
48458
|
var CLI_NAME2 = "kxm";
|
|
48459
|
+
function resolveCliAuthToken(runtime, project) {
|
|
48460
|
+
const envToken = runtime.env.KXM_AUTH_TOKEN?.trim();
|
|
48461
|
+
if (envToken) return envToken;
|
|
48462
|
+
const record = readHubEnvRecord(runtime.env);
|
|
48463
|
+
return record?.projectTokens?.[project]?.trim() || record?.authToken?.trim() || void 0;
|
|
48464
|
+
}
|
|
48391
48465
|
var USAGE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
48392
48466
|
"commander.help",
|
|
48393
48467
|
"commander.helpDisplayed",
|
|
@@ -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
|
|
48486
|
+
const authToken = resolveCliAuthToken(runtime, 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
|
}
|