@kontextmind/kxm 0.7.20 → 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 +958 -872
- package/plugins/kxm/dist/client.js +2 -2
- package/plugins/kxm/dist/extension.js +85 -67
- package/plugins/kxm/dist/mcp-server.js +3 -3
- package/plugins/kxm/dist/runtime.js +212 -194
- package/plugins/kxm/dist/server.js +46 -26
- package/plugins/kxm/dist/vnext-runtime-supervisor.js +155 -137
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/cli/system.ts +3 -4
- package/plugins/kxm/src/cli/types.ts +2 -4
- package/plugins/kxm/src/cli/vnext.ts +1 -4
- package/plugins/kxm/src/cli.ts +15 -3
- package/plugins/kxm/src/client.ts +4 -2
- package/plugins/kxm/src/hub-autostart.ts +4 -4
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/repo-root.ts +29 -0
- package/plugins/kxm/src/vnext-config.ts +5 -3
- package/plugins/kxm/src/vnext-runtime-supervisor.ts +3 -4
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -14780,7 +14780,7 @@ var require_dist = __commonJS({
|
|
|
14780
14780
|
|
|
14781
14781
|
// plugins/kxm/src/cli.ts
|
|
14782
14782
|
import { resolve as resolve30 } from "node:path";
|
|
14783
|
-
import { fileURLToPath as
|
|
14783
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
14784
14784
|
|
|
14785
14785
|
// node_modules/commander/lib/error.js
|
|
14786
14786
|
var CommanderError = class extends Error {
|
|
@@ -18329,6 +18329,25 @@ function planKxmPackageUpdate(source, latest, releaseDir, asset) {
|
|
|
18329
18329
|
return steps;
|
|
18330
18330
|
}
|
|
18331
18331
|
|
|
18332
|
+
// plugins/kxm/src/repo-root.ts
|
|
18333
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
18334
|
+
import { dirname, join as join2 } from "node:path";
|
|
18335
|
+
import { fileURLToPath } from "node:url";
|
|
18336
|
+
var ROOT_MARKERS = ["scripts/kxm-hub.mjs", "scripts/kxm.mjs"];
|
|
18337
|
+
var MAX_WALK_DEPTH = 10;
|
|
18338
|
+
function findKxmRepoRoot(fromUrl = import.meta.url) {
|
|
18339
|
+
let dir = dirname(fileURLToPath(fromUrl));
|
|
18340
|
+
for (let depth = 0; depth < MAX_WALK_DEPTH; depth += 1) {
|
|
18341
|
+
if (ROOT_MARKERS.some((marker) => existsSync2(join2(dir, marker)))) return dir;
|
|
18342
|
+
const parent = dirname(dir);
|
|
18343
|
+
if (parent === dir) break;
|
|
18344
|
+
dir = parent;
|
|
18345
|
+
}
|
|
18346
|
+
throw new Error(
|
|
18347
|
+
`kxm: cannot locate the KXM repo root from ${fileURLToPath(fromUrl)} (walked ${MAX_WALK_DEPTH} levels looking for ${ROOT_MARKERS[0]})`
|
|
18348
|
+
);
|
|
18349
|
+
}
|
|
18350
|
+
|
|
18332
18351
|
// plugins/kxm/src/client.ts
|
|
18333
18352
|
import { createHash as createHash3 } from "node:crypto";
|
|
18334
18353
|
|
|
@@ -19459,7 +19478,7 @@ var HubClient = class {
|
|
|
19459
19478
|
while (!this.stopped && this.agent) {
|
|
19460
19479
|
this.eventsAbort = new AbortController();
|
|
19461
19480
|
try {
|
|
19462
|
-
const response = await fetch(
|
|
19481
|
+
const response = await (this.options.fetchImpl ?? fetch)(
|
|
19463
19482
|
`${this.options.serverUrl.replace(/\/$/, "")}/v1/events?agentId=${encodeURIComponent(this.agent.id)}`,
|
|
19464
19483
|
{
|
|
19465
19484
|
headers: this.headers(),
|
|
@@ -19536,7 +19555,7 @@ var HubClient = class {
|
|
|
19536
19555
|
const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
|
|
19537
19556
|
let response;
|
|
19538
19557
|
try {
|
|
19539
|
-
response = await fetch(`${this.options.serverUrl.replace(/\/$/, "")}${path4}`, {
|
|
19558
|
+
response = await (this.options.fetchImpl ?? fetch)(`${this.options.serverUrl.replace(/\/$/, "")}${path4}`, {
|
|
19540
19559
|
...init,
|
|
19541
19560
|
signal,
|
|
19542
19561
|
headers: { ...this.headers(includeIdentity), ...init.headers ?? {} }
|
|
@@ -19571,14 +19590,82 @@ var HubClient = class {
|
|
|
19571
19590
|
}
|
|
19572
19591
|
};
|
|
19573
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
|
+
|
|
19574
19661
|
// plugins/kxm/src/project-name.ts
|
|
19575
|
-
import { readFileSync as
|
|
19576
|
-
import { basename, join as
|
|
19662
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
19663
|
+
import { basename, join as join4 } from "node:path";
|
|
19577
19664
|
function defaultProjectName(cwd, env = process.env) {
|
|
19578
19665
|
const fromEnv = env.KXM_PROJECT?.trim();
|
|
19579
19666
|
if (fromEnv) return fromEnv;
|
|
19580
19667
|
try {
|
|
19581
|
-
const pkg = JSON.parse(
|
|
19668
|
+
const pkg = JSON.parse(readFileSync3(join4(cwd, "package.json"), "utf8"));
|
|
19582
19669
|
if (typeof pkg.name === "string" && pkg.name.trim().length > 0) return pkg.name.trim();
|
|
19583
19670
|
} catch {
|
|
19584
19671
|
}
|
|
@@ -19587,9 +19674,9 @@ function defaultProjectName(cwd, env = process.env) {
|
|
|
19587
19674
|
|
|
19588
19675
|
// plugins/kxm/src/commands.ts
|
|
19589
19676
|
import { createHash as createHash4, randomUUID as randomUUID2, timingSafeEqual } from "node:crypto";
|
|
19590
|
-
import { chmodSync, existsSync as
|
|
19591
|
-
import { homedir } from "node:os";
|
|
19592
|
-
import { dirname, join 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";
|
|
19593
19680
|
function requiredString(value, name) {
|
|
19594
19681
|
if (typeof value !== "string" || value.trim() === "") throw new Error(`${name} is required`);
|
|
19595
19682
|
return value.trim();
|
|
@@ -20337,18 +20424,18 @@ function parseSessionToken(token) {
|
|
|
20337
20424
|
return void 0;
|
|
20338
20425
|
}
|
|
20339
20426
|
function resolveUserConfigDirectory(overrideDir) {
|
|
20340
|
-
if (overrideDir) return
|
|
20341
|
-
return
|
|
20427
|
+
if (overrideDir) return resolve2(overrideDir);
|
|
20428
|
+
return resolve2(process.env.KXM_USER_CONFIG_DIR?.trim() || join5(homedir2(), ".config", "kxm"));
|
|
20342
20429
|
}
|
|
20343
20430
|
function sessionTokenPath(userConfigDir) {
|
|
20344
|
-
return
|
|
20431
|
+
return join5(resolveUserConfigDirectory(userConfigDir), "session.token");
|
|
20345
20432
|
}
|
|
20346
20433
|
function persistSessionTokenToDisk(token, options) {
|
|
20347
20434
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
20348
|
-
const dir =
|
|
20349
|
-
|
|
20435
|
+
const dir = dirname3(filePath);
|
|
20436
|
+
mkdirSync3(dir, { recursive: true, mode: 448 });
|
|
20350
20437
|
const mode = options?.mode ?? 384;
|
|
20351
|
-
|
|
20438
|
+
writeFileSync3(filePath, `${token.trim()}
|
|
20352
20439
|
`, { encoding: "utf8", mode });
|
|
20353
20440
|
try {
|
|
20354
20441
|
chmodSync(filePath, mode);
|
|
@@ -20358,9 +20445,9 @@ function persistSessionTokenToDisk(token, options) {
|
|
|
20358
20445
|
}
|
|
20359
20446
|
function readSessionTokenFromDisk(options) {
|
|
20360
20447
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
20361
|
-
if (!
|
|
20448
|
+
if (!existsSync4(filePath)) return void 0;
|
|
20362
20449
|
try {
|
|
20363
|
-
const token =
|
|
20450
|
+
const token = readFileSync4(filePath, "utf8").trim();
|
|
20364
20451
|
if (!token) return void 0;
|
|
20365
20452
|
const payload = parseSessionToken(token);
|
|
20366
20453
|
if (!payload) return void 0;
|
|
@@ -20371,7 +20458,7 @@ function readSessionTokenFromDisk(options) {
|
|
|
20371
20458
|
}
|
|
20372
20459
|
function clearSessionTokenFromDisk(options) {
|
|
20373
20460
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
20374
|
-
if (!
|
|
20461
|
+
if (!existsSync4(filePath)) return false;
|
|
20375
20462
|
try {
|
|
20376
20463
|
unlinkSync(filePath);
|
|
20377
20464
|
return true;
|
|
@@ -20470,10 +20557,10 @@ function enforceToolPolicy(commandName, env = process.env, options) {
|
|
|
20470
20557
|
return { allowed: true };
|
|
20471
20558
|
}
|
|
20472
20559
|
const tokenFile = sessionTokenPath(env.KXM_USER_CONFIG_DIR);
|
|
20473
|
-
if (
|
|
20560
|
+
if (existsSync4(tokenFile)) {
|
|
20474
20561
|
let tokenRaw;
|
|
20475
20562
|
try {
|
|
20476
|
-
tokenRaw =
|
|
20563
|
+
tokenRaw = readFileSync4(tokenFile, "utf8").trim();
|
|
20477
20564
|
} catch {
|
|
20478
20565
|
return { allowed: false, error: "session_token_invalid", detail: "Session token file on disk could not be read" };
|
|
20479
20566
|
}
|
|
@@ -20497,9 +20584,8 @@ function enforceToolPolicy(commandName, env = process.env, options) {
|
|
|
20497
20584
|
var import__ = __toESM(require__(), 1);
|
|
20498
20585
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
20499
20586
|
import { createHash as createHash6 } from "node:crypto";
|
|
20500
|
-
import { existsSync as
|
|
20501
|
-
import { basename as basename2, dirname as
|
|
20502
|
-
import { fileURLToPath } from "node:url";
|
|
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";
|
|
20503
20589
|
|
|
20504
20590
|
// plugins/kxm/src/restricted-yaml.mjs
|
|
20505
20591
|
var import_yaml = __toESM(require_dist(), 1);
|
|
@@ -20827,7 +20913,7 @@ function resolveVnextTemplateBaseline(value) {
|
|
|
20827
20913
|
|
|
20828
20914
|
// plugins/kxm/src/vnext-harness.ts
|
|
20829
20915
|
import { spawnSync } from "node:child_process";
|
|
20830
|
-
import { existsSync as
|
|
20916
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
20831
20917
|
import { win32 as win32Path } from "node:path";
|
|
20832
20918
|
|
|
20833
20919
|
// plugins/kxm/src/vnext-oneshot-process.ts
|
|
@@ -21376,7 +21462,7 @@ function findWinNpmInnerExe(cliId, options = {}) {
|
|
|
21376
21462
|
if ((options.platform ?? process.platform) !== "win32") return void 0;
|
|
21377
21463
|
const segments = WIN_NPM_INNER_EXE[cliId];
|
|
21378
21464
|
if (!segments) return void 0;
|
|
21379
|
-
const exists = options.existsSync ??
|
|
21465
|
+
const exists = options.existsSync ?? existsSync5;
|
|
21380
21466
|
const pathEnv = options.pathEnv ?? process.env.PATH ?? "";
|
|
21381
21467
|
for (const dir of pathEnv.split(";").filter(Boolean)) {
|
|
21382
21468
|
if (!exists(win32Path.join(dir, `${cliId}.cmd`))) continue;
|
|
@@ -21893,8 +21979,10 @@ var VnextConfigError = class extends Error {
|
|
|
21893
21979
|
this.issues = sorted;
|
|
21894
21980
|
}
|
|
21895
21981
|
};
|
|
21896
|
-
|
|
21897
|
-
|
|
21982
|
+
function defaultVnextSchemaDir() {
|
|
21983
|
+
return join6(findKxmRepoRoot(import.meta.url), "schemas", "vnext");
|
|
21984
|
+
}
|
|
21985
|
+
var DEFAULT_SCHEMA_DIR = defaultVnextSchemaDir();
|
|
21898
21986
|
var RESOURCE_SCHEMA = Object.freeze({
|
|
21899
21987
|
project: { identity: "kxm.project.v1", file: "project.schema.json" },
|
|
21900
21988
|
repository: { identity: "kxm.repository.v1", file: "repository.schema.json" },
|
|
@@ -21940,7 +22028,7 @@ function parseRestrictedYaml2(input, label = "<yaml>", limits = VNEXT_YAML_LIMIT
|
|
|
21940
22028
|
}
|
|
21941
22029
|
}
|
|
21942
22030
|
function readJsonObject(file) {
|
|
21943
|
-
const parsed = JSON.parse(
|
|
22031
|
+
const parsed = JSON.parse(readFileSync5(file, "utf8"));
|
|
21944
22032
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`${file} is not a JSON object`);
|
|
21945
22033
|
return parsed;
|
|
21946
22034
|
}
|
|
@@ -21957,12 +22045,12 @@ var VnextSchemaRegistry = class {
|
|
|
21957
22045
|
permissionDiffValidator;
|
|
21958
22046
|
runEventValidator;
|
|
21959
22047
|
constructor(schemasDir = DEFAULT_SCHEMA_DIR) {
|
|
21960
|
-
this.schemasDir =
|
|
22048
|
+
this.schemasDir = resolve3(schemasDir);
|
|
21961
22049
|
this.ajv = new import__.Ajv2020({ allErrors: true, strict: true, strictRequired: false });
|
|
21962
|
-
const common = readJsonObject(
|
|
22050
|
+
const common = readJsonObject(join6(this.schemasDir, "common.schema.json"));
|
|
21963
22051
|
this.ajv.addSchema(common);
|
|
21964
22052
|
for (const definition of Object.values(RESOURCE_SCHEMA)) {
|
|
21965
|
-
this.ajv.addSchema(readJsonObject(
|
|
22053
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, definition.file)));
|
|
21966
22054
|
}
|
|
21967
22055
|
const localBindingsFile = "local-repository-bindings.schema.json";
|
|
21968
22056
|
const templateProvenanceFile = "template-provenance.schema.json";
|
|
@@ -21972,14 +22060,14 @@ var VnextSchemaRegistry = class {
|
|
|
21972
22060
|
const migrationReceiptFile = "migration-receipt.schema.json";
|
|
21973
22061
|
const permissionDiffFile = "permission-diff.schema.json";
|
|
21974
22062
|
const runEventFile = "run-event.schema.json";
|
|
21975
|
-
this.ajv.addSchema(readJsonObject(
|
|
21976
|
-
this.ajv.addSchema(readJsonObject(
|
|
21977
|
-
this.ajv.addSchema(readJsonObject(
|
|
21978
|
-
this.ajv.addSchema(readJsonObject(
|
|
21979
|
-
this.ajv.addSchema(readJsonObject(
|
|
21980
|
-
this.ajv.addSchema(readJsonObject(
|
|
21981
|
-
this.ajv.addSchema(readJsonObject(
|
|
21982
|
-
this.ajv.addSchema(readJsonObject(
|
|
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)));
|
|
21983
22071
|
for (const [kind, definition] of Object.entries(RESOURCE_SCHEMA)) {
|
|
21984
22072
|
const validator = this.ajv.getSchema(`https://schemas.kxm.dev/vnext/${definition.file}`);
|
|
21985
22073
|
if (!validator) throw new Error(`schema did not compile: ${definition.file}`);
|
|
@@ -22055,7 +22143,7 @@ function schemaIssue(file, error) {
|
|
|
22055
22143
|
return issue2("schema", `schema_${error.keyword}`, file, `${location} ${error.message ?? "is invalid"}${suffix}`);
|
|
22056
22144
|
}
|
|
22057
22145
|
function canonicalHostPath(path4) {
|
|
22058
|
-
const resolved =
|
|
22146
|
+
const resolved = resolve3(path4);
|
|
22059
22147
|
try {
|
|
22060
22148
|
return realpathSync.native(resolved);
|
|
22061
22149
|
} catch {
|
|
@@ -22069,20 +22157,20 @@ function sameHostPath(left, right) {
|
|
|
22069
22157
|
}
|
|
22070
22158
|
function containedHostPath(root, candidate) {
|
|
22071
22159
|
const path4 = relative(root, candidate);
|
|
22072
|
-
return path4 === "" || !
|
|
22160
|
+
return path4 === "" || !isAbsolute2(path4) && path4 !== ".." && !path4.startsWith(`..${sep}`);
|
|
22073
22161
|
}
|
|
22074
22162
|
function portableBindingIssue(root, pathHint, repositoryId) {
|
|
22075
22163
|
let current = root;
|
|
22076
22164
|
for (const segment of pathHint === "." ? [] : pathHint.split("/")) {
|
|
22077
|
-
current =
|
|
22078
|
-
if (!
|
|
22165
|
+
current = join6(current, segment);
|
|
22166
|
+
if (!existsSync6(current)) break;
|
|
22079
22167
|
const stat = lstatSync(current);
|
|
22080
22168
|
if (stat.isSymbolicLink()) {
|
|
22081
22169
|
return issue2("path", "repository_binding_path_link", ".kxm/project.yaml", `portable pathHint for ${repositoryId} traverses a symbolic link or junction`);
|
|
22082
22170
|
}
|
|
22083
22171
|
}
|
|
22084
|
-
const binding =
|
|
22085
|
-
if (
|
|
22172
|
+
const binding = resolve3(root, ...pathHint.split("/"));
|
|
22173
|
+
if (existsSync6(binding)) {
|
|
22086
22174
|
const realRoot = canonicalHostPath(root);
|
|
22087
22175
|
const realBinding = canonicalHostPath(binding);
|
|
22088
22176
|
if (!containedHostPath(realRoot, realBinding)) {
|
|
@@ -22119,10 +22207,10 @@ function readResource(registry, root, file, logicalPath, kind, id, containmentRo
|
|
|
22119
22207
|
fail2("discovery", "resource_missing", label, "resource does not exist");
|
|
22120
22208
|
}
|
|
22121
22209
|
if (stat.isSymbolicLink()) fail2("path", "resource_symlink", label, "configuration resources must not be symbolic links");
|
|
22122
|
-
const boundary =
|
|
22123
|
-
let parent =
|
|
22210
|
+
const boundary = resolve3(containmentRoot);
|
|
22211
|
+
let parent = dirname4(file);
|
|
22124
22212
|
while (parent !== boundary) {
|
|
22125
|
-
if (parent ===
|
|
22213
|
+
if (parent === dirname4(parent)) fail2("path", "resource_outside_project", label, "resource escapes the project root");
|
|
22126
22214
|
let parentStat;
|
|
22127
22215
|
try {
|
|
22128
22216
|
parentStat = lstatSync(parent);
|
|
@@ -22130,33 +22218,33 @@ function readResource(registry, root, file, logicalPath, kind, id, containmentRo
|
|
|
22130
22218
|
fail2("discovery", "resource_parent_missing", label, "resource parent does not exist");
|
|
22131
22219
|
}
|
|
22132
22220
|
if (parentStat.isSymbolicLink()) fail2("path", "resource_parent_symlink", label, "configuration resource parents must not be symbolic links");
|
|
22133
|
-
parent =
|
|
22221
|
+
parent = dirname4(parent);
|
|
22134
22222
|
}
|
|
22135
22223
|
if (!stat.isFile()) fail2("path", "resource_not_file", label, "configuration resource must be a regular file");
|
|
22136
|
-
const value = parseRestrictedYaml2(
|
|
22224
|
+
const value = parseRestrictedYaml2(readFileSync5(file), label);
|
|
22137
22225
|
const issues = registry.validate(kind, value, label);
|
|
22138
22226
|
if (issues.length > 0) throw new VnextConfigError(issues);
|
|
22139
22227
|
return { kind, ...id === void 0 ? {} : { id }, file, logicalPath, value };
|
|
22140
22228
|
}
|
|
22141
22229
|
function readTemplateProvenance(registry, root) {
|
|
22142
|
-
const file =
|
|
22143
|
-
if (!
|
|
22230
|
+
const file = join6(root, ".kxm", "template-provenance.yaml");
|
|
22231
|
+
if (!existsSync6(file)) return void 0;
|
|
22144
22232
|
const label = ".kxm/template-provenance.yaml";
|
|
22145
22233
|
const stat = lstatSync(file);
|
|
22146
22234
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
22147
22235
|
fail2("path", "resource_not_file", label, "template provenance must be a regular file, not a link or directory");
|
|
22148
22236
|
}
|
|
22149
|
-
const configRoot =
|
|
22150
|
-
let parent =
|
|
22237
|
+
const configRoot = join6(root, ".kxm");
|
|
22238
|
+
let parent = dirname4(file);
|
|
22151
22239
|
while (parent !== root) {
|
|
22152
22240
|
const parentStat = lstatSync(parent);
|
|
22153
22241
|
if (parentStat.isSymbolicLink() || !parentStat.isDirectory()) {
|
|
22154
22242
|
fail2("path", "resource_parent_symlink", label, "template provenance parents must be regular directories");
|
|
22155
22243
|
}
|
|
22156
22244
|
if (parent === configRoot) break;
|
|
22157
|
-
parent =
|
|
22245
|
+
parent = dirname4(parent);
|
|
22158
22246
|
}
|
|
22159
|
-
const value = parseRestrictedYaml2(
|
|
22247
|
+
const value = parseRestrictedYaml2(readFileSync5(file), label);
|
|
22160
22248
|
const issues = registry.validateTemplateProvenance(value, label);
|
|
22161
22249
|
if (issues.length > 0) throw new VnextConfigError(issues);
|
|
22162
22250
|
if (!resolveVnextTemplateBaseline(value)) {
|
|
@@ -22187,7 +22275,7 @@ function readTemplateProvenance(registry, root) {
|
|
|
22187
22275
|
}
|
|
22188
22276
|
function listNamedResources(registry, root, directory, logicalDirectory, kind) {
|
|
22189
22277
|
const resources = /* @__PURE__ */ new Map();
|
|
22190
|
-
if (!
|
|
22278
|
+
if (!existsSync6(directory)) return resources;
|
|
22191
22279
|
const stat = lstatSync(directory);
|
|
22192
22280
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
22193
22281
|
fail2("path", "resource_directory_invalid", displayPath(root, directory), "resource directory must be a regular directory");
|
|
@@ -22196,27 +22284,27 @@ function listNamedResources(registry, root, directory, logicalDirectory, kind) {
|
|
|
22196
22284
|
const entries = readdirSync(directory, { withFileTypes: true }).sort((left, right) => compareCodeUnits3(left.name, right.name));
|
|
22197
22285
|
for (const entry of entries) {
|
|
22198
22286
|
if (entry.isDirectory()) {
|
|
22199
|
-
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"));
|
|
22200
22288
|
continue;
|
|
22201
22289
|
}
|
|
22202
22290
|
if (!entry.name.toLowerCase().endsWith(".yaml") && !entry.name.toLowerCase().endsWith(".yml")) continue;
|
|
22203
22291
|
if (!entry.isFile() || extname(entry.name) !== ".yaml") {
|
|
22204
|
-
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"));
|
|
22205
22293
|
continue;
|
|
22206
22294
|
}
|
|
22207
22295
|
const id = basename2(entry.name, ".yaml");
|
|
22208
22296
|
if (kind === "model" && id === "inventory") continue;
|
|
22209
22297
|
if (!resourceIdentifier(id)) {
|
|
22210
|
-
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`));
|
|
22211
22299
|
continue;
|
|
22212
22300
|
}
|
|
22213
22301
|
const collision = [...resources.keys()].find((candidate) => candidate.toLocaleLowerCase("en-US") === id.toLocaleLowerCase("en-US"));
|
|
22214
22302
|
if (collision) {
|
|
22215
|
-
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}`));
|
|
22216
22304
|
continue;
|
|
22217
22305
|
}
|
|
22218
22306
|
try {
|
|
22219
|
-
const resource = readResource(registry, root,
|
|
22307
|
+
const resource = readResource(registry, root, join6(directory, entry.name), `${logicalDirectory}/${id}.yaml`, kind, id);
|
|
22220
22308
|
resources.set(id, resource);
|
|
22221
22309
|
} catch (error) {
|
|
22222
22310
|
if (error instanceof VnextConfigError) issues.push(...error.issues);
|
|
@@ -22537,8 +22625,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
22537
22625
|
const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
|
|
22538
22626
|
if (maxWriteRepositories > writable) issues.push(issue2("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
|
|
22539
22627
|
}
|
|
22540
|
-
const
|
|
22541
|
-
const minimumPassed =
|
|
22628
|
+
const join50 = objectValue(step.join);
|
|
22629
|
+
const minimumPassed = join50 && typeof join50.minimumPassed === "number" ? join50.minimumPassed : void 0;
|
|
22542
22630
|
if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue2("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
|
|
22543
22631
|
const distinctBy = names(assignment?.distinctBy);
|
|
22544
22632
|
if (distinctBy.length > 0) {
|
|
@@ -22752,11 +22840,11 @@ function validateBundle(project, repositories, agents, models, workflows, enviro
|
|
|
22752
22840
|
if (!workflows.has(defaultWorkflow)) issues.push(issue2("reference", "default_workflow_unknown", project.logicalPath, `default workflow ${defaultWorkflow} does not exist`));
|
|
22753
22841
|
for (const workflow of workflows.values()) validateWorkflow(workflow, agents, models, repositoryIds, gates, issues);
|
|
22754
22842
|
if (projectRoot) {
|
|
22755
|
-
const writerRolePath =
|
|
22843
|
+
const writerRolePath = join6(projectRoot, ".kxm", "roles", "writer.yaml");
|
|
22756
22844
|
const implementerAgent = agents.get("implementer") ?? agents.get("writer");
|
|
22757
|
-
if (
|
|
22845
|
+
if (existsSync6(writerRolePath) && implementerAgent) {
|
|
22758
22846
|
try {
|
|
22759
|
-
const rawRole = parseRestrictedYaml2(
|
|
22847
|
+
const rawRole = parseRestrictedYaml2(readFileSync5(writerRolePath, "utf8"));
|
|
22760
22848
|
const roleObj = objectValue(rawRole);
|
|
22761
22849
|
const rosterEntries = valuesOf(roleObj ?? {}, "roster").map((candidate) => objectValue(candidate)).filter((entry) => Boolean(entry));
|
|
22762
22850
|
const enabledRosterModels = rosterEntries.filter((entry) => entry.enabled !== false).map((entry) => stringValue(entry.model)).filter((m2) => Boolean(m2));
|
|
@@ -22802,8 +22890,8 @@ function gitEnvironment() {
|
|
|
22802
22890
|
return Object.fromEntries(Object.entries(process.env).filter(([name]) => !name.toUpperCase().startsWith("GIT_")));
|
|
22803
22891
|
}
|
|
22804
22892
|
function discoverGitRoot(start = process.cwd()) {
|
|
22805
|
-
let current =
|
|
22806
|
-
if (
|
|
22893
|
+
let current = resolve3(start);
|
|
22894
|
+
if (existsSync6(current) && !lstatSync(current).isDirectory()) current = dirname4(current);
|
|
22807
22895
|
const result = spawnSync2("git", ["-C", current, "rev-parse", "--show-toplevel"], {
|
|
22808
22896
|
encoding: "utf8",
|
|
22809
22897
|
env: gitEnvironment(),
|
|
@@ -22811,12 +22899,12 @@ function discoverGitRoot(start = process.cwd()) {
|
|
|
22811
22899
|
windowsHide: true
|
|
22812
22900
|
});
|
|
22813
22901
|
if (result.status !== 0 || result.error || !result.stdout.trim()) return void 0;
|
|
22814
|
-
const root =
|
|
22815
|
-
return
|
|
22902
|
+
const root = resolve3(result.stdout.trim());
|
|
22903
|
+
return existsSync6(root) && lstatSync(root).isDirectory() ? root : void 0;
|
|
22816
22904
|
}
|
|
22817
22905
|
function discoverVnextProjectRoot(start = process.cwd()) {
|
|
22818
22906
|
const gitRoot = discoverGitRoot(start);
|
|
22819
|
-
return gitRoot &&
|
|
22907
|
+
return gitRoot && existsSync6(join6(gitRoot, ".kxm", "project.yaml")) ? gitRoot : void 0;
|
|
22820
22908
|
}
|
|
22821
22909
|
function assertNoRegisteredGates(options) {
|
|
22822
22910
|
if ("registeredGates" in options) {
|
|
@@ -22825,7 +22913,7 @@ function assertNoRegisteredGates(options) {
|
|
|
22825
22913
|
}
|
|
22826
22914
|
function loadVnextProject(projectRoot, options = {}) {
|
|
22827
22915
|
assertNoRegisteredGates(options);
|
|
22828
|
-
const root =
|
|
22916
|
+
const root = resolve3(projectRoot);
|
|
22829
22917
|
let migrationReceipt;
|
|
22830
22918
|
if (legacyConfigFilesAt(root).length > 0 && options.allowUnreceiptedLegacyConfig !== true) {
|
|
22831
22919
|
const receiptCheck = readVnextMigrationReceipt(root, options);
|
|
@@ -22833,7 +22921,7 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22833
22921
|
migrationReceipt = receiptCheck.receipt;
|
|
22834
22922
|
}
|
|
22835
22923
|
const registry = new VnextSchemaRegistry(options.schemasDir);
|
|
22836
|
-
const project = readResource(registry, root,
|
|
22924
|
+
const project = readResource(registry, root, join6(root, ".kxm", "project.yaml"), ".kxm/project.yaml", "project");
|
|
22837
22925
|
const earlyIssues = [];
|
|
22838
22926
|
validatePortablePaths(project, earlyIssues);
|
|
22839
22927
|
const templateProvenance = readTemplateProvenance(registry, root);
|
|
@@ -22855,16 +22943,16 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22855
22943
|
}
|
|
22856
22944
|
}
|
|
22857
22945
|
if (earlyIssues.length > 0) throw new VnextConfigError(earlyIssues);
|
|
22858
|
-
const agents = listNamedResources(registry, root,
|
|
22859
|
-
const models = listNamedResources(registry, root,
|
|
22860
|
-
const workflows = listNamedResources(registry, root,
|
|
22861
|
-
const gatePath =
|
|
22862
|
-
const gateRegistry =
|
|
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;
|
|
22863
22951
|
const environments = [];
|
|
22864
22952
|
const repositories = /* @__PURE__ */ new Map();
|
|
22865
22953
|
const loadIssues = [];
|
|
22866
|
-
const projectEnvironment =
|
|
22867
|
-
if (
|
|
22954
|
+
const projectEnvironment = join6(root, ".kxm", "project", "env.yaml");
|
|
22955
|
+
if (existsSync6(projectEnvironment)) {
|
|
22868
22956
|
try {
|
|
22869
22957
|
environments.push(readResource(registry, root, projectEnvironment, ".kxm/project/env.yaml", "environment"));
|
|
22870
22958
|
} catch (error) {
|
|
@@ -22882,7 +22970,7 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22882
22970
|
if (!repositoryId) continue;
|
|
22883
22971
|
const hasLocalBinding = Object.hasOwn(options.repositoryBindings ?? {}, repositoryId);
|
|
22884
22972
|
const localBinding = options.repositoryBindings?.[repositoryId];
|
|
22885
|
-
if (hasLocalBinding && (!localBinding || !
|
|
22973
|
+
if (hasLocalBinding && (!localBinding || !isAbsolute2(localBinding))) {
|
|
22886
22974
|
loadIssues.push(issue2("path", "repository_binding_not_absolute", ".kxm/project.yaml", `host-local binding for ${repositoryId} must be absolute`));
|
|
22887
22975
|
continue;
|
|
22888
22976
|
}
|
|
@@ -22901,12 +22989,12 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22901
22989
|
continue;
|
|
22902
22990
|
}
|
|
22903
22991
|
}
|
|
22904
|
-
const binding = hasLocalBinding && localBinding ?
|
|
22992
|
+
const binding = hasLocalBinding && localBinding ? resolve3(localBinding) : role === "control" ? root : pathHint && portablePath(pathHint) ? resolve3(root, ...pathHint.split("/")) : void 0;
|
|
22905
22993
|
if (!binding) {
|
|
22906
22994
|
if (required) loadIssues.push(issue2("discovery", "repository_binding_missing", ".kxm/project.yaml", `required repository ${repositoryId} has no portable pathHint or host-local binding`));
|
|
22907
22995
|
continue;
|
|
22908
22996
|
}
|
|
22909
|
-
if (!
|
|
22997
|
+
if (!existsSync6(binding)) {
|
|
22910
22998
|
if (required || hasLocalBinding) loadIssues.push(issue2("discovery", "repository_binding_unavailable", ".kxm/project.yaml", `${hasLocalBinding ? "explicit" : "required"} repository binding ${repositoryId} is unavailable`));
|
|
22911
22999
|
continue;
|
|
22912
23000
|
}
|
|
@@ -22929,9 +23017,9 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22929
23017
|
continue;
|
|
22930
23018
|
}
|
|
22931
23019
|
seenBindings.set(foldedBinding, repositoryId);
|
|
22932
|
-
const repositoryFile =
|
|
23020
|
+
const repositoryFile = join6(binding, ".kxm", "repo", "repo.yaml");
|
|
22933
23021
|
let definitionValidated = false;
|
|
22934
|
-
if (
|
|
23022
|
+
if (existsSync6(repositoryFile)) {
|
|
22935
23023
|
try {
|
|
22936
23024
|
const resource = readResource(registry, root, repositoryFile, `.kxm/repositories/${repositoryId}/repo.yaml`, "repository", repositoryId, binding);
|
|
22937
23025
|
if (resource.value.repositoryId !== repositoryId) {
|
|
@@ -22947,8 +23035,8 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22947
23035
|
} else if (required || hasLocalBinding) {
|
|
22948
23036
|
loadIssues.push(issue2("discovery", "repository_definition_missing", `.kxm/repositories/${repositoryId}/repo.yaml`, `${hasLocalBinding ? "explicit" : "required"} repository ${repositoryId} has no repo.yaml`));
|
|
22949
23037
|
}
|
|
22950
|
-
const environmentFile =
|
|
22951
|
-
if (
|
|
23038
|
+
const environmentFile = join6(binding, ".kxm", "repo", "env.yaml");
|
|
23039
|
+
if (existsSync6(environmentFile)) {
|
|
22952
23040
|
if (!definitionValidated) {
|
|
22953
23041
|
loadIssues.push(issue2("reference", "repository_environment_without_definition", `.kxm/repositories/${repositoryId}/env.yaml`, `repository ${repositoryId} environment requires a validated matching repo.yaml`));
|
|
22954
23042
|
} else {
|
|
@@ -23016,7 +23104,7 @@ function verifyVnextMigrationReceiptTarget(root, receipt, resources, configRevis
|
|
|
23016
23104
|
}
|
|
23017
23105
|
function relativePortable(root, absolute) {
|
|
23018
23106
|
const rel = relative(root, absolute);
|
|
23019
|
-
if (!rel ||
|
|
23107
|
+
if (!rel || isAbsolute2(rel) || rel === ".." || rel.startsWith(`..${sep}`)) return void 0;
|
|
23020
23108
|
return rel.split(sep).join("/");
|
|
23021
23109
|
}
|
|
23022
23110
|
function legacyInputsAt(root) {
|
|
@@ -23026,21 +23114,21 @@ function legacyInputsAt(root) {
|
|
|
23026
23114
|
".kxm/config/workflows",
|
|
23027
23115
|
".kxm/state/kxm.db"
|
|
23028
23116
|
];
|
|
23029
|
-
return candidates.filter((candidate) =>
|
|
23117
|
+
return candidates.filter((candidate) => existsSync6(join6(root, ...candidate.split("/"))));
|
|
23030
23118
|
}
|
|
23031
23119
|
var VNEXT_MIGRATION_RECEIPT_PATH = ".kxm/migration-receipt.yaml";
|
|
23032
23120
|
var LEGACY_CONFIG_FILES = [".kxm/config/agents.json", ".kxm/config/gates.json"];
|
|
23033
23121
|
function legacyConfigFilesAt(root) {
|
|
23034
23122
|
const files = [];
|
|
23035
23123
|
for (const component of [".kxm", ".kxm/config"]) {
|
|
23036
|
-
const absolute =
|
|
23037
|
-
if (
|
|
23124
|
+
const absolute = join6(root, ...component.split("/"));
|
|
23125
|
+
if (existsSync6(absolute) && lstatSync(absolute).isSymbolicLink()) return [component];
|
|
23038
23126
|
}
|
|
23039
23127
|
for (const candidate of LEGACY_CONFIG_FILES) {
|
|
23040
|
-
if (
|
|
23128
|
+
if (existsSync6(join6(root, ...candidate.split("/")))) files.push(candidate);
|
|
23041
23129
|
}
|
|
23042
|
-
const workflowsDir =
|
|
23043
|
-
if (
|
|
23130
|
+
const workflowsDir = join6(root, ".kxm", "config", "workflows");
|
|
23131
|
+
if (existsSync6(workflowsDir)) {
|
|
23044
23132
|
const stat = lstatSync(workflowsDir);
|
|
23045
23133
|
if (stat.isSymbolicLink()) {
|
|
23046
23134
|
files.push(".kxm/config/workflows");
|
|
@@ -23055,9 +23143,9 @@ function legacyConfigFilesAt(root) {
|
|
|
23055
23143
|
return files;
|
|
23056
23144
|
}
|
|
23057
23145
|
function hashFileRecord(root, relativePath) {
|
|
23058
|
-
const absolute =
|
|
23059
|
-
if (!
|
|
23060
|
-
const bytes =
|
|
23146
|
+
const absolute = join6(root, ...relativePath.split("/"));
|
|
23147
|
+
if (!existsSync6(absolute)) return void 0;
|
|
23148
|
+
const bytes = readFileSync5(absolute);
|
|
23061
23149
|
return {
|
|
23062
23150
|
path: relativePath,
|
|
23063
23151
|
sha256: `sha256:${createHash6("sha256").update(bytes).digest("hex")}`,
|
|
@@ -23069,9 +23157,9 @@ function migrationReceiptSelfHash(receipt) {
|
|
|
23069
23157
|
return `sha256:${createHash6("sha256").update(vnextCanonicalJson(unsigned), "utf8").digest("hex")}`;
|
|
23070
23158
|
}
|
|
23071
23159
|
function readVnextMigrationReceipt(root, options = {}) {
|
|
23072
|
-
const receiptPath =
|
|
23160
|
+
const receiptPath = join6(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
|
|
23073
23161
|
const legacyFiles = legacyConfigFilesAt(root);
|
|
23074
|
-
if (!
|
|
23162
|
+
if (!existsSync6(receiptPath)) {
|
|
23075
23163
|
return {
|
|
23076
23164
|
issues: legacyFiles.map((file) => issue2("semantic", "legacy_vnext_conflict", file, "legacy and vNext configuration cannot coexist before an accepted migration receipt"))
|
|
23077
23165
|
};
|
|
@@ -23082,7 +23170,7 @@ function readVnextMigrationReceipt(root, options = {}) {
|
|
|
23082
23170
|
}
|
|
23083
23171
|
let receipt;
|
|
23084
23172
|
try {
|
|
23085
|
-
receipt = parseRestrictedYaml2(
|
|
23173
|
+
receipt = parseRestrictedYaml2(readFileSync5(receiptPath), VNEXT_MIGRATION_RECEIPT_PATH);
|
|
23086
23174
|
} catch (error) {
|
|
23087
23175
|
if (error instanceof VnextConfigError) return { issues: [...error.issues] };
|
|
23088
23176
|
throw error;
|
|
@@ -23115,14 +23203,14 @@ function readVnextMigrationReceipt(root, options = {}) {
|
|
|
23115
23203
|
return issues.length > 0 ? { issues } : { receipt, issues: [] };
|
|
23116
23204
|
}
|
|
23117
23205
|
function discoverLegacyRoot(start) {
|
|
23118
|
-
let initial =
|
|
23119
|
-
if (
|
|
23206
|
+
let initial = resolve3(start);
|
|
23207
|
+
if (existsSync6(initial) && !lstatSync(initial).isDirectory()) initial = dirname4(initial);
|
|
23120
23208
|
const candidate = discoverGitRoot(initial) ?? initial;
|
|
23121
23209
|
const inputs = legacyInputsAt(candidate);
|
|
23122
23210
|
return inputs.length > 0 ? { root: candidate, inputs } : void 0;
|
|
23123
23211
|
}
|
|
23124
23212
|
function planVnextInitialization(start = process.cwd(), options = {}) {
|
|
23125
|
-
const inspectedFrom =
|
|
23213
|
+
const inspectedFrom = resolve3(start);
|
|
23126
23214
|
const projectRoot = discoverVnextProjectRoot(inspectedFrom);
|
|
23127
23215
|
if (projectRoot) {
|
|
23128
23216
|
try {
|
|
@@ -23143,7 +23231,7 @@ function planVnextInitialization(start = process.cwd(), options = {}) {
|
|
|
23143
23231
|
}
|
|
23144
23232
|
const gitRoot = discoverGitRoot(inspectedFrom);
|
|
23145
23233
|
const candidateRoot = gitRoot ?? inspectedFrom;
|
|
23146
|
-
if (
|
|
23234
|
+
if (existsSync6(join6(candidateRoot, ".kxm"))) {
|
|
23147
23235
|
return {
|
|
23148
23236
|
mode: "repair",
|
|
23149
23237
|
inspectedFrom,
|
|
@@ -23159,14 +23247,13 @@ function planVnextInitialization(start = process.cwd(), options = {}) {
|
|
|
23159
23247
|
// plugins/kxm/src/vnext-runtime-supervisor.ts
|
|
23160
23248
|
import { spawn as spawn2 } from "node:child_process";
|
|
23161
23249
|
import { createHash as createHash11, createHmac, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
23162
|
-
import { chmodSync as chmodSync4, existsSync as
|
|
23163
|
-
import { dirname as
|
|
23164
|
-
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
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";
|
|
23165
23252
|
|
|
23166
23253
|
// plugins/kxm/src/vnext-runtime-store.ts
|
|
23167
23254
|
import { createHash as createHash9, randomUUID as randomUUID4 } from "node:crypto";
|
|
23168
|
-
import { existsSync as
|
|
23169
|
-
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";
|
|
23170
23257
|
|
|
23171
23258
|
// plugins/kxm/src/vnext-bindings.ts
|
|
23172
23259
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
@@ -23174,18 +23261,18 @@ import { createHash as createHash7, randomUUID as randomUUID3 } from "node:crypt
|
|
|
23174
23261
|
import {
|
|
23175
23262
|
chmodSync as chmodSync2,
|
|
23176
23263
|
closeSync,
|
|
23177
|
-
existsSync as
|
|
23264
|
+
existsSync as existsSync7,
|
|
23178
23265
|
fsyncSync,
|
|
23179
23266
|
lstatSync as lstatSync2,
|
|
23180
|
-
mkdirSync as
|
|
23267
|
+
mkdirSync as mkdirSync4,
|
|
23181
23268
|
openSync,
|
|
23182
|
-
readFileSync as
|
|
23269
|
+
readFileSync as readFileSync6,
|
|
23183
23270
|
realpathSync as realpathSync2,
|
|
23184
|
-
renameSync,
|
|
23185
|
-
rmSync,
|
|
23186
|
-
writeFileSync as
|
|
23271
|
+
renameSync as renameSync2,
|
|
23272
|
+
rmSync as rmSync2,
|
|
23273
|
+
writeFileSync as writeFileSync4
|
|
23187
23274
|
} from "node:fs";
|
|
23188
|
-
import { homedir as
|
|
23275
|
+
import { homedir as homedir3 } from "node:os";
|
|
23189
23276
|
|
|
23190
23277
|
// plugins/kxm/src/sqlite.ts
|
|
23191
23278
|
import { createRequire } from "node:module";
|
|
@@ -23227,7 +23314,7 @@ var DatabaseSync = class {
|
|
|
23227
23314
|
};
|
|
23228
23315
|
|
|
23229
23316
|
// plugins/kxm/src/vnext-bindings.ts
|
|
23230
|
-
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";
|
|
23231
23318
|
var MAX_BINDING_RECORD_BYTES = 256 * 1024;
|
|
23232
23319
|
var BINDING_LABEL = "Runtime-local repository bindings";
|
|
23233
23320
|
var activeLocks = /* @__PURE__ */ new WeakSet();
|
|
@@ -23238,7 +23325,7 @@ function bindingError(phase, code, message) {
|
|
|
23238
23325
|
throw new VnextConfigError([bindingIssue(phase, code, message)]);
|
|
23239
23326
|
}
|
|
23240
23327
|
function canonicalHostPath2(path4) {
|
|
23241
|
-
const absolute =
|
|
23328
|
+
const absolute = resolve4(path4);
|
|
23242
23329
|
try {
|
|
23243
23330
|
return realpathSync2.native(absolute);
|
|
23244
23331
|
} catch {
|
|
@@ -23253,21 +23340,21 @@ function sameHostPath2(left, right, platform = process.platform) {
|
|
|
23253
23340
|
function vnextUserStateRoot(options = {}) {
|
|
23254
23341
|
const env = options.env ?? process.env;
|
|
23255
23342
|
const platform = options.platform ?? process.platform;
|
|
23256
|
-
const home = options.homeDir ??
|
|
23343
|
+
const home = options.homeDir ?? homedir3();
|
|
23257
23344
|
const explicit = options.stateRoot ?? env.KXM_STATE_HOME?.trim();
|
|
23258
23345
|
if (explicit) {
|
|
23259
|
-
if (!
|
|
23260
|
-
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);
|
|
23261
23348
|
}
|
|
23262
23349
|
if (platform === "win32") {
|
|
23263
23350
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
23264
|
-
const base2 = localAppData &&
|
|
23265
|
-
return
|
|
23351
|
+
const base2 = localAppData && isAbsolute3(localAppData) ? localAppData : join7(home, "AppData", "Local");
|
|
23352
|
+
return resolve4(base2, "KXM");
|
|
23266
23353
|
}
|
|
23267
|
-
if (platform === "darwin") return
|
|
23354
|
+
if (platform === "darwin") return resolve4(home, "Library", "Application Support", "KXM");
|
|
23268
23355
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
23269
|
-
const base = xdgState &&
|
|
23270
|
-
return
|
|
23356
|
+
const base = xdgState && isAbsolute3(xdgState) ? xdgState : join7(home, ".local", "state");
|
|
23357
|
+
return resolve4(base, "kxm");
|
|
23271
23358
|
}
|
|
23272
23359
|
function projectBindingKey(projectRoot, platform = process.platform) {
|
|
23273
23360
|
const canonical2 = canonicalHostPath2(projectRoot);
|
|
@@ -23276,10 +23363,10 @@ function projectBindingKey(projectRoot, platform = process.platform) {
|
|
|
23276
23363
|
}
|
|
23277
23364
|
function vnextLocalBindingFile(projectRoot, options = {}) {
|
|
23278
23365
|
const stateRoot = vnextUserStateRoot(options);
|
|
23279
|
-
return
|
|
23366
|
+
return join7(stateRoot, "projects", projectBindingKey(projectRoot, options.platform), "repository-bindings.json");
|
|
23280
23367
|
}
|
|
23281
23368
|
function checkedDirectory(path4, description) {
|
|
23282
|
-
if (!
|
|
23369
|
+
if (!existsSync7(path4)) return false;
|
|
23283
23370
|
const stat = lstatSync2(path4);
|
|
23284
23371
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23285
23372
|
bindingError("path", "local_binding_directory_invalid", `${description} must be a regular directory, not a link or file`);
|
|
@@ -23287,8 +23374,8 @@ function checkedDirectory(path4, description) {
|
|
|
23287
23374
|
return true;
|
|
23288
23375
|
}
|
|
23289
23376
|
function existingBindingDirectory(file, stateRoot) {
|
|
23290
|
-
const projects =
|
|
23291
|
-
const project =
|
|
23377
|
+
const projects = join7(stateRoot, "projects");
|
|
23378
|
+
const project = dirname5(file);
|
|
23292
23379
|
if (!checkedDirectory(stateRoot, "local state root")) return false;
|
|
23293
23380
|
if (!checkedDirectory(projects, "local projects directory")) return false;
|
|
23294
23381
|
return checkedDirectory(project, "local project binding directory");
|
|
@@ -23311,10 +23398,10 @@ function asRecord2(value, file, projectRoot, schemasDir) {
|
|
|
23311
23398
|
};
|
|
23312
23399
|
}
|
|
23313
23400
|
function readVnextLocalBindings(projectRoot, options = {}) {
|
|
23314
|
-
const root =
|
|
23401
|
+
const root = resolve4(projectRoot);
|
|
23315
23402
|
const stateRoot = vnextUserStateRoot(options);
|
|
23316
23403
|
const file = vnextLocalBindingFile(root, options);
|
|
23317
|
-
if (!existingBindingDirectory(file, stateRoot) || !
|
|
23404
|
+
if (!existingBindingDirectory(file, stateRoot) || !existsSync7(file)) return void 0;
|
|
23318
23405
|
const stat = lstatSync2(file);
|
|
23319
23406
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
23320
23407
|
bindingError("path", "local_binding_file_invalid", "binding record must be a regular file, not a link or directory");
|
|
@@ -23322,12 +23409,12 @@ function readVnextLocalBindings(projectRoot, options = {}) {
|
|
|
23322
23409
|
if (stat.size > MAX_BINDING_RECORD_BYTES) {
|
|
23323
23410
|
bindingError("parse", "local_binding_file_too_large", `binding record exceeds ${MAX_BINDING_RECORD_BYTES} bytes`);
|
|
23324
23411
|
}
|
|
23325
|
-
const parsed = parseRestrictedYaml2(
|
|
23412
|
+
const parsed = parseRestrictedYaml2(readFileSync6(file), BINDING_LABEL);
|
|
23326
23413
|
return asRecord2(parsed, file, root, options.schemasDir);
|
|
23327
23414
|
}
|
|
23328
23415
|
function normalizedRecord(projectRoot, projectId, repositories, schemasDir) {
|
|
23329
23416
|
const normalizedRepositories = Object.fromEntries(Object.entries(repositories).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([repositoryId, path4]) => {
|
|
23330
|
-
if (!
|
|
23417
|
+
if (!isAbsolute3(path4)) bindingError("path", "repository_binding_not_absolute", `host-local binding for ${repositoryId} must be absolute`);
|
|
23331
23418
|
return [repositoryId, canonicalHostPath2(path4)];
|
|
23332
23419
|
}));
|
|
23333
23420
|
const value = {
|
|
@@ -23362,48 +23449,48 @@ function syncDirectory(path4) {
|
|
|
23362
23449
|
}
|
|
23363
23450
|
}
|
|
23364
23451
|
function createDirectoryIfMissing(path4) {
|
|
23365
|
-
if (
|
|
23452
|
+
if (existsSync7(path4)) return;
|
|
23366
23453
|
try {
|
|
23367
|
-
|
|
23368
|
-
syncDirectory(
|
|
23454
|
+
mkdirSync4(path4, { mode: 448 });
|
|
23455
|
+
syncDirectory(dirname5(path4));
|
|
23369
23456
|
} catch (error) {
|
|
23370
23457
|
if (error.code !== "EEXIST") throw error;
|
|
23371
23458
|
}
|
|
23372
23459
|
}
|
|
23373
23460
|
function ensureDurableDirectory(path4, description) {
|
|
23374
23461
|
const missing = [];
|
|
23375
|
-
let current =
|
|
23376
|
-
while (!
|
|
23462
|
+
let current = resolve4(path4);
|
|
23463
|
+
while (!existsSync7(current)) {
|
|
23377
23464
|
missing.push(current);
|
|
23378
|
-
const parent =
|
|
23465
|
+
const parent = dirname5(current);
|
|
23379
23466
|
if (parent === current) bindingError("path", "local_binding_directory_invalid", `${description} has no existing filesystem ancestor`);
|
|
23380
23467
|
current = parent;
|
|
23381
23468
|
}
|
|
23382
23469
|
checkedDirectory(current, `${description} ancestor`);
|
|
23383
23470
|
for (const directory of missing.reverse()) {
|
|
23384
|
-
|
|
23471
|
+
mkdirSync4(directory, { mode: 448 });
|
|
23385
23472
|
checkedDirectory(directory, description);
|
|
23386
|
-
syncDirectory(
|
|
23473
|
+
syncDirectory(dirname5(directory));
|
|
23387
23474
|
}
|
|
23388
23475
|
}
|
|
23389
23476
|
function ensureBindingDirectory(file, stateRoot) {
|
|
23390
23477
|
ensureDurableDirectory(stateRoot, "local state root");
|
|
23391
23478
|
checkedDirectory(stateRoot, "local state root");
|
|
23392
23479
|
syncDirectory(stateRoot);
|
|
23393
|
-
const projects =
|
|
23480
|
+
const projects = join7(stateRoot, "projects");
|
|
23394
23481
|
createDirectoryIfMissing(projects);
|
|
23395
23482
|
checkedDirectory(projects, "local projects directory");
|
|
23396
|
-
const project =
|
|
23483
|
+
const project = dirname5(file);
|
|
23397
23484
|
createDirectoryIfMissing(project);
|
|
23398
23485
|
checkedDirectory(project, "local project binding directory");
|
|
23399
23486
|
}
|
|
23400
23487
|
function assertNoLinkedDirectoryComponents(path4, description) {
|
|
23401
|
-
const absolute =
|
|
23488
|
+
const absolute = resolve4(path4);
|
|
23402
23489
|
const filesystemRoot = parse(absolute).root;
|
|
23403
23490
|
let current = filesystemRoot;
|
|
23404
23491
|
const remainder = relative2(filesystemRoot, absolute);
|
|
23405
23492
|
for (const segment of remainder.split(sep2).filter(Boolean)) {
|
|
23406
|
-
current =
|
|
23493
|
+
current = join7(current, segment);
|
|
23407
23494
|
const stat = lstatSync2(current);
|
|
23408
23495
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23409
23496
|
bindingError("path", "project_operation_lock_parent_invalid", `${description} contains a linked or non-directory component`);
|
|
@@ -23424,28 +23511,28 @@ function projectOperationLockFile(projectRoot) {
|
|
|
23424
23511
|
if (result.status !== 0 || result.error || !result.stdout.trim()) {
|
|
23425
23512
|
bindingError("discovery", "project_operation_lock_unavailable", "cannot resolve the authoritative Git metadata path for project locking");
|
|
23426
23513
|
}
|
|
23427
|
-
const gitDirectory =
|
|
23514
|
+
const gitDirectory = resolve4(result.stdout.trim());
|
|
23428
23515
|
assertNoLinkedDirectoryComponents(gitDirectory, "authoritative Git metadata path");
|
|
23429
23516
|
const gitStat = lstatSync2(gitDirectory);
|
|
23430
23517
|
if (gitStat.isSymbolicLink() || !gitStat.isDirectory()) {
|
|
23431
23518
|
bindingError("path", "project_operation_lock_parent_invalid", "authoritative Git metadata must resolve to a regular directory");
|
|
23432
23519
|
}
|
|
23433
|
-
const lockDirectory =
|
|
23434
|
-
if (
|
|
23520
|
+
const lockDirectory = join7(gitDirectory, "kxm");
|
|
23521
|
+
if (existsSync7(lockDirectory)) {
|
|
23435
23522
|
const stat = lstatSync2(lockDirectory);
|
|
23436
23523
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23437
23524
|
bindingError("path", "project_operation_lock_parent_invalid", "Git-local KXM lock directory must be regular, not a link or file");
|
|
23438
23525
|
}
|
|
23439
23526
|
} else {
|
|
23440
|
-
|
|
23527
|
+
mkdirSync4(lockDirectory, { mode: 448 });
|
|
23441
23528
|
syncDirectory(gitDirectory);
|
|
23442
23529
|
}
|
|
23443
|
-
return
|
|
23530
|
+
return join7(lockDirectory, "project-operation-lock.sqlite");
|
|
23444
23531
|
}
|
|
23445
23532
|
function withVnextLocalBindingLock(projectRoot, options, callback) {
|
|
23446
|
-
const root =
|
|
23533
|
+
const root = resolve4(projectRoot);
|
|
23447
23534
|
const file = projectOperationLockFile(root);
|
|
23448
|
-
if (
|
|
23535
|
+
if (existsSync7(file)) {
|
|
23449
23536
|
const stat = lstatSync2(file);
|
|
23450
23537
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
23451
23538
|
bindingError("path", "local_binding_lock_invalid", "project-operation lock must be a regular file, not a link or directory");
|
|
@@ -23478,7 +23565,7 @@ function withVnextLocalBindingLock(projectRoot, options, callback) {
|
|
|
23478
23565
|
}
|
|
23479
23566
|
}
|
|
23480
23567
|
function planVnextLocalBindings(projectRoot, projectId, repositories, options = {}) {
|
|
23481
|
-
const root =
|
|
23568
|
+
const root = resolve4(projectRoot);
|
|
23482
23569
|
const file = vnextLocalBindingFile(root, options);
|
|
23483
23570
|
const record = normalizedRecord(root, projectId, repositories, options.schemasDir);
|
|
23484
23571
|
const existing = readVnextLocalBindings(root, options);
|
|
@@ -23488,7 +23575,7 @@ function planVnextLocalBindings(projectRoot, projectId, repositories, options =
|
|
|
23488
23575
|
return { file, written: !existing || !recordsEqual(existing, record), record };
|
|
23489
23576
|
}
|
|
23490
23577
|
function writeVnextLocalBindings(projectRoot, projectId, repositories, options = {}, lock) {
|
|
23491
|
-
const root =
|
|
23578
|
+
const root = resolve4(projectRoot);
|
|
23492
23579
|
if (!lock) {
|
|
23493
23580
|
return withVnextLocalBindingLock(root, options, (acquired) => writeVnextLocalBindings(root, projectId, repositories, options, acquired));
|
|
23494
23581
|
}
|
|
@@ -23499,20 +23586,20 @@ function writeVnextLocalBindings(projectRoot, projectId, repositories, options =
|
|
|
23499
23586
|
const { file, record } = planned;
|
|
23500
23587
|
if (!planned.written) return planned;
|
|
23501
23588
|
ensureBindingDirectory(file, vnextUserStateRoot(options));
|
|
23502
|
-
const temporary =
|
|
23589
|
+
const temporary = join7(dirname5(file), `.repository-bindings-${process.pid}-${randomUUID3()}.tmp`);
|
|
23503
23590
|
let descriptor;
|
|
23504
23591
|
try {
|
|
23505
23592
|
descriptor = openSync(temporary, "wx", 384);
|
|
23506
|
-
|
|
23593
|
+
writeFileSync4(descriptor, `${JSON.stringify(record, null, 2)}
|
|
23507
23594
|
`, "utf8");
|
|
23508
23595
|
fsyncSync(descriptor);
|
|
23509
23596
|
closeSync(descriptor);
|
|
23510
23597
|
descriptor = void 0;
|
|
23511
|
-
|
|
23512
|
-
syncDirectory(
|
|
23598
|
+
renameSync2(temporary, file);
|
|
23599
|
+
syncDirectory(dirname5(file));
|
|
23513
23600
|
} finally {
|
|
23514
23601
|
if (descriptor !== void 0) closeSync(descriptor);
|
|
23515
|
-
|
|
23602
|
+
rmSync2(temporary, { force: true });
|
|
23516
23603
|
}
|
|
23517
23604
|
const verified = readVnextLocalBindings(root, options);
|
|
23518
23605
|
if (!verified || !recordsEqual(verified, record)) {
|
|
@@ -23526,22 +23613,22 @@ import { createHash as createHash8, randomBytes } from "node:crypto";
|
|
|
23526
23613
|
import {
|
|
23527
23614
|
chmodSync as chmodSync3,
|
|
23528
23615
|
copyFileSync,
|
|
23529
|
-
existsSync as
|
|
23616
|
+
existsSync as existsSync8,
|
|
23530
23617
|
lstatSync as lstatSync3,
|
|
23531
|
-
mkdirSync as
|
|
23618
|
+
mkdirSync as mkdirSync5,
|
|
23532
23619
|
readdirSync as readdirSync2,
|
|
23533
|
-
readFileSync as
|
|
23620
|
+
readFileSync as readFileSync7,
|
|
23534
23621
|
unlinkSync as unlinkSync2,
|
|
23535
|
-
writeFileSync as
|
|
23622
|
+
writeFileSync as writeFileSync5
|
|
23536
23623
|
} from "node:fs";
|
|
23537
|
-
import { basename as basename3, dirname as
|
|
23624
|
+
import { basename as basename3, dirname as dirname6, join as join8, resolve as resolve5 } from "node:path";
|
|
23538
23625
|
function databaseError(code, file, message) {
|
|
23539
23626
|
const issue3 = { phase: "semantic", code, file, message };
|
|
23540
23627
|
return new VnextConfigError([issue3]);
|
|
23541
23628
|
}
|
|
23542
23629
|
function checkedParent(path4, description) {
|
|
23543
|
-
const parent =
|
|
23544
|
-
if (!
|
|
23630
|
+
const parent = dirname6(path4);
|
|
23631
|
+
if (!existsSync8(parent)) mkdirSync5(parent, { recursive: true, mode: 448 });
|
|
23545
23632
|
const stat = lstatSync3(parent, { throwIfNoEntry: false });
|
|
23546
23633
|
if (!stat || stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23547
23634
|
throw databaseError("runtime_path_invalid", description, `${description} parent must be a regular directory, not a link`);
|
|
@@ -23683,18 +23770,18 @@ function checkIntegrity(database) {
|
|
|
23683
23770
|
return rows.length === 1 && rows[0]?.integrity_check === "ok";
|
|
23684
23771
|
}
|
|
23685
23772
|
function fileSha256(filePath) {
|
|
23686
|
-
const bytes =
|
|
23773
|
+
const bytes = readFileSync7(filePath);
|
|
23687
23774
|
return `sha256:${createHash8("sha256").update(bytes).digest("hex")}`;
|
|
23688
23775
|
}
|
|
23689
23776
|
function backupDatabaseFile(sourcePath, targetPath, storeId) {
|
|
23690
|
-
const resolvedSource =
|
|
23691
|
-
const resolvedTarget =
|
|
23777
|
+
const resolvedSource = resolve5(sourcePath);
|
|
23778
|
+
const resolvedTarget = resolve5(targetPath);
|
|
23692
23779
|
const sourceStat = lstatSync3(resolvedSource, { throwIfNoEntry: false });
|
|
23693
23780
|
if (!sourceStat || !sourceStat.isFile() || sourceStat.isSymbolicLink()) {
|
|
23694
23781
|
throw databaseError("runtime_path_invalid", resolvedSource, `source database ${resolvedSource} must be a regular file, not a link or directory`);
|
|
23695
23782
|
}
|
|
23696
23783
|
checkedParent(resolvedTarget, "backup target");
|
|
23697
|
-
if (
|
|
23784
|
+
if (existsSync8(resolvedTarget)) {
|
|
23698
23785
|
unlinkSync2(resolvedTarget);
|
|
23699
23786
|
}
|
|
23700
23787
|
const sourceDb = new DatabaseSync(resolvedSource);
|
|
@@ -23738,8 +23825,8 @@ function backupDatabaseFile(sourcePath, targetPath, storeId) {
|
|
|
23738
23825
|
};
|
|
23739
23826
|
}
|
|
23740
23827
|
function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVersion, maxSupportedVersion) {
|
|
23741
|
-
const resolvedBackup =
|
|
23742
|
-
const resolvedTarget =
|
|
23828
|
+
const resolvedBackup = resolve5(backupPath);
|
|
23829
|
+
const resolvedTarget = resolve5(targetPath);
|
|
23743
23830
|
const backupStat = lstatSync3(resolvedBackup, { throwIfNoEntry: false });
|
|
23744
23831
|
if (!backupStat || !backupStat.isFile() || backupStat.isSymbolicLink()) {
|
|
23745
23832
|
throw databaseError("runtime_path_invalid", resolvedBackup, `backup database ${resolvedBackup} must be a regular file, not a link or directory`);
|
|
@@ -23772,7 +23859,7 @@ function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVers
|
|
|
23772
23859
|
}
|
|
23773
23860
|
checkedParent(resolvedTarget, "restore target");
|
|
23774
23861
|
for (const file of [resolvedTarget, `${resolvedTarget}-wal`, `${resolvedTarget}-shm`]) {
|
|
23775
|
-
if (
|
|
23862
|
+
if (existsSync8(file)) {
|
|
23776
23863
|
try {
|
|
23777
23864
|
unlinkSync2(file);
|
|
23778
23865
|
} catch {
|
|
@@ -23802,29 +23889,29 @@ function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVers
|
|
|
23802
23889
|
};
|
|
23803
23890
|
}
|
|
23804
23891
|
function discoverProjectStores(projectRoot, options = {}) {
|
|
23805
|
-
const root =
|
|
23892
|
+
const root = resolve5(projectRoot);
|
|
23806
23893
|
const stores = [];
|
|
23807
|
-
const hubPath = options.hubDataPath ?
|
|
23808
|
-
if (
|
|
23894
|
+
const hubPath = options.hubDataPath ? resolve5(options.hubDataPath) : join8(root, ".kxm", "state", "kxm.db");
|
|
23895
|
+
if (existsSync8(hubPath)) {
|
|
23809
23896
|
stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: 3 });
|
|
23810
23897
|
}
|
|
23811
|
-
const registryPath =
|
|
23812
|
-
if (
|
|
23898
|
+
const registryPath = join8(root, ".kxm", "runtime", "registry.db");
|
|
23899
|
+
if (existsSync8(registryPath)) {
|
|
23813
23900
|
stores.push({ storeId: "registry", sourcePath: registryPath, maxSupportedVersion: 1 });
|
|
23814
23901
|
}
|
|
23815
|
-
const bindingsPath =
|
|
23816
|
-
if (
|
|
23902
|
+
const bindingsPath = join8(root, ".kxm", "runtime", "bindings.db");
|
|
23903
|
+
if (existsSync8(bindingsPath)) {
|
|
23817
23904
|
stores.push({ storeId: "binding-store", sourcePath: bindingsPath, maxSupportedVersion: 1 });
|
|
23818
23905
|
}
|
|
23819
|
-
const eventsDir =
|
|
23820
|
-
if (
|
|
23906
|
+
const eventsDir = join8(root, ".kxm", "runtime", "events");
|
|
23907
|
+
if (existsSync8(eventsDir)) {
|
|
23821
23908
|
const entries = readdirSync2(eventsDir, { withFileTypes: true });
|
|
23822
23909
|
for (const entry of entries) {
|
|
23823
23910
|
if (entry.isFile() && entry.name.endsWith(".db")) {
|
|
23824
23911
|
const key = entry.name.replace(/\.db$/, "");
|
|
23825
23912
|
stores.push({
|
|
23826
23913
|
storeId: `events:${key}`,
|
|
23827
|
-
sourcePath:
|
|
23914
|
+
sourcePath: join8(eventsDir, entry.name),
|
|
23828
23915
|
maxSupportedVersion: 3
|
|
23829
23916
|
});
|
|
23830
23917
|
}
|
|
@@ -23833,7 +23920,7 @@ function discoverProjectStores(projectRoot, options = {}) {
|
|
|
23833
23920
|
return stores;
|
|
23834
23921
|
}
|
|
23835
23922
|
function createBackup(options = {}) {
|
|
23836
|
-
const projectRoot = options.projectRoot ?
|
|
23923
|
+
const projectRoot = options.projectRoot ? resolve5(options.projectRoot) : process.cwd();
|
|
23837
23924
|
const stores = discoverProjectStores(projectRoot, {
|
|
23838
23925
|
...options.hubDataPath !== void 0 ? { hubDataPath: options.hubDataPath } : {}
|
|
23839
23926
|
});
|
|
@@ -23843,9 +23930,9 @@ function createBackup(options = {}) {
|
|
|
23843
23930
|
const now = /* @__PURE__ */ new Date();
|
|
23844
23931
|
const timestamp = now.toISOString().replace(/[:.]/g, "-");
|
|
23845
23932
|
const backupId = `bk_${randomBytes(8).toString("hex")}`;
|
|
23846
|
-
const outDir = options.outDir ?
|
|
23847
|
-
if (!
|
|
23848
|
-
|
|
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 });
|
|
23849
23936
|
}
|
|
23850
23937
|
const backedUpStores = [];
|
|
23851
23938
|
const usedFilenames = /* @__PURE__ */ new Set();
|
|
@@ -23856,7 +23943,7 @@ function createBackup(options = {}) {
|
|
|
23856
23943
|
filename = `${sanitizedId}-${filename}`;
|
|
23857
23944
|
}
|
|
23858
23945
|
usedFilenames.add(filename);
|
|
23859
|
-
const targetFile2 =
|
|
23946
|
+
const targetFile2 = join8(outDir, filename);
|
|
23860
23947
|
const record = backupDatabaseFile(store.sourcePath, targetFile2, store.storeId);
|
|
23861
23948
|
backedUpStores.push(record);
|
|
23862
23949
|
}
|
|
@@ -23871,24 +23958,24 @@ function createBackup(options = {}) {
|
|
|
23871
23958
|
const manifestSha256 = `sha256:${createHash8("sha256").update(manifestJson, "utf8").digest("hex")}`;
|
|
23872
23959
|
manifest.manifestSha256 = manifestSha256;
|
|
23873
23960
|
const finalJson = JSON.stringify(manifest, null, 2) + "\n";
|
|
23874
|
-
const manifestPath =
|
|
23875
|
-
|
|
23961
|
+
const manifestPath = join8(outDir, "manifest.json");
|
|
23962
|
+
writeFileSync5(manifestPath, finalJson, "utf8");
|
|
23876
23963
|
return { manifest, outDir };
|
|
23877
23964
|
}
|
|
23878
23965
|
function restoreBackup(manifestPathOrDir, options = {}) {
|
|
23879
|
-
let manifestPath =
|
|
23966
|
+
let manifestPath = resolve5(manifestPathOrDir);
|
|
23880
23967
|
const stat = lstatSync3(manifestPath, { throwIfNoEntry: false });
|
|
23881
23968
|
if (!stat) {
|
|
23882
23969
|
throw databaseError("runtime_path_invalid", manifestPath, `manifest path ${manifestPath} does not exist`);
|
|
23883
23970
|
}
|
|
23884
23971
|
if (stat.isDirectory()) {
|
|
23885
|
-
manifestPath =
|
|
23972
|
+
manifestPath = join8(manifestPath, "manifest.json");
|
|
23886
23973
|
}
|
|
23887
|
-
if (!
|
|
23974
|
+
if (!existsSync8(manifestPath)) {
|
|
23888
23975
|
throw databaseError("runtime_path_invalid", manifestPath, `backup manifest ${manifestPath} not found`);
|
|
23889
23976
|
}
|
|
23890
|
-
const manifestDir =
|
|
23891
|
-
const rawText =
|
|
23977
|
+
const manifestDir = dirname6(manifestPath);
|
|
23978
|
+
const rawText = readFileSync7(manifestPath, "utf8");
|
|
23892
23979
|
let manifest;
|
|
23893
23980
|
try {
|
|
23894
23981
|
manifest = JSON.parse(rawText);
|
|
@@ -23900,8 +23987,8 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23900
23987
|
}
|
|
23901
23988
|
const restoredStores = [];
|
|
23902
23989
|
for (const store of manifest.stores) {
|
|
23903
|
-
const backupFilePath =
|
|
23904
|
-
if (!
|
|
23990
|
+
const backupFilePath = join8(manifestDir, store.backupFile);
|
|
23991
|
+
if (!existsSync8(backupFilePath)) {
|
|
23905
23992
|
throw databaseError("restore_file_missing", backupFilePath, `backup file ${store.backupFile} missing from ${manifestDir}`);
|
|
23906
23993
|
}
|
|
23907
23994
|
const actualSha256 = fileSha256(backupFilePath);
|
|
@@ -23919,7 +24006,7 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23919
24006
|
let targetPath = store.sourcePath;
|
|
23920
24007
|
if (options.projectRoot && manifest.projectRoot && targetPath.startsWith(manifest.projectRoot)) {
|
|
23921
24008
|
const rel = targetPath.slice(manifest.projectRoot.length).replace(/^[\\/]+/, "");
|
|
23922
|
-
targetPath =
|
|
24009
|
+
targetPath = join8(resolve5(options.projectRoot), rel);
|
|
23923
24010
|
}
|
|
23924
24011
|
const result = restoreDatabaseFile(
|
|
23925
24012
|
backupFilePath,
|
|
@@ -23939,13 +24026,13 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23939
24026
|
|
|
23940
24027
|
// plugins/kxm/src/vnext-runtime-store.ts
|
|
23941
24028
|
function vnextRuntimePaths(options = {}) {
|
|
23942
|
-
const stateRoot = options.stateRoot ?
|
|
23943
|
-
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");
|
|
23944
24031
|
return {
|
|
23945
24032
|
stateRoot,
|
|
23946
24033
|
runtimeDir,
|
|
23947
|
-
registryDb:
|
|
23948
|
-
projectsDir:
|
|
24034
|
+
registryDb: join9(runtimeDir, "registry.db"),
|
|
24035
|
+
projectsDir: join9(runtimeDir, "projects")
|
|
23949
24036
|
};
|
|
23950
24037
|
}
|
|
23951
24038
|
function runtimeIssue(phase, code, file, message) {
|
|
@@ -23957,9 +24044,9 @@ function runtimeError(code, file, message) {
|
|
|
23957
24044
|
function projectRuntimeKey(projectRoot) {
|
|
23958
24045
|
let canonical2;
|
|
23959
24046
|
try {
|
|
23960
|
-
canonical2 = realpathSync3.native(
|
|
24047
|
+
canonical2 = realpathSync3.native(resolve6(projectRoot));
|
|
23961
24048
|
} catch {
|
|
23962
|
-
canonical2 =
|
|
24049
|
+
canonical2 = resolve6(projectRoot);
|
|
23963
24050
|
}
|
|
23964
24051
|
const folded = process.platform === "win32" ? canonical2.toLocaleLowerCase("en-US") : canonical2;
|
|
23965
24052
|
return createHash9("sha256").update(folded, "utf8").digest("hex").slice(0, 24);
|
|
@@ -23993,7 +24080,7 @@ var VnextRuntimeRegistry = class {
|
|
|
23993
24080
|
path;
|
|
23994
24081
|
database;
|
|
23995
24082
|
constructor(path4) {
|
|
23996
|
-
this.path =
|
|
24083
|
+
this.path = resolve6(path4);
|
|
23997
24084
|
this.database = openDatabase(this.path, "runtime registry", {
|
|
23998
24085
|
schema: REGISTRY_SCHEMA,
|
|
23999
24086
|
version: VNEXT_REGISTRY_SCHEMA_VERSION,
|
|
@@ -24083,7 +24170,7 @@ var VnextRuntimeRegistry = class {
|
|
|
24083
24170
|
}
|
|
24084
24171
|
/** Register or revalidate a project's home binding. Home Runtime is immutable. */
|
|
24085
24172
|
registerProject(registration) {
|
|
24086
|
-
const projectRoot =
|
|
24173
|
+
const projectRoot = resolve6(registration.projectRoot);
|
|
24087
24174
|
const projectKey = projectRuntimeKey(projectRoot);
|
|
24088
24175
|
this.database.exec("BEGIN IMMEDIATE");
|
|
24089
24176
|
try {
|
|
@@ -24304,7 +24391,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
24304
24391
|
const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
|
|
24305
24392
|
const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
|
|
24306
24393
|
const assignments = compileAssignments(step, id, agent, sink);
|
|
24307
|
-
const
|
|
24394
|
+
const join50 = compileJoin(step, id, sink);
|
|
24308
24395
|
const requiredEvidence = compileEvidence(step, id, sink);
|
|
24309
24396
|
const transitions = compileTransitions(step, id, index, stepIndex, sink);
|
|
24310
24397
|
const outcomes = Object.keys(transitions).sort(compareCodeUnits4);
|
|
@@ -24332,7 +24419,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
24332
24419
|
transitions: orderedTransitions,
|
|
24333
24420
|
requiresPlanHash: requirePlanHash.includes(id),
|
|
24334
24421
|
assignments,
|
|
24335
|
-
join:
|
|
24422
|
+
join: join50
|
|
24336
24423
|
};
|
|
24337
24424
|
if (kind === "agent" || kind === "moa") {
|
|
24338
24425
|
if (!agent) return void 0;
|
|
@@ -24382,15 +24469,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
|
|
|
24382
24469
|
};
|
|
24383
24470
|
}
|
|
24384
24471
|
function compileJoin(step, stepId, sink) {
|
|
24385
|
-
const
|
|
24386
|
-
if (!
|
|
24387
|
-
const declared = stringValue2(
|
|
24472
|
+
const join50 = objectValue2(step.join);
|
|
24473
|
+
if (!join50) return { strategy: "all" };
|
|
24474
|
+
const declared = stringValue2(join50.strategy);
|
|
24388
24475
|
const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
|
|
24389
|
-
const minimumPassed = compileOptionalCount(
|
|
24476
|
+
const minimumPassed = compileOptionalCount(join50.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
|
|
24390
24477
|
const compiled = {
|
|
24391
24478
|
strategy,
|
|
24392
24479
|
...minimumPassed !== void 0 ? { minimumPassed } : {},
|
|
24393
|
-
...typeof
|
|
24480
|
+
...typeof join50.cancelRemaining === "boolean" ? { cancelRemaining: join50.cancelRemaining } : {}
|
|
24394
24481
|
};
|
|
24395
24482
|
return compiled;
|
|
24396
24483
|
}
|
|
@@ -24670,8 +24757,8 @@ var RECORD_LIMIT = 16 * 1024 * 1024;
|
|
|
24670
24757
|
// plugins/kxm/src/prices.ts
|
|
24671
24758
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
24672
24759
|
import { createHash as createHash10 } from "node:crypto";
|
|
24673
|
-
import { existsSync as
|
|
24674
|
-
import { join as
|
|
24760
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9, statSync } from "node:fs";
|
|
24761
|
+
import { join as join10 } from "node:path";
|
|
24675
24762
|
|
|
24676
24763
|
// plugins/kxm/src/price-calc.ts
|
|
24677
24764
|
var PRICES_SCHEMA = "kxm.prices.v1";
|
|
@@ -24823,11 +24910,11 @@ function parsePriceCatalog(text) {
|
|
|
24823
24910
|
return catalog;
|
|
24824
24911
|
}
|
|
24825
24912
|
function loadPriceCatalog(rootOrPath) {
|
|
24826
|
-
const candidatePath =
|
|
24827
|
-
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)) {
|
|
24828
24915
|
return void 0;
|
|
24829
24916
|
}
|
|
24830
|
-
const content =
|
|
24917
|
+
const content = readFileSync9(candidatePath, "utf8");
|
|
24831
24918
|
return parsePriceCatalog(content);
|
|
24832
24919
|
}
|
|
24833
24920
|
function loadPriceCatalogForEstimate(options) {
|
|
@@ -24848,13 +24935,13 @@ var import_yaml5 = __toESM(require_dist(), 1);
|
|
|
24848
24935
|
|
|
24849
24936
|
// plugins/kxm/src/producers.ts
|
|
24850
24937
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
24851
|
-
import { existsSync as
|
|
24852
|
-
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";
|
|
24853
24940
|
var empty = () => ({ schema: "kxm.producers.v1", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), promoted: [], demoted: [], enabled: [], disabled: [], roles: {} });
|
|
24854
24941
|
function loadProducerPolicy(root) {
|
|
24855
|
-
const path4 =
|
|
24856
|
-
if (!
|
|
24857
|
-
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"));
|
|
24858
24945
|
if (value?.schema !== "kxm.producers.v1" || !Array.isArray(value.promoted) || !Array.isArray(value.demoted)) throw new Error("invalid .kxm/producers.yaml");
|
|
24859
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")])) : {} };
|
|
24860
24947
|
}
|
|
@@ -24864,8 +24951,8 @@ function updateProducer(root, model, status) {
|
|
|
24864
24951
|
policy.demoted = policy.demoted.filter((x2) => x2 !== model);
|
|
24865
24952
|
policy[status].push(model);
|
|
24866
24953
|
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24867
|
-
|
|
24868
|
-
|
|
24954
|
+
mkdirSync7(join11(root, ".kxm"), { recursive: true });
|
|
24955
|
+
writeFileSync7(join11(root, ".kxm", "producers.yaml"), (0, import_yaml4.stringify)(policy), "utf8");
|
|
24869
24956
|
return policy;
|
|
24870
24957
|
}
|
|
24871
24958
|
function setModelState(root, model, state, role, removeRole2 = false) {
|
|
@@ -24875,10 +24962,10 @@ function setModelState(root, model, state, role, removeRole2 = false) {
|
|
|
24875
24962
|
policy[state].push(model);
|
|
24876
24963
|
if (role) {
|
|
24877
24964
|
if (!/^[a-z][a-z0-9_-]{0,63}$/i.test(role)) throw new Error("invalid role id");
|
|
24878
|
-
const rolePath =
|
|
24965
|
+
const rolePath = join11(root, ".kxm", "roles", `${role}.yaml`);
|
|
24879
24966
|
let roleFile = {};
|
|
24880
|
-
if (
|
|
24881
|
-
const parsed = (0, import_yaml4.parse)(
|
|
24967
|
+
if (existsSync11(rolePath)) {
|
|
24968
|
+
const parsed = (0, import_yaml4.parse)(readFileSync10(rolePath, "utf8"));
|
|
24882
24969
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) roleFile = parsed;
|
|
24883
24970
|
}
|
|
24884
24971
|
const roster = Array.isArray(roleFile.roster) ? roleFile.roster.filter((entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)) : [];
|
|
@@ -24889,42 +24976,42 @@ function setModelState(root, model, state, role, removeRole2 = false) {
|
|
|
24889
24976
|
roleFile.schema ??= "kxm.role.v1";
|
|
24890
24977
|
roleFile.id ??= role;
|
|
24891
24978
|
roleFile.roster = roster;
|
|
24892
|
-
|
|
24893
|
-
|
|
24979
|
+
mkdirSync7(join11(root, ".kxm", "roles"), { recursive: true });
|
|
24980
|
+
writeFileSync7(rolePath, (0, import_yaml4.stringify)(roleFile), "utf8");
|
|
24894
24981
|
}
|
|
24895
24982
|
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24896
|
-
|
|
24897
|
-
|
|
24983
|
+
mkdirSync7(join11(root, ".kxm"), { recursive: true });
|
|
24984
|
+
writeFileSync7(join11(root, ".kxm", "producers.yaml"), (0, import_yaml4.stringify)(policy), "utf8");
|
|
24898
24985
|
return policy;
|
|
24899
24986
|
}
|
|
24900
24987
|
function listRoleBindings(root) {
|
|
24901
|
-
const dir =
|
|
24988
|
+
const dir = join11(root, ".kxm", "roles");
|
|
24902
24989
|
const result = {};
|
|
24903
|
-
if (!
|
|
24990
|
+
if (!existsSync11(dir)) return result;
|
|
24904
24991
|
for (const file of readdirSync3(dir).filter((name) => name.endsWith(".yaml"))) {
|
|
24905
24992
|
const role = file.slice(0, -5);
|
|
24906
|
-
const value = (0, import_yaml4.parse)(
|
|
24993
|
+
const value = (0, import_yaml4.parse)(readFileSync10(join11(dir, file), "utf8"));
|
|
24907
24994
|
result[role] = (value.roster ?? []).map((entry) => entry.model).filter((model) => typeof model === "string");
|
|
24908
24995
|
}
|
|
24909
24996
|
return result;
|
|
24910
24997
|
}
|
|
24911
24998
|
function listInventoryModels(root) {
|
|
24912
|
-
const path4 =
|
|
24913
|
-
if (!
|
|
24914
|
-
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"));
|
|
24915
25002
|
return (value.models ?? []).map((m2) => m2.id).filter((id) => typeof id === "string");
|
|
24916
25003
|
}
|
|
24917
25004
|
|
|
24918
25005
|
// plugins/kxm/src/artifacts-exist.ts
|
|
24919
25006
|
import { lstatSync as lstatSync5, realpathSync as realpathSync4, statSync as statSync2 } from "node:fs";
|
|
24920
|
-
import { isAbsolute as
|
|
25007
|
+
import { isAbsolute as isAbsolute4, relative as relative3, resolve as resolve7 } from "node:path";
|
|
24921
25008
|
function staysUnder(root, candidate) {
|
|
24922
25009
|
const child = relative3(root, candidate);
|
|
24923
|
-
return child === "" || !
|
|
25010
|
+
return child === "" || !isAbsolute4(child) && child !== ".." && !child.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`);
|
|
24924
25011
|
}
|
|
24925
25012
|
function verifyArtifactExists(rootInput, pathInput) {
|
|
24926
|
-
const lexicalRoot =
|
|
24927
|
-
const lexicalPath =
|
|
25013
|
+
const lexicalRoot = resolve7(rootInput);
|
|
25014
|
+
const lexicalPath = resolve7(pathInput);
|
|
24928
25015
|
if (!staysUnder(lexicalRoot, lexicalPath)) {
|
|
24929
25016
|
return { ok: false, error: "artifact_outside_workspace_assets", path: lexicalPath };
|
|
24930
25017
|
}
|
|
@@ -25543,9 +25630,8 @@ function formatRoutingReport(report2, options = {}) {
|
|
|
25543
25630
|
}
|
|
25544
25631
|
|
|
25545
25632
|
// plugins/kxm/src/vnext-runtime-supervisor.ts
|
|
25546
|
-
var repoRoot = resolve7(fileURLToPath2(new URL("../../../", import.meta.url)));
|
|
25547
25633
|
function vnextSupervisorTokenFile(paths) {
|
|
25548
|
-
return
|
|
25634
|
+
return join12(paths.runtimeDir, "supervisor.token");
|
|
25549
25635
|
}
|
|
25550
25636
|
function readVnextSupervisorToken(paths) {
|
|
25551
25637
|
const file = vnextSupervisorTokenFile(paths);
|
|
@@ -25554,7 +25640,7 @@ function readVnextSupervisorToken(paths) {
|
|
|
25554
25640
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
25555
25641
|
throw runtimeError("runtime_path_invalid", file, "supervisor token file must be a regular file, not a link");
|
|
25556
25642
|
}
|
|
25557
|
-
const token =
|
|
25643
|
+
const token = readFileSync11(file, "utf8").trim();
|
|
25558
25644
|
return token.length >= 32 ? token : void 0;
|
|
25559
25645
|
}
|
|
25560
25646
|
function processAlive(pid) {
|
|
@@ -25568,11 +25654,11 @@ function processAlive(pid) {
|
|
|
25568
25654
|
var HEARTBEAT_STALE_MS = 15e3;
|
|
25569
25655
|
var SUPERVISOR_ERROR_MAX_AGE_MS = 3e4;
|
|
25570
25656
|
function supervisorErrorFile(paths) {
|
|
25571
|
-
return
|
|
25657
|
+
return join12(paths.runtimeDir, "supervisor.error");
|
|
25572
25658
|
}
|
|
25573
25659
|
function clearSupervisorError(paths) {
|
|
25574
25660
|
const file = supervisorErrorFile(paths);
|
|
25575
|
-
if (
|
|
25661
|
+
if (existsSync12(file)) rmSync3(file, { force: true });
|
|
25576
25662
|
}
|
|
25577
25663
|
function readRecentSupervisorError(paths) {
|
|
25578
25664
|
const file = supervisorErrorFile(paths);
|
|
@@ -25581,13 +25667,13 @@ function readRecentSupervisorError(paths) {
|
|
|
25581
25667
|
const ageMs = Date.now() - stat.mtimeMs;
|
|
25582
25668
|
if (ageMs > SUPERVISOR_ERROR_MAX_AGE_MS) return void 0;
|
|
25583
25669
|
try {
|
|
25584
|
-
return
|
|
25670
|
+
return readFileSync11(file, "utf8").trim();
|
|
25585
25671
|
} catch {
|
|
25586
25672
|
return void 0;
|
|
25587
25673
|
}
|
|
25588
25674
|
}
|
|
25589
25675
|
function vnextSupervisorStatus(paths) {
|
|
25590
|
-
if (!
|
|
25676
|
+
if (!existsSync12(paths.registryDb)) return { running: false };
|
|
25591
25677
|
const registry = new VnextRuntimeRegistry(paths.registryDb);
|
|
25592
25678
|
try {
|
|
25593
25679
|
const record = registry.supervisor();
|
|
@@ -25648,7 +25734,7 @@ async function ensureVnextSupervisor(options = {}) {
|
|
|
25648
25734
|
throw runtimeError("runtime_supervisor_unreachable", paths.registryDb, `runtime supervisor pid ${status.pid} is registered as running but cannot be probed`);
|
|
25649
25735
|
}
|
|
25650
25736
|
clearSupervisorError(paths);
|
|
25651
|
-
const scriptPath =
|
|
25737
|
+
const scriptPath = join12(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
|
|
25652
25738
|
const spawnImpl = options.spawnImpl ?? ((script, env) => {
|
|
25653
25739
|
const child = spawn2(process.execPath, [script], {
|
|
25654
25740
|
detached: true,
|
|
@@ -25701,8 +25787,7 @@ async function vnextRuntimeRequest(handle, method, path4, body) {
|
|
|
25701
25787
|
|
|
25702
25788
|
// plugins/kxm/src/cli/types.ts
|
|
25703
25789
|
import { spawn as spawn3 } from "node:child_process";
|
|
25704
|
-
import { join as
|
|
25705
|
-
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
25790
|
+
import { join as join15, resolve as resolve9 } from "node:path";
|
|
25706
25791
|
|
|
25707
25792
|
// plugins/kxm/src/redact.ts
|
|
25708
25793
|
var SECRET_PATTERNS = [
|
|
@@ -25732,8 +25817,8 @@ function redactStringList(values, maxItems = 32) {
|
|
|
25732
25817
|
}
|
|
25733
25818
|
|
|
25734
25819
|
// plugins/kxm/src/telemetry.ts
|
|
25735
|
-
import { appendFileSync, mkdirSync as
|
|
25736
|
-
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";
|
|
25737
25822
|
var TELEMETRY_SCHEMA = "kxm.telemetry.v1";
|
|
25738
25823
|
function inferImprovementTarget(input) {
|
|
25739
25824
|
const explicit = input.env?.KXM_IMPROVE_TARGET?.trim();
|
|
@@ -25743,12 +25828,12 @@ function inferImprovementTarget(input) {
|
|
|
25743
25828
|
return project || workflowId ? "project" : "cli";
|
|
25744
25829
|
}
|
|
25745
25830
|
function appendTelemetry(path4, event) {
|
|
25746
|
-
|
|
25831
|
+
mkdirSync9(dirname9(path4), { recursive: true });
|
|
25747
25832
|
appendFileSync(path4, `${JSON.stringify(event)}
|
|
25748
25833
|
`, { encoding: "utf8", mode: 384 });
|
|
25749
25834
|
}
|
|
25750
25835
|
function telemetryPath(logsDir) {
|
|
25751
|
-
return
|
|
25836
|
+
return join13(logsDir, "telemetry.jsonl");
|
|
25752
25837
|
}
|
|
25753
25838
|
function makeTelemetryEvent(input) {
|
|
25754
25839
|
return {
|
|
@@ -25763,7 +25848,7 @@ function makeTelemetryEvent(input) {
|
|
|
25763
25848
|
function readRoutingRecords(path4) {
|
|
25764
25849
|
const records = [];
|
|
25765
25850
|
try {
|
|
25766
|
-
const raw =
|
|
25851
|
+
const raw = readFileSync12(path4, "utf8");
|
|
25767
25852
|
for (const line of raw.split(/\r?\n/)) {
|
|
25768
25853
|
if (!line.trim()) continue;
|
|
25769
25854
|
try {
|
|
@@ -25840,9 +25925,9 @@ function workerResult(worker, payload) {
|
|
|
25840
25925
|
}
|
|
25841
25926
|
|
|
25842
25927
|
// plugins/kxm/src/hub-binding.ts
|
|
25843
|
-
import { existsSync as
|
|
25844
|
-
import { homedir as
|
|
25845
|
-
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";
|
|
25846
25931
|
var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
25847
25932
|
var HUB_HEALTH_PROBE_MS = 300;
|
|
25848
25933
|
var HubBindingError = class extends Error {
|
|
@@ -25851,24 +25936,24 @@ var HubBindingError = class extends Error {
|
|
|
25851
25936
|
this.name = "HubBindingError";
|
|
25852
25937
|
}
|
|
25853
25938
|
};
|
|
25854
|
-
function
|
|
25939
|
+
function resolveUserStateRoot2(env) {
|
|
25855
25940
|
const explicit = env.KXM_STATE_HOME?.trim();
|
|
25856
25941
|
if (explicit) {
|
|
25857
|
-
if (!
|
|
25942
|
+
if (!isAbsolute6(explicit)) throw new HubBindingError("local_state_root_not_absolute");
|
|
25858
25943
|
return resolve8(explicit);
|
|
25859
25944
|
}
|
|
25860
25945
|
if (process.platform === "win32") {
|
|
25861
25946
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
25862
|
-
const base2 = localAppData &&
|
|
25947
|
+
const base2 = localAppData && isAbsolute6(localAppData) ? localAppData : join14(homedir4(), "AppData", "Local");
|
|
25863
25948
|
return resolve8(base2, "KXM");
|
|
25864
25949
|
}
|
|
25865
|
-
if (process.platform === "darwin") return resolve8(
|
|
25950
|
+
if (process.platform === "darwin") return resolve8(homedir4(), "Library", "Application Support", "KXM");
|
|
25866
25951
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
25867
|
-
const base = xdgState &&
|
|
25952
|
+
const base = xdgState && isAbsolute6(xdgState) ? xdgState : join14(homedir4(), ".local", "state");
|
|
25868
25953
|
return resolve8(base, "kxm");
|
|
25869
25954
|
}
|
|
25870
25955
|
function hubBindingFile(env = process.env) {
|
|
25871
|
-
return
|
|
25956
|
+
return join14(resolveUserStateRoot2(env), "hub-binding.json");
|
|
25872
25957
|
}
|
|
25873
25958
|
function validateHubUrl(raw) {
|
|
25874
25959
|
let parsed;
|
|
@@ -25893,10 +25978,10 @@ function isAbortError(error) {
|
|
|
25893
25978
|
}
|
|
25894
25979
|
function readHubBinding(env = process.env) {
|
|
25895
25980
|
const file = hubBindingFile(env);
|
|
25896
|
-
if (!
|
|
25981
|
+
if (!existsSync13(file)) return void 0;
|
|
25897
25982
|
let parsed;
|
|
25898
25983
|
try {
|
|
25899
|
-
parsed = JSON.parse(
|
|
25984
|
+
parsed = JSON.parse(readFileSync13(file, "utf8"));
|
|
25900
25985
|
} catch {
|
|
25901
25986
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
25902
25987
|
}
|
|
@@ -25918,21 +26003,21 @@ function readHubBinding(env = process.env) {
|
|
|
25918
26003
|
}
|
|
25919
26004
|
function writeHubBinding(record, env = process.env) {
|
|
25920
26005
|
const file = hubBindingFile(env);
|
|
25921
|
-
|
|
25922
|
-
const temporary =
|
|
26006
|
+
mkdirSync10(dirname10(file), { recursive: true, mode: 448 });
|
|
26007
|
+
const temporary = join14(dirname10(file), `.hub-binding-${process.pid}.tmp`);
|
|
25923
26008
|
try {
|
|
25924
|
-
|
|
26009
|
+
writeFileSync9(temporary, `${JSON.stringify(record, null, 2)}
|
|
25925
26010
|
`, { encoding: "utf8", mode: 384 });
|
|
25926
|
-
|
|
26011
|
+
renameSync4(temporary, file);
|
|
25927
26012
|
} finally {
|
|
25928
|
-
|
|
26013
|
+
rmSync4(temporary, { force: true });
|
|
25929
26014
|
}
|
|
25930
26015
|
return file;
|
|
25931
26016
|
}
|
|
25932
26017
|
function removeHubBinding(env = process.env) {
|
|
25933
26018
|
const file = hubBindingFile(env);
|
|
25934
26019
|
try {
|
|
25935
|
-
|
|
26020
|
+
rmSync4(file);
|
|
25936
26021
|
return true;
|
|
25937
26022
|
} catch (error) {
|
|
25938
26023
|
if (error.code === "ENOENT") return false;
|
|
@@ -25964,10 +26049,9 @@ async function probeHubHealth(url, fetchImpl, timeoutMs = HUB_HEALTH_PROBE_MS) {
|
|
|
25964
26049
|
}
|
|
25965
26050
|
|
|
25966
26051
|
// plugins/kxm/src/cli/types.ts
|
|
25967
|
-
var repoRoot2 = resolve9(fileURLToPath3(new URL("../../../../", import.meta.url)));
|
|
25968
26052
|
function spawnScript(scriptName, extraEnv = {}) {
|
|
25969
26053
|
return new Promise((resolveExit) => {
|
|
25970
|
-
const child = spawn3(process.execPath, [
|
|
26054
|
+
const child = spawn3(process.execPath, [join15(findKxmRepoRoot(import.meta.url), "scripts", scriptName)], {
|
|
25971
26055
|
stdio: "inherit",
|
|
25972
26056
|
env: { ...process.env, ...extraEnv }
|
|
25973
26057
|
});
|
|
@@ -26057,10 +26141,10 @@ function workspaceDirs(cwd, workspaceFlag, env) {
|
|
|
26057
26141
|
return {
|
|
26058
26142
|
workdir,
|
|
26059
26143
|
workspace,
|
|
26060
|
-
config: derive ?
|
|
26061
|
-
logs: derive ?
|
|
26062
|
-
assets: derive ?
|
|
26063
|
-
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"))
|
|
26064
26148
|
};
|
|
26065
26149
|
}
|
|
26066
26150
|
function maskEnvName(name) {
|
|
@@ -26128,20 +26212,20 @@ function workspaceEnv(runtime) {
|
|
|
26128
26212
|
// plugins/kxm/src/cli/roles.ts
|
|
26129
26213
|
var import_yaml8 = __toESM(require_dist(), 1);
|
|
26130
26214
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
26131
|
-
import { existsSync as
|
|
26132
|
-
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";
|
|
26133
26217
|
import { createInterface } from "node:readline";
|
|
26134
26218
|
|
|
26135
26219
|
// plugins/kxm/src/role.ts
|
|
26136
26220
|
var import_yaml7 = __toESM(require_dist(), 1);
|
|
26137
|
-
import { existsSync as
|
|
26138
|
-
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";
|
|
26139
26223
|
|
|
26140
26224
|
// plugins/kxm/src/config.ts
|
|
26141
26225
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
26142
|
-
import { existsSync as
|
|
26143
|
-
import { homedir as
|
|
26144
|
-
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";
|
|
26145
26229
|
var KXM_CONFIG_SCHEMA = "kxm.config.v1";
|
|
26146
26230
|
var DEFAULT_KXM_CONFIG = {
|
|
26147
26231
|
schema: KXM_CONFIG_SCHEMA,
|
|
@@ -26195,10 +26279,10 @@ var DEFAULT_KXM_CONFIG = {
|
|
|
26195
26279
|
};
|
|
26196
26280
|
function userConfigDirectory(overrideDir) {
|
|
26197
26281
|
if (overrideDir) return resolve10(overrideDir);
|
|
26198
|
-
return resolve10(process.env.KXM_USER_CONFIG_DIR?.trim() ||
|
|
26282
|
+
return resolve10(process.env.KXM_USER_CONFIG_DIR?.trim() || join16(homedir5(), ".config", "kxm"));
|
|
26199
26283
|
}
|
|
26200
|
-
function repoConfigDirectory(
|
|
26201
|
-
return resolve10(
|
|
26284
|
+
function repoConfigDirectory(repoRoot) {
|
|
26285
|
+
return resolve10(repoRoot, ".kxm");
|
|
26202
26286
|
}
|
|
26203
26287
|
function deepMerge(target, source) {
|
|
26204
26288
|
const result = { ...target };
|
|
@@ -26216,16 +26300,16 @@ function normalizeHubConfig(raw) {
|
|
|
26216
26300
|
const autoStart = raw?.autoStart;
|
|
26217
26301
|
return { autoStart: autoStart === "off" || autoStart === "background" ? autoStart : DEFAULT_KXM_CONFIG.hub.autoStart };
|
|
26218
26302
|
}
|
|
26219
|
-
function loadKxmConfig(
|
|
26303
|
+
function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
|
|
26220
26304
|
const userDir = userConfigDirectory(options.userConfigDir);
|
|
26221
|
-
const userConfigFile =
|
|
26222
|
-
const repoDir = repoConfigDirectory(
|
|
26223
|
-
const repoConfigFile =
|
|
26305
|
+
const userConfigFile = join16(userDir, "config.yaml");
|
|
26306
|
+
const repoDir = repoConfigDirectory(repoRoot);
|
|
26307
|
+
const repoConfigFile = join16(repoDir, "config.yaml");
|
|
26224
26308
|
let userRaw = {};
|
|
26225
26309
|
let userLoadedPath;
|
|
26226
|
-
if (
|
|
26310
|
+
if (existsSync14(userConfigFile)) {
|
|
26227
26311
|
try {
|
|
26228
|
-
const text =
|
|
26312
|
+
const text = readFileSync14(userConfigFile, "utf8");
|
|
26229
26313
|
userRaw = (0, import_yaml6.parse)(text) ?? {};
|
|
26230
26314
|
userLoadedPath = userConfigFile;
|
|
26231
26315
|
} catch (error) {
|
|
@@ -26234,9 +26318,9 @@ function loadKxmConfig(repoRoot6 = process.cwd(), options = {}) {
|
|
|
26234
26318
|
}
|
|
26235
26319
|
let repoRaw = {};
|
|
26236
26320
|
let repoLoadedPath;
|
|
26237
|
-
if (
|
|
26321
|
+
if (existsSync14(repoConfigFile)) {
|
|
26238
26322
|
try {
|
|
26239
|
-
const text =
|
|
26323
|
+
const text = readFileSync14(repoConfigFile, "utf8");
|
|
26240
26324
|
repoRaw = (0, import_yaml6.parse)(text) ?? {};
|
|
26241
26325
|
repoLoadedPath = repoConfigFile;
|
|
26242
26326
|
} catch (error) {
|
|
@@ -26271,14 +26355,14 @@ function getKxmConfigValue(config, keyPath) {
|
|
|
26271
26355
|
}
|
|
26272
26356
|
return current;
|
|
26273
26357
|
}
|
|
26274
|
-
function setKxmConfigValue(
|
|
26358
|
+
function setKxmConfigValue(repoRoot, keyPath, value, options = {}) {
|
|
26275
26359
|
const scope = options.scope ?? "project";
|
|
26276
|
-
const targetFile2 = scope === "user" ?
|
|
26277
|
-
|
|
26360
|
+
const targetFile2 = scope === "user" ? join16(userConfigDirectory(options.userConfigDir), "config.yaml") : join16(repoConfigDirectory(repoRoot), "config.yaml");
|
|
26361
|
+
mkdirSync11(dirname11(targetFile2), { recursive: true });
|
|
26278
26362
|
let existing = {};
|
|
26279
|
-
if (
|
|
26363
|
+
if (existsSync14(targetFile2)) {
|
|
26280
26364
|
try {
|
|
26281
|
-
existing = (0, import_yaml6.parse)(
|
|
26365
|
+
existing = (0, import_yaml6.parse)(readFileSync14(targetFile2, "utf8")) ?? {};
|
|
26282
26366
|
} catch {
|
|
26283
26367
|
existing = {};
|
|
26284
26368
|
}
|
|
@@ -26296,7 +26380,7 @@ function setKxmConfigValue(repoRoot6, keyPath, value, options = {}) {
|
|
|
26296
26380
|
cursor2 = cursor2[p];
|
|
26297
26381
|
}
|
|
26298
26382
|
cursor2[parts[parts.length - 1]] = value;
|
|
26299
|
-
|
|
26383
|
+
writeFileSync10(targetFile2, (0, import_yaml6.stringify)(existing).trim() + "\n", "utf8");
|
|
26300
26384
|
}
|
|
26301
26385
|
function formatKxmConfig(config) {
|
|
26302
26386
|
const display = {
|
|
@@ -26387,23 +26471,23 @@ var DEFAULT_ROLES = {
|
|
|
26387
26471
|
]
|
|
26388
26472
|
}
|
|
26389
26473
|
};
|
|
26390
|
-
function rolesDirectory(scope,
|
|
26474
|
+
function rolesDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
26391
26475
|
if (scope === "global") {
|
|
26392
|
-
return
|
|
26476
|
+
return join17(userConfigDirectory(userConfigDir), "roles");
|
|
26393
26477
|
}
|
|
26394
|
-
return
|
|
26478
|
+
return join17(repoConfigDirectory(repoRoot), "roles");
|
|
26395
26479
|
}
|
|
26396
|
-
function ensureRolesDirectory(scope,
|
|
26397
|
-
const dir = rolesDirectory(scope,
|
|
26398
|
-
if (!
|
|
26399
|
-
|
|
26480
|
+
function ensureRolesDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
26481
|
+
const dir = rolesDirectory(scope, repoRoot, userConfigDir);
|
|
26482
|
+
if (!existsSync15(dir)) {
|
|
26483
|
+
mkdirSync12(dir, { recursive: true });
|
|
26400
26484
|
}
|
|
26401
26485
|
return dir;
|
|
26402
26486
|
}
|
|
26403
26487
|
function parseRoleFile(filePath) {
|
|
26404
|
-
if (!
|
|
26488
|
+
if (!existsSync15(filePath)) return void 0;
|
|
26405
26489
|
try {
|
|
26406
|
-
const raw =
|
|
26490
|
+
const raw = readFileSync15(filePath, "utf8");
|
|
26407
26491
|
const parsed = (0, import_yaml7.parse)(raw);
|
|
26408
26492
|
if (!parsed || typeof parsed !== "object" || parsed.schema !== KXM_ROLE_SCHEMA) {
|
|
26409
26493
|
return void 0;
|
|
@@ -26426,14 +26510,14 @@ function parseRoleFile(filePath) {
|
|
|
26426
26510
|
}
|
|
26427
26511
|
function listRoles(options = {}) {
|
|
26428
26512
|
const scopeFilter = options.scope ?? "all";
|
|
26429
|
-
const
|
|
26430
|
-
const globalDir = rolesDirectory("global",
|
|
26431
|
-
const localDir = rolesDirectory("local",
|
|
26513
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26514
|
+
const globalDir = rolesDirectory("global", repoRoot, options.userConfigDir);
|
|
26515
|
+
const localDir = rolesDirectory("local", repoRoot, options.userConfigDir);
|
|
26432
26516
|
const localRoles = /* @__PURE__ */ new Map();
|
|
26433
|
-
if (scopeFilter !== "global" &&
|
|
26517
|
+
if (scopeFilter !== "global" && existsSync15(localDir)) {
|
|
26434
26518
|
for (const entry of readdirSync4(localDir)) {
|
|
26435
26519
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
26436
|
-
const filePath =
|
|
26520
|
+
const filePath = join17(localDir, entry);
|
|
26437
26521
|
const parsed = parseRoleFile(filePath);
|
|
26438
26522
|
if (parsed) {
|
|
26439
26523
|
localRoles.set(parsed.id, { role: parsed, filePath });
|
|
@@ -26442,10 +26526,10 @@ function listRoles(options = {}) {
|
|
|
26442
26526
|
}
|
|
26443
26527
|
}
|
|
26444
26528
|
const globalRoles = /* @__PURE__ */ new Map();
|
|
26445
|
-
if (scopeFilter !== "local" &&
|
|
26529
|
+
if (scopeFilter !== "local" && existsSync15(globalDir)) {
|
|
26446
26530
|
for (const entry of readdirSync4(globalDir)) {
|
|
26447
26531
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
26448
|
-
const filePath =
|
|
26532
|
+
const filePath = join17(globalDir, entry);
|
|
26449
26533
|
const parsed = parseRoleFile(filePath);
|
|
26450
26534
|
if (parsed) {
|
|
26451
26535
|
globalRoles.set(parsed.id, { role: parsed, filePath });
|
|
@@ -26490,16 +26574,16 @@ function listRoles(options = {}) {
|
|
|
26490
26574
|
}
|
|
26491
26575
|
function getRole(roleId, options = {}) {
|
|
26492
26576
|
const scope = options.scope ?? "all";
|
|
26493
|
-
const
|
|
26577
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26494
26578
|
if (scope !== "global") {
|
|
26495
|
-
const localDir = rolesDirectory("local",
|
|
26496
|
-
const localFile =
|
|
26579
|
+
const localDir = rolesDirectory("local", repoRoot, options.userConfigDir);
|
|
26580
|
+
const localFile = join17(localDir, `${roleId}.yaml`);
|
|
26497
26581
|
const parsed = parseRoleFile(localFile);
|
|
26498
26582
|
if (parsed) return { role: parsed, scope: "local", filePath: localFile };
|
|
26499
26583
|
}
|
|
26500
26584
|
if (scope !== "local") {
|
|
26501
|
-
const globalDir = rolesDirectory("global",
|
|
26502
|
-
const globalFile =
|
|
26585
|
+
const globalDir = rolesDirectory("global", repoRoot, options.userConfigDir);
|
|
26586
|
+
const globalFile = join17(globalDir, `${roleId}.yaml`);
|
|
26503
26587
|
const parsed = parseRoleFile(globalFile);
|
|
26504
26588
|
if (parsed) return { role: parsed, scope: "global", filePath: globalFile };
|
|
26505
26589
|
}
|
|
@@ -26507,24 +26591,24 @@ function getRole(roleId, options = {}) {
|
|
|
26507
26591
|
}
|
|
26508
26592
|
function addRole(role, options = {}) {
|
|
26509
26593
|
const scope = options.scope ?? "local";
|
|
26510
|
-
const
|
|
26511
|
-
const dir = ensureRolesDirectory(scope,
|
|
26512
|
-
const filePath =
|
|
26513
|
-
if (
|
|
26594
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26595
|
+
const dir = ensureRolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
26596
|
+
const filePath = join17(dir, `${role.id}.yaml`);
|
|
26597
|
+
if (existsSync15(filePath) && !options.overwrite) {
|
|
26514
26598
|
throw new Error(`role_already_exists: role '${role.id}' already exists at ${filePath}`);
|
|
26515
26599
|
}
|
|
26516
|
-
|
|
26600
|
+
writeFileSync11(filePath, (0, import_yaml7.stringify)(role), "utf8");
|
|
26517
26601
|
return { id: role.id, filePath, scope };
|
|
26518
26602
|
}
|
|
26519
26603
|
function removeRole(roleId, options = {}) {
|
|
26520
26604
|
const scope = options.scope ?? "local";
|
|
26521
|
-
const
|
|
26522
|
-
const dir = rolesDirectory(scope,
|
|
26523
|
-
const filePath =
|
|
26524
|
-
if (!
|
|
26605
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26606
|
+
const dir = rolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
26607
|
+
const filePath = join17(dir, `${roleId}.yaml`);
|
|
26608
|
+
if (!existsSync15(filePath)) {
|
|
26525
26609
|
throw new Error(`role_not_found: role '${roleId}' not found in ${scope} directory (${filePath})`);
|
|
26526
26610
|
}
|
|
26527
|
-
|
|
26611
|
+
rmSync5(filePath);
|
|
26528
26612
|
return { id: roleId, removed: true, filePath, scope };
|
|
26529
26613
|
}
|
|
26530
26614
|
function modifyRole(roleId, updates, options = {}) {
|
|
@@ -26540,10 +26624,10 @@ function modifyRole(roleId, updates, options = {}) {
|
|
|
26540
26624
|
// preserve identity
|
|
26541
26625
|
};
|
|
26542
26626
|
const scope = options.scope ?? target.scope;
|
|
26543
|
-
const
|
|
26544
|
-
const dir = ensureRolesDirectory(scope,
|
|
26545
|
-
const filePath =
|
|
26546
|
-
|
|
26627
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26628
|
+
const dir = ensureRolesDirectory(scope, repoRoot, options.userConfigDir);
|
|
26629
|
+
const filePath = join17(dir, `${roleId}.yaml`);
|
|
26630
|
+
writeFileSync11(filePath, (0, import_yaml7.stringify)(updated), "utf8");
|
|
26547
26631
|
return { id: roleId, role: updated, filePath, scope };
|
|
26548
26632
|
}
|
|
26549
26633
|
var KXM_ROLE_HOSTS_SCHEMA = "kxm.role-hosts.v1";
|
|
@@ -26589,20 +26673,20 @@ var DEFAULT_ROLE_SEATS = {
|
|
|
26589
26673
|
requiredEvidenceKind: "test_run"
|
|
26590
26674
|
}
|
|
26591
26675
|
};
|
|
26592
|
-
function findExistingRoleHostsFile(scope,
|
|
26593
|
-
const dir = scope === "global" ? userConfigDirectory(userConfigDir) : repoConfigDirectory(
|
|
26594
|
-
const yamlPath =
|
|
26595
|
-
const ymlPath =
|
|
26596
|
-
const jsonPath =
|
|
26597
|
-
if (
|
|
26598
|
-
if (
|
|
26599
|
-
if (
|
|
26676
|
+
function findExistingRoleHostsFile(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
26677
|
+
const dir = scope === "global" ? userConfigDirectory(userConfigDir) : repoConfigDirectory(repoRoot);
|
|
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" };
|
|
26600
26684
|
return { filePath: yamlPath, exists: false, format: "yaml" };
|
|
26601
26685
|
}
|
|
26602
26686
|
function parseRoleHostsFile(filePath) {
|
|
26603
|
-
if (!
|
|
26687
|
+
if (!existsSync15(filePath)) return void 0;
|
|
26604
26688
|
try {
|
|
26605
|
-
const raw =
|
|
26689
|
+
const raw = readFileSync15(filePath, "utf8");
|
|
26606
26690
|
const parsed = (0, import_yaml7.parse)(raw);
|
|
26607
26691
|
if (!parsed || typeof parsed !== "object") return void 0;
|
|
26608
26692
|
if (parsed.schema && parsed.schema !== KXM_ROLE_HOSTS_SCHEMA) return void 0;
|
|
@@ -26617,11 +26701,11 @@ function parseRoleHostsFile(filePath) {
|
|
|
26617
26701
|
}
|
|
26618
26702
|
function loadRoleHostsConfig(options = {}) {
|
|
26619
26703
|
const scopeFilter = options.scope ?? "all";
|
|
26620
|
-
const
|
|
26704
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26621
26705
|
let localConfig;
|
|
26622
26706
|
let localPath;
|
|
26623
26707
|
if (scopeFilter !== "global") {
|
|
26624
|
-
const localFound = findExistingRoleHostsFile("local",
|
|
26708
|
+
const localFound = findExistingRoleHostsFile("local", repoRoot, options.userConfigDir);
|
|
26625
26709
|
if (localFound.exists) {
|
|
26626
26710
|
localConfig = parseRoleHostsFile(localFound.filePath);
|
|
26627
26711
|
localPath = localFound.filePath;
|
|
@@ -26630,7 +26714,7 @@ function loadRoleHostsConfig(options = {}) {
|
|
|
26630
26714
|
let globalConfig;
|
|
26631
26715
|
let globalPath;
|
|
26632
26716
|
if (scopeFilter !== "local") {
|
|
26633
|
-
const globalFound = findExistingRoleHostsFile("global",
|
|
26717
|
+
const globalFound = findExistingRoleHostsFile("global", repoRoot, options.userConfigDir);
|
|
26634
26718
|
if (globalFound.exists) {
|
|
26635
26719
|
globalConfig = parseRoleHostsFile(globalFound.filePath);
|
|
26636
26720
|
globalPath = globalFound.filePath;
|
|
@@ -26672,20 +26756,20 @@ function loadRoleHostsConfig(options = {}) {
|
|
|
26672
26756
|
}
|
|
26673
26757
|
function saveRoleHostsConfig(config, options = {}) {
|
|
26674
26758
|
const scope = options.scope ?? "local";
|
|
26675
|
-
const
|
|
26676
|
-
const dir = scope === "global" ? userConfigDirectory(options.userConfigDir) : repoConfigDirectory(
|
|
26677
|
-
if (!
|
|
26678
|
-
|
|
26759
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
26760
|
+
const dir = scope === "global" ? userConfigDirectory(options.userConfigDir) : repoConfigDirectory(repoRoot);
|
|
26761
|
+
if (!existsSync15(dir)) {
|
|
26762
|
+
mkdirSync12(dir, { recursive: true });
|
|
26679
26763
|
}
|
|
26680
26764
|
const format = options.format ?? "yaml";
|
|
26681
|
-
const filePath =
|
|
26765
|
+
const filePath = join17(dir, format === "json" ? "role-hosts.json" : "role-hosts.yaml");
|
|
26682
26766
|
const payload = {
|
|
26683
26767
|
schema: KXM_ROLE_HOSTS_SCHEMA,
|
|
26684
26768
|
seats: config.seats ?? {},
|
|
26685
26769
|
...config.hostProviders && Object.keys(config.hostProviders).length > 0 ? { hostProviders: config.hostProviders } : {}
|
|
26686
26770
|
};
|
|
26687
26771
|
const content = format === "json" ? JSON.stringify(payload, null, 2) + "\n" : (0, import_yaml7.stringify)(payload);
|
|
26688
|
-
|
|
26772
|
+
writeFileSync11(filePath, content, "utf8");
|
|
26689
26773
|
return { filePath, scope };
|
|
26690
26774
|
}
|
|
26691
26775
|
function setRoleSeatHost(seatId, host, options = {}) {
|
|
@@ -26920,7 +27004,7 @@ async function cmdRoleAdd(runtime, roleId, options) {
|
|
|
26920
27004
|
let roleDef;
|
|
26921
27005
|
if (options.file) {
|
|
26922
27006
|
const filePath = resolve12(runtime.cwd, options.file);
|
|
26923
|
-
const content =
|
|
27007
|
+
const content = readFileSync16(filePath, "utf8");
|
|
26924
27008
|
roleDef = (0, import_yaml8.parse)(content);
|
|
26925
27009
|
roleDef.id = roleId;
|
|
26926
27010
|
} else {
|
|
@@ -27219,8 +27303,8 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
27219
27303
|
return 1;
|
|
27220
27304
|
}
|
|
27221
27305
|
}
|
|
27222
|
-
const dbPath =
|
|
27223
|
-
if (
|
|
27306
|
+
const dbPath = join18(runtime.cwd, ".kxm", "state", "kxm.db");
|
|
27307
|
+
if (existsSync16(dbPath)) {
|
|
27224
27308
|
try {
|
|
27225
27309
|
const database = new DatabaseSync(dbPath);
|
|
27226
27310
|
try {
|
|
@@ -27282,11 +27366,11 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
27282
27366
|
|
|
27283
27367
|
// plugins/kxm/src/cli/workflows.ts
|
|
27284
27368
|
import { createHmac as createHmac3, randomUUID as randomUUID7 } from "node:crypto";
|
|
27285
|
-
import { existsSync as
|
|
27286
|
-
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";
|
|
27287
27371
|
|
|
27288
27372
|
// plugins/kxm/src/retrospective.ts
|
|
27289
|
-
import { mkdirSync as
|
|
27373
|
+
import { mkdirSync as mkdirSync13, renameSync as renameSync5, writeFileSync as writeFileSync12 } from "node:fs";
|
|
27290
27374
|
import { resolve as resolve13 } from "node:path";
|
|
27291
27375
|
var MAX_RETROSPECTIVE_ENTRIES = 500;
|
|
27292
27376
|
var SAFE_RUN_ID = /^run_[A-Za-z0-9_-]{1,120}$/;
|
|
@@ -27499,7 +27583,7 @@ function renderRetrospectiveMarkdown(doc) {
|
|
|
27499
27583
|
}
|
|
27500
27584
|
function writeRetrospective(outDir, doc) {
|
|
27501
27585
|
if (!SAFE_RUN_ID.test(doc.runId)) throw new Error("invalid retrospective run id");
|
|
27502
|
-
|
|
27586
|
+
mkdirSync13(outDir, { recursive: true });
|
|
27503
27587
|
const root = resolve13(outDir);
|
|
27504
27588
|
const jsonPath = resolve13(root, `${doc.runId}.json`);
|
|
27505
27589
|
const mdPath = resolve13(root, `${doc.runId}.md`);
|
|
@@ -27507,11 +27591,11 @@ function writeRetrospective(outDir, doc) {
|
|
|
27507
27591
|
if (!jsonPath.startsWith(prefix) || !mdPath.startsWith(prefix)) throw new Error("retrospective path escaped output directory");
|
|
27508
27592
|
const jsonTmp = `${jsonPath}.tmp`;
|
|
27509
27593
|
const mdTmp = `${mdPath}.tmp`;
|
|
27510
|
-
|
|
27594
|
+
writeFileSync12(jsonTmp, `${JSON.stringify(doc, null, 2)}
|
|
27511
27595
|
`, { encoding: "utf8", mode: 384 });
|
|
27512
|
-
|
|
27513
|
-
|
|
27514
|
-
|
|
27596
|
+
writeFileSync12(mdTmp, renderRetrospectiveMarkdown(doc), { encoding: "utf8", mode: 384 });
|
|
27597
|
+
renameSync5(jsonTmp, jsonPath);
|
|
27598
|
+
renameSync5(mdTmp, mdPath);
|
|
27515
27599
|
return { jsonPath, mdPath };
|
|
27516
27600
|
}
|
|
27517
27601
|
|
|
@@ -27701,8 +27785,8 @@ async function watchGithubChecks(input) {
|
|
|
27701
27785
|
|
|
27702
27786
|
// plugins/kxm/src/workflow-manager.ts
|
|
27703
27787
|
var import_yaml9 = __toESM(require_dist(), 1);
|
|
27704
|
-
import { existsSync as
|
|
27705
|
-
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";
|
|
27706
27790
|
var WORKFLOW_TEMPLATES = {
|
|
27707
27791
|
"implement-and-verify": {
|
|
27708
27792
|
schema: "kxm.workflow.v1",
|
|
@@ -27851,23 +27935,23 @@ var WORKFLOW_TEMPLATES = {
|
|
|
27851
27935
|
}
|
|
27852
27936
|
};
|
|
27853
27937
|
var DEFAULT_WORKFLOW_TEMPLATE = WORKFLOW_TEMPLATES["implement-and-verify"];
|
|
27854
|
-
function workflowsDirectory(scope,
|
|
27938
|
+
function workflowsDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
27855
27939
|
if (scope === "global") {
|
|
27856
|
-
return
|
|
27940
|
+
return join19(userConfigDirectory(userConfigDir), "workflows");
|
|
27857
27941
|
}
|
|
27858
|
-
return
|
|
27942
|
+
return join19(repoConfigDirectory(repoRoot), "workflows");
|
|
27859
27943
|
}
|
|
27860
|
-
function ensureWorkflowsDirectory(scope,
|
|
27861
|
-
const dir = workflowsDirectory(scope,
|
|
27862
|
-
if (!
|
|
27863
|
-
|
|
27944
|
+
function ensureWorkflowsDirectory(scope, repoRoot = process.cwd(), userConfigDir) {
|
|
27945
|
+
const dir = workflowsDirectory(scope, repoRoot, userConfigDir);
|
|
27946
|
+
if (!existsSync17(dir)) {
|
|
27947
|
+
mkdirSync14(dir, { recursive: true });
|
|
27864
27948
|
}
|
|
27865
27949
|
return dir;
|
|
27866
27950
|
}
|
|
27867
27951
|
function parseWorkflowFile(filePath) {
|
|
27868
|
-
if (!
|
|
27952
|
+
if (!existsSync17(filePath)) return void 0;
|
|
27869
27953
|
try {
|
|
27870
|
-
const raw =
|
|
27954
|
+
const raw = readFileSync17(filePath, "utf8");
|
|
27871
27955
|
const parsed = (0, import_yaml9.parse)(raw);
|
|
27872
27956
|
if (!parsed || typeof parsed !== "object") return void 0;
|
|
27873
27957
|
return parsed;
|
|
@@ -27877,14 +27961,14 @@ function parseWorkflowFile(filePath) {
|
|
|
27877
27961
|
}
|
|
27878
27962
|
function listWorkflowDefinitions(options = {}) {
|
|
27879
27963
|
const scopeFilter = options.scope ?? "all";
|
|
27880
|
-
const
|
|
27881
|
-
const globalDir = workflowsDirectory("global",
|
|
27882
|
-
const localDir = workflowsDirectory("local",
|
|
27964
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
27965
|
+
const globalDir = workflowsDirectory("global", repoRoot, options.userConfigDir);
|
|
27966
|
+
const localDir = workflowsDirectory("local", repoRoot, options.userConfigDir);
|
|
27883
27967
|
const localDefs = /* @__PURE__ */ new Map();
|
|
27884
|
-
if (scopeFilter !== "global" &&
|
|
27968
|
+
if (scopeFilter !== "global" && existsSync17(localDir)) {
|
|
27885
27969
|
for (const entry of readdirSync5(localDir)) {
|
|
27886
27970
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
27887
|
-
const filePath =
|
|
27971
|
+
const filePath = join19(localDir, entry);
|
|
27888
27972
|
const def = parseWorkflowFile(filePath);
|
|
27889
27973
|
if (def) {
|
|
27890
27974
|
const id = def.id || entry.replace(/\.ya?ml$/i, "");
|
|
@@ -27894,10 +27978,10 @@ function listWorkflowDefinitions(options = {}) {
|
|
|
27894
27978
|
}
|
|
27895
27979
|
}
|
|
27896
27980
|
const globalDefs = /* @__PURE__ */ new Map();
|
|
27897
|
-
if (scopeFilter !== "local" &&
|
|
27981
|
+
if (scopeFilter !== "local" && existsSync17(globalDir)) {
|
|
27898
27982
|
for (const entry of readdirSync5(globalDir)) {
|
|
27899
27983
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
27900
|
-
const filePath =
|
|
27984
|
+
const filePath = join19(globalDir, entry);
|
|
27901
27985
|
const def = parseWorkflowFile(filePath);
|
|
27902
27986
|
if (def) {
|
|
27903
27987
|
const id = def.id || entry.replace(/\.ya?ml$/i, "");
|
|
@@ -27950,16 +28034,16 @@ function listWorkflowDefinitions(options = {}) {
|
|
|
27950
28034
|
}
|
|
27951
28035
|
function getWorkflowDefinition(workflowId, options = {}) {
|
|
27952
28036
|
const scope = options.scope ?? "all";
|
|
27953
|
-
const
|
|
28037
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
27954
28038
|
if (scope !== "global") {
|
|
27955
|
-
const localDir = workflowsDirectory("local",
|
|
27956
|
-
const localFile =
|
|
28039
|
+
const localDir = workflowsDirectory("local", repoRoot, options.userConfigDir);
|
|
28040
|
+
const localFile = join19(localDir, `${workflowId}.yaml`);
|
|
27957
28041
|
const parsed = parseWorkflowFile(localFile);
|
|
27958
28042
|
if (parsed) return { workflow: parsed, scope: "local", filePath: localFile };
|
|
27959
28043
|
}
|
|
27960
28044
|
if (scope !== "local") {
|
|
27961
|
-
const globalDir = workflowsDirectory("global",
|
|
27962
|
-
const globalFile =
|
|
28045
|
+
const globalDir = workflowsDirectory("global", repoRoot, options.userConfigDir);
|
|
28046
|
+
const globalFile = join19(globalDir, `${workflowId}.yaml`);
|
|
27963
28047
|
const parsed = parseWorkflowFile(globalFile);
|
|
27964
28048
|
if (parsed) return { workflow: parsed, scope: "global", filePath: globalFile };
|
|
27965
28049
|
}
|
|
@@ -27967,25 +28051,25 @@ function getWorkflowDefinition(workflowId, options = {}) {
|
|
|
27967
28051
|
}
|
|
27968
28052
|
function addWorkflowDefinition(workflowId, content = DEFAULT_WORKFLOW_TEMPLATE, options = {}) {
|
|
27969
28053
|
const scope = options.scope ?? "local";
|
|
27970
|
-
const
|
|
27971
|
-
const dir = ensureWorkflowsDirectory(scope,
|
|
27972
|
-
const filePath =
|
|
27973
|
-
if (
|
|
28054
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
28055
|
+
const dir = ensureWorkflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
28056
|
+
const filePath = join19(dir, `${workflowId}.yaml`);
|
|
28057
|
+
if (existsSync17(filePath) && !options.overwrite) {
|
|
27974
28058
|
throw new Error(`workflow_already_exists: workflow '${workflowId}' already exists at ${filePath}`);
|
|
27975
28059
|
}
|
|
27976
28060
|
const payload = typeof content === "string" ? content : (0, import_yaml9.stringify)(content);
|
|
27977
|
-
|
|
28061
|
+
writeFileSync13(filePath, payload, "utf8");
|
|
27978
28062
|
return { id: workflowId, filePath, scope };
|
|
27979
28063
|
}
|
|
27980
28064
|
function removeWorkflowDefinition(workflowId, options = {}) {
|
|
27981
28065
|
const scope = options.scope ?? "local";
|
|
27982
|
-
const
|
|
27983
|
-
const dir = workflowsDirectory(scope,
|
|
27984
|
-
const filePath =
|
|
27985
|
-
if (!
|
|
28066
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
28067
|
+
const dir = workflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
28068
|
+
const filePath = join19(dir, `${workflowId}.yaml`);
|
|
28069
|
+
if (!existsSync17(filePath)) {
|
|
27986
28070
|
throw new Error(`workflow_not_found: workflow '${workflowId}' not found in ${scope} directory (${filePath})`);
|
|
27987
28071
|
}
|
|
27988
|
-
|
|
28072
|
+
rmSync6(filePath);
|
|
27989
28073
|
return { id: workflowId, removed: true, filePath, scope };
|
|
27990
28074
|
}
|
|
27991
28075
|
function modifyWorkflowDefinition(workflowId, updates, options = {}) {
|
|
@@ -27998,17 +28082,17 @@ function modifyWorkflowDefinition(workflowId, updates, options = {}) {
|
|
|
27998
28082
|
...updates
|
|
27999
28083
|
};
|
|
28000
28084
|
const scope = options.scope ?? target.scope;
|
|
28001
|
-
const
|
|
28002
|
-
const dir = ensureWorkflowsDirectory(scope,
|
|
28003
|
-
const filePath =
|
|
28004
|
-
|
|
28085
|
+
const repoRoot = options.repoRoot ?? process.cwd();
|
|
28086
|
+
const dir = ensureWorkflowsDirectory(scope, repoRoot, options.userConfigDir);
|
|
28087
|
+
const filePath = join19(dir, `${workflowId}.yaml`);
|
|
28088
|
+
writeFileSync13(filePath, (0, import_yaml9.stringify)(updated), "utf8");
|
|
28005
28089
|
return { id: workflowId, workflow: updated, filePath, scope };
|
|
28006
28090
|
}
|
|
28007
28091
|
|
|
28008
28092
|
// plugins/kxm/src/cli/workflows.ts
|
|
28009
28093
|
var CLI_NAME = "kxm";
|
|
28010
28094
|
function localWorkflowSnapshot(dataPath, runId) {
|
|
28011
|
-
if (!
|
|
28095
|
+
if (!existsSync18(dataPath)) throw new Error("state_database_not_found");
|
|
28012
28096
|
const database = new DatabaseSync(dataPath, { readOnly: true });
|
|
28013
28097
|
try {
|
|
28014
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();
|
|
@@ -28085,7 +28169,7 @@ function activeWorkflowDefinition(runtime, definitionId) {
|
|
|
28085
28169
|
let raw;
|
|
28086
28170
|
if (file) {
|
|
28087
28171
|
try {
|
|
28088
|
-
raw =
|
|
28172
|
+
raw = readFileSync18(resolve15(runtime.cwd, file), "utf8");
|
|
28089
28173
|
} catch {
|
|
28090
28174
|
throw new Error("workflow definition file is unavailable");
|
|
28091
28175
|
}
|
|
@@ -28167,7 +28251,7 @@ async function cmdWorkflowAdd(runtime, workflowId, options) {
|
|
|
28167
28251
|
}
|
|
28168
28252
|
if (options.file) {
|
|
28169
28253
|
const filePath = resolve15(runtime.cwd, options.file);
|
|
28170
|
-
content =
|
|
28254
|
+
content = readFileSync18(filePath, "utf8");
|
|
28171
28255
|
} else if (!content) {
|
|
28172
28256
|
content = {
|
|
28173
28257
|
schema: "kxm.workflow.v1",
|
|
@@ -28325,7 +28409,7 @@ async function cmdWorkflowStart(runtime, definitionIdArg, options) {
|
|
|
28325
28409
|
}
|
|
28326
28410
|
let payload;
|
|
28327
28411
|
try {
|
|
28328
|
-
const raw = payloadFlag.startsWith("@") ?
|
|
28412
|
+
const raw = payloadFlag.startsWith("@") ? readFileSync18(resolve15(runtime.cwd, payloadFlag.slice(1)), "utf8") : payloadFlag;
|
|
28329
28413
|
const value = JSON.parse(raw);
|
|
28330
28414
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("object required");
|
|
28331
28415
|
payload = value;
|
|
@@ -28392,7 +28476,7 @@ async function cmdWorkflowDegrade(runtime, runId, stageId, options) {
|
|
|
28392
28476
|
}
|
|
28393
28477
|
}
|
|
28394
28478
|
async function cmdWorkflowInspect(runtime, action, runId) {
|
|
28395
|
-
const dataPath = resolve15(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() ||
|
|
28479
|
+
const dataPath = resolve15(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join20(runtime.dirs.state, "kxm.db"));
|
|
28396
28480
|
if (action === "get" && !runId) {
|
|
28397
28481
|
runtime.io.stderr(`Usage: ${CLI_NAME} workflow get <runId>
|
|
28398
28482
|
`);
|
|
@@ -28565,10 +28649,10 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28565
28649
|
let snapshot;
|
|
28566
28650
|
try {
|
|
28567
28651
|
if (snapshotPath) {
|
|
28568
|
-
if (!
|
|
28569
|
-
snapshot = JSON.parse(
|
|
28652
|
+
if (!existsSync18(snapshotPath)) throw new Error("snapshot_missing");
|
|
28653
|
+
snapshot = JSON.parse(readFileSync18(snapshotPath, "utf8"));
|
|
28570
28654
|
} else {
|
|
28571
|
-
const dataPath = resolve15(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() ||
|
|
28655
|
+
const dataPath = resolve15(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join20(runtime.dirs.state, "kxm.db"));
|
|
28572
28656
|
const local = localWorkflowSnapshot(dataPath, runId);
|
|
28573
28657
|
if (!local.runs[0]) throw new Error("workflow_not_found");
|
|
28574
28658
|
snapshot = { run: local.runs[0], journal: local.journal };
|
|
@@ -28580,7 +28664,7 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28580
28664
|
return 1;
|
|
28581
28665
|
}
|
|
28582
28666
|
const doc = buildRetrospective(snapshot.run, snapshot.journal);
|
|
28583
|
-
const outDir = resolve15(runtime.cwd, String(options.outDir ||
|
|
28667
|
+
const outDir = resolve15(runtime.cwd, String(options.outDir || join20(runtime.dirs.assets, "retrospectives")));
|
|
28584
28668
|
const assetsRoot = resolve15(runtime.dirs.assets);
|
|
28585
28669
|
const assetsPrefix = `${assetsRoot}${process.platform === "win32" ? "\\" : "/"}`;
|
|
28586
28670
|
if (outDir !== assetsRoot && !outDir.startsWith(assetsPrefix)) {
|
|
@@ -28598,8 +28682,8 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28598
28682
|
|
|
28599
28683
|
// plugins/kxm/src/cli/tasks.ts
|
|
28600
28684
|
var import_yaml13 = __toESM(require_dist(), 1);
|
|
28601
|
-
import { existsSync as
|
|
28602
|
-
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";
|
|
28603
28687
|
|
|
28604
28688
|
// plugins/kxm/src/suggest.ts
|
|
28605
28689
|
var WORKFLOW_PATTERNS = [
|
|
@@ -28710,19 +28794,19 @@ function suggestWorkflowAndRoles(prompt, options = {}) {
|
|
|
28710
28794
|
// plugins/kxm/src/task-manager.ts
|
|
28711
28795
|
var import_yaml10 = __toESM(require_dist(), 1);
|
|
28712
28796
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
28713
|
-
import { existsSync as
|
|
28714
|
-
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";
|
|
28715
28799
|
var GOAL_SCHEMA = "kxm.goal.v1";
|
|
28716
28800
|
var TASK_SCHEMA = "kxm.task.v1";
|
|
28717
|
-
function goalsDirectory(
|
|
28718
|
-
return resolve16(
|
|
28801
|
+
function goalsDirectory(repoRoot) {
|
|
28802
|
+
return resolve16(repoRoot, ".kxm", "goals");
|
|
28719
28803
|
}
|
|
28720
|
-
function tasksDirectory(
|
|
28721
|
-
return resolve16(
|
|
28804
|
+
function tasksDirectory(repoRoot) {
|
|
28805
|
+
return resolve16(repoRoot, ".kxm", "tasks");
|
|
28722
28806
|
}
|
|
28723
|
-
function createGoal(
|
|
28724
|
-
const dir = goalsDirectory(
|
|
28725
|
-
|
|
28807
|
+
function createGoal(repoRoot, input) {
|
|
28808
|
+
const dir = goalsDirectory(repoRoot);
|
|
28809
|
+
mkdirSync15(dir, { recursive: true });
|
|
28726
28810
|
const id = `goal_${randomUUID8().replaceAll("-", "").slice(0, 12)}`;
|
|
28727
28811
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
28728
28812
|
const record = {
|
|
@@ -28736,19 +28820,19 @@ function createGoal(repoRoot6, input) {
|
|
|
28736
28820
|
createdAt: now,
|
|
28737
28821
|
updatedAt: now
|
|
28738
28822
|
};
|
|
28739
|
-
const filePath =
|
|
28740
|
-
|
|
28823
|
+
const filePath = join21(dir, `${id}.yaml`);
|
|
28824
|
+
writeFileSync14(filePath, (0, import_yaml10.stringify)(record).trim() + "\n", "utf8");
|
|
28741
28825
|
return record;
|
|
28742
28826
|
}
|
|
28743
|
-
function listGoals(
|
|
28744
|
-
const dir = goalsDirectory(
|
|
28745
|
-
if (!
|
|
28827
|
+
function listGoals(repoRoot) {
|
|
28828
|
+
const dir = goalsDirectory(repoRoot);
|
|
28829
|
+
if (!existsSync19(dir)) return [];
|
|
28746
28830
|
const goals = [];
|
|
28747
28831
|
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
28748
28832
|
for (const entry of entries) {
|
|
28749
28833
|
if (entry.isFile() && (entry.name.endsWith(".yaml") || entry.name.endsWith(".yml"))) {
|
|
28750
28834
|
try {
|
|
28751
|
-
const text =
|
|
28835
|
+
const text = readFileSync19(join21(dir, entry.name), "utf8");
|
|
28752
28836
|
const doc = (0, import_yaml10.parse)(text);
|
|
28753
28837
|
if (doc && doc.schema === GOAL_SCHEMA) goals.push(doc);
|
|
28754
28838
|
} catch {
|
|
@@ -28757,9 +28841,9 @@ function listGoals(repoRoot6) {
|
|
|
28757
28841
|
}
|
|
28758
28842
|
return goals.sort((a, b2) => a.createdAt.localeCompare(b2.createdAt));
|
|
28759
28843
|
}
|
|
28760
|
-
function createTask(
|
|
28761
|
-
const dir = tasksDirectory(
|
|
28762
|
-
|
|
28844
|
+
function createTask(repoRoot, input) {
|
|
28845
|
+
const dir = tasksDirectory(repoRoot);
|
|
28846
|
+
mkdirSync15(dir, { recursive: true });
|
|
28763
28847
|
const id = `task_${randomUUID8().replaceAll("-", "").slice(0, 12)}`;
|
|
28764
28848
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
28765
28849
|
const record = {
|
|
@@ -28781,19 +28865,19 @@ function createTask(repoRoot6, input) {
|
|
|
28781
28865
|
createdAt: now,
|
|
28782
28866
|
updatedAt: now
|
|
28783
28867
|
};
|
|
28784
|
-
const filePath =
|
|
28785
|
-
|
|
28868
|
+
const filePath = join21(dir, `${id}.yaml`);
|
|
28869
|
+
writeFileSync14(filePath, (0, import_yaml10.stringify)(record).trim() + "\n", "utf8");
|
|
28786
28870
|
return record;
|
|
28787
28871
|
}
|
|
28788
|
-
function listTasks(
|
|
28789
|
-
const dir = tasksDirectory(
|
|
28790
|
-
if (!
|
|
28872
|
+
function listTasks(repoRoot, options = {}) {
|
|
28873
|
+
const dir = tasksDirectory(repoRoot);
|
|
28874
|
+
if (!existsSync19(dir)) return [];
|
|
28791
28875
|
const tasks = [];
|
|
28792
28876
|
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
28793
28877
|
for (const entry of entries) {
|
|
28794
28878
|
if (entry.isFile() && (entry.name.endsWith(".yaml") || entry.name.endsWith(".yml"))) {
|
|
28795
28879
|
try {
|
|
28796
|
-
const text =
|
|
28880
|
+
const text = readFileSync19(join21(dir, entry.name), "utf8");
|
|
28797
28881
|
const doc = (0, import_yaml10.parse)(text);
|
|
28798
28882
|
if (doc && doc.schema === TASK_SCHEMA) {
|
|
28799
28883
|
if (options.goalId && doc.goalId !== options.goalId) continue;
|
|
@@ -28806,32 +28890,32 @@ function listTasks(repoRoot6, options = {}) {
|
|
|
28806
28890
|
}
|
|
28807
28891
|
return tasks.sort((a, b2) => a.createdAt.localeCompare(b2.createdAt));
|
|
28808
28892
|
}
|
|
28809
|
-
function getTask(
|
|
28810
|
-
const dir = tasksDirectory(
|
|
28811
|
-
const filePath =
|
|
28812
|
-
if (!
|
|
28893
|
+
function getTask(repoRoot, taskId) {
|
|
28894
|
+
const dir = tasksDirectory(repoRoot);
|
|
28895
|
+
const filePath = join21(dir, `${taskId}.yaml`);
|
|
28896
|
+
if (!existsSync19(filePath)) return void 0;
|
|
28813
28897
|
try {
|
|
28814
|
-
const text =
|
|
28898
|
+
const text = readFileSync19(filePath, "utf8");
|
|
28815
28899
|
const doc = (0, import_yaml10.parse)(text);
|
|
28816
28900
|
return doc && doc.schema === TASK_SCHEMA ? doc : void 0;
|
|
28817
28901
|
} catch {
|
|
28818
28902
|
return void 0;
|
|
28819
28903
|
}
|
|
28820
28904
|
}
|
|
28821
|
-
function updateTaskStatus(
|
|
28822
|
-
const task = getTask(
|
|
28905
|
+
function updateTaskStatus(repoRoot, taskId, status, options = {}) {
|
|
28906
|
+
const task = getTask(repoRoot, taskId);
|
|
28823
28907
|
if (!task) {
|
|
28824
28908
|
throw new Error(`Task ${taskId} not found`);
|
|
28825
28909
|
}
|
|
28826
28910
|
task.status = status;
|
|
28827
28911
|
if (options.workflowRunId) task.workflowRunId = options.workflowRunId;
|
|
28828
28912
|
task.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
28829
|
-
const filePath =
|
|
28830
|
-
|
|
28913
|
+
const filePath = join21(tasksDirectory(repoRoot), `${taskId}.yaml`);
|
|
28914
|
+
writeFileSync14(filePath, (0, import_yaml10.stringify)(task).trim() + "\n", "utf8");
|
|
28831
28915
|
return task;
|
|
28832
28916
|
}
|
|
28833
|
-
function syncTaskWithTracker(
|
|
28834
|
-
const task = getTask(
|
|
28917
|
+
function syncTaskWithTracker(repoRoot, taskId, options = {}) {
|
|
28918
|
+
const task = getTask(repoRoot, taskId);
|
|
28835
28919
|
if (!task) {
|
|
28836
28920
|
throw new Error(`Task ${taskId} not found`);
|
|
28837
28921
|
}
|
|
@@ -28842,8 +28926,8 @@ function syncTaskWithTracker(repoRoot6, taskId, options = {}) {
|
|
|
28842
28926
|
task.trackerSync.syncStatus = "synced";
|
|
28843
28927
|
task.trackerSync.lastSyncedAt = now;
|
|
28844
28928
|
task.updatedAt = now;
|
|
28845
|
-
const filePath =
|
|
28846
|
-
|
|
28929
|
+
const filePath = join21(tasksDirectory(repoRoot), `${taskId}.yaml`);
|
|
28930
|
+
writeFileSync14(filePath, (0, import_yaml10.stringify)(task).trim() + "\n", "utf8");
|
|
28847
28931
|
return task;
|
|
28848
28932
|
}
|
|
28849
28933
|
|
|
@@ -29609,14 +29693,13 @@ function createStudioServer(options = {}) {
|
|
|
29609
29693
|
}
|
|
29610
29694
|
|
|
29611
29695
|
// plugins/kxm/src/cli/vnext.ts
|
|
29612
|
-
import { join as
|
|
29696
|
+
import { join as join27, resolve as resolve20 } from "node:path";
|
|
29613
29697
|
import { createInterface as createInterface2 } from "node:readline";
|
|
29614
|
-
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
29615
29698
|
|
|
29616
29699
|
// plugins/kxm/src/model-inventory.ts
|
|
29617
29700
|
var import_yaml11 = __toESM(require_dist(), 1);
|
|
29618
|
-
import { mkdirSync as
|
|
29619
|
-
import { join as
|
|
29701
|
+
import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync15 } from "node:fs";
|
|
29702
|
+
import { join as join22 } from "node:path";
|
|
29620
29703
|
var OR_URL = "https://openrouter.ai/api/v1/models";
|
|
29621
29704
|
var NOUS_URL = "https://inference-api.nousresearch.com/v1/models";
|
|
29622
29705
|
function price(value) {
|
|
@@ -29702,41 +29785,41 @@ async function refreshModelInventory(options) {
|
|
|
29702
29785
|
sources.nous = { url: nousUrl, ok: !nous.error, ...nous.error ? { error: nous.error } : {} };
|
|
29703
29786
|
for (const item of nous.data) add(item, "nous", "discount");
|
|
29704
29787
|
const inventory = { schema: "kxm.model-inventory.v1", fetchedAt, currency: "USD", sources, models: [...byId.values()].sort((a, b2) => a.id.localeCompare(b2.id)) };
|
|
29705
|
-
|
|
29706
|
-
|
|
29788
|
+
mkdirSync16(join22(options.outputRoot, ".kxm", "models"), { recursive: true });
|
|
29789
|
+
writeFileSync15(join22(options.outputRoot, ".kxm", "models", "inventory.yaml"), (0, import_yaml11.stringify)(inventory), "utf8");
|
|
29707
29790
|
return inventory;
|
|
29708
29791
|
}
|
|
29709
29792
|
|
|
29710
29793
|
// plugins/kxm/src/vnext-init.ts
|
|
29711
29794
|
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
29712
|
-
import { existsSync as
|
|
29713
|
-
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";
|
|
29714
29797
|
|
|
29715
29798
|
// plugins/kxm/src/vnext-repair.ts
|
|
29716
29799
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
29717
29800
|
import {
|
|
29718
29801
|
chmodSync as chmodSync5,
|
|
29719
29802
|
closeSync as closeSync2,
|
|
29720
|
-
existsSync as
|
|
29803
|
+
existsSync as existsSync21,
|
|
29721
29804
|
fsyncSync as fsyncSync2,
|
|
29722
29805
|
linkSync,
|
|
29723
29806
|
lstatSync as lstatSync7,
|
|
29724
|
-
mkdirSync as
|
|
29807
|
+
mkdirSync as mkdirSync18,
|
|
29725
29808
|
openSync as openSync2,
|
|
29726
|
-
readFileSync as
|
|
29809
|
+
readFileSync as readFileSync21,
|
|
29727
29810
|
readdirSync as readdirSync7,
|
|
29728
|
-
renameSync as
|
|
29729
|
-
rmSync as
|
|
29730
|
-
writeFileSync as
|
|
29811
|
+
renameSync as renameSync6,
|
|
29812
|
+
rmSync as rmSync8,
|
|
29813
|
+
writeFileSync as writeFileSync17
|
|
29731
29814
|
} from "node:fs";
|
|
29732
|
-
import { dirname as
|
|
29815
|
+
import { dirname as dirname15, isAbsolute as isAbsolute7, join as join24, relative as relative4, resolve as resolve18 } from "node:path";
|
|
29733
29816
|
|
|
29734
29817
|
// plugins/kxm/src/vnext-permission.ts
|
|
29735
29818
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
29736
29819
|
import { createHash as createHash12 } from "node:crypto";
|
|
29737
|
-
import { existsSync as
|
|
29820
|
+
import { existsSync as existsSync20, mkdtempSync, mkdirSync as mkdirSync17, readFileSync as readFileSync20, rmSync as rmSync7, writeFileSync as writeFileSync16 } from "node:fs";
|
|
29738
29821
|
import { tmpdir } from "node:os";
|
|
29739
|
-
import { dirname as
|
|
29822
|
+
import { dirname as dirname14, join as join23, resolve as resolve17, sep as sep3 } from "node:path";
|
|
29740
29823
|
var PROSE_FIELDS = {
|
|
29741
29824
|
project: /* @__PURE__ */ new Set(["name", "description"]),
|
|
29742
29825
|
repository: /* @__PURE__ */ new Set(["description"]),
|
|
@@ -30257,7 +30340,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30257
30340
|
const tree = resolveTreeRevision(root, revision);
|
|
30258
30341
|
const listing = gitBuffer(root, ["ls-tree", "-r", "-z", "--name-only", tree]).toString("utf8");
|
|
30259
30342
|
const paths = listing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
30260
|
-
const shadow = mkdtempSync(
|
|
30343
|
+
const shadow = mkdtempSync(join23(tmpdir(), "kxm-permission-base-"));
|
|
30261
30344
|
const shadowResolved = resolve17(shadow);
|
|
30262
30345
|
const shadowMembersDir = `.kxm-shadow-members-${createHash12("sha256").update(shadowResolved, "utf8").digest("hex").slice(0, 8)}`;
|
|
30263
30346
|
try {
|
|
@@ -30271,7 +30354,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30271
30354
|
message: "Git tree entry contains a traversal or non-portable segment"
|
|
30272
30355
|
}]);
|
|
30273
30356
|
}
|
|
30274
|
-
const absolute =
|
|
30357
|
+
const absolute = join23(shadowResolved, ...segments);
|
|
30275
30358
|
const resolved = resolve17(absolute);
|
|
30276
30359
|
if (!resolved.startsWith(`${shadowResolved}${sep3}`)) {
|
|
30277
30360
|
throw new VnextConfigError([{
|
|
@@ -30282,11 +30365,11 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30282
30365
|
}]);
|
|
30283
30366
|
}
|
|
30284
30367
|
const content = gitBuffer(root, ["cat-file", "blob", `${tree}:${path4}`]);
|
|
30285
|
-
|
|
30286
|
-
|
|
30368
|
+
mkdirSync17(dirname14(absolute), { recursive: true });
|
|
30369
|
+
writeFileSync16(absolute, content);
|
|
30287
30370
|
}
|
|
30288
30371
|
initShadowGitRoot(shadowResolved);
|
|
30289
|
-
const baseProjectFile =
|
|
30372
|
+
const baseProjectFile = join23(shadowResolved, ".kxm", "project.yaml");
|
|
30290
30373
|
let baseProject;
|
|
30291
30374
|
try {
|
|
30292
30375
|
baseProject = loadBaseProjectDeclarations(baseProjectFile);
|
|
@@ -30317,7 +30400,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30317
30400
|
}
|
|
30318
30401
|
const boundPath = options.repositoryBindings?.[member.repositoryId];
|
|
30319
30402
|
const memberWorktree = boundPath ? resolve17(boundPath) : member.pathHint ? resolve17(root, ...member.pathHint.split("/")) : void 0;
|
|
30320
|
-
if (!memberWorktree || !
|
|
30403
|
+
if (!memberWorktree || !existsSync20(memberWorktree)) {
|
|
30321
30404
|
if (member.required === false) continue;
|
|
30322
30405
|
throw new VnextConfigError([{
|
|
30323
30406
|
phase: "discovery",
|
|
@@ -30364,7 +30447,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30364
30447
|
const memberTree = git(memberWorktree, ["rev-parse", "--verify", "--quiet", `${pinnedCommit}^{tree}`]).trim();
|
|
30365
30448
|
const memberListing = gitBuffer(memberWorktree, ["ls-tree", "-r", "-z", "--name-only", memberTree]).toString("utf8");
|
|
30366
30449
|
const memberPaths = memberListing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
30367
|
-
const memberShadowRoot =
|
|
30450
|
+
const memberShadowRoot = join23(shadowResolved, shadowMembersDir, member.repositoryId);
|
|
30368
30451
|
if (!resolve17(memberShadowRoot).startsWith(`${resolve17(shadowResolved, shadowMembersDir)}${sep3}`)) {
|
|
30369
30452
|
throw new VnextConfigError([{
|
|
30370
30453
|
phase: "path",
|
|
@@ -30378,14 +30461,14 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30378
30461
|
if (segments.some((segment) => segment === "" || segment === "." || segment === ".." || /[\\:]/.test(segment))) {
|
|
30379
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" }]);
|
|
30380
30463
|
}
|
|
30381
|
-
const absolute =
|
|
30464
|
+
const absolute = join23(memberShadowRoot, ...segments);
|
|
30382
30465
|
const resolved = resolve17(absolute);
|
|
30383
30466
|
if (!resolved.startsWith(`${resolve17(memberShadowRoot)}${sep3}`)) {
|
|
30384
30467
|
throw new VnextConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path4, message: "member Git tree entry escapes the shadow root" }]);
|
|
30385
30468
|
}
|
|
30386
30469
|
const content = gitBuffer(memberWorktree, ["cat-file", "blob", `${memberTree}:${path4}`]);
|
|
30387
|
-
|
|
30388
|
-
|
|
30470
|
+
mkdirSync17(dirname14(absolute), { recursive: true });
|
|
30471
|
+
writeFileSync16(absolute, content);
|
|
30389
30472
|
}
|
|
30390
30473
|
initShadowGitRoot(memberShadowRoot);
|
|
30391
30474
|
shadowBindings[member.repositoryId] = memberShadowRoot;
|
|
@@ -30399,15 +30482,15 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30399
30482
|
throw error;
|
|
30400
30483
|
}
|
|
30401
30484
|
} finally {
|
|
30402
|
-
|
|
30485
|
+
rmSync7(shadow, { recursive: true, force: true });
|
|
30403
30486
|
}
|
|
30404
30487
|
}
|
|
30405
30488
|
function portableMemberPathHint(pathHint) {
|
|
30406
30489
|
return pathHint !== "." && vnextPortablePath(pathHint);
|
|
30407
30490
|
}
|
|
30408
30491
|
function loadBaseProjectDeclarations(projectFile) {
|
|
30409
|
-
if (!
|
|
30410
|
-
const value = parseRestrictedYaml2(
|
|
30492
|
+
if (!existsSync20(projectFile)) return [];
|
|
30493
|
+
const value = parseRestrictedYaml2(readFileSync20(projectFile, "utf8"), ".kxm/project.yaml");
|
|
30411
30494
|
const repositories = Array.isArray(value?.repositories) ? value.repositories : [];
|
|
30412
30495
|
const members = [];
|
|
30413
30496
|
for (const entry of repositories) {
|
|
@@ -30499,7 +30582,7 @@ function writeDurableNew(file, bytes, mode) {
|
|
|
30499
30582
|
let descriptor;
|
|
30500
30583
|
try {
|
|
30501
30584
|
descriptor = openSync2(file, "wx", mode);
|
|
30502
|
-
|
|
30585
|
+
writeFileSync17(descriptor, bytes);
|
|
30503
30586
|
fsyncSync2(descriptor);
|
|
30504
30587
|
closeSync2(descriptor);
|
|
30505
30588
|
descriptor = void 0;
|
|
@@ -30510,13 +30593,13 @@ function writeDurableNew(file, bytes, mode) {
|
|
|
30510
30593
|
} finally {
|
|
30511
30594
|
if (descriptor !== void 0) closeSync2(descriptor);
|
|
30512
30595
|
}
|
|
30513
|
-
syncDirectory2(
|
|
30596
|
+
syncDirectory2(dirname15(file));
|
|
30514
30597
|
}
|
|
30515
30598
|
function writeDurable(file, bytes, mode) {
|
|
30516
30599
|
let descriptor;
|
|
30517
30600
|
try {
|
|
30518
30601
|
descriptor = openSync2(file, "w", mode);
|
|
30519
|
-
|
|
30602
|
+
writeFileSync17(descriptor, bytes);
|
|
30520
30603
|
fsyncSync2(descriptor);
|
|
30521
30604
|
closeSync2(descriptor);
|
|
30522
30605
|
descriptor = void 0;
|
|
@@ -30527,7 +30610,7 @@ function writeDurable(file, bytes, mode) {
|
|
|
30527
30610
|
} finally {
|
|
30528
30611
|
if (descriptor !== void 0) closeSync2(descriptor);
|
|
30529
30612
|
}
|
|
30530
|
-
syncDirectory2(
|
|
30613
|
+
syncDirectory2(dirname15(file));
|
|
30531
30614
|
}
|
|
30532
30615
|
function sameHostPath3(left, right) {
|
|
30533
30616
|
const first = resolve18(left);
|
|
@@ -30535,45 +30618,45 @@ function sameHostPath3(left, right) {
|
|
|
30535
30618
|
return process.platform === "win32" ? first.toLocaleLowerCase("en-US") === second.toLocaleLowerCase("en-US") : first === second;
|
|
30536
30619
|
}
|
|
30537
30620
|
function transactionRoot(projectRoot) {
|
|
30538
|
-
return
|
|
30621
|
+
return join24(resolve18(projectRoot), TRANSACTION_NAME);
|
|
30539
30622
|
}
|
|
30540
30623
|
function operationFile(projectRoot) {
|
|
30541
|
-
return
|
|
30624
|
+
return join24(transactionRoot(projectRoot), OPERATION_FILE);
|
|
30542
30625
|
}
|
|
30543
30626
|
function targetFile(projectRoot, portablePath2) {
|
|
30544
|
-
return
|
|
30627
|
+
return join24(transactionRoot(projectRoot), "targets", ...portablePath2.split("/"));
|
|
30545
30628
|
}
|
|
30546
30629
|
function shadowRoot(projectRoot) {
|
|
30547
|
-
return
|
|
30630
|
+
return join24(transactionRoot(projectRoot), "shadow");
|
|
30548
30631
|
}
|
|
30549
30632
|
function backupFile(projectRoot, portablePath2) {
|
|
30550
|
-
return
|
|
30633
|
+
return join24(transactionRoot(projectRoot), "backups", ...portablePath2.split("/"));
|
|
30551
30634
|
}
|
|
30552
30635
|
function portableManagedPath(path4) {
|
|
30553
|
-
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);
|
|
30554
30637
|
}
|
|
30555
30638
|
function readRegularBounded(file, label) {
|
|
30556
30639
|
const stat = lstatSync7(file);
|
|
30557
30640
|
if (stat.isSymbolicLink() || !stat.isFile()) fail3("repair_file_invalid", label, "managed file must be a regular file, not a link or directory", "path");
|
|
30558
30641
|
if (stat.size > MAX_MANAGED_FILE_BYTES) fail3("repair_file_too_large", label, `managed file exceeds ${MAX_MANAGED_FILE_BYTES} bytes`, "parse");
|
|
30559
|
-
return
|
|
30642
|
+
return readFileSync21(file);
|
|
30560
30643
|
}
|
|
30561
30644
|
function readOptionalManaged(projectRoot, path4) {
|
|
30562
|
-
const file =
|
|
30563
|
-
if (!
|
|
30564
|
-
let parent =
|
|
30645
|
+
const file = join24(projectRoot, ...path4.split("/"));
|
|
30646
|
+
if (!existsSync21(file)) return void 0;
|
|
30647
|
+
let parent = dirname15(file);
|
|
30565
30648
|
const boundary = resolve18(projectRoot);
|
|
30566
30649
|
while (parent !== boundary) {
|
|
30567
30650
|
const stat = lstatSync7(parent);
|
|
30568
30651
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_parent_invalid", path4, "managed file parents must be regular directories", "path");
|
|
30569
|
-
parent =
|
|
30652
|
+
parent = dirname15(parent);
|
|
30570
30653
|
}
|
|
30571
30654
|
return readRegularBounded(file, path4);
|
|
30572
30655
|
}
|
|
30573
30656
|
function readProjectAndProvenance(projectRoot, schemasDir) {
|
|
30574
|
-
const projectFile =
|
|
30575
|
-
const provenanceFile =
|
|
30576
|
-
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;
|
|
30577
30660
|
const projectBytes = readOptionalManaged(projectRoot, ".kxm/project.yaml");
|
|
30578
30661
|
const provenanceBytes = readOptionalManaged(projectRoot, VNEXT_TEMPLATE_PROVENANCE_PATH);
|
|
30579
30662
|
if (!projectBytes || !provenanceBytes) return void 0;
|
|
@@ -30737,14 +30820,14 @@ function operationPlanSha(operation) {
|
|
|
30737
30820
|
function writeOperation(projectRoot, operation) {
|
|
30738
30821
|
const root = transactionRoot(projectRoot);
|
|
30739
30822
|
const file = operationFile(projectRoot);
|
|
30740
|
-
const temporary =
|
|
30823
|
+
const temporary = join24(root, `.operation-${operation.operationId}-${randomUUID10()}.tmp`);
|
|
30741
30824
|
try {
|
|
30742
30825
|
writeDurableNew(temporary, Buffer.from(`${JSON.stringify(operation, null, 2)}
|
|
30743
30826
|
`, "utf8"), 384);
|
|
30744
|
-
|
|
30827
|
+
renameSync6(temporary, file);
|
|
30745
30828
|
syncDirectory2(root);
|
|
30746
30829
|
} finally {
|
|
30747
|
-
|
|
30830
|
+
rmSync8(temporary, { force: true });
|
|
30748
30831
|
}
|
|
30749
30832
|
}
|
|
30750
30833
|
function updatePhase(projectRoot, operation, phase) {
|
|
@@ -30754,11 +30837,11 @@ function updatePhase(projectRoot, operation, phase) {
|
|
|
30754
30837
|
}
|
|
30755
30838
|
function readOperation(projectRoot, schemasDir) {
|
|
30756
30839
|
const root = transactionRoot(projectRoot);
|
|
30757
|
-
if (!
|
|
30840
|
+
if (!existsSync21(root)) return void 0;
|
|
30758
30841
|
const stat = lstatSync7(root);
|
|
30759
30842
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("init_transaction_invalid", TRANSACTION_NAME, "initialization transaction must be a regular directory", "path");
|
|
30760
30843
|
const file = operationFile(projectRoot);
|
|
30761
|
-
if (!
|
|
30844
|
+
if (!existsSync21(file)) {
|
|
30762
30845
|
const entries = readdirSync7(root, { withFileTypes: true });
|
|
30763
30846
|
const recoverable = entries.every((entry) => entry.isFile() && /^\.operation-op_[a-f0-9]{32}-[a-f0-9-]{36}\.tmp$/.test(entry.name));
|
|
30764
30847
|
if (recoverable) return void 0;
|
|
@@ -30781,20 +30864,20 @@ function readOperation(projectRoot, schemasDir) {
|
|
|
30781
30864
|
seen.add(folded);
|
|
30782
30865
|
prior = entry.path;
|
|
30783
30866
|
}
|
|
30784
|
-
if (!
|
|
30867
|
+
if (!isAbsolute7(operation.projectRoot)) fail3("init_transaction_project_root_invalid", TRANSACTION_NAME, "operation project root must be absolute", "path");
|
|
30785
30868
|
validateOperationIntent(projectRoot, operation);
|
|
30786
30869
|
return operation;
|
|
30787
30870
|
}
|
|
30788
30871
|
function hasVnextInitTransaction(projectRoot) {
|
|
30789
|
-
return
|
|
30872
|
+
return existsSync21(transactionRoot(projectRoot));
|
|
30790
30873
|
}
|
|
30791
30874
|
function readTarget(projectRoot, path4) {
|
|
30792
|
-
return readOptionalManaged(
|
|
30875
|
+
return readOptionalManaged(join24(transactionRoot(projectRoot), "targets"), path4);
|
|
30793
30876
|
}
|
|
30794
30877
|
function writeTarget(projectRoot, path4, bytes) {
|
|
30795
30878
|
if (bytes.byteLength > MAX_MANAGED_FILE_BYTES) fail3("template_target_too_large", path4, `target exceeds ${MAX_MANAGED_FILE_BYTES} bytes`);
|
|
30796
30879
|
const file = targetFile(projectRoot, path4);
|
|
30797
|
-
|
|
30880
|
+
mkdirSync18(dirname15(file), { recursive: true, mode: 448 });
|
|
30798
30881
|
writeDurableNew(file, bytes, 384);
|
|
30799
30882
|
}
|
|
30800
30883
|
function writeAndVerifyBackups(projectRoot, operation) {
|
|
@@ -30806,7 +30889,7 @@ function writeAndVerifyBackups(projectRoot, operation) {
|
|
|
30806
30889
|
fail3("repair_preimage_changed", entry.path, "destination changed before transaction preparation; local bytes were preserved");
|
|
30807
30890
|
}
|
|
30808
30891
|
const file = backupFile(projectRoot, entry.path);
|
|
30809
|
-
|
|
30892
|
+
mkdirSync18(dirname15(file), { recursive: true, mode: 448 });
|
|
30810
30893
|
writeDurableNew(file, current, 384);
|
|
30811
30894
|
}
|
|
30812
30895
|
}
|
|
@@ -30821,7 +30904,7 @@ function writeKnownBackups(projectRoot, operation) {
|
|
|
30821
30904
|
fail3("init_transaction_backup_source_invalid", entry.path, "supported source template cannot reproduce the pinned preimage");
|
|
30822
30905
|
}
|
|
30823
30906
|
const file = backupFile(projectRoot, entry.path);
|
|
30824
|
-
|
|
30907
|
+
mkdirSync18(dirname15(file), { recursive: true, mode: 448 });
|
|
30825
30908
|
writeDurableNew(file, bytes, 384);
|
|
30826
30909
|
}
|
|
30827
30910
|
}
|
|
@@ -30829,7 +30912,7 @@ function verifyBackups(projectRoot, operation) {
|
|
|
30829
30912
|
if (operation.kind !== "repair") return;
|
|
30830
30913
|
for (const entry of operation.files) {
|
|
30831
30914
|
if (entry.observedSha256 === null) continue;
|
|
30832
|
-
const bytes = readOptionalManaged(
|
|
30915
|
+
const bytes = readOptionalManaged(join24(transactionRoot(projectRoot), "backups"), entry.path);
|
|
30833
30916
|
if (!bytes || vnextContentSha256(bytes) !== entry.observedSha256) {
|
|
30834
30917
|
fail3("init_transaction_backup_invalid", entry.path, "pinned preimage backup is missing or corrupt");
|
|
30835
30918
|
}
|
|
@@ -30863,10 +30946,10 @@ function sourceConfigFiles(projectRoot) {
|
|
|
30863
30946
|
".kxm/repo/repo.yaml",
|
|
30864
30947
|
".kxm/repo/env.yaml"
|
|
30865
30948
|
];
|
|
30866
|
-
const files = fixed.filter((path4) =>
|
|
30949
|
+
const files = fixed.filter((path4) => existsSync21(join24(projectRoot, ...path4.split("/"))));
|
|
30867
30950
|
for (const directory of ["agents", "models", "workflows"]) {
|
|
30868
|
-
const absolute =
|
|
30869
|
-
if (!
|
|
30951
|
+
const absolute = join24(projectRoot, ".kxm", directory);
|
|
30952
|
+
if (!existsSync21(absolute)) continue;
|
|
30870
30953
|
const stat = lstatSync7(absolute);
|
|
30871
30954
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_directory_invalid", `.kxm/${directory}`, "configuration directory must be regular", "path");
|
|
30872
30955
|
for (const entry of readdirSync7(absolute, { withFileTypes: true })) {
|
|
@@ -30888,23 +30971,23 @@ function absoluteMemberBindings(projectRoot, project, explicit = {}) {
|
|
|
30888
30971
|
if (repository.role !== "member" || typeof repository.id !== "string" || Object.hasOwn(bindings, repository.id)) continue;
|
|
30889
30972
|
if (typeof repository.pathHint === "string") {
|
|
30890
30973
|
const candidate2 = resolve18(projectRoot, ...repository.pathHint.split("/"));
|
|
30891
|
-
if (
|
|
30974
|
+
if (existsSync21(candidate2)) bindings[repository.id] = candidate2;
|
|
30892
30975
|
}
|
|
30893
30976
|
}
|
|
30894
30977
|
return bindings;
|
|
30895
30978
|
}
|
|
30896
30979
|
function prepareShadow(projectRoot, operation, options) {
|
|
30897
30980
|
const shadow = shadowRoot(projectRoot);
|
|
30898
|
-
|
|
30981
|
+
mkdirSync18(shadow, { recursive: true, mode: 448 });
|
|
30899
30982
|
let total = 0;
|
|
30900
30983
|
if (operation.kind === "repair") {
|
|
30901
30984
|
for (const path4 of sourceConfigFiles(projectRoot)) {
|
|
30902
30985
|
const bytes = readOptionalManaged(projectRoot, path4);
|
|
30903
30986
|
if (!bytes) fail3("repair_snapshot_file_missing", path4, "configuration changed during shadow preparation");
|
|
30904
30987
|
total += bytes.byteLength;
|
|
30905
|
-
const source =
|
|
30906
|
-
const destination =
|
|
30907
|
-
|
|
30988
|
+
const source = join24(projectRoot, ...path4.split("/"));
|
|
30989
|
+
const destination = join24(shadow, ...path4.split("/"));
|
|
30990
|
+
mkdirSync18(dirname15(destination), { recursive: true, mode: 448 });
|
|
30908
30991
|
writeDurableNew(destination, bytes, lstatSync7(source).mode & 511);
|
|
30909
30992
|
if (total > MAX_MANAGED_TOTAL_BYTES) fail3("repair_snapshot_too_large", ".kxm", `configuration snapshot exceeds ${MAX_MANAGED_TOTAL_BYTES} bytes`, "parse");
|
|
30910
30993
|
}
|
|
@@ -30912,12 +30995,12 @@ function prepareShadow(projectRoot, operation, options) {
|
|
|
30912
30995
|
for (const entry of operation.files) {
|
|
30913
30996
|
const bytes = readTarget(projectRoot, entry.path);
|
|
30914
30997
|
if (!bytes) fail3("init_transaction_target_missing", entry.path, "pinned target artifact is missing");
|
|
30915
|
-
const destination =
|
|
30916
|
-
|
|
30917
|
-
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;
|
|
30918
31001
|
writeDurable(destination, bytes, mode);
|
|
30919
31002
|
}
|
|
30920
|
-
const project = parseRestrictedYaml2(
|
|
31003
|
+
const project = parseRestrictedYaml2(readFileSync21(join24(shadow, ".kxm", "project.yaml")), ".kxm/project.yaml");
|
|
30921
31004
|
const bound = absoluteMemberBindings(projectRoot, project, options.repositoryBindings);
|
|
30922
31005
|
loadVnextProject(shadow, { ...loaderOptions(options), repositoryBindings: bound });
|
|
30923
31006
|
const provenance = readProjectAndProvenance(shadow, options.schemasDir)?.provenance;
|
|
@@ -30955,8 +31038,8 @@ function prepareOperation(projectRoot, operation, rendered, options) {
|
|
|
30955
31038
|
const transaction = transactionRoot(projectRoot);
|
|
30956
31039
|
validateOperationRecord(operation, options.schemasDir);
|
|
30957
31040
|
validateOperationIntent(projectRoot, operation);
|
|
30958
|
-
if (
|
|
30959
|
-
|
|
31041
|
+
if (existsSync21(transaction)) fail3("init_transaction_exists", TRANSACTION_NAME, "an initialization transaction already exists and must be resumed");
|
|
31042
|
+
mkdirSync18(transaction, { mode: 448 });
|
|
30960
31043
|
syncDirectory2(projectRoot);
|
|
30961
31044
|
writeOperation(projectRoot, operation);
|
|
30962
31045
|
try {
|
|
@@ -30972,7 +31055,7 @@ function prepareOperation(projectRoot, operation, rendered, options) {
|
|
|
30972
31055
|
syncTreeDirectories(transaction);
|
|
30973
31056
|
return updatePhase(projectRoot, operation, "prepared");
|
|
30974
31057
|
} catch (error) {
|
|
30975
|
-
|
|
31058
|
+
rmSync8(transaction, { recursive: true, force: true });
|
|
30976
31059
|
throw error;
|
|
30977
31060
|
}
|
|
30978
31061
|
}
|
|
@@ -30981,21 +31064,21 @@ function ensureDestinationParents(projectRoot, path4) {
|
|
|
30981
31064
|
const segments = path4.split("/").slice(0, -1);
|
|
30982
31065
|
let current = boundary;
|
|
30983
31066
|
for (const segment of segments) {
|
|
30984
|
-
current =
|
|
30985
|
-
if (!
|
|
31067
|
+
current = join24(current, segment);
|
|
31068
|
+
if (!existsSync21(current)) mkdirSync18(current, { mode: 448 });
|
|
30986
31069
|
const stat = lstatSync7(current);
|
|
30987
31070
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_destination_parent_invalid", path4, "destination parent must be a regular directory", "path");
|
|
30988
31071
|
}
|
|
30989
31072
|
}
|
|
30990
31073
|
function destinationSha(projectRoot, path4) {
|
|
30991
|
-
const file =
|
|
30992
|
-
if (!
|
|
31074
|
+
const file = join24(projectRoot, ...path4.split("/"));
|
|
31075
|
+
if (!existsSync21(file)) return void 0;
|
|
30993
31076
|
return vnextContentSha256(readRegularBounded(file, path4));
|
|
30994
31077
|
}
|
|
30995
31078
|
function requireConditionalLinkSupport(directory, operationId, path4) {
|
|
30996
31079
|
const nonce = randomUUID10();
|
|
30997
|
-
const source =
|
|
30998
|
-
const target =
|
|
31080
|
+
const source = join24(directory, `.kxm-repair-${operationId}-${nonce}.link-source`);
|
|
31081
|
+
const target = join24(directory, `.kxm-repair-${operationId}-${nonce}.link-target`);
|
|
30999
31082
|
try {
|
|
31000
31083
|
writeDurableNew(source, Buffer.from("kxm-link-probe\n", "utf8"), 384);
|
|
31001
31084
|
try {
|
|
@@ -31004,25 +31087,25 @@ function requireConditionalLinkSupport(directory, operationId, path4) {
|
|
|
31004
31087
|
fail3("repair_hard_link_unsupported", path4, "filesystem does not support the conditional hard-link install required for safe repair");
|
|
31005
31088
|
}
|
|
31006
31089
|
} finally {
|
|
31007
|
-
|
|
31008
|
-
|
|
31090
|
+
rmSync8(target, { force: true });
|
|
31091
|
+
rmSync8(source, { force: true });
|
|
31009
31092
|
syncDirectory2(directory);
|
|
31010
31093
|
}
|
|
31011
31094
|
}
|
|
31012
31095
|
function atomicInstallTarget(projectRoot, operation, entry) {
|
|
31013
|
-
const destination =
|
|
31096
|
+
const destination = join24(projectRoot, ...entry.path.split("/"));
|
|
31014
31097
|
ensureDestinationParents(projectRoot, entry.path);
|
|
31015
|
-
const directory =
|
|
31098
|
+
const directory = dirname15(destination);
|
|
31016
31099
|
const temporaryPrefix = `.kxm-repair-${operation.operationId}-`;
|
|
31017
31100
|
const pathKey = vnextContentSha256(entry.path).slice("sha256:".length, "sha256:".length + 16);
|
|
31018
|
-
const displaced =
|
|
31019
|
-
if (
|
|
31101
|
+
const displaced = join24(directory, `${temporaryPrefix}${pathKey}.preimage`);
|
|
31102
|
+
if (existsSync21(displaced)) {
|
|
31020
31103
|
const stat = lstatSync7(displaced);
|
|
31021
31104
|
if (stat.isSymbolicLink() || !stat.isFile()) fail3("repair_preimage_temporary_invalid", entry.path, "stale displaced preimage is not a regular file", "path");
|
|
31022
|
-
if (entry.observedSha256 === null || vnextContentSha256(
|
|
31105
|
+
if (entry.observedSha256 === null || vnextContentSha256(readFileSync21(displaced)) !== entry.observedSha256) {
|
|
31023
31106
|
fail3("repair_preimage_temporary_mismatch", entry.path, "stale displaced preimage does not match the pinned operation");
|
|
31024
31107
|
}
|
|
31025
|
-
if (!
|
|
31108
|
+
if (!existsSync21(destination)) {
|
|
31026
31109
|
try {
|
|
31027
31110
|
linkSync(displaced, destination);
|
|
31028
31111
|
} catch {
|
|
@@ -31030,14 +31113,14 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31030
31113
|
}
|
|
31031
31114
|
syncDirectory2(directory);
|
|
31032
31115
|
}
|
|
31033
|
-
|
|
31116
|
+
rmSync8(displaced, { force: true });
|
|
31034
31117
|
syncDirectory2(directory);
|
|
31035
31118
|
}
|
|
31036
31119
|
for (const candidate of readdirSync7(directory, { withFileTypes: true })) {
|
|
31037
31120
|
const owned = candidate.name.startsWith(temporaryPrefix) && (candidate.name.endsWith(".tmp") || candidate.name.endsWith(".link-source") || candidate.name.endsWith(".link-target"));
|
|
31038
31121
|
if (!owned) continue;
|
|
31039
31122
|
if (!candidate.isFile()) fail3("repair_temporary_invalid", entry.path, "stale operation temporary is not a regular file", "path");
|
|
31040
|
-
|
|
31123
|
+
rmSync8(join24(directory, candidate.name), { force: true });
|
|
31041
31124
|
}
|
|
31042
31125
|
const current = destinationSha(projectRoot, entry.path);
|
|
31043
31126
|
if (current === entry.targetSha256) return;
|
|
@@ -31047,22 +31130,22 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31047
31130
|
requireConditionalLinkSupport(directory, operation.operationId, entry.path);
|
|
31048
31131
|
const bytes = readTarget(projectRoot, entry.path);
|
|
31049
31132
|
if (!bytes) fail3("init_transaction_target_missing", entry.path, "pinned target artifact is missing");
|
|
31050
|
-
const temporary =
|
|
31051
|
-
const mode =
|
|
31133
|
+
const temporary = join24(directory, `${temporaryPrefix}${randomUUID10()}.tmp`);
|
|
31134
|
+
const mode = existsSync21(destination) ? lstatSync7(destination).mode & 511 : 420;
|
|
31052
31135
|
try {
|
|
31053
31136
|
writeDurableNew(temporary, bytes, mode);
|
|
31054
31137
|
if (entry.observedSha256 !== null) {
|
|
31055
|
-
|
|
31138
|
+
renameSync6(destination, displaced);
|
|
31056
31139
|
syncDirectory2(directory);
|
|
31057
|
-
if (vnextContentSha256(
|
|
31058
|
-
if (!
|
|
31140
|
+
if (vnextContentSha256(readFileSync21(displaced)) !== entry.observedSha256) {
|
|
31141
|
+
if (!existsSync21(destination)) {
|
|
31059
31142
|
try {
|
|
31060
31143
|
linkSync(displaced, destination);
|
|
31061
31144
|
} catch {
|
|
31062
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");
|
|
31063
31146
|
}
|
|
31064
31147
|
syncDirectory2(directory);
|
|
31065
|
-
|
|
31148
|
+
rmSync8(displaced, { force: true });
|
|
31066
31149
|
syncDirectory2(directory);
|
|
31067
31150
|
}
|
|
31068
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");
|
|
@@ -31071,7 +31154,7 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31071
31154
|
try {
|
|
31072
31155
|
linkSync(temporary, destination);
|
|
31073
31156
|
} catch {
|
|
31074
|
-
if (!
|
|
31157
|
+
if (!existsSync21(destination) && existsSync21(displaced)) {
|
|
31075
31158
|
try {
|
|
31076
31159
|
linkSync(displaced, destination);
|
|
31077
31160
|
} catch {
|
|
@@ -31079,26 +31162,26 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31079
31162
|
}
|
|
31080
31163
|
syncDirectory2(directory);
|
|
31081
31164
|
}
|
|
31082
|
-
|
|
31165
|
+
rmSync8(displaced, { force: true });
|
|
31083
31166
|
syncDirectory2(directory);
|
|
31084
31167
|
fail3("repair_destination_recreated", entry.path, "destination was recreated concurrently or conditional install is unsupported; pinned target was not installed");
|
|
31085
31168
|
}
|
|
31086
31169
|
syncDirectory2(directory);
|
|
31087
|
-
|
|
31088
|
-
|
|
31170
|
+
rmSync8(temporary, { force: true });
|
|
31171
|
+
rmSync8(displaced, { force: true });
|
|
31089
31172
|
syncDirectory2(directory);
|
|
31090
31173
|
} finally {
|
|
31091
|
-
|
|
31174
|
+
rmSync8(temporary, { force: true });
|
|
31092
31175
|
}
|
|
31093
31176
|
if (destinationSha(projectRoot, entry.path) !== entry.targetSha256) fail3("repair_install_verification_failed", entry.path, "installed target hash does not match the pinned operation");
|
|
31094
31177
|
}
|
|
31095
31178
|
function installedCreateMatches(projectRoot, operation) {
|
|
31096
|
-
const configRoot =
|
|
31097
|
-
if (!
|
|
31179
|
+
const configRoot = join24(projectRoot, ".kxm");
|
|
31180
|
+
if (!existsSync21(configRoot)) return false;
|
|
31098
31181
|
const actual = [];
|
|
31099
31182
|
const visit2 = (directory) => {
|
|
31100
31183
|
for (const entry of readdirSync7(directory, { withFileTypes: true })) {
|
|
31101
|
-
const absolute =
|
|
31184
|
+
const absolute = join24(directory, entry.name);
|
|
31102
31185
|
if (entry.isSymbolicLink()) fail3("create_resume_link", relativeConfigPath(projectRoot, absolute), "created configuration must not contain links", "path");
|
|
31103
31186
|
if (entry.isDirectory()) visit2(absolute);
|
|
31104
31187
|
else if (entry.isFile()) actual.push(relativeConfigPath(projectRoot, absolute));
|
|
@@ -31114,12 +31197,12 @@ function relativeConfigPath(projectRoot, file) {
|
|
|
31114
31197
|
return relative4(resolve18(projectRoot), file).replaceAll("\\", "/");
|
|
31115
31198
|
}
|
|
31116
31199
|
function syncTreeDirectories(root) {
|
|
31117
|
-
if (!
|
|
31200
|
+
if (!existsSync21(root)) return;
|
|
31118
31201
|
const directories = [];
|
|
31119
31202
|
const visit2 = (directory) => {
|
|
31120
31203
|
directories.push(directory);
|
|
31121
31204
|
for (const entry of readdirSync7(directory, { withFileTypes: true })) {
|
|
31122
|
-
if (entry.isDirectory()) visit2(
|
|
31205
|
+
if (entry.isDirectory()) visit2(join24(directory, entry.name));
|
|
31123
31206
|
}
|
|
31124
31207
|
};
|
|
31125
31208
|
visit2(root);
|
|
@@ -31127,13 +31210,13 @@ function syncTreeDirectories(root) {
|
|
|
31127
31210
|
}
|
|
31128
31211
|
function rebuildCreateShadow(projectRoot, operation, options) {
|
|
31129
31212
|
const shadow = shadowRoot(projectRoot);
|
|
31130
|
-
|
|
31213
|
+
rmSync8(shadow, { recursive: true, force: true });
|
|
31131
31214
|
prepareShadow(projectRoot, operation, options);
|
|
31132
31215
|
const stat = lstatSync7(shadow);
|
|
31133
31216
|
if (stat.isSymbolicLink() || !stat.isDirectory() || !installedCreateMatches(shadow, operation)) {
|
|
31134
31217
|
fail3("create_shadow_invalid", TRANSACTION_NAME, "reconstructed create shadow does not exactly match pinned target files", "path");
|
|
31135
31218
|
}
|
|
31136
|
-
syncTreeDirectories(
|
|
31219
|
+
syncTreeDirectories(join24(shadow, ".kxm"));
|
|
31137
31220
|
}
|
|
31138
31221
|
function applyOperation(projectRoot, original, options, resumed) {
|
|
31139
31222
|
assertNoRegisteredGates(options);
|
|
@@ -31143,10 +31226,10 @@ function applyOperation(projectRoot, original, options, resumed) {
|
|
|
31143
31226
|
verifyBackups(projectRoot, operation);
|
|
31144
31227
|
operation = updatePhase(projectRoot, operation, "applying");
|
|
31145
31228
|
if (operation.kind === "create") {
|
|
31146
|
-
const destination =
|
|
31147
|
-
if (!
|
|
31229
|
+
const destination = join24(projectRoot, ".kxm");
|
|
31230
|
+
if (!existsSync21(destination)) {
|
|
31148
31231
|
rebuildCreateShadow(projectRoot, operation, effectiveOptions);
|
|
31149
|
-
|
|
31232
|
+
renameSync6(join24(shadowRoot(projectRoot), ".kxm"), destination);
|
|
31150
31233
|
syncDirectory2(projectRoot);
|
|
31151
31234
|
} else if (!installedCreateMatches(projectRoot, operation)) {
|
|
31152
31235
|
fail3("create_resume_conflict", ".kxm", "existing project configuration does not match the pinned create operation");
|
|
@@ -31173,7 +31256,7 @@ function applyOperation(projectRoot, original, options, resumed) {
|
|
|
31173
31256
|
operation = updatePhase(projectRoot, operation, "verified");
|
|
31174
31257
|
if (options.testFaultAt === "verified") throw new Error("injected init fault after verification");
|
|
31175
31258
|
const files = operation.files.map((entry) => entry.path);
|
|
31176
|
-
syncTreeDirectories(
|
|
31259
|
+
syncTreeDirectories(join24(projectRoot, ".kxm"));
|
|
31177
31260
|
return { kind: operation.kind, resumed, bundle, files };
|
|
31178
31261
|
}
|
|
31179
31262
|
function prepareAndApplyVnextCreate(projectRoot, rendered, options = {}) {
|
|
@@ -31288,7 +31371,7 @@ function finishPreparingOperation(projectRoot, operation, options) {
|
|
|
31288
31371
|
const rendered = rendererForOperation(operation);
|
|
31289
31372
|
if (!rendered) fail3("init_transaction_renderer_unavailable", TRANSACTION_NAME, "this binary cannot reproduce the pinned pre-application target");
|
|
31290
31373
|
for (const directory of ["targets", "backups", "shadow"]) {
|
|
31291
|
-
|
|
31374
|
+
rmSync8(join24(transactionRoot(projectRoot), directory), { recursive: true, force: true });
|
|
31292
31375
|
}
|
|
31293
31376
|
for (const entry of operation.files) {
|
|
31294
31377
|
const bytes = rendered.files.get(entry.path);
|
|
@@ -31307,8 +31390,8 @@ function resumeVnextInitTransaction(projectRoot, options = {}) {
|
|
|
31307
31390
|
let operation = readOperation(projectRoot, options.schemasDir);
|
|
31308
31391
|
if (!operation) {
|
|
31309
31392
|
const root = transactionRoot(projectRoot);
|
|
31310
|
-
if (
|
|
31311
|
-
|
|
31393
|
+
if (existsSync21(root)) {
|
|
31394
|
+
rmSync8(root, { recursive: true, force: true });
|
|
31312
31395
|
syncDirectory2(projectRoot);
|
|
31313
31396
|
}
|
|
31314
31397
|
return void 0;
|
|
@@ -31323,10 +31406,10 @@ function commitVnextInitTransaction(projectRoot, schemasDir) {
|
|
|
31323
31406
|
fail3("init_transaction_not_verified", TRANSACTION_NAME, "initialization transaction cannot commit before installed state is verified");
|
|
31324
31407
|
}
|
|
31325
31408
|
const transaction = transactionRoot(projectRoot);
|
|
31326
|
-
const retired =
|
|
31327
|
-
|
|
31409
|
+
const retired = join24(projectRoot, `${TRANSACTION_NAME}-cleanup-${operation.operationId}-${randomUUID10()}`);
|
|
31410
|
+
renameSync6(transaction, retired);
|
|
31328
31411
|
syncDirectory2(projectRoot);
|
|
31329
|
-
|
|
31412
|
+
rmSync8(retired, { recursive: true, force: true });
|
|
31330
31413
|
syncDirectory2(projectRoot);
|
|
31331
31414
|
}
|
|
31332
31415
|
function inspectVnextInitTransaction(projectRoot, schemasDir) {
|
|
@@ -31432,7 +31515,7 @@ function validateBindingIdentities(bundle, persisted, explicit) {
|
|
|
31432
31515
|
}
|
|
31433
31516
|
function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock) {
|
|
31434
31517
|
const storeOptions = bindingStoreOptions(options);
|
|
31435
|
-
const persisted =
|
|
31518
|
+
const persisted = existsSync22(join25(gitRoot, ".kxm", "project.yaml")) ? readVnextLocalBindings(gitRoot, storeOptions) : void 0;
|
|
31436
31519
|
const repositoryBindings = Object.fromEntries([
|
|
31437
31520
|
...Object.entries(persisted?.repositories ?? {}),
|
|
31438
31521
|
...Object.entries(options.repositoryBindings ?? {})
|
|
@@ -31621,7 +31704,7 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31621
31704
|
const files = [...rendered.files.keys()];
|
|
31622
31705
|
if (options.dryRun) return { action: "planned", plan, projectRoot: gitRoot, files };
|
|
31623
31706
|
if (!mutationLock) throw new Error("project mutation lock is required to create configuration");
|
|
31624
|
-
if (
|
|
31707
|
+
if (existsSync22(join25(gitRoot, ".kxm"))) {
|
|
31625
31708
|
throw new VnextConfigError([initIssue("workspace_changed", ".kxm", "workspace changed after planning; existing .kxm state was not overwritten")]);
|
|
31626
31709
|
}
|
|
31627
31710
|
const created = prepareAndApplyVnextCreate(gitRoot, rendered, transactionOptions);
|
|
@@ -31653,8 +31736,8 @@ function initializeVnextProject(start = process.cwd(), options = {}) {
|
|
|
31653
31736
|
// plugins/kxm/src/vnext-migrate.ts
|
|
31654
31737
|
var import_yaml12 = __toESM(require_dist(), 1);
|
|
31655
31738
|
import { createHash as createHash13 } from "node:crypto";
|
|
31656
|
-
import { chmodSync as chmodSync6, closeSync as closeSync3, existsSync as
|
|
31657
|
-
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";
|
|
31658
31741
|
var MAX_LEGACY_JSON_BYTES = 1024 * 1024;
|
|
31659
31742
|
var MAX_LEGACY_JSON_DEPTH = 32;
|
|
31660
31743
|
var MAX_LEGACY_JSON_NODES = 32768;
|
|
@@ -31823,12 +31906,12 @@ function readVnextLegacySources(root) {
|
|
|
31823
31906
|
throw new VnextConfigError([migrateIssue("discovery", "legacy_source_limit", ".kxm/config", `legacy configuration exceeds ${MAX_LEGACY_SOURCES} files`)]);
|
|
31824
31907
|
}
|
|
31825
31908
|
return files.map((path4) => {
|
|
31826
|
-
const absolute =
|
|
31909
|
+
const absolute = join26(root, ...path4.split("/"));
|
|
31827
31910
|
const stat = lstatSync8(absolute);
|
|
31828
31911
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
31829
31912
|
throw new VnextConfigError([migrateIssue("path", "legacy_source_invalid", path4, "legacy configuration must be a regular file, not a link")]);
|
|
31830
31913
|
}
|
|
31831
|
-
const buffer =
|
|
31914
|
+
const buffer = readFileSync22(absolute);
|
|
31832
31915
|
let text;
|
|
31833
31916
|
try {
|
|
31834
31917
|
text = new TextDecoder("utf-8", { fatal: true }).decode(buffer);
|
|
@@ -32901,11 +32984,11 @@ function planVnextMigration(projectRoot, options = {}) {
|
|
|
32901
32984
|
};
|
|
32902
32985
|
}
|
|
32903
32986
|
function readVnextMigrationDecisions(path4, schemasDir) {
|
|
32904
|
-
if (!
|
|
32987
|
+
if (!existsSync23(path4)) {
|
|
32905
32988
|
throw new VnextConfigError([migrateIssue("discovery", "decisions_missing", path4, "migration decisions file does not exist")]);
|
|
32906
32989
|
}
|
|
32907
32990
|
const registry = new VnextSchemaRegistry(schemasDir);
|
|
32908
|
-
const value = parseRestrictedYaml2(
|
|
32991
|
+
const value = parseRestrictedYaml2(readFileSync22(path4), path4);
|
|
32909
32992
|
const issues = registry.validateMigrationDecision(value, path4);
|
|
32910
32993
|
if (issues.length > 0) throw new VnextConfigError(issues);
|
|
32911
32994
|
return value;
|
|
@@ -32934,19 +33017,19 @@ function writeDurable2(path4, content) {
|
|
|
32934
33017
|
const descriptor = openSync3(temp, "wx", 384);
|
|
32935
33018
|
created = true;
|
|
32936
33019
|
try {
|
|
32937
|
-
|
|
33020
|
+
writeFileSync18(descriptor, content);
|
|
32938
33021
|
fsyncSync3(descriptor);
|
|
32939
33022
|
} finally {
|
|
32940
33023
|
closeSync3(descriptor);
|
|
32941
33024
|
}
|
|
32942
|
-
|
|
33025
|
+
renameSync7(temp, path4);
|
|
32943
33026
|
try {
|
|
32944
33027
|
chmodSync6(path4, 384);
|
|
32945
33028
|
} catch {
|
|
32946
33029
|
}
|
|
32947
|
-
syncDirectory3(
|
|
33030
|
+
syncDirectory3(join26(path4, ".."));
|
|
32948
33031
|
} finally {
|
|
32949
|
-
if (created &&
|
|
33032
|
+
if (created && existsSync23(temp)) rmSync9(temp, { force: true });
|
|
32950
33033
|
}
|
|
32951
33034
|
}
|
|
32952
33035
|
function applyVnextMigration(projectRoot, options = {}) {
|
|
@@ -32956,8 +33039,8 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
32956
33039
|
...options.schemasDir === void 0 ? {} : { schemasDir: options.schemasDir }
|
|
32957
33040
|
};
|
|
32958
33041
|
const execute = (lock) => {
|
|
32959
|
-
const receiptAbsolute =
|
|
32960
|
-
if (
|
|
33042
|
+
const receiptAbsolute = join26(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
|
|
33043
|
+
if (existsSync23(receiptAbsolute)) {
|
|
32961
33044
|
const stat = lstatSync8(receiptAbsolute);
|
|
32962
33045
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
32963
33046
|
throw new VnextConfigError([migrateIssue("path", "migration_receipt_invalid", VNEXT_MIGRATION_RECEIPT_PATH, "migration receipt must be a regular file, not a link")]);
|
|
@@ -33010,7 +33093,7 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33010
33093
|
return { action: "planned", projectRoot: root, files: [], plan: first.plan };
|
|
33011
33094
|
}
|
|
33012
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") }));
|
|
33013
|
-
const collisions = files.filter((file) =>
|
|
33096
|
+
const collisions = files.filter((file) => existsSync23(join26(root, ...file.path.split("/"))));
|
|
33014
33097
|
if (collisions.length > 0) {
|
|
33015
33098
|
throw new VnextConfigError(collisions.map((file) => migrateIssue("semantic", "migration_target_exists", file.path, "target resource already exists; refusing to overwrite")));
|
|
33016
33099
|
}
|
|
@@ -33019,8 +33102,8 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33019
33102
|
const segments = file.path.split("/");
|
|
33020
33103
|
let current = root;
|
|
33021
33104
|
for (const segment of segments.slice(0, -1)) {
|
|
33022
|
-
current =
|
|
33023
|
-
if (!
|
|
33105
|
+
current = join26(current, segment);
|
|
33106
|
+
if (!existsSync23(current)) continue;
|
|
33024
33107
|
const stat = lstatSync8(current);
|
|
33025
33108
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
33026
33109
|
parentIssues.push(migrateIssue("path", "migration_target_parent_invalid", file.path, `migration target parent ${segment} must be a regular directory, not a link`));
|
|
@@ -33036,8 +33119,8 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33036
33119
|
const written = [];
|
|
33037
33120
|
try {
|
|
33038
33121
|
for (const file of files) {
|
|
33039
|
-
const absolute =
|
|
33040
|
-
|
|
33122
|
+
const absolute = join26(root, ...file.path.split("/"));
|
|
33123
|
+
mkdirSync19(join26(absolute, ".."), { recursive: true });
|
|
33041
33124
|
written.push(absolute);
|
|
33042
33125
|
writeDurable2(absolute, file.bytes);
|
|
33043
33126
|
}
|
|
@@ -33071,7 +33154,7 @@ ${bundle.configRevision}`).slice(7, 39)}`,
|
|
|
33071
33154
|
} catch (error) {
|
|
33072
33155
|
for (const absolute of written.reverse()) {
|
|
33073
33156
|
try {
|
|
33074
|
-
|
|
33157
|
+
rmSync9(absolute, { force: true });
|
|
33075
33158
|
} catch {
|
|
33076
33159
|
}
|
|
33077
33160
|
}
|
|
@@ -33083,8 +33166,8 @@ ${bundle.configRevision}`).slice(7, 39)}`,
|
|
|
33083
33166
|
}
|
|
33084
33167
|
function verifyVnextMigration(projectRoot, options = {}) {
|
|
33085
33168
|
const root = migrationGitRoot(projectRoot);
|
|
33086
|
-
const receiptAbsolute =
|
|
33087
|
-
if (!
|
|
33169
|
+
const receiptAbsolute = join26(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
|
|
33170
|
+
if (!existsSync23(receiptAbsolute)) {
|
|
33088
33171
|
return {
|
|
33089
33172
|
ok: false,
|
|
33090
33173
|
projectRoot: root,
|
|
@@ -33132,7 +33215,6 @@ function verifyVnextMigration(projectRoot, options = {}) {
|
|
|
33132
33215
|
|
|
33133
33216
|
// plugins/kxm/src/cli/vnext.ts
|
|
33134
33217
|
var vnextDriveCliSeams = {};
|
|
33135
|
-
var repoRoot3 = resolve20(fileURLToPath4(new URL("../../../../", import.meta.url)));
|
|
33136
33218
|
function initPlanPayload(plan) {
|
|
33137
33219
|
return {
|
|
33138
33220
|
mode: plan.mode,
|
|
@@ -33394,7 +33476,7 @@ async function cmdBackup(runtime, options) {
|
|
|
33394
33476
|
const summary = [
|
|
33395
33477
|
`Created SQLite backup with ${manifest.stores.length} store(s):`,
|
|
33396
33478
|
...manifest.stores.map((s) => ` - ${s.storeId}: ${s.sourcePath} -> ${s.backupFile} (schema v${s.schemaVersion}, ${s.bytes} bytes, sha256 ${s.sha256.slice(0, 12)}...)`),
|
|
33397
|
-
`Manifest: ${
|
|
33479
|
+
`Manifest: ${join27(outDir, "manifest.json")}`
|
|
33398
33480
|
].join("\n");
|
|
33399
33481
|
print(runtime.io, runtime.json, payload, summary);
|
|
33400
33482
|
return 0;
|
|
@@ -33963,8 +34045,8 @@ async function cmdStudioLayout(runtime, workflowPath) {
|
|
|
33963
34045
|
}
|
|
33964
34046
|
let yamlContent;
|
|
33965
34047
|
let workflowId = "default";
|
|
33966
|
-
if (
|
|
33967
|
-
yamlContent =
|
|
34048
|
+
if (existsSync24(filePath)) {
|
|
34049
|
+
yamlContent = readFileSync23(filePath, "utf8");
|
|
33968
34050
|
} else {
|
|
33969
34051
|
yamlContent = `schema: kxm.workflow.v1
|
|
33970
34052
|
description: Feature implementation workflow
|
|
@@ -34037,15 +34119,15 @@ async function cmdStudioServe(runtime, options) {
|
|
|
34037
34119
|
sessionToken,
|
|
34038
34120
|
planProvider: () => {
|
|
34039
34121
|
try {
|
|
34040
|
-
const wfDir =
|
|
34041
|
-
const defaultPath =
|
|
34042
|
-
let targetPath =
|
|
34043
|
-
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)) {
|
|
34044
34126
|
const yml = readdirSync8(wfDir).find((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
|
|
34045
|
-
if (yml) targetPath =
|
|
34127
|
+
if (yml) targetPath = join28(wfDir, yml);
|
|
34046
34128
|
}
|
|
34047
|
-
if (targetPath &&
|
|
34048
|
-
const raw =
|
|
34129
|
+
if (targetPath && existsSync24(targetPath)) {
|
|
34130
|
+
const raw = readFileSync23(targetPath, "utf8");
|
|
34049
34131
|
const parsed = (0, import_yaml13.parse)(raw);
|
|
34050
34132
|
const wfId = basename6(targetPath).replace(/\.(yaml|yml)$/, "");
|
|
34051
34133
|
return compileVnextWorkflow({ id: wfId, value: parsed });
|
|
@@ -34095,14 +34177,14 @@ Press Ctrl+C to stop.
|
|
|
34095
34177
|
}
|
|
34096
34178
|
|
|
34097
34179
|
// plugins/kxm/src/cli/context-skills.ts
|
|
34098
|
-
import { readFileSync as
|
|
34099
|
-
import { join as
|
|
34180
|
+
import { readFileSync as readFileSync26 } from "node:fs";
|
|
34181
|
+
import { join as join32, relative as relative5 } from "node:path";
|
|
34100
34182
|
|
|
34101
34183
|
// plugins/kxm/src/memory.ts
|
|
34102
34184
|
var import_yaml14 = __toESM(require_dist(), 1);
|
|
34103
34185
|
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
34104
|
-
import { existsSync as
|
|
34105
|
-
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";
|
|
34106
34188
|
var MEMORY_SCHEMA = "kxm.memory.v1";
|
|
34107
34189
|
var MEMORY_BRIEF_SCHEMA = "kxm.memory-brief.v1";
|
|
34108
34190
|
var MEMORY_MARKER_START = "<!-- kxm:memory:start -->";
|
|
@@ -34227,22 +34309,22 @@ ${yamlText}
|
|
|
34227
34309
|
---
|
|
34228
34310
|
`;
|
|
34229
34311
|
}
|
|
34230
|
-
function memoryDirectories(
|
|
34231
|
-
const root = resolve22(
|
|
34232
|
-
const memoryDir =
|
|
34233
|
-
const candidatesDir =
|
|
34312
|
+
function memoryDirectories(repoRoot) {
|
|
34313
|
+
const root = resolve22(repoRoot);
|
|
34314
|
+
const memoryDir = join29(root, ".kxm", "memory");
|
|
34315
|
+
const candidatesDir = join29(memoryDir, "candidates");
|
|
34234
34316
|
return { memoryDir, candidatesDir };
|
|
34235
34317
|
}
|
|
34236
|
-
function loadAuthoredMemory(
|
|
34237
|
-
const { memoryDir } = memoryDirectories(
|
|
34238
|
-
if (!
|
|
34318
|
+
function loadAuthoredMemory(repoRoot) {
|
|
34319
|
+
const { memoryDir } = memoryDirectories(repoRoot);
|
|
34320
|
+
if (!existsSync25(memoryDir)) return [];
|
|
34239
34321
|
const records = [];
|
|
34240
34322
|
const entries = readdirSync9(memoryDir, { withFileTypes: true });
|
|
34241
34323
|
for (const entry of entries) {
|
|
34242
34324
|
if (entry.isFile() && extname2(entry.name) === ".md") {
|
|
34243
|
-
const fullPath =
|
|
34325
|
+
const fullPath = join29(memoryDir, entry.name);
|
|
34244
34326
|
try {
|
|
34245
|
-
const text =
|
|
34327
|
+
const text = readFileSync24(fullPath, "utf8");
|
|
34246
34328
|
const record = parseMemoryRecord(text, entry.name);
|
|
34247
34329
|
if (record.lifecycle === "active") {
|
|
34248
34330
|
records.push(record);
|
|
@@ -34254,9 +34336,9 @@ function loadAuthoredMemory(repoRoot6) {
|
|
|
34254
34336
|
}
|
|
34255
34337
|
return records.sort((left, right) => left.id.localeCompare(right.id));
|
|
34256
34338
|
}
|
|
34257
|
-
function createMemoryNote(
|
|
34258
|
-
const { candidatesDir } = memoryDirectories(
|
|
34259
|
-
|
|
34339
|
+
function createMemoryNote(repoRoot, summary, options = {}) {
|
|
34340
|
+
const { candidatesDir } = memoryDirectories(repoRoot);
|
|
34341
|
+
mkdirSync20(candidatesDir, { recursive: true });
|
|
34260
34342
|
const scope = options.scope ?? "project";
|
|
34261
34343
|
if (!VALID_SCOPES.has(scope)) {
|
|
34262
34344
|
throw new Error(`invalid memory note scope: ${scope}; must be one of agent, project, run, operator`);
|
|
@@ -34281,12 +34363,12 @@ function createMemoryNote(repoRoot6, summary, options = {}) {
|
|
|
34281
34363
|
evidenceRefs: [],
|
|
34282
34364
|
...options.body ? { body: options.body.trim() } : {}
|
|
34283
34365
|
};
|
|
34284
|
-
const targetPath =
|
|
34285
|
-
|
|
34366
|
+
const targetPath = join29(candidatesDir, `${id}.md`);
|
|
34367
|
+
writeFileSync19(targetPath, formatMemoryRecord(record), "utf8");
|
|
34286
34368
|
return { record, path: targetPath };
|
|
34287
34369
|
}
|
|
34288
|
-
function generateMemoryBrief(
|
|
34289
|
-
const facts = loadAuthoredMemory(
|
|
34370
|
+
function generateMemoryBrief(repoRoot) {
|
|
34371
|
+
const facts = loadAuthoredMemory(repoRoot);
|
|
34290
34372
|
return {
|
|
34291
34373
|
schema: MEMORY_BRIEF_SCHEMA,
|
|
34292
34374
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -34318,8 +34400,8 @@ function formatHarnessMemoryBlock(records) {
|
|
|
34318
34400
|
}
|
|
34319
34401
|
function updateHarnessDocument(filePath, block, defaultHeader) {
|
|
34320
34402
|
let original = "";
|
|
34321
|
-
if (
|
|
34322
|
-
original =
|
|
34403
|
+
if (existsSync25(filePath)) {
|
|
34404
|
+
original = readFileSync24(filePath, "utf8");
|
|
34323
34405
|
}
|
|
34324
34406
|
let updated = "";
|
|
34325
34407
|
if (original.includes(MEMORY_MARKER_START) && original.includes(MEMORY_MARKER_END)) {
|
|
@@ -34347,25 +34429,25 @@ ${block}
|
|
|
34347
34429
|
`;
|
|
34348
34430
|
}
|
|
34349
34431
|
if (updated !== original) {
|
|
34350
|
-
|
|
34432
|
+
writeFileSync19(filePath, updated, "utf8");
|
|
34351
34433
|
return true;
|
|
34352
34434
|
}
|
|
34353
34435
|
return false;
|
|
34354
34436
|
}
|
|
34355
|
-
function syncHarnessMemory(
|
|
34356
|
-
const root = resolve22(
|
|
34437
|
+
function syncHarnessMemory(repoRoot) {
|
|
34438
|
+
const root = resolve22(repoRoot);
|
|
34357
34439
|
const records = loadAuthoredMemory(root);
|
|
34358
34440
|
const block = formatHarnessMemoryBlock(records);
|
|
34359
34441
|
const updated = [];
|
|
34360
34442
|
const created = [];
|
|
34361
|
-
const agentsPath =
|
|
34443
|
+
const agentsPath = join29(root, "AGENTS.md");
|
|
34362
34444
|
const agentsHeader = "# AGENTS\n\nFollow project instructions.\n";
|
|
34363
|
-
const agentsExisted =
|
|
34445
|
+
const agentsExisted = existsSync25(agentsPath);
|
|
34364
34446
|
if (updateHarnessDocument(agentsPath, block, agentsHeader)) {
|
|
34365
34447
|
if (agentsExisted) updated.push("AGENTS.md");
|
|
34366
34448
|
else created.push("AGENTS.md");
|
|
34367
34449
|
}
|
|
34368
|
-
const claudePath =
|
|
34450
|
+
const claudePath = join29(root, "CLAUDE.md");
|
|
34369
34451
|
const claudeHeader = `# KXM (Claude)
|
|
34370
34452
|
|
|
34371
34453
|
Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
@@ -34376,12 +34458,12 @@ you to implement. Default writer is native Grok CLI (\`grok --model grok-4.6\`).
|
|
|
34376
34458
|
If \`grok\` is logged out, fail closed; do not fall back to Pi. Your reviews are
|
|
34377
34459
|
artifacts, not hub \`peer-reply\` evidence.
|
|
34378
34460
|
`;
|
|
34379
|
-
const claudeExisted =
|
|
34461
|
+
const claudeExisted = existsSync25(claudePath);
|
|
34380
34462
|
if (updateHarnessDocument(claudePath, block, claudeHeader)) {
|
|
34381
34463
|
if (claudeExisted) updated.push("CLAUDE.md");
|
|
34382
34464
|
else created.push("CLAUDE.md");
|
|
34383
34465
|
}
|
|
34384
|
-
const geminiPath =
|
|
34466
|
+
const geminiPath = join29(root, "GEMINI.md");
|
|
34385
34467
|
const geminiHeader = `# KXM (Gemini / Antigravity)
|
|
34386
34468
|
|
|
34387
34469
|
Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
@@ -34390,7 +34472,7 @@ Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
|
34390
34472
|
Google / Antigravity CLI (\`agy\`) is an admitted native writer and experiment edit route
|
|
34391
34473
|
for Gemini models. Starting rotation remains Grok.
|
|
34392
34474
|
`;
|
|
34393
|
-
const geminiExisted =
|
|
34475
|
+
const geminiExisted = existsSync25(geminiPath);
|
|
34394
34476
|
if (updateHarnessDocument(geminiPath, block, geminiHeader)) {
|
|
34395
34477
|
if (geminiExisted) updated.push("GEMINI.md");
|
|
34396
34478
|
else created.push("GEMINI.md");
|
|
@@ -34401,8 +34483,8 @@ for Gemini models. Starting rotation remains Grok.
|
|
|
34401
34483
|
// plugins/kxm/src/skills.ts
|
|
34402
34484
|
var import_yaml15 = __toESM(require_dist(), 1);
|
|
34403
34485
|
import { createHash as createHash14 } from "node:crypto";
|
|
34404
|
-
import { existsSync as
|
|
34405
|
-
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";
|
|
34406
34488
|
var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
|
|
34407
34489
|
var SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
|
|
34408
34490
|
var SKILL_DECISION_SCHEMA = "kxm.skill-decision.v1";
|
|
@@ -34496,48 +34578,48 @@ var SkillLifecycle = class {
|
|
|
34496
34578
|
this.allowOptimizationEvals = options.allowOptimizationEvals === true;
|
|
34497
34579
|
}
|
|
34498
34580
|
dir(state) {
|
|
34499
|
-
return
|
|
34581
|
+
return join30(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
|
|
34500
34582
|
}
|
|
34501
34583
|
historyFile(id) {
|
|
34502
|
-
return
|
|
34584
|
+
return join30(this.root, "history", `${id}.jsonl`);
|
|
34503
34585
|
}
|
|
34504
34586
|
paths(state, id) {
|
|
34505
|
-
const dir =
|
|
34506
|
-
return { dir, metadata:
|
|
34587
|
+
const dir = join30(this.dir(state), id);
|
|
34588
|
+
return { dir, metadata: join30(dir, "metadata.json"), skill: join30(dir, "SKILL.md") };
|
|
34507
34589
|
}
|
|
34508
34590
|
appendHistory(id, record) {
|
|
34509
|
-
|
|
34591
|
+
mkdirSync21(join30(this.root, "history"), { recursive: true });
|
|
34510
34592
|
const line = `${JSON.stringify(record)}
|
|
34511
34593
|
`;
|
|
34512
|
-
if (
|
|
34513
|
-
const existing =
|
|
34594
|
+
if (existsSync26(this.historyFile(id))) {
|
|
34595
|
+
const existing = readFileSync25(this.historyFile(id), "utf8");
|
|
34514
34596
|
const lines = existing.split("\n").filter((entry) => entry.trim());
|
|
34515
|
-
|
|
34597
|
+
writeFileSync20(this.historyFile(id), [...lines.slice(-499), line.trim()].join("\n") + "\n");
|
|
34516
34598
|
} else {
|
|
34517
|
-
|
|
34599
|
+
writeFileSync20(this.historyFile(id), line);
|
|
34518
34600
|
}
|
|
34519
34601
|
}
|
|
34520
34602
|
history(id) {
|
|
34521
34603
|
const file = this.historyFile(id);
|
|
34522
|
-
if (!
|
|
34523
|
-
return
|
|
34604
|
+
if (!existsSync26(file)) return [];
|
|
34605
|
+
return readFileSync25(file, "utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
34524
34606
|
}
|
|
34525
34607
|
readMetadata(state, id) {
|
|
34526
34608
|
const { metadata } = this.paths(state, id);
|
|
34527
|
-
if (!
|
|
34609
|
+
if (!existsSync26(metadata)) {
|
|
34528
34610
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${state}`);
|
|
34529
34611
|
}
|
|
34530
|
-
return JSON.parse(
|
|
34612
|
+
return JSON.parse(readFileSync25(metadata, "utf8"));
|
|
34531
34613
|
}
|
|
34532
34614
|
move(from, to, id) {
|
|
34533
|
-
const fromDir =
|
|
34534
|
-
const toDir =
|
|
34535
|
-
if (!
|
|
34615
|
+
const fromDir = join30(this.dir(from), id);
|
|
34616
|
+
const toDir = join30(this.dir(to), id);
|
|
34617
|
+
if (!existsSync26(fromDir)) {
|
|
34536
34618
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${from}`);
|
|
34537
34619
|
}
|
|
34538
|
-
|
|
34539
|
-
if (
|
|
34540
|
-
|
|
34620
|
+
mkdirSync21(this.dir(to), { recursive: true });
|
|
34621
|
+
if (existsSync26(toDir)) rmSync10(toDir, { recursive: true, force: true });
|
|
34622
|
+
renameSync8(fromDir, toDir);
|
|
34541
34623
|
}
|
|
34542
34624
|
/** Submit a new skill candidate. Content is redacted of secret material at
|
|
34543
34625
|
* creation; the ID is derived from name + content hash. */
|
|
@@ -34579,7 +34661,7 @@ var SkillLifecycle = class {
|
|
|
34579
34661
|
const contentSha256 = skillContentSha256(content);
|
|
34580
34662
|
const id = skillIdFor(name, contentSha256);
|
|
34581
34663
|
const { dir, metadata, skill } = this.paths("candidate", id);
|
|
34582
|
-
if (
|
|
34664
|
+
if (existsSync26(metadata)) {
|
|
34583
34665
|
throw new SkillLifecycleError(
|
|
34584
34666
|
"skill_candidate_exists",
|
|
34585
34667
|
`identical candidate ${id} already exists; changed behavior requires changed content`
|
|
@@ -34598,9 +34680,9 @@ var SkillLifecycle = class {
|
|
|
34598
34680
|
createdAt: this.now(),
|
|
34599
34681
|
...input.supersedes ? { supersedes: input.supersedes } : {}
|
|
34600
34682
|
};
|
|
34601
|
-
|
|
34602
|
-
|
|
34603
|
-
|
|
34683
|
+
mkdirSync21(dir, { recursive: true });
|
|
34684
|
+
writeFileSync20(skill, content);
|
|
34685
|
+
writeFileSync20(metadata, `${JSON.stringify(record, null, 2)}
|
|
34604
34686
|
`);
|
|
34605
34687
|
this.appendHistory(id, { schema: "kxm.skill-history-event.v1", event: "candidate_created", by: createdBy, supersedes: input.supersedes, at: record.createdAt });
|
|
34606
34688
|
return record;
|
|
@@ -34689,18 +34771,18 @@ var SkillLifecycle = class {
|
|
|
34689
34771
|
};
|
|
34690
34772
|
const candidatePaths = this.paths("candidate", candidateId);
|
|
34691
34773
|
const promotedPaths = this.paths("promoted", candidateId);
|
|
34692
|
-
|
|
34693
|
-
const skillContent =
|
|
34694
|
-
const metadataContent =
|
|
34695
|
-
|
|
34696
|
-
|
|
34697
|
-
const patchesDir =
|
|
34698
|
-
|
|
34699
|
-
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`);
|
|
34700
34782
|
const relSkillPath = `.kxm/skills/promoted/${candidateId}/SKILL.md`;
|
|
34701
34783
|
const relMetaPath = `.kxm/skills/promoted/${candidateId}/metadata.json`;
|
|
34702
34784
|
const patch = `${createUnifiedPatch(relSkillPath, skillContent)}${createUnifiedPatch(relMetaPath, metadataContent)}`;
|
|
34703
|
-
|
|
34785
|
+
writeFileSync20(patchPath, patch, "utf8");
|
|
34704
34786
|
this.appendHistory(candidateId, record);
|
|
34705
34787
|
return { ...metadata, patch, patchPath };
|
|
34706
34788
|
}
|
|
@@ -34724,7 +34806,7 @@ var SkillLifecycle = class {
|
|
|
34724
34806
|
verify(state, id) {
|
|
34725
34807
|
const metadata = this.readMetadata(state, id);
|
|
34726
34808
|
const { skill } = this.paths(state, id);
|
|
34727
|
-
const content =
|
|
34809
|
+
const content = readFileSync25(skill, "utf8");
|
|
34728
34810
|
if (skillContentSha256(content) !== metadata.contentSha256) {
|
|
34729
34811
|
throw new SkillLifecycleError(
|
|
34730
34812
|
"skill_integrity_violation",
|
|
@@ -34742,7 +34824,7 @@ var SkillLifecycle = class {
|
|
|
34742
34824
|
}
|
|
34743
34825
|
list(state) {
|
|
34744
34826
|
const dir = this.dir(state);
|
|
34745
|
-
if (!
|
|
34827
|
+
if (!existsSync26(dir)) return [];
|
|
34746
34828
|
const ids = readdirSorted(dir);
|
|
34747
34829
|
return ids.map((id) => {
|
|
34748
34830
|
try {
|
|
@@ -34755,7 +34837,7 @@ var SkillLifecycle = class {
|
|
|
34755
34837
|
read(state, id) {
|
|
34756
34838
|
const metadata = this.readMetadata(state, id);
|
|
34757
34839
|
const { skill } = this.paths(state, id);
|
|
34758
|
-
return { metadata, content:
|
|
34840
|
+
return { metadata, content: readFileSync25(skill, "utf8") };
|
|
34759
34841
|
}
|
|
34760
34842
|
};
|
|
34761
34843
|
function boundedList(value, field) {
|
|
@@ -34770,18 +34852,18 @@ function boundedList(value, field) {
|
|
|
34770
34852
|
return [...new Set(refs)];
|
|
34771
34853
|
}
|
|
34772
34854
|
function readdirSorted(dir) {
|
|
34773
|
-
return readdirSync10(dir).filter((entry) => statSync3(
|
|
34855
|
+
return readdirSync10(dir).filter((entry) => statSync3(join30(dir, entry)).isDirectory()).sort();
|
|
34774
34856
|
}
|
|
34775
34857
|
|
|
34776
34858
|
// plugins/kxm/src/wiki.ts
|
|
34777
|
-
import { mkdirSync as
|
|
34778
|
-
import { join as
|
|
34859
|
+
import { mkdirSync as mkdirSync22, writeFileSync as writeFileSync21 } from "node:fs";
|
|
34860
|
+
import { join as join31 } from "node:path";
|
|
34779
34861
|
function writeCompiledWiki(root, wiki) {
|
|
34780
34862
|
const written = [];
|
|
34781
34863
|
for (const [relativePath, content] of [...wiki.pages].sort(([left], [right]) => left.localeCompare(right))) {
|
|
34782
|
-
const absolute =
|
|
34783
|
-
|
|
34784
|
-
|
|
34864
|
+
const absolute = join31(root, relativePath);
|
|
34865
|
+
mkdirSync22(absolute.slice(0, absolute.lastIndexOf("/")), { recursive: true });
|
|
34866
|
+
writeFileSync21(absolute, content);
|
|
34785
34867
|
written.push(relativePath);
|
|
34786
34868
|
}
|
|
34787
34869
|
return written;
|
|
@@ -34947,7 +35029,7 @@ function skillStateFromFlag(value) {
|
|
|
34947
35029
|
throw new Error(`invalid skill state ${value}`);
|
|
34948
35030
|
}
|
|
34949
35031
|
function skillsRoot(runtime) {
|
|
34950
|
-
return
|
|
35032
|
+
return join32(runtime.dirs.workdir, ".kxm", "skills");
|
|
34951
35033
|
}
|
|
34952
35034
|
function csv(value) {
|
|
34953
35035
|
if (!value) return void 0;
|
|
@@ -34964,7 +35046,7 @@ async function cmdSkillsCreate(runtime, options) {
|
|
|
34964
35046
|
const metadata = lifecycle.create({
|
|
34965
35047
|
name: options.name,
|
|
34966
35048
|
description: options.description ?? "",
|
|
34967
|
-
content:
|
|
35049
|
+
content: readFileSync26(options.file, "utf8"),
|
|
34968
35050
|
createdBy: options.createdBy,
|
|
34969
35051
|
sources: {
|
|
34970
35052
|
runIds: csv(options.run) ?? [],
|
|
@@ -35122,8 +35204,8 @@ async function cmdMemorySync(runtime) {
|
|
|
35122
35204
|
|
|
35123
35205
|
// plugins/kxm/src/cli/hub.ts
|
|
35124
35206
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
35125
|
-
import { existsSync as
|
|
35126
|
-
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";
|
|
35127
35209
|
|
|
35128
35210
|
// node_modules/marked/lib/marked.esm.js
|
|
35129
35211
|
function M() {
|
|
@@ -41056,19 +41138,19 @@ import * as path2 from "node:path";
|
|
|
41056
41138
|
|
|
41057
41139
|
// node_modules/@earendil-works/pi-tui/dist/native-module-path.js
|
|
41058
41140
|
import { createRequire as createRequire2 } from "node:module";
|
|
41059
|
-
import { dirname as
|
|
41060
|
-
import { fileURLToPath as
|
|
41141
|
+
import { dirname as dirname17, join as join33 } from "node:path";
|
|
41142
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
41061
41143
|
var moduleRequire = createRequire2(import.meta.url);
|
|
41062
41144
|
var TUI_PACKAGE_NAME = "@earendil-works/pi-tui";
|
|
41063
41145
|
function getNativeModuleCandidates(nativePath, options = {}) {
|
|
41064
|
-
const moduleDir =
|
|
41146
|
+
const moduleDir = dirname17(fileURLToPath2(options.moduleUrl ?? import.meta.url));
|
|
41065
41147
|
const candidates = [];
|
|
41066
41148
|
try {
|
|
41067
41149
|
const packageEntry = (options.resolvePackage ?? moduleRequire.resolve)(TUI_PACKAGE_NAME);
|
|
41068
|
-
candidates.push(
|
|
41150
|
+
candidates.push(join33(dirname17(packageEntry), "..", nativePath));
|
|
41069
41151
|
} catch {
|
|
41070
41152
|
}
|
|
41071
|
-
candidates.push(
|
|
41153
|
+
candidates.push(join33(moduleDir, "..", nativePath), join33(moduleDir, nativePath), join33(dirname17(options.execPath ?? process.execPath), nativePath));
|
|
41072
41154
|
return Array.from(new Set(candidates));
|
|
41073
41155
|
}
|
|
41074
41156
|
|
|
@@ -43524,8 +43606,8 @@ var TuiAltScreen = class extends TuiBase {
|
|
|
43524
43606
|
var MAX_RENDER_WRITE_CHARS = 1024 * 1024;
|
|
43525
43607
|
|
|
43526
43608
|
// plugins/kxm/src/tui.ts
|
|
43527
|
-
import { mkdirSync as
|
|
43528
|
-
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";
|
|
43529
43611
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
43530
43612
|
|
|
43531
43613
|
// plugins/kxm/src/external-effects.ts
|
|
@@ -43536,9 +43618,9 @@ function slugifyBranchPart(text, maxLength = 40) {
|
|
|
43536
43618
|
}
|
|
43537
43619
|
|
|
43538
43620
|
// plugins/kxm/src/local-snapshot.ts
|
|
43539
|
-
import { existsSync as
|
|
43540
|
-
import { homedir as
|
|
43541
|
-
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";
|
|
43542
43624
|
function processExists2(pid) {
|
|
43543
43625
|
try {
|
|
43544
43626
|
process.kill(pid, 0);
|
|
@@ -43658,36 +43740,36 @@ function readOpenMessageMetadata(database) {
|
|
|
43658
43740
|
return messages;
|
|
43659
43741
|
}
|
|
43660
43742
|
function resolveKxmSnapshotPaths(cwd, env = process.env) {
|
|
43661
|
-
const stateDir = env.KXM_STATE_DIR?.trim() ||
|
|
43743
|
+
const stateDir = env.KXM_STATE_DIR?.trim() || join36(cwd, ".kxm", "state");
|
|
43662
43744
|
const configured = env.KXM_DATA_PATH?.trim();
|
|
43663
|
-
const dataPath = configured ? resolve23(cwd, configured) :
|
|
43745
|
+
const dataPath = configured ? resolve23(cwd, configured) : join36(stateDir, "kxm.db");
|
|
43664
43746
|
return { dataPath, stateDir };
|
|
43665
43747
|
}
|
|
43666
43748
|
function resolveVnextStateRoot(stateDir, options) {
|
|
43667
|
-
if (options?.vnextStateRoot &&
|
|
43749
|
+
if (options?.vnextStateRoot && existsSync27(options.vnextStateRoot)) {
|
|
43668
43750
|
return resolve23(options.vnextStateRoot);
|
|
43669
43751
|
}
|
|
43670
|
-
if (
|
|
43752
|
+
if (existsSync27(join36(stateDir, "runtime", "registry.db")) || existsSync27(join36(stateDir, "runtime", "projects"))) {
|
|
43671
43753
|
return stateDir;
|
|
43672
43754
|
}
|
|
43673
43755
|
const env = options?.env ?? process.env;
|
|
43674
43756
|
const explicit = env.KXM_STATE_HOME?.trim() || env.KXM_USER_STATE_DIR?.trim() || env.KXM_STATE_ROOT?.trim();
|
|
43675
|
-
if (explicit &&
|
|
43757
|
+
if (explicit && isAbsolute8(explicit) && existsSync27(resolve23(explicit))) {
|
|
43676
43758
|
return resolve23(explicit);
|
|
43677
43759
|
}
|
|
43678
43760
|
let base;
|
|
43679
43761
|
if (process.platform === "win32") {
|
|
43680
43762
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
43681
|
-
base = localAppData &&
|
|
43763
|
+
base = localAppData && isAbsolute8(localAppData) ? localAppData : join36(homedir6(), "AppData", "Local");
|
|
43682
43764
|
base = resolve23(base, "KXM");
|
|
43683
43765
|
} else if (process.platform === "darwin") {
|
|
43684
|
-
base = resolve23(
|
|
43766
|
+
base = resolve23(homedir6(), "Library", "Application Support", "KXM");
|
|
43685
43767
|
} else {
|
|
43686
43768
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
43687
|
-
base = xdgState &&
|
|
43769
|
+
base = xdgState && isAbsolute8(xdgState) ? xdgState : join36(homedir6(), ".local", "state");
|
|
43688
43770
|
base = resolve23(base, "kxm");
|
|
43689
43771
|
}
|
|
43690
|
-
if (
|
|
43772
|
+
if (existsSync27(base)) return base;
|
|
43691
43773
|
return void 0;
|
|
43692
43774
|
}
|
|
43693
43775
|
function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
@@ -43698,7 +43780,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43698
43780
|
let legacyRuns = [];
|
|
43699
43781
|
let legacyRunTotal = 0;
|
|
43700
43782
|
let plans = [];
|
|
43701
|
-
if (
|
|
43783
|
+
if (existsSync27(dataPath)) {
|
|
43702
43784
|
hasLegacy = true;
|
|
43703
43785
|
const database = new DatabaseSync(dataPath, { readOnly: true });
|
|
43704
43786
|
try {
|
|
@@ -43718,11 +43800,11 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43718
43800
|
let vnextRunTotal = 0;
|
|
43719
43801
|
const vnextStateRoot = resolveVnextStateRoot(stateDir, options);
|
|
43720
43802
|
if (vnextStateRoot) {
|
|
43721
|
-
const runtimeDir =
|
|
43722
|
-
const registryDbPath =
|
|
43723
|
-
const projectsDir =
|
|
43803
|
+
const runtimeDir = join36(vnextStateRoot, "runtime");
|
|
43804
|
+
const registryDbPath = join36(runtimeDir, "registry.db");
|
|
43805
|
+
const projectsDir = join36(runtimeDir, "projects");
|
|
43724
43806
|
const projectKeys = /* @__PURE__ */ new Set();
|
|
43725
|
-
if (
|
|
43807
|
+
if (existsSync27(registryDbPath)) {
|
|
43726
43808
|
hasVnext = true;
|
|
43727
43809
|
try {
|
|
43728
43810
|
const regDb = new DatabaseSync(registryDbPath, { readOnly: true });
|
|
@@ -43738,7 +43820,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43738
43820
|
} catch {
|
|
43739
43821
|
}
|
|
43740
43822
|
}
|
|
43741
|
-
if (
|
|
43823
|
+
if (existsSync27(projectsDir)) {
|
|
43742
43824
|
try {
|
|
43743
43825
|
for (const entry of readdirSync11(projectsDir, { withFileTypes: true })) {
|
|
43744
43826
|
if (entry.isDirectory()) {
|
|
@@ -43749,8 +43831,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43749
43831
|
}
|
|
43750
43832
|
}
|
|
43751
43833
|
for (const key of projectKeys) {
|
|
43752
|
-
const eventDbPath =
|
|
43753
|
-
if (
|
|
43834
|
+
const eventDbPath = join36(projectsDir, key, "run-events.db");
|
|
43835
|
+
if (existsSync27(eventDbPath)) {
|
|
43754
43836
|
hasVnext = true;
|
|
43755
43837
|
try {
|
|
43756
43838
|
const eventDb = new DatabaseSync(eventDbPath, { readOnly: true });
|
|
@@ -43780,10 +43862,10 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43780
43862
|
}
|
|
43781
43863
|
}
|
|
43782
43864
|
const pids = [];
|
|
43783
|
-
if (
|
|
43865
|
+
if (existsSync27(stateDir)) {
|
|
43784
43866
|
for (const file of readdirSync11(stateDir).filter((name) => name.endsWith(".pid"))) {
|
|
43785
43867
|
try {
|
|
43786
|
-
const record = JSON.parse(
|
|
43868
|
+
const record = JSON.parse(readFileSync27(join36(stateDir, file), "utf8"));
|
|
43787
43869
|
pids.push({
|
|
43788
43870
|
file,
|
|
43789
43871
|
...record.role ? { role: record.role } : {},
|
|
@@ -43822,8 +43904,8 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43822
43904
|
} else {
|
|
43823
43905
|
source = "legacy";
|
|
43824
43906
|
}
|
|
43825
|
-
const telemetryFile =
|
|
43826
|
-
const spend =
|
|
43907
|
+
const telemetryFile = join36(stateDir, "telemetry.jsonl");
|
|
43908
|
+
const spend = existsSync27(telemetryFile) ? readRoutingRecords(telemetryFile) : [];
|
|
43827
43909
|
return {
|
|
43828
43910
|
source,
|
|
43829
43911
|
agents: agents.sort((a, b2) => Number(b2.online) - Number(a.online) || a.name.localeCompare(b2.name)),
|
|
@@ -43938,10 +44020,10 @@ function copyToClipboard(text) {
|
|
|
43938
44020
|
return false;
|
|
43939
44021
|
}
|
|
43940
44022
|
}
|
|
43941
|
-
function spawnDegradeWorktree(
|
|
44023
|
+
function spawnDegradeWorktree(repoRoot, runId, options) {
|
|
43942
44024
|
const runner = options?.execFn ?? ((cmd, args) => {
|
|
43943
44025
|
const res = spawnSync5(cmd, args, {
|
|
43944
|
-
cwd:
|
|
44026
|
+
cwd: repoRoot,
|
|
43945
44027
|
encoding: "utf8",
|
|
43946
44028
|
windowsHide: true,
|
|
43947
44029
|
env: Object.fromEntries(
|
|
@@ -43957,11 +44039,11 @@ function spawnDegradeWorktree(repoRoot6, runId, options) {
|
|
|
43957
44039
|
const cleanRunId = runId.replace(/^run_/, "");
|
|
43958
44040
|
const desc = options?.description ? slugifyBranchPart(options.description, 30) : "degrade";
|
|
43959
44041
|
const branchName = `kxm/run-${cleanRunId}-${desc}`;
|
|
43960
|
-
const relativeWtPath =
|
|
43961
|
-
const absoluteWtPath = resolve24(
|
|
44042
|
+
const relativeWtPath = join37(".kxm", "worktrees", `run-${cleanRunId}-${desc}`);
|
|
44043
|
+
const absoluteWtPath = resolve24(repoRoot, relativeWtPath);
|
|
43962
44044
|
const jumpCommand = `cd "${absoluteWtPath}"`;
|
|
43963
44045
|
try {
|
|
43964
|
-
|
|
44046
|
+
mkdirSync23(dirname18(absoluteWtPath), { recursive: true });
|
|
43965
44047
|
const branchCheck = runner("git", ["rev-parse", "--verify", `refs/heads/${branchName}`]);
|
|
43966
44048
|
let wtRes;
|
|
43967
44049
|
if (branchCheck.status === 0) {
|
|
@@ -44556,8 +44638,8 @@ async function runMeshTui(input) {
|
|
|
44556
44638
|
body: JSON.stringify({ signalKey: "operator-degrade", status: "degraded", summary: "Degraded to operator worktree from kxm dash" }),
|
|
44557
44639
|
signal: abort.signal
|
|
44558
44640
|
});
|
|
44559
|
-
const
|
|
44560
|
-
const degradeRes = spawnDegradeWorktree(
|
|
44641
|
+
const repoRoot = process.cwd();
|
|
44642
|
+
const degradeRes = spawnDegradeWorktree(repoRoot, targetId, {
|
|
44561
44643
|
description: "operator-degrade"
|
|
44562
44644
|
});
|
|
44563
44645
|
if (dashboard) {
|
|
@@ -44727,8 +44809,8 @@ async function runMeshTui(input) {
|
|
|
44727
44809
|
// plugins/kxm/src/session-work.ts
|
|
44728
44810
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
44729
44811
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
44730
|
-
import { existsSync as
|
|
44731
|
-
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";
|
|
44732
44814
|
var MAX_SESSION_BRIEF_TASKS = 5;
|
|
44733
44815
|
var MAX_SESSION_BRIEF_PLANS = 5;
|
|
44734
44816
|
var SESSION_BRIEF_SCHEMA = "kxm.session-brief.v1";
|
|
@@ -44884,10 +44966,10 @@ function buildSessionBrief(snapshot, current, hub, ship, updateLatest, cost, ses
|
|
|
44884
44966
|
};
|
|
44885
44967
|
}
|
|
44886
44968
|
function readCachedSessionBrief(stateDir) {
|
|
44887
|
-
const file =
|
|
44969
|
+
const file = join38(stateDir, "session-brief.json");
|
|
44888
44970
|
try {
|
|
44889
|
-
if (!
|
|
44890
|
-
const raw =
|
|
44971
|
+
if (!existsSync28(file)) return void 0;
|
|
44972
|
+
const raw = readFileSync28(file, "utf8");
|
|
44891
44973
|
const parsed = JSON.parse(raw);
|
|
44892
44974
|
if (parsed && parsed.schema === "kxm.session-brief.v1" && typeof parsed.generatedAt === "string") {
|
|
44893
44975
|
const ageMs = Date.now() - Date.parse(parsed.generatedAt);
|
|
@@ -44902,18 +44984,18 @@ function readCachedSessionBrief(stateDir) {
|
|
|
44902
44984
|
}
|
|
44903
44985
|
function writeCachedSessionBrief(stateDir, brief) {
|
|
44904
44986
|
try {
|
|
44905
|
-
|
|
44906
|
-
const file =
|
|
44987
|
+
mkdirSync24(stateDir, { recursive: true, mode: 448 });
|
|
44988
|
+
const file = join38(stateDir, "session-brief.json");
|
|
44907
44989
|
const tmp = `${file}.tmp.${randomUUID13().slice(0, 8)}`;
|
|
44908
|
-
|
|
44909
|
-
|
|
44990
|
+
writeFileSync22(tmp, JSON.stringify(brief, null, 2), { encoding: "utf8", mode: 384 });
|
|
44991
|
+
renameSync9(tmp, file);
|
|
44910
44992
|
} catch {
|
|
44911
44993
|
}
|
|
44912
44994
|
}
|
|
44913
44995
|
function estimateSessionCost(stateDir) {
|
|
44914
44996
|
try {
|
|
44915
|
-
const telemetryFile =
|
|
44916
|
-
if (!
|
|
44997
|
+
const telemetryFile = join38(stateDir, "telemetry.jsonl");
|
|
44998
|
+
if (!existsSync28(telemetryFile)) return void 0;
|
|
44917
44999
|
const records = readRoutingRecords(telemetryFile);
|
|
44918
45000
|
if (records.length === 0) return void 0;
|
|
44919
45001
|
let totalCost = 0;
|
|
@@ -45081,11 +45163,11 @@ function formatSessionBriefText(brief) {
|
|
|
45081
45163
|
}
|
|
45082
45164
|
|
|
45083
45165
|
// plugins/kxm/src/kxm-install-kind.ts
|
|
45084
|
-
import { existsSync as
|
|
45085
|
-
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";
|
|
45086
45168
|
function packageIsKxm(root) {
|
|
45087
45169
|
try {
|
|
45088
|
-
const pkg = JSON.parse(
|
|
45170
|
+
const pkg = JSON.parse(readFileSync29(join39(root, "package.json"), "utf8"));
|
|
45089
45171
|
return pkg.name === "@kontextmind/kxm";
|
|
45090
45172
|
} catch {
|
|
45091
45173
|
return false;
|
|
@@ -45107,8 +45189,8 @@ function lastSegments(path4) {
|
|
|
45107
45189
|
function segmentEq(left, right, platform) {
|
|
45108
45190
|
return platform === "win32" ? left.toLocaleLowerCase("en-US") === right.toLocaleLowerCase("en-US") : left === right;
|
|
45109
45191
|
}
|
|
45110
|
-
function isNpmPackageLayout(
|
|
45111
|
-
const last = lastSegments(
|
|
45192
|
+
function isNpmPackageLayout(repoRoot, platform) {
|
|
45193
|
+
const last = lastSegments(repoRoot);
|
|
45112
45194
|
const expected = ["node_modules", "@kontextmind", "kxm"];
|
|
45113
45195
|
return last.length === 3 && last.every((part, i) => segmentEq(part, expected[i], platform));
|
|
45114
45196
|
}
|
|
@@ -45134,12 +45216,12 @@ function report(kind, root) {
|
|
|
45134
45216
|
return { kind, root, instruction: installKindInstruction(kind, root) };
|
|
45135
45217
|
}
|
|
45136
45218
|
function classifyInstallRoot(probe) {
|
|
45137
|
-
const piGitRoot =
|
|
45219
|
+
const piGitRoot = join39(probe.homeDir, ".pi", "agent", "git");
|
|
45138
45220
|
if (isUnder(probe.repoRoot, piGitRoot, probe.platform)) return report("pi-git", probe.repoRoot);
|
|
45139
|
-
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() ||
|
|
45140
|
-
const pluginsRoot =
|
|
45221
|
+
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() || join39(probe.homeDir, ".claude");
|
|
45222
|
+
const pluginsRoot = join39(claudeHome, "plugins");
|
|
45141
45223
|
if (isUnder(probe.moduleDir, pluginsRoot, probe.platform)) return report("claude-marketplace", probe.moduleDir);
|
|
45142
|
-
const hasGit =
|
|
45224
|
+
const hasGit = existsSync29(join39(probe.repoRoot, ".git"));
|
|
45143
45225
|
if (hasGit && packageIsKxm(probe.repoRoot)) return report("source", probe.repoRoot);
|
|
45144
45226
|
if (isNpmPackageLayout(probe.repoRoot, probe.platform) && packageIsKxm(probe.repoRoot) && !hasGit) {
|
|
45145
45227
|
return report("npm-package", probe.repoRoot);
|
|
@@ -45153,21 +45235,21 @@ function resolveInstallKind(probe, npmGlobalRoot) {
|
|
|
45153
45235
|
if (typeof globalRoot !== "string" || globalRoot.trim() === "") {
|
|
45154
45236
|
return report("unknown", classified.root);
|
|
45155
45237
|
}
|
|
45156
|
-
const expected =
|
|
45238
|
+
const expected = dirname19(dirname19(classified.root));
|
|
45157
45239
|
if (sameHostPath2(globalRoot.trim(), expected, probe.platform)) return report("npm-global", classified.root);
|
|
45158
45240
|
return report("npm-local", classified.root);
|
|
45159
45241
|
}
|
|
45160
45242
|
|
|
45161
45243
|
// plugins/kxm/src/kxm-update-config.ts
|
|
45162
45244
|
var import_yaml16 = __toESM(require_dist(), 1);
|
|
45163
|
-
import { existsSync as
|
|
45164
|
-
import { join as
|
|
45245
|
+
import { existsSync as existsSync30, readFileSync as readFileSync30 } from "node:fs";
|
|
45246
|
+
import { join as join40 } from "node:path";
|
|
45165
45247
|
function loadKxmUpdateConfig(env = process.env) {
|
|
45166
|
-
const path4 =
|
|
45167
|
-
if (!
|
|
45248
|
+
const path4 = join40(vnextUserStateRoot({ env }), "update.yaml");
|
|
45249
|
+
if (!existsSync30(path4)) return { schema: KXM_UPDATE_SCHEMA, auto: false, source: "github" };
|
|
45168
45250
|
let parsed;
|
|
45169
45251
|
try {
|
|
45170
|
-
parsed = (0, import_yaml16.parse)(
|
|
45252
|
+
parsed = (0, import_yaml16.parse)(readFileSync30(path4, "utf8"));
|
|
45171
45253
|
} catch {
|
|
45172
45254
|
throw new KxmUpdateConfigError("update.yaml is not valid YAML");
|
|
45173
45255
|
}
|
|
@@ -45193,8 +45275,8 @@ function loadKxmUpdateConfig(env = process.env) {
|
|
|
45193
45275
|
}
|
|
45194
45276
|
|
|
45195
45277
|
// plugins/kxm/src/session.ts
|
|
45196
|
-
import { existsSync as
|
|
45197
|
-
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";
|
|
45198
45280
|
var SESSION_SCHEMA = "kxm.session.v1";
|
|
45199
45281
|
var SessionConfigError = class extends Error {
|
|
45200
45282
|
code = "session_config_invalid";
|
|
@@ -45204,12 +45286,12 @@ var SessionConfigError = class extends Error {
|
|
|
45204
45286
|
}
|
|
45205
45287
|
};
|
|
45206
45288
|
function workflowAssetDirs(assetsDir, workflowId) {
|
|
45207
|
-
const root =
|
|
45208
|
-
return [root,
|
|
45289
|
+
const root = join41(assetsDir, "workflows", workflowId);
|
|
45290
|
+
return [root, join41(root, "inputs"), join41(root, "outputs"), join41(root, "generated")];
|
|
45209
45291
|
}
|
|
45210
45292
|
function sessionAssetDirs(assetsDir, sessionId) {
|
|
45211
|
-
const root =
|
|
45212
|
-
return [root,
|
|
45293
|
+
const root = join41(assetsDir, "sessions", sessionId);
|
|
45294
|
+
return [root, join41(root, "inputs"), join41(root, "outputs")];
|
|
45213
45295
|
}
|
|
45214
45296
|
function rosterNames(configDir) {
|
|
45215
45297
|
return [...loadRosterMap(configDir).values()].map((row) => String(row.name));
|
|
@@ -45259,7 +45341,7 @@ function workerFromRosterRow(name, row, project) {
|
|
|
45259
45341
|
function loadRosterMap(configDir) {
|
|
45260
45342
|
const byName = /* @__PURE__ */ new Map();
|
|
45261
45343
|
for (const [file, key] of [["agents.json", "agents"], ["gates.json", "gates"]]) {
|
|
45262
|
-
const path4 =
|
|
45344
|
+
const path4 = join41(configDir, file);
|
|
45263
45345
|
for (const row of loadRoster(path4, key)) {
|
|
45264
45346
|
const name = String(row.name).trim();
|
|
45265
45347
|
const lowered = name.toLowerCase();
|
|
@@ -45273,10 +45355,10 @@ function loadRosterMap(configDir) {
|
|
|
45273
45355
|
return byName;
|
|
45274
45356
|
}
|
|
45275
45357
|
function loadRoster(path4, key) {
|
|
45276
|
-
if (!
|
|
45358
|
+
if (!existsSync31(path4)) return [];
|
|
45277
45359
|
let parsed;
|
|
45278
45360
|
try {
|
|
45279
|
-
parsed = JSON.parse(
|
|
45361
|
+
parsed = JSON.parse(readFileSync31(path4, "utf8"));
|
|
45280
45362
|
} catch (error) {
|
|
45281
45363
|
throw new SessionConfigError(
|
|
45282
45364
|
`${key} roster at ${path4} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -45301,7 +45383,7 @@ function loadRoster(path4, key) {
|
|
|
45301
45383
|
});
|
|
45302
45384
|
}
|
|
45303
45385
|
function createSession(input) {
|
|
45304
|
-
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);
|
|
45305
45387
|
return {
|
|
45306
45388
|
schema: SESSION_SCHEMA,
|
|
45307
45389
|
id: input.id,
|
|
@@ -45314,20 +45396,20 @@ function createSession(input) {
|
|
|
45314
45396
|
};
|
|
45315
45397
|
}
|
|
45316
45398
|
function writeSession(assetsDir, session, dryRun = false) {
|
|
45317
|
-
const dir =
|
|
45318
|
-
const path4 =
|
|
45399
|
+
const dir = join41(assetsDir, "sessions", session.id);
|
|
45400
|
+
const path4 = join41(dir, "session.json");
|
|
45319
45401
|
if (!dryRun) {
|
|
45320
|
-
|
|
45321
|
-
|
|
45402
|
+
mkdirSync25(dir, { recursive: true });
|
|
45403
|
+
writeFileSync23(path4, `${JSON.stringify(session, null, 2)}
|
|
45322
45404
|
`, { encoding: "utf8" });
|
|
45323
45405
|
}
|
|
45324
45406
|
return path4;
|
|
45325
45407
|
}
|
|
45326
45408
|
|
|
45327
45409
|
// plugins/kxm/src/cli/hub.ts
|
|
45328
|
-
import { fileURLToPath as
|
|
45329
|
-
import { dirname as
|
|
45330
|
-
import { homedir as
|
|
45410
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
45411
|
+
import { dirname as dirname20 } from "node:path";
|
|
45412
|
+
import { homedir as homedir7 } from "node:os";
|
|
45331
45413
|
async function hubGet(url, fetchImpl) {
|
|
45332
45414
|
try {
|
|
45333
45415
|
const response = await fetchImpl(url);
|
|
@@ -45345,17 +45427,17 @@ async function hubGet(url, fetchImpl) {
|
|
|
45345
45427
|
function installProbeFrom(runtime) {
|
|
45346
45428
|
const partial = runtime.io.installProbe ?? {};
|
|
45347
45429
|
return {
|
|
45348
|
-
moduleDir: partial.moduleDir ??
|
|
45430
|
+
moduleDir: partial.moduleDir ?? dirname20(fileURLToPath3(import.meta.url)),
|
|
45349
45431
|
repoRoot: partial.repoRoot ?? resolve25("."),
|
|
45350
|
-
homeDir: partial.homeDir ??
|
|
45432
|
+
homeDir: partial.homeDir ?? homedir7(),
|
|
45351
45433
|
platform: partial.platform ?? process.platform,
|
|
45352
45434
|
env: partial.env ?? runtime.env
|
|
45353
45435
|
};
|
|
45354
45436
|
}
|
|
45355
45437
|
function warnIgnoredProjectUpdateYaml(runtime) {
|
|
45356
|
-
const projectFile =
|
|
45357
|
-
if (!
|
|
45358
|
-
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");
|
|
45359
45441
|
runtime.io.stderr(`kxm: ignoring .kxm/update.yaml in ${runtime.dirs.workdir}; update settings are read only from ${userFile}
|
|
45360
45442
|
`);
|
|
45361
45443
|
}
|
|
@@ -45381,7 +45463,7 @@ async function cmdDash(runtime, options = {}) {
|
|
|
45381
45463
|
return 2;
|
|
45382
45464
|
}
|
|
45383
45465
|
const screen = requested;
|
|
45384
|
-
const dataPath = resolve25(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() ||
|
|
45466
|
+
const dataPath = resolve25(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join42(runtime.dirs.state, "kxm.db"));
|
|
45385
45467
|
if (runtime.dryRun) {
|
|
45386
45468
|
print(runtime.io, runtime.json, {
|
|
45387
45469
|
ok: true,
|
|
@@ -45427,7 +45509,7 @@ async function cmdHub(runtime) {
|
|
|
45427
45509
|
config = loadKxmUpdateConfig(runtime.env);
|
|
45428
45510
|
} catch (error) {
|
|
45429
45511
|
if (error instanceof KxmUpdateConfigError) {
|
|
45430
|
-
const yamlPath =
|
|
45512
|
+
const yamlPath = join42(vnextUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
45431
45513
|
runtime.io.stderr(`kxm: ${error.message}; update check skipped; fix or remove ${yamlPath}
|
|
45432
45514
|
`);
|
|
45433
45515
|
} else {
|
|
@@ -45563,7 +45645,7 @@ async function cmdWorker(runtime, options) {
|
|
|
45563
45645
|
return await (runtime.io.spawnWorker ?? ((launchEnv) => spawnScript("kxm-worker.mjs", launchEnv)))(extraEnv);
|
|
45564
45646
|
}
|
|
45565
45647
|
async function cmdStop(runtime, waitMsFlag) {
|
|
45566
|
-
const pids =
|
|
45648
|
+
const pids = existsSync32(runtime.dirs.state) ? readdirSync12(runtime.dirs.state).filter((name) => name.endsWith(".pid")) : [];
|
|
45567
45649
|
if (runtime.dryRun) {
|
|
45568
45650
|
print(runtime.io, runtime.json, { ok: true, command: "stop", dryRun: true, pidFiles: pids }, "would signal pid files");
|
|
45569
45651
|
return 0;
|
|
@@ -45578,7 +45660,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45578
45660
|
const orphans = [];
|
|
45579
45661
|
for (const file of pids) {
|
|
45580
45662
|
try {
|
|
45581
|
-
const record = JSON.parse(
|
|
45663
|
+
const record = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
|
|
45582
45664
|
const expectedControl = file === "hub.pid" ? "hub.stop" : file.startsWith("worker-") ? `${file.slice(0, -4)}.stop` : void 0;
|
|
45583
45665
|
const expectedRole = file === "hub.pid" ? "hub" : file.startsWith("worker-") ? "worker" : void 0;
|
|
45584
45666
|
if (record.version !== 1 || !Number.isInteger(record.pid) || record.pid <= 0 || !record.startedAt || !expectedControl || record.controlFile !== expectedControl || record.role !== expectedRole) {
|
|
@@ -45598,7 +45680,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45598
45680
|
ignored.push(file);
|
|
45599
45681
|
continue;
|
|
45600
45682
|
}
|
|
45601
|
-
|
|
45683
|
+
writeFileSync24(join42(runtime.dirs.state, record.controlFile), `${JSON.stringify({ startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {}, requestedAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
45602
45684
|
`, { encoding: "utf8", mode: 384 });
|
|
45603
45685
|
requested.push(file);
|
|
45604
45686
|
records.set(file, { pid: record.pid, startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {} });
|
|
@@ -45616,7 +45698,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45616
45698
|
while (Date.now() <= deadline && stopped.size < requested.length) {
|
|
45617
45699
|
for (const [file, record] of records) {
|
|
45618
45700
|
try {
|
|
45619
|
-
const current = JSON.parse(
|
|
45701
|
+
const current = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
|
|
45620
45702
|
if (current.pid !== record.pid || current.startedAt !== record.startedAt || current.generation !== record.generation || !processExists(record.pid)) stopped.add(file);
|
|
45621
45703
|
} catch {
|
|
45622
45704
|
stopped.add(file);
|
|
@@ -45629,7 +45711,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45629
45711
|
for (const file of orphans) {
|
|
45630
45712
|
while (Date.now() <= deadlineOrphans) {
|
|
45631
45713
|
try {
|
|
45632
|
-
const current = JSON.parse(
|
|
45714
|
+
const current = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
|
|
45633
45715
|
if (!Number.isInteger(current.serverPid) || !processExists(current.serverPid)) break;
|
|
45634
45716
|
} catch {
|
|
45635
45717
|
break;
|
|
@@ -45637,14 +45719,14 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45637
45719
|
await (runtime.io.sleep ?? ((ms) => new Promise((resolveSleep) => setTimeout(resolveSleep, ms))))(100);
|
|
45638
45720
|
}
|
|
45639
45721
|
try {
|
|
45640
|
-
const current = JSON.parse(
|
|
45722
|
+
const current = JSON.parse(readFileSync32(join42(runtime.dirs.state, file), "utf8"));
|
|
45641
45723
|
if (Number.isInteger(current.serverPid) && processExists(current.serverPid)) {
|
|
45642
45724
|
try {
|
|
45643
45725
|
process.kill(current.serverPid, "SIGKILL");
|
|
45644
45726
|
} catch {
|
|
45645
45727
|
}
|
|
45646
45728
|
}
|
|
45647
|
-
|
|
45729
|
+
rmSync11(join42(runtime.dirs.state, file), { force: true });
|
|
45648
45730
|
} catch {
|
|
45649
45731
|
}
|
|
45650
45732
|
stopped.add(file);
|
|
@@ -45655,11 +45737,11 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45655
45737
|
}
|
|
45656
45738
|
async function cmdSessionStatus(runtime) {
|
|
45657
45739
|
const stateDir = runtime.dirs.state;
|
|
45658
|
-
const names3 =
|
|
45740
|
+
const names3 = existsSync32(stateDir) ? readdirSync12(stateDir) : [];
|
|
45659
45741
|
const claims = [];
|
|
45660
45742
|
for (const file of names3.filter((name) => name.endsWith(".pid"))) {
|
|
45661
45743
|
try {
|
|
45662
|
-
const record = JSON.parse(
|
|
45744
|
+
const record = JSON.parse(readFileSync32(join42(stateDir, file), "utf8"));
|
|
45663
45745
|
claims.push({
|
|
45664
45746
|
file,
|
|
45665
45747
|
role: record.role,
|
|
@@ -45674,7 +45756,7 @@ async function cmdSessionStatus(runtime) {
|
|
|
45674
45756
|
const recoveries = [];
|
|
45675
45757
|
for (const file of names3.filter((name) => name.startsWith("worker-recovery-") && name.endsWith(".json"))) {
|
|
45676
45758
|
try {
|
|
45677
|
-
const envelope = JSON.parse(
|
|
45759
|
+
const envelope = JSON.parse(readFileSync32(join42(stateDir, file), "utf8"));
|
|
45678
45760
|
recoveries.push({
|
|
45679
45761
|
file,
|
|
45680
45762
|
reason: envelope.reason,
|
|
@@ -45779,7 +45861,7 @@ async function cmdSessionBrief(runtime, options = {}) {
|
|
|
45779
45861
|
print(runtime.io, runtime.json, { ok: true, command: "session brief", sessionToken }, sessionToken);
|
|
45780
45862
|
return 0;
|
|
45781
45863
|
}
|
|
45782
|
-
const dataPath = resolve25(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() ||
|
|
45864
|
+
const dataPath = resolve25(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join42(runtime.dirs.state, "kxm.db"));
|
|
45783
45865
|
const env = {
|
|
45784
45866
|
...runtime.env,
|
|
45785
45867
|
KXM_STATE_DIR: runtime.dirs.state,
|
|
@@ -45855,7 +45937,7 @@ async function cmdSessionStart(runtime, options) {
|
|
|
45855
45937
|
...workflowId ? workflowAssetDirs(runtime.dirs.assets, workflowId) : []
|
|
45856
45938
|
];
|
|
45857
45939
|
if (!runtime.dryRun) {
|
|
45858
|
-
for (const directory of created)
|
|
45940
|
+
for (const directory of created) mkdirSync26(directory, { recursive: true });
|
|
45859
45941
|
writeSession(runtime.dirs.assets, session);
|
|
45860
45942
|
}
|
|
45861
45943
|
print(runtime.io, runtime.json, {
|
|
@@ -45871,16 +45953,15 @@ async function cmdSessionStart(runtime, options) {
|
|
|
45871
45953
|
// plugins/kxm/src/cli/system.ts
|
|
45872
45954
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
45873
45955
|
import { createHash as createHash16 } from "node:crypto";
|
|
45874
|
-
import { existsSync as
|
|
45956
|
+
import { existsSync as existsSync38, mkdtempSync as mkdtempSync2, readFileSync as readFileSync37, rmSync as rmSync13 } from "node:fs";
|
|
45875
45957
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
45876
|
-
import { join as
|
|
45958
|
+
import { join as join48, resolve as resolve29 } from "node:path";
|
|
45877
45959
|
import { createInterface as createInterface3 } from "node:readline";
|
|
45878
|
-
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
45879
45960
|
|
|
45880
45961
|
// plugins/kxm/src/improve.ts
|
|
45881
45962
|
import { createHash as createHash15 } from "node:crypto";
|
|
45882
|
-
import { existsSync as
|
|
45883
|
-
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";
|
|
45884
45965
|
var CANDIDATE_SCHEMA = "kxm.candidate.v1";
|
|
45885
45966
|
var IMPROVEMENT_REPORT_SCHEMA = "kxm.improvement-report.v2";
|
|
45886
45967
|
function classifyCandidateKind(stepId, agentRole) {
|
|
@@ -46052,7 +46133,7 @@ function groupRoutingRecords(records, options = {}) {
|
|
|
46052
46133
|
}
|
|
46053
46134
|
function buildImprovementReport(records, options = {}) {
|
|
46054
46135
|
const projectRoot = options.projectRoot ? resolve26(options.projectRoot) : process.cwd();
|
|
46055
|
-
const candidatesDir = options.candidatesDir ? resolve26(options.candidatesDir) :
|
|
46136
|
+
const candidatesDir = options.candidatesDir ? resolve26(options.candidatesDir) : join43(projectRoot, ".kxm", "candidates");
|
|
46056
46137
|
const groups = groupRoutingRecords(records, options);
|
|
46057
46138
|
const candidates = [];
|
|
46058
46139
|
for (const group of groups) {
|
|
@@ -46064,7 +46145,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46064
46145
|
group.workflowHash
|
|
46065
46146
|
);
|
|
46066
46147
|
const diffFileName = `${group.candidateId}.diff`;
|
|
46067
|
-
const diffFilePath =
|
|
46148
|
+
const diffFilePath = join43(candidatesDir, diffFileName);
|
|
46068
46149
|
const relDiffPath = relative6(projectRoot, diffFilePath).replace(/\\/g, "/");
|
|
46069
46150
|
const candidate = {
|
|
46070
46151
|
schema: CANDIDATE_SCHEMA,
|
|
@@ -46086,12 +46167,12 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46086
46167
|
createdAt: nowIso()
|
|
46087
46168
|
};
|
|
46088
46169
|
if (!options.dryRun) {
|
|
46089
|
-
if (!
|
|
46090
|
-
|
|
46170
|
+
if (!existsSync33(candidatesDir)) {
|
|
46171
|
+
mkdirSync27(candidatesDir, { recursive: true });
|
|
46091
46172
|
}
|
|
46092
|
-
|
|
46093
|
-
const jsonFilePath =
|
|
46094
|
-
|
|
46173
|
+
writeFileSync25(diffFilePath, diff, "utf8");
|
|
46174
|
+
const jsonFilePath = join43(candidatesDir, `${group.candidateId}.json`);
|
|
46175
|
+
writeFileSync25(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
|
|
46095
46176
|
}
|
|
46096
46177
|
candidates.push(candidate);
|
|
46097
46178
|
}
|
|
@@ -46106,10 +46187,10 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46106
46187
|
}
|
|
46107
46188
|
function writeImprovementReport(improvementsDir, report2, dryRun = false) {
|
|
46108
46189
|
const stamp = report2.createdAt.replace(/[:.]/g, "-");
|
|
46109
|
-
const path4 =
|
|
46190
|
+
const path4 = join43(improvementsDir, `${stamp}.json`);
|
|
46110
46191
|
if (!dryRun) {
|
|
46111
|
-
|
|
46112
|
-
|
|
46192
|
+
mkdirSync27(improvementsDir, { recursive: true });
|
|
46193
|
+
writeFileSync25(path4, `${JSON.stringify(report2, null, 2)}
|
|
46113
46194
|
`, { encoding: "utf8" });
|
|
46114
46195
|
}
|
|
46115
46196
|
return path4;
|
|
@@ -46149,8 +46230,8 @@ function formatImprovementReport(report2) {
|
|
|
46149
46230
|
|
|
46150
46231
|
// plugins/kxm/src/modes.ts
|
|
46151
46232
|
var import_yaml17 = __toESM(require_dist(), 1);
|
|
46152
|
-
import { existsSync as
|
|
46153
|
-
import { join as
|
|
46233
|
+
import { existsSync as existsSync34, readFileSync as readFileSync34 } from "node:fs";
|
|
46234
|
+
import { join as join44 } from "node:path";
|
|
46154
46235
|
var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
46155
46236
|
schema: "kxm.modes.v1",
|
|
46156
46237
|
majorModes: {
|
|
@@ -46213,12 +46294,12 @@ function loadModesConfig(projectRoot) {
|
|
|
46213
46294
|
if (!projectRoot) {
|
|
46214
46295
|
return DEFAULT_MODES_CONFIG;
|
|
46215
46296
|
}
|
|
46216
|
-
const modesPath =
|
|
46217
|
-
if (!
|
|
46297
|
+
const modesPath = join44(projectRoot, ".kxm", "modes.yaml");
|
|
46298
|
+
if (!existsSync34(modesPath)) {
|
|
46218
46299
|
return DEFAULT_MODES_CONFIG;
|
|
46219
46300
|
}
|
|
46220
46301
|
try {
|
|
46221
|
-
const raw =
|
|
46302
|
+
const raw = readFileSync34(modesPath, "utf8");
|
|
46222
46303
|
const parsed = (0, import_yaml17.parse)(raw);
|
|
46223
46304
|
if (parsed && parsed.schema === "kxm.modes.v1" && parsed.majorModes) {
|
|
46224
46305
|
return {
|
|
@@ -46304,11 +46385,11 @@ function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog
|
|
|
46304
46385
|
estimatedTokens: estimateTokens(baseSystemPromptChars)
|
|
46305
46386
|
});
|
|
46306
46387
|
for (const relPath of resolved.contextFiles) {
|
|
46307
|
-
const fullPath =
|
|
46388
|
+
const fullPath = join44(projectRoot, relPath);
|
|
46308
46389
|
let chars = 0;
|
|
46309
|
-
if (
|
|
46390
|
+
if (existsSync34(fullPath)) {
|
|
46310
46391
|
try {
|
|
46311
|
-
chars =
|
|
46392
|
+
chars = readFileSync34(fullPath, "utf8").length;
|
|
46312
46393
|
} catch {
|
|
46313
46394
|
chars = 0;
|
|
46314
46395
|
}
|
|
@@ -46440,9 +46521,9 @@ ${divider}
|
|
|
46440
46521
|
|
|
46441
46522
|
// plugins/kxm/src/ssh-remote.ts
|
|
46442
46523
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
46443
|
-
import { existsSync as
|
|
46444
|
-
import { homedir as
|
|
46445
|
-
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";
|
|
46446
46527
|
var MAX_SSH_OUTPUT_BYTES = 50 * 1024;
|
|
46447
46528
|
var MAX_SSH_OUTPUT_LINES = 2e3;
|
|
46448
46529
|
var DEFAULT_SOCKET_DIR = ".kxm/run/ssh-sockets";
|
|
@@ -46468,12 +46549,12 @@ function truncateSshOutput(raw) {
|
|
|
46468
46549
|
return { text, truncated };
|
|
46469
46550
|
}
|
|
46470
46551
|
function parseSshConfig(configPath) {
|
|
46471
|
-
const targetPath = configPath ??
|
|
46472
|
-
if (!
|
|
46552
|
+
const targetPath = configPath ?? join45(homedir8(), ".ssh", "config");
|
|
46553
|
+
if (!existsSync35(targetPath)) {
|
|
46473
46554
|
return [];
|
|
46474
46555
|
}
|
|
46475
46556
|
try {
|
|
46476
|
-
const content =
|
|
46557
|
+
const content = readFileSync35(targetPath, "utf-8");
|
|
46477
46558
|
const lines = content.split("\n");
|
|
46478
46559
|
const hosts = [];
|
|
46479
46560
|
let currentHosts = [];
|
|
@@ -46551,14 +46632,14 @@ function resolveSshHostG(host, execFn = spawnSync7) {
|
|
|
46551
46632
|
}
|
|
46552
46633
|
function ensureSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
46553
46634
|
const resolved = resolve27(socketDir);
|
|
46554
|
-
if (!
|
|
46555
|
-
|
|
46635
|
+
if (!existsSync35(resolved)) {
|
|
46636
|
+
mkdirSync28(resolved, { recursive: true, mode: 448 });
|
|
46556
46637
|
}
|
|
46557
46638
|
return resolved;
|
|
46558
46639
|
}
|
|
46559
46640
|
function buildSshArgs(options) {
|
|
46560
46641
|
const socketDir = ensureSocketDir(options.socketDir ?? DEFAULT_SOCKET_DIR);
|
|
46561
|
-
const controlPath =
|
|
46642
|
+
const controlPath = join45(socketDir, "%C");
|
|
46562
46643
|
const persist = options.controlPersist ?? DEFAULT_CONTROL_PERSIST;
|
|
46563
46644
|
const args = [
|
|
46564
46645
|
"-o",
|
|
@@ -46583,7 +46664,7 @@ function buildSshArgs(options) {
|
|
|
46583
46664
|
}
|
|
46584
46665
|
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
46585
46666
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
46586
|
-
const controlPath =
|
|
46667
|
+
const controlPath = join45(resolvedDir, "%C");
|
|
46587
46668
|
try {
|
|
46588
46669
|
const result = execFn("ssh", ["-O", "check", "-o", `ControlPath=${controlPath}`, host], {
|
|
46589
46670
|
encoding: "utf-8"
|
|
@@ -46595,7 +46676,7 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
46595
46676
|
}
|
|
46596
46677
|
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
46597
46678
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
46598
|
-
const controlPath =
|
|
46679
|
+
const controlPath = join45(resolvedDir, "%C");
|
|
46599
46680
|
try {
|
|
46600
46681
|
const result = execFn("ssh", ["-O", "stop", "-o", `ControlPath=${controlPath}`, host], {
|
|
46601
46682
|
encoding: "utf-8"
|
|
@@ -47041,9 +47122,9 @@ complete -c kxm -n "__fish_seen_subcommand_from goal" -a "create list get"
|
|
|
47041
47122
|
}
|
|
47042
47123
|
|
|
47043
47124
|
// plugins/kxm/src/completion-install.ts
|
|
47044
|
-
import { existsSync as
|
|
47045
|
-
import { homedir as
|
|
47046
|
-
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";
|
|
47047
47128
|
var COMPLETION_MARKER = "# kxm completion";
|
|
47048
47129
|
var PATH_MARKER = "# kxm path";
|
|
47049
47130
|
function detectShell(env = process.env, platform = process.platform) {
|
|
@@ -47059,31 +47140,31 @@ function effectiveHome(options) {
|
|
|
47059
47140
|
const env = options.env ?? process.env;
|
|
47060
47141
|
if (options.homeDir) return options.homeDir;
|
|
47061
47142
|
const envHome = env.HOME?.trim() ?? env.USERPROFILE?.trim();
|
|
47062
|
-
return envHome && envHome.length > 0 ? resolve28(envHome) :
|
|
47143
|
+
return envHome && envHome.length > 0 ? resolve28(envHome) : homedir9();
|
|
47063
47144
|
}
|
|
47064
47145
|
function completionScriptPath(shell, options = {}) {
|
|
47065
47146
|
const env = options.env ?? process.env;
|
|
47066
47147
|
const explicit = options.configDir ?? env.KXM_USER_CONFIG_DIR?.trim();
|
|
47067
47148
|
const base = explicit && explicit.length > 0 ? resolve28(explicit) : resolve28(effectiveHome(options), ".config", "kxm");
|
|
47068
|
-
return
|
|
47149
|
+
return join46(base, "completions", `kxm.${shell}`);
|
|
47069
47150
|
}
|
|
47070
47151
|
function bashRcCandidate(options) {
|
|
47071
47152
|
const home = effectiveHome(options);
|
|
47072
|
-
const candidates = [
|
|
47073
|
-
const existing = candidates.find((candidate) =>
|
|
47153
|
+
const candidates = [join46(home, ".bashrc"), join46(home, ".bash_profile")];
|
|
47154
|
+
const existing = candidates.find((candidate) => existsSync36(candidate));
|
|
47074
47155
|
return existing ?? candidates[0];
|
|
47075
47156
|
}
|
|
47076
47157
|
function zshRcCandidate(options) {
|
|
47077
47158
|
const env = options.env ?? process.env;
|
|
47078
47159
|
const home = effectiveHome(options);
|
|
47079
|
-
if (env.ZDOTDIR?.trim()) return
|
|
47080
|
-
return
|
|
47160
|
+
if (env.ZDOTDIR?.trim()) return join46(resolve28(env.ZDOTDIR.trim()), ".zshrc");
|
|
47161
|
+
return join46(home, ".zshrc");
|
|
47081
47162
|
}
|
|
47082
47163
|
function fishCompletionTarget(shell, options) {
|
|
47083
47164
|
const env = options.env ?? process.env;
|
|
47084
47165
|
const home = effectiveHome(options);
|
|
47085
|
-
if (env.XDG_CONFIG_HOME?.trim()) return
|
|
47086
|
-
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");
|
|
47087
47168
|
}
|
|
47088
47169
|
function completionRcTarget(shell, options = {}) {
|
|
47089
47170
|
if (shell === "fish") {
|
|
@@ -47115,17 +47196,17 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47115
47196
|
const scriptPath = completionScriptPath(shell, options);
|
|
47116
47197
|
const { rcFile } = completionRcTarget(shell, options);
|
|
47117
47198
|
const script = generateShellCompletion(shell);
|
|
47118
|
-
const existingScript =
|
|
47119
|
-
const existingScriptMatches = existingScript &&
|
|
47199
|
+
const existingScript = existsSync36(scriptPath);
|
|
47200
|
+
const existingScriptMatches = existingScript && readFileSync36(scriptPath, "utf8") === script;
|
|
47120
47201
|
let rcModified = false;
|
|
47121
47202
|
let alreadyInstalled = false;
|
|
47122
47203
|
if (shell === "fish") {
|
|
47123
47204
|
const fishTarget = fishCompletionTarget(shell, options);
|
|
47124
|
-
const fishInstalled =
|
|
47205
|
+
const fishInstalled = existsSync36(fishTarget) && readFileSync36(fishTarget, "utf8") === script;
|
|
47125
47206
|
alreadyInstalled = fishInstalled;
|
|
47126
47207
|
if (!options.dryRun && (!fishInstalled || options.overwrite)) {
|
|
47127
|
-
|
|
47128
|
-
|
|
47208
|
+
mkdirSync29(resolve28(fishTarget, ".."), { recursive: true });
|
|
47209
|
+
writeFileSync26(fishTarget, script, { encoding: "utf8" });
|
|
47129
47210
|
}
|
|
47130
47211
|
return {
|
|
47131
47212
|
ok: true,
|
|
@@ -47138,13 +47219,13 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47138
47219
|
}
|
|
47139
47220
|
if (rcFile) {
|
|
47140
47221
|
const line = sourceLine(shell, scriptPath);
|
|
47141
|
-
const rcContent =
|
|
47222
|
+
const rcContent = existsSync36(rcFile) ? readFileSync36(rcFile, "utf8") : "";
|
|
47142
47223
|
alreadyInstalled = rcContent.includes(line) || rcContent.includes(`${COMPLETION_MARKER}`);
|
|
47143
47224
|
}
|
|
47144
47225
|
if (!options.dryRun) {
|
|
47145
47226
|
if (!existingScriptMatches || options.overwrite) {
|
|
47146
|
-
|
|
47147
|
-
|
|
47227
|
+
mkdirSync29(resolve28(scriptPath, ".."), { recursive: true });
|
|
47228
|
+
writeFileSync26(scriptPath, script, { encoding: "utf8" });
|
|
47148
47229
|
}
|
|
47149
47230
|
if (rcFile && !alreadyInstalled) {
|
|
47150
47231
|
const line = sourceLine(shell, scriptPath);
|
|
@@ -47153,8 +47234,8 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47153
47234
|
${marker}
|
|
47154
47235
|
${line}
|
|
47155
47236
|
`;
|
|
47156
|
-
|
|
47157
|
-
|
|
47237
|
+
mkdirSync29(resolve28(rcFile, ".."), { recursive: true });
|
|
47238
|
+
writeFileSync26(rcFile, (existsSync36(rcFile) ? readFileSync36(rcFile, "utf8") : "") + stanza, { encoding: "utf8" });
|
|
47158
47239
|
rcModified = true;
|
|
47159
47240
|
}
|
|
47160
47241
|
}
|
|
@@ -47169,15 +47250,15 @@ ${line}
|
|
|
47169
47250
|
}
|
|
47170
47251
|
function kxmBinDir(env = process.env) {
|
|
47171
47252
|
const argv1 = env.KXM_ENTRY ?? process.argv[1];
|
|
47172
|
-
if (argv1 &&
|
|
47173
|
-
const dir =
|
|
47174
|
-
if (
|
|
47253
|
+
if (argv1 && isAbsolute9(argv1)) {
|
|
47254
|
+
const dir = dirname22(argv1);
|
|
47255
|
+
if (existsSync36(join46(dir, process.platform === "win32" ? "kxm.cmd" : "kxm"))) return dir;
|
|
47175
47256
|
}
|
|
47176
47257
|
const pathEnv = env.PATH ?? "";
|
|
47177
47258
|
for (const part of pathEnv.split(delimiter)) {
|
|
47178
47259
|
if (!part) continue;
|
|
47179
47260
|
const candidate = resolve28(part, process.platform === "win32" ? "kxm.cmd" : "kxm");
|
|
47180
|
-
if (
|
|
47261
|
+
if (existsSync36(candidate)) return resolve28(part);
|
|
47181
47262
|
}
|
|
47182
47263
|
return void 0;
|
|
47183
47264
|
}
|
|
@@ -47195,11 +47276,11 @@ function installPathEntry(shellInput, options = {}) {
|
|
|
47195
47276
|
}
|
|
47196
47277
|
const { rcFile } = completionRcTarget(shell, options);
|
|
47197
47278
|
const line = pathLine(binDir);
|
|
47198
|
-
const rcContent =
|
|
47279
|
+
const rcContent = existsSync36(rcFile ?? "") ? readFileSync36(rcFile, "utf8") : "";
|
|
47199
47280
|
const alreadyInstalled = rcContent.includes(binDir) || (options.env?.PATH ?? process.env.PATH ?? "").split(delimiter).includes(binDir);
|
|
47200
47281
|
if (!options.dryRun && rcFile && !alreadyInstalled) {
|
|
47201
|
-
|
|
47202
|
-
|
|
47282
|
+
mkdirSync29(dirname22(rcFile), { recursive: true });
|
|
47283
|
+
writeFileSync26(rcFile, rcContent + `
|
|
47203
47284
|
${PATH_MARKER}
|
|
47204
47285
|
${line}
|
|
47205
47286
|
`, { encoding: "utf8" });
|
|
@@ -47209,8 +47290,8 @@ ${line}
|
|
|
47209
47290
|
|
|
47210
47291
|
// plugins/kxm/src/init-guide-setup.ts
|
|
47211
47292
|
var import_yaml18 = __toESM(require_dist(), 1);
|
|
47212
|
-
import { existsSync as
|
|
47213
|
-
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";
|
|
47214
47295
|
var NATIVE_VENDOR_HARNESS = Object.freeze({
|
|
47215
47296
|
anthropic: "claude",
|
|
47216
47297
|
openai: "codex",
|
|
@@ -47609,13 +47690,13 @@ function renderGuideSetupFiles(projectRoot, plan) {
|
|
|
47609
47690
|
const stage = roleStages.get(role);
|
|
47610
47691
|
if (!stage) continue;
|
|
47611
47692
|
files.push({
|
|
47612
|
-
path:
|
|
47693
|
+
path: join47(projectRoot, ".kxm", "agents", `${role}.yaml`),
|
|
47613
47694
|
content: (0, import_yaml18.stringify)(agentDocument(role, stage, binding))
|
|
47614
47695
|
});
|
|
47615
47696
|
}
|
|
47616
47697
|
for (const workflow of plan.workflows) {
|
|
47617
47698
|
files.push({
|
|
47618
|
-
path:
|
|
47699
|
+
path: join47(projectRoot, ".kxm", "workflows", `${workflow.slug}.yaml`),
|
|
47619
47700
|
content: (0, import_yaml18.stringify)(workflowDocument(workflow))
|
|
47620
47701
|
});
|
|
47621
47702
|
}
|
|
@@ -47625,12 +47706,12 @@ function writeGuideSetupFiles(files) {
|
|
|
47625
47706
|
const written = [];
|
|
47626
47707
|
const existed = [];
|
|
47627
47708
|
for (const file of files) {
|
|
47628
|
-
if (
|
|
47709
|
+
if (existsSync37(file.path)) {
|
|
47629
47710
|
existed.push(file.path);
|
|
47630
47711
|
continue;
|
|
47631
47712
|
}
|
|
47632
|
-
|
|
47633
|
-
|
|
47713
|
+
mkdirSync30(dirname23(file.path), { recursive: true });
|
|
47714
|
+
writeFileSync27(file.path, file.content, "utf8");
|
|
47634
47715
|
written.push(file.path);
|
|
47635
47716
|
}
|
|
47636
47717
|
return { written, existed };
|
|
@@ -47653,7 +47734,6 @@ function parseGuideSelection(input, catalog = GUIDE_WORKFLOWS) {
|
|
|
47653
47734
|
}
|
|
47654
47735
|
|
|
47655
47736
|
// plugins/kxm/src/cli/system.ts
|
|
47656
|
-
var repoRoot4 = resolve29(fileURLToPath7(new URL("../../../../", import.meta.url)));
|
|
47657
47737
|
function cliSpawn(runtime, command, args, extra) {
|
|
47658
47738
|
if (runtime.io.spawnSync) return runtime.io.spawnSync(command, args);
|
|
47659
47739
|
const result = spawnSync8(command, [...args], {
|
|
@@ -47694,7 +47774,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
47694
47774
|
detail: `release v${notice.latest} has no sha256 digest for ${name}; refusing to install`
|
|
47695
47775
|
};
|
|
47696
47776
|
}
|
|
47697
|
-
const releaseDir = mkdtempSync2(
|
|
47777
|
+
const releaseDir = mkdtempSync2(join48(tmpdir2(), "kxm-pkg-update-"));
|
|
47698
47778
|
try {
|
|
47699
47779
|
const planned = planKxmPackageUpdate(notice.source, notice.latest, releaseDir, notice.asset);
|
|
47700
47780
|
if (runtime.dryRun) {
|
|
@@ -47703,7 +47783,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
47703
47783
|
for (const step of planned) {
|
|
47704
47784
|
if (step.kind === "verify") {
|
|
47705
47785
|
if (!verifyReleaseAssetDigest(step.path, step.sha256)) {
|
|
47706
|
-
const actual =
|
|
47786
|
+
const actual = existsSync38(step.path) ? createHash16("sha256").update(readFileSync37(step.path)).digest("hex") : "missing";
|
|
47707
47787
|
return {
|
|
47708
47788
|
ok: false,
|
|
47709
47789
|
error: "release_digest_mismatch",
|
|
@@ -47720,7 +47800,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
47720
47800
|
}
|
|
47721
47801
|
return { ok: true, detail: `installed ${notice.latest} from ${notice.source}` };
|
|
47722
47802
|
} finally {
|
|
47723
|
-
|
|
47803
|
+
rmSync13(releaseDir, { recursive: true, force: true });
|
|
47724
47804
|
}
|
|
47725
47805
|
}
|
|
47726
47806
|
async function cmdExplain(runtime, options) {
|
|
@@ -47822,7 +47902,7 @@ async function cmdUpdate(runtime, harness, options) {
|
|
|
47822
47902
|
warnIgnoredProjectUpdateYaml(runtime);
|
|
47823
47903
|
const probe = installProbeFrom(runtime);
|
|
47824
47904
|
const classified = classifyInstallRoot(probe);
|
|
47825
|
-
const current = readInstalledKxmVersion(
|
|
47905
|
+
const current = readInstalledKxmVersion(findKxmRepoRoot(import.meta.url));
|
|
47826
47906
|
let notice;
|
|
47827
47907
|
let kindReport = classified;
|
|
47828
47908
|
if (classified.kind === "source") {
|
|
@@ -47969,12 +48049,12 @@ async function cmdValidate(runtime, fileFlag) {
|
|
|
47969
48049
|
}
|
|
47970
48050
|
const selectedFile = explicitFile || configuredFile;
|
|
47971
48051
|
const file = selectedFile ? resolve29(runtime.cwd, selectedFile) : void 0;
|
|
47972
|
-
if (file && !
|
|
48052
|
+
if (file && !existsSync38(file)) {
|
|
47973
48053
|
printWorker(runtime, worker, { ok: false, command: "validate", error: "file_not_found", file }, `workflow file not found: ${file}`);
|
|
47974
48054
|
return 1;
|
|
47975
48055
|
}
|
|
47976
48056
|
try {
|
|
47977
|
-
const raw = file ?
|
|
48057
|
+
const raw = file ? readFileSync37(file, "utf8") : inline;
|
|
47978
48058
|
const warnings = [];
|
|
47979
48059
|
const definitions = parseWorkflowDefinitions(raw, runtime.env, (message) => warnings.push(message));
|
|
47980
48060
|
const secretEnvs = definitions.map((definition) => ({
|
|
@@ -48019,14 +48099,14 @@ async function cmdArtifactsExist(runtime, pathFlag) {
|
|
|
48019
48099
|
}
|
|
48020
48100
|
async function cmdImprove(runtime, options = {}) {
|
|
48021
48101
|
const file = options.file ? resolve29(runtime.cwd, options.file) : telemetryPath(runtime.dirs.logs);
|
|
48022
|
-
const routingRecords =
|
|
48023
|
-
const candidatesDir = options.outDir ? resolve29(runtime.cwd, options.outDir) :
|
|
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");
|
|
48024
48104
|
const report2 = buildImprovementReport(routingRecords, {
|
|
48025
48105
|
candidatesDir,
|
|
48026
48106
|
projectRoot: runtime.cwd,
|
|
48027
48107
|
dryRun: runtime.dryRun
|
|
48028
48108
|
});
|
|
48029
|
-
const reportDir =
|
|
48109
|
+
const reportDir = join48(runtime.dirs.assets, "improvements");
|
|
48030
48110
|
const reportPath = writeImprovementReport(reportDir, report2, runtime.dryRun);
|
|
48031
48111
|
const text = formatImprovementReport(report2);
|
|
48032
48112
|
print(runtime.io, runtime.json, {
|
|
@@ -48158,9 +48238,9 @@ async function maybeOfferCompletionInstall(runtime) {
|
|
|
48158
48238
|
if (!pathNeeded) {
|
|
48159
48239
|
const scriptPath = completionScriptPath(shell, { env: runtime.env, configDir: runtime.env.KXM_USER_CONFIG_DIR });
|
|
48160
48240
|
const { rcFile } = completionRcTarget(shell, { env: runtime.env });
|
|
48161
|
-
if (rcFile &&
|
|
48241
|
+
if (rcFile && existsSync38(rcFile)) {
|
|
48162
48242
|
try {
|
|
48163
|
-
if (
|
|
48243
|
+
if (readFileSync37(rcFile, "utf8").includes(scriptPath)) return;
|
|
48164
48244
|
} catch {
|
|
48165
48245
|
}
|
|
48166
48246
|
}
|
|
@@ -48292,7 +48372,7 @@ async function cmdRoutingReport(runtime, options) {
|
|
|
48292
48372
|
let catalog;
|
|
48293
48373
|
if (includeEquivalentListCost) {
|
|
48294
48374
|
try {
|
|
48295
|
-
const pricesPath = options.prices ? resolve29(runtime.cwd, options.prices) :
|
|
48375
|
+
const pricesPath = options.prices ? resolve29(runtime.cwd, options.prices) : join48(runtime.dirs.workspace, "prices.yaml");
|
|
48296
48376
|
catalog = loadPriceCatalog(pricesPath);
|
|
48297
48377
|
} catch {
|
|
48298
48378
|
}
|
|
@@ -48376,7 +48456,12 @@ async function cmdRoutingBenchmark(runtime, options) {
|
|
|
48376
48456
|
|
|
48377
48457
|
// plugins/kxm/src/cli.ts
|
|
48378
48458
|
var CLI_NAME2 = "kxm";
|
|
48379
|
-
|
|
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
|
+
}
|
|
48380
48465
|
var USAGE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
48381
48466
|
"commander.help",
|
|
48382
48467
|
"commander.helpDisplayed",
|
|
@@ -48398,12 +48483,13 @@ async function ensureCliClient(runtime) {
|
|
|
48398
48483
|
const project = defaultProjectName(runtime.cwd, runtime.env);
|
|
48399
48484
|
const name = runtime.env.KXM_AGENT_NAME?.trim() || `cli-${process.pid}`;
|
|
48400
48485
|
const purpose = runtime.env.KXM_AGENT_PURPOSE?.trim() || "CLI agent client";
|
|
48401
|
-
const authToken = runtime
|
|
48486
|
+
const authToken = resolveCliAuthToken(runtime, project);
|
|
48402
48487
|
const client = new HubClient({
|
|
48403
48488
|
serverUrl,
|
|
48404
48489
|
name,
|
|
48405
48490
|
project,
|
|
48406
48491
|
purpose,
|
|
48492
|
+
fetchImpl: runtime.fetchImpl,
|
|
48407
48493
|
...authToken ? { authToken } : {}
|
|
48408
48494
|
});
|
|
48409
48495
|
await client.start(() => {
|
|
@@ -48519,7 +48605,7 @@ function createProgram(ctx, result) {
|
|
|
48519
48605
|
};
|
|
48520
48606
|
};
|
|
48521
48607
|
const program2 = new Command(CLI_NAME2);
|
|
48522
|
-
program2.description("KontextMind local-first orchestration CLI").version(readInstalledKxmVersion(
|
|
48608
|
+
program2.description("KontextMind local-first orchestration CLI").version(readInstalledKxmVersion(findKxmRepoRoot(import.meta.url)), "-V, --version", "Print the installed kxm version").exitOverride().configureOutput({
|
|
48523
48609
|
writeOut: (text) => ctx.io.stdout(text),
|
|
48524
48610
|
writeErr: (text) => ctx.io.stderr(text)
|
|
48525
48611
|
}).helpCommand("help", "Show help");
|
|
@@ -48986,7 +49072,7 @@ async function runCli(argv, env = process.env, io = { stdout: (text) => process.
|
|
|
48986
49072
|
throw error;
|
|
48987
49073
|
}
|
|
48988
49074
|
}
|
|
48989
|
-
if (process.argv[1] && resolve30(process.argv[1]) ===
|
|
49075
|
+
if (process.argv[1] && resolve30(process.argv[1]) === fileURLToPath4(import.meta.url)) {
|
|
48990
49076
|
const code = await runCli(process.argv.slice(2));
|
|
48991
49077
|
process.exitCode = code;
|
|
48992
49078
|
}
|