@kontextmind/kxm 0.7.165 → 0.7.167
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/CHANGELOG.md +16 -0
- package/docs/README.md +1 -0
- package/docs/architecture/hosted-direction.md +9 -4
- package/docs/architecture/inventory.md +1 -0
- package/docs/concepts/trust-model.md +1 -1
- package/docs/contributing/decisions.md +153 -0
- package/docs/contributing/learnings.md +54 -53
- package/docs/contributing/operating-rules.md +19 -6
- package/docs/glossary.md +2 -2
- package/docs/operations/troubleshooting.md +2 -2
- package/docs/operations.md +62 -8
- package/docs/reference/cli-reference.md +11 -11
- package/docs/reference/config-reference.md +36 -11
- package/docs/reference/configuration.md +2 -2
- package/docs/reference/tools.md +1 -1
- package/docs/start/quickstart-claude-code.md +2 -2
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/README.md +3 -3
- package/plugins/kxm/dist/claude-hook.js +417 -66
- package/plugins/kxm/dist/cli.js +1399 -900
- package/plugins/kxm/dist/extension.js +399 -64
- package/plugins/kxm/dist/mcp-server.js +622 -135
- package/plugins/kxm/dist/runtime-supervisor.js +668 -166
- package/plugins/kxm/dist/runtime.js +713 -211
- package/plugins/kxm/dist/server.js +466 -58
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +15 -7
- package/plugins/kxm/src/cli/hub.ts +80 -21
- package/plugins/kxm/src/cli/types.ts +8 -1
- package/plugins/kxm/src/cli.ts +41 -7
- package/plugins/kxm/src/config.ts +246 -3
- package/plugins/kxm/src/extension.ts +8 -7
- package/plugins/kxm/src/hub-autostart.ts +20 -0
- package/plugins/kxm/src/hub-env.ts +83 -31
- package/plugins/kxm/src/hub-identity.ts +337 -0
- package/plugins/kxm/src/mcp-server.ts +17 -15
- package/plugins/kxm/src/project-name.ts +6 -47
- package/plugins/kxm/src/server.ts +22 -4
- package/scripts/kxm-hub.mjs +5 -0
|
@@ -2986,7 +2986,7 @@ var require_compile = __commonJS({
|
|
|
2986
2986
|
const schOrFunc = root.refs[ref];
|
|
2987
2987
|
if (schOrFunc)
|
|
2988
2988
|
return schOrFunc;
|
|
2989
|
-
let _sch =
|
|
2989
|
+
let _sch = resolve15.call(this, root, ref);
|
|
2990
2990
|
if (_sch === void 0) {
|
|
2991
2991
|
const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
2992
2992
|
const { schemaId } = this.opts;
|
|
@@ -3013,7 +3013,7 @@ var require_compile = __commonJS({
|
|
|
3013
3013
|
function sameSchemaEnv(s1, s2) {
|
|
3014
3014
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
3015
3015
|
}
|
|
3016
|
-
function
|
|
3016
|
+
function resolve15(root, ref) {
|
|
3017
3017
|
let sch;
|
|
3018
3018
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3019
3019
|
ref = sch;
|
|
@@ -3838,7 +3838,7 @@ var require_fast_uri = __commonJS({
|
|
|
3838
3838
|
}
|
|
3839
3839
|
return uri;
|
|
3840
3840
|
}
|
|
3841
|
-
function
|
|
3841
|
+
function resolve15(baseURI, relativeURI, options) {
|
|
3842
3842
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3843
3843
|
const {
|
|
3844
3844
|
parsed: baseParsed,
|
|
@@ -4200,7 +4200,7 @@ var require_fast_uri = __commonJS({
|
|
|
4200
4200
|
var fastUri = {
|
|
4201
4201
|
SCHEMES,
|
|
4202
4202
|
normalize,
|
|
4203
|
-
resolve:
|
|
4203
|
+
resolve: resolve15,
|
|
4204
4204
|
resolveComponent,
|
|
4205
4205
|
equal,
|
|
4206
4206
|
serialize,
|
|
@@ -16094,7 +16094,7 @@ function defaultSpawn(command, args, options) {
|
|
|
16094
16094
|
if (options.signal?.aborted) {
|
|
16095
16095
|
return Promise.resolve({ stdout: "", stderr: "", code: null, started: false, observedChildExit: false, error: new Error("process_aborted") });
|
|
16096
16096
|
}
|
|
16097
|
-
return new Promise((
|
|
16097
|
+
return new Promise((resolve15) => {
|
|
16098
16098
|
const stdout = [];
|
|
16099
16099
|
const stderr = [];
|
|
16100
16100
|
let outputBytes = 0;
|
|
@@ -16125,7 +16125,7 @@ function defaultSpawn(command, args, options) {
|
|
|
16125
16125
|
const started = Boolean(child?.pid);
|
|
16126
16126
|
if (started && !observedChildExit) error ??= new Error("process_exit_unobserved");
|
|
16127
16127
|
const unverifiedDescendants = stopping || started && !observedChildExit;
|
|
16128
|
-
|
|
16128
|
+
resolve15({
|
|
16129
16129
|
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
16130
16130
|
stderr: Buffer.concat(stderr).toString("utf8"),
|
|
16131
16131
|
code,
|
|
@@ -18146,8 +18146,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
18146
18146
|
const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
|
|
18147
18147
|
if (maxWriteRepositories > writable) issues.push(issue3("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
|
|
18148
18148
|
}
|
|
18149
|
-
const
|
|
18150
|
-
const minimumPassed =
|
|
18149
|
+
const join27 = objectValue(step.join);
|
|
18150
|
+
const minimumPassed = join27 && typeof join27.minimumPassed === "number" ? join27.minimumPassed : void 0;
|
|
18151
18151
|
if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue3("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
|
|
18152
18152
|
const distinctBy = names(assignment?.distinctBy);
|
|
18153
18153
|
if (distinctBy.length > 0) {
|
|
@@ -23218,7 +23218,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
23218
23218
|
const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
|
|
23219
23219
|
const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
|
|
23220
23220
|
const assignments = compileAssignments(step, id, agent, sink);
|
|
23221
|
-
const
|
|
23221
|
+
const join27 = compileJoin(step, id, sink);
|
|
23222
23222
|
const requiredEvidence = compileEvidence(step, id, sink);
|
|
23223
23223
|
const transitions = compileTransitions(step, id, index, stepIndex, sink);
|
|
23224
23224
|
const outcomes = Object.keys(transitions).sort(compareCodeUnits5);
|
|
@@ -23246,7 +23246,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
23246
23246
|
transitions: orderedTransitions,
|
|
23247
23247
|
requiresPlanHash: requirePlanHash.includes(id),
|
|
23248
23248
|
assignments,
|
|
23249
|
-
join:
|
|
23249
|
+
join: join27
|
|
23250
23250
|
};
|
|
23251
23251
|
if (kind === "agent" || kind === "moa") {
|
|
23252
23252
|
if (!agent) return void 0;
|
|
@@ -23296,15 +23296,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
|
|
|
23296
23296
|
};
|
|
23297
23297
|
}
|
|
23298
23298
|
function compileJoin(step, stepId, sink) {
|
|
23299
|
-
const
|
|
23300
|
-
if (!
|
|
23301
|
-
const declared = stringValue2(
|
|
23299
|
+
const join27 = objectValue2(step.join);
|
|
23300
|
+
if (!join27) return { strategy: "all" };
|
|
23301
|
+
const declared = stringValue2(join27.strategy);
|
|
23302
23302
|
const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
|
|
23303
|
-
const minimumPassed = compileOptionalCount(
|
|
23303
|
+
const minimumPassed = compileOptionalCount(join27.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
|
|
23304
23304
|
const compiled = {
|
|
23305
23305
|
strategy,
|
|
23306
23306
|
...minimumPassed !== void 0 ? { minimumPassed } : {},
|
|
23307
|
-
...typeof
|
|
23307
|
+
...typeof join27.cancelRemaining === "boolean" ? { cancelRemaining: join27.cancelRemaining } : {}
|
|
23308
23308
|
};
|
|
23309
23309
|
return compiled;
|
|
23310
23310
|
}
|
|
@@ -24657,12 +24657,12 @@ function enqueueKxmScheduledRun(storePath, runId, configRevision, bound, start)
|
|
|
24657
24657
|
if (owner.admitted.has(runId) || owner.queue.some((item) => item.runId === runId)) {
|
|
24658
24658
|
return Promise.reject(runtimeError("run_busy", runId, `run ${runId} is already admitted or queued`));
|
|
24659
24659
|
}
|
|
24660
|
-
return new Promise((
|
|
24660
|
+
return new Promise((resolve15, reject) => {
|
|
24661
24661
|
owner.queue.push({
|
|
24662
24662
|
runId,
|
|
24663
24663
|
configRevision,
|
|
24664
24664
|
bound,
|
|
24665
|
-
start: (token) => start(token).then(
|
|
24665
|
+
start: (token) => start(token).then(resolve15, reject),
|
|
24666
24666
|
fail: (error) => reject(error)
|
|
24667
24667
|
});
|
|
24668
24668
|
pump(storePath, owner);
|
|
@@ -25188,9 +25188,9 @@ function assertKxmConfigError(error) {
|
|
|
25188
25188
|
// plugins/kxm/src/runtime-supervisor.ts
|
|
25189
25189
|
import { spawn as spawn3 } from "node:child_process";
|
|
25190
25190
|
import { createHash as createHash16, createHmac, randomBytes as randomBytes3, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
25191
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
25191
|
+
import { chmodSync as chmodSync2, existsSync as existsSync20, lstatSync as lstatSync6, mkdirSync as mkdirSync10, readFileSync as readFileSync17, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync10 } from "node:fs";
|
|
25192
25192
|
import { createServer } from "node:http";
|
|
25193
|
-
import { dirname as
|
|
25193
|
+
import { dirname as dirname13, isAbsolute as isAbsolute8, join as join22 } from "node:path";
|
|
25194
25194
|
|
|
25195
25195
|
// plugins/kxm/src/oneshot-evidence.ts
|
|
25196
25196
|
import { createHash as createHash10, randomUUID as randomUUID3 } from "node:crypto";
|
|
@@ -25521,38 +25521,344 @@ function loadPriceCatalogForEstimate(options) {
|
|
|
25521
25521
|
// plugins/kxm/src/engine.ts
|
|
25522
25522
|
var import_yaml11 = __toESM(require_dist(), 1);
|
|
25523
25523
|
import { createHash as createHash15, randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
|
|
25524
|
-
import { existsSync as
|
|
25525
|
-
import { join as
|
|
25524
|
+
import { existsSync as existsSync15, readFileSync as readFileSync13 } from "node:fs";
|
|
25525
|
+
import { join as join18 } from "node:path";
|
|
25526
25526
|
|
|
25527
25527
|
// plugins/kxm/src/routes.ts
|
|
25528
25528
|
var import_yaml7 = __toESM(require_dist(), 1);
|
|
25529
|
-
import { existsSync as
|
|
25530
|
-
import { join as
|
|
25529
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, readdirSync as readdirSync6 } from "node:fs";
|
|
25530
|
+
import { join as join12 } from "node:path";
|
|
25531
25531
|
|
|
25532
25532
|
// plugins/kxm/src/role.ts
|
|
25533
25533
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
25534
25534
|
|
|
25535
25535
|
// plugins/kxm/src/config.ts
|
|
25536
25536
|
var import_yaml5 = __toESM(require_dist(), 1);
|
|
25537
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "node:fs";
|
|
25538
|
+
import { tmpdir, homedir as homedir2 } from "node:os";
|
|
25539
|
+
import { dirname as dirname6, join as join11, resolve as resolve7 } from "node:path";
|
|
25540
|
+
var KXM_CONFIG_SCHEMA = "kxm.config.v1";
|
|
25541
|
+
var KxmHubConfigError = class extends Error {
|
|
25542
|
+
code = "hub_config_invalid";
|
|
25543
|
+
constructor(message) {
|
|
25544
|
+
super(message);
|
|
25545
|
+
this.name = "KxmHubConfigError";
|
|
25546
|
+
}
|
|
25547
|
+
};
|
|
25548
|
+
var HUB_ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
25549
|
+
var HUB_OP_REF = /^op:\/\/\S+\/\S+\/\S+$/;
|
|
25550
|
+
var LITERAL_SECRET_KEY = /^(token|secret|password|authToken|auth_token|apiKey|api_key|api_token|bearer|credential|access_token)$/i;
|
|
25551
|
+
function isHubKeyEnvName(value) {
|
|
25552
|
+
return HUB_ENV_NAME.test(value);
|
|
25553
|
+
}
|
|
25554
|
+
function isHubOpReference(value) {
|
|
25555
|
+
return HUB_OP_REF.test(value);
|
|
25556
|
+
}
|
|
25557
|
+
var IMPROVEMENT_PROMOTION_POLICIES = ["manual_pr", "critic_quorum", "auto_threshold"];
|
|
25558
|
+
var DEFAULT_KXM_CONFIG = {
|
|
25559
|
+
schema: KXM_CONFIG_SCHEMA,
|
|
25560
|
+
user: {
|
|
25561
|
+
theme: "dark",
|
|
25562
|
+
preferredCritics: ["reviewer-arch", "reviewer-cli"],
|
|
25563
|
+
tokenBudget: 16e3
|
|
25564
|
+
},
|
|
25565
|
+
defaults: {
|
|
25566
|
+
workflow: "software-engineering/feature-implementation",
|
|
25567
|
+
harness: "pi"
|
|
25568
|
+
},
|
|
25569
|
+
dash: {
|
|
25570
|
+
defaultScreen: "agents",
|
|
25571
|
+
refreshIntervalMs: 1e3,
|
|
25572
|
+
autoOpen: false
|
|
25573
|
+
},
|
|
25574
|
+
sync: {
|
|
25575
|
+
defaultTracker: "none"
|
|
25576
|
+
},
|
|
25577
|
+
hub: {
|
|
25578
|
+
autoStart: "background"
|
|
25579
|
+
},
|
|
25580
|
+
improvement: {
|
|
25581
|
+
promotionPolicy: "manual_pr",
|
|
25582
|
+
telemetryHalfLifeDays: 14,
|
|
25583
|
+
autoThreshold: {
|
|
25584
|
+
minRuns: 10,
|
|
25585
|
+
minPassRate: 0.95,
|
|
25586
|
+
minCostSavings: 0.5
|
|
25587
|
+
}
|
|
25588
|
+
},
|
|
25589
|
+
routing: {
|
|
25590
|
+
shadowExecution: {
|
|
25591
|
+
enabled: false,
|
|
25592
|
+
sampleRate: 0.05,
|
|
25593
|
+
candidateModels: []
|
|
25594
|
+
},
|
|
25595
|
+
circuitBreaker: {
|
|
25596
|
+
mode: "soft_demotion",
|
|
25597
|
+
failureThreshold: 3,
|
|
25598
|
+
windowSeconds: 3600,
|
|
25599
|
+
cooldownSeconds: 1800,
|
|
25600
|
+
penaltyMultiplier: 5
|
|
25601
|
+
}
|
|
25602
|
+
},
|
|
25603
|
+
telemetry: {
|
|
25604
|
+
federated: true,
|
|
25605
|
+
anonymize: true
|
|
25606
|
+
}
|
|
25607
|
+
};
|
|
25608
|
+
function userConfigDirectory(overrideDir) {
|
|
25609
|
+
if (overrideDir) return resolve7(overrideDir);
|
|
25610
|
+
return resolve7(process.env.KXM_USER_CONFIG_DIR?.trim() || join11(homedir2(), ".config", "kxm"));
|
|
25611
|
+
}
|
|
25612
|
+
function repoConfigDirectory(repoRoot) {
|
|
25613
|
+
return resolve7(repoRoot, ".kxm");
|
|
25614
|
+
}
|
|
25615
|
+
function deepMerge(target, source) {
|
|
25616
|
+
const result = { ...target };
|
|
25617
|
+
for (const [key, val] of Object.entries(source)) {
|
|
25618
|
+
if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
25619
|
+
const existing = result[key] && typeof result[key] === "object" && !Array.isArray(result[key]) ? result[key] : {};
|
|
25620
|
+
result[key] = deepMerge(existing, val);
|
|
25621
|
+
} else if (val !== void 0) {
|
|
25622
|
+
result[key] = val;
|
|
25623
|
+
}
|
|
25624
|
+
}
|
|
25625
|
+
return result;
|
|
25626
|
+
}
|
|
25627
|
+
function literalSecretMessage(path) {
|
|
25628
|
+
return `refusing literal hub token at ${path}: store an op:// reference (key.op) or an environment variable name (key.env), never the token`;
|
|
25629
|
+
}
|
|
25630
|
+
function rejectLiteralHubSecrets(value, path) {
|
|
25631
|
+
if (Array.isArray(value)) {
|
|
25632
|
+
value.forEach((item, index) => rejectLiteralHubSecrets(item, `${path}[${index}]`));
|
|
25633
|
+
return;
|
|
25634
|
+
}
|
|
25635
|
+
if (!value || typeof value !== "object") return;
|
|
25636
|
+
for (const [key, child] of Object.entries(value)) {
|
|
25637
|
+
const childPath = `${path}.${key}`;
|
|
25638
|
+
if (typeof child === "string" && (key === "key" || LITERAL_SECRET_KEY.test(key))) {
|
|
25639
|
+
throw new KxmHubConfigError(literalSecretMessage(childPath));
|
|
25640
|
+
}
|
|
25641
|
+
if (child && typeof child === "object") rejectLiteralHubSecrets(child, childPath);
|
|
25642
|
+
}
|
|
25643
|
+
}
|
|
25644
|
+
function parseKeyRef(raw, path) {
|
|
25645
|
+
if (raw === void 0) return void 0;
|
|
25646
|
+
if (typeof raw === "string") throw new KxmHubConfigError(literalSecretMessage(path));
|
|
25647
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
25648
|
+
throw new KxmHubConfigError(`${path} must be a key reference with op and/or env, never a token`);
|
|
25649
|
+
}
|
|
25650
|
+
const row = raw;
|
|
25651
|
+
for (const key of Object.keys(row)) {
|
|
25652
|
+
if (key !== "op" && key !== "env") {
|
|
25653
|
+
throw new KxmHubConfigError(literalSecretMessage(`${path}.${key}`));
|
|
25654
|
+
}
|
|
25655
|
+
}
|
|
25656
|
+
const ref = {};
|
|
25657
|
+
if (row.op !== void 0) {
|
|
25658
|
+
if (typeof row.op !== "string" || !isHubOpReference(row.op)) {
|
|
25659
|
+
throw new KxmHubConfigError(`${path}.op must be an op://vault/item/field reference, not a token`);
|
|
25660
|
+
}
|
|
25661
|
+
ref.op = row.op;
|
|
25662
|
+
}
|
|
25663
|
+
if (row.env !== void 0) {
|
|
25664
|
+
if (typeof row.env !== "string" || !isHubKeyEnvName(row.env)) {
|
|
25665
|
+
throw new KxmHubConfigError(`${path}.env must be an environment variable name, not a token`);
|
|
25666
|
+
}
|
|
25667
|
+
ref.env = row.env;
|
|
25668
|
+
}
|
|
25669
|
+
if (!ref.op && !ref.env) throw new KxmHubConfigError(`${path} needs key.op, key.env, or both`);
|
|
25670
|
+
return ref;
|
|
25671
|
+
}
|
|
25672
|
+
function parseEndpoint(raw, path) {
|
|
25673
|
+
if (raw === void 0) return void 0;
|
|
25674
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
25675
|
+
throw new KxmHubConfigError(`${path} must be an object with url, project, and key`);
|
|
25676
|
+
}
|
|
25677
|
+
const row = raw;
|
|
25678
|
+
const endpoint = {};
|
|
25679
|
+
if (row.url !== void 0) {
|
|
25680
|
+
if (typeof row.url !== "string" || !isHubUrl(row.url)) {
|
|
25681
|
+
throw new KxmHubConfigError(`${path}.url must be an http or https URL without credentials, query, or fragment`);
|
|
25682
|
+
}
|
|
25683
|
+
endpoint.url = row.url.replace(/\/$/, "");
|
|
25684
|
+
}
|
|
25685
|
+
if (row.project !== void 0) {
|
|
25686
|
+
if (typeof row.project !== "string" || !isHubProjectId(row.project)) {
|
|
25687
|
+
throw new KxmHubConfigError(`${path}.project must be a single-line project id, not a token`);
|
|
25688
|
+
}
|
|
25689
|
+
endpoint.project = row.project.trim();
|
|
25690
|
+
}
|
|
25691
|
+
const key = parseKeyRef(row.key, `${path}.key`);
|
|
25692
|
+
if (key) endpoint.key = key;
|
|
25693
|
+
for (const name of Object.keys(row)) {
|
|
25694
|
+
if (name !== "url" && name !== "project" && name !== "key") {
|
|
25695
|
+
if (typeof row[name] === "string") throw new KxmHubConfigError(literalSecretMessage(`${path}.${name}`));
|
|
25696
|
+
throw new KxmHubConfigError(`${path}.${name} is not a hub endpoint field`);
|
|
25697
|
+
}
|
|
25698
|
+
}
|
|
25699
|
+
return endpoint;
|
|
25700
|
+
}
|
|
25701
|
+
function isHubUrl(raw) {
|
|
25702
|
+
try {
|
|
25703
|
+
const parsed = new URL(raw);
|
|
25704
|
+
return (parsed.protocol === "http:" || parsed.protocol === "https:") && parsed.username === "" && parsed.password === "" && parsed.search === "" && parsed.hash === "" && !raw.includes("?") && !raw.includes("#");
|
|
25705
|
+
} catch {
|
|
25706
|
+
return false;
|
|
25707
|
+
}
|
|
25708
|
+
}
|
|
25709
|
+
function isHubProjectId(raw) {
|
|
25710
|
+
const value = raw.trim();
|
|
25711
|
+
return value.length > 0 && value.length <= 200 && !/[\s\r\n]/.test(value);
|
|
25712
|
+
}
|
|
25713
|
+
function parseProjectMap(raw) {
|
|
25714
|
+
if (raw === void 0) return void 0;
|
|
25715
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
25716
|
+
throw new KxmHubConfigError("hub.projects must be a map of project id to key reference, never a token");
|
|
25717
|
+
}
|
|
25718
|
+
const projects = {};
|
|
25719
|
+
for (const [project, value] of Object.entries(raw)) {
|
|
25720
|
+
if (!isHubProjectId(project)) {
|
|
25721
|
+
throw new KxmHubConfigError(`hub.projects key ${JSON.stringify(project)} must be a project id, not a token`);
|
|
25722
|
+
}
|
|
25723
|
+
const ref = parseKeyRef(value, `hub.projects.${project}`);
|
|
25724
|
+
if (!ref) throw new KxmHubConfigError(`hub.projects.${project} needs an op:// reference or an environment variable name`);
|
|
25725
|
+
projects[project.trim()] = ref;
|
|
25726
|
+
}
|
|
25727
|
+
return projects;
|
|
25728
|
+
}
|
|
25729
|
+
function normalizeHubConfig(raw) {
|
|
25730
|
+
const autoStart = raw?.autoStart;
|
|
25731
|
+
const hub = {
|
|
25732
|
+
autoStart: autoStart === "off" || autoStart === "background" ? autoStart : DEFAULT_KXM_CONFIG.hub.autoStart
|
|
25733
|
+
};
|
|
25734
|
+
if (raw === void 0) return hub;
|
|
25735
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
25736
|
+
throw new KxmHubConfigError("hub must be an object");
|
|
25737
|
+
}
|
|
25738
|
+
rejectLiteralHubSecrets(raw, "hub");
|
|
25739
|
+
const row = raw;
|
|
25740
|
+
if (row.mode !== void 0) {
|
|
25741
|
+
if (row.mode !== "local" && row.mode !== "cloud") {
|
|
25742
|
+
throw new KxmHubConfigError("hub.mode must be local or cloud");
|
|
25743
|
+
}
|
|
25744
|
+
hub.mode = row.mode;
|
|
25745
|
+
}
|
|
25746
|
+
const local = parseEndpoint(row.local, "hub.local");
|
|
25747
|
+
const cloud = parseEndpoint(row.cloud, "hub.cloud");
|
|
25748
|
+
const projects = parseProjectMap(row.projects);
|
|
25749
|
+
if (local) hub.local = local;
|
|
25750
|
+
if (cloud) hub.cloud = cloud;
|
|
25751
|
+
if (projects && Object.keys(projects).length > 0) hub.projects = projects;
|
|
25752
|
+
return hub;
|
|
25753
|
+
}
|
|
25754
|
+
function findConfigRoot(start) {
|
|
25755
|
+
let dir = resolve7(start);
|
|
25756
|
+
for (; ; ) {
|
|
25757
|
+
if (existsSync10(join11(dir, ".kxm", "project.yaml")) || existsSync10(join11(dir, ".kxm", "config.yaml"))) return dir;
|
|
25758
|
+
const parent = dirname6(dir);
|
|
25759
|
+
if (parent === dir) return resolve7(start);
|
|
25760
|
+
dir = parent;
|
|
25761
|
+
}
|
|
25762
|
+
}
|
|
25763
|
+
function userConfigDirForEnv(env) {
|
|
25764
|
+
const explicit = env.KXM_USER_CONFIG_DIR?.trim();
|
|
25765
|
+
if (explicit) return explicit;
|
|
25766
|
+
if (env === process.env) return void 0;
|
|
25767
|
+
return join11(tmpdir(), "kxm-no-user-config");
|
|
25768
|
+
}
|
|
25769
|
+
function loadHubSettings(start, env = process.env) {
|
|
25770
|
+
const userConfigDir = userConfigDirForEnv(env);
|
|
25771
|
+
return loadKxmConfig(findConfigRoot(start), userConfigDir === void 0 ? {} : { userConfigDir }).hub;
|
|
25772
|
+
}
|
|
25773
|
+
function recordOf(raw) {
|
|
25774
|
+
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
25775
|
+
}
|
|
25776
|
+
function finiteNumber(value) {
|
|
25777
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
25778
|
+
}
|
|
25779
|
+
function normalizeImprovementConfig(raw) {
|
|
25780
|
+
const value = recordOf(raw);
|
|
25781
|
+
const threshold = recordOf(value.autoThreshold);
|
|
25782
|
+
const policy = value.promotionPolicy;
|
|
25783
|
+
const halfLife = finiteNumber(value.telemetryHalfLifeDays);
|
|
25784
|
+
const minRuns = finiteNumber(threshold.minRuns);
|
|
25785
|
+
const minPassRate = finiteNumber(threshold.minPassRate);
|
|
25786
|
+
const minCostSavings = finiteNumber(threshold.minCostSavings);
|
|
25787
|
+
return {
|
|
25788
|
+
promotionPolicy: IMPROVEMENT_PROMOTION_POLICIES.includes(policy) ? policy : "manual_pr",
|
|
25789
|
+
telemetryHalfLifeDays: halfLife !== void 0 && halfLife > 0 && halfLife <= 3650 ? halfLife : 14,
|
|
25790
|
+
autoThreshold: {
|
|
25791
|
+
minRuns: minRuns !== void 0 && Number.isInteger(minRuns) && minRuns >= 1 && minRuns <= 1e6 ? minRuns : 10,
|
|
25792
|
+
minPassRate: minPassRate !== void 0 && minPassRate >= 0 && minPassRate <= 1 ? minPassRate : 0.95,
|
|
25793
|
+
minCostSavings: minCostSavings !== void 0 && minCostSavings >= 0 ? minCostSavings : 0.5
|
|
25794
|
+
}
|
|
25795
|
+
};
|
|
25796
|
+
}
|
|
25797
|
+
function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
|
|
25798
|
+
const userDir = userConfigDirectory(options.userConfigDir);
|
|
25799
|
+
const userConfigFile = join11(userDir, "config.yaml");
|
|
25800
|
+
const repoDir = repoConfigDirectory(repoRoot);
|
|
25801
|
+
const repoConfigFile = join11(repoDir, "config.yaml");
|
|
25802
|
+
let userRaw = {};
|
|
25803
|
+
let userLoadedPath;
|
|
25804
|
+
if (existsSync10(userConfigFile)) {
|
|
25805
|
+
try {
|
|
25806
|
+
const text = readFileSync8(userConfigFile, "utf8");
|
|
25807
|
+
userRaw = (0, import_yaml5.parse)(text) ?? {};
|
|
25808
|
+
userLoadedPath = userConfigFile;
|
|
25809
|
+
} catch (error) {
|
|
25810
|
+
throw new Error(`invalid user config YAML at ${userConfigFile}`, { cause: error });
|
|
25811
|
+
}
|
|
25812
|
+
}
|
|
25813
|
+
let repoRaw = {};
|
|
25814
|
+
let repoLoadedPath;
|
|
25815
|
+
if (existsSync10(repoConfigFile)) {
|
|
25816
|
+
try {
|
|
25817
|
+
const text = readFileSync8(repoConfigFile, "utf8");
|
|
25818
|
+
repoRaw = (0, import_yaml5.parse)(text) ?? {};
|
|
25819
|
+
repoLoadedPath = repoConfigFile;
|
|
25820
|
+
} catch (error) {
|
|
25821
|
+
throw new Error(`invalid project config YAML at ${repoConfigFile}`, { cause: error });
|
|
25822
|
+
}
|
|
25823
|
+
}
|
|
25824
|
+
const baseCopy = JSON.parse(JSON.stringify(DEFAULT_KXM_CONFIG));
|
|
25825
|
+
const mergedUser = deepMerge(baseCopy, userRaw);
|
|
25826
|
+
const mergedAll = deepMerge(mergedUser, repoRaw);
|
|
25827
|
+
return {
|
|
25828
|
+
schema: KXM_CONFIG_SCHEMA,
|
|
25829
|
+
user: mergedAll.user ?? {},
|
|
25830
|
+
defaults: mergedAll.defaults ?? {},
|
|
25831
|
+
dash: mergedAll.dash ?? {},
|
|
25832
|
+
sync: mergedAll.sync ?? {},
|
|
25833
|
+
hub: normalizeHubConfig(mergedAll.hub),
|
|
25834
|
+
improvement: normalizeImprovementConfig(mergedAll.improvement),
|
|
25835
|
+
routing: mergedAll.routing ?? DEFAULT_KXM_CONFIG.routing,
|
|
25836
|
+
telemetry: mergedAll.telemetry ?? DEFAULT_KXM_CONFIG.telemetry,
|
|
25837
|
+
loadedFrom: {
|
|
25838
|
+
userConfigPath: userLoadedPath,
|
|
25839
|
+
repoConfigPath: repoLoadedPath
|
|
25840
|
+
}
|
|
25841
|
+
};
|
|
25842
|
+
}
|
|
25537
25843
|
|
|
25538
25844
|
// plugins/kxm/src/routes.ts
|
|
25539
25845
|
var RETIRED_POLICY = ".kxm/producers.yaml";
|
|
25540
25846
|
var empty = () => ({ schema: "kxm.routes.v2", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), admitted: [], disabled: [] });
|
|
25541
25847
|
function loadRoutePolicy(root) {
|
|
25542
|
-
if (
|
|
25543
|
-
const path =
|
|
25544
|
-
if (!
|
|
25545
|
-
const value = (0, import_yaml7.parse)(
|
|
25848
|
+
if (existsSync11(join12(root, RETIRED_POLICY))) throw new Error(`retired ${RETIRED_POLICY} present; use .kxm/routes.yaml (kxm.routes.v2)`);
|
|
25849
|
+
const path = join12(root, ".kxm", "routes.yaml");
|
|
25850
|
+
if (!existsSync11(path)) return empty();
|
|
25851
|
+
const value = (0, import_yaml7.parse)(readFileSync9(path, "utf8"));
|
|
25546
25852
|
if (value?.schema !== "kxm.routes.v2" || !Array.isArray(value.admitted)) throw new Error("invalid .kxm/routes.yaml");
|
|
25547
25853
|
return { schema: "kxm.routes.v2", updatedAt: typeof value.updatedAt === "string" ? value.updatedAt : (/* @__PURE__ */ new Date()).toISOString(), admitted: value.admitted.filter((x) => typeof x === "string"), disabled: Array.isArray(value.disabled) ? value.disabled.filter((x) => typeof x === "string") : [] };
|
|
25548
25854
|
}
|
|
25549
25855
|
function listRoleBindings(root) {
|
|
25550
|
-
const dir =
|
|
25856
|
+
const dir = join12(root, ".kxm", "roles");
|
|
25551
25857
|
const result = {};
|
|
25552
|
-
if (!
|
|
25858
|
+
if (!existsSync11(dir)) return result;
|
|
25553
25859
|
for (const file of readdirSync6(dir).filter((name) => name.endsWith(".yaml"))) {
|
|
25554
25860
|
const role = file.slice(0, -5);
|
|
25555
|
-
const value = (0, import_yaml7.parse)(
|
|
25861
|
+
const value = (0, import_yaml7.parse)(readFileSync9(join12(dir, file), "utf8"));
|
|
25556
25862
|
result[role] = (value.roster ?? []).map((entry) => entry.route).filter((route) => typeof route === "string");
|
|
25557
25863
|
}
|
|
25558
25864
|
return result;
|
|
@@ -25560,8 +25866,8 @@ function listRoleBindings(root) {
|
|
|
25560
25866
|
|
|
25561
25867
|
// plugins/kxm/src/route-fallback.ts
|
|
25562
25868
|
var import_yaml8 = __toESM(require_dist(), 1);
|
|
25563
|
-
import { existsSync as
|
|
25564
|
-
import { join as
|
|
25869
|
+
import { existsSync as existsSync12, readdirSync as readdirSync7, readFileSync as readFileSync10 } from "node:fs";
|
|
25870
|
+
import { join as join13 } from "node:path";
|
|
25565
25871
|
|
|
25566
25872
|
// plugins/kxm/src/route-switch.ts
|
|
25567
25873
|
var WALKABLE_CLASSES = ["rate_limit", "transport", "provider_unavailable", "context_overflow"];
|
|
@@ -25761,9 +26067,9 @@ ${lines.join("\n")}`;
|
|
|
25761
26067
|
${block}`;
|
|
25762
26068
|
}
|
|
25763
26069
|
function readYaml(file) {
|
|
25764
|
-
if (!
|
|
26070
|
+
if (!existsSync12(file)) return void 0;
|
|
25765
26071
|
try {
|
|
25766
|
-
const parsed = (0, import_yaml8.parse)(
|
|
26072
|
+
const parsed = (0, import_yaml8.parse)(readFileSync10(file, "utf8"));
|
|
25767
26073
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
25768
26074
|
return parsed;
|
|
25769
26075
|
} catch {
|
|
@@ -25775,7 +26081,7 @@ function stringList(value) {
|
|
|
25775
26081
|
}
|
|
25776
26082
|
function readSelectors(projectRoot, value) {
|
|
25777
26083
|
if (!Array.isArray(value)) return [];
|
|
25778
|
-
const modelsDir =
|
|
26084
|
+
const modelsDir = join13(projectRoot, ".kxm", "models");
|
|
25779
26085
|
const selectors = [];
|
|
25780
26086
|
for (const item of value) {
|
|
25781
26087
|
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
@@ -25794,9 +26100,9 @@ function readSelectors(projectRoot, value) {
|
|
|
25794
26100
|
return selectors;
|
|
25795
26101
|
}
|
|
25796
26102
|
function loadChainModel(projectRoot, routeId2, writerIds) {
|
|
25797
|
-
const modelsDir =
|
|
26103
|
+
const modelsDir = join13(projectRoot, ".kxm", "models");
|
|
25798
26104
|
const fileId = findYamlBasename(modelsDir, routeId2, "route") ?? routeId2;
|
|
25799
|
-
const doc = readYaml(
|
|
26105
|
+
const doc = readYaml(join13(modelsDir, `${fileId}.yaml`));
|
|
25800
26106
|
if (!doc || doc.schema !== "kxm.model.v2") return void 0;
|
|
25801
26107
|
const harness = typeof doc.harness === "string" ? doc.harness : "";
|
|
25802
26108
|
const model = typeof doc.model === "string" ? doc.model : "";
|
|
@@ -25823,7 +26129,7 @@ function loadChainModel(projectRoot, routeId2, writerIds) {
|
|
|
25823
26129
|
};
|
|
25824
26130
|
}
|
|
25825
26131
|
function canonicalRoster(projectRoot, entries) {
|
|
25826
|
-
const modelsDir =
|
|
26132
|
+
const modelsDir = join13(projectRoot, ".kxm", "models");
|
|
25827
26133
|
return entries.map((entry) => {
|
|
25828
26134
|
const route = findYamlBasename(modelsDir, entry.route, "route") ?? entry.route;
|
|
25829
26135
|
return entry.effort ? { route, effort: entry.effort } : { route };
|
|
@@ -25842,10 +26148,10 @@ function rosterEntries(doc) {
|
|
|
25842
26148
|
return entries;
|
|
25843
26149
|
}
|
|
25844
26150
|
function loadModelsFor(projectRoot, roster, writerIds) {
|
|
25845
|
-
const modelsDir =
|
|
26151
|
+
const modelsDir = join13(projectRoot, ".kxm", "models");
|
|
25846
26152
|
const wanted = /* @__PURE__ */ new Set();
|
|
25847
26153
|
for (const entry of roster) wanted.add(entry.route);
|
|
25848
|
-
if (
|
|
26154
|
+
if (existsSync12(modelsDir)) {
|
|
25849
26155
|
for (const name of readdirSync7(modelsDir)) {
|
|
25850
26156
|
if (!name.endsWith(".yaml") || name === "inventory.yaml") continue;
|
|
25851
26157
|
wanted.add(name.slice(0, -5));
|
|
@@ -25862,12 +26168,12 @@ function loadModelsFor(projectRoot, roster, writerIds) {
|
|
|
25862
26168
|
return models;
|
|
25863
26169
|
}
|
|
25864
26170
|
function criticVendors(projectRoot, writerIds) {
|
|
25865
|
-
const dir =
|
|
25866
|
-
if (!
|
|
26171
|
+
const dir = join13(projectRoot, ".kxm", "roles");
|
|
26172
|
+
if (!existsSync12(dir)) return [];
|
|
25867
26173
|
const vendors = [];
|
|
25868
26174
|
for (const name of readdirSync7(dir)) {
|
|
25869
26175
|
if (!name.endsWith(".yaml")) continue;
|
|
25870
|
-
const doc = readYaml(
|
|
26176
|
+
const doc = readYaml(join13(dir, name));
|
|
25871
26177
|
const purpose = doc?.purpose;
|
|
25872
26178
|
if (purpose !== "reviewer-arch" && purpose !== "reviewer-cli") continue;
|
|
25873
26179
|
const first = rosterEntries(doc)[0];
|
|
@@ -25878,12 +26184,12 @@ function criticVendors(projectRoot, writerIds) {
|
|
|
25878
26184
|
return vendors;
|
|
25879
26185
|
}
|
|
25880
26186
|
function loadAgentFallback(projectRoot, agentId, options) {
|
|
25881
|
-
const agentsDir =
|
|
26187
|
+
const agentsDir = join13(projectRoot, ".kxm", "agents");
|
|
25882
26188
|
const agentFile = findYamlBasename(agentsDir, agentId, "agent") ?? agentId;
|
|
25883
|
-
const agent = readYaml(
|
|
26189
|
+
const agent = readYaml(join13(agentsDir, `${agentFile}.yaml`));
|
|
25884
26190
|
const roleId = typeof agent?.role === "string" ? agent.role : "";
|
|
25885
26191
|
if (!roleId) return void 0;
|
|
25886
|
-
const role = readYaml(
|
|
26192
|
+
const role = readYaml(join13(projectRoot, ".kxm", "roles", `${roleId}.yaml`));
|
|
25887
26193
|
if (!role) return void 0;
|
|
25888
26194
|
const policyRecord = role.policy && typeof role.policy === "object" ? role.policy.fallback : void 0;
|
|
25889
26195
|
const policy = parseFallbackPolicy(policyRecord);
|
|
@@ -25894,7 +26200,7 @@ function loadAgentFallback(projectRoot, agentId, options) {
|
|
|
25894
26200
|
let cursor = typeof role.extends === "string" ? role.extends : "";
|
|
25895
26201
|
while (cursor && !seenRoles.has(cursor)) {
|
|
25896
26202
|
seenRoles.add(cursor);
|
|
25897
|
-
const parent = readYaml(
|
|
26203
|
+
const parent = readYaml(join13(projectRoot, ".kxm", "roles", `${cursor}.yaml`));
|
|
25898
26204
|
extendsRoster = extendsRoster.concat(canonicalRoster(projectRoot, rosterEntries(parent)));
|
|
25899
26205
|
cursor = typeof parent?.extends === "string" ? parent.extends : "";
|
|
25900
26206
|
}
|
|
@@ -26242,7 +26548,7 @@ function pruneContextPacket(packet, tokenBudget) {
|
|
|
26242
26548
|
// plugins/kxm/src/dispatch-context.ts
|
|
26243
26549
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
26244
26550
|
import { readdirSync as readdirSync10 } from "node:fs";
|
|
26245
|
-
import { extname as extname3, join as
|
|
26551
|
+
import { extname as extname3, join as join16 } from "node:path";
|
|
26246
26552
|
|
|
26247
26553
|
// plugins/kxm/src/protocol.ts
|
|
26248
26554
|
var DEFAULT_MESSAGE_TTL_MS = 24 * 60 * 6e4;
|
|
@@ -26874,8 +27180,8 @@ function memoryRecordToContextItem(record2, project) {
|
|
|
26874
27180
|
|
|
26875
27181
|
// plugins/kxm/src/memory.ts
|
|
26876
27182
|
var import_yaml9 = __toESM(require_dist(), 1);
|
|
26877
|
-
import { existsSync as
|
|
26878
|
-
import { extname as extname2, join as
|
|
27183
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync5, readdirSync as readdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "node:fs";
|
|
27184
|
+
import { extname as extname2, join as join14, resolve as resolve8 } from "node:path";
|
|
26879
27185
|
var MEMORY_SCHEMA = "kxm.memory.v1";
|
|
26880
27186
|
var VALID_SCOPES = /* @__PURE__ */ new Set(["agent", "project", "run", "operator"]);
|
|
26881
27187
|
var VALID_AUTHORITIES = /* @__PURE__ */ new Set(["instruction", "evidence", "promoted"]);
|
|
@@ -26973,21 +27279,21 @@ function parseMemoryRecord(raw, filename = "memory.md") {
|
|
|
26973
27279
|
};
|
|
26974
27280
|
}
|
|
26975
27281
|
function memoryDirectories(repoRoot) {
|
|
26976
|
-
const root =
|
|
26977
|
-
const memoryDir =
|
|
26978
|
-
const candidatesDir =
|
|
27282
|
+
const root = resolve8(repoRoot);
|
|
27283
|
+
const memoryDir = join14(root, ".kxm", "memory");
|
|
27284
|
+
const candidatesDir = join14(memoryDir, "candidates");
|
|
26979
27285
|
return { memoryDir, candidatesDir };
|
|
26980
27286
|
}
|
|
26981
27287
|
function loadAuthoredMemory(repoRoot) {
|
|
26982
27288
|
const { memoryDir } = memoryDirectories(repoRoot);
|
|
26983
|
-
if (!
|
|
27289
|
+
if (!existsSync13(memoryDir)) return [];
|
|
26984
27290
|
const records = [];
|
|
26985
27291
|
const entries = readdirSync8(memoryDir, { withFileTypes: true });
|
|
26986
27292
|
for (const entry of entries) {
|
|
26987
27293
|
if (entry.isFile() && extname2(entry.name) === ".md") {
|
|
26988
|
-
const fullPath =
|
|
27294
|
+
const fullPath = join14(memoryDir, entry.name);
|
|
26989
27295
|
try {
|
|
26990
|
-
const text =
|
|
27296
|
+
const text = readFileSync11(fullPath, "utf8");
|
|
26991
27297
|
const record2 = parseMemoryRecord(text, entry.name);
|
|
26992
27298
|
if (record2.lifecycle === "active") {
|
|
26993
27299
|
records.push(record2);
|
|
@@ -27003,8 +27309,8 @@ function loadAuthoredMemory(repoRoot) {
|
|
|
27003
27309
|
// plugins/kxm/src/skills.ts
|
|
27004
27310
|
var import_yaml10 = __toESM(require_dist(), 1);
|
|
27005
27311
|
import { createHash as createHash12 } from "node:crypto";
|
|
27006
|
-
import { existsSync as
|
|
27007
|
-
import { dirname as
|
|
27312
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync6, readdirSync as readdirSync9, readFileSync as readFileSync12, renameSync, rmSync, statSync as statSync3, writeFileSync as writeFileSync7 } from "node:fs";
|
|
27313
|
+
import { dirname as dirname8, join as join15 } from "node:path";
|
|
27008
27314
|
var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
|
|
27009
27315
|
var SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
|
|
27010
27316
|
var SKILL_DECISION_SCHEMA = "kxm.skill-decision.v1";
|
|
@@ -27106,24 +27412,24 @@ var SkillLifecycle = class {
|
|
|
27106
27412
|
this.planned.push({ action: "write", target: file });
|
|
27107
27413
|
return;
|
|
27108
27414
|
}
|
|
27109
|
-
|
|
27110
|
-
|
|
27415
|
+
mkdirSync6(dirname8(file), { recursive: true });
|
|
27416
|
+
writeFileSync7(file, content);
|
|
27111
27417
|
}
|
|
27112
27418
|
dir(state) {
|
|
27113
|
-
return
|
|
27419
|
+
return join15(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
|
|
27114
27420
|
}
|
|
27115
27421
|
historyFile(id) {
|
|
27116
|
-
return
|
|
27422
|
+
return join15(this.root, "history", `${id}.jsonl`);
|
|
27117
27423
|
}
|
|
27118
27424
|
paths(state, id) {
|
|
27119
|
-
const dir =
|
|
27120
|
-
return { dir, metadata:
|
|
27425
|
+
const dir = join15(this.dir(state), id);
|
|
27426
|
+
return { dir, metadata: join15(dir, "metadata.json"), skill: join15(dir, "SKILL.md") };
|
|
27121
27427
|
}
|
|
27122
27428
|
appendHistory(id, record2) {
|
|
27123
27429
|
const line = `${JSON.stringify(record2)}
|
|
27124
27430
|
`;
|
|
27125
|
-
if (
|
|
27126
|
-
const existing =
|
|
27431
|
+
if (existsSync14(this.historyFile(id))) {
|
|
27432
|
+
const existing = readFileSync12(this.historyFile(id), "utf8");
|
|
27127
27433
|
const lines = existing.split("\n").filter((entry) => entry.trim());
|
|
27128
27434
|
this.write(this.historyFile(id), [...lines.slice(-499), line.trim()].join("\n") + "\n");
|
|
27129
27435
|
} else {
|
|
@@ -27132,28 +27438,28 @@ var SkillLifecycle = class {
|
|
|
27132
27438
|
}
|
|
27133
27439
|
history(id) {
|
|
27134
27440
|
const file = this.historyFile(id);
|
|
27135
|
-
if (!
|
|
27136
|
-
return
|
|
27441
|
+
if (!existsSync14(file)) return [];
|
|
27442
|
+
return readFileSync12(file, "utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
27137
27443
|
}
|
|
27138
27444
|
readMetadata(state, id) {
|
|
27139
27445
|
const { metadata } = this.paths(state, id);
|
|
27140
|
-
if (!
|
|
27446
|
+
if (!existsSync14(metadata)) {
|
|
27141
27447
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${state}`);
|
|
27142
27448
|
}
|
|
27143
|
-
return JSON.parse(
|
|
27449
|
+
return JSON.parse(readFileSync12(metadata, "utf8"));
|
|
27144
27450
|
}
|
|
27145
27451
|
move(from, to, id) {
|
|
27146
|
-
const fromDir =
|
|
27147
|
-
const toDir =
|
|
27148
|
-
if (!
|
|
27452
|
+
const fromDir = join15(this.dir(from), id);
|
|
27453
|
+
const toDir = join15(this.dir(to), id);
|
|
27454
|
+
if (!existsSync14(fromDir)) {
|
|
27149
27455
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${from}`);
|
|
27150
27456
|
}
|
|
27151
27457
|
if (this.dryRun) {
|
|
27152
27458
|
this.planned.push({ action: "move", target: `${fromDir} -> ${toDir}` });
|
|
27153
27459
|
return;
|
|
27154
27460
|
}
|
|
27155
|
-
|
|
27156
|
-
if (
|
|
27461
|
+
mkdirSync6(this.dir(to), { recursive: true });
|
|
27462
|
+
if (existsSync14(toDir)) rmSync(toDir, { recursive: true, force: true });
|
|
27157
27463
|
renameSync(fromDir, toDir);
|
|
27158
27464
|
}
|
|
27159
27465
|
/** Submit a new skill candidate. Content is redacted of secret material at
|
|
@@ -27196,7 +27502,7 @@ var SkillLifecycle = class {
|
|
|
27196
27502
|
const contentSha256 = skillContentSha256(content);
|
|
27197
27503
|
const id = skillIdFor(name, contentSha256);
|
|
27198
27504
|
const { metadata, skill } = this.paths("candidate", id);
|
|
27199
|
-
if (
|
|
27505
|
+
if (existsSync14(metadata)) {
|
|
27200
27506
|
throw new SkillLifecycleError(
|
|
27201
27507
|
"skill_candidate_exists",
|
|
27202
27508
|
`identical candidate ${id} already exists; changed behavior requires changed content`
|
|
@@ -27305,11 +27611,11 @@ var SkillLifecycle = class {
|
|
|
27305
27611
|
};
|
|
27306
27612
|
const candidatePaths = this.paths("candidate", candidateId);
|
|
27307
27613
|
const promotedPaths = this.paths("promoted", candidateId);
|
|
27308
|
-
const skillContent =
|
|
27309
|
-
const metadataContent =
|
|
27614
|
+
const skillContent = readFileSync12(candidatePaths.skill, "utf8");
|
|
27615
|
+
const metadataContent = readFileSync12(candidatePaths.metadata, "utf8");
|
|
27310
27616
|
this.write(promotedPaths.skill, skillContent);
|
|
27311
27617
|
this.write(promotedPaths.metadata, metadataContent);
|
|
27312
|
-
const patchPath =
|
|
27618
|
+
const patchPath = join15(this.root, "patches", `${candidateId}.patch`);
|
|
27313
27619
|
const relSkillPath = `.kxm/skills/promoted/${candidateId}/SKILL.md`;
|
|
27314
27620
|
const relMetaPath = `.kxm/skills/promoted/${candidateId}/metadata.json`;
|
|
27315
27621
|
const patch = `${createUnifiedPatch(relSkillPath, skillContent)}${createUnifiedPatch(relMetaPath, metadataContent)}`;
|
|
@@ -27337,7 +27643,7 @@ var SkillLifecycle = class {
|
|
|
27337
27643
|
verify(state, id) {
|
|
27338
27644
|
const metadata = this.readMetadata(state, id);
|
|
27339
27645
|
const { skill } = this.paths(state, id);
|
|
27340
|
-
const content =
|
|
27646
|
+
const content = readFileSync12(skill, "utf8");
|
|
27341
27647
|
if (skillContentSha256(content) !== metadata.contentSha256) {
|
|
27342
27648
|
throw new SkillLifecycleError(
|
|
27343
27649
|
"skill_integrity_violation",
|
|
@@ -27355,7 +27661,7 @@ var SkillLifecycle = class {
|
|
|
27355
27661
|
}
|
|
27356
27662
|
list(state) {
|
|
27357
27663
|
const dir = this.dir(state);
|
|
27358
|
-
if (!
|
|
27664
|
+
if (!existsSync14(dir)) return [];
|
|
27359
27665
|
const ids = readdirSorted(dir);
|
|
27360
27666
|
return ids.map((id) => {
|
|
27361
27667
|
try {
|
|
@@ -27368,7 +27674,7 @@ var SkillLifecycle = class {
|
|
|
27368
27674
|
read(state, id) {
|
|
27369
27675
|
const metadata = this.readMetadata(state, id);
|
|
27370
27676
|
const { skill } = this.paths(state, id);
|
|
27371
|
-
return { metadata, content:
|
|
27677
|
+
return { metadata, content: readFileSync12(skill, "utf8") };
|
|
27372
27678
|
}
|
|
27373
27679
|
};
|
|
27374
27680
|
function boundedList(value, field) {
|
|
@@ -27383,7 +27689,7 @@ function boundedList(value, field) {
|
|
|
27383
27689
|
return [...new Set(refs)];
|
|
27384
27690
|
}
|
|
27385
27691
|
function readdirSorted(dir) {
|
|
27386
|
-
return readdirSync9(dir).filter((entry) => statSync3(
|
|
27692
|
+
return readdirSync9(dir).filter((entry) => statSync3(join15(dir, entry)).isDirectory()).sort();
|
|
27387
27693
|
}
|
|
27388
27694
|
|
|
27389
27695
|
// plugins/kxm/src/dispatch-context.ts
|
|
@@ -27424,7 +27730,7 @@ function contextRoleForAgent(agentId) {
|
|
|
27424
27730
|
return agentId;
|
|
27425
27731
|
}
|
|
27426
27732
|
function dispatchContextPresent(projectRoot) {
|
|
27427
|
-
return hasTopLevelMarkdown(
|
|
27733
|
+
return hasTopLevelMarkdown(join16(projectRoot, ".kxm", "memory")) || hasAnyEntry(join16(projectRoot, ".kxm", "skills", "promoted"));
|
|
27428
27734
|
}
|
|
27429
27735
|
function hasTopLevelMarkdown(dir) {
|
|
27430
27736
|
try {
|
|
@@ -27500,7 +27806,7 @@ function loadDispatchContextSources(input) {
|
|
|
27500
27806
|
}
|
|
27501
27807
|
const promoted = [];
|
|
27502
27808
|
try {
|
|
27503
|
-
const lifecycle = new SkillLifecycle(
|
|
27809
|
+
const lifecycle = new SkillLifecycle(join16(projectRoot, ".kxm", "skills"));
|
|
27504
27810
|
for (const metadata of lifecycle.list("promoted")) {
|
|
27505
27811
|
try {
|
|
27506
27812
|
promoted.push(lifecycle.verify("promoted", metadata.id));
|
|
@@ -27583,18 +27889,18 @@ function assembleDispatchContext(sources, input) {
|
|
|
27583
27889
|
}
|
|
27584
27890
|
|
|
27585
27891
|
// plugins/kxm/src/engine-artifacts.ts
|
|
27586
|
-
import { join as
|
|
27892
|
+
import { join as join17 } from "node:path";
|
|
27587
27893
|
|
|
27588
27894
|
// plugins/kxm/src/artifacts-exist.ts
|
|
27589
27895
|
import { lstatSync as lstatSync5, realpathSync as realpathSync4, statSync as statSync4 } from "node:fs";
|
|
27590
|
-
import { isAbsolute as isAbsolute5, relative as relative4, resolve as
|
|
27896
|
+
import { isAbsolute as isAbsolute5, relative as relative4, resolve as resolve9 } from "node:path";
|
|
27591
27897
|
function staysUnder(root, candidate) {
|
|
27592
27898
|
const child = relative4(root, candidate);
|
|
27593
27899
|
return child === "" || !isAbsolute5(child) && child !== ".." && !child.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`);
|
|
27594
27900
|
}
|
|
27595
27901
|
function verifyArtifactExists(rootInput, pathInput) {
|
|
27596
|
-
const lexicalRoot =
|
|
27597
|
-
const lexicalPath =
|
|
27902
|
+
const lexicalRoot = resolve9(rootInput);
|
|
27903
|
+
const lexicalPath = resolve9(pathInput);
|
|
27598
27904
|
if (!staysUnder(lexicalRoot, lexicalPath)) {
|
|
27599
27905
|
return { ok: false, error: "artifact_outside_workspace_assets", path: lexicalPath };
|
|
27600
27906
|
}
|
|
@@ -27630,14 +27936,14 @@ function verifyArtifactExists(rootInput, pathInput) {
|
|
|
27630
27936
|
// plugins/kxm/src/engine-artifacts.ts
|
|
27631
27937
|
var kxmArtifactsGateSeams = {};
|
|
27632
27938
|
function evaluateArtifactsGate(context, definition) {
|
|
27633
|
-
const root =
|
|
27939
|
+
const root = join17(context.projectRoot, ".kxm", "assets");
|
|
27634
27940
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
27635
27941
|
const startTime = process.hrtime.bigint();
|
|
27636
27942
|
let checkedCount = 0;
|
|
27637
27943
|
let failedCount = 0;
|
|
27638
27944
|
for (const [index, path] of definition.paths.entries()) {
|
|
27639
27945
|
checkedCount += 1;
|
|
27640
|
-
const result = verifyArtifactExists(root,
|
|
27946
|
+
const result = verifyArtifactExists(root, join17(root, path));
|
|
27641
27947
|
if (!result.ok) failedCount += 1;
|
|
27642
27948
|
kxmArtifactsGateSeams.afterPathChecked?.({ path, index, checkedCount, failedCount });
|
|
27643
27949
|
}
|
|
@@ -27793,8 +28099,8 @@ var CommandObserver = class {
|
|
|
27793
28099
|
this.requestStop("error", "lost-close");
|
|
27794
28100
|
}
|
|
27795
28101
|
run() {
|
|
27796
|
-
return new Promise((
|
|
27797
|
-
this.resolveOutcome =
|
|
28102
|
+
return new Promise((resolve15) => {
|
|
28103
|
+
this.resolveOutcome = resolve15;
|
|
27798
28104
|
try {
|
|
27799
28105
|
this.start();
|
|
27800
28106
|
} catch (error) {
|
|
@@ -29128,8 +29434,8 @@ var KxmRunScheduler = class _KxmRunScheduler {
|
|
|
29128
29434
|
resolve: (_value) => void 0,
|
|
29129
29435
|
reject: (_error) => void 0
|
|
29130
29436
|
};
|
|
29131
|
-
const settled = new Promise((
|
|
29132
|
-
pending.resolve =
|
|
29437
|
+
const settled = new Promise((resolve15, reject) => {
|
|
29438
|
+
pending.resolve = resolve15;
|
|
29133
29439
|
pending.reject = reject;
|
|
29134
29440
|
});
|
|
29135
29441
|
void settled.then(void 0, () => void 0);
|
|
@@ -29668,9 +29974,9 @@ function readYamlFile(file) {
|
|
|
29668
29974
|
return readModelDocument(file);
|
|
29669
29975
|
}
|
|
29670
29976
|
function readModelDocument(file) {
|
|
29671
|
-
if (!
|
|
29977
|
+
if (!existsSync15(file)) return void 0;
|
|
29672
29978
|
try {
|
|
29673
|
-
const parsed = (0, import_yaml11.parse)(
|
|
29979
|
+
const parsed = (0, import_yaml11.parse)(readFileSync13(file, "utf8"));
|
|
29674
29980
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
29675
29981
|
return parsed;
|
|
29676
29982
|
} catch {
|
|
@@ -29701,8 +30007,8 @@ function resolveProducerRoute(projectRoot, step, agentId) {
|
|
|
29701
30007
|
}
|
|
29702
30008
|
};
|
|
29703
30009
|
}
|
|
29704
|
-
const agentFile = findYamlBasename(
|
|
29705
|
-
const agent = readYamlFile(
|
|
30010
|
+
const agentFile = findYamlBasename(join18(projectRoot, ".kxm", "agents"), agentId, "agent") ?? agentId;
|
|
30011
|
+
const agent = readYamlFile(join18(projectRoot, ".kxm", "agents", `${agentFile}.yaml`));
|
|
29706
30012
|
const role = typeof agent?.role === "string" ? agent.role : "";
|
|
29707
30013
|
if (!role) {
|
|
29708
30014
|
return {
|
|
@@ -29713,7 +30019,7 @@ function resolveProducerRoute(projectRoot, step, agentId) {
|
|
|
29713
30019
|
}
|
|
29714
30020
|
};
|
|
29715
30021
|
}
|
|
29716
|
-
const roleDoc = readYamlFile(
|
|
30022
|
+
const roleDoc = readYamlFile(join18(projectRoot, ".kxm", "roles", `${role}.yaml`));
|
|
29717
30023
|
const roster = Array.isArray(roleDoc?.roster) ? roleDoc.roster : void 0;
|
|
29718
30024
|
if (!roster) {
|
|
29719
30025
|
return {
|
|
@@ -29729,8 +30035,8 @@ function resolveProducerRoute(projectRoot, step, agentId) {
|
|
|
29729
30035
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
29730
30036
|
const record2 = entry;
|
|
29731
30037
|
if (typeof record2.route !== "string" || record2.route.length === 0) continue;
|
|
29732
|
-
const routeFile = findYamlBasename(
|
|
29733
|
-
const modelPath =
|
|
30038
|
+
const routeFile = findYamlBasename(join18(projectRoot, ".kxm", "models"), record2.route, "route") ?? record2.route;
|
|
30039
|
+
const modelPath = join18(projectRoot, ".kxm", "models", `${routeFile}.yaml`);
|
|
29734
30040
|
const doc = readModelDocument(modelPath);
|
|
29735
30041
|
if (!doc) {
|
|
29736
30042
|
return {
|
|
@@ -32070,9 +32376,9 @@ var RuntimeHubClient = class {
|
|
|
32070
32376
|
|
|
32071
32377
|
// plugins/kxm/src/hub-binding.ts
|
|
32072
32378
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
32073
|
-
import { existsSync as
|
|
32074
|
-
import { homedir as
|
|
32075
|
-
import { dirname as
|
|
32379
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync14, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync8 } from "node:fs";
|
|
32380
|
+
import { homedir as homedir3 } from "node:os";
|
|
32381
|
+
import { dirname as dirname9, isAbsolute as isAbsolute6, join as join19, resolve as resolve10 } from "node:path";
|
|
32076
32382
|
var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
32077
32383
|
var CloudTokenError = class extends Error {
|
|
32078
32384
|
code;
|
|
@@ -32095,20 +32401,20 @@ function resolveUserStateRoot(env) {
|
|
|
32095
32401
|
const explicit = env.KXM_STATE_HOME?.trim();
|
|
32096
32402
|
if (explicit) {
|
|
32097
32403
|
if (!isAbsolute6(explicit)) throw new HubBindingError("local_state_root_not_absolute");
|
|
32098
|
-
return
|
|
32404
|
+
return resolve10(explicit);
|
|
32099
32405
|
}
|
|
32100
32406
|
if (process.platform === "win32") {
|
|
32101
32407
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
32102
|
-
const base2 = localAppData && isAbsolute6(localAppData) ? localAppData :
|
|
32103
|
-
return
|
|
32408
|
+
const base2 = localAppData && isAbsolute6(localAppData) ? localAppData : join19(homedir3(), "AppData", "Local");
|
|
32409
|
+
return resolve10(base2, "KXM");
|
|
32104
32410
|
}
|
|
32105
|
-
if (process.platform === "darwin") return
|
|
32411
|
+
if (process.platform === "darwin") return resolve10(homedir3(), "Library", "Application Support", "KXM");
|
|
32106
32412
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
32107
|
-
const base = xdgState && isAbsolute6(xdgState) ? xdgState :
|
|
32108
|
-
return
|
|
32413
|
+
const base = xdgState && isAbsolute6(xdgState) ? xdgState : join19(homedir3(), ".local", "state");
|
|
32414
|
+
return resolve10(base, "kxm");
|
|
32109
32415
|
}
|
|
32110
32416
|
function hubBindingFile(env = process.env) {
|
|
32111
|
-
return
|
|
32417
|
+
return join19(resolveUserStateRoot(env), "hub-binding.json");
|
|
32112
32418
|
}
|
|
32113
32419
|
function validateHubUrl(raw) {
|
|
32114
32420
|
let parsed;
|
|
@@ -32204,16 +32510,27 @@ function runTokenCommand(command, env) {
|
|
|
32204
32510
|
}
|
|
32205
32511
|
return stdout.trim();
|
|
32206
32512
|
}
|
|
32513
|
+
function hubBindingScope(url) {
|
|
32514
|
+
let host;
|
|
32515
|
+
try {
|
|
32516
|
+
host = new URL(url).hostname.toLowerCase();
|
|
32517
|
+
} catch {
|
|
32518
|
+
return "remote";
|
|
32519
|
+
}
|
|
32520
|
+
if (host === "localhost" || host === "::1" || host === "[::1]" || host.endsWith(".localhost")) return "loopback";
|
|
32521
|
+
const v4 = /^127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/.exec(host);
|
|
32522
|
+
return v4 && [v4[1], v4[2], v4[3]].every((part) => Number(part) <= 255) ? "loopback" : "remote";
|
|
32523
|
+
}
|
|
32207
32524
|
function isIsoTimestamp(value) {
|
|
32208
32525
|
if (Number.isNaN(Date.parse(value))) return false;
|
|
32209
32526
|
return value === new Date(value).toISOString();
|
|
32210
32527
|
}
|
|
32211
32528
|
function readHubBinding(env = process.env) {
|
|
32212
32529
|
const file = hubBindingFile(env);
|
|
32213
|
-
if (!
|
|
32530
|
+
if (!existsSync16(file)) return void 0;
|
|
32214
32531
|
let parsed;
|
|
32215
32532
|
try {
|
|
32216
|
-
parsed = JSON.parse(
|
|
32533
|
+
parsed = JSON.parse(readFileSync14(file, "utf8"));
|
|
32217
32534
|
} catch {
|
|
32218
32535
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
32219
32536
|
}
|
|
@@ -32264,12 +32581,197 @@ function readHubBinding(env = process.env) {
|
|
|
32264
32581
|
}
|
|
32265
32582
|
|
|
32266
32583
|
// plugins/kxm/src/hub-env.ts
|
|
32267
|
-
import { existsSync as
|
|
32268
|
-
import { homedir as
|
|
32269
|
-
import { dirname as
|
|
32584
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync8, readFileSync as readFileSync16, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync9 } from "node:fs";
|
|
32585
|
+
import { homedir as homedir4 } from "node:os";
|
|
32586
|
+
import { dirname as dirname11, isAbsolute as isAbsolute7, join as join21, resolve as resolve12 } from "node:path";
|
|
32270
32587
|
|
|
32271
|
-
// plugins/kxm/src/
|
|
32588
|
+
// plugins/kxm/src/hub-identity.ts
|
|
32272
32589
|
var import_yaml12 = __toESM(require_dist(), 1);
|
|
32590
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
32591
|
+
import { existsSync as existsSync17, readFileSync as readFileSync15 } from "node:fs";
|
|
32592
|
+
import { basename as basename4, dirname as dirname10, join as join20, resolve as resolve11 } from "node:path";
|
|
32593
|
+
var OP_TIMEOUT_MS = 15e3;
|
|
32594
|
+
var OP_MAX_BUFFER = 4096;
|
|
32595
|
+
function normalizeUrl(raw) {
|
|
32596
|
+
try {
|
|
32597
|
+
return validateHubUrl(raw);
|
|
32598
|
+
} catch {
|
|
32599
|
+
return void 0;
|
|
32600
|
+
}
|
|
32601
|
+
}
|
|
32602
|
+
function projectYamlId(start) {
|
|
32603
|
+
let dir = resolve11(start);
|
|
32604
|
+
for (; ; ) {
|
|
32605
|
+
const file = join20(dir, ".kxm", "project.yaml");
|
|
32606
|
+
if (existsSync17(file)) {
|
|
32607
|
+
try {
|
|
32608
|
+
const doc = (0, import_yaml12.parse)(readFileSync15(file, "utf8"));
|
|
32609
|
+
if (doc && typeof doc === "object" && !Array.isArray(doc) && typeof doc.id === "string" && doc.id.trim()) {
|
|
32610
|
+
return doc.id.trim();
|
|
32611
|
+
}
|
|
32612
|
+
} catch {
|
|
32613
|
+
}
|
|
32614
|
+
return void 0;
|
|
32615
|
+
}
|
|
32616
|
+
const parent = dirname10(dir);
|
|
32617
|
+
if (parent === dir) return void 0;
|
|
32618
|
+
dir = parent;
|
|
32619
|
+
}
|
|
32620
|
+
}
|
|
32621
|
+
function packageName(cwd) {
|
|
32622
|
+
try {
|
|
32623
|
+
const pkg = JSON.parse(readFileSync15(join20(cwd, "package.json"), "utf8"));
|
|
32624
|
+
if (typeof pkg.name === "string" && pkg.name.trim().length > 0) return pkg.name.trim();
|
|
32625
|
+
} catch {
|
|
32626
|
+
}
|
|
32627
|
+
return void 0;
|
|
32628
|
+
}
|
|
32629
|
+
function activeBinding(env) {
|
|
32630
|
+
try {
|
|
32631
|
+
return readHubBinding(env);
|
|
32632
|
+
} catch (error) {
|
|
32633
|
+
if (error instanceof HubBindingError) return void 0;
|
|
32634
|
+
throw error;
|
|
32635
|
+
}
|
|
32636
|
+
}
|
|
32637
|
+
function endpointFor(mode, settings) {
|
|
32638
|
+
return mode === "cloud" ? settings.cloud : settings.local;
|
|
32639
|
+
}
|
|
32640
|
+
function resolveProjectIdentity(cwd, env = process.env, explicit) {
|
|
32641
|
+
const fromExplicit = explicit?.trim();
|
|
32642
|
+
if (fromExplicit) return { project: fromExplicit, source: "flag", sourceLabel: "--project" };
|
|
32643
|
+
const fromEnv = env.KXM_PROJECT?.trim();
|
|
32644
|
+
if (fromEnv) return { project: fromEnv, source: "env", sourceLabel: "KXM_PROJECT" };
|
|
32645
|
+
const settings = loadHubSettings(cwd, env);
|
|
32646
|
+
const mode = settings.mode ?? (activeBinding(env)?.cloud ? "cloud" : "local");
|
|
32647
|
+
const fromConfig = endpointFor(mode, settings)?.project?.trim();
|
|
32648
|
+
if (fromConfig) {
|
|
32649
|
+
return { project: fromConfig, source: "config", sourceLabel: `.kxm/config.yaml hub.${mode}.project` };
|
|
32650
|
+
}
|
|
32651
|
+
const fromProject = projectYamlId(cwd);
|
|
32652
|
+
if (fromProject) return { project: fromProject, source: "project.yaml", sourceLabel: ".kxm/project.yaml id" };
|
|
32653
|
+
const fromPackage = packageName(cwd);
|
|
32654
|
+
if (fromPackage) return { project: fromPackage, source: "package.json", sourceLabel: "package.json name" };
|
|
32655
|
+
return { project: basename4(cwd), source: "directory", sourceLabel: "directory name" };
|
|
32656
|
+
}
|
|
32657
|
+
function opReferenceFromTokenCommand(command) {
|
|
32658
|
+
try {
|
|
32659
|
+
const args = splitTokenCommand(command);
|
|
32660
|
+
if (args[0] === "op" && args[1] === "read" && args[2] && isHubOpReference(args[2])) return args[2];
|
|
32661
|
+
} catch {
|
|
32662
|
+
return void 0;
|
|
32663
|
+
}
|
|
32664
|
+
return void 0;
|
|
32665
|
+
}
|
|
32666
|
+
function defaultOpRead(reference, env) {
|
|
32667
|
+
if (!isHubOpReference(reference)) {
|
|
32668
|
+
throw new CloudTokenError("cloud_token_command_invalid", `refusing to resolve ${reference}; an op:// reference is required`);
|
|
32669
|
+
}
|
|
32670
|
+
const result = spawnSync7("op", ["read", reference], {
|
|
32671
|
+
encoding: "utf8",
|
|
32672
|
+
shell: false,
|
|
32673
|
+
timeout: OP_TIMEOUT_MS,
|
|
32674
|
+
maxBuffer: OP_MAX_BUFFER,
|
|
32675
|
+
env,
|
|
32676
|
+
windowsHide: true
|
|
32677
|
+
});
|
|
32678
|
+
if (result.error || result.status !== 0) {
|
|
32679
|
+
throw new CloudTokenError(
|
|
32680
|
+
"cloud_token_command_failed",
|
|
32681
|
+
`op read failed for ${reference}; the token was not saved`
|
|
32682
|
+
);
|
|
32683
|
+
}
|
|
32684
|
+
const line = (result.stdout ?? "").trim();
|
|
32685
|
+
if (!line || line.split(/\r?\n/).length !== 1) {
|
|
32686
|
+
throw new CloudTokenError(
|
|
32687
|
+
"cloud_token_command_failed",
|
|
32688
|
+
`op read did not print a single token for ${reference}; the token was not saved`
|
|
32689
|
+
);
|
|
32690
|
+
}
|
|
32691
|
+
return line;
|
|
32692
|
+
}
|
|
32693
|
+
function resolveKeyReference(ref, env, opRead = defaultOpRead) {
|
|
32694
|
+
if (!ref) return void 0;
|
|
32695
|
+
if (ref.env) {
|
|
32696
|
+
const value = env[ref.env]?.trim();
|
|
32697
|
+
if (value) return { value, source: `env:${ref.env}` };
|
|
32698
|
+
}
|
|
32699
|
+
if (ref.op) {
|
|
32700
|
+
const value = opRead(ref.op, env).trim();
|
|
32701
|
+
if (!value || value.split(/\r?\n/).length !== 1) {
|
|
32702
|
+
throw new CloudTokenError("cloud_token_command_failed", `op read did not print a single token for ${ref.op}`);
|
|
32703
|
+
}
|
|
32704
|
+
return { value, source: `op:${ref.op}` };
|
|
32705
|
+
}
|
|
32706
|
+
return void 0;
|
|
32707
|
+
}
|
|
32708
|
+
function keySourceFor(input) {
|
|
32709
|
+
const ref = input.endpoint?.key;
|
|
32710
|
+
if (input.mode === "local" && input.env.KXM_AUTH_TOKEN?.trim()) return "env:KXM_AUTH_TOKEN";
|
|
32711
|
+
if (ref?.env && input.env[ref.env]?.trim()) return `env:${ref.env}`;
|
|
32712
|
+
if (ref?.op) return `op:${ref.op}`;
|
|
32713
|
+
if (ref?.env) return `env:${ref.env}`;
|
|
32714
|
+
if (input.mode === "cloud") {
|
|
32715
|
+
if (input.binding?.tokenEnv) return `env:${input.binding.tokenEnv}`;
|
|
32716
|
+
if (input.binding?.tokenCommand) {
|
|
32717
|
+
const op = opReferenceFromTokenCommand(input.binding.tokenCommand);
|
|
32718
|
+
return op ? `op:${op}` : "command";
|
|
32719
|
+
}
|
|
32720
|
+
return "missing";
|
|
32721
|
+
}
|
|
32722
|
+
if (input.hasSavedProjectToken?.(input.project)) return "hub-env";
|
|
32723
|
+
return "missing";
|
|
32724
|
+
}
|
|
32725
|
+
function describeHubConnection(cwd, env = process.env, hooks = {}) {
|
|
32726
|
+
const settings = loadHubSettings(cwd, env);
|
|
32727
|
+
const binding = activeBinding(env);
|
|
32728
|
+
const mode = settings.mode ?? (binding?.cloud ? "cloud" : "local");
|
|
32729
|
+
const modeSource = settings.mode ? "config" : binding?.cloud ? "binding" : "default";
|
|
32730
|
+
const endpoint = endpointFor(mode, settings);
|
|
32731
|
+
const fromEnv = env.KXM_SERVER_URL?.trim();
|
|
32732
|
+
const fromConfig = endpoint?.url?.trim();
|
|
32733
|
+
const fromBinding = binding?.url;
|
|
32734
|
+
let url = "http://127.0.0.1:7331";
|
|
32735
|
+
let urlSource = "default";
|
|
32736
|
+
if (fromEnv) {
|
|
32737
|
+
url = fromEnv.replace(/\/$/, "");
|
|
32738
|
+
urlSource = "env";
|
|
32739
|
+
} else if (fromConfig) {
|
|
32740
|
+
url = fromConfig.replace(/\/$/, "");
|
|
32741
|
+
urlSource = "config";
|
|
32742
|
+
} else if (fromBinding) {
|
|
32743
|
+
url = fromBinding;
|
|
32744
|
+
urlSource = "binding";
|
|
32745
|
+
}
|
|
32746
|
+
const identity = resolveProjectIdentity(cwd, env, hooks.explicitProject);
|
|
32747
|
+
const configuredCloudUrl = settings.cloud?.url ?? (binding?.cloud ? binding.url : void 0);
|
|
32748
|
+
let scope;
|
|
32749
|
+
if (mode === "cloud") {
|
|
32750
|
+
const override = fromEnv ? normalizeUrl(fromEnv) : void 0;
|
|
32751
|
+
const named = configuredCloudUrl ? normalizeUrl(configuredCloudUrl) : void 0;
|
|
32752
|
+
scope = override && named && override !== named ? hubBindingScope(url) : "remote";
|
|
32753
|
+
} else {
|
|
32754
|
+
scope = hubBindingScope(url);
|
|
32755
|
+
}
|
|
32756
|
+
return {
|
|
32757
|
+
...identity,
|
|
32758
|
+
mode,
|
|
32759
|
+
modeSource,
|
|
32760
|
+
url,
|
|
32761
|
+
urlSource,
|
|
32762
|
+
scope,
|
|
32763
|
+
...endpoint ? { endpoint } : {},
|
|
32764
|
+
...binding ? { binding } : {},
|
|
32765
|
+
keySource: keySourceFor({
|
|
32766
|
+
mode,
|
|
32767
|
+
env,
|
|
32768
|
+
...endpoint ? { endpoint } : {},
|
|
32769
|
+
...binding ? { binding } : {},
|
|
32770
|
+
project: identity.project,
|
|
32771
|
+
...hooks.hasSavedProjectToken ? { hasSavedProjectToken: hooks.hasSavedProjectToken } : {}
|
|
32772
|
+
})
|
|
32773
|
+
};
|
|
32774
|
+
}
|
|
32273
32775
|
|
|
32274
32776
|
// plugins/kxm/src/hub-env.ts
|
|
32275
32777
|
var HUB_ENV_SCHEMA = "kxm.hub-env.v1";
|
|
@@ -32283,27 +32785,27 @@ function resolveUserStateRoot2(env) {
|
|
|
32283
32785
|
const explicit = env.KXM_STATE_HOME?.trim();
|
|
32284
32786
|
if (explicit) {
|
|
32285
32787
|
if (!isAbsolute7(explicit)) throw new HubEnvError("local_state_root_not_absolute");
|
|
32286
|
-
return
|
|
32788
|
+
return resolve12(explicit);
|
|
32287
32789
|
}
|
|
32288
32790
|
if (process.platform === "win32") {
|
|
32289
32791
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
32290
|
-
const base2 = localAppData && isAbsolute7(localAppData) ? localAppData :
|
|
32291
|
-
return
|
|
32792
|
+
const base2 = localAppData && isAbsolute7(localAppData) ? localAppData : join21(homedir4(), "AppData", "Local");
|
|
32793
|
+
return resolve12(base2, "KXM");
|
|
32292
32794
|
}
|
|
32293
|
-
if (process.platform === "darwin") return
|
|
32795
|
+
if (process.platform === "darwin") return resolve12(homedir4(), "Library", "Application Support", "KXM");
|
|
32294
32796
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
32295
|
-
const base = xdgState && isAbsolute7(xdgState) ? xdgState :
|
|
32296
|
-
return
|
|
32797
|
+
const base = xdgState && isAbsolute7(xdgState) ? xdgState : join21(homedir4(), ".local", "state");
|
|
32798
|
+
return resolve12(base, "kxm");
|
|
32297
32799
|
}
|
|
32298
32800
|
function hubEnvFile(env = process.env) {
|
|
32299
|
-
return
|
|
32801
|
+
return join21(resolveUserStateRoot2(env), "hub-env.json");
|
|
32300
32802
|
}
|
|
32301
32803
|
function readHubEnvRecord(env = process.env) {
|
|
32302
32804
|
const file = hubEnvFile(env);
|
|
32303
|
-
if (!
|
|
32805
|
+
if (!existsSync18(file)) return void 0;
|
|
32304
32806
|
let parsed;
|
|
32305
32807
|
try {
|
|
32306
|
-
parsed = JSON.parse(
|
|
32808
|
+
parsed = JSON.parse(readFileSync16(file, "utf8"));
|
|
32307
32809
|
} catch (error) {
|
|
32308
32810
|
throw new HubEnvError(`hub env file is malformed at ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
32309
32811
|
}
|
|
@@ -32335,31 +32837,31 @@ function readHubEnvRecord(env = process.env) {
|
|
|
32335
32837
|
...record2.projectTokens !== void 0 ? { projectTokens: record2.projectTokens } : {}
|
|
32336
32838
|
};
|
|
32337
32839
|
}
|
|
32338
|
-
function
|
|
32339
|
-
|
|
32340
|
-
|
|
32341
|
-
|
|
32342
|
-
|
|
32343
|
-
|
|
32344
|
-
|
|
32345
|
-
|
|
32346
|
-
|
|
32347
|
-
|
|
32348
|
-
throw error;
|
|
32349
|
-
}
|
|
32840
|
+
function cloudModeToken(cwd, env, explicitProject, opRead) {
|
|
32841
|
+
const connection = describeHubConnection(cwd, env, explicitProject === void 0 ? {} : { explicitProject });
|
|
32842
|
+
if (connection.mode !== "cloud") return void 0;
|
|
32843
|
+
const fromConfig = resolveKeyReference(connection.endpoint?.key, env, opRead);
|
|
32844
|
+
if (fromConfig) return fromConfig.value;
|
|
32845
|
+
if (connection.binding?.cloud) return resolveCloudHubToken(connection.binding, env);
|
|
32846
|
+
throw new CloudTokenError(
|
|
32847
|
+
"cloud_token_missing",
|
|
32848
|
+
"cloud hub token is missing; the local hub-env token was not used"
|
|
32849
|
+
);
|
|
32350
32850
|
}
|
|
32351
|
-
function resolveClientHubAuthToken(env, project) {
|
|
32352
|
-
const cloud =
|
|
32353
|
-
if (cloud) return
|
|
32851
|
+
function resolveClientHubAuthToken(env, project, cwd = process.cwd(), opRead) {
|
|
32852
|
+
const cloud = cloudModeToken(cwd, env, void 0, opRead);
|
|
32853
|
+
if (cloud) return cloud;
|
|
32354
32854
|
const envToken = env.KXM_AUTH_TOKEN?.trim();
|
|
32355
32855
|
if (envToken) return envToken;
|
|
32856
|
+
const fromConfig = resolveKeyReference(describeHubConnection(cwd, env).endpoint?.key, env, opRead);
|
|
32857
|
+
if (fromConfig) return fromConfig.value;
|
|
32356
32858
|
const record2 = readHubEnvRecord(env);
|
|
32357
32859
|
return record2?.projectTokens?.[project]?.trim() || record2?.authToken?.trim() || void 0;
|
|
32358
32860
|
}
|
|
32359
32861
|
|
|
32360
32862
|
// plugins/kxm/src/logger.ts
|
|
32361
|
-
import { appendFileSync, existsSync as
|
|
32362
|
-
import { dirname as
|
|
32863
|
+
import { appendFileSync, existsSync as existsSync19, mkdirSync as mkdirSync9, renameSync as renameSync4, statSync as statSync5, unlinkSync as unlinkSync2 } from "node:fs";
|
|
32864
|
+
import { dirname as dirname12 } from "node:path";
|
|
32363
32865
|
var LOG_LEVEL_PRIORITY = {
|
|
32364
32866
|
debug: 10,
|
|
32365
32867
|
info: 20,
|
|
@@ -32396,7 +32898,7 @@ function redactLogValue(val, key) {
|
|
|
32396
32898
|
function rotateLogFiles(filePath, maxFiles) {
|
|
32397
32899
|
for (let i = maxFiles; i >= 1; i--) {
|
|
32398
32900
|
const current = `${filePath}.${i}`;
|
|
32399
|
-
if (
|
|
32901
|
+
if (existsSync19(current)) {
|
|
32400
32902
|
if (i >= maxFiles) {
|
|
32401
32903
|
try {
|
|
32402
32904
|
unlinkSync2(current);
|
|
@@ -32410,7 +32912,7 @@ function rotateLogFiles(filePath, maxFiles) {
|
|
|
32410
32912
|
}
|
|
32411
32913
|
}
|
|
32412
32914
|
}
|
|
32413
|
-
if (
|
|
32915
|
+
if (existsSync19(filePath)) {
|
|
32414
32916
|
try {
|
|
32415
32917
|
renameSync4(filePath, `${filePath}.1`);
|
|
32416
32918
|
} catch {
|
|
@@ -32427,7 +32929,7 @@ function createLogger(options) {
|
|
|
32427
32929
|
const shouldStdout = options.stdout ?? !isDaemon;
|
|
32428
32930
|
const correlationDefaults = options.correlation ?? {};
|
|
32429
32931
|
let currentSize = 0;
|
|
32430
|
-
if (filePath &&
|
|
32932
|
+
if (filePath && existsSync19(filePath)) {
|
|
32431
32933
|
try {
|
|
32432
32934
|
currentSize = statSync5(filePath).size;
|
|
32433
32935
|
} catch {
|
|
@@ -32465,7 +32967,7 @@ function createLogger(options) {
|
|
|
32465
32967
|
currentSize = 0;
|
|
32466
32968
|
}
|
|
32467
32969
|
try {
|
|
32468
|
-
|
|
32970
|
+
mkdirSync9(dirname12(filePath), { recursive: true });
|
|
32469
32971
|
appendFileSync(filePath, line, { encoding: "utf8", mode: 384 });
|
|
32470
32972
|
currentSize += lineBytes;
|
|
32471
32973
|
} catch {
|
|
@@ -32508,13 +33010,13 @@ function createLogger(options) {
|
|
|
32508
33010
|
|
|
32509
33011
|
// plugins/kxm/src/runtime-supervisor.ts
|
|
32510
33012
|
function kxmSupervisorTokenFile(paths) {
|
|
32511
|
-
return
|
|
33013
|
+
return join22(paths.runtimeDir, "supervisor.token");
|
|
32512
33014
|
}
|
|
32513
33015
|
function publishKxmSupervisorToken(paths, token) {
|
|
32514
33016
|
const file = kxmSupervisorTokenFile(paths);
|
|
32515
|
-
|
|
33017
|
+
mkdirSync10(dirname13(file), { recursive: true, mode: 448 });
|
|
32516
33018
|
const temp = `${file}.${process.pid}.tmp`;
|
|
32517
|
-
|
|
33019
|
+
writeFileSync10(temp, `${token}
|
|
32518
33020
|
`, { encoding: "utf8", mode: 384 });
|
|
32519
33021
|
try {
|
|
32520
33022
|
chmodSync2(temp, 384);
|
|
@@ -32536,7 +33038,7 @@ function readKxmSupervisorToken(paths) {
|
|
|
32536
33038
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
32537
33039
|
throw runtimeError("runtime_path_invalid", file, "supervisor token file must be a regular file, not a link");
|
|
32538
33040
|
}
|
|
32539
|
-
const token =
|
|
33041
|
+
const token = readFileSync17(file, "utf8").trim();
|
|
32540
33042
|
return token.length >= 32 ? token : void 0;
|
|
32541
33043
|
}
|
|
32542
33044
|
function processAlive(pid) {
|
|
@@ -32550,16 +33052,16 @@ function processAlive(pid) {
|
|
|
32550
33052
|
var HEARTBEAT_STALE_MS = 15e3;
|
|
32551
33053
|
var SUPERVISOR_ERROR_MAX_AGE_MS = 3e4;
|
|
32552
33054
|
function supervisorErrorFile(paths) {
|
|
32553
|
-
return
|
|
33055
|
+
return join22(paths.runtimeDir, "supervisor.error");
|
|
32554
33056
|
}
|
|
32555
33057
|
function clearSupervisorError(paths) {
|
|
32556
33058
|
const file = supervisorErrorFile(paths);
|
|
32557
|
-
if (
|
|
33059
|
+
if (existsSync20(file)) rmSync4(file, { force: true });
|
|
32558
33060
|
}
|
|
32559
33061
|
function recordSupervisorError(paths, message) {
|
|
32560
33062
|
try {
|
|
32561
|
-
|
|
32562
|
-
|
|
33063
|
+
mkdirSync10(paths.runtimeDir, { recursive: true, mode: 448 });
|
|
33064
|
+
writeFileSync10(supervisorErrorFile(paths), `${message}
|
|
32563
33065
|
`, { encoding: "utf8", mode: 384 });
|
|
32564
33066
|
} catch {
|
|
32565
33067
|
}
|
|
@@ -32571,7 +33073,7 @@ function readRecentSupervisorError(paths) {
|
|
|
32571
33073
|
const ageMs = Date.now() - stat.mtimeMs;
|
|
32572
33074
|
if (ageMs > SUPERVISOR_ERROR_MAX_AGE_MS) return void 0;
|
|
32573
33075
|
try {
|
|
32574
|
-
return
|
|
33076
|
+
return readFileSync17(file, "utf8").trim();
|
|
32575
33077
|
} catch {
|
|
32576
33078
|
return void 0;
|
|
32577
33079
|
}
|
|
@@ -32610,7 +33112,7 @@ function supervisorStatusOf(record2) {
|
|
|
32610
33112
|
};
|
|
32611
33113
|
}
|
|
32612
33114
|
function kxmSupervisorStatus(paths, options = {}) {
|
|
32613
|
-
if (!
|
|
33115
|
+
if (!existsSync20(paths.registryDb)) return { running: false };
|
|
32614
33116
|
if (options.readOnly) {
|
|
32615
33117
|
const database = openReadOnlyDatabase(paths.registryDb);
|
|
32616
33118
|
try {
|
|
@@ -32676,7 +33178,7 @@ async function ensureKxmSupervisor(options = {}) {
|
|
|
32676
33178
|
throw runtimeError("runtime_supervisor_unreachable", paths.registryDb, `runtime supervisor pid ${status.pid} is registered as running but cannot be probed`);
|
|
32677
33179
|
}
|
|
32678
33180
|
clearSupervisorError(paths);
|
|
32679
|
-
const scriptPath =
|
|
33181
|
+
const scriptPath = join22(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
|
|
32680
33182
|
const spawnImpl = options.spawnImpl ?? ((script, env) => {
|
|
32681
33183
|
const child = spawn3(process.execPath, [script], {
|
|
32682
33184
|
detached: true,
|
|
@@ -32761,8 +33263,8 @@ async function waitForDriveSessions(settled, graceMs) {
|
|
|
32761
33263
|
try {
|
|
32762
33264
|
await Promise.race([
|
|
32763
33265
|
Promise.allSettled(settled),
|
|
32764
|
-
new Promise((
|
|
32765
|
-
timeout = setTimeout(
|
|
33266
|
+
new Promise((resolve15) => {
|
|
33267
|
+
timeout = setTimeout(resolve15, graceMs);
|
|
32766
33268
|
timeout.unref?.();
|
|
32767
33269
|
})
|
|
32768
33270
|
]);
|
|
@@ -32899,7 +33401,7 @@ function syncFailureText(error) {
|
|
|
32899
33401
|
return `${code ? `${code}: ` : ""}${message}`.replace(/(kxm_[A-Za-z0-9_]+|[A-Za-z0-9._-]{40,})/g, "[redacted]").slice(0, 300);
|
|
32900
33402
|
}
|
|
32901
33403
|
function runtimeSupervisorLogFile(paths) {
|
|
32902
|
-
return
|
|
33404
|
+
return join22(paths.runtimeDir, "logs", "kxm-runtime.jsonl");
|
|
32903
33405
|
}
|
|
32904
33406
|
async function startKxmRuntimeSupervisor(options = {}) {
|
|
32905
33407
|
const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -32915,8 +33417,8 @@ async function startKxmRuntimeSupervisor(options = {}) {
|
|
|
32915
33417
|
}
|
|
32916
33418
|
}
|
|
32917
33419
|
async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now, env) {
|
|
32918
|
-
|
|
32919
|
-
|
|
33420
|
+
mkdirSync10(paths.runtimeDir, { recursive: true, mode: 448 });
|
|
33421
|
+
mkdirSync10(paths.projectsDir, { recursive: true, mode: 448 });
|
|
32920
33422
|
const logger = createLogger({
|
|
32921
33423
|
component: "runtime",
|
|
32922
33424
|
path: runtimeSupervisorLogFile(paths),
|
|
@@ -33028,8 +33530,8 @@ async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now, e
|
|
|
33028
33530
|
openRunIds = unsettledRunIds(existing2);
|
|
33029
33531
|
} else {
|
|
33030
33532
|
const registration = registry.projectByRoot(projectRoot);
|
|
33031
|
-
const eventsPath =
|
|
33032
|
-
if (registration &&
|
|
33533
|
+
const eventsPath = join22(paths.projectsDir, registration?.projectKey ?? projectRuntimeKey(projectRoot), "run-events.db");
|
|
33534
|
+
if (registration && existsSync20(eventsPath)) {
|
|
33033
33535
|
const store = new KxmRunEventStore(eventsPath);
|
|
33034
33536
|
try {
|
|
33035
33537
|
openRunIds = store.runsForProject(registration.projectId, 1e4).filter((run) => !SETTLED_RUN_STATUS.has(run.status)).map((run) => run.runId);
|
|
@@ -33545,7 +34047,7 @@ function handoffSuffix(handoff) {
|
|
|
33545
34047
|
|
|
33546
34048
|
// plugins/kxm/src/pi-producer.ts
|
|
33547
34049
|
import { spawn as spawn4 } from "node:child_process";
|
|
33548
|
-
import { join as
|
|
34050
|
+
import { join as join23 } from "node:path";
|
|
33549
34051
|
import { StringDecoder } from "node:string_decoder";
|
|
33550
34052
|
function formatPiSessionKey(params) {
|
|
33551
34053
|
if (params.agentId === "coordinator") {
|
|
@@ -33761,8 +34263,8 @@ var PiSession = class {
|
|
|
33761
34263
|
}
|
|
33762
34264
|
const id = `cmd_${++this.commandCounter}`;
|
|
33763
34265
|
const payload = { ...command, id };
|
|
33764
|
-
return new Promise((
|
|
33765
|
-
this.pendingCommands.set(id, { resolve:
|
|
34266
|
+
return new Promise((resolve15, reject) => {
|
|
34267
|
+
this.pendingCommands.set(id, { resolve: resolve15, reject });
|
|
33766
34268
|
try {
|
|
33767
34269
|
this.process.stdin.write(JSON.stringify(payload) + "\n");
|
|
33768
34270
|
} catch (err) {
|
|
@@ -33782,7 +34284,7 @@ var PiSession = class {
|
|
|
33782
34284
|
return { outcome: "cancelled", text: "aborted", usage: {} };
|
|
33783
34285
|
}
|
|
33784
34286
|
this.status = "busy";
|
|
33785
|
-
return new Promise((
|
|
34287
|
+
return new Promise((resolve15, reject) => {
|
|
33786
34288
|
let signalCleanup;
|
|
33787
34289
|
if (signal) {
|
|
33788
34290
|
const onAbort = () => {
|
|
@@ -33796,7 +34298,7 @@ var PiSession = class {
|
|
|
33796
34298
|
signalCleanup = () => signal.removeEventListener("abort", onAbort);
|
|
33797
34299
|
}
|
|
33798
34300
|
this.activePrompt = {
|
|
33799
|
-
resolve:
|
|
34301
|
+
resolve: resolve15,
|
|
33800
34302
|
reject,
|
|
33801
34303
|
allowedOutcomes,
|
|
33802
34304
|
text: "",
|
|
@@ -33919,7 +34421,7 @@ function createKxmPiProducer(options = {}) {
|
|
|
33919
34421
|
const args = ["--mode", "rpc", "--name", displayName];
|
|
33920
34422
|
if (options.sessionDir) {
|
|
33921
34423
|
const safeDirName = key.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
33922
|
-
args.push("--session-dir",
|
|
34424
|
+
args.push("--session-dir", join23(options.sessionDir, request.runId, safeDirName));
|
|
33923
34425
|
}
|
|
33924
34426
|
if (model) {
|
|
33925
34427
|
args.push("--model", model);
|
|
@@ -34048,8 +34550,8 @@ function createKxmPiProducer(options = {}) {
|
|
|
34048
34550
|
|
|
34049
34551
|
// plugins/kxm/src/improve.ts
|
|
34050
34552
|
import { createHash as createHash17 } from "node:crypto";
|
|
34051
|
-
import { existsSync as
|
|
34052
|
-
import { join as
|
|
34553
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "node:fs";
|
|
34554
|
+
import { join as join24, relative as relative5, resolve as resolve13 } from "node:path";
|
|
34053
34555
|
var CANDIDATE_SCHEMA = "kxm.candidate.v1";
|
|
34054
34556
|
var IMPROVEMENT_REPORT_SCHEMA = "kxm.improvement-report.v2";
|
|
34055
34557
|
var IMPROVEMENT_REPORT_V1_SCHEMA = "kxm.improvement-report.v1";
|
|
@@ -34305,8 +34807,8 @@ function groupRoutingRecords(records, options = {}) {
|
|
|
34305
34807
|
}).map((entry) => entry.row);
|
|
34306
34808
|
}
|
|
34307
34809
|
function buildImprovementReport(records, options = {}) {
|
|
34308
|
-
const projectRoot = options.projectRoot ?
|
|
34309
|
-
const candidatesDir = options.candidatesDir ?
|
|
34810
|
+
const projectRoot = options.projectRoot ? resolve13(options.projectRoot) : process.cwd();
|
|
34811
|
+
const candidatesDir = options.candidatesDir ? resolve13(options.candidatesDir) : join24(projectRoot, ".kxm", "candidates");
|
|
34310
34812
|
const promotionPolicy = options.promotionPolicy ?? "manual_pr";
|
|
34311
34813
|
const groups = groupRoutingRecords(records, options);
|
|
34312
34814
|
const candidates = [];
|
|
@@ -34320,7 +34822,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
34320
34822
|
group.workflowId
|
|
34321
34823
|
);
|
|
34322
34824
|
const diffFileName = `${group.candidateId}.diff`;
|
|
34323
|
-
const diffFilePath =
|
|
34825
|
+
const diffFilePath = join24(candidatesDir, diffFileName);
|
|
34324
34826
|
const relDiffPath = relative5(projectRoot, diffFilePath).replace(/\\/g, "/");
|
|
34325
34827
|
const candidate = {
|
|
34326
34828
|
schema: CANDIDATE_SCHEMA,
|
|
@@ -34342,12 +34844,12 @@ function buildImprovementReport(records, options = {}) {
|
|
|
34342
34844
|
createdAt: nowIso()
|
|
34343
34845
|
};
|
|
34344
34846
|
if (!options.dryRun) {
|
|
34345
|
-
if (!
|
|
34346
|
-
|
|
34847
|
+
if (!existsSync21(candidatesDir)) {
|
|
34848
|
+
mkdirSync11(candidatesDir, { recursive: true });
|
|
34347
34849
|
}
|
|
34348
|
-
|
|
34349
|
-
const jsonFilePath =
|
|
34350
|
-
|
|
34850
|
+
writeFileSync11(diffFilePath, diff, "utf8");
|
|
34851
|
+
const jsonFilePath = join24(candidatesDir, `${group.candidateId}.json`);
|
|
34852
|
+
writeFileSync11(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
|
|
34351
34853
|
}
|
|
34352
34854
|
candidates.push(candidate);
|
|
34353
34855
|
}
|
|
@@ -34377,10 +34879,10 @@ function buildImprovementReport(records, options = {}) {
|
|
|
34377
34879
|
}
|
|
34378
34880
|
function writeImprovementReport(improvementsDir, report, dryRun = false) {
|
|
34379
34881
|
const stamp = report.createdAt.replace(/[:.]/g, "-");
|
|
34380
|
-
const path =
|
|
34882
|
+
const path = join24(improvementsDir, `${stamp}.json`);
|
|
34381
34883
|
if (!dryRun) {
|
|
34382
|
-
|
|
34383
|
-
|
|
34884
|
+
mkdirSync11(improvementsDir, { recursive: true });
|
|
34885
|
+
writeFileSync11(path, `${JSON.stringify(report, null, 2)}
|
|
34384
34886
|
`, { encoding: "utf8" });
|
|
34385
34887
|
}
|
|
34386
34888
|
return path;
|
|
@@ -35047,8 +35549,8 @@ Instructions for Operator:
|
|
|
35047
35549
|
|
|
35048
35550
|
// plugins/kxm/src/modes.ts
|
|
35049
35551
|
var import_yaml13 = __toESM(require_dist(), 1);
|
|
35050
|
-
import { existsSync as
|
|
35051
|
-
import { join as
|
|
35552
|
+
import { existsSync as existsSync22, readFileSync as readFileSync19 } from "node:fs";
|
|
35553
|
+
import { join as join25 } from "node:path";
|
|
35052
35554
|
var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
35053
35555
|
schema: "kxm.modes.v1",
|
|
35054
35556
|
majorModes: {
|
|
@@ -35111,12 +35613,12 @@ function loadModesConfig(projectRoot) {
|
|
|
35111
35613
|
if (!projectRoot) {
|
|
35112
35614
|
return DEFAULT_MODES_CONFIG;
|
|
35113
35615
|
}
|
|
35114
|
-
const modesPath =
|
|
35115
|
-
if (!
|
|
35616
|
+
const modesPath = join25(projectRoot, ".kxm", "modes.yaml");
|
|
35617
|
+
if (!existsSync22(modesPath)) {
|
|
35116
35618
|
return DEFAULT_MODES_CONFIG;
|
|
35117
35619
|
}
|
|
35118
35620
|
try {
|
|
35119
|
-
const raw =
|
|
35621
|
+
const raw = readFileSync19(modesPath, "utf8");
|
|
35120
35622
|
const parsed = (0, import_yaml13.parse)(raw);
|
|
35121
35623
|
if (parsed && parsed.schema === "kxm.modes.v1" && parsed.majorModes) {
|
|
35122
35624
|
return {
|
|
@@ -35202,11 +35704,11 @@ function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog
|
|
|
35202
35704
|
estimatedTokens: estimateTokens(baseSystemPromptChars)
|
|
35203
35705
|
});
|
|
35204
35706
|
for (const relPath of resolved.contextFiles) {
|
|
35205
|
-
const fullPath =
|
|
35707
|
+
const fullPath = join25(projectRoot, relPath);
|
|
35206
35708
|
let chars = 0;
|
|
35207
|
-
if (
|
|
35709
|
+
if (existsSync22(fullPath)) {
|
|
35208
35710
|
try {
|
|
35209
|
-
chars =
|
|
35711
|
+
chars = readFileSync19(fullPath, "utf8").length;
|
|
35210
35712
|
} catch {
|
|
35211
35713
|
chars = 0;
|
|
35212
35714
|
}
|
|
@@ -35337,10 +35839,10 @@ ${divider}
|
|
|
35337
35839
|
}
|
|
35338
35840
|
|
|
35339
35841
|
// plugins/kxm/src/ssh-remote.ts
|
|
35340
|
-
import { spawnSync as
|
|
35341
|
-
import { existsSync as
|
|
35342
|
-
import { homedir as
|
|
35343
|
-
import { join as
|
|
35842
|
+
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
35843
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync12, readFileSync as readFileSync20, readdirSync as readdirSync11, rmSync as rmSync5, statSync as statSync6 } from "node:fs";
|
|
35844
|
+
import { homedir as homedir5 } from "node:os";
|
|
35845
|
+
import { join as join26, resolve as resolve14 } from "node:path";
|
|
35344
35846
|
var MAX_SSH_OUTPUT_BYTES = 50 * 1024;
|
|
35345
35847
|
var MAX_SSH_OUTPUT_LINES = 2e3;
|
|
35346
35848
|
var DEFAULT_SOCKET_DIR = ".kxm/run/ssh-sockets";
|
|
@@ -35366,12 +35868,12 @@ function truncateSshOutput(raw) {
|
|
|
35366
35868
|
return { text, truncated };
|
|
35367
35869
|
}
|
|
35368
35870
|
function parseSshConfig(configPath) {
|
|
35369
|
-
const targetPath = configPath ??
|
|
35370
|
-
if (!
|
|
35871
|
+
const targetPath = configPath ?? join26(homedir5(), ".ssh", "config");
|
|
35872
|
+
if (!existsSync23(targetPath)) {
|
|
35371
35873
|
return [];
|
|
35372
35874
|
}
|
|
35373
35875
|
try {
|
|
35374
|
-
const content =
|
|
35876
|
+
const content = readFileSync20(targetPath, "utf-8");
|
|
35375
35877
|
const lines = content.split("\n");
|
|
35376
35878
|
const hosts = [];
|
|
35377
35879
|
let currentHosts = [];
|
|
@@ -35413,7 +35915,7 @@ function parseSshConfig(configPath) {
|
|
|
35413
35915
|
return [];
|
|
35414
35916
|
}
|
|
35415
35917
|
}
|
|
35416
|
-
function resolveSshHostG(host, execFn =
|
|
35918
|
+
function resolveSshHostG(host, execFn = spawnSync8) {
|
|
35417
35919
|
try {
|
|
35418
35920
|
const result = execFn("ssh", ["-G", host], { encoding: "utf-8" });
|
|
35419
35921
|
if (result.status !== 0 || !result.stdout) {
|
|
@@ -35448,15 +35950,15 @@ function resolveSshHostG(host, execFn = spawnSync7) {
|
|
|
35448
35950
|
}
|
|
35449
35951
|
}
|
|
35450
35952
|
function ensureSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
35451
|
-
const resolved =
|
|
35452
|
-
if (!
|
|
35453
|
-
|
|
35953
|
+
const resolved = resolve14(socketDir);
|
|
35954
|
+
if (!existsSync23(resolved)) {
|
|
35955
|
+
mkdirSync12(resolved, { recursive: true, mode: 448 });
|
|
35454
35956
|
}
|
|
35455
35957
|
return resolved;
|
|
35456
35958
|
}
|
|
35457
35959
|
function buildSshArgs(options) {
|
|
35458
35960
|
const socketDir = ensureSocketDir(options.socketDir ?? DEFAULT_SOCKET_DIR);
|
|
35459
|
-
const controlPath =
|
|
35961
|
+
const controlPath = join26(socketDir, "%C");
|
|
35460
35962
|
const persist2 = options.controlPersist ?? DEFAULT_CONTROL_PERSIST;
|
|
35461
35963
|
const args = [
|
|
35462
35964
|
"-o",
|
|
@@ -35479,9 +35981,9 @@ function buildSshArgs(options) {
|
|
|
35479
35981
|
args.push(options.host);
|
|
35480
35982
|
return args;
|
|
35481
35983
|
}
|
|
35482
|
-
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn =
|
|
35984
|
+
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync8) {
|
|
35483
35985
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
35484
|
-
const controlPath =
|
|
35986
|
+
const controlPath = join26(resolvedDir, "%C");
|
|
35485
35987
|
try {
|
|
35486
35988
|
const result = execFn("ssh", ["-O", "check", "-o", `ControlPath=${controlPath}`, host], {
|
|
35487
35989
|
encoding: "utf-8"
|
|
@@ -35491,9 +35993,9 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
35491
35993
|
return false;
|
|
35492
35994
|
}
|
|
35493
35995
|
}
|
|
35494
|
-
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn =
|
|
35996
|
+
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync8) {
|
|
35495
35997
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
35496
|
-
const controlPath =
|
|
35998
|
+
const controlPath = join26(resolvedDir, "%C");
|
|
35497
35999
|
try {
|
|
35498
36000
|
const result = execFn("ssh", ["-O", "stop", "-o", `ControlPath=${controlPath}`, host], {
|
|
35499
36001
|
encoding: "utf-8"
|
|
@@ -35509,7 +36011,7 @@ function pruneSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
|
35509
36011
|
try {
|
|
35510
36012
|
const entries = readdirSync11(resolvedDir);
|
|
35511
36013
|
for (const entry of entries) {
|
|
35512
|
-
const fullPath =
|
|
36014
|
+
const fullPath = join26(resolvedDir, entry);
|
|
35513
36015
|
try {
|
|
35514
36016
|
const stat = statSync6(fullPath);
|
|
35515
36017
|
if (stat.isSocket()) {
|
|
@@ -35525,7 +36027,7 @@ function pruneSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
|
35525
36027
|
}
|
|
35526
36028
|
function executeSshRun(params) {
|
|
35527
36029
|
const startTime = Date.now();
|
|
35528
|
-
const execSyncFn = params.execFn ??
|
|
36030
|
+
const execSyncFn = params.execFn ?? spawnSync8;
|
|
35529
36031
|
if (params.action === "info") {
|
|
35530
36032
|
if (params.host) {
|
|
35531
36033
|
const hostInfo = resolveSshHostG(params.host, execSyncFn);
|