@kontextmind/kxm 0.7.17 → 0.7.19
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/docs/configuration.md +17 -1
- package/docs/getting-started.md +4 -1
- package/docs/kxm-handbook.md +6 -2
- package/package.json +8 -6
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +484 -458
- package/plugins/kxm/dist/core.js +3 -2
- package/plugins/kxm/dist/extension.js +28841 -5273
- package/plugins/kxm/dist/mcp-server.js +21 -10
- package/plugins/kxm/dist/runtime.js +43 -39
- package/plugins/kxm/dist/server.js +43 -39
- package/plugins/kxm/dist/vnext-runtime-supervisor.js +40 -37
- package/plugins/kxm/package.json +4 -1
- package/plugins/kxm/src/cli/hub.ts +3 -2
- package/plugins/kxm/src/cli.ts +3 -2
- package/plugins/kxm/src/config.ts +20 -0
- package/plugins/kxm/src/extension.ts +46 -3
- package/plugins/kxm/src/hub-autostart.ts +214 -0
- package/plugins/kxm/src/mcp-server.ts +3 -3
- package/plugins/kxm/src/project-name.ts +20 -0
- package/plugins/kxm/src/providers/claude-bridge/LICENSE +21 -0
- package/plugins/kxm/src/providers/claude-bridge/README.md +18 -0
- package/plugins/kxm/src/providers/claude-bridge/config.ts +53 -0
- package/plugins/kxm/src/providers/claude-bridge/convert.ts +180 -0
- package/plugins/kxm/src/providers/claude-bridge/index.ts +28 -0
- package/plugins/kxm/src/providers/claude-bridge/mcp-server.ts +59 -0
- package/plugins/kxm/src/providers/claude-bridge/models.ts +166 -0
- package/plugins/kxm/src/providers/claude-bridge/pi-compat.ts +215 -0
- package/plugins/kxm/src/providers/claude-bridge/prompt-stream.ts +89 -0
- package/plugins/kxm/src/providers/claude-bridge/provider.ts +286 -0
- package/plugins/kxm/src/providers/claude-bridge/query-state.ts +72 -0
- package/plugins/kxm/src/providers/claude-bridge/redact.ts +26 -0
- package/plugins/kxm/src/providers/claude-bridge/register.ts +124 -0
- package/plugins/kxm/src/providers/claude-bridge/stream.ts +390 -0
- package/plugins/kxm/src/providers/claude-bridge/tools.ts +140 -0
- package/plugins/kxm/src/redact.ts +3 -2
- package/scripts/build-runtime.mjs +5 -1
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -8072,36 +8072,38 @@ var require_Alias = __commonJS({
|
|
|
8072
8072
|
if (node.anchor === this.source)
|
|
8073
8073
|
found = node;
|
|
8074
8074
|
}
|
|
8075
|
+
if (found && ctx) {
|
|
8076
|
+
const { anchors: anchors2, doc: doc2, maxAliasCount } = ctx;
|
|
8077
|
+
let data = anchors2.get(found);
|
|
8078
|
+
if (!data) {
|
|
8079
|
+
toJS.toJS(found, null, ctx);
|
|
8080
|
+
data = anchors2.get(found);
|
|
8081
|
+
}
|
|
8082
|
+
if (data?.res === void 0) {
|
|
8083
|
+
const msg = "This should not happen: Alias anchor was not resolved?";
|
|
8084
|
+
throw new ReferenceError(msg);
|
|
8085
|
+
}
|
|
8086
|
+
if (maxAliasCount >= 0) {
|
|
8087
|
+
data.count += 1;
|
|
8088
|
+
if (data.aliasCount === 0)
|
|
8089
|
+
data.aliasCount = getAliasCount(doc2, found, anchors2);
|
|
8090
|
+
if (data.count * data.aliasCount > maxAliasCount) {
|
|
8091
|
+
const msg = "Excessive alias count indicates a resource exhaustion attack";
|
|
8092
|
+
throw new ReferenceError(msg);
|
|
8093
|
+
}
|
|
8094
|
+
}
|
|
8095
|
+
}
|
|
8075
8096
|
return found;
|
|
8076
8097
|
}
|
|
8077
8098
|
toJSON(_arg, ctx) {
|
|
8078
8099
|
if (!ctx)
|
|
8079
8100
|
return { source: this.source };
|
|
8080
|
-
const
|
|
8081
|
-
const source = this.resolve(doc, ctx);
|
|
8101
|
+
const source = this.resolve(ctx.doc, ctx);
|
|
8082
8102
|
if (!source) {
|
|
8083
8103
|
const msg = `Unresolved alias (the anchor must be set before the alias): ${this.source}`;
|
|
8084
8104
|
throw new ReferenceError(msg);
|
|
8085
8105
|
}
|
|
8086
|
-
|
|
8087
|
-
if (!data) {
|
|
8088
|
-
toJS.toJS(source, null, ctx);
|
|
8089
|
-
data = anchors2.get(source);
|
|
8090
|
-
}
|
|
8091
|
-
if (data?.res === void 0) {
|
|
8092
|
-
const msg = "This should not happen: Alias anchor was not resolved?";
|
|
8093
|
-
throw new ReferenceError(msg);
|
|
8094
|
-
}
|
|
8095
|
-
if (maxAliasCount >= 0) {
|
|
8096
|
-
data.count += 1;
|
|
8097
|
-
if (data.aliasCount === 0)
|
|
8098
|
-
data.aliasCount = getAliasCount(doc, source, anchors2);
|
|
8099
|
-
if (data.count * data.aliasCount > maxAliasCount) {
|
|
8100
|
-
const msg = "Excessive alias count indicates a resource exhaustion attack";
|
|
8101
|
-
throw new ReferenceError(msg);
|
|
8102
|
-
}
|
|
8103
|
-
}
|
|
8104
|
-
return data.res;
|
|
8106
|
+
return ctx.anchors.get(source).res;
|
|
8105
8107
|
}
|
|
8106
8108
|
toString(ctx, _onComment, _onChompKeep) {
|
|
8107
8109
|
const src = `*${this.source}`;
|
|
@@ -12103,37 +12105,38 @@ var require_resolve_flow_scalar = __commonJS({
|
|
|
12103
12105
|
}
|
|
12104
12106
|
if (badChar)
|
|
12105
12107
|
onError(0, "BAD_SCALAR_START", `Plain value cannot start with ${badChar}`);
|
|
12106
|
-
return
|
|
12108
|
+
return unfoldLines(source);
|
|
12107
12109
|
}
|
|
12108
12110
|
function singleQuotedValue(source, onError) {
|
|
12109
12111
|
if (source[source.length - 1] !== "'" || source.length === 1)
|
|
12110
12112
|
onError(source.length, "MISSING_CHAR", "Missing closing 'quote");
|
|
12111
|
-
return
|
|
12113
|
+
return unfoldLines(source.slice(1, -1)).replace(/''/g, "'");
|
|
12112
12114
|
}
|
|
12113
|
-
function
|
|
12114
|
-
|
|
12115
|
+
function unfoldLines(source) {
|
|
12116
|
+
const line = /(.*?)\r?\n/sy;
|
|
12117
|
+
let match = line.exec(source);
|
|
12118
|
+
if (!match)
|
|
12119
|
+
return source;
|
|
12120
|
+
let trimEnd, trimBoth;
|
|
12115
12121
|
try {
|
|
12116
|
-
|
|
12117
|
-
|
|
12122
|
+
trimEnd = new RegExp("(?<![ ])[ ]+$");
|
|
12123
|
+
trimBoth = new RegExp("^[ ]+|(?<![ ])[ ]+$", "g");
|
|
12118
12124
|
} catch {
|
|
12119
|
-
|
|
12120
|
-
|
|
12125
|
+
trimEnd = /[ \t]+$/;
|
|
12126
|
+
trimBoth = /^[ \t]+|[ \t]+$/g;
|
|
12121
12127
|
}
|
|
12122
|
-
let
|
|
12123
|
-
if (!match)
|
|
12124
|
-
return source;
|
|
12125
|
-
let res = match[1];
|
|
12128
|
+
let res = match[1].replace(trimEnd, "");
|
|
12126
12129
|
let sep4 = " ";
|
|
12127
|
-
let pos =
|
|
12128
|
-
line.lastIndex = pos;
|
|
12130
|
+
let pos = line.lastIndex;
|
|
12129
12131
|
while (match = line.exec(source)) {
|
|
12130
|
-
|
|
12132
|
+
const lm = match[1].replace(trimBoth, "");
|
|
12133
|
+
if (lm === "") {
|
|
12131
12134
|
if (sep4 === "\n")
|
|
12132
12135
|
res += sep4;
|
|
12133
12136
|
else
|
|
12134
12137
|
sep4 = "\n";
|
|
12135
12138
|
} else {
|
|
12136
|
-
res += sep4 +
|
|
12139
|
+
res += sep4 + lm;
|
|
12137
12140
|
sep4 = " ";
|
|
12138
12141
|
}
|
|
12139
12142
|
pos = line.lastIndex;
|
|
@@ -14776,7 +14779,7 @@ var require_dist = __commonJS({
|
|
|
14776
14779
|
});
|
|
14777
14780
|
|
|
14778
14781
|
// plugins/kxm/src/cli.ts
|
|
14779
|
-
import {
|
|
14782
|
+
import { resolve as resolve30 } from "node:path";
|
|
14780
14783
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
14781
14784
|
|
|
14782
14785
|
// node_modules/commander/lib/error.js
|
|
@@ -19568,11 +19571,25 @@ var HubClient = class {
|
|
|
19568
19571
|
}
|
|
19569
19572
|
};
|
|
19570
19573
|
|
|
19574
|
+
// plugins/kxm/src/project-name.ts
|
|
19575
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
19576
|
+
import { basename, join as join2 } from "node:path";
|
|
19577
|
+
function defaultProjectName(cwd, env = process.env) {
|
|
19578
|
+
const fromEnv = env.KXM_PROJECT?.trim();
|
|
19579
|
+
if (fromEnv) return fromEnv;
|
|
19580
|
+
try {
|
|
19581
|
+
const pkg = JSON.parse(readFileSync2(join2(cwd, "package.json"), "utf8"));
|
|
19582
|
+
if (typeof pkg.name === "string" && pkg.name.trim().length > 0) return pkg.name.trim();
|
|
19583
|
+
} catch {
|
|
19584
|
+
}
|
|
19585
|
+
return basename(cwd);
|
|
19586
|
+
}
|
|
19587
|
+
|
|
19571
19588
|
// plugins/kxm/src/commands.ts
|
|
19572
19589
|
import { createHash as createHash4, randomUUID as randomUUID2, timingSafeEqual } from "node:crypto";
|
|
19573
|
-
import { chmodSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as
|
|
19590
|
+
import { chmodSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
19574
19591
|
import { homedir } from "node:os";
|
|
19575
|
-
import { dirname, join as
|
|
19592
|
+
import { dirname, join as join3, resolve } from "node:path";
|
|
19576
19593
|
function requiredString(value, name) {
|
|
19577
19594
|
if (typeof value !== "string" || value.trim() === "") throw new Error(`${name} is required`);
|
|
19578
19595
|
return value.trim();
|
|
@@ -20321,10 +20338,10 @@ function parseSessionToken(token) {
|
|
|
20321
20338
|
}
|
|
20322
20339
|
function resolveUserConfigDirectory(overrideDir) {
|
|
20323
20340
|
if (overrideDir) return resolve(overrideDir);
|
|
20324
|
-
return resolve(process.env.KXM_USER_CONFIG_DIR?.trim() ||
|
|
20341
|
+
return resolve(process.env.KXM_USER_CONFIG_DIR?.trim() || join3(homedir(), ".config", "kxm"));
|
|
20325
20342
|
}
|
|
20326
20343
|
function sessionTokenPath(userConfigDir) {
|
|
20327
|
-
return
|
|
20344
|
+
return join3(resolveUserConfigDirectory(userConfigDir), "session.token");
|
|
20328
20345
|
}
|
|
20329
20346
|
function persistSessionTokenToDisk(token, options) {
|
|
20330
20347
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
@@ -20343,7 +20360,7 @@ function readSessionTokenFromDisk(options) {
|
|
|
20343
20360
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
20344
20361
|
if (!existsSync2(filePath)) return void 0;
|
|
20345
20362
|
try {
|
|
20346
|
-
const token =
|
|
20363
|
+
const token = readFileSync3(filePath, "utf8").trim();
|
|
20347
20364
|
if (!token) return void 0;
|
|
20348
20365
|
const payload = parseSessionToken(token);
|
|
20349
20366
|
if (!payload) return void 0;
|
|
@@ -20456,7 +20473,7 @@ function enforceToolPolicy(commandName, env = process.env, options) {
|
|
|
20456
20473
|
if (existsSync2(tokenFile)) {
|
|
20457
20474
|
let tokenRaw;
|
|
20458
20475
|
try {
|
|
20459
|
-
tokenRaw =
|
|
20476
|
+
tokenRaw = readFileSync3(tokenFile, "utf8").trim();
|
|
20460
20477
|
} catch {
|
|
20461
20478
|
return { allowed: false, error: "session_token_invalid", detail: "Session token file on disk could not be read" };
|
|
20462
20479
|
}
|
|
@@ -20480,8 +20497,8 @@ function enforceToolPolicy(commandName, env = process.env, options) {
|
|
|
20480
20497
|
var import__ = __toESM(require__(), 1);
|
|
20481
20498
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
20482
20499
|
import { createHash as createHash6 } from "node:crypto";
|
|
20483
|
-
import { existsSync as existsSync4, lstatSync, readFileSync as
|
|
20484
|
-
import { basename, dirname as dirname2, extname, isAbsolute, join as
|
|
20500
|
+
import { existsSync as existsSync4, lstatSync, readFileSync as readFileSync4, readdirSync, realpathSync } from "node:fs";
|
|
20501
|
+
import { basename as basename2, dirname as dirname2, extname, isAbsolute, join as join4, relative, resolve as resolve2, sep } from "node:path";
|
|
20485
20502
|
import { fileURLToPath } from "node:url";
|
|
20486
20503
|
|
|
20487
20504
|
// plugins/kxm/src/restricted-yaml.mjs
|
|
@@ -21877,7 +21894,7 @@ var VnextConfigError = class extends Error {
|
|
|
21877
21894
|
}
|
|
21878
21895
|
};
|
|
21879
21896
|
var PACKAGE_ROOT = resolve2(dirname2(fileURLToPath(import.meta.url)), "../../..");
|
|
21880
|
-
var DEFAULT_SCHEMA_DIR =
|
|
21897
|
+
var DEFAULT_SCHEMA_DIR = join4(PACKAGE_ROOT, "schemas", "vnext");
|
|
21881
21898
|
var RESOURCE_SCHEMA = Object.freeze({
|
|
21882
21899
|
project: { identity: "kxm.project.v1", file: "project.schema.json" },
|
|
21883
21900
|
repository: { identity: "kxm.repository.v1", file: "repository.schema.json" },
|
|
@@ -21923,7 +21940,7 @@ function parseRestrictedYaml2(input, label = "<yaml>", limits = VNEXT_YAML_LIMIT
|
|
|
21923
21940
|
}
|
|
21924
21941
|
}
|
|
21925
21942
|
function readJsonObject(file) {
|
|
21926
|
-
const parsed = JSON.parse(
|
|
21943
|
+
const parsed = JSON.parse(readFileSync4(file, "utf8"));
|
|
21927
21944
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`${file} is not a JSON object`);
|
|
21928
21945
|
return parsed;
|
|
21929
21946
|
}
|
|
@@ -21942,10 +21959,10 @@ var VnextSchemaRegistry = class {
|
|
|
21942
21959
|
constructor(schemasDir = DEFAULT_SCHEMA_DIR) {
|
|
21943
21960
|
this.schemasDir = resolve2(schemasDir);
|
|
21944
21961
|
this.ajv = new import__.Ajv2020({ allErrors: true, strict: true, strictRequired: false });
|
|
21945
|
-
const common = readJsonObject(
|
|
21962
|
+
const common = readJsonObject(join4(this.schemasDir, "common.schema.json"));
|
|
21946
21963
|
this.ajv.addSchema(common);
|
|
21947
21964
|
for (const definition of Object.values(RESOURCE_SCHEMA)) {
|
|
21948
|
-
this.ajv.addSchema(readJsonObject(
|
|
21965
|
+
this.ajv.addSchema(readJsonObject(join4(this.schemasDir, definition.file)));
|
|
21949
21966
|
}
|
|
21950
21967
|
const localBindingsFile = "local-repository-bindings.schema.json";
|
|
21951
21968
|
const templateProvenanceFile = "template-provenance.schema.json";
|
|
@@ -21955,14 +21972,14 @@ var VnextSchemaRegistry = class {
|
|
|
21955
21972
|
const migrationReceiptFile = "migration-receipt.schema.json";
|
|
21956
21973
|
const permissionDiffFile = "permission-diff.schema.json";
|
|
21957
21974
|
const runEventFile = "run-event.schema.json";
|
|
21958
|
-
this.ajv.addSchema(readJsonObject(
|
|
21959
|
-
this.ajv.addSchema(readJsonObject(
|
|
21960
|
-
this.ajv.addSchema(readJsonObject(
|
|
21961
|
-
this.ajv.addSchema(readJsonObject(
|
|
21962
|
-
this.ajv.addSchema(readJsonObject(
|
|
21963
|
-
this.ajv.addSchema(readJsonObject(
|
|
21964
|
-
this.ajv.addSchema(readJsonObject(
|
|
21965
|
-
this.ajv.addSchema(readJsonObject(
|
|
21975
|
+
this.ajv.addSchema(readJsonObject(join4(this.schemasDir, localBindingsFile)));
|
|
21976
|
+
this.ajv.addSchema(readJsonObject(join4(this.schemasDir, templateProvenanceFile)));
|
|
21977
|
+
this.ajv.addSchema(readJsonObject(join4(this.schemasDir, initOperationFile)));
|
|
21978
|
+
this.ajv.addSchema(readJsonObject(join4(this.schemasDir, migrationPlanFile)));
|
|
21979
|
+
this.ajv.addSchema(readJsonObject(join4(this.schemasDir, migrationDecisionFile)));
|
|
21980
|
+
this.ajv.addSchema(readJsonObject(join4(this.schemasDir, migrationReceiptFile)));
|
|
21981
|
+
this.ajv.addSchema(readJsonObject(join4(this.schemasDir, permissionDiffFile)));
|
|
21982
|
+
this.ajv.addSchema(readJsonObject(join4(this.schemasDir, runEventFile)));
|
|
21966
21983
|
for (const [kind, definition] of Object.entries(RESOURCE_SCHEMA)) {
|
|
21967
21984
|
const validator = this.ajv.getSchema(`https://schemas.kxm.dev/vnext/${definition.file}`);
|
|
21968
21985
|
if (!validator) throw new Error(`schema did not compile: ${definition.file}`);
|
|
@@ -22057,7 +22074,7 @@ function containedHostPath(root, candidate) {
|
|
|
22057
22074
|
function portableBindingIssue(root, pathHint, repositoryId) {
|
|
22058
22075
|
let current = root;
|
|
22059
22076
|
for (const segment of pathHint === "." ? [] : pathHint.split("/")) {
|
|
22060
|
-
current =
|
|
22077
|
+
current = join4(current, segment);
|
|
22061
22078
|
if (!existsSync4(current)) break;
|
|
22062
22079
|
const stat = lstatSync(current);
|
|
22063
22080
|
if (stat.isSymbolicLink()) {
|
|
@@ -22116,20 +22133,20 @@ function readResource(registry, root, file, logicalPath, kind, id, containmentRo
|
|
|
22116
22133
|
parent = dirname2(parent);
|
|
22117
22134
|
}
|
|
22118
22135
|
if (!stat.isFile()) fail2("path", "resource_not_file", label, "configuration resource must be a regular file");
|
|
22119
|
-
const value = parseRestrictedYaml2(
|
|
22136
|
+
const value = parseRestrictedYaml2(readFileSync4(file), label);
|
|
22120
22137
|
const issues = registry.validate(kind, value, label);
|
|
22121
22138
|
if (issues.length > 0) throw new VnextConfigError(issues);
|
|
22122
22139
|
return { kind, ...id === void 0 ? {} : { id }, file, logicalPath, value };
|
|
22123
22140
|
}
|
|
22124
22141
|
function readTemplateProvenance(registry, root) {
|
|
22125
|
-
const file =
|
|
22142
|
+
const file = join4(root, ".kxm", "template-provenance.yaml");
|
|
22126
22143
|
if (!existsSync4(file)) return void 0;
|
|
22127
22144
|
const label = ".kxm/template-provenance.yaml";
|
|
22128
22145
|
const stat = lstatSync(file);
|
|
22129
22146
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
22130
22147
|
fail2("path", "resource_not_file", label, "template provenance must be a regular file, not a link or directory");
|
|
22131
22148
|
}
|
|
22132
|
-
const configRoot =
|
|
22149
|
+
const configRoot = join4(root, ".kxm");
|
|
22133
22150
|
let parent = dirname2(file);
|
|
22134
22151
|
while (parent !== root) {
|
|
22135
22152
|
const parentStat = lstatSync(parent);
|
|
@@ -22139,7 +22156,7 @@ function readTemplateProvenance(registry, root) {
|
|
|
22139
22156
|
if (parent === configRoot) break;
|
|
22140
22157
|
parent = dirname2(parent);
|
|
22141
22158
|
}
|
|
22142
|
-
const value = parseRestrictedYaml2(
|
|
22159
|
+
const value = parseRestrictedYaml2(readFileSync4(file), label);
|
|
22143
22160
|
const issues = registry.validateTemplateProvenance(value, label);
|
|
22144
22161
|
if (issues.length > 0) throw new VnextConfigError(issues);
|
|
22145
22162
|
if (!resolveVnextTemplateBaseline(value)) {
|
|
@@ -22179,27 +22196,27 @@ function listNamedResources(registry, root, directory, logicalDirectory, kind) {
|
|
|
22179
22196
|
const entries = readdirSync(directory, { withFileTypes: true }).sort((left, right) => compareCodeUnits3(left.name, right.name));
|
|
22180
22197
|
for (const entry of entries) {
|
|
22181
22198
|
if (entry.isDirectory()) {
|
|
22182
|
-
issues.push(issue2("path", "nested_resource_directory", displayPath(root,
|
|
22199
|
+
issues.push(issue2("path", "nested_resource_directory", displayPath(root, join4(directory, entry.name)), "nested resource directories are not allowed"));
|
|
22183
22200
|
continue;
|
|
22184
22201
|
}
|
|
22185
22202
|
if (!entry.name.toLowerCase().endsWith(".yaml") && !entry.name.toLowerCase().endsWith(".yml")) continue;
|
|
22186
22203
|
if (!entry.isFile() || extname(entry.name) !== ".yaml") {
|
|
22187
|
-
issues.push(issue2("path", "resource_filename_invalid", displayPath(root,
|
|
22204
|
+
issues.push(issue2("path", "resource_filename_invalid", displayPath(root, join4(directory, entry.name)), "resource must be a regular file with the exact .yaml extension"));
|
|
22188
22205
|
continue;
|
|
22189
22206
|
}
|
|
22190
|
-
const id =
|
|
22207
|
+
const id = basename2(entry.name, ".yaml");
|
|
22191
22208
|
if (kind === "model" && id === "inventory") continue;
|
|
22192
22209
|
if (!resourceIdentifier(id)) {
|
|
22193
|
-
issues.push(issue2("path", "resource_id_invalid", displayPath(root,
|
|
22210
|
+
issues.push(issue2("path", "resource_id_invalid", displayPath(root, join4(directory, entry.name)), `filename-derived identity ${id} is invalid or platform-reserved`));
|
|
22194
22211
|
continue;
|
|
22195
22212
|
}
|
|
22196
22213
|
const collision = [...resources.keys()].find((candidate) => candidate.toLocaleLowerCase("en-US") === id.toLocaleLowerCase("en-US"));
|
|
22197
22214
|
if (collision) {
|
|
22198
|
-
issues.push(issue2("path", "resource_id_collision", displayPath(root,
|
|
22215
|
+
issues.push(issue2("path", "resource_id_collision", displayPath(root, join4(directory, entry.name)), `${id} case-folds to existing ${collision}`));
|
|
22199
22216
|
continue;
|
|
22200
22217
|
}
|
|
22201
22218
|
try {
|
|
22202
|
-
const resource = readResource(registry, root,
|
|
22219
|
+
const resource = readResource(registry, root, join4(directory, entry.name), `${logicalDirectory}/${id}.yaml`, kind, id);
|
|
22203
22220
|
resources.set(id, resource);
|
|
22204
22221
|
} catch (error) {
|
|
22205
22222
|
if (error instanceof VnextConfigError) issues.push(...error.issues);
|
|
@@ -22520,8 +22537,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
22520
22537
|
const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
|
|
22521
22538
|
if (maxWriteRepositories > writable) issues.push(issue2("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
|
|
22522
22539
|
}
|
|
22523
|
-
const
|
|
22524
|
-
const minimumPassed =
|
|
22540
|
+
const join48 = objectValue(step.join);
|
|
22541
|
+
const minimumPassed = join48 && typeof join48.minimumPassed === "number" ? join48.minimumPassed : void 0;
|
|
22525
22542
|
if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue2("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
|
|
22526
22543
|
const distinctBy = names(assignment?.distinctBy);
|
|
22527
22544
|
if (distinctBy.length > 0) {
|
|
@@ -22735,11 +22752,11 @@ function validateBundle(project, repositories, agents, models, workflows, enviro
|
|
|
22735
22752
|
if (!workflows.has(defaultWorkflow)) issues.push(issue2("reference", "default_workflow_unknown", project.logicalPath, `default workflow ${defaultWorkflow} does not exist`));
|
|
22736
22753
|
for (const workflow of workflows.values()) validateWorkflow(workflow, agents, models, repositoryIds, gates, issues);
|
|
22737
22754
|
if (projectRoot) {
|
|
22738
|
-
const writerRolePath =
|
|
22755
|
+
const writerRolePath = join4(projectRoot, ".kxm", "roles", "writer.yaml");
|
|
22739
22756
|
const implementerAgent = agents.get("implementer") ?? agents.get("writer");
|
|
22740
22757
|
if (existsSync4(writerRolePath) && implementerAgent) {
|
|
22741
22758
|
try {
|
|
22742
|
-
const rawRole = parseRestrictedYaml2(
|
|
22759
|
+
const rawRole = parseRestrictedYaml2(readFileSync4(writerRolePath, "utf8"));
|
|
22743
22760
|
const roleObj = objectValue(rawRole);
|
|
22744
22761
|
const rosterEntries = valuesOf(roleObj ?? {}, "roster").map((candidate) => objectValue(candidate)).filter((entry) => Boolean(entry));
|
|
22745
22762
|
const enabledRosterModels = rosterEntries.filter((entry) => entry.enabled !== false).map((entry) => stringValue(entry.model)).filter((m2) => Boolean(m2));
|
|
@@ -22799,7 +22816,7 @@ function discoverGitRoot(start = process.cwd()) {
|
|
|
22799
22816
|
}
|
|
22800
22817
|
function discoverVnextProjectRoot(start = process.cwd()) {
|
|
22801
22818
|
const gitRoot = discoverGitRoot(start);
|
|
22802
|
-
return gitRoot && existsSync4(
|
|
22819
|
+
return gitRoot && existsSync4(join4(gitRoot, ".kxm", "project.yaml")) ? gitRoot : void 0;
|
|
22803
22820
|
}
|
|
22804
22821
|
function assertNoRegisteredGates(options) {
|
|
22805
22822
|
if ("registeredGates" in options) {
|
|
@@ -22816,7 +22833,7 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22816
22833
|
migrationReceipt = receiptCheck.receipt;
|
|
22817
22834
|
}
|
|
22818
22835
|
const registry = new VnextSchemaRegistry(options.schemasDir);
|
|
22819
|
-
const project = readResource(registry, root,
|
|
22836
|
+
const project = readResource(registry, root, join4(root, ".kxm", "project.yaml"), ".kxm/project.yaml", "project");
|
|
22820
22837
|
const earlyIssues = [];
|
|
22821
22838
|
validatePortablePaths(project, earlyIssues);
|
|
22822
22839
|
const templateProvenance = readTemplateProvenance(registry, root);
|
|
@@ -22838,15 +22855,15 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22838
22855
|
}
|
|
22839
22856
|
}
|
|
22840
22857
|
if (earlyIssues.length > 0) throw new VnextConfigError(earlyIssues);
|
|
22841
|
-
const agents = listNamedResources(registry, root,
|
|
22842
|
-
const models = listNamedResources(registry, root,
|
|
22843
|
-
const workflows = listNamedResources(registry, root,
|
|
22844
|
-
const gatePath =
|
|
22858
|
+
const agents = listNamedResources(registry, root, join4(root, ".kxm", "agents"), ".kxm/agents", "agent");
|
|
22859
|
+
const models = listNamedResources(registry, root, join4(root, ".kxm", "models"), ".kxm/models", "model");
|
|
22860
|
+
const workflows = listNamedResources(registry, root, join4(root, ".kxm", "workflows"), ".kxm/workflows", "workflow");
|
|
22861
|
+
const gatePath = join4(root, ".kxm", "gates.yaml");
|
|
22845
22862
|
const gateRegistry = existsSync4(gatePath) ? readResource(registry, root, gatePath, ".kxm/gates.yaml", "gate-registry") : void 0;
|
|
22846
22863
|
const environments = [];
|
|
22847
22864
|
const repositories = /* @__PURE__ */ new Map();
|
|
22848
22865
|
const loadIssues = [];
|
|
22849
|
-
const projectEnvironment =
|
|
22866
|
+
const projectEnvironment = join4(root, ".kxm", "project", "env.yaml");
|
|
22850
22867
|
if (existsSync4(projectEnvironment)) {
|
|
22851
22868
|
try {
|
|
22852
22869
|
environments.push(readResource(registry, root, projectEnvironment, ".kxm/project/env.yaml", "environment"));
|
|
@@ -22912,7 +22929,7 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22912
22929
|
continue;
|
|
22913
22930
|
}
|
|
22914
22931
|
seenBindings.set(foldedBinding, repositoryId);
|
|
22915
|
-
const repositoryFile =
|
|
22932
|
+
const repositoryFile = join4(binding, ".kxm", "repo", "repo.yaml");
|
|
22916
22933
|
let definitionValidated = false;
|
|
22917
22934
|
if (existsSync4(repositoryFile)) {
|
|
22918
22935
|
try {
|
|
@@ -22930,7 +22947,7 @@ function loadVnextProject(projectRoot, options = {}) {
|
|
|
22930
22947
|
} else if (required || hasLocalBinding) {
|
|
22931
22948
|
loadIssues.push(issue2("discovery", "repository_definition_missing", `.kxm/repositories/${repositoryId}/repo.yaml`, `${hasLocalBinding ? "explicit" : "required"} repository ${repositoryId} has no repo.yaml`));
|
|
22932
22949
|
}
|
|
22933
|
-
const environmentFile =
|
|
22950
|
+
const environmentFile = join4(binding, ".kxm", "repo", "env.yaml");
|
|
22934
22951
|
if (existsSync4(environmentFile)) {
|
|
22935
22952
|
if (!definitionValidated) {
|
|
22936
22953
|
loadIssues.push(issue2("reference", "repository_environment_without_definition", `.kxm/repositories/${repositoryId}/env.yaml`, `repository ${repositoryId} environment requires a validated matching repo.yaml`));
|
|
@@ -23009,20 +23026,20 @@ function legacyInputsAt(root) {
|
|
|
23009
23026
|
".kxm/config/workflows",
|
|
23010
23027
|
".kxm/state/kxm.db"
|
|
23011
23028
|
];
|
|
23012
|
-
return candidates.filter((candidate) => existsSync4(
|
|
23029
|
+
return candidates.filter((candidate) => existsSync4(join4(root, ...candidate.split("/"))));
|
|
23013
23030
|
}
|
|
23014
23031
|
var VNEXT_MIGRATION_RECEIPT_PATH = ".kxm/migration-receipt.yaml";
|
|
23015
23032
|
var LEGACY_CONFIG_FILES = [".kxm/config/agents.json", ".kxm/config/gates.json"];
|
|
23016
23033
|
function legacyConfigFilesAt(root) {
|
|
23017
23034
|
const files = [];
|
|
23018
23035
|
for (const component of [".kxm", ".kxm/config"]) {
|
|
23019
|
-
const absolute =
|
|
23036
|
+
const absolute = join4(root, ...component.split("/"));
|
|
23020
23037
|
if (existsSync4(absolute) && lstatSync(absolute).isSymbolicLink()) return [component];
|
|
23021
23038
|
}
|
|
23022
23039
|
for (const candidate of LEGACY_CONFIG_FILES) {
|
|
23023
|
-
if (existsSync4(
|
|
23040
|
+
if (existsSync4(join4(root, ...candidate.split("/")))) files.push(candidate);
|
|
23024
23041
|
}
|
|
23025
|
-
const workflowsDir =
|
|
23042
|
+
const workflowsDir = join4(root, ".kxm", "config", "workflows");
|
|
23026
23043
|
if (existsSync4(workflowsDir)) {
|
|
23027
23044
|
const stat = lstatSync(workflowsDir);
|
|
23028
23045
|
if (stat.isSymbolicLink()) {
|
|
@@ -23038,9 +23055,9 @@ function legacyConfigFilesAt(root) {
|
|
|
23038
23055
|
return files;
|
|
23039
23056
|
}
|
|
23040
23057
|
function hashFileRecord(root, relativePath) {
|
|
23041
|
-
const absolute =
|
|
23058
|
+
const absolute = join4(root, ...relativePath.split("/"));
|
|
23042
23059
|
if (!existsSync4(absolute)) return void 0;
|
|
23043
|
-
const bytes =
|
|
23060
|
+
const bytes = readFileSync4(absolute);
|
|
23044
23061
|
return {
|
|
23045
23062
|
path: relativePath,
|
|
23046
23063
|
sha256: `sha256:${createHash6("sha256").update(bytes).digest("hex")}`,
|
|
@@ -23052,7 +23069,7 @@ function migrationReceiptSelfHash(receipt) {
|
|
|
23052
23069
|
return `sha256:${createHash6("sha256").update(vnextCanonicalJson(unsigned), "utf8").digest("hex")}`;
|
|
23053
23070
|
}
|
|
23054
23071
|
function readVnextMigrationReceipt(root, options = {}) {
|
|
23055
|
-
const receiptPath =
|
|
23072
|
+
const receiptPath = join4(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
|
|
23056
23073
|
const legacyFiles = legacyConfigFilesAt(root);
|
|
23057
23074
|
if (!existsSync4(receiptPath)) {
|
|
23058
23075
|
return {
|
|
@@ -23065,7 +23082,7 @@ function readVnextMigrationReceipt(root, options = {}) {
|
|
|
23065
23082
|
}
|
|
23066
23083
|
let receipt;
|
|
23067
23084
|
try {
|
|
23068
|
-
receipt = parseRestrictedYaml2(
|
|
23085
|
+
receipt = parseRestrictedYaml2(readFileSync4(receiptPath), VNEXT_MIGRATION_RECEIPT_PATH);
|
|
23069
23086
|
} catch (error) {
|
|
23070
23087
|
if (error instanceof VnextConfigError) return { issues: [...error.issues] };
|
|
23071
23088
|
throw error;
|
|
@@ -23126,7 +23143,7 @@ function planVnextInitialization(start = process.cwd(), options = {}) {
|
|
|
23126
23143
|
}
|
|
23127
23144
|
const gitRoot = discoverGitRoot(inspectedFrom);
|
|
23128
23145
|
const candidateRoot = gitRoot ?? inspectedFrom;
|
|
23129
|
-
if (existsSync4(
|
|
23146
|
+
if (existsSync4(join4(candidateRoot, ".kxm"))) {
|
|
23130
23147
|
return {
|
|
23131
23148
|
mode: "repair",
|
|
23132
23149
|
inspectedFrom,
|
|
@@ -23142,14 +23159,14 @@ function planVnextInitialization(start = process.cwd(), options = {}) {
|
|
|
23142
23159
|
// plugins/kxm/src/vnext-runtime-supervisor.ts
|
|
23143
23160
|
import { spawn as spawn2 } from "node:child_process";
|
|
23144
23161
|
import { createHash as createHash11, createHmac, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
23145
|
-
import { chmodSync as chmodSync4, existsSync as existsSync10, lstatSync as lstatSync6, mkdirSync as mkdirSync7, readFileSync as
|
|
23146
|
-
import { dirname as dirname6, isAbsolute as isAbsolute4, join as
|
|
23162
|
+
import { chmodSync as chmodSync4, existsSync as existsSync10, lstatSync as lstatSync6, mkdirSync as mkdirSync7, readFileSync as readFileSync10, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
|
|
23163
|
+
import { dirname as dirname6, isAbsolute as isAbsolute4, join as join10, resolve as resolve7 } from "node:path";
|
|
23147
23164
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
23148
23165
|
|
|
23149
23166
|
// plugins/kxm/src/vnext-runtime-store.ts
|
|
23150
23167
|
import { createHash as createHash9, randomUUID as randomUUID4 } from "node:crypto";
|
|
23151
|
-
import { existsSync as existsSync7, lstatSync as lstatSync4, mkdirSync as mkdirSync5, readFileSync as
|
|
23152
|
-
import { dirname as dirname5, join as
|
|
23168
|
+
import { existsSync as existsSync7, lstatSync as lstatSync4, mkdirSync as mkdirSync5, readFileSync as readFileSync7, realpathSync as realpathSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
23169
|
+
import { dirname as dirname5, join as join7, resolve as resolve5 } from "node:path";
|
|
23153
23170
|
|
|
23154
23171
|
// plugins/kxm/src/vnext-bindings.ts
|
|
23155
23172
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
@@ -23162,7 +23179,7 @@ import {
|
|
|
23162
23179
|
lstatSync as lstatSync2,
|
|
23163
23180
|
mkdirSync as mkdirSync3,
|
|
23164
23181
|
openSync,
|
|
23165
|
-
readFileSync as
|
|
23182
|
+
readFileSync as readFileSync5,
|
|
23166
23183
|
realpathSync as realpathSync2,
|
|
23167
23184
|
renameSync,
|
|
23168
23185
|
rmSync,
|
|
@@ -23210,7 +23227,7 @@ var DatabaseSync = class {
|
|
|
23210
23227
|
};
|
|
23211
23228
|
|
|
23212
23229
|
// plugins/kxm/src/vnext-bindings.ts
|
|
23213
|
-
import { dirname as dirname3, isAbsolute as isAbsolute2, join as
|
|
23230
|
+
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join5, parse, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
|
|
23214
23231
|
var MAX_BINDING_RECORD_BYTES = 256 * 1024;
|
|
23215
23232
|
var BINDING_LABEL = "Runtime-local repository bindings";
|
|
23216
23233
|
var activeLocks = /* @__PURE__ */ new WeakSet();
|
|
@@ -23244,12 +23261,12 @@ function vnextUserStateRoot(options = {}) {
|
|
|
23244
23261
|
}
|
|
23245
23262
|
if (platform === "win32") {
|
|
23246
23263
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
23247
|
-
const base2 = localAppData && isAbsolute2(localAppData) ? localAppData :
|
|
23264
|
+
const base2 = localAppData && isAbsolute2(localAppData) ? localAppData : join5(home, "AppData", "Local");
|
|
23248
23265
|
return resolve3(base2, "KXM");
|
|
23249
23266
|
}
|
|
23250
23267
|
if (platform === "darwin") return resolve3(home, "Library", "Application Support", "KXM");
|
|
23251
23268
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
23252
|
-
const base = xdgState && isAbsolute2(xdgState) ? xdgState :
|
|
23269
|
+
const base = xdgState && isAbsolute2(xdgState) ? xdgState : join5(home, ".local", "state");
|
|
23253
23270
|
return resolve3(base, "kxm");
|
|
23254
23271
|
}
|
|
23255
23272
|
function projectBindingKey(projectRoot, platform = process.platform) {
|
|
@@ -23259,7 +23276,7 @@ function projectBindingKey(projectRoot, platform = process.platform) {
|
|
|
23259
23276
|
}
|
|
23260
23277
|
function vnextLocalBindingFile(projectRoot, options = {}) {
|
|
23261
23278
|
const stateRoot = vnextUserStateRoot(options);
|
|
23262
|
-
return
|
|
23279
|
+
return join5(stateRoot, "projects", projectBindingKey(projectRoot, options.platform), "repository-bindings.json");
|
|
23263
23280
|
}
|
|
23264
23281
|
function checkedDirectory(path4, description) {
|
|
23265
23282
|
if (!existsSync5(path4)) return false;
|
|
@@ -23270,7 +23287,7 @@ function checkedDirectory(path4, description) {
|
|
|
23270
23287
|
return true;
|
|
23271
23288
|
}
|
|
23272
23289
|
function existingBindingDirectory(file, stateRoot) {
|
|
23273
|
-
const projects =
|
|
23290
|
+
const projects = join5(stateRoot, "projects");
|
|
23274
23291
|
const project = dirname3(file);
|
|
23275
23292
|
if (!checkedDirectory(stateRoot, "local state root")) return false;
|
|
23276
23293
|
if (!checkedDirectory(projects, "local projects directory")) return false;
|
|
@@ -23305,7 +23322,7 @@ function readVnextLocalBindings(projectRoot, options = {}) {
|
|
|
23305
23322
|
if (stat.size > MAX_BINDING_RECORD_BYTES) {
|
|
23306
23323
|
bindingError("parse", "local_binding_file_too_large", `binding record exceeds ${MAX_BINDING_RECORD_BYTES} bytes`);
|
|
23307
23324
|
}
|
|
23308
|
-
const parsed = parseRestrictedYaml2(
|
|
23325
|
+
const parsed = parseRestrictedYaml2(readFileSync5(file), BINDING_LABEL);
|
|
23309
23326
|
return asRecord2(parsed, file, root, options.schemasDir);
|
|
23310
23327
|
}
|
|
23311
23328
|
function normalizedRecord(projectRoot, projectId, repositories, schemasDir) {
|
|
@@ -23373,7 +23390,7 @@ function ensureBindingDirectory(file, stateRoot) {
|
|
|
23373
23390
|
ensureDurableDirectory(stateRoot, "local state root");
|
|
23374
23391
|
checkedDirectory(stateRoot, "local state root");
|
|
23375
23392
|
syncDirectory(stateRoot);
|
|
23376
|
-
const projects =
|
|
23393
|
+
const projects = join5(stateRoot, "projects");
|
|
23377
23394
|
createDirectoryIfMissing(projects);
|
|
23378
23395
|
checkedDirectory(projects, "local projects directory");
|
|
23379
23396
|
const project = dirname3(file);
|
|
@@ -23386,7 +23403,7 @@ function assertNoLinkedDirectoryComponents(path4, description) {
|
|
|
23386
23403
|
let current = filesystemRoot;
|
|
23387
23404
|
const remainder = relative2(filesystemRoot, absolute);
|
|
23388
23405
|
for (const segment of remainder.split(sep2).filter(Boolean)) {
|
|
23389
|
-
current =
|
|
23406
|
+
current = join5(current, segment);
|
|
23390
23407
|
const stat = lstatSync2(current);
|
|
23391
23408
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
23392
23409
|
bindingError("path", "project_operation_lock_parent_invalid", `${description} contains a linked or non-directory component`);
|
|
@@ -23413,7 +23430,7 @@ function projectOperationLockFile(projectRoot) {
|
|
|
23413
23430
|
if (gitStat.isSymbolicLink() || !gitStat.isDirectory()) {
|
|
23414
23431
|
bindingError("path", "project_operation_lock_parent_invalid", "authoritative Git metadata must resolve to a regular directory");
|
|
23415
23432
|
}
|
|
23416
|
-
const lockDirectory =
|
|
23433
|
+
const lockDirectory = join5(gitDirectory, "kxm");
|
|
23417
23434
|
if (existsSync5(lockDirectory)) {
|
|
23418
23435
|
const stat = lstatSync2(lockDirectory);
|
|
23419
23436
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
@@ -23423,7 +23440,7 @@ function projectOperationLockFile(projectRoot) {
|
|
|
23423
23440
|
mkdirSync3(lockDirectory, { mode: 448 });
|
|
23424
23441
|
syncDirectory(gitDirectory);
|
|
23425
23442
|
}
|
|
23426
|
-
return
|
|
23443
|
+
return join5(lockDirectory, "project-operation-lock.sqlite");
|
|
23427
23444
|
}
|
|
23428
23445
|
function withVnextLocalBindingLock(projectRoot, options, callback) {
|
|
23429
23446
|
const root = resolve3(projectRoot);
|
|
@@ -23482,7 +23499,7 @@ function writeVnextLocalBindings(projectRoot, projectId, repositories, options =
|
|
|
23482
23499
|
const { file, record } = planned;
|
|
23483
23500
|
if (!planned.written) return planned;
|
|
23484
23501
|
ensureBindingDirectory(file, vnextUserStateRoot(options));
|
|
23485
|
-
const temporary =
|
|
23502
|
+
const temporary = join5(dirname3(file), `.repository-bindings-${process.pid}-${randomUUID3()}.tmp`);
|
|
23486
23503
|
let descriptor;
|
|
23487
23504
|
try {
|
|
23488
23505
|
descriptor = openSync(temporary, "wx", 384);
|
|
@@ -23513,11 +23530,11 @@ import {
|
|
|
23513
23530
|
lstatSync as lstatSync3,
|
|
23514
23531
|
mkdirSync as mkdirSync4,
|
|
23515
23532
|
readdirSync as readdirSync2,
|
|
23516
|
-
readFileSync as
|
|
23533
|
+
readFileSync as readFileSync6,
|
|
23517
23534
|
unlinkSync as unlinkSync2,
|
|
23518
23535
|
writeFileSync as writeFileSync4
|
|
23519
23536
|
} from "node:fs";
|
|
23520
|
-
import { basename as
|
|
23537
|
+
import { basename as basename3, dirname as dirname4, join as join6, resolve as resolve4 } from "node:path";
|
|
23521
23538
|
function databaseError(code, file, message) {
|
|
23522
23539
|
const issue3 = { phase: "semantic", code, file, message };
|
|
23523
23540
|
return new VnextConfigError([issue3]);
|
|
@@ -23666,7 +23683,7 @@ function checkIntegrity(database) {
|
|
|
23666
23683
|
return rows.length === 1 && rows[0]?.integrity_check === "ok";
|
|
23667
23684
|
}
|
|
23668
23685
|
function fileSha256(filePath) {
|
|
23669
|
-
const bytes =
|
|
23686
|
+
const bytes = readFileSync6(filePath);
|
|
23670
23687
|
return `sha256:${createHash8("sha256").update(bytes).digest("hex")}`;
|
|
23671
23688
|
}
|
|
23672
23689
|
function backupDatabaseFile(sourcePath, targetPath, storeId) {
|
|
@@ -23713,7 +23730,7 @@ function backupDatabaseFile(sourcePath, targetPath, storeId) {
|
|
|
23713
23730
|
return {
|
|
23714
23731
|
storeId,
|
|
23715
23732
|
sourcePath: resolvedSource,
|
|
23716
|
-
backupFile:
|
|
23733
|
+
backupFile: basename3(resolvedTarget),
|
|
23717
23734
|
schemaVersion,
|
|
23718
23735
|
sha256,
|
|
23719
23736
|
bytes,
|
|
@@ -23779,7 +23796,7 @@ function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVers
|
|
|
23779
23796
|
return {
|
|
23780
23797
|
storeId,
|
|
23781
23798
|
sourcePath: resolvedTarget,
|
|
23782
|
-
backupFile:
|
|
23799
|
+
backupFile: basename3(resolvedBackup),
|
|
23783
23800
|
schemaVersion,
|
|
23784
23801
|
integrity: "ok"
|
|
23785
23802
|
};
|
|
@@ -23787,19 +23804,19 @@ function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVers
|
|
|
23787
23804
|
function discoverProjectStores(projectRoot, options = {}) {
|
|
23788
23805
|
const root = resolve4(projectRoot);
|
|
23789
23806
|
const stores = [];
|
|
23790
|
-
const hubPath = options.hubDataPath ? resolve4(options.hubDataPath) :
|
|
23807
|
+
const hubPath = options.hubDataPath ? resolve4(options.hubDataPath) : join6(root, ".kxm", "state", "kxm.db");
|
|
23791
23808
|
if (existsSync6(hubPath)) {
|
|
23792
23809
|
stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: 3 });
|
|
23793
23810
|
}
|
|
23794
|
-
const registryPath =
|
|
23811
|
+
const registryPath = join6(root, ".kxm", "runtime", "registry.db");
|
|
23795
23812
|
if (existsSync6(registryPath)) {
|
|
23796
23813
|
stores.push({ storeId: "registry", sourcePath: registryPath, maxSupportedVersion: 1 });
|
|
23797
23814
|
}
|
|
23798
|
-
const bindingsPath =
|
|
23815
|
+
const bindingsPath = join6(root, ".kxm", "runtime", "bindings.db");
|
|
23799
23816
|
if (existsSync6(bindingsPath)) {
|
|
23800
23817
|
stores.push({ storeId: "binding-store", sourcePath: bindingsPath, maxSupportedVersion: 1 });
|
|
23801
23818
|
}
|
|
23802
|
-
const eventsDir =
|
|
23819
|
+
const eventsDir = join6(root, ".kxm", "runtime", "events");
|
|
23803
23820
|
if (existsSync6(eventsDir)) {
|
|
23804
23821
|
const entries = readdirSync2(eventsDir, { withFileTypes: true });
|
|
23805
23822
|
for (const entry of entries) {
|
|
@@ -23807,7 +23824,7 @@ function discoverProjectStores(projectRoot, options = {}) {
|
|
|
23807
23824
|
const key = entry.name.replace(/\.db$/, "");
|
|
23808
23825
|
stores.push({
|
|
23809
23826
|
storeId: `events:${key}`,
|
|
23810
|
-
sourcePath:
|
|
23827
|
+
sourcePath: join6(eventsDir, entry.name),
|
|
23811
23828
|
maxSupportedVersion: 3
|
|
23812
23829
|
});
|
|
23813
23830
|
}
|
|
@@ -23826,20 +23843,20 @@ function createBackup(options = {}) {
|
|
|
23826
23843
|
const now = /* @__PURE__ */ new Date();
|
|
23827
23844
|
const timestamp = now.toISOString().replace(/[:.]/g, "-");
|
|
23828
23845
|
const backupId = `bk_${randomBytes(8).toString("hex")}`;
|
|
23829
|
-
const outDir = options.outDir ? resolve4(options.outDir) :
|
|
23846
|
+
const outDir = options.outDir ? resolve4(options.outDir) : join6(projectRoot, ".kxm", "backups", `backup-${timestamp}`);
|
|
23830
23847
|
if (!existsSync6(outDir)) {
|
|
23831
23848
|
mkdirSync4(outDir, { recursive: true, mode: 448 });
|
|
23832
23849
|
}
|
|
23833
23850
|
const backedUpStores = [];
|
|
23834
23851
|
const usedFilenames = /* @__PURE__ */ new Set();
|
|
23835
23852
|
for (const store of stores) {
|
|
23836
|
-
let filename =
|
|
23853
|
+
let filename = basename3(store.sourcePath);
|
|
23837
23854
|
if (usedFilenames.has(filename)) {
|
|
23838
23855
|
const sanitizedId = store.storeId.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
23839
23856
|
filename = `${sanitizedId}-${filename}`;
|
|
23840
23857
|
}
|
|
23841
23858
|
usedFilenames.add(filename);
|
|
23842
|
-
const targetFile2 =
|
|
23859
|
+
const targetFile2 = join6(outDir, filename);
|
|
23843
23860
|
const record = backupDatabaseFile(store.sourcePath, targetFile2, store.storeId);
|
|
23844
23861
|
backedUpStores.push(record);
|
|
23845
23862
|
}
|
|
@@ -23854,7 +23871,7 @@ function createBackup(options = {}) {
|
|
|
23854
23871
|
const manifestSha256 = `sha256:${createHash8("sha256").update(manifestJson, "utf8").digest("hex")}`;
|
|
23855
23872
|
manifest.manifestSha256 = manifestSha256;
|
|
23856
23873
|
const finalJson = JSON.stringify(manifest, null, 2) + "\n";
|
|
23857
|
-
const manifestPath =
|
|
23874
|
+
const manifestPath = join6(outDir, "manifest.json");
|
|
23858
23875
|
writeFileSync4(manifestPath, finalJson, "utf8");
|
|
23859
23876
|
return { manifest, outDir };
|
|
23860
23877
|
}
|
|
@@ -23865,13 +23882,13 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23865
23882
|
throw databaseError("runtime_path_invalid", manifestPath, `manifest path ${manifestPath} does not exist`);
|
|
23866
23883
|
}
|
|
23867
23884
|
if (stat.isDirectory()) {
|
|
23868
|
-
manifestPath =
|
|
23885
|
+
manifestPath = join6(manifestPath, "manifest.json");
|
|
23869
23886
|
}
|
|
23870
23887
|
if (!existsSync6(manifestPath)) {
|
|
23871
23888
|
throw databaseError("runtime_path_invalid", manifestPath, `backup manifest ${manifestPath} not found`);
|
|
23872
23889
|
}
|
|
23873
23890
|
const manifestDir = dirname4(manifestPath);
|
|
23874
|
-
const rawText =
|
|
23891
|
+
const rawText = readFileSync6(manifestPath, "utf8");
|
|
23875
23892
|
let manifest;
|
|
23876
23893
|
try {
|
|
23877
23894
|
manifest = JSON.parse(rawText);
|
|
@@ -23883,7 +23900,7 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23883
23900
|
}
|
|
23884
23901
|
const restoredStores = [];
|
|
23885
23902
|
for (const store of manifest.stores) {
|
|
23886
|
-
const backupFilePath =
|
|
23903
|
+
const backupFilePath = join6(manifestDir, store.backupFile);
|
|
23887
23904
|
if (!existsSync6(backupFilePath)) {
|
|
23888
23905
|
throw databaseError("restore_file_missing", backupFilePath, `backup file ${store.backupFile} missing from ${manifestDir}`);
|
|
23889
23906
|
}
|
|
@@ -23902,7 +23919,7 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23902
23919
|
let targetPath = store.sourcePath;
|
|
23903
23920
|
if (options.projectRoot && manifest.projectRoot && targetPath.startsWith(manifest.projectRoot)) {
|
|
23904
23921
|
const rel = targetPath.slice(manifest.projectRoot.length).replace(/^[\\/]+/, "");
|
|
23905
|
-
targetPath =
|
|
23922
|
+
targetPath = join6(resolve4(options.projectRoot), rel);
|
|
23906
23923
|
}
|
|
23907
23924
|
const result = restoreDatabaseFile(
|
|
23908
23925
|
backupFilePath,
|
|
@@ -23923,12 +23940,12 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
23923
23940
|
// plugins/kxm/src/vnext-runtime-store.ts
|
|
23924
23941
|
function vnextRuntimePaths(options = {}) {
|
|
23925
23942
|
const stateRoot = options.stateRoot ? resolve5(options.stateRoot) : vnextUserStateRoot({ ...options.env ? { env: options.env } : {}, ...options.homeDir ? { homeDir: options.homeDir } : {} });
|
|
23926
|
-
const runtimeDir =
|
|
23943
|
+
const runtimeDir = join7(stateRoot, "runtime");
|
|
23927
23944
|
return {
|
|
23928
23945
|
stateRoot,
|
|
23929
23946
|
runtimeDir,
|
|
23930
|
-
registryDb:
|
|
23931
|
-
projectsDir:
|
|
23947
|
+
registryDb: join7(runtimeDir, "registry.db"),
|
|
23948
|
+
projectsDir: join7(runtimeDir, "projects")
|
|
23932
23949
|
};
|
|
23933
23950
|
}
|
|
23934
23951
|
function runtimeIssue(phase, code, file, message) {
|
|
@@ -24287,7 +24304,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
24287
24304
|
const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
|
|
24288
24305
|
const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
|
|
24289
24306
|
const assignments = compileAssignments(step, id, agent, sink);
|
|
24290
|
-
const
|
|
24307
|
+
const join48 = compileJoin(step, id, sink);
|
|
24291
24308
|
const requiredEvidence = compileEvidence(step, id, sink);
|
|
24292
24309
|
const transitions = compileTransitions(step, id, index, stepIndex, sink);
|
|
24293
24310
|
const outcomes = Object.keys(transitions).sort(compareCodeUnits4);
|
|
@@ -24315,7 +24332,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
24315
24332
|
transitions: orderedTransitions,
|
|
24316
24333
|
requiresPlanHash: requirePlanHash.includes(id),
|
|
24317
24334
|
assignments,
|
|
24318
|
-
join:
|
|
24335
|
+
join: join48
|
|
24319
24336
|
};
|
|
24320
24337
|
if (kind === "agent" || kind === "moa") {
|
|
24321
24338
|
if (!agent) return void 0;
|
|
@@ -24365,15 +24382,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
|
|
|
24365
24382
|
};
|
|
24366
24383
|
}
|
|
24367
24384
|
function compileJoin(step, stepId, sink) {
|
|
24368
|
-
const
|
|
24369
|
-
if (!
|
|
24370
|
-
const declared = stringValue2(
|
|
24385
|
+
const join48 = objectValue2(step.join);
|
|
24386
|
+
if (!join48) return { strategy: "all" };
|
|
24387
|
+
const declared = stringValue2(join48.strategy);
|
|
24371
24388
|
const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
|
|
24372
|
-
const minimumPassed = compileOptionalCount(
|
|
24389
|
+
const minimumPassed = compileOptionalCount(join48.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
|
|
24373
24390
|
const compiled = {
|
|
24374
24391
|
strategy,
|
|
24375
24392
|
...minimumPassed !== void 0 ? { minimumPassed } : {},
|
|
24376
|
-
...typeof
|
|
24393
|
+
...typeof join48.cancelRemaining === "boolean" ? { cancelRemaining: join48.cancelRemaining } : {}
|
|
24377
24394
|
};
|
|
24378
24395
|
return compiled;
|
|
24379
24396
|
}
|
|
@@ -24653,8 +24670,8 @@ var RECORD_LIMIT = 16 * 1024 * 1024;
|
|
|
24653
24670
|
// plugins/kxm/src/prices.ts
|
|
24654
24671
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
24655
24672
|
import { createHash as createHash10 } from "node:crypto";
|
|
24656
|
-
import { existsSync as existsSync8, readFileSync as
|
|
24657
|
-
import { join as
|
|
24673
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8, statSync } from "node:fs";
|
|
24674
|
+
import { join as join8 } from "node:path";
|
|
24658
24675
|
|
|
24659
24676
|
// plugins/kxm/src/price-calc.ts
|
|
24660
24677
|
var PRICES_SCHEMA = "kxm.prices.v1";
|
|
@@ -24806,11 +24823,11 @@ function parsePriceCatalog(text) {
|
|
|
24806
24823
|
return catalog;
|
|
24807
24824
|
}
|
|
24808
24825
|
function loadPriceCatalog(rootOrPath) {
|
|
24809
|
-
const candidatePath = existsSync8(
|
|
24826
|
+
const candidatePath = existsSync8(join8(rootOrPath, ".kxm", "prices.yaml")) ? join8(rootOrPath, ".kxm", "prices.yaml") : existsSync8(join8(rootOrPath, "prices.yaml")) ? join8(rootOrPath, "prices.yaml") : existsSync8(rootOrPath) && statSync(rootOrPath).isFile() ? rootOrPath : void 0;
|
|
24810
24827
|
if (!candidatePath || !existsSync8(candidatePath)) {
|
|
24811
24828
|
return void 0;
|
|
24812
24829
|
}
|
|
24813
|
-
const content =
|
|
24830
|
+
const content = readFileSync8(candidatePath, "utf8");
|
|
24814
24831
|
return parsePriceCatalog(content);
|
|
24815
24832
|
}
|
|
24816
24833
|
function loadPriceCatalogForEstimate(options) {
|
|
@@ -24831,13 +24848,13 @@ var import_yaml5 = __toESM(require_dist(), 1);
|
|
|
24831
24848
|
|
|
24832
24849
|
// plugins/kxm/src/producers.ts
|
|
24833
24850
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
24834
|
-
import { existsSync as existsSync9, readFileSync as
|
|
24835
|
-
import { join as
|
|
24851
|
+
import { existsSync as existsSync9, readFileSync as readFileSync9, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readdirSync as readdirSync3 } from "node:fs";
|
|
24852
|
+
import { join as join9 } from "node:path";
|
|
24836
24853
|
var empty = () => ({ schema: "kxm.producers.v1", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), promoted: [], demoted: [], enabled: [], disabled: [], roles: {} });
|
|
24837
24854
|
function loadProducerPolicy(root) {
|
|
24838
|
-
const path4 =
|
|
24855
|
+
const path4 = join9(root, ".kxm", "producers.yaml");
|
|
24839
24856
|
if (!existsSync9(path4)) return empty();
|
|
24840
|
-
const value = (0, import_yaml4.parse)(
|
|
24857
|
+
const value = (0, import_yaml4.parse)(readFileSync9(path4, "utf8"));
|
|
24841
24858
|
if (value?.schema !== "kxm.producers.v1" || !Array.isArray(value.promoted) || !Array.isArray(value.demoted)) throw new Error("invalid .kxm/producers.yaml");
|
|
24842
24859
|
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")])) : {} };
|
|
24843
24860
|
}
|
|
@@ -24847,8 +24864,8 @@ function updateProducer(root, model, status) {
|
|
|
24847
24864
|
policy.demoted = policy.demoted.filter((x2) => x2 !== model);
|
|
24848
24865
|
policy[status].push(model);
|
|
24849
24866
|
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24850
|
-
mkdirSync6(
|
|
24851
|
-
writeFileSync6(
|
|
24867
|
+
mkdirSync6(join9(root, ".kxm"), { recursive: true });
|
|
24868
|
+
writeFileSync6(join9(root, ".kxm", "producers.yaml"), (0, import_yaml4.stringify)(policy), "utf8");
|
|
24852
24869
|
return policy;
|
|
24853
24870
|
}
|
|
24854
24871
|
function setModelState(root, model, state, role, removeRole2 = false) {
|
|
@@ -24858,10 +24875,10 @@ function setModelState(root, model, state, role, removeRole2 = false) {
|
|
|
24858
24875
|
policy[state].push(model);
|
|
24859
24876
|
if (role) {
|
|
24860
24877
|
if (!/^[a-z][a-z0-9_-]{0,63}$/i.test(role)) throw new Error("invalid role id");
|
|
24861
|
-
const rolePath =
|
|
24878
|
+
const rolePath = join9(root, ".kxm", "roles", `${role}.yaml`);
|
|
24862
24879
|
let roleFile = {};
|
|
24863
24880
|
if (existsSync9(rolePath)) {
|
|
24864
|
-
const parsed = (0, import_yaml4.parse)(
|
|
24881
|
+
const parsed = (0, import_yaml4.parse)(readFileSync9(rolePath, "utf8"));
|
|
24865
24882
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) roleFile = parsed;
|
|
24866
24883
|
}
|
|
24867
24884
|
const roster = Array.isArray(roleFile.roster) ? roleFile.roster.filter((entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry)) : [];
|
|
@@ -24872,29 +24889,29 @@ function setModelState(root, model, state, role, removeRole2 = false) {
|
|
|
24872
24889
|
roleFile.schema ??= "kxm.role.v1";
|
|
24873
24890
|
roleFile.id ??= role;
|
|
24874
24891
|
roleFile.roster = roster;
|
|
24875
|
-
mkdirSync6(
|
|
24892
|
+
mkdirSync6(join9(root, ".kxm", "roles"), { recursive: true });
|
|
24876
24893
|
writeFileSync6(rolePath, (0, import_yaml4.stringify)(roleFile), "utf8");
|
|
24877
24894
|
}
|
|
24878
24895
|
policy.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24879
|
-
mkdirSync6(
|
|
24880
|
-
writeFileSync6(
|
|
24896
|
+
mkdirSync6(join9(root, ".kxm"), { recursive: true });
|
|
24897
|
+
writeFileSync6(join9(root, ".kxm", "producers.yaml"), (0, import_yaml4.stringify)(policy), "utf8");
|
|
24881
24898
|
return policy;
|
|
24882
24899
|
}
|
|
24883
24900
|
function listRoleBindings(root) {
|
|
24884
|
-
const dir =
|
|
24901
|
+
const dir = join9(root, ".kxm", "roles");
|
|
24885
24902
|
const result = {};
|
|
24886
24903
|
if (!existsSync9(dir)) return result;
|
|
24887
24904
|
for (const file of readdirSync3(dir).filter((name) => name.endsWith(".yaml"))) {
|
|
24888
24905
|
const role = file.slice(0, -5);
|
|
24889
|
-
const value = (0, import_yaml4.parse)(
|
|
24906
|
+
const value = (0, import_yaml4.parse)(readFileSync9(join9(dir, file), "utf8"));
|
|
24890
24907
|
result[role] = (value.roster ?? []).map((entry) => entry.model).filter((model) => typeof model === "string");
|
|
24891
24908
|
}
|
|
24892
24909
|
return result;
|
|
24893
24910
|
}
|
|
24894
24911
|
function listInventoryModels(root) {
|
|
24895
|
-
const path4 =
|
|
24912
|
+
const path4 = join9(root, ".kxm", "models", "inventory.yaml");
|
|
24896
24913
|
if (!existsSync9(path4)) return [];
|
|
24897
|
-
const value = (0, import_yaml4.parse)(
|
|
24914
|
+
const value = (0, import_yaml4.parse)(readFileSync9(path4, "utf8"));
|
|
24898
24915
|
return (value.models ?? []).map((m2) => m2.id).filter((id) => typeof id === "string");
|
|
24899
24916
|
}
|
|
24900
24917
|
|
|
@@ -25528,7 +25545,7 @@ function formatRoutingReport(report2, options = {}) {
|
|
|
25528
25545
|
// plugins/kxm/src/vnext-runtime-supervisor.ts
|
|
25529
25546
|
var repoRoot = resolve7(fileURLToPath2(new URL("../../../", import.meta.url)));
|
|
25530
25547
|
function vnextSupervisorTokenFile(paths) {
|
|
25531
|
-
return
|
|
25548
|
+
return join10(paths.runtimeDir, "supervisor.token");
|
|
25532
25549
|
}
|
|
25533
25550
|
function readVnextSupervisorToken(paths) {
|
|
25534
25551
|
const file = vnextSupervisorTokenFile(paths);
|
|
@@ -25537,7 +25554,7 @@ function readVnextSupervisorToken(paths) {
|
|
|
25537
25554
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
25538
25555
|
throw runtimeError("runtime_path_invalid", file, "supervisor token file must be a regular file, not a link");
|
|
25539
25556
|
}
|
|
25540
|
-
const token =
|
|
25557
|
+
const token = readFileSync10(file, "utf8").trim();
|
|
25541
25558
|
return token.length >= 32 ? token : void 0;
|
|
25542
25559
|
}
|
|
25543
25560
|
function processAlive(pid) {
|
|
@@ -25551,7 +25568,7 @@ function processAlive(pid) {
|
|
|
25551
25568
|
var HEARTBEAT_STALE_MS = 15e3;
|
|
25552
25569
|
var SUPERVISOR_ERROR_MAX_AGE_MS = 3e4;
|
|
25553
25570
|
function supervisorErrorFile(paths) {
|
|
25554
|
-
return
|
|
25571
|
+
return join10(paths.runtimeDir, "supervisor.error");
|
|
25555
25572
|
}
|
|
25556
25573
|
function clearSupervisorError(paths) {
|
|
25557
25574
|
const file = supervisorErrorFile(paths);
|
|
@@ -25564,7 +25581,7 @@ function readRecentSupervisorError(paths) {
|
|
|
25564
25581
|
const ageMs = Date.now() - stat.mtimeMs;
|
|
25565
25582
|
if (ageMs > SUPERVISOR_ERROR_MAX_AGE_MS) return void 0;
|
|
25566
25583
|
try {
|
|
25567
|
-
return
|
|
25584
|
+
return readFileSync10(file, "utf8").trim();
|
|
25568
25585
|
} catch {
|
|
25569
25586
|
return void 0;
|
|
25570
25587
|
}
|
|
@@ -25631,7 +25648,7 @@ async function ensureVnextSupervisor(options = {}) {
|
|
|
25631
25648
|
throw runtimeError("runtime_supervisor_unreachable", paths.registryDb, `runtime supervisor pid ${status.pid} is registered as running but cannot be probed`);
|
|
25632
25649
|
}
|
|
25633
25650
|
clearSupervisorError(paths);
|
|
25634
|
-
const scriptPath =
|
|
25651
|
+
const scriptPath = join10(repoRoot, "scripts", "kxm-runtime-supervisor.mjs");
|
|
25635
25652
|
const spawnImpl = options.spawnImpl ?? ((script, env) => {
|
|
25636
25653
|
const child = spawn2(process.execPath, [script], {
|
|
25637
25654
|
detached: true,
|
|
@@ -25684,12 +25701,13 @@ async function vnextRuntimeRequest(handle, method, path4, body) {
|
|
|
25684
25701
|
|
|
25685
25702
|
// plugins/kxm/src/cli/types.ts
|
|
25686
25703
|
import { spawn as spawn3 } from "node:child_process";
|
|
25687
|
-
import { join as
|
|
25704
|
+
import { join as join13, resolve as resolve9 } from "node:path";
|
|
25688
25705
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
25689
25706
|
|
|
25690
25707
|
// plugins/kxm/src/redact.ts
|
|
25691
25708
|
var SECRET_PATTERNS = [
|
|
25692
25709
|
/\bsk-[A-Za-z0-9_-]{8,}\b/g,
|
|
25710
|
+
/\bsk-ant-[A-Za-z0-9_-]{8,}\b/g,
|
|
25693
25711
|
/\bghp_[A-Za-z0-9_]{20,}\b/g,
|
|
25694
25712
|
/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g,
|
|
25695
25713
|
/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/gi,
|
|
@@ -25697,9 +25715,9 @@ var SECRET_PATTERNS = [
|
|
|
25697
25715
|
/\bya29\.[A-Za-z0-9._~+/-]+=*/g,
|
|
25698
25716
|
/\b1\/\/[A-Za-z0-9_-]+/g,
|
|
25699
25717
|
/\b1\/[A-Za-z0-9_-]{20,}/g,
|
|
25700
|
-
/("?(?:access_token|refresh_token|id_token)"?\s*[:=]\s*")[^"]*(")/gi,
|
|
25718
|
+
/("?(?:access_token|refresh_token|id_token|sessionKey|session_key|claude_oauth_token|anthropicApiKey)"?\s*[:=]\s*")[^"]*(")/gi,
|
|
25701
25719
|
/\bKXM_[A-Z0-9_]*(TOKEN|SECRET|KEY)[A-Z0-9_]*=\S+/gi,
|
|
25702
|
-
/\b(GITHUB_TOKEN|GH_TOKEN|KXM_AUTH_TOKEN|KXM_WORKFLOW_SIGNAL_SECRET)=\S+/gi,
|
|
25720
|
+
/\b(GITHUB_TOKEN|GH_TOKEN|KXM_AUTH_TOKEN|KXM_WORKFLOW_SIGNAL_SECRET|ANTHROPIC_API_KEY|ANTHROPIC_AUTH_TOKEN|CLAUDE_API_KEY)=\S+/gi,
|
|
25703
25721
|
/\b[A-Fa-f0-9]{64}\b/g
|
|
25704
25722
|
];
|
|
25705
25723
|
function redactSecrets(value) {
|
|
@@ -25714,8 +25732,8 @@ function redactStringList(values, maxItems = 32) {
|
|
|
25714
25732
|
}
|
|
25715
25733
|
|
|
25716
25734
|
// plugins/kxm/src/telemetry.ts
|
|
25717
|
-
import { appendFileSync, mkdirSync as mkdirSync8, readFileSync as
|
|
25718
|
-
import { dirname as dirname7, join as
|
|
25735
|
+
import { appendFileSync, mkdirSync as mkdirSync8, readFileSync as readFileSync11 } from "node:fs";
|
|
25736
|
+
import { dirname as dirname7, join as join11 } from "node:path";
|
|
25719
25737
|
var TELEMETRY_SCHEMA = "kxm.telemetry.v1";
|
|
25720
25738
|
function inferImprovementTarget(input) {
|
|
25721
25739
|
const explicit = input.env?.KXM_IMPROVE_TARGET?.trim();
|
|
@@ -25730,7 +25748,7 @@ function appendTelemetry(path4, event) {
|
|
|
25730
25748
|
`, { encoding: "utf8", mode: 384 });
|
|
25731
25749
|
}
|
|
25732
25750
|
function telemetryPath(logsDir) {
|
|
25733
|
-
return
|
|
25751
|
+
return join11(logsDir, "telemetry.jsonl");
|
|
25734
25752
|
}
|
|
25735
25753
|
function makeTelemetryEvent(input) {
|
|
25736
25754
|
return {
|
|
@@ -25745,7 +25763,7 @@ function makeTelemetryEvent(input) {
|
|
|
25745
25763
|
function readRoutingRecords(path4) {
|
|
25746
25764
|
const records = [];
|
|
25747
25765
|
try {
|
|
25748
|
-
const raw =
|
|
25766
|
+
const raw = readFileSync11(path4, "utf8");
|
|
25749
25767
|
for (const line of raw.split(/\r?\n/)) {
|
|
25750
25768
|
if (!line.trim()) continue;
|
|
25751
25769
|
try {
|
|
@@ -25822,9 +25840,9 @@ function workerResult(worker, payload) {
|
|
|
25822
25840
|
}
|
|
25823
25841
|
|
|
25824
25842
|
// plugins/kxm/src/hub-binding.ts
|
|
25825
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync9, readFileSync as
|
|
25843
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync9, readFileSync as readFileSync12, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
|
|
25826
25844
|
import { homedir as homedir3 } from "node:os";
|
|
25827
|
-
import { dirname as dirname8, isAbsolute as isAbsolute5, join as
|
|
25845
|
+
import { dirname as dirname8, isAbsolute as isAbsolute5, join as join12, resolve as resolve8 } from "node:path";
|
|
25828
25846
|
var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
25829
25847
|
var HUB_HEALTH_PROBE_MS = 300;
|
|
25830
25848
|
var HubBindingError = class extends Error {
|
|
@@ -25841,16 +25859,16 @@ function resolveUserStateRoot(env) {
|
|
|
25841
25859
|
}
|
|
25842
25860
|
if (process.platform === "win32") {
|
|
25843
25861
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
25844
|
-
const base2 = localAppData && isAbsolute5(localAppData) ? localAppData :
|
|
25862
|
+
const base2 = localAppData && isAbsolute5(localAppData) ? localAppData : join12(homedir3(), "AppData", "Local");
|
|
25845
25863
|
return resolve8(base2, "KXM");
|
|
25846
25864
|
}
|
|
25847
25865
|
if (process.platform === "darwin") return resolve8(homedir3(), "Library", "Application Support", "KXM");
|
|
25848
25866
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
25849
|
-
const base = xdgState && isAbsolute5(xdgState) ? xdgState :
|
|
25867
|
+
const base = xdgState && isAbsolute5(xdgState) ? xdgState : join12(homedir3(), ".local", "state");
|
|
25850
25868
|
return resolve8(base, "kxm");
|
|
25851
25869
|
}
|
|
25852
25870
|
function hubBindingFile(env = process.env) {
|
|
25853
|
-
return
|
|
25871
|
+
return join12(resolveUserStateRoot(env), "hub-binding.json");
|
|
25854
25872
|
}
|
|
25855
25873
|
function validateHubUrl(raw) {
|
|
25856
25874
|
let parsed;
|
|
@@ -25878,7 +25896,7 @@ function readHubBinding(env = process.env) {
|
|
|
25878
25896
|
if (!existsSync11(file)) return void 0;
|
|
25879
25897
|
let parsed;
|
|
25880
25898
|
try {
|
|
25881
|
-
parsed = JSON.parse(
|
|
25899
|
+
parsed = JSON.parse(readFileSync12(file, "utf8"));
|
|
25882
25900
|
} catch {
|
|
25883
25901
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
25884
25902
|
}
|
|
@@ -25901,7 +25919,7 @@ function readHubBinding(env = process.env) {
|
|
|
25901
25919
|
function writeHubBinding(record, env = process.env) {
|
|
25902
25920
|
const file = hubBindingFile(env);
|
|
25903
25921
|
mkdirSync9(dirname8(file), { recursive: true, mode: 448 });
|
|
25904
|
-
const temporary =
|
|
25922
|
+
const temporary = join12(dirname8(file), `.hub-binding-${process.pid}.tmp`);
|
|
25905
25923
|
try {
|
|
25906
25924
|
writeFileSync8(temporary, `${JSON.stringify(record, null, 2)}
|
|
25907
25925
|
`, { encoding: "utf8", mode: 384 });
|
|
@@ -25949,7 +25967,7 @@ async function probeHubHealth(url, fetchImpl, timeoutMs = HUB_HEALTH_PROBE_MS) {
|
|
|
25949
25967
|
var repoRoot2 = resolve9(fileURLToPath3(new URL("../../../../", import.meta.url)));
|
|
25950
25968
|
function spawnScript(scriptName, extraEnv = {}) {
|
|
25951
25969
|
return new Promise((resolveExit) => {
|
|
25952
|
-
const child = spawn3(process.execPath, [
|
|
25970
|
+
const child = spawn3(process.execPath, [join13(repoRoot2, "scripts", scriptName)], {
|
|
25953
25971
|
stdio: "inherit",
|
|
25954
25972
|
env: { ...process.env, ...extraEnv }
|
|
25955
25973
|
});
|
|
@@ -26039,10 +26057,10 @@ function workspaceDirs(cwd, workspaceFlag, env) {
|
|
|
26039
26057
|
return {
|
|
26040
26058
|
workdir,
|
|
26041
26059
|
workspace,
|
|
26042
|
-
config: derive ?
|
|
26043
|
-
logs: derive ?
|
|
26044
|
-
assets: derive ?
|
|
26045
|
-
state: derive ?
|
|
26060
|
+
config: derive ? join13(workspace, "config") : resolve9(workdir, env.KXM_CONFIG_DIR?.trim() || join13(workspace, "config")),
|
|
26061
|
+
logs: derive ? join13(workspace, "logs") : resolve9(workdir, env.KXM_LOGS_DIR?.trim() || join13(workspace, "logs")),
|
|
26062
|
+
assets: derive ? join13(workspace, "assets") : resolve9(workdir, env.KXM_ASSETS_DIR?.trim() || join13(workspace, "assets")),
|
|
26063
|
+
state: derive ? join13(workspace, "state") : resolve9(workdir, env.KXM_STATE_DIR?.trim() || join13(workspace, "state"))
|
|
26046
26064
|
};
|
|
26047
26065
|
}
|
|
26048
26066
|
function maskEnvName(name) {
|
|
@@ -26110,20 +26128,20 @@ function workspaceEnv(runtime) {
|
|
|
26110
26128
|
// plugins/kxm/src/cli/roles.ts
|
|
26111
26129
|
var import_yaml8 = __toESM(require_dist(), 1);
|
|
26112
26130
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
26113
|
-
import { existsSync as existsSync14, readFileSync as
|
|
26114
|
-
import { join as
|
|
26131
|
+
import { existsSync as existsSync14, readFileSync as readFileSync15 } from "node:fs";
|
|
26132
|
+
import { join as join16, resolve as resolve12 } from "node:path";
|
|
26115
26133
|
import { createInterface } from "node:readline";
|
|
26116
26134
|
|
|
26117
26135
|
// plugins/kxm/src/role.ts
|
|
26118
26136
|
var import_yaml7 = __toESM(require_dist(), 1);
|
|
26119
|
-
import { existsSync as existsSync13, mkdirSync as mkdirSync11, readdirSync as readdirSync4, readFileSync as
|
|
26120
|
-
import { join as
|
|
26137
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync11, readdirSync as readdirSync4, readFileSync as readFileSync14, rmSync as rmSync4, writeFileSync as writeFileSync10 } from "node:fs";
|
|
26138
|
+
import { join as join15 } from "node:path";
|
|
26121
26139
|
|
|
26122
26140
|
// plugins/kxm/src/config.ts
|
|
26123
26141
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
26124
|
-
import { existsSync as existsSync12, mkdirSync as mkdirSync10, readFileSync as
|
|
26142
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "node:fs";
|
|
26125
26143
|
import { homedir as homedir4 } from "node:os";
|
|
26126
|
-
import { dirname as dirname9, join as
|
|
26144
|
+
import { dirname as dirname9, join as join14, resolve as resolve10 } from "node:path";
|
|
26127
26145
|
var KXM_CONFIG_SCHEMA = "kxm.config.v1";
|
|
26128
26146
|
var DEFAULT_KXM_CONFIG = {
|
|
26129
26147
|
schema: KXM_CONFIG_SCHEMA,
|
|
@@ -26144,6 +26162,9 @@ var DEFAULT_KXM_CONFIG = {
|
|
|
26144
26162
|
sync: {
|
|
26145
26163
|
defaultTracker: "none"
|
|
26146
26164
|
},
|
|
26165
|
+
hub: {
|
|
26166
|
+
autoStart: "background"
|
|
26167
|
+
},
|
|
26147
26168
|
improvement: {
|
|
26148
26169
|
promotionPolicy: "manual_pr",
|
|
26149
26170
|
telemetryHalfLifeDays: 14,
|
|
@@ -26174,7 +26195,7 @@ var DEFAULT_KXM_CONFIG = {
|
|
|
26174
26195
|
};
|
|
26175
26196
|
function userConfigDirectory(overrideDir) {
|
|
26176
26197
|
if (overrideDir) return resolve10(overrideDir);
|
|
26177
|
-
return resolve10(process.env.KXM_USER_CONFIG_DIR?.trim() ||
|
|
26198
|
+
return resolve10(process.env.KXM_USER_CONFIG_DIR?.trim() || join14(homedir4(), ".config", "kxm"));
|
|
26178
26199
|
}
|
|
26179
26200
|
function repoConfigDirectory(repoRoot6) {
|
|
26180
26201
|
return resolve10(repoRoot6, ".kxm");
|
|
@@ -26191,16 +26212,20 @@ function deepMerge(target, source) {
|
|
|
26191
26212
|
}
|
|
26192
26213
|
return result;
|
|
26193
26214
|
}
|
|
26215
|
+
function normalizeHubConfig(raw) {
|
|
26216
|
+
const autoStart = raw?.autoStart;
|
|
26217
|
+
return { autoStart: autoStart === "off" || autoStart === "background" ? autoStart : DEFAULT_KXM_CONFIG.hub.autoStart };
|
|
26218
|
+
}
|
|
26194
26219
|
function loadKxmConfig(repoRoot6 = process.cwd(), options = {}) {
|
|
26195
26220
|
const userDir = userConfigDirectory(options.userConfigDir);
|
|
26196
|
-
const userConfigFile =
|
|
26221
|
+
const userConfigFile = join14(userDir, "config.yaml");
|
|
26197
26222
|
const repoDir = repoConfigDirectory(repoRoot6);
|
|
26198
|
-
const repoConfigFile =
|
|
26223
|
+
const repoConfigFile = join14(repoDir, "config.yaml");
|
|
26199
26224
|
let userRaw = {};
|
|
26200
26225
|
let userLoadedPath;
|
|
26201
26226
|
if (existsSync12(userConfigFile)) {
|
|
26202
26227
|
try {
|
|
26203
|
-
const text =
|
|
26228
|
+
const text = readFileSync13(userConfigFile, "utf8");
|
|
26204
26229
|
userRaw = (0, import_yaml6.parse)(text) ?? {};
|
|
26205
26230
|
userLoadedPath = userConfigFile;
|
|
26206
26231
|
} catch (error) {
|
|
@@ -26211,7 +26236,7 @@ function loadKxmConfig(repoRoot6 = process.cwd(), options = {}) {
|
|
|
26211
26236
|
let repoLoadedPath;
|
|
26212
26237
|
if (existsSync12(repoConfigFile)) {
|
|
26213
26238
|
try {
|
|
26214
|
-
const text =
|
|
26239
|
+
const text = readFileSync13(repoConfigFile, "utf8");
|
|
26215
26240
|
repoRaw = (0, import_yaml6.parse)(text) ?? {};
|
|
26216
26241
|
repoLoadedPath = repoConfigFile;
|
|
26217
26242
|
} catch (error) {
|
|
@@ -26227,6 +26252,7 @@ function loadKxmConfig(repoRoot6 = process.cwd(), options = {}) {
|
|
|
26227
26252
|
defaults: mergedAll.defaults ?? {},
|
|
26228
26253
|
dash: mergedAll.dash ?? {},
|
|
26229
26254
|
sync: mergedAll.sync ?? {},
|
|
26255
|
+
hub: normalizeHubConfig(mergedAll.hub),
|
|
26230
26256
|
improvement: mergedAll.improvement ?? DEFAULT_KXM_CONFIG.improvement,
|
|
26231
26257
|
routing: mergedAll.routing ?? DEFAULT_KXM_CONFIG.routing,
|
|
26232
26258
|
telemetry: mergedAll.telemetry ?? DEFAULT_KXM_CONFIG.telemetry,
|
|
@@ -26247,12 +26273,12 @@ function getKxmConfigValue(config, keyPath) {
|
|
|
26247
26273
|
}
|
|
26248
26274
|
function setKxmConfigValue(repoRoot6, keyPath, value, options = {}) {
|
|
26249
26275
|
const scope = options.scope ?? "project";
|
|
26250
|
-
const targetFile2 = scope === "user" ?
|
|
26276
|
+
const targetFile2 = scope === "user" ? join14(userConfigDirectory(options.userConfigDir), "config.yaml") : join14(repoConfigDirectory(repoRoot6), "config.yaml");
|
|
26251
26277
|
mkdirSync10(dirname9(targetFile2), { recursive: true });
|
|
26252
26278
|
let existing = {};
|
|
26253
26279
|
if (existsSync12(targetFile2)) {
|
|
26254
26280
|
try {
|
|
26255
|
-
existing = (0, import_yaml6.parse)(
|
|
26281
|
+
existing = (0, import_yaml6.parse)(readFileSync13(targetFile2, "utf8")) ?? {};
|
|
26256
26282
|
} catch {
|
|
26257
26283
|
existing = {};
|
|
26258
26284
|
}
|
|
@@ -26363,9 +26389,9 @@ var DEFAULT_ROLES = {
|
|
|
26363
26389
|
};
|
|
26364
26390
|
function rolesDirectory(scope, repoRoot6 = process.cwd(), userConfigDir) {
|
|
26365
26391
|
if (scope === "global") {
|
|
26366
|
-
return
|
|
26392
|
+
return join15(userConfigDirectory(userConfigDir), "roles");
|
|
26367
26393
|
}
|
|
26368
|
-
return
|
|
26394
|
+
return join15(repoConfigDirectory(repoRoot6), "roles");
|
|
26369
26395
|
}
|
|
26370
26396
|
function ensureRolesDirectory(scope, repoRoot6 = process.cwd(), userConfigDir) {
|
|
26371
26397
|
const dir = rolesDirectory(scope, repoRoot6, userConfigDir);
|
|
@@ -26377,7 +26403,7 @@ function ensureRolesDirectory(scope, repoRoot6 = process.cwd(), userConfigDir) {
|
|
|
26377
26403
|
function parseRoleFile(filePath) {
|
|
26378
26404
|
if (!existsSync13(filePath)) return void 0;
|
|
26379
26405
|
try {
|
|
26380
|
-
const raw =
|
|
26406
|
+
const raw = readFileSync14(filePath, "utf8");
|
|
26381
26407
|
const parsed = (0, import_yaml7.parse)(raw);
|
|
26382
26408
|
if (!parsed || typeof parsed !== "object" || parsed.schema !== KXM_ROLE_SCHEMA) {
|
|
26383
26409
|
return void 0;
|
|
@@ -26407,7 +26433,7 @@ function listRoles(options = {}) {
|
|
|
26407
26433
|
if (scopeFilter !== "global" && existsSync13(localDir)) {
|
|
26408
26434
|
for (const entry of readdirSync4(localDir)) {
|
|
26409
26435
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
26410
|
-
const filePath =
|
|
26436
|
+
const filePath = join15(localDir, entry);
|
|
26411
26437
|
const parsed = parseRoleFile(filePath);
|
|
26412
26438
|
if (parsed) {
|
|
26413
26439
|
localRoles.set(parsed.id, { role: parsed, filePath });
|
|
@@ -26419,7 +26445,7 @@ function listRoles(options = {}) {
|
|
|
26419
26445
|
if (scopeFilter !== "local" && existsSync13(globalDir)) {
|
|
26420
26446
|
for (const entry of readdirSync4(globalDir)) {
|
|
26421
26447
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
26422
|
-
const filePath =
|
|
26448
|
+
const filePath = join15(globalDir, entry);
|
|
26423
26449
|
const parsed = parseRoleFile(filePath);
|
|
26424
26450
|
if (parsed) {
|
|
26425
26451
|
globalRoles.set(parsed.id, { role: parsed, filePath });
|
|
@@ -26467,13 +26493,13 @@ function getRole(roleId, options = {}) {
|
|
|
26467
26493
|
const repoRoot6 = options.repoRoot ?? process.cwd();
|
|
26468
26494
|
if (scope !== "global") {
|
|
26469
26495
|
const localDir = rolesDirectory("local", repoRoot6, options.userConfigDir);
|
|
26470
|
-
const localFile =
|
|
26496
|
+
const localFile = join15(localDir, `${roleId}.yaml`);
|
|
26471
26497
|
const parsed = parseRoleFile(localFile);
|
|
26472
26498
|
if (parsed) return { role: parsed, scope: "local", filePath: localFile };
|
|
26473
26499
|
}
|
|
26474
26500
|
if (scope !== "local") {
|
|
26475
26501
|
const globalDir = rolesDirectory("global", repoRoot6, options.userConfigDir);
|
|
26476
|
-
const globalFile =
|
|
26502
|
+
const globalFile = join15(globalDir, `${roleId}.yaml`);
|
|
26477
26503
|
const parsed = parseRoleFile(globalFile);
|
|
26478
26504
|
if (parsed) return { role: parsed, scope: "global", filePath: globalFile };
|
|
26479
26505
|
}
|
|
@@ -26483,7 +26509,7 @@ function addRole(role, options = {}) {
|
|
|
26483
26509
|
const scope = options.scope ?? "local";
|
|
26484
26510
|
const repoRoot6 = options.repoRoot ?? process.cwd();
|
|
26485
26511
|
const dir = ensureRolesDirectory(scope, repoRoot6, options.userConfigDir);
|
|
26486
|
-
const filePath =
|
|
26512
|
+
const filePath = join15(dir, `${role.id}.yaml`);
|
|
26487
26513
|
if (existsSync13(filePath) && !options.overwrite) {
|
|
26488
26514
|
throw new Error(`role_already_exists: role '${role.id}' already exists at ${filePath}`);
|
|
26489
26515
|
}
|
|
@@ -26494,7 +26520,7 @@ function removeRole(roleId, options = {}) {
|
|
|
26494
26520
|
const scope = options.scope ?? "local";
|
|
26495
26521
|
const repoRoot6 = options.repoRoot ?? process.cwd();
|
|
26496
26522
|
const dir = rolesDirectory(scope, repoRoot6, options.userConfigDir);
|
|
26497
|
-
const filePath =
|
|
26523
|
+
const filePath = join15(dir, `${roleId}.yaml`);
|
|
26498
26524
|
if (!existsSync13(filePath)) {
|
|
26499
26525
|
throw new Error(`role_not_found: role '${roleId}' not found in ${scope} directory (${filePath})`);
|
|
26500
26526
|
}
|
|
@@ -26516,7 +26542,7 @@ function modifyRole(roleId, updates, options = {}) {
|
|
|
26516
26542
|
const scope = options.scope ?? target.scope;
|
|
26517
26543
|
const repoRoot6 = options.repoRoot ?? process.cwd();
|
|
26518
26544
|
const dir = ensureRolesDirectory(scope, repoRoot6, options.userConfigDir);
|
|
26519
|
-
const filePath =
|
|
26545
|
+
const filePath = join15(dir, `${roleId}.yaml`);
|
|
26520
26546
|
writeFileSync10(filePath, (0, import_yaml7.stringify)(updated), "utf8");
|
|
26521
26547
|
return { id: roleId, role: updated, filePath, scope };
|
|
26522
26548
|
}
|
|
@@ -26565,9 +26591,9 @@ var DEFAULT_ROLE_SEATS = {
|
|
|
26565
26591
|
};
|
|
26566
26592
|
function findExistingRoleHostsFile(scope, repoRoot6 = process.cwd(), userConfigDir) {
|
|
26567
26593
|
const dir = scope === "global" ? userConfigDirectory(userConfigDir) : repoConfigDirectory(repoRoot6);
|
|
26568
|
-
const yamlPath =
|
|
26569
|
-
const ymlPath =
|
|
26570
|
-
const jsonPath =
|
|
26594
|
+
const yamlPath = join15(dir, "role-hosts.yaml");
|
|
26595
|
+
const ymlPath = join15(dir, "role-hosts.yml");
|
|
26596
|
+
const jsonPath = join15(dir, "role-hosts.json");
|
|
26571
26597
|
if (existsSync13(yamlPath)) return { filePath: yamlPath, exists: true, format: "yaml" };
|
|
26572
26598
|
if (existsSync13(ymlPath)) return { filePath: ymlPath, exists: true, format: "yaml" };
|
|
26573
26599
|
if (existsSync13(jsonPath)) return { filePath: jsonPath, exists: true, format: "json" };
|
|
@@ -26576,7 +26602,7 @@ function findExistingRoleHostsFile(scope, repoRoot6 = process.cwd(), userConfigD
|
|
|
26576
26602
|
function parseRoleHostsFile(filePath) {
|
|
26577
26603
|
if (!existsSync13(filePath)) return void 0;
|
|
26578
26604
|
try {
|
|
26579
|
-
const raw =
|
|
26605
|
+
const raw = readFileSync14(filePath, "utf8");
|
|
26580
26606
|
const parsed = (0, import_yaml7.parse)(raw);
|
|
26581
26607
|
if (!parsed || typeof parsed !== "object") return void 0;
|
|
26582
26608
|
if (parsed.schema && parsed.schema !== KXM_ROLE_HOSTS_SCHEMA) return void 0;
|
|
@@ -26652,7 +26678,7 @@ function saveRoleHostsConfig(config, options = {}) {
|
|
|
26652
26678
|
mkdirSync11(dir, { recursive: true });
|
|
26653
26679
|
}
|
|
26654
26680
|
const format = options.format ?? "yaml";
|
|
26655
|
-
const filePath =
|
|
26681
|
+
const filePath = join15(dir, format === "json" ? "role-hosts.json" : "role-hosts.yaml");
|
|
26656
26682
|
const payload = {
|
|
26657
26683
|
schema: KXM_ROLE_HOSTS_SCHEMA,
|
|
26658
26684
|
seats: config.seats ?? {},
|
|
@@ -26894,7 +26920,7 @@ async function cmdRoleAdd(runtime, roleId, options) {
|
|
|
26894
26920
|
let roleDef;
|
|
26895
26921
|
if (options.file) {
|
|
26896
26922
|
const filePath = resolve12(runtime.cwd, options.file);
|
|
26897
|
-
const content =
|
|
26923
|
+
const content = readFileSync15(filePath, "utf8");
|
|
26898
26924
|
roleDef = (0, import_yaml8.parse)(content);
|
|
26899
26925
|
roleDef.id = roleId;
|
|
26900
26926
|
} else {
|
|
@@ -27193,7 +27219,7 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
27193
27219
|
return 1;
|
|
27194
27220
|
}
|
|
27195
27221
|
}
|
|
27196
|
-
const dbPath =
|
|
27222
|
+
const dbPath = join16(runtime.cwd, ".kxm", "state", "kxm.db");
|
|
27197
27223
|
if (existsSync14(dbPath)) {
|
|
27198
27224
|
try {
|
|
27199
27225
|
const database = new DatabaseSync(dbPath);
|
|
@@ -27256,8 +27282,8 @@ async function cmdRoleResume(runtime, runId, ruling) {
|
|
|
27256
27282
|
|
|
27257
27283
|
// plugins/kxm/src/cli/workflows.ts
|
|
27258
27284
|
import { createHmac as createHmac3, randomUUID as randomUUID7 } from "node:crypto";
|
|
27259
|
-
import { existsSync as existsSync16, readFileSync as
|
|
27260
|
-
import { join as
|
|
27285
|
+
import { existsSync as existsSync16, readFileSync as readFileSync17 } from "node:fs";
|
|
27286
|
+
import { join as join18, resolve as resolve15 } from "node:path";
|
|
27261
27287
|
|
|
27262
27288
|
// plugins/kxm/src/retrospective.ts
|
|
27263
27289
|
import { mkdirSync as mkdirSync12, renameSync as renameSync4, writeFileSync as writeFileSync11 } from "node:fs";
|
|
@@ -27675,8 +27701,8 @@ async function watchGithubChecks(input) {
|
|
|
27675
27701
|
|
|
27676
27702
|
// plugins/kxm/src/workflow-manager.ts
|
|
27677
27703
|
var import_yaml9 = __toESM(require_dist(), 1);
|
|
27678
|
-
import { existsSync as existsSync15, mkdirSync as mkdirSync13, readdirSync as readdirSync5, readFileSync as
|
|
27679
|
-
import { join as
|
|
27704
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync13, readdirSync as readdirSync5, readFileSync as readFileSync16, rmSync as rmSync5, writeFileSync as writeFileSync12 } from "node:fs";
|
|
27705
|
+
import { join as join17 } from "node:path";
|
|
27680
27706
|
var WORKFLOW_TEMPLATES = {
|
|
27681
27707
|
"implement-and-verify": {
|
|
27682
27708
|
schema: "kxm.workflow.v1",
|
|
@@ -27827,9 +27853,9 @@ var WORKFLOW_TEMPLATES = {
|
|
|
27827
27853
|
var DEFAULT_WORKFLOW_TEMPLATE = WORKFLOW_TEMPLATES["implement-and-verify"];
|
|
27828
27854
|
function workflowsDirectory(scope, repoRoot6 = process.cwd(), userConfigDir) {
|
|
27829
27855
|
if (scope === "global") {
|
|
27830
|
-
return
|
|
27856
|
+
return join17(userConfigDirectory(userConfigDir), "workflows");
|
|
27831
27857
|
}
|
|
27832
|
-
return
|
|
27858
|
+
return join17(repoConfigDirectory(repoRoot6), "workflows");
|
|
27833
27859
|
}
|
|
27834
27860
|
function ensureWorkflowsDirectory(scope, repoRoot6 = process.cwd(), userConfigDir) {
|
|
27835
27861
|
const dir = workflowsDirectory(scope, repoRoot6, userConfigDir);
|
|
@@ -27841,7 +27867,7 @@ function ensureWorkflowsDirectory(scope, repoRoot6 = process.cwd(), userConfigDi
|
|
|
27841
27867
|
function parseWorkflowFile(filePath) {
|
|
27842
27868
|
if (!existsSync15(filePath)) return void 0;
|
|
27843
27869
|
try {
|
|
27844
|
-
const raw =
|
|
27870
|
+
const raw = readFileSync16(filePath, "utf8");
|
|
27845
27871
|
const parsed = (0, import_yaml9.parse)(raw);
|
|
27846
27872
|
if (!parsed || typeof parsed !== "object") return void 0;
|
|
27847
27873
|
return parsed;
|
|
@@ -27858,7 +27884,7 @@ function listWorkflowDefinitions(options = {}) {
|
|
|
27858
27884
|
if (scopeFilter !== "global" && existsSync15(localDir)) {
|
|
27859
27885
|
for (const entry of readdirSync5(localDir)) {
|
|
27860
27886
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
27861
|
-
const filePath =
|
|
27887
|
+
const filePath = join17(localDir, entry);
|
|
27862
27888
|
const def = parseWorkflowFile(filePath);
|
|
27863
27889
|
if (def) {
|
|
27864
27890
|
const id = def.id || entry.replace(/\.ya?ml$/i, "");
|
|
@@ -27871,7 +27897,7 @@ function listWorkflowDefinitions(options = {}) {
|
|
|
27871
27897
|
if (scopeFilter !== "local" && existsSync15(globalDir)) {
|
|
27872
27898
|
for (const entry of readdirSync5(globalDir)) {
|
|
27873
27899
|
if (entry.endsWith(".yaml") || entry.endsWith(".yml")) {
|
|
27874
|
-
const filePath =
|
|
27900
|
+
const filePath = join17(globalDir, entry);
|
|
27875
27901
|
const def = parseWorkflowFile(filePath);
|
|
27876
27902
|
if (def) {
|
|
27877
27903
|
const id = def.id || entry.replace(/\.ya?ml$/i, "");
|
|
@@ -27927,13 +27953,13 @@ function getWorkflowDefinition(workflowId, options = {}) {
|
|
|
27927
27953
|
const repoRoot6 = options.repoRoot ?? process.cwd();
|
|
27928
27954
|
if (scope !== "global") {
|
|
27929
27955
|
const localDir = workflowsDirectory("local", repoRoot6, options.userConfigDir);
|
|
27930
|
-
const localFile =
|
|
27956
|
+
const localFile = join17(localDir, `${workflowId}.yaml`);
|
|
27931
27957
|
const parsed = parseWorkflowFile(localFile);
|
|
27932
27958
|
if (parsed) return { workflow: parsed, scope: "local", filePath: localFile };
|
|
27933
27959
|
}
|
|
27934
27960
|
if (scope !== "local") {
|
|
27935
27961
|
const globalDir = workflowsDirectory("global", repoRoot6, options.userConfigDir);
|
|
27936
|
-
const globalFile =
|
|
27962
|
+
const globalFile = join17(globalDir, `${workflowId}.yaml`);
|
|
27937
27963
|
const parsed = parseWorkflowFile(globalFile);
|
|
27938
27964
|
if (parsed) return { workflow: parsed, scope: "global", filePath: globalFile };
|
|
27939
27965
|
}
|
|
@@ -27943,7 +27969,7 @@ function addWorkflowDefinition(workflowId, content = DEFAULT_WORKFLOW_TEMPLATE,
|
|
|
27943
27969
|
const scope = options.scope ?? "local";
|
|
27944
27970
|
const repoRoot6 = options.repoRoot ?? process.cwd();
|
|
27945
27971
|
const dir = ensureWorkflowsDirectory(scope, repoRoot6, options.userConfigDir);
|
|
27946
|
-
const filePath =
|
|
27972
|
+
const filePath = join17(dir, `${workflowId}.yaml`);
|
|
27947
27973
|
if (existsSync15(filePath) && !options.overwrite) {
|
|
27948
27974
|
throw new Error(`workflow_already_exists: workflow '${workflowId}' already exists at ${filePath}`);
|
|
27949
27975
|
}
|
|
@@ -27955,7 +27981,7 @@ function removeWorkflowDefinition(workflowId, options = {}) {
|
|
|
27955
27981
|
const scope = options.scope ?? "local";
|
|
27956
27982
|
const repoRoot6 = options.repoRoot ?? process.cwd();
|
|
27957
27983
|
const dir = workflowsDirectory(scope, repoRoot6, options.userConfigDir);
|
|
27958
|
-
const filePath =
|
|
27984
|
+
const filePath = join17(dir, `${workflowId}.yaml`);
|
|
27959
27985
|
if (!existsSync15(filePath)) {
|
|
27960
27986
|
throw new Error(`workflow_not_found: workflow '${workflowId}' not found in ${scope} directory (${filePath})`);
|
|
27961
27987
|
}
|
|
@@ -27974,7 +28000,7 @@ function modifyWorkflowDefinition(workflowId, updates, options = {}) {
|
|
|
27974
28000
|
const scope = options.scope ?? target.scope;
|
|
27975
28001
|
const repoRoot6 = options.repoRoot ?? process.cwd();
|
|
27976
28002
|
const dir = ensureWorkflowsDirectory(scope, repoRoot6, options.userConfigDir);
|
|
27977
|
-
const filePath =
|
|
28003
|
+
const filePath = join17(dir, `${workflowId}.yaml`);
|
|
27978
28004
|
writeFileSync12(filePath, (0, import_yaml9.stringify)(updated), "utf8");
|
|
27979
28005
|
return { id: workflowId, workflow: updated, filePath, scope };
|
|
27980
28006
|
}
|
|
@@ -28059,7 +28085,7 @@ function activeWorkflowDefinition(runtime, definitionId) {
|
|
|
28059
28085
|
let raw;
|
|
28060
28086
|
if (file) {
|
|
28061
28087
|
try {
|
|
28062
|
-
raw =
|
|
28088
|
+
raw = readFileSync17(resolve15(runtime.cwd, file), "utf8");
|
|
28063
28089
|
} catch {
|
|
28064
28090
|
throw new Error("workflow definition file is unavailable");
|
|
28065
28091
|
}
|
|
@@ -28141,7 +28167,7 @@ async function cmdWorkflowAdd(runtime, workflowId, options) {
|
|
|
28141
28167
|
}
|
|
28142
28168
|
if (options.file) {
|
|
28143
28169
|
const filePath = resolve15(runtime.cwd, options.file);
|
|
28144
|
-
content =
|
|
28170
|
+
content = readFileSync17(filePath, "utf8");
|
|
28145
28171
|
} else if (!content) {
|
|
28146
28172
|
content = {
|
|
28147
28173
|
schema: "kxm.workflow.v1",
|
|
@@ -28299,7 +28325,7 @@ async function cmdWorkflowStart(runtime, definitionIdArg, options) {
|
|
|
28299
28325
|
}
|
|
28300
28326
|
let payload;
|
|
28301
28327
|
try {
|
|
28302
|
-
const raw = payloadFlag.startsWith("@") ?
|
|
28328
|
+
const raw = payloadFlag.startsWith("@") ? readFileSync17(resolve15(runtime.cwd, payloadFlag.slice(1)), "utf8") : payloadFlag;
|
|
28303
28329
|
const value = JSON.parse(raw);
|
|
28304
28330
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("object required");
|
|
28305
28331
|
payload = value;
|
|
@@ -28366,7 +28392,7 @@ async function cmdWorkflowDegrade(runtime, runId, stageId, options) {
|
|
|
28366
28392
|
}
|
|
28367
28393
|
}
|
|
28368
28394
|
async function cmdWorkflowInspect(runtime, action, runId) {
|
|
28369
|
-
const dataPath = resolve15(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() ||
|
|
28395
|
+
const dataPath = resolve15(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join18(runtime.dirs.state, "kxm.db"));
|
|
28370
28396
|
if (action === "get" && !runId) {
|
|
28371
28397
|
runtime.io.stderr(`Usage: ${CLI_NAME} workflow get <runId>
|
|
28372
28398
|
`);
|
|
@@ -28540,9 +28566,9 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28540
28566
|
try {
|
|
28541
28567
|
if (snapshotPath) {
|
|
28542
28568
|
if (!existsSync16(snapshotPath)) throw new Error("snapshot_missing");
|
|
28543
|
-
snapshot = JSON.parse(
|
|
28569
|
+
snapshot = JSON.parse(readFileSync17(snapshotPath, "utf8"));
|
|
28544
28570
|
} else {
|
|
28545
|
-
const dataPath = resolve15(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() ||
|
|
28571
|
+
const dataPath = resolve15(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join18(runtime.dirs.state, "kxm.db"));
|
|
28546
28572
|
const local = localWorkflowSnapshot(dataPath, runId);
|
|
28547
28573
|
if (!local.runs[0]) throw new Error("workflow_not_found");
|
|
28548
28574
|
snapshot = { run: local.runs[0], journal: local.journal };
|
|
@@ -28554,7 +28580,7 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28554
28580
|
return 1;
|
|
28555
28581
|
}
|
|
28556
28582
|
const doc = buildRetrospective(snapshot.run, snapshot.journal);
|
|
28557
|
-
const outDir = resolve15(runtime.cwd, String(options.outDir ||
|
|
28583
|
+
const outDir = resolve15(runtime.cwd, String(options.outDir || join18(runtime.dirs.assets, "retrospectives")));
|
|
28558
28584
|
const assetsRoot = resolve15(runtime.dirs.assets);
|
|
28559
28585
|
const assetsPrefix = `${assetsRoot}${process.platform === "win32" ? "\\" : "/"}`;
|
|
28560
28586
|
if (outDir !== assetsRoot && !outDir.startsWith(assetsPrefix)) {
|
|
@@ -28572,8 +28598,8 @@ async function cmdRetrospectiveExport(runtime, runId, options) {
|
|
|
28572
28598
|
|
|
28573
28599
|
// plugins/kxm/src/cli/tasks.ts
|
|
28574
28600
|
var import_yaml13 = __toESM(require_dist(), 1);
|
|
28575
|
-
import { existsSync as existsSync22, readFileSync as
|
|
28576
|
-
import { basename as
|
|
28601
|
+
import { existsSync as existsSync22, readFileSync as readFileSync22, readdirSync as readdirSync8 } from "node:fs";
|
|
28602
|
+
import { basename as basename6, join as join26, resolve as resolve21 } from "node:path";
|
|
28577
28603
|
|
|
28578
28604
|
// plugins/kxm/src/suggest.ts
|
|
28579
28605
|
var WORKFLOW_PATTERNS = [
|
|
@@ -28684,8 +28710,8 @@ function suggestWorkflowAndRoles(prompt, options = {}) {
|
|
|
28684
28710
|
// plugins/kxm/src/task-manager.ts
|
|
28685
28711
|
var import_yaml10 = __toESM(require_dist(), 1);
|
|
28686
28712
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
28687
|
-
import { existsSync as existsSync17, mkdirSync as mkdirSync14, readFileSync as
|
|
28688
|
-
import { join as
|
|
28713
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync14, readFileSync as readFileSync18, readdirSync as readdirSync6, writeFileSync as writeFileSync13 } from "node:fs";
|
|
28714
|
+
import { join as join19, resolve as resolve16 } from "node:path";
|
|
28689
28715
|
var GOAL_SCHEMA = "kxm.goal.v1";
|
|
28690
28716
|
var TASK_SCHEMA = "kxm.task.v1";
|
|
28691
28717
|
function goalsDirectory(repoRoot6) {
|
|
@@ -28710,7 +28736,7 @@ function createGoal(repoRoot6, input) {
|
|
|
28710
28736
|
createdAt: now,
|
|
28711
28737
|
updatedAt: now
|
|
28712
28738
|
};
|
|
28713
|
-
const filePath =
|
|
28739
|
+
const filePath = join19(dir, `${id}.yaml`);
|
|
28714
28740
|
writeFileSync13(filePath, (0, import_yaml10.stringify)(record).trim() + "\n", "utf8");
|
|
28715
28741
|
return record;
|
|
28716
28742
|
}
|
|
@@ -28722,7 +28748,7 @@ function listGoals(repoRoot6) {
|
|
|
28722
28748
|
for (const entry of entries) {
|
|
28723
28749
|
if (entry.isFile() && (entry.name.endsWith(".yaml") || entry.name.endsWith(".yml"))) {
|
|
28724
28750
|
try {
|
|
28725
|
-
const text =
|
|
28751
|
+
const text = readFileSync18(join19(dir, entry.name), "utf8");
|
|
28726
28752
|
const doc = (0, import_yaml10.parse)(text);
|
|
28727
28753
|
if (doc && doc.schema === GOAL_SCHEMA) goals.push(doc);
|
|
28728
28754
|
} catch {
|
|
@@ -28755,7 +28781,7 @@ function createTask(repoRoot6, input) {
|
|
|
28755
28781
|
createdAt: now,
|
|
28756
28782
|
updatedAt: now
|
|
28757
28783
|
};
|
|
28758
|
-
const filePath =
|
|
28784
|
+
const filePath = join19(dir, `${id}.yaml`);
|
|
28759
28785
|
writeFileSync13(filePath, (0, import_yaml10.stringify)(record).trim() + "\n", "utf8");
|
|
28760
28786
|
return record;
|
|
28761
28787
|
}
|
|
@@ -28767,7 +28793,7 @@ function listTasks(repoRoot6, options = {}) {
|
|
|
28767
28793
|
for (const entry of entries) {
|
|
28768
28794
|
if (entry.isFile() && (entry.name.endsWith(".yaml") || entry.name.endsWith(".yml"))) {
|
|
28769
28795
|
try {
|
|
28770
|
-
const text =
|
|
28796
|
+
const text = readFileSync18(join19(dir, entry.name), "utf8");
|
|
28771
28797
|
const doc = (0, import_yaml10.parse)(text);
|
|
28772
28798
|
if (doc && doc.schema === TASK_SCHEMA) {
|
|
28773
28799
|
if (options.goalId && doc.goalId !== options.goalId) continue;
|
|
@@ -28782,10 +28808,10 @@ function listTasks(repoRoot6, options = {}) {
|
|
|
28782
28808
|
}
|
|
28783
28809
|
function getTask(repoRoot6, taskId) {
|
|
28784
28810
|
const dir = tasksDirectory(repoRoot6);
|
|
28785
|
-
const filePath =
|
|
28811
|
+
const filePath = join19(dir, `${taskId}.yaml`);
|
|
28786
28812
|
if (!existsSync17(filePath)) return void 0;
|
|
28787
28813
|
try {
|
|
28788
|
-
const text =
|
|
28814
|
+
const text = readFileSync18(filePath, "utf8");
|
|
28789
28815
|
const doc = (0, import_yaml10.parse)(text);
|
|
28790
28816
|
return doc && doc.schema === TASK_SCHEMA ? doc : void 0;
|
|
28791
28817
|
} catch {
|
|
@@ -28800,7 +28826,7 @@ function updateTaskStatus(repoRoot6, taskId, status, options = {}) {
|
|
|
28800
28826
|
task.status = status;
|
|
28801
28827
|
if (options.workflowRunId) task.workflowRunId = options.workflowRunId;
|
|
28802
28828
|
task.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
28803
|
-
const filePath =
|
|
28829
|
+
const filePath = join19(tasksDirectory(repoRoot6), `${taskId}.yaml`);
|
|
28804
28830
|
writeFileSync13(filePath, (0, import_yaml10.stringify)(task).trim() + "\n", "utf8");
|
|
28805
28831
|
return task;
|
|
28806
28832
|
}
|
|
@@ -28816,7 +28842,7 @@ function syncTaskWithTracker(repoRoot6, taskId, options = {}) {
|
|
|
28816
28842
|
task.trackerSync.syncStatus = "synced";
|
|
28817
28843
|
task.trackerSync.lastSyncedAt = now;
|
|
28818
28844
|
task.updatedAt = now;
|
|
28819
|
-
const filePath =
|
|
28845
|
+
const filePath = join19(tasksDirectory(repoRoot6), `${taskId}.yaml`);
|
|
28820
28846
|
writeFileSync13(filePath, (0, import_yaml10.stringify)(task).trim() + "\n", "utf8");
|
|
28821
28847
|
return task;
|
|
28822
28848
|
}
|
|
@@ -29583,14 +29609,14 @@ function createStudioServer(options = {}) {
|
|
|
29583
29609
|
}
|
|
29584
29610
|
|
|
29585
29611
|
// plugins/kxm/src/cli/vnext.ts
|
|
29586
|
-
import { join as
|
|
29612
|
+
import { join as join25, resolve as resolve20 } from "node:path";
|
|
29587
29613
|
import { createInterface as createInterface2 } from "node:readline";
|
|
29588
29614
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
29589
29615
|
|
|
29590
29616
|
// plugins/kxm/src/model-inventory.ts
|
|
29591
29617
|
var import_yaml11 = __toESM(require_dist(), 1);
|
|
29592
29618
|
import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync14 } from "node:fs";
|
|
29593
|
-
import { join as
|
|
29619
|
+
import { join as join20 } from "node:path";
|
|
29594
29620
|
var OR_URL = "https://openrouter.ai/api/v1/models";
|
|
29595
29621
|
var NOUS_URL = "https://inference-api.nousresearch.com/v1/models";
|
|
29596
29622
|
function price(value) {
|
|
@@ -29676,15 +29702,15 @@ async function refreshModelInventory(options) {
|
|
|
29676
29702
|
sources.nous = { url: nousUrl, ok: !nous.error, ...nous.error ? { error: nous.error } : {} };
|
|
29677
29703
|
for (const item of nous.data) add(item, "nous", "discount");
|
|
29678
29704
|
const inventory = { schema: "kxm.model-inventory.v1", fetchedAt, currency: "USD", sources, models: [...byId.values()].sort((a, b2) => a.id.localeCompare(b2.id)) };
|
|
29679
|
-
mkdirSync15(
|
|
29680
|
-
writeFileSync14(
|
|
29705
|
+
mkdirSync15(join20(options.outputRoot, ".kxm", "models"), { recursive: true });
|
|
29706
|
+
writeFileSync14(join20(options.outputRoot, ".kxm", "models", "inventory.yaml"), (0, import_yaml11.stringify)(inventory), "utf8");
|
|
29681
29707
|
return inventory;
|
|
29682
29708
|
}
|
|
29683
29709
|
|
|
29684
29710
|
// plugins/kxm/src/vnext-init.ts
|
|
29685
29711
|
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
29686
29712
|
import { existsSync as existsSync20 } from "node:fs";
|
|
29687
|
-
import { basename as
|
|
29713
|
+
import { basename as basename5, join as join23 } from "node:path";
|
|
29688
29714
|
|
|
29689
29715
|
// plugins/kxm/src/vnext-repair.ts
|
|
29690
29716
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
@@ -29697,20 +29723,20 @@ import {
|
|
|
29697
29723
|
lstatSync as lstatSync7,
|
|
29698
29724
|
mkdirSync as mkdirSync17,
|
|
29699
29725
|
openSync as openSync2,
|
|
29700
|
-
readFileSync as
|
|
29726
|
+
readFileSync as readFileSync20,
|
|
29701
29727
|
readdirSync as readdirSync7,
|
|
29702
29728
|
renameSync as renameSync5,
|
|
29703
29729
|
rmSync as rmSync7,
|
|
29704
29730
|
writeFileSync as writeFileSync16
|
|
29705
29731
|
} from "node:fs";
|
|
29706
|
-
import { dirname as dirname13, isAbsolute as isAbsolute6, join as
|
|
29732
|
+
import { dirname as dirname13, isAbsolute as isAbsolute6, join as join22, relative as relative4, resolve as resolve18 } from "node:path";
|
|
29707
29733
|
|
|
29708
29734
|
// plugins/kxm/src/vnext-permission.ts
|
|
29709
29735
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
29710
29736
|
import { createHash as createHash12 } from "node:crypto";
|
|
29711
|
-
import { existsSync as existsSync18, mkdtempSync, mkdirSync as mkdirSync16, readFileSync as
|
|
29737
|
+
import { existsSync as existsSync18, mkdtempSync, mkdirSync as mkdirSync16, readFileSync as readFileSync19, rmSync as rmSync6, writeFileSync as writeFileSync15 } from "node:fs";
|
|
29712
29738
|
import { tmpdir } from "node:os";
|
|
29713
|
-
import { dirname as dirname12, join as
|
|
29739
|
+
import { dirname as dirname12, join as join21, resolve as resolve17, sep as sep3 } from "node:path";
|
|
29714
29740
|
var PROSE_FIELDS = {
|
|
29715
29741
|
project: /* @__PURE__ */ new Set(["name", "description"]),
|
|
29716
29742
|
repository: /* @__PURE__ */ new Set(["description"]),
|
|
@@ -30231,7 +30257,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30231
30257
|
const tree = resolveTreeRevision(root, revision);
|
|
30232
30258
|
const listing = gitBuffer(root, ["ls-tree", "-r", "-z", "--name-only", tree]).toString("utf8");
|
|
30233
30259
|
const paths = listing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
30234
|
-
const shadow = mkdtempSync(
|
|
30260
|
+
const shadow = mkdtempSync(join21(tmpdir(), "kxm-permission-base-"));
|
|
30235
30261
|
const shadowResolved = resolve17(shadow);
|
|
30236
30262
|
const shadowMembersDir = `.kxm-shadow-members-${createHash12("sha256").update(shadowResolved, "utf8").digest("hex").slice(0, 8)}`;
|
|
30237
30263
|
try {
|
|
@@ -30245,7 +30271,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30245
30271
|
message: "Git tree entry contains a traversal or non-portable segment"
|
|
30246
30272
|
}]);
|
|
30247
30273
|
}
|
|
30248
|
-
const absolute =
|
|
30274
|
+
const absolute = join21(shadowResolved, ...segments);
|
|
30249
30275
|
const resolved = resolve17(absolute);
|
|
30250
30276
|
if (!resolved.startsWith(`${shadowResolved}${sep3}`)) {
|
|
30251
30277
|
throw new VnextConfigError([{
|
|
@@ -30260,7 +30286,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30260
30286
|
writeFileSync15(absolute, content);
|
|
30261
30287
|
}
|
|
30262
30288
|
initShadowGitRoot(shadowResolved);
|
|
30263
|
-
const baseProjectFile =
|
|
30289
|
+
const baseProjectFile = join21(shadowResolved, ".kxm", "project.yaml");
|
|
30264
30290
|
let baseProject;
|
|
30265
30291
|
try {
|
|
30266
30292
|
baseProject = loadBaseProjectDeclarations(baseProjectFile);
|
|
@@ -30338,7 +30364,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30338
30364
|
const memberTree = git(memberWorktree, ["rev-parse", "--verify", "--quiet", `${pinnedCommit}^{tree}`]).trim();
|
|
30339
30365
|
const memberListing = gitBuffer(memberWorktree, ["ls-tree", "-r", "-z", "--name-only", memberTree]).toString("utf8");
|
|
30340
30366
|
const memberPaths = memberListing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
30341
|
-
const memberShadowRoot =
|
|
30367
|
+
const memberShadowRoot = join21(shadowResolved, shadowMembersDir, member.repositoryId);
|
|
30342
30368
|
if (!resolve17(memberShadowRoot).startsWith(`${resolve17(shadowResolved, shadowMembersDir)}${sep3}`)) {
|
|
30343
30369
|
throw new VnextConfigError([{
|
|
30344
30370
|
phase: "path",
|
|
@@ -30352,7 +30378,7 @@ function loadVnextProjectAtRevision(root, revision, options = {}) {
|
|
|
30352
30378
|
if (segments.some((segment) => segment === "" || segment === "." || segment === ".." || /[\\:]/.test(segment))) {
|
|
30353
30379
|
throw new VnextConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path4, message: "member Git tree entry contains a traversal or non-portable segment" }]);
|
|
30354
30380
|
}
|
|
30355
|
-
const absolute =
|
|
30381
|
+
const absolute = join21(memberShadowRoot, ...segments);
|
|
30356
30382
|
const resolved = resolve17(absolute);
|
|
30357
30383
|
if (!resolved.startsWith(`${resolve17(memberShadowRoot)}${sep3}`)) {
|
|
30358
30384
|
throw new VnextConfigError([{ phase: "path", code: "git_tree_path_invalid", file: path4, message: "member Git tree entry escapes the shadow root" }]);
|
|
@@ -30381,7 +30407,7 @@ function portableMemberPathHint(pathHint) {
|
|
|
30381
30407
|
}
|
|
30382
30408
|
function loadBaseProjectDeclarations(projectFile) {
|
|
30383
30409
|
if (!existsSync18(projectFile)) return [];
|
|
30384
|
-
const value = parseRestrictedYaml2(
|
|
30410
|
+
const value = parseRestrictedYaml2(readFileSync19(projectFile, "utf8"), ".kxm/project.yaml");
|
|
30385
30411
|
const repositories = Array.isArray(value?.repositories) ? value.repositories : [];
|
|
30386
30412
|
const members = [];
|
|
30387
30413
|
for (const entry of repositories) {
|
|
@@ -30509,19 +30535,19 @@ function sameHostPath3(left, right) {
|
|
|
30509
30535
|
return process.platform === "win32" ? first.toLocaleLowerCase("en-US") === second.toLocaleLowerCase("en-US") : first === second;
|
|
30510
30536
|
}
|
|
30511
30537
|
function transactionRoot(projectRoot) {
|
|
30512
|
-
return
|
|
30538
|
+
return join22(resolve18(projectRoot), TRANSACTION_NAME);
|
|
30513
30539
|
}
|
|
30514
30540
|
function operationFile(projectRoot) {
|
|
30515
|
-
return
|
|
30541
|
+
return join22(transactionRoot(projectRoot), OPERATION_FILE);
|
|
30516
30542
|
}
|
|
30517
30543
|
function targetFile(projectRoot, portablePath2) {
|
|
30518
|
-
return
|
|
30544
|
+
return join22(transactionRoot(projectRoot), "targets", ...portablePath2.split("/"));
|
|
30519
30545
|
}
|
|
30520
30546
|
function shadowRoot(projectRoot) {
|
|
30521
|
-
return
|
|
30547
|
+
return join22(transactionRoot(projectRoot), "shadow");
|
|
30522
30548
|
}
|
|
30523
30549
|
function backupFile(projectRoot, portablePath2) {
|
|
30524
|
-
return
|
|
30550
|
+
return join22(transactionRoot(projectRoot), "backups", ...portablePath2.split("/"));
|
|
30525
30551
|
}
|
|
30526
30552
|
function portableManagedPath(path4) {
|
|
30527
30553
|
return path4.startsWith(".kxm/") && path4 !== VNEXT_TEMPLATE_PROVENANCE_PATH && path4.length <= 1024 && !path4.includes("\\") && !isAbsolute6(path4) && PORTABLE_PATH.test(path4) && !/[<>:"|?*]/.test(path4);
|
|
@@ -30530,10 +30556,10 @@ function readRegularBounded(file, label) {
|
|
|
30530
30556
|
const stat = lstatSync7(file);
|
|
30531
30557
|
if (stat.isSymbolicLink() || !stat.isFile()) fail3("repair_file_invalid", label, "managed file must be a regular file, not a link or directory", "path");
|
|
30532
30558
|
if (stat.size > MAX_MANAGED_FILE_BYTES) fail3("repair_file_too_large", label, `managed file exceeds ${MAX_MANAGED_FILE_BYTES} bytes`, "parse");
|
|
30533
|
-
return
|
|
30559
|
+
return readFileSync20(file);
|
|
30534
30560
|
}
|
|
30535
30561
|
function readOptionalManaged(projectRoot, path4) {
|
|
30536
|
-
const file =
|
|
30562
|
+
const file = join22(projectRoot, ...path4.split("/"));
|
|
30537
30563
|
if (!existsSync19(file)) return void 0;
|
|
30538
30564
|
let parent = dirname13(file);
|
|
30539
30565
|
const boundary = resolve18(projectRoot);
|
|
@@ -30545,8 +30571,8 @@ function readOptionalManaged(projectRoot, path4) {
|
|
|
30545
30571
|
return readRegularBounded(file, path4);
|
|
30546
30572
|
}
|
|
30547
30573
|
function readProjectAndProvenance(projectRoot, schemasDir) {
|
|
30548
|
-
const projectFile =
|
|
30549
|
-
const provenanceFile =
|
|
30574
|
+
const projectFile = join22(projectRoot, ".kxm", "project.yaml");
|
|
30575
|
+
const provenanceFile = join22(projectRoot, ...VNEXT_TEMPLATE_PROVENANCE_PATH.split("/"));
|
|
30550
30576
|
if (!existsSync19(projectFile) || !existsSync19(provenanceFile)) return void 0;
|
|
30551
30577
|
const projectBytes = readOptionalManaged(projectRoot, ".kxm/project.yaml");
|
|
30552
30578
|
const provenanceBytes = readOptionalManaged(projectRoot, VNEXT_TEMPLATE_PROVENANCE_PATH);
|
|
@@ -30711,7 +30737,7 @@ function operationPlanSha(operation) {
|
|
|
30711
30737
|
function writeOperation(projectRoot, operation) {
|
|
30712
30738
|
const root = transactionRoot(projectRoot);
|
|
30713
30739
|
const file = operationFile(projectRoot);
|
|
30714
|
-
const temporary =
|
|
30740
|
+
const temporary = join22(root, `.operation-${operation.operationId}-${randomUUID10()}.tmp`);
|
|
30715
30741
|
try {
|
|
30716
30742
|
writeDurableNew(temporary, Buffer.from(`${JSON.stringify(operation, null, 2)}
|
|
30717
30743
|
`, "utf8"), 384);
|
|
@@ -30763,7 +30789,7 @@ function hasVnextInitTransaction(projectRoot) {
|
|
|
30763
30789
|
return existsSync19(transactionRoot(projectRoot));
|
|
30764
30790
|
}
|
|
30765
30791
|
function readTarget(projectRoot, path4) {
|
|
30766
|
-
return readOptionalManaged(
|
|
30792
|
+
return readOptionalManaged(join22(transactionRoot(projectRoot), "targets"), path4);
|
|
30767
30793
|
}
|
|
30768
30794
|
function writeTarget(projectRoot, path4, bytes) {
|
|
30769
30795
|
if (bytes.byteLength > MAX_MANAGED_FILE_BYTES) fail3("template_target_too_large", path4, `target exceeds ${MAX_MANAGED_FILE_BYTES} bytes`);
|
|
@@ -30803,7 +30829,7 @@ function verifyBackups(projectRoot, operation) {
|
|
|
30803
30829
|
if (operation.kind !== "repair") return;
|
|
30804
30830
|
for (const entry of operation.files) {
|
|
30805
30831
|
if (entry.observedSha256 === null) continue;
|
|
30806
|
-
const bytes = readOptionalManaged(
|
|
30832
|
+
const bytes = readOptionalManaged(join22(transactionRoot(projectRoot), "backups"), entry.path);
|
|
30807
30833
|
if (!bytes || vnextContentSha256(bytes) !== entry.observedSha256) {
|
|
30808
30834
|
fail3("init_transaction_backup_invalid", entry.path, "pinned preimage backup is missing or corrupt");
|
|
30809
30835
|
}
|
|
@@ -30837,9 +30863,9 @@ function sourceConfigFiles(projectRoot) {
|
|
|
30837
30863
|
".kxm/repo/repo.yaml",
|
|
30838
30864
|
".kxm/repo/env.yaml"
|
|
30839
30865
|
];
|
|
30840
|
-
const files = fixed.filter((path4) => existsSync19(
|
|
30866
|
+
const files = fixed.filter((path4) => existsSync19(join22(projectRoot, ...path4.split("/"))));
|
|
30841
30867
|
for (const directory of ["agents", "models", "workflows"]) {
|
|
30842
|
-
const absolute =
|
|
30868
|
+
const absolute = join22(projectRoot, ".kxm", directory);
|
|
30843
30869
|
if (!existsSync19(absolute)) continue;
|
|
30844
30870
|
const stat = lstatSync7(absolute);
|
|
30845
30871
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_directory_invalid", `.kxm/${directory}`, "configuration directory must be regular", "path");
|
|
@@ -30876,8 +30902,8 @@ function prepareShadow(projectRoot, operation, options) {
|
|
|
30876
30902
|
const bytes = readOptionalManaged(projectRoot, path4);
|
|
30877
30903
|
if (!bytes) fail3("repair_snapshot_file_missing", path4, "configuration changed during shadow preparation");
|
|
30878
30904
|
total += bytes.byteLength;
|
|
30879
|
-
const source =
|
|
30880
|
-
const destination =
|
|
30905
|
+
const source = join22(projectRoot, ...path4.split("/"));
|
|
30906
|
+
const destination = join22(shadow, ...path4.split("/"));
|
|
30881
30907
|
mkdirSync17(dirname13(destination), { recursive: true, mode: 448 });
|
|
30882
30908
|
writeDurableNew(destination, bytes, lstatSync7(source).mode & 511);
|
|
30883
30909
|
if (total > MAX_MANAGED_TOTAL_BYTES) fail3("repair_snapshot_too_large", ".kxm", `configuration snapshot exceeds ${MAX_MANAGED_TOTAL_BYTES} bytes`, "parse");
|
|
@@ -30886,12 +30912,12 @@ function prepareShadow(projectRoot, operation, options) {
|
|
|
30886
30912
|
for (const entry of operation.files) {
|
|
30887
30913
|
const bytes = readTarget(projectRoot, entry.path);
|
|
30888
30914
|
if (!bytes) fail3("init_transaction_target_missing", entry.path, "pinned target artifact is missing");
|
|
30889
|
-
const destination =
|
|
30915
|
+
const destination = join22(shadow, ...entry.path.split("/"));
|
|
30890
30916
|
mkdirSync17(dirname13(destination), { recursive: true, mode: 448 });
|
|
30891
30917
|
const mode = existsSync19(destination) ? lstatSync7(destination).mode & 511 : 420;
|
|
30892
30918
|
writeDurable(destination, bytes, mode);
|
|
30893
30919
|
}
|
|
30894
|
-
const project = parseRestrictedYaml2(
|
|
30920
|
+
const project = parseRestrictedYaml2(readFileSync20(join22(shadow, ".kxm", "project.yaml")), ".kxm/project.yaml");
|
|
30895
30921
|
const bound = absoluteMemberBindings(projectRoot, project, options.repositoryBindings);
|
|
30896
30922
|
loadVnextProject(shadow, { ...loaderOptions(options), repositoryBindings: bound });
|
|
30897
30923
|
const provenance = readProjectAndProvenance(shadow, options.schemasDir)?.provenance;
|
|
@@ -30955,21 +30981,21 @@ function ensureDestinationParents(projectRoot, path4) {
|
|
|
30955
30981
|
const segments = path4.split("/").slice(0, -1);
|
|
30956
30982
|
let current = boundary;
|
|
30957
30983
|
for (const segment of segments) {
|
|
30958
|
-
current =
|
|
30984
|
+
current = join22(current, segment);
|
|
30959
30985
|
if (!existsSync19(current)) mkdirSync17(current, { mode: 448 });
|
|
30960
30986
|
const stat = lstatSync7(current);
|
|
30961
30987
|
if (stat.isSymbolicLink() || !stat.isDirectory()) fail3("repair_destination_parent_invalid", path4, "destination parent must be a regular directory", "path");
|
|
30962
30988
|
}
|
|
30963
30989
|
}
|
|
30964
30990
|
function destinationSha(projectRoot, path4) {
|
|
30965
|
-
const file =
|
|
30991
|
+
const file = join22(projectRoot, ...path4.split("/"));
|
|
30966
30992
|
if (!existsSync19(file)) return void 0;
|
|
30967
30993
|
return vnextContentSha256(readRegularBounded(file, path4));
|
|
30968
30994
|
}
|
|
30969
30995
|
function requireConditionalLinkSupport(directory, operationId, path4) {
|
|
30970
30996
|
const nonce = randomUUID10();
|
|
30971
|
-
const source =
|
|
30972
|
-
const target =
|
|
30997
|
+
const source = join22(directory, `.kxm-repair-${operationId}-${nonce}.link-source`);
|
|
30998
|
+
const target = join22(directory, `.kxm-repair-${operationId}-${nonce}.link-target`);
|
|
30973
30999
|
try {
|
|
30974
31000
|
writeDurableNew(source, Buffer.from("kxm-link-probe\n", "utf8"), 384);
|
|
30975
31001
|
try {
|
|
@@ -30984,16 +31010,16 @@ function requireConditionalLinkSupport(directory, operationId, path4) {
|
|
|
30984
31010
|
}
|
|
30985
31011
|
}
|
|
30986
31012
|
function atomicInstallTarget(projectRoot, operation, entry) {
|
|
30987
|
-
const destination =
|
|
31013
|
+
const destination = join22(projectRoot, ...entry.path.split("/"));
|
|
30988
31014
|
ensureDestinationParents(projectRoot, entry.path);
|
|
30989
31015
|
const directory = dirname13(destination);
|
|
30990
31016
|
const temporaryPrefix = `.kxm-repair-${operation.operationId}-`;
|
|
30991
31017
|
const pathKey = vnextContentSha256(entry.path).slice("sha256:".length, "sha256:".length + 16);
|
|
30992
|
-
const displaced =
|
|
31018
|
+
const displaced = join22(directory, `${temporaryPrefix}${pathKey}.preimage`);
|
|
30993
31019
|
if (existsSync19(displaced)) {
|
|
30994
31020
|
const stat = lstatSync7(displaced);
|
|
30995
31021
|
if (stat.isSymbolicLink() || !stat.isFile()) fail3("repair_preimage_temporary_invalid", entry.path, "stale displaced preimage is not a regular file", "path");
|
|
30996
|
-
if (entry.observedSha256 === null || vnextContentSha256(
|
|
31022
|
+
if (entry.observedSha256 === null || vnextContentSha256(readFileSync20(displaced)) !== entry.observedSha256) {
|
|
30997
31023
|
fail3("repair_preimage_temporary_mismatch", entry.path, "stale displaced preimage does not match the pinned operation");
|
|
30998
31024
|
}
|
|
30999
31025
|
if (!existsSync19(destination)) {
|
|
@@ -31011,7 +31037,7 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31011
31037
|
const owned = candidate.name.startsWith(temporaryPrefix) && (candidate.name.endsWith(".tmp") || candidate.name.endsWith(".link-source") || candidate.name.endsWith(".link-target"));
|
|
31012
31038
|
if (!owned) continue;
|
|
31013
31039
|
if (!candidate.isFile()) fail3("repair_temporary_invalid", entry.path, "stale operation temporary is not a regular file", "path");
|
|
31014
|
-
rmSync7(
|
|
31040
|
+
rmSync7(join22(directory, candidate.name), { force: true });
|
|
31015
31041
|
}
|
|
31016
31042
|
const current = destinationSha(projectRoot, entry.path);
|
|
31017
31043
|
if (current === entry.targetSha256) return;
|
|
@@ -31021,14 +31047,14 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31021
31047
|
requireConditionalLinkSupport(directory, operation.operationId, entry.path);
|
|
31022
31048
|
const bytes = readTarget(projectRoot, entry.path);
|
|
31023
31049
|
if (!bytes) fail3("init_transaction_target_missing", entry.path, "pinned target artifact is missing");
|
|
31024
|
-
const temporary =
|
|
31050
|
+
const temporary = join22(directory, `${temporaryPrefix}${randomUUID10()}.tmp`);
|
|
31025
31051
|
const mode = existsSync19(destination) ? lstatSync7(destination).mode & 511 : 420;
|
|
31026
31052
|
try {
|
|
31027
31053
|
writeDurableNew(temporary, bytes, mode);
|
|
31028
31054
|
if (entry.observedSha256 !== null) {
|
|
31029
31055
|
renameSync5(destination, displaced);
|
|
31030
31056
|
syncDirectory2(directory);
|
|
31031
|
-
if (vnextContentSha256(
|
|
31057
|
+
if (vnextContentSha256(readFileSync20(displaced)) !== entry.observedSha256) {
|
|
31032
31058
|
if (!existsSync19(destination)) {
|
|
31033
31059
|
try {
|
|
31034
31060
|
linkSync(displaced, destination);
|
|
@@ -31067,12 +31093,12 @@ function atomicInstallTarget(projectRoot, operation, entry) {
|
|
|
31067
31093
|
if (destinationSha(projectRoot, entry.path) !== entry.targetSha256) fail3("repair_install_verification_failed", entry.path, "installed target hash does not match the pinned operation");
|
|
31068
31094
|
}
|
|
31069
31095
|
function installedCreateMatches(projectRoot, operation) {
|
|
31070
|
-
const configRoot =
|
|
31096
|
+
const configRoot = join22(projectRoot, ".kxm");
|
|
31071
31097
|
if (!existsSync19(configRoot)) return false;
|
|
31072
31098
|
const actual = [];
|
|
31073
31099
|
const visit2 = (directory) => {
|
|
31074
31100
|
for (const entry of readdirSync7(directory, { withFileTypes: true })) {
|
|
31075
|
-
const absolute =
|
|
31101
|
+
const absolute = join22(directory, entry.name);
|
|
31076
31102
|
if (entry.isSymbolicLink()) fail3("create_resume_link", relativeConfigPath(projectRoot, absolute), "created configuration must not contain links", "path");
|
|
31077
31103
|
if (entry.isDirectory()) visit2(absolute);
|
|
31078
31104
|
else if (entry.isFile()) actual.push(relativeConfigPath(projectRoot, absolute));
|
|
@@ -31093,7 +31119,7 @@ function syncTreeDirectories(root) {
|
|
|
31093
31119
|
const visit2 = (directory) => {
|
|
31094
31120
|
directories.push(directory);
|
|
31095
31121
|
for (const entry of readdirSync7(directory, { withFileTypes: true })) {
|
|
31096
|
-
if (entry.isDirectory()) visit2(
|
|
31122
|
+
if (entry.isDirectory()) visit2(join22(directory, entry.name));
|
|
31097
31123
|
}
|
|
31098
31124
|
};
|
|
31099
31125
|
visit2(root);
|
|
@@ -31107,7 +31133,7 @@ function rebuildCreateShadow(projectRoot, operation, options) {
|
|
|
31107
31133
|
if (stat.isSymbolicLink() || !stat.isDirectory() || !installedCreateMatches(shadow, operation)) {
|
|
31108
31134
|
fail3("create_shadow_invalid", TRANSACTION_NAME, "reconstructed create shadow does not exactly match pinned target files", "path");
|
|
31109
31135
|
}
|
|
31110
|
-
syncTreeDirectories(
|
|
31136
|
+
syncTreeDirectories(join22(shadow, ".kxm"));
|
|
31111
31137
|
}
|
|
31112
31138
|
function applyOperation(projectRoot, original, options, resumed) {
|
|
31113
31139
|
assertNoRegisteredGates(options);
|
|
@@ -31117,10 +31143,10 @@ function applyOperation(projectRoot, original, options, resumed) {
|
|
|
31117
31143
|
verifyBackups(projectRoot, operation);
|
|
31118
31144
|
operation = updatePhase(projectRoot, operation, "applying");
|
|
31119
31145
|
if (operation.kind === "create") {
|
|
31120
|
-
const destination =
|
|
31146
|
+
const destination = join22(projectRoot, ".kxm");
|
|
31121
31147
|
if (!existsSync19(destination)) {
|
|
31122
31148
|
rebuildCreateShadow(projectRoot, operation, effectiveOptions);
|
|
31123
|
-
renameSync5(
|
|
31149
|
+
renameSync5(join22(shadowRoot(projectRoot), ".kxm"), destination);
|
|
31124
31150
|
syncDirectory2(projectRoot);
|
|
31125
31151
|
} else if (!installedCreateMatches(projectRoot, operation)) {
|
|
31126
31152
|
fail3("create_resume_conflict", ".kxm", "existing project configuration does not match the pinned create operation");
|
|
@@ -31147,7 +31173,7 @@ function applyOperation(projectRoot, original, options, resumed) {
|
|
|
31147
31173
|
operation = updatePhase(projectRoot, operation, "verified");
|
|
31148
31174
|
if (options.testFaultAt === "verified") throw new Error("injected init fault after verification");
|
|
31149
31175
|
const files = operation.files.map((entry) => entry.path);
|
|
31150
|
-
syncTreeDirectories(
|
|
31176
|
+
syncTreeDirectories(join22(projectRoot, ".kxm"));
|
|
31151
31177
|
return { kind: operation.kind, resumed, bundle, files };
|
|
31152
31178
|
}
|
|
31153
31179
|
function prepareAndApplyVnextCreate(projectRoot, rendered, options = {}) {
|
|
@@ -31262,7 +31288,7 @@ function finishPreparingOperation(projectRoot, operation, options) {
|
|
|
31262
31288
|
const rendered = rendererForOperation(operation);
|
|
31263
31289
|
if (!rendered) fail3("init_transaction_renderer_unavailable", TRANSACTION_NAME, "this binary cannot reproduce the pinned pre-application target");
|
|
31264
31290
|
for (const directory of ["targets", "backups", "shadow"]) {
|
|
31265
|
-
rmSync7(
|
|
31291
|
+
rmSync7(join22(transactionRoot(projectRoot), directory), { recursive: true, force: true });
|
|
31266
31292
|
}
|
|
31267
31293
|
for (const entry of operation.files) {
|
|
31268
31294
|
const bytes = rendered.files.get(entry.path);
|
|
@@ -31297,7 +31323,7 @@ function commitVnextInitTransaction(projectRoot, schemasDir) {
|
|
|
31297
31323
|
fail3("init_transaction_not_verified", TRANSACTION_NAME, "initialization transaction cannot commit before installed state is verified");
|
|
31298
31324
|
}
|
|
31299
31325
|
const transaction = transactionRoot(projectRoot);
|
|
31300
|
-
const retired =
|
|
31326
|
+
const retired = join22(projectRoot, `${TRANSACTION_NAME}-cleanup-${operation.operationId}-${randomUUID10()}`);
|
|
31301
31327
|
renameSync5(transaction, retired);
|
|
31302
31328
|
syncDirectory2(projectRoot);
|
|
31303
31329
|
rmSync7(retired, { recursive: true, force: true });
|
|
@@ -31318,7 +31344,7 @@ function initIssue(code, file, message) {
|
|
|
31318
31344
|
return { phase: "discovery", code, file, message };
|
|
31319
31345
|
}
|
|
31320
31346
|
function normalizedProjectName(root, requested) {
|
|
31321
|
-
const name = (requested ??
|
|
31347
|
+
const name = (requested ?? basename5(root) ?? "KXM Project").trim();
|
|
31322
31348
|
if (name.length < 1 || name.length > 120 || /[\u0000\r\n]/.test(name)) {
|
|
31323
31349
|
throw new VnextConfigError([initIssue("project_name_invalid", ".kxm/project.yaml", "project name must contain 1-120 characters on one line")]);
|
|
31324
31350
|
}
|
|
@@ -31406,7 +31432,7 @@ function validateBindingIdentities(bundle, persisted, explicit) {
|
|
|
31406
31432
|
}
|
|
31407
31433
|
function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock) {
|
|
31408
31434
|
const storeOptions = bindingStoreOptions(options);
|
|
31409
|
-
const persisted = existsSync20(
|
|
31435
|
+
const persisted = existsSync20(join23(gitRoot, ".kxm", "project.yaml")) ? readVnextLocalBindings(gitRoot, storeOptions) : void 0;
|
|
31410
31436
|
const repositoryBindings = Object.fromEntries([
|
|
31411
31437
|
...Object.entries(persisted?.repositories ?? {}),
|
|
31412
31438
|
...Object.entries(options.repositoryBindings ?? {})
|
|
@@ -31595,7 +31621,7 @@ function initializeVnextProjectAtGitRoot(start, gitRoot, options, mutationLock)
|
|
|
31595
31621
|
const files = [...rendered.files.keys()];
|
|
31596
31622
|
if (options.dryRun) return { action: "planned", plan, projectRoot: gitRoot, files };
|
|
31597
31623
|
if (!mutationLock) throw new Error("project mutation lock is required to create configuration");
|
|
31598
|
-
if (existsSync20(
|
|
31624
|
+
if (existsSync20(join23(gitRoot, ".kxm"))) {
|
|
31599
31625
|
throw new VnextConfigError([initIssue("workspace_changed", ".kxm", "workspace changed after planning; existing .kxm state was not overwritten")]);
|
|
31600
31626
|
}
|
|
31601
31627
|
const created = prepareAndApplyVnextCreate(gitRoot, rendered, transactionOptions);
|
|
@@ -31627,8 +31653,8 @@ function initializeVnextProject(start = process.cwd(), options = {}) {
|
|
|
31627
31653
|
// plugins/kxm/src/vnext-migrate.ts
|
|
31628
31654
|
var import_yaml12 = __toESM(require_dist(), 1);
|
|
31629
31655
|
import { createHash as createHash13 } from "node:crypto";
|
|
31630
|
-
import { chmodSync as chmodSync6, closeSync as closeSync3, existsSync as existsSync21, fsyncSync as fsyncSync3, lstatSync as lstatSync8, mkdirSync as mkdirSync18, openSync as openSync3, readFileSync as
|
|
31631
|
-
import { join as
|
|
31656
|
+
import { chmodSync as chmodSync6, closeSync as closeSync3, existsSync as existsSync21, fsyncSync as fsyncSync3, lstatSync as lstatSync8, mkdirSync as mkdirSync18, openSync as openSync3, readFileSync as readFileSync21, renameSync as renameSync6, rmSync as rmSync8, writeFileSync as writeFileSync17 } from "node:fs";
|
|
31657
|
+
import { join as join24 } from "node:path";
|
|
31632
31658
|
var MAX_LEGACY_JSON_BYTES = 1024 * 1024;
|
|
31633
31659
|
var MAX_LEGACY_JSON_DEPTH = 32;
|
|
31634
31660
|
var MAX_LEGACY_JSON_NODES = 32768;
|
|
@@ -31797,12 +31823,12 @@ function readVnextLegacySources(root) {
|
|
|
31797
31823
|
throw new VnextConfigError([migrateIssue("discovery", "legacy_source_limit", ".kxm/config", `legacy configuration exceeds ${MAX_LEGACY_SOURCES} files`)]);
|
|
31798
31824
|
}
|
|
31799
31825
|
return files.map((path4) => {
|
|
31800
|
-
const absolute =
|
|
31826
|
+
const absolute = join24(root, ...path4.split("/"));
|
|
31801
31827
|
const stat = lstatSync8(absolute);
|
|
31802
31828
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
31803
31829
|
throw new VnextConfigError([migrateIssue("path", "legacy_source_invalid", path4, "legacy configuration must be a regular file, not a link")]);
|
|
31804
31830
|
}
|
|
31805
|
-
const buffer =
|
|
31831
|
+
const buffer = readFileSync21(absolute);
|
|
31806
31832
|
let text;
|
|
31807
31833
|
try {
|
|
31808
31834
|
text = new TextDecoder("utf-8", { fatal: true }).decode(buffer);
|
|
@@ -32879,7 +32905,7 @@ function readVnextMigrationDecisions(path4, schemasDir) {
|
|
|
32879
32905
|
throw new VnextConfigError([migrateIssue("discovery", "decisions_missing", path4, "migration decisions file does not exist")]);
|
|
32880
32906
|
}
|
|
32881
32907
|
const registry = new VnextSchemaRegistry(schemasDir);
|
|
32882
|
-
const value = parseRestrictedYaml2(
|
|
32908
|
+
const value = parseRestrictedYaml2(readFileSync21(path4), path4);
|
|
32883
32909
|
const issues = registry.validateMigrationDecision(value, path4);
|
|
32884
32910
|
if (issues.length > 0) throw new VnextConfigError(issues);
|
|
32885
32911
|
return value;
|
|
@@ -32918,7 +32944,7 @@ function writeDurable2(path4, content) {
|
|
|
32918
32944
|
chmodSync6(path4, 384);
|
|
32919
32945
|
} catch {
|
|
32920
32946
|
}
|
|
32921
|
-
syncDirectory3(
|
|
32947
|
+
syncDirectory3(join24(path4, ".."));
|
|
32922
32948
|
} finally {
|
|
32923
32949
|
if (created && existsSync21(temp)) rmSync8(temp, { force: true });
|
|
32924
32950
|
}
|
|
@@ -32930,7 +32956,7 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
32930
32956
|
...options.schemasDir === void 0 ? {} : { schemasDir: options.schemasDir }
|
|
32931
32957
|
};
|
|
32932
32958
|
const execute = (lock) => {
|
|
32933
|
-
const receiptAbsolute =
|
|
32959
|
+
const receiptAbsolute = join24(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
|
|
32934
32960
|
if (existsSync21(receiptAbsolute)) {
|
|
32935
32961
|
const stat = lstatSync8(receiptAbsolute);
|
|
32936
32962
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
@@ -32984,7 +33010,7 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
32984
33010
|
return { action: "planned", projectRoot: root, files: [], plan: first.plan };
|
|
32985
33011
|
}
|
|
32986
33012
|
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") }));
|
|
32987
|
-
const collisions = files.filter((file) => existsSync21(
|
|
33013
|
+
const collisions = files.filter((file) => existsSync21(join24(root, ...file.path.split("/"))));
|
|
32988
33014
|
if (collisions.length > 0) {
|
|
32989
33015
|
throw new VnextConfigError(collisions.map((file) => migrateIssue("semantic", "migration_target_exists", file.path, "target resource already exists; refusing to overwrite")));
|
|
32990
33016
|
}
|
|
@@ -32993,7 +33019,7 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
32993
33019
|
const segments = file.path.split("/");
|
|
32994
33020
|
let current = root;
|
|
32995
33021
|
for (const segment of segments.slice(0, -1)) {
|
|
32996
|
-
current =
|
|
33022
|
+
current = join24(current, segment);
|
|
32997
33023
|
if (!existsSync21(current)) continue;
|
|
32998
33024
|
const stat = lstatSync8(current);
|
|
32999
33025
|
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
@@ -33010,8 +33036,8 @@ function applyVnextMigration(projectRoot, options = {}) {
|
|
|
33010
33036
|
const written = [];
|
|
33011
33037
|
try {
|
|
33012
33038
|
for (const file of files) {
|
|
33013
|
-
const absolute =
|
|
33014
|
-
mkdirSync18(
|
|
33039
|
+
const absolute = join24(root, ...file.path.split("/"));
|
|
33040
|
+
mkdirSync18(join24(absolute, ".."), { recursive: true });
|
|
33015
33041
|
written.push(absolute);
|
|
33016
33042
|
writeDurable2(absolute, file.bytes);
|
|
33017
33043
|
}
|
|
@@ -33057,7 +33083,7 @@ ${bundle.configRevision}`).slice(7, 39)}`,
|
|
|
33057
33083
|
}
|
|
33058
33084
|
function verifyVnextMigration(projectRoot, options = {}) {
|
|
33059
33085
|
const root = migrationGitRoot(projectRoot);
|
|
33060
|
-
const receiptAbsolute =
|
|
33086
|
+
const receiptAbsolute = join24(root, ...VNEXT_MIGRATION_RECEIPT_PATH.split("/"));
|
|
33061
33087
|
if (!existsSync21(receiptAbsolute)) {
|
|
33062
33088
|
return {
|
|
33063
33089
|
ok: false,
|
|
@@ -33368,7 +33394,7 @@ async function cmdBackup(runtime, options) {
|
|
|
33368
33394
|
const summary = [
|
|
33369
33395
|
`Created SQLite backup with ${manifest.stores.length} store(s):`,
|
|
33370
33396
|
...manifest.stores.map((s) => ` - ${s.storeId}: ${s.sourcePath} -> ${s.backupFile} (schema v${s.schemaVersion}, ${s.bytes} bytes, sha256 ${s.sha256.slice(0, 12)}...)`),
|
|
33371
|
-
`Manifest: ${
|
|
33397
|
+
`Manifest: ${join25(outDir, "manifest.json")}`
|
|
33372
33398
|
].join("\n");
|
|
33373
33399
|
print(runtime.io, runtime.json, payload, summary);
|
|
33374
33400
|
return 0;
|
|
@@ -33938,7 +33964,7 @@ async function cmdStudioLayout(runtime, workflowPath) {
|
|
|
33938
33964
|
let yamlContent;
|
|
33939
33965
|
let workflowId = "default";
|
|
33940
33966
|
if (existsSync22(filePath)) {
|
|
33941
|
-
yamlContent =
|
|
33967
|
+
yamlContent = readFileSync22(filePath, "utf8");
|
|
33942
33968
|
} else {
|
|
33943
33969
|
yamlContent = `schema: kxm.workflow.v1
|
|
33944
33970
|
description: Feature implementation workflow
|
|
@@ -34011,17 +34037,17 @@ async function cmdStudioServe(runtime, options) {
|
|
|
34011
34037
|
sessionToken,
|
|
34012
34038
|
planProvider: () => {
|
|
34013
34039
|
try {
|
|
34014
|
-
const wfDir =
|
|
34015
|
-
const defaultPath =
|
|
34040
|
+
const wfDir = join26(runtime.cwd, ".kxm", "workflows");
|
|
34041
|
+
const defaultPath = join26(wfDir, "default.yaml");
|
|
34016
34042
|
let targetPath = existsSync22(defaultPath) ? defaultPath : void 0;
|
|
34017
34043
|
if (!targetPath && existsSync22(wfDir)) {
|
|
34018
34044
|
const yml = readdirSync8(wfDir).find((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
|
|
34019
|
-
if (yml) targetPath =
|
|
34045
|
+
if (yml) targetPath = join26(wfDir, yml);
|
|
34020
34046
|
}
|
|
34021
34047
|
if (targetPath && existsSync22(targetPath)) {
|
|
34022
|
-
const raw =
|
|
34048
|
+
const raw = readFileSync22(targetPath, "utf8");
|
|
34023
34049
|
const parsed = (0, import_yaml13.parse)(raw);
|
|
34024
|
-
const wfId =
|
|
34050
|
+
const wfId = basename6(targetPath).replace(/\.(yaml|yml)$/, "");
|
|
34025
34051
|
return compileVnextWorkflow({ id: wfId, value: parsed });
|
|
34026
34052
|
}
|
|
34027
34053
|
} catch {
|
|
@@ -34069,14 +34095,14 @@ Press Ctrl+C to stop.
|
|
|
34069
34095
|
}
|
|
34070
34096
|
|
|
34071
34097
|
// plugins/kxm/src/cli/context-skills.ts
|
|
34072
|
-
import { readFileSync as
|
|
34073
|
-
import { join as
|
|
34098
|
+
import { readFileSync as readFileSync25 } from "node:fs";
|
|
34099
|
+
import { join as join30, relative as relative5 } from "node:path";
|
|
34074
34100
|
|
|
34075
34101
|
// plugins/kxm/src/memory.ts
|
|
34076
34102
|
var import_yaml14 = __toESM(require_dist(), 1);
|
|
34077
34103
|
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
34078
|
-
import { existsSync as existsSync23, mkdirSync as mkdirSync19, readdirSync as readdirSync9, readFileSync as
|
|
34079
|
-
import { extname as extname2, join as
|
|
34104
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync19, readdirSync as readdirSync9, readFileSync as readFileSync23, writeFileSync as writeFileSync18 } from "node:fs";
|
|
34105
|
+
import { extname as extname2, join as join27, resolve as resolve22 } from "node:path";
|
|
34080
34106
|
var MEMORY_SCHEMA = "kxm.memory.v1";
|
|
34081
34107
|
var MEMORY_BRIEF_SCHEMA = "kxm.memory-brief.v1";
|
|
34082
34108
|
var MEMORY_MARKER_START = "<!-- kxm:memory:start -->";
|
|
@@ -34203,8 +34229,8 @@ ${yamlText}
|
|
|
34203
34229
|
}
|
|
34204
34230
|
function memoryDirectories(repoRoot6) {
|
|
34205
34231
|
const root = resolve22(repoRoot6);
|
|
34206
|
-
const memoryDir =
|
|
34207
|
-
const candidatesDir =
|
|
34232
|
+
const memoryDir = join27(root, ".kxm", "memory");
|
|
34233
|
+
const candidatesDir = join27(memoryDir, "candidates");
|
|
34208
34234
|
return { memoryDir, candidatesDir };
|
|
34209
34235
|
}
|
|
34210
34236
|
function loadAuthoredMemory(repoRoot6) {
|
|
@@ -34214,9 +34240,9 @@ function loadAuthoredMemory(repoRoot6) {
|
|
|
34214
34240
|
const entries = readdirSync9(memoryDir, { withFileTypes: true });
|
|
34215
34241
|
for (const entry of entries) {
|
|
34216
34242
|
if (entry.isFile() && extname2(entry.name) === ".md") {
|
|
34217
|
-
const fullPath =
|
|
34243
|
+
const fullPath = join27(memoryDir, entry.name);
|
|
34218
34244
|
try {
|
|
34219
|
-
const text =
|
|
34245
|
+
const text = readFileSync23(fullPath, "utf8");
|
|
34220
34246
|
const record = parseMemoryRecord(text, entry.name);
|
|
34221
34247
|
if (record.lifecycle === "active") {
|
|
34222
34248
|
records.push(record);
|
|
@@ -34255,7 +34281,7 @@ function createMemoryNote(repoRoot6, summary, options = {}) {
|
|
|
34255
34281
|
evidenceRefs: [],
|
|
34256
34282
|
...options.body ? { body: options.body.trim() } : {}
|
|
34257
34283
|
};
|
|
34258
|
-
const targetPath =
|
|
34284
|
+
const targetPath = join27(candidatesDir, `${id}.md`);
|
|
34259
34285
|
writeFileSync18(targetPath, formatMemoryRecord(record), "utf8");
|
|
34260
34286
|
return { record, path: targetPath };
|
|
34261
34287
|
}
|
|
@@ -34293,7 +34319,7 @@ function formatHarnessMemoryBlock(records) {
|
|
|
34293
34319
|
function updateHarnessDocument(filePath, block, defaultHeader) {
|
|
34294
34320
|
let original = "";
|
|
34295
34321
|
if (existsSync23(filePath)) {
|
|
34296
|
-
original =
|
|
34322
|
+
original = readFileSync23(filePath, "utf8");
|
|
34297
34323
|
}
|
|
34298
34324
|
let updated = "";
|
|
34299
34325
|
if (original.includes(MEMORY_MARKER_START) && original.includes(MEMORY_MARKER_END)) {
|
|
@@ -34332,14 +34358,14 @@ function syncHarnessMemory(repoRoot6) {
|
|
|
34332
34358
|
const block = formatHarnessMemoryBlock(records);
|
|
34333
34359
|
const updated = [];
|
|
34334
34360
|
const created = [];
|
|
34335
|
-
const agentsPath =
|
|
34361
|
+
const agentsPath = join27(root, "AGENTS.md");
|
|
34336
34362
|
const agentsHeader = "# AGENTS\n\nFollow project instructions.\n";
|
|
34337
34363
|
const agentsExisted = existsSync23(agentsPath);
|
|
34338
34364
|
if (updateHarnessDocument(agentsPath, block, agentsHeader)) {
|
|
34339
34365
|
if (agentsExisted) updated.push("AGENTS.md");
|
|
34340
34366
|
else created.push("AGENTS.md");
|
|
34341
34367
|
}
|
|
34342
|
-
const claudePath =
|
|
34368
|
+
const claudePath = join27(root, "CLAUDE.md");
|
|
34343
34369
|
const claudeHeader = `# KXM (Claude)
|
|
34344
34370
|
|
|
34345
34371
|
Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
@@ -34355,7 +34381,7 @@ artifacts, not hub \`peer-reply\` evidence.
|
|
|
34355
34381
|
if (claudeExisted) updated.push("CLAUDE.md");
|
|
34356
34382
|
else created.push("CLAUDE.md");
|
|
34357
34383
|
}
|
|
34358
|
-
const geminiPath =
|
|
34384
|
+
const geminiPath = join27(root, "GEMINI.md");
|
|
34359
34385
|
const geminiHeader = `# KXM (Gemini / Antigravity)
|
|
34360
34386
|
|
|
34361
34387
|
Follow [\`AGENTS.md\`](AGENTS.md). Official phase tracking:
|
|
@@ -34375,8 +34401,8 @@ for Gemini models. Starting rotation remains Grok.
|
|
|
34375
34401
|
// plugins/kxm/src/skills.ts
|
|
34376
34402
|
var import_yaml15 = __toESM(require_dist(), 1);
|
|
34377
34403
|
import { createHash as createHash14 } from "node:crypto";
|
|
34378
|
-
import { existsSync as existsSync24, mkdirSync as mkdirSync20, readdirSync as readdirSync10, readFileSync as
|
|
34379
|
-
import { join as
|
|
34404
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync20, readdirSync as readdirSync10, readFileSync as readFileSync24, renameSync as renameSync7, rmSync as rmSync9, statSync as statSync3, writeFileSync as writeFileSync19 } from "node:fs";
|
|
34405
|
+
import { join as join28 } from "node:path";
|
|
34380
34406
|
var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
|
|
34381
34407
|
var SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
|
|
34382
34408
|
var SKILL_DECISION_SCHEMA = "kxm.skill-decision.v1";
|
|
@@ -34470,21 +34496,21 @@ var SkillLifecycle = class {
|
|
|
34470
34496
|
this.allowOptimizationEvals = options.allowOptimizationEvals === true;
|
|
34471
34497
|
}
|
|
34472
34498
|
dir(state) {
|
|
34473
|
-
return
|
|
34499
|
+
return join28(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
|
|
34474
34500
|
}
|
|
34475
34501
|
historyFile(id) {
|
|
34476
|
-
return
|
|
34502
|
+
return join28(this.root, "history", `${id}.jsonl`);
|
|
34477
34503
|
}
|
|
34478
34504
|
paths(state, id) {
|
|
34479
|
-
const dir =
|
|
34480
|
-
return { dir, metadata:
|
|
34505
|
+
const dir = join28(this.dir(state), id);
|
|
34506
|
+
return { dir, metadata: join28(dir, "metadata.json"), skill: join28(dir, "SKILL.md") };
|
|
34481
34507
|
}
|
|
34482
34508
|
appendHistory(id, record) {
|
|
34483
|
-
mkdirSync20(
|
|
34509
|
+
mkdirSync20(join28(this.root, "history"), { recursive: true });
|
|
34484
34510
|
const line = `${JSON.stringify(record)}
|
|
34485
34511
|
`;
|
|
34486
34512
|
if (existsSync24(this.historyFile(id))) {
|
|
34487
|
-
const existing =
|
|
34513
|
+
const existing = readFileSync24(this.historyFile(id), "utf8");
|
|
34488
34514
|
const lines = existing.split("\n").filter((entry) => entry.trim());
|
|
34489
34515
|
writeFileSync19(this.historyFile(id), [...lines.slice(-499), line.trim()].join("\n") + "\n");
|
|
34490
34516
|
} else {
|
|
@@ -34494,18 +34520,18 @@ var SkillLifecycle = class {
|
|
|
34494
34520
|
history(id) {
|
|
34495
34521
|
const file = this.historyFile(id);
|
|
34496
34522
|
if (!existsSync24(file)) return [];
|
|
34497
|
-
return
|
|
34523
|
+
return readFileSync24(file, "utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
34498
34524
|
}
|
|
34499
34525
|
readMetadata(state, id) {
|
|
34500
34526
|
const { metadata } = this.paths(state, id);
|
|
34501
34527
|
if (!existsSync24(metadata)) {
|
|
34502
34528
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${state}`);
|
|
34503
34529
|
}
|
|
34504
|
-
return JSON.parse(
|
|
34530
|
+
return JSON.parse(readFileSync24(metadata, "utf8"));
|
|
34505
34531
|
}
|
|
34506
34532
|
move(from, to, id) {
|
|
34507
|
-
const fromDir =
|
|
34508
|
-
const toDir =
|
|
34533
|
+
const fromDir = join28(this.dir(from), id);
|
|
34534
|
+
const toDir = join28(this.dir(to), id);
|
|
34509
34535
|
if (!existsSync24(fromDir)) {
|
|
34510
34536
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${from}`);
|
|
34511
34537
|
}
|
|
@@ -34664,13 +34690,13 @@ var SkillLifecycle = class {
|
|
|
34664
34690
|
const candidatePaths = this.paths("candidate", candidateId);
|
|
34665
34691
|
const promotedPaths = this.paths("promoted", candidateId);
|
|
34666
34692
|
mkdirSync20(promotedPaths.dir, { recursive: true });
|
|
34667
|
-
const skillContent =
|
|
34668
|
-
const metadataContent =
|
|
34693
|
+
const skillContent = readFileSync24(candidatePaths.skill, "utf8");
|
|
34694
|
+
const metadataContent = readFileSync24(candidatePaths.metadata, "utf8");
|
|
34669
34695
|
writeFileSync19(promotedPaths.skill, skillContent);
|
|
34670
34696
|
writeFileSync19(promotedPaths.metadata, metadataContent);
|
|
34671
|
-
const patchesDir =
|
|
34697
|
+
const patchesDir = join28(this.root, "patches");
|
|
34672
34698
|
mkdirSync20(patchesDir, { recursive: true });
|
|
34673
|
-
const patchPath =
|
|
34699
|
+
const patchPath = join28(patchesDir, `${candidateId}.patch`);
|
|
34674
34700
|
const relSkillPath = `.kxm/skills/promoted/${candidateId}/SKILL.md`;
|
|
34675
34701
|
const relMetaPath = `.kxm/skills/promoted/${candidateId}/metadata.json`;
|
|
34676
34702
|
const patch = `${createUnifiedPatch(relSkillPath, skillContent)}${createUnifiedPatch(relMetaPath, metadataContent)}`;
|
|
@@ -34698,7 +34724,7 @@ var SkillLifecycle = class {
|
|
|
34698
34724
|
verify(state, id) {
|
|
34699
34725
|
const metadata = this.readMetadata(state, id);
|
|
34700
34726
|
const { skill } = this.paths(state, id);
|
|
34701
|
-
const content =
|
|
34727
|
+
const content = readFileSync24(skill, "utf8");
|
|
34702
34728
|
if (skillContentSha256(content) !== metadata.contentSha256) {
|
|
34703
34729
|
throw new SkillLifecycleError(
|
|
34704
34730
|
"skill_integrity_violation",
|
|
@@ -34729,7 +34755,7 @@ var SkillLifecycle = class {
|
|
|
34729
34755
|
read(state, id) {
|
|
34730
34756
|
const metadata = this.readMetadata(state, id);
|
|
34731
34757
|
const { skill } = this.paths(state, id);
|
|
34732
|
-
return { metadata, content:
|
|
34758
|
+
return { metadata, content: readFileSync24(skill, "utf8") };
|
|
34733
34759
|
}
|
|
34734
34760
|
};
|
|
34735
34761
|
function boundedList(value, field) {
|
|
@@ -34744,16 +34770,16 @@ function boundedList(value, field) {
|
|
|
34744
34770
|
return [...new Set(refs)];
|
|
34745
34771
|
}
|
|
34746
34772
|
function readdirSorted(dir) {
|
|
34747
|
-
return readdirSync10(dir).filter((entry) => statSync3(
|
|
34773
|
+
return readdirSync10(dir).filter((entry) => statSync3(join28(dir, entry)).isDirectory()).sort();
|
|
34748
34774
|
}
|
|
34749
34775
|
|
|
34750
34776
|
// plugins/kxm/src/wiki.ts
|
|
34751
34777
|
import { mkdirSync as mkdirSync21, writeFileSync as writeFileSync20 } from "node:fs";
|
|
34752
|
-
import { join as
|
|
34778
|
+
import { join as join29 } from "node:path";
|
|
34753
34779
|
function writeCompiledWiki(root, wiki) {
|
|
34754
34780
|
const written = [];
|
|
34755
34781
|
for (const [relativePath, content] of [...wiki.pages].sort(([left], [right]) => left.localeCompare(right))) {
|
|
34756
|
-
const absolute =
|
|
34782
|
+
const absolute = join29(root, relativePath);
|
|
34757
34783
|
mkdirSync21(absolute.slice(0, absolute.lastIndexOf("/")), { recursive: true });
|
|
34758
34784
|
writeFileSync20(absolute, content);
|
|
34759
34785
|
written.push(relativePath);
|
|
@@ -34921,7 +34947,7 @@ function skillStateFromFlag(value) {
|
|
|
34921
34947
|
throw new Error(`invalid skill state ${value}`);
|
|
34922
34948
|
}
|
|
34923
34949
|
function skillsRoot(runtime) {
|
|
34924
|
-
return
|
|
34950
|
+
return join30(runtime.dirs.workdir, ".kxm", "skills");
|
|
34925
34951
|
}
|
|
34926
34952
|
function csv(value) {
|
|
34927
34953
|
if (!value) return void 0;
|
|
@@ -34938,7 +34964,7 @@ async function cmdSkillsCreate(runtime, options) {
|
|
|
34938
34964
|
const metadata = lifecycle.create({
|
|
34939
34965
|
name: options.name,
|
|
34940
34966
|
description: options.description ?? "",
|
|
34941
|
-
content:
|
|
34967
|
+
content: readFileSync25(options.file, "utf8"),
|
|
34942
34968
|
createdBy: options.createdBy,
|
|
34943
34969
|
sources: {
|
|
34944
34970
|
runIds: csv(options.run) ?? [],
|
|
@@ -35096,8 +35122,8 @@ async function cmdMemorySync(runtime) {
|
|
|
35096
35122
|
|
|
35097
35123
|
// plugins/kxm/src/cli/hub.ts
|
|
35098
35124
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
35099
|
-
import { existsSync as existsSync30, mkdirSync as mkdirSync25, readFileSync as
|
|
35100
|
-
import {
|
|
35125
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync25, readFileSync as readFileSync31, readdirSync as readdirSync12, rmSync as rmSync10, writeFileSync as writeFileSync23 } from "node:fs";
|
|
35126
|
+
import { join as join40, resolve as resolve25 } from "node:path";
|
|
35101
35127
|
|
|
35102
35128
|
// node_modules/marked/lib/marked.esm.js
|
|
35103
35129
|
function M() {
|
|
@@ -41030,7 +41056,7 @@ import * as path2 from "node:path";
|
|
|
41030
41056
|
|
|
41031
41057
|
// node_modules/@earendil-works/pi-tui/dist/native-module-path.js
|
|
41032
41058
|
import { createRequire as createRequire2 } from "node:module";
|
|
41033
|
-
import { dirname as dirname16, join as
|
|
41059
|
+
import { dirname as dirname16, join as join31 } from "node:path";
|
|
41034
41060
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
41035
41061
|
var moduleRequire = createRequire2(import.meta.url);
|
|
41036
41062
|
var TUI_PACKAGE_NAME = "@earendil-works/pi-tui";
|
|
@@ -41039,10 +41065,10 @@ function getNativeModuleCandidates(nativePath, options = {}) {
|
|
|
41039
41065
|
const candidates = [];
|
|
41040
41066
|
try {
|
|
41041
41067
|
const packageEntry = (options.resolvePackage ?? moduleRequire.resolve)(TUI_PACKAGE_NAME);
|
|
41042
|
-
candidates.push(
|
|
41068
|
+
candidates.push(join31(dirname16(packageEntry), "..", nativePath));
|
|
41043
41069
|
} catch {
|
|
41044
41070
|
}
|
|
41045
|
-
candidates.push(
|
|
41071
|
+
candidates.push(join31(moduleDir, "..", nativePath), join31(moduleDir, nativePath), join31(dirname16(options.execPath ?? process.execPath), nativePath));
|
|
41046
41072
|
return Array.from(new Set(candidates));
|
|
41047
41073
|
}
|
|
41048
41074
|
|
|
@@ -43499,7 +43525,7 @@ var MAX_RENDER_WRITE_CHARS = 1024 * 1024;
|
|
|
43499
43525
|
|
|
43500
43526
|
// plugins/kxm/src/tui.ts
|
|
43501
43527
|
import { mkdirSync as mkdirSync22 } from "node:fs";
|
|
43502
|
-
import { join as
|
|
43528
|
+
import { join as join35, resolve as resolve24, dirname as dirname17 } from "node:path";
|
|
43503
43529
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
43504
43530
|
|
|
43505
43531
|
// plugins/kxm/src/external-effects.ts
|
|
@@ -43510,9 +43536,9 @@ function slugifyBranchPart(text, maxLength = 40) {
|
|
|
43510
43536
|
}
|
|
43511
43537
|
|
|
43512
43538
|
// plugins/kxm/src/local-snapshot.ts
|
|
43513
|
-
import { existsSync as existsSync25, readdirSync as readdirSync11, readFileSync as
|
|
43539
|
+
import { existsSync as existsSync25, readdirSync as readdirSync11, readFileSync as readFileSync26 } from "node:fs";
|
|
43514
43540
|
import { homedir as homedir5 } from "node:os";
|
|
43515
|
-
import { isAbsolute as isAbsolute7, join as
|
|
43541
|
+
import { isAbsolute as isAbsolute7, join as join34, resolve as resolve23 } from "node:path";
|
|
43516
43542
|
function processExists2(pid) {
|
|
43517
43543
|
try {
|
|
43518
43544
|
process.kill(pid, 0);
|
|
@@ -43632,16 +43658,16 @@ function readOpenMessageMetadata(database) {
|
|
|
43632
43658
|
return messages;
|
|
43633
43659
|
}
|
|
43634
43660
|
function resolveKxmSnapshotPaths(cwd, env = process.env) {
|
|
43635
|
-
const stateDir = env.KXM_STATE_DIR?.trim() ||
|
|
43661
|
+
const stateDir = env.KXM_STATE_DIR?.trim() || join34(cwd, ".kxm", "state");
|
|
43636
43662
|
const configured = env.KXM_DATA_PATH?.trim();
|
|
43637
|
-
const dataPath = configured ? resolve23(cwd, configured) :
|
|
43663
|
+
const dataPath = configured ? resolve23(cwd, configured) : join34(stateDir, "kxm.db");
|
|
43638
43664
|
return { dataPath, stateDir };
|
|
43639
43665
|
}
|
|
43640
43666
|
function resolveVnextStateRoot(stateDir, options) {
|
|
43641
43667
|
if (options?.vnextStateRoot && existsSync25(options.vnextStateRoot)) {
|
|
43642
43668
|
return resolve23(options.vnextStateRoot);
|
|
43643
43669
|
}
|
|
43644
|
-
if (existsSync25(
|
|
43670
|
+
if (existsSync25(join34(stateDir, "runtime", "registry.db")) || existsSync25(join34(stateDir, "runtime", "projects"))) {
|
|
43645
43671
|
return stateDir;
|
|
43646
43672
|
}
|
|
43647
43673
|
const env = options?.env ?? process.env;
|
|
@@ -43652,13 +43678,13 @@ function resolveVnextStateRoot(stateDir, options) {
|
|
|
43652
43678
|
let base;
|
|
43653
43679
|
if (process.platform === "win32") {
|
|
43654
43680
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
43655
|
-
base = localAppData && isAbsolute7(localAppData) ? localAppData :
|
|
43681
|
+
base = localAppData && isAbsolute7(localAppData) ? localAppData : join34(homedir5(), "AppData", "Local");
|
|
43656
43682
|
base = resolve23(base, "KXM");
|
|
43657
43683
|
} else if (process.platform === "darwin") {
|
|
43658
43684
|
base = resolve23(homedir5(), "Library", "Application Support", "KXM");
|
|
43659
43685
|
} else {
|
|
43660
43686
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
43661
|
-
base = xdgState && isAbsolute7(xdgState) ? xdgState :
|
|
43687
|
+
base = xdgState && isAbsolute7(xdgState) ? xdgState : join34(homedir5(), ".local", "state");
|
|
43662
43688
|
base = resolve23(base, "kxm");
|
|
43663
43689
|
}
|
|
43664
43690
|
if (existsSync25(base)) return base;
|
|
@@ -43692,9 +43718,9 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43692
43718
|
let vnextRunTotal = 0;
|
|
43693
43719
|
const vnextStateRoot = resolveVnextStateRoot(stateDir, options);
|
|
43694
43720
|
if (vnextStateRoot) {
|
|
43695
|
-
const runtimeDir =
|
|
43696
|
-
const registryDbPath =
|
|
43697
|
-
const projectsDir =
|
|
43721
|
+
const runtimeDir = join34(vnextStateRoot, "runtime");
|
|
43722
|
+
const registryDbPath = join34(runtimeDir, "registry.db");
|
|
43723
|
+
const projectsDir = join34(runtimeDir, "projects");
|
|
43698
43724
|
const projectKeys = /* @__PURE__ */ new Set();
|
|
43699
43725
|
if (existsSync25(registryDbPath)) {
|
|
43700
43726
|
hasVnext = true;
|
|
@@ -43723,7 +43749,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43723
43749
|
}
|
|
43724
43750
|
}
|
|
43725
43751
|
for (const key of projectKeys) {
|
|
43726
|
-
const eventDbPath =
|
|
43752
|
+
const eventDbPath = join34(projectsDir, key, "run-events.db");
|
|
43727
43753
|
if (existsSync25(eventDbPath)) {
|
|
43728
43754
|
hasVnext = true;
|
|
43729
43755
|
try {
|
|
@@ -43757,7 +43783,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43757
43783
|
if (existsSync25(stateDir)) {
|
|
43758
43784
|
for (const file of readdirSync11(stateDir).filter((name) => name.endsWith(".pid"))) {
|
|
43759
43785
|
try {
|
|
43760
|
-
const record = JSON.parse(
|
|
43786
|
+
const record = JSON.parse(readFileSync26(join34(stateDir, file), "utf8"));
|
|
43761
43787
|
pids.push({
|
|
43762
43788
|
file,
|
|
43763
43789
|
...record.role ? { role: record.role } : {},
|
|
@@ -43796,7 +43822,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
43796
43822
|
} else {
|
|
43797
43823
|
source = "legacy";
|
|
43798
43824
|
}
|
|
43799
|
-
const telemetryFile =
|
|
43825
|
+
const telemetryFile = join34(stateDir, "telemetry.jsonl");
|
|
43800
43826
|
const spend = existsSync25(telemetryFile) ? readRoutingRecords(telemetryFile) : [];
|
|
43801
43827
|
return {
|
|
43802
43828
|
source,
|
|
@@ -43931,7 +43957,7 @@ function spawnDegradeWorktree(repoRoot6, runId, options) {
|
|
|
43931
43957
|
const cleanRunId = runId.replace(/^run_/, "");
|
|
43932
43958
|
const desc = options?.description ? slugifyBranchPart(options.description, 30) : "degrade";
|
|
43933
43959
|
const branchName = `kxm/run-${cleanRunId}-${desc}`;
|
|
43934
|
-
const relativeWtPath =
|
|
43960
|
+
const relativeWtPath = join35(".kxm", "worktrees", `run-${cleanRunId}-${desc}`);
|
|
43935
43961
|
const absoluteWtPath = resolve24(repoRoot6, relativeWtPath);
|
|
43936
43962
|
const jumpCommand = `cd "${absoluteWtPath}"`;
|
|
43937
43963
|
try {
|
|
@@ -44701,8 +44727,8 @@ async function runMeshTui(input) {
|
|
|
44701
44727
|
// plugins/kxm/src/session-work.ts
|
|
44702
44728
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
44703
44729
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
44704
|
-
import { existsSync as existsSync26, mkdirSync as mkdirSync23, readFileSync as
|
|
44705
|
-
import { join as
|
|
44730
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync23, readFileSync as readFileSync27, renameSync as renameSync8, writeFileSync as writeFileSync21 } from "node:fs";
|
|
44731
|
+
import { join as join36 } from "node:path";
|
|
44706
44732
|
var MAX_SESSION_BRIEF_TASKS = 5;
|
|
44707
44733
|
var MAX_SESSION_BRIEF_PLANS = 5;
|
|
44708
44734
|
var SESSION_BRIEF_SCHEMA = "kxm.session-brief.v1";
|
|
@@ -44858,10 +44884,10 @@ function buildSessionBrief(snapshot, current, hub, ship, updateLatest, cost, ses
|
|
|
44858
44884
|
};
|
|
44859
44885
|
}
|
|
44860
44886
|
function readCachedSessionBrief(stateDir) {
|
|
44861
|
-
const file =
|
|
44887
|
+
const file = join36(stateDir, "session-brief.json");
|
|
44862
44888
|
try {
|
|
44863
44889
|
if (!existsSync26(file)) return void 0;
|
|
44864
|
-
const raw =
|
|
44890
|
+
const raw = readFileSync27(file, "utf8");
|
|
44865
44891
|
const parsed = JSON.parse(raw);
|
|
44866
44892
|
if (parsed && parsed.schema === "kxm.session-brief.v1" && typeof parsed.generatedAt === "string") {
|
|
44867
44893
|
const ageMs = Date.now() - Date.parse(parsed.generatedAt);
|
|
@@ -44877,7 +44903,7 @@ function readCachedSessionBrief(stateDir) {
|
|
|
44877
44903
|
function writeCachedSessionBrief(stateDir, brief) {
|
|
44878
44904
|
try {
|
|
44879
44905
|
mkdirSync23(stateDir, { recursive: true, mode: 448 });
|
|
44880
|
-
const file =
|
|
44906
|
+
const file = join36(stateDir, "session-brief.json");
|
|
44881
44907
|
const tmp = `${file}.tmp.${randomUUID13().slice(0, 8)}`;
|
|
44882
44908
|
writeFileSync21(tmp, JSON.stringify(brief, null, 2), { encoding: "utf8", mode: 384 });
|
|
44883
44909
|
renameSync8(tmp, file);
|
|
@@ -44886,7 +44912,7 @@ function writeCachedSessionBrief(stateDir, brief) {
|
|
|
44886
44912
|
}
|
|
44887
44913
|
function estimateSessionCost(stateDir) {
|
|
44888
44914
|
try {
|
|
44889
|
-
const telemetryFile =
|
|
44915
|
+
const telemetryFile = join36(stateDir, "telemetry.jsonl");
|
|
44890
44916
|
if (!existsSync26(telemetryFile)) return void 0;
|
|
44891
44917
|
const records = readRoutingRecords(telemetryFile);
|
|
44892
44918
|
if (records.length === 0) return void 0;
|
|
@@ -45055,11 +45081,11 @@ function formatSessionBriefText(brief) {
|
|
|
45055
45081
|
}
|
|
45056
45082
|
|
|
45057
45083
|
// plugins/kxm/src/kxm-install-kind.ts
|
|
45058
|
-
import { existsSync as existsSync27, readFileSync as
|
|
45059
|
-
import { dirname as dirname18, join as
|
|
45084
|
+
import { existsSync as existsSync27, readFileSync as readFileSync28 } from "node:fs";
|
|
45085
|
+
import { dirname as dirname18, join as join37 } from "node:path";
|
|
45060
45086
|
function packageIsKxm(root) {
|
|
45061
45087
|
try {
|
|
45062
|
-
const pkg = JSON.parse(
|
|
45088
|
+
const pkg = JSON.parse(readFileSync28(join37(root, "package.json"), "utf8"));
|
|
45063
45089
|
return pkg.name === "@kontextmind/kxm";
|
|
45064
45090
|
} catch {
|
|
45065
45091
|
return false;
|
|
@@ -45108,12 +45134,12 @@ function report(kind, root) {
|
|
|
45108
45134
|
return { kind, root, instruction: installKindInstruction(kind, root) };
|
|
45109
45135
|
}
|
|
45110
45136
|
function classifyInstallRoot(probe) {
|
|
45111
|
-
const piGitRoot =
|
|
45137
|
+
const piGitRoot = join37(probe.homeDir, ".pi", "agent", "git");
|
|
45112
45138
|
if (isUnder(probe.repoRoot, piGitRoot, probe.platform)) return report("pi-git", probe.repoRoot);
|
|
45113
|
-
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() ||
|
|
45114
|
-
const pluginsRoot =
|
|
45139
|
+
const claudeHome = probe.env.CLAUDE_CONFIG_DIR?.trim() || join37(probe.homeDir, ".claude");
|
|
45140
|
+
const pluginsRoot = join37(claudeHome, "plugins");
|
|
45115
45141
|
if (isUnder(probe.moduleDir, pluginsRoot, probe.platform)) return report("claude-marketplace", probe.moduleDir);
|
|
45116
|
-
const hasGit = existsSync27(
|
|
45142
|
+
const hasGit = existsSync27(join37(probe.repoRoot, ".git"));
|
|
45117
45143
|
if (hasGit && packageIsKxm(probe.repoRoot)) return report("source", probe.repoRoot);
|
|
45118
45144
|
if (isNpmPackageLayout(probe.repoRoot, probe.platform) && packageIsKxm(probe.repoRoot) && !hasGit) {
|
|
45119
45145
|
return report("npm-package", probe.repoRoot);
|
|
@@ -45134,14 +45160,14 @@ function resolveInstallKind(probe, npmGlobalRoot) {
|
|
|
45134
45160
|
|
|
45135
45161
|
// plugins/kxm/src/kxm-update-config.ts
|
|
45136
45162
|
var import_yaml16 = __toESM(require_dist(), 1);
|
|
45137
|
-
import { existsSync as existsSync28, readFileSync as
|
|
45138
|
-
import { join as
|
|
45163
|
+
import { existsSync as existsSync28, readFileSync as readFileSync29 } from "node:fs";
|
|
45164
|
+
import { join as join38 } from "node:path";
|
|
45139
45165
|
function loadKxmUpdateConfig(env = process.env) {
|
|
45140
|
-
const path4 =
|
|
45166
|
+
const path4 = join38(vnextUserStateRoot({ env }), "update.yaml");
|
|
45141
45167
|
if (!existsSync28(path4)) return { schema: KXM_UPDATE_SCHEMA, auto: false, source: "github" };
|
|
45142
45168
|
let parsed;
|
|
45143
45169
|
try {
|
|
45144
|
-
parsed = (0, import_yaml16.parse)(
|
|
45170
|
+
parsed = (0, import_yaml16.parse)(readFileSync29(path4, "utf8"));
|
|
45145
45171
|
} catch {
|
|
45146
45172
|
throw new KxmUpdateConfigError("update.yaml is not valid YAML");
|
|
45147
45173
|
}
|
|
@@ -45167,8 +45193,8 @@ function loadKxmUpdateConfig(env = process.env) {
|
|
|
45167
45193
|
}
|
|
45168
45194
|
|
|
45169
45195
|
// plugins/kxm/src/session.ts
|
|
45170
|
-
import { existsSync as existsSync29, mkdirSync as mkdirSync24, readFileSync as
|
|
45171
|
-
import { join as
|
|
45196
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync24, readFileSync as readFileSync30, writeFileSync as writeFileSync22 } from "node:fs";
|
|
45197
|
+
import { join as join39 } from "node:path";
|
|
45172
45198
|
var SESSION_SCHEMA = "kxm.session.v1";
|
|
45173
45199
|
var SessionConfigError = class extends Error {
|
|
45174
45200
|
code = "session_config_invalid";
|
|
@@ -45178,12 +45204,12 @@ var SessionConfigError = class extends Error {
|
|
|
45178
45204
|
}
|
|
45179
45205
|
};
|
|
45180
45206
|
function workflowAssetDirs(assetsDir, workflowId) {
|
|
45181
|
-
const root =
|
|
45182
|
-
return [root,
|
|
45207
|
+
const root = join39(assetsDir, "workflows", workflowId);
|
|
45208
|
+
return [root, join39(root, "inputs"), join39(root, "outputs"), join39(root, "generated")];
|
|
45183
45209
|
}
|
|
45184
45210
|
function sessionAssetDirs(assetsDir, sessionId) {
|
|
45185
|
-
const root =
|
|
45186
|
-
return [root,
|
|
45211
|
+
const root = join39(assetsDir, "sessions", sessionId);
|
|
45212
|
+
return [root, join39(root, "inputs"), join39(root, "outputs")];
|
|
45187
45213
|
}
|
|
45188
45214
|
function rosterNames(configDir) {
|
|
45189
45215
|
return [...loadRosterMap(configDir).values()].map((row) => String(row.name));
|
|
@@ -45233,7 +45259,7 @@ function workerFromRosterRow(name, row, project) {
|
|
|
45233
45259
|
function loadRosterMap(configDir) {
|
|
45234
45260
|
const byName = /* @__PURE__ */ new Map();
|
|
45235
45261
|
for (const [file, key] of [["agents.json", "agents"], ["gates.json", "gates"]]) {
|
|
45236
|
-
const path4 =
|
|
45262
|
+
const path4 = join39(configDir, file);
|
|
45237
45263
|
for (const row of loadRoster(path4, key)) {
|
|
45238
45264
|
const name = String(row.name).trim();
|
|
45239
45265
|
const lowered = name.toLowerCase();
|
|
@@ -45250,7 +45276,7 @@ function loadRoster(path4, key) {
|
|
|
45250
45276
|
if (!existsSync29(path4)) return [];
|
|
45251
45277
|
let parsed;
|
|
45252
45278
|
try {
|
|
45253
|
-
parsed = JSON.parse(
|
|
45279
|
+
parsed = JSON.parse(readFileSync30(path4, "utf8"));
|
|
45254
45280
|
} catch (error) {
|
|
45255
45281
|
throw new SessionConfigError(
|
|
45256
45282
|
`${key} roster at ${path4} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -45275,7 +45301,7 @@ function loadRoster(path4, key) {
|
|
|
45275
45301
|
});
|
|
45276
45302
|
}
|
|
45277
45303
|
function createSession(input) {
|
|
45278
|
-
const assetDir = input.mode === "workflow" && input.workflowId ?
|
|
45304
|
+
const assetDir = input.mode === "workflow" && input.workflowId ? join39("assets", "workflows", input.workflowId) : join39("assets", "sessions", input.id);
|
|
45279
45305
|
return {
|
|
45280
45306
|
schema: SESSION_SCHEMA,
|
|
45281
45307
|
id: input.id,
|
|
@@ -45288,8 +45314,8 @@ function createSession(input) {
|
|
|
45288
45314
|
};
|
|
45289
45315
|
}
|
|
45290
45316
|
function writeSession(assetsDir, session, dryRun = false) {
|
|
45291
|
-
const dir =
|
|
45292
|
-
const path4 =
|
|
45317
|
+
const dir = join39(assetsDir, "sessions", session.id);
|
|
45318
|
+
const path4 = join39(dir, "session.json");
|
|
45293
45319
|
if (!dryRun) {
|
|
45294
45320
|
mkdirSync24(dir, { recursive: true });
|
|
45295
45321
|
writeFileSync22(path4, `${JSON.stringify(session, null, 2)}
|
|
@@ -45327,9 +45353,9 @@ function installProbeFrom(runtime) {
|
|
|
45327
45353
|
};
|
|
45328
45354
|
}
|
|
45329
45355
|
function warnIgnoredProjectUpdateYaml(runtime) {
|
|
45330
|
-
const projectFile =
|
|
45356
|
+
const projectFile = join40(runtime.dirs.workspace, "update.yaml");
|
|
45331
45357
|
if (!existsSync30(projectFile)) return;
|
|
45332
|
-
const userFile =
|
|
45358
|
+
const userFile = join40(vnextUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
45333
45359
|
runtime.io.stderr(`kxm: ignoring .kxm/update.yaml in ${runtime.dirs.workdir}; update settings are read only from ${userFile}
|
|
45334
45360
|
`);
|
|
45335
45361
|
}
|
|
@@ -45355,7 +45381,7 @@ async function cmdDash(runtime, options = {}) {
|
|
|
45355
45381
|
return 2;
|
|
45356
45382
|
}
|
|
45357
45383
|
const screen = requested;
|
|
45358
|
-
const dataPath = resolve25(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() ||
|
|
45384
|
+
const dataPath = resolve25(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join40(runtime.dirs.state, "kxm.db"));
|
|
45359
45385
|
if (runtime.dryRun) {
|
|
45360
45386
|
print(runtime.io, runtime.json, {
|
|
45361
45387
|
ok: true,
|
|
@@ -45371,7 +45397,7 @@ async function cmdDash(runtime, options = {}) {
|
|
|
45371
45397
|
runtime.io.stderr("kxm dash does not support --json; use kxm hub view\n");
|
|
45372
45398
|
return 2;
|
|
45373
45399
|
}
|
|
45374
|
-
const project = runtime.
|
|
45400
|
+
const project = defaultProjectName(runtime.dirs.workdir, runtime.env) || "project";
|
|
45375
45401
|
const authToken = runtime.env.KXM_AUTH_TOKEN?.trim();
|
|
45376
45402
|
return await runMeshTui({
|
|
45377
45403
|
serverUrl: runtime.serverUrl,
|
|
@@ -45401,7 +45427,7 @@ async function cmdHub(runtime) {
|
|
|
45401
45427
|
config = loadKxmUpdateConfig(runtime.env);
|
|
45402
45428
|
} catch (error) {
|
|
45403
45429
|
if (error instanceof KxmUpdateConfigError) {
|
|
45404
|
-
const yamlPath =
|
|
45430
|
+
const yamlPath = join40(vnextUserStateRoot({ env: runtime.env }), "update.yaml");
|
|
45405
45431
|
runtime.io.stderr(`kxm: ${error.message}; update check skipped; fix or remove ${yamlPath}
|
|
45406
45432
|
`);
|
|
45407
45433
|
} else {
|
|
@@ -45552,7 +45578,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45552
45578
|
const orphans = [];
|
|
45553
45579
|
for (const file of pids) {
|
|
45554
45580
|
try {
|
|
45555
|
-
const record = JSON.parse(
|
|
45581
|
+
const record = JSON.parse(readFileSync31(join40(runtime.dirs.state, file), "utf8"));
|
|
45556
45582
|
const expectedControl = file === "hub.pid" ? "hub.stop" : file.startsWith("worker-") ? `${file.slice(0, -4)}.stop` : void 0;
|
|
45557
45583
|
const expectedRole = file === "hub.pid" ? "hub" : file.startsWith("worker-") ? "worker" : void 0;
|
|
45558
45584
|
if (record.version !== 1 || !Number.isInteger(record.pid) || record.pid <= 0 || !record.startedAt || !expectedControl || record.controlFile !== expectedControl || record.role !== expectedRole) {
|
|
@@ -45572,7 +45598,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45572
45598
|
ignored.push(file);
|
|
45573
45599
|
continue;
|
|
45574
45600
|
}
|
|
45575
|
-
writeFileSync23(
|
|
45601
|
+
writeFileSync23(join40(runtime.dirs.state, record.controlFile), `${JSON.stringify({ startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {}, requestedAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
45576
45602
|
`, { encoding: "utf8", mode: 384 });
|
|
45577
45603
|
requested.push(file);
|
|
45578
45604
|
records.set(file, { pid: record.pid, startedAt: record.startedAt, ...record.generation ? { generation: record.generation } : {} });
|
|
@@ -45590,7 +45616,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45590
45616
|
while (Date.now() <= deadline && stopped.size < requested.length) {
|
|
45591
45617
|
for (const [file, record] of records) {
|
|
45592
45618
|
try {
|
|
45593
|
-
const current = JSON.parse(
|
|
45619
|
+
const current = JSON.parse(readFileSync31(join40(runtime.dirs.state, file), "utf8"));
|
|
45594
45620
|
if (current.pid !== record.pid || current.startedAt !== record.startedAt || current.generation !== record.generation || !processExists(record.pid)) stopped.add(file);
|
|
45595
45621
|
} catch {
|
|
45596
45622
|
stopped.add(file);
|
|
@@ -45603,7 +45629,7 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45603
45629
|
for (const file of orphans) {
|
|
45604
45630
|
while (Date.now() <= deadlineOrphans) {
|
|
45605
45631
|
try {
|
|
45606
|
-
const current = JSON.parse(
|
|
45632
|
+
const current = JSON.parse(readFileSync31(join40(runtime.dirs.state, file), "utf8"));
|
|
45607
45633
|
if (!Number.isInteger(current.serverPid) || !processExists(current.serverPid)) break;
|
|
45608
45634
|
} catch {
|
|
45609
45635
|
break;
|
|
@@ -45611,14 +45637,14 @@ async function cmdStop(runtime, waitMsFlag) {
|
|
|
45611
45637
|
await (runtime.io.sleep ?? ((ms) => new Promise((resolveSleep) => setTimeout(resolveSleep, ms))))(100);
|
|
45612
45638
|
}
|
|
45613
45639
|
try {
|
|
45614
|
-
const current = JSON.parse(
|
|
45640
|
+
const current = JSON.parse(readFileSync31(join40(runtime.dirs.state, file), "utf8"));
|
|
45615
45641
|
if (Number.isInteger(current.serverPid) && processExists(current.serverPid)) {
|
|
45616
45642
|
try {
|
|
45617
45643
|
process.kill(current.serverPid, "SIGKILL");
|
|
45618
45644
|
} catch {
|
|
45619
45645
|
}
|
|
45620
45646
|
}
|
|
45621
|
-
rmSync10(
|
|
45647
|
+
rmSync10(join40(runtime.dirs.state, file), { force: true });
|
|
45622
45648
|
} catch {
|
|
45623
45649
|
}
|
|
45624
45650
|
stopped.add(file);
|
|
@@ -45633,7 +45659,7 @@ async function cmdSessionStatus(runtime) {
|
|
|
45633
45659
|
const claims = [];
|
|
45634
45660
|
for (const file of names3.filter((name) => name.endsWith(".pid"))) {
|
|
45635
45661
|
try {
|
|
45636
|
-
const record = JSON.parse(
|
|
45662
|
+
const record = JSON.parse(readFileSync31(join40(stateDir, file), "utf8"));
|
|
45637
45663
|
claims.push({
|
|
45638
45664
|
file,
|
|
45639
45665
|
role: record.role,
|
|
@@ -45648,7 +45674,7 @@ async function cmdSessionStatus(runtime) {
|
|
|
45648
45674
|
const recoveries = [];
|
|
45649
45675
|
for (const file of names3.filter((name) => name.startsWith("worker-recovery-") && name.endsWith(".json"))) {
|
|
45650
45676
|
try {
|
|
45651
|
-
const envelope = JSON.parse(
|
|
45677
|
+
const envelope = JSON.parse(readFileSync31(join40(stateDir, file), "utf8"));
|
|
45652
45678
|
recoveries.push({
|
|
45653
45679
|
file,
|
|
45654
45680
|
reason: envelope.reason,
|
|
@@ -45753,7 +45779,7 @@ async function cmdSessionBrief(runtime, options = {}) {
|
|
|
45753
45779
|
print(runtime.io, runtime.json, { ok: true, command: "session brief", sessionToken }, sessionToken);
|
|
45754
45780
|
return 0;
|
|
45755
45781
|
}
|
|
45756
|
-
const dataPath = resolve25(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() ||
|
|
45782
|
+
const dataPath = resolve25(runtime.dirs.workdir, runtime.env.KXM_DATA_PATH?.trim() || join40(runtime.dirs.state, "kxm.db"));
|
|
45757
45783
|
const env = {
|
|
45758
45784
|
...runtime.env,
|
|
45759
45785
|
KXM_STATE_DIR: runtime.dirs.state,
|
|
@@ -45845,16 +45871,16 @@ async function cmdSessionStart(runtime, options) {
|
|
|
45845
45871
|
// plugins/kxm/src/cli/system.ts
|
|
45846
45872
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
45847
45873
|
import { createHash as createHash16 } from "node:crypto";
|
|
45848
|
-
import { existsSync as existsSync36, mkdtempSync as mkdtempSync2, readFileSync as
|
|
45874
|
+
import { existsSync as existsSync36, mkdtempSync as mkdtempSync2, readFileSync as readFileSync36, rmSync as rmSync12 } from "node:fs";
|
|
45849
45875
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
45850
|
-
import { join as
|
|
45876
|
+
import { join as join46, resolve as resolve29 } from "node:path";
|
|
45851
45877
|
import { createInterface as createInterface3 } from "node:readline";
|
|
45852
45878
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
45853
45879
|
|
|
45854
45880
|
// plugins/kxm/src/improve.ts
|
|
45855
45881
|
import { createHash as createHash15 } from "node:crypto";
|
|
45856
45882
|
import { existsSync as existsSync31, mkdirSync as mkdirSync26, writeFileSync as writeFileSync24 } from "node:fs";
|
|
45857
|
-
import { join as
|
|
45883
|
+
import { join as join41, relative as relative6, resolve as resolve26 } from "node:path";
|
|
45858
45884
|
var CANDIDATE_SCHEMA = "kxm.candidate.v1";
|
|
45859
45885
|
var IMPROVEMENT_REPORT_SCHEMA = "kxm.improvement-report.v2";
|
|
45860
45886
|
function classifyCandidateKind(stepId, agentRole) {
|
|
@@ -46026,7 +46052,7 @@ function groupRoutingRecords(records, options = {}) {
|
|
|
46026
46052
|
}
|
|
46027
46053
|
function buildImprovementReport(records, options = {}) {
|
|
46028
46054
|
const projectRoot = options.projectRoot ? resolve26(options.projectRoot) : process.cwd();
|
|
46029
|
-
const candidatesDir = options.candidatesDir ? resolve26(options.candidatesDir) :
|
|
46055
|
+
const candidatesDir = options.candidatesDir ? resolve26(options.candidatesDir) : join41(projectRoot, ".kxm", "candidates");
|
|
46030
46056
|
const groups = groupRoutingRecords(records, options);
|
|
46031
46057
|
const candidates = [];
|
|
46032
46058
|
for (const group of groups) {
|
|
@@ -46038,7 +46064,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46038
46064
|
group.workflowHash
|
|
46039
46065
|
);
|
|
46040
46066
|
const diffFileName = `${group.candidateId}.diff`;
|
|
46041
|
-
const diffFilePath =
|
|
46067
|
+
const diffFilePath = join41(candidatesDir, diffFileName);
|
|
46042
46068
|
const relDiffPath = relative6(projectRoot, diffFilePath).replace(/\\/g, "/");
|
|
46043
46069
|
const candidate = {
|
|
46044
46070
|
schema: CANDIDATE_SCHEMA,
|
|
@@ -46064,7 +46090,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46064
46090
|
mkdirSync26(candidatesDir, { recursive: true });
|
|
46065
46091
|
}
|
|
46066
46092
|
writeFileSync24(diffFilePath, diff, "utf8");
|
|
46067
|
-
const jsonFilePath =
|
|
46093
|
+
const jsonFilePath = join41(candidatesDir, `${group.candidateId}.json`);
|
|
46068
46094
|
writeFileSync24(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
|
|
46069
46095
|
}
|
|
46070
46096
|
candidates.push(candidate);
|
|
@@ -46080,7 +46106,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
46080
46106
|
}
|
|
46081
46107
|
function writeImprovementReport(improvementsDir, report2, dryRun = false) {
|
|
46082
46108
|
const stamp = report2.createdAt.replace(/[:.]/g, "-");
|
|
46083
|
-
const path4 =
|
|
46109
|
+
const path4 = join41(improvementsDir, `${stamp}.json`);
|
|
46084
46110
|
if (!dryRun) {
|
|
46085
46111
|
mkdirSync26(improvementsDir, { recursive: true });
|
|
46086
46112
|
writeFileSync24(path4, `${JSON.stringify(report2, null, 2)}
|
|
@@ -46123,8 +46149,8 @@ function formatImprovementReport(report2) {
|
|
|
46123
46149
|
|
|
46124
46150
|
// plugins/kxm/src/modes.ts
|
|
46125
46151
|
var import_yaml17 = __toESM(require_dist(), 1);
|
|
46126
|
-
import { existsSync as existsSync32, readFileSync as
|
|
46127
|
-
import { join as
|
|
46152
|
+
import { existsSync as existsSync32, readFileSync as readFileSync33 } from "node:fs";
|
|
46153
|
+
import { join as join42 } from "node:path";
|
|
46128
46154
|
var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
46129
46155
|
schema: "kxm.modes.v1",
|
|
46130
46156
|
majorModes: {
|
|
@@ -46187,12 +46213,12 @@ function loadModesConfig(projectRoot) {
|
|
|
46187
46213
|
if (!projectRoot) {
|
|
46188
46214
|
return DEFAULT_MODES_CONFIG;
|
|
46189
46215
|
}
|
|
46190
|
-
const modesPath =
|
|
46216
|
+
const modesPath = join42(projectRoot, ".kxm", "modes.yaml");
|
|
46191
46217
|
if (!existsSync32(modesPath)) {
|
|
46192
46218
|
return DEFAULT_MODES_CONFIG;
|
|
46193
46219
|
}
|
|
46194
46220
|
try {
|
|
46195
|
-
const raw =
|
|
46221
|
+
const raw = readFileSync33(modesPath, "utf8");
|
|
46196
46222
|
const parsed = (0, import_yaml17.parse)(raw);
|
|
46197
46223
|
if (parsed && parsed.schema === "kxm.modes.v1" && parsed.majorModes) {
|
|
46198
46224
|
return {
|
|
@@ -46278,11 +46304,11 @@ function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog
|
|
|
46278
46304
|
estimatedTokens: estimateTokens(baseSystemPromptChars)
|
|
46279
46305
|
});
|
|
46280
46306
|
for (const relPath of resolved.contextFiles) {
|
|
46281
|
-
const fullPath =
|
|
46307
|
+
const fullPath = join42(projectRoot, relPath);
|
|
46282
46308
|
let chars = 0;
|
|
46283
46309
|
if (existsSync32(fullPath)) {
|
|
46284
46310
|
try {
|
|
46285
|
-
chars =
|
|
46311
|
+
chars = readFileSync33(fullPath, "utf8").length;
|
|
46286
46312
|
} catch {
|
|
46287
46313
|
chars = 0;
|
|
46288
46314
|
}
|
|
@@ -46414,9 +46440,9 @@ ${divider}
|
|
|
46414
46440
|
|
|
46415
46441
|
// plugins/kxm/src/ssh-remote.ts
|
|
46416
46442
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
46417
|
-
import { existsSync as existsSync33, mkdirSync as mkdirSync27, readFileSync as
|
|
46443
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync27, readFileSync as readFileSync34, readdirSync as readdirSync13, rmSync as rmSync11, statSync as statSync5 } from "node:fs";
|
|
46418
46444
|
import { homedir as homedir7 } from "node:os";
|
|
46419
|
-
import { join as
|
|
46445
|
+
import { join as join43, resolve as resolve27 } from "node:path";
|
|
46420
46446
|
var MAX_SSH_OUTPUT_BYTES = 50 * 1024;
|
|
46421
46447
|
var MAX_SSH_OUTPUT_LINES = 2e3;
|
|
46422
46448
|
var DEFAULT_SOCKET_DIR = ".kxm/run/ssh-sockets";
|
|
@@ -46442,12 +46468,12 @@ function truncateSshOutput(raw) {
|
|
|
46442
46468
|
return { text, truncated };
|
|
46443
46469
|
}
|
|
46444
46470
|
function parseSshConfig(configPath) {
|
|
46445
|
-
const targetPath = configPath ??
|
|
46471
|
+
const targetPath = configPath ?? join43(homedir7(), ".ssh", "config");
|
|
46446
46472
|
if (!existsSync33(targetPath)) {
|
|
46447
46473
|
return [];
|
|
46448
46474
|
}
|
|
46449
46475
|
try {
|
|
46450
|
-
const content =
|
|
46476
|
+
const content = readFileSync34(targetPath, "utf-8");
|
|
46451
46477
|
const lines = content.split("\n");
|
|
46452
46478
|
const hosts = [];
|
|
46453
46479
|
let currentHosts = [];
|
|
@@ -46532,7 +46558,7 @@ function ensureSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
|
46532
46558
|
}
|
|
46533
46559
|
function buildSshArgs(options) {
|
|
46534
46560
|
const socketDir = ensureSocketDir(options.socketDir ?? DEFAULT_SOCKET_DIR);
|
|
46535
|
-
const controlPath =
|
|
46561
|
+
const controlPath = join43(socketDir, "%C");
|
|
46536
46562
|
const persist = options.controlPersist ?? DEFAULT_CONTROL_PERSIST;
|
|
46537
46563
|
const args = [
|
|
46538
46564
|
"-o",
|
|
@@ -46557,7 +46583,7 @@ function buildSshArgs(options) {
|
|
|
46557
46583
|
}
|
|
46558
46584
|
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
46559
46585
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
46560
|
-
const controlPath =
|
|
46586
|
+
const controlPath = join43(resolvedDir, "%C");
|
|
46561
46587
|
try {
|
|
46562
46588
|
const result = execFn("ssh", ["-O", "check", "-o", `ControlPath=${controlPath}`, host], {
|
|
46563
46589
|
encoding: "utf-8"
|
|
@@ -46569,7 +46595,7 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
46569
46595
|
}
|
|
46570
46596
|
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync7) {
|
|
46571
46597
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
46572
|
-
const controlPath =
|
|
46598
|
+
const controlPath = join43(resolvedDir, "%C");
|
|
46573
46599
|
try {
|
|
46574
46600
|
const result = execFn("ssh", ["-O", "stop", "-o", `ControlPath=${controlPath}`, host], {
|
|
46575
46601
|
encoding: "utf-8"
|
|
@@ -47015,9 +47041,9 @@ complete -c kxm -n "__fish_seen_subcommand_from goal" -a "create list get"
|
|
|
47015
47041
|
}
|
|
47016
47042
|
|
|
47017
47043
|
// plugins/kxm/src/completion-install.ts
|
|
47018
|
-
import { existsSync as existsSync34, mkdirSync as mkdirSync28, readFileSync as
|
|
47044
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync28, readFileSync as readFileSync35, writeFileSync as writeFileSync25 } from "node:fs";
|
|
47019
47045
|
import { homedir as homedir8 } from "node:os";
|
|
47020
|
-
import { basename as basename9, delimiter, dirname as dirname21, isAbsolute as isAbsolute8, join as
|
|
47046
|
+
import { basename as basename9, delimiter, dirname as dirname21, isAbsolute as isAbsolute8, join as join44, resolve as resolve28 } from "node:path";
|
|
47021
47047
|
var COMPLETION_MARKER = "# kxm completion";
|
|
47022
47048
|
var PATH_MARKER = "# kxm path";
|
|
47023
47049
|
function detectShell(env = process.env, platform = process.platform) {
|
|
@@ -47039,25 +47065,25 @@ function completionScriptPath(shell, options = {}) {
|
|
|
47039
47065
|
const env = options.env ?? process.env;
|
|
47040
47066
|
const explicit = options.configDir ?? env.KXM_USER_CONFIG_DIR?.trim();
|
|
47041
47067
|
const base = explicit && explicit.length > 0 ? resolve28(explicit) : resolve28(effectiveHome(options), ".config", "kxm");
|
|
47042
|
-
return
|
|
47068
|
+
return join44(base, "completions", `kxm.${shell}`);
|
|
47043
47069
|
}
|
|
47044
47070
|
function bashRcCandidate(options) {
|
|
47045
47071
|
const home = effectiveHome(options);
|
|
47046
|
-
const candidates = [
|
|
47072
|
+
const candidates = [join44(home, ".bashrc"), join44(home, ".bash_profile")];
|
|
47047
47073
|
const existing = candidates.find((candidate) => existsSync34(candidate));
|
|
47048
47074
|
return existing ?? candidates[0];
|
|
47049
47075
|
}
|
|
47050
47076
|
function zshRcCandidate(options) {
|
|
47051
47077
|
const env = options.env ?? process.env;
|
|
47052
47078
|
const home = effectiveHome(options);
|
|
47053
|
-
if (env.ZDOTDIR?.trim()) return
|
|
47054
|
-
return
|
|
47079
|
+
if (env.ZDOTDIR?.trim()) return join44(resolve28(env.ZDOTDIR.trim()), ".zshrc");
|
|
47080
|
+
return join44(home, ".zshrc");
|
|
47055
47081
|
}
|
|
47056
47082
|
function fishCompletionTarget(shell, options) {
|
|
47057
47083
|
const env = options.env ?? process.env;
|
|
47058
47084
|
const home = effectiveHome(options);
|
|
47059
|
-
if (env.XDG_CONFIG_HOME?.trim()) return
|
|
47060
|
-
return
|
|
47085
|
+
if (env.XDG_CONFIG_HOME?.trim()) return join44(resolve28(env.XDG_CONFIG_HOME.trim()), "fish", "completions", "kxm.fish");
|
|
47086
|
+
return join44(home, ".config", "fish", "completions", "kxm.fish");
|
|
47061
47087
|
}
|
|
47062
47088
|
function completionRcTarget(shell, options = {}) {
|
|
47063
47089
|
if (shell === "fish") {
|
|
@@ -47090,12 +47116,12 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47090
47116
|
const { rcFile } = completionRcTarget(shell, options);
|
|
47091
47117
|
const script = generateShellCompletion(shell);
|
|
47092
47118
|
const existingScript = existsSync34(scriptPath);
|
|
47093
|
-
const existingScriptMatches = existingScript &&
|
|
47119
|
+
const existingScriptMatches = existingScript && readFileSync35(scriptPath, "utf8") === script;
|
|
47094
47120
|
let rcModified = false;
|
|
47095
47121
|
let alreadyInstalled = false;
|
|
47096
47122
|
if (shell === "fish") {
|
|
47097
47123
|
const fishTarget = fishCompletionTarget(shell, options);
|
|
47098
|
-
const fishInstalled = existsSync34(fishTarget) &&
|
|
47124
|
+
const fishInstalled = existsSync34(fishTarget) && readFileSync35(fishTarget, "utf8") === script;
|
|
47099
47125
|
alreadyInstalled = fishInstalled;
|
|
47100
47126
|
if (!options.dryRun && (!fishInstalled || options.overwrite)) {
|
|
47101
47127
|
mkdirSync28(resolve28(fishTarget, ".."), { recursive: true });
|
|
@@ -47112,7 +47138,7 @@ function installShellCompletion(shellInput, options = {}) {
|
|
|
47112
47138
|
}
|
|
47113
47139
|
if (rcFile) {
|
|
47114
47140
|
const line = sourceLine(shell, scriptPath);
|
|
47115
|
-
const rcContent = existsSync34(rcFile) ?
|
|
47141
|
+
const rcContent = existsSync34(rcFile) ? readFileSync35(rcFile, "utf8") : "";
|
|
47116
47142
|
alreadyInstalled = rcContent.includes(line) || rcContent.includes(`${COMPLETION_MARKER}`);
|
|
47117
47143
|
}
|
|
47118
47144
|
if (!options.dryRun) {
|
|
@@ -47128,7 +47154,7 @@ ${marker}
|
|
|
47128
47154
|
${line}
|
|
47129
47155
|
`;
|
|
47130
47156
|
mkdirSync28(resolve28(rcFile, ".."), { recursive: true });
|
|
47131
|
-
writeFileSync25(rcFile, (existsSync34(rcFile) ?
|
|
47157
|
+
writeFileSync25(rcFile, (existsSync34(rcFile) ? readFileSync35(rcFile, "utf8") : "") + stanza, { encoding: "utf8" });
|
|
47132
47158
|
rcModified = true;
|
|
47133
47159
|
}
|
|
47134
47160
|
}
|
|
@@ -47145,7 +47171,7 @@ function kxmBinDir(env = process.env) {
|
|
|
47145
47171
|
const argv1 = env.KXM_ENTRY ?? process.argv[1];
|
|
47146
47172
|
if (argv1 && isAbsolute8(argv1)) {
|
|
47147
47173
|
const dir = dirname21(argv1);
|
|
47148
|
-
if (existsSync34(
|
|
47174
|
+
if (existsSync34(join44(dir, process.platform === "win32" ? "kxm.cmd" : "kxm"))) return dir;
|
|
47149
47175
|
}
|
|
47150
47176
|
const pathEnv = env.PATH ?? "";
|
|
47151
47177
|
for (const part of pathEnv.split(delimiter)) {
|
|
@@ -47169,7 +47195,7 @@ function installPathEntry(shellInput, options = {}) {
|
|
|
47169
47195
|
}
|
|
47170
47196
|
const { rcFile } = completionRcTarget(shell, options);
|
|
47171
47197
|
const line = pathLine(binDir);
|
|
47172
|
-
const rcContent = existsSync34(rcFile ?? "") ?
|
|
47198
|
+
const rcContent = existsSync34(rcFile ?? "") ? readFileSync35(rcFile, "utf8") : "";
|
|
47173
47199
|
const alreadyInstalled = rcContent.includes(binDir) || (options.env?.PATH ?? process.env.PATH ?? "").split(delimiter).includes(binDir);
|
|
47174
47200
|
if (!options.dryRun && rcFile && !alreadyInstalled) {
|
|
47175
47201
|
mkdirSync28(dirname21(rcFile), { recursive: true });
|
|
@@ -47184,7 +47210,7 @@ ${line}
|
|
|
47184
47210
|
// plugins/kxm/src/init-guide-setup.ts
|
|
47185
47211
|
var import_yaml18 = __toESM(require_dist(), 1);
|
|
47186
47212
|
import { existsSync as existsSync35, mkdirSync as mkdirSync29, writeFileSync as writeFileSync26 } from "node:fs";
|
|
47187
|
-
import { dirname as dirname22, join as
|
|
47213
|
+
import { dirname as dirname22, join as join45 } from "node:path";
|
|
47188
47214
|
var NATIVE_VENDOR_HARNESS = Object.freeze({
|
|
47189
47215
|
anthropic: "claude",
|
|
47190
47216
|
openai: "codex",
|
|
@@ -47583,13 +47609,13 @@ function renderGuideSetupFiles(projectRoot, plan) {
|
|
|
47583
47609
|
const stage = roleStages.get(role);
|
|
47584
47610
|
if (!stage) continue;
|
|
47585
47611
|
files.push({
|
|
47586
|
-
path:
|
|
47612
|
+
path: join45(projectRoot, ".kxm", "agents", `${role}.yaml`),
|
|
47587
47613
|
content: (0, import_yaml18.stringify)(agentDocument(role, stage, binding))
|
|
47588
47614
|
});
|
|
47589
47615
|
}
|
|
47590
47616
|
for (const workflow of plan.workflows) {
|
|
47591
47617
|
files.push({
|
|
47592
|
-
path:
|
|
47618
|
+
path: join45(projectRoot, ".kxm", "workflows", `${workflow.slug}.yaml`),
|
|
47593
47619
|
content: (0, import_yaml18.stringify)(workflowDocument(workflow))
|
|
47594
47620
|
});
|
|
47595
47621
|
}
|
|
@@ -47668,7 +47694,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
47668
47694
|
detail: `release v${notice.latest} has no sha256 digest for ${name}; refusing to install`
|
|
47669
47695
|
};
|
|
47670
47696
|
}
|
|
47671
|
-
const releaseDir = mkdtempSync2(
|
|
47697
|
+
const releaseDir = mkdtempSync2(join46(tmpdir2(), "kxm-pkg-update-"));
|
|
47672
47698
|
try {
|
|
47673
47699
|
const planned = planKxmPackageUpdate(notice.source, notice.latest, releaseDir, notice.asset);
|
|
47674
47700
|
if (runtime.dryRun) {
|
|
@@ -47677,7 +47703,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
47677
47703
|
for (const step of planned) {
|
|
47678
47704
|
if (step.kind === "verify") {
|
|
47679
47705
|
if (!verifyReleaseAssetDigest(step.path, step.sha256)) {
|
|
47680
|
-
const actual = existsSync36(step.path) ? createHash16("sha256").update(
|
|
47706
|
+
const actual = existsSync36(step.path) ? createHash16("sha256").update(readFileSync36(step.path)).digest("hex") : "missing";
|
|
47681
47707
|
return {
|
|
47682
47708
|
ok: false,
|
|
47683
47709
|
error: "release_digest_mismatch",
|
|
@@ -47948,7 +47974,7 @@ async function cmdValidate(runtime, fileFlag) {
|
|
|
47948
47974
|
return 1;
|
|
47949
47975
|
}
|
|
47950
47976
|
try {
|
|
47951
|
-
const raw = file ?
|
|
47977
|
+
const raw = file ? readFileSync36(file, "utf8") : inline;
|
|
47952
47978
|
const warnings = [];
|
|
47953
47979
|
const definitions = parseWorkflowDefinitions(raw, runtime.env, (message) => warnings.push(message));
|
|
47954
47980
|
const secretEnvs = definitions.map((definition) => ({
|
|
@@ -47994,13 +48020,13 @@ async function cmdArtifactsExist(runtime, pathFlag) {
|
|
|
47994
48020
|
async function cmdImprove(runtime, options = {}) {
|
|
47995
48021
|
const file = options.file ? resolve29(runtime.cwd, options.file) : telemetryPath(runtime.dirs.logs);
|
|
47996
48022
|
const routingRecords = existsSync36(file) ? readRoutingRecords(file).map((entry) => entry.routing) : [];
|
|
47997
|
-
const candidatesDir = options.outDir ? resolve29(runtime.cwd, options.outDir) :
|
|
48023
|
+
const candidatesDir = options.outDir ? resolve29(runtime.cwd, options.outDir) : join46(runtime.cwd, ".kxm", "candidates");
|
|
47998
48024
|
const report2 = buildImprovementReport(routingRecords, {
|
|
47999
48025
|
candidatesDir,
|
|
48000
48026
|
projectRoot: runtime.cwd,
|
|
48001
48027
|
dryRun: runtime.dryRun
|
|
48002
48028
|
});
|
|
48003
|
-
const reportDir =
|
|
48029
|
+
const reportDir = join46(runtime.dirs.assets, "improvements");
|
|
48004
48030
|
const reportPath = writeImprovementReport(reportDir, report2, runtime.dryRun);
|
|
48005
48031
|
const text = formatImprovementReport(report2);
|
|
48006
48032
|
print(runtime.io, runtime.json, {
|
|
@@ -48134,7 +48160,7 @@ async function maybeOfferCompletionInstall(runtime) {
|
|
|
48134
48160
|
const { rcFile } = completionRcTarget(shell, { env: runtime.env });
|
|
48135
48161
|
if (rcFile && existsSync36(rcFile)) {
|
|
48136
48162
|
try {
|
|
48137
|
-
if (
|
|
48163
|
+
if (readFileSync36(rcFile, "utf8").includes(scriptPath)) return;
|
|
48138
48164
|
} catch {
|
|
48139
48165
|
}
|
|
48140
48166
|
}
|
|
@@ -48266,7 +48292,7 @@ async function cmdRoutingReport(runtime, options) {
|
|
|
48266
48292
|
let catalog;
|
|
48267
48293
|
if (includeEquivalentListCost) {
|
|
48268
48294
|
try {
|
|
48269
|
-
const pricesPath = options.prices ? resolve29(runtime.cwd, options.prices) :
|
|
48295
|
+
const pricesPath = options.prices ? resolve29(runtime.cwd, options.prices) : join46(runtime.dirs.workspace, "prices.yaml");
|
|
48270
48296
|
catalog = loadPriceCatalog(pricesPath);
|
|
48271
48297
|
} catch {
|
|
48272
48298
|
}
|
|
@@ -48369,7 +48395,7 @@ function addGlobalOptions(command) {
|
|
|
48369
48395
|
}
|
|
48370
48396
|
async function ensureCliClient(runtime) {
|
|
48371
48397
|
const serverUrl = runtime.serverUrl;
|
|
48372
|
-
const project =
|
|
48398
|
+
const project = defaultProjectName(runtime.cwd, runtime.env);
|
|
48373
48399
|
const name = runtime.env.KXM_AGENT_NAME?.trim() || `cli-${process.pid}`;
|
|
48374
48400
|
const purpose = runtime.env.KXM_AGENT_PURPOSE?.trim() || "CLI agent client";
|
|
48375
48401
|
const authToken = runtime.env.KXM_AUTH_TOKEN?.trim();
|