@kontextmind/kxm 0.7.164 → 0.7.166
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 +25 -0
- package/README.md +2 -0
- package/docs/README.md +1 -0
- package/docs/architecture/inventory.md +4 -3
- package/docs/concepts/trust-model.md +1 -1
- package/docs/glossary.md +4 -4
- package/docs/operations/troubleshooting.md +4 -1
- package/docs/operations.md +208 -0
- package/docs/reference/cli-reference.md +12 -11
- package/docs/reference/config-reference.md +36 -11
- package/docs/reference/configuration.md +11 -1
- 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 +2 -2
- package/plugins/kxm/README.md +4 -4
- package/plugins/kxm/dist/claude-hook.js +511 -56
- package/plugins/kxm/dist/cli.js +15661 -14775
- package/plugins/kxm/dist/extension.js +645 -133
- package/plugins/kxm/dist/mcp-server.js +8152 -81
- package/plugins/kxm/dist/runtime-supervisor.js +804 -155
- package/plugins/kxm/dist/runtime.js +851 -202
- package/plugins/kxm/dist/server.js +466 -58
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +17 -5
- package/plugins/kxm/src/cli/context-skills.ts +64 -10
- package/plugins/kxm/src/cli/hub.ts +192 -22
- package/plugins/kxm/src/cli/project.ts +7 -3
- package/plugins/kxm/src/cli/types.ts +14 -1
- package/plugins/kxm/src/cli/workflows.ts +12 -1
- package/plugins/kxm/src/cli.ts +63 -11
- package/plugins/kxm/src/config.ts +246 -3
- package/plugins/kxm/src/extension.ts +12 -7
- package/plugins/kxm/src/hub-autostart.ts +23 -0
- package/plugins/kxm/src/hub-binding.ts +182 -2
- package/plugins/kxm/src/hub-env.ts +132 -9
- package/plugins/kxm/src/hub-identity.ts +337 -0
- package/plugins/kxm/src/mcp-server.ts +17 -14
- package/plugins/kxm/src/project-name.ts +6 -20
- package/plugins/kxm/src/runtime-supervisor.ts +9 -3
- package/plugins/kxm/src/server.ts +22 -4
- package/plugins/kxm/src/tenant-status.ts +9 -2
- package/scripts/build-runtime.mjs +5 -0
- 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 {
|
|
@@ -32069,10 +32375,22 @@ var RuntimeHubClient = class {
|
|
|
32069
32375
|
};
|
|
32070
32376
|
|
|
32071
32377
|
// plugins/kxm/src/hub-binding.ts
|
|
32072
|
-
import {
|
|
32073
|
-
import {
|
|
32074
|
-
import {
|
|
32378
|
+
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
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";
|
|
32075
32382
|
var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
32383
|
+
var CloudTokenError = class extends Error {
|
|
32384
|
+
code;
|
|
32385
|
+
constructor(code, message) {
|
|
32386
|
+
super(message);
|
|
32387
|
+
this.name = "CloudTokenError";
|
|
32388
|
+
this.code = code;
|
|
32389
|
+
}
|
|
32390
|
+
};
|
|
32391
|
+
var TOKEN_ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
32392
|
+
var TOKEN_COMMAND_TIMEOUT_MS = 15e3;
|
|
32393
|
+
var TOKEN_COMMAND_MAX_BUFFER = 4096;
|
|
32076
32394
|
var HubBindingError = class extends Error {
|
|
32077
32395
|
constructor(message) {
|
|
32078
32396
|
super(message);
|
|
@@ -32083,20 +32401,20 @@ function resolveUserStateRoot(env) {
|
|
|
32083
32401
|
const explicit = env.KXM_STATE_HOME?.trim();
|
|
32084
32402
|
if (explicit) {
|
|
32085
32403
|
if (!isAbsolute6(explicit)) throw new HubBindingError("local_state_root_not_absolute");
|
|
32086
|
-
return
|
|
32404
|
+
return resolve10(explicit);
|
|
32087
32405
|
}
|
|
32088
32406
|
if (process.platform === "win32") {
|
|
32089
32407
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
32090
|
-
const base2 = localAppData && isAbsolute6(localAppData) ? localAppData :
|
|
32091
|
-
return
|
|
32408
|
+
const base2 = localAppData && isAbsolute6(localAppData) ? localAppData : join19(homedir3(), "AppData", "Local");
|
|
32409
|
+
return resolve10(base2, "KXM");
|
|
32092
32410
|
}
|
|
32093
|
-
if (process.platform === "darwin") return
|
|
32411
|
+
if (process.platform === "darwin") return resolve10(homedir3(), "Library", "Application Support", "KXM");
|
|
32094
32412
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
32095
|
-
const base = xdgState && isAbsolute6(xdgState) ? xdgState :
|
|
32096
|
-
return
|
|
32413
|
+
const base = xdgState && isAbsolute6(xdgState) ? xdgState : join19(homedir3(), ".local", "state");
|
|
32414
|
+
return resolve10(base, "kxm");
|
|
32097
32415
|
}
|
|
32098
32416
|
function hubBindingFile(env = process.env) {
|
|
32099
|
-
return
|
|
32417
|
+
return join19(resolveUserStateRoot(env), "hub-binding.json");
|
|
32100
32418
|
}
|
|
32101
32419
|
function validateHubUrl(raw) {
|
|
32102
32420
|
let parsed;
|
|
@@ -32110,16 +32428,109 @@ function validateHubUrl(raw) {
|
|
|
32110
32428
|
}
|
|
32111
32429
|
return parsed.href.replace(/\/$/, "");
|
|
32112
32430
|
}
|
|
32431
|
+
function splitTokenCommand(raw) {
|
|
32432
|
+
if (/[|&;<>$`\n\r]/.test(raw)) {
|
|
32433
|
+
throw new CloudTokenError(
|
|
32434
|
+
"cloud_token_command_invalid",
|
|
32435
|
+
"token command must be a program and arguments, not a shell pipeline"
|
|
32436
|
+
);
|
|
32437
|
+
}
|
|
32438
|
+
const args = [];
|
|
32439
|
+
let current = "";
|
|
32440
|
+
let quote;
|
|
32441
|
+
for (const ch of raw) {
|
|
32442
|
+
if (quote) {
|
|
32443
|
+
if (ch === quote) quote = void 0;
|
|
32444
|
+
else current += ch;
|
|
32445
|
+
continue;
|
|
32446
|
+
}
|
|
32447
|
+
if (ch === "'" || ch === '"') {
|
|
32448
|
+
quote = ch;
|
|
32449
|
+
continue;
|
|
32450
|
+
}
|
|
32451
|
+
if (ch === " " || ch === " ") {
|
|
32452
|
+
if (current.length > 0) {
|
|
32453
|
+
args.push(current);
|
|
32454
|
+
current = "";
|
|
32455
|
+
}
|
|
32456
|
+
continue;
|
|
32457
|
+
}
|
|
32458
|
+
current += ch;
|
|
32459
|
+
}
|
|
32460
|
+
if (quote) {
|
|
32461
|
+
throw new CloudTokenError("cloud_token_command_invalid", "token command has an unclosed quote");
|
|
32462
|
+
}
|
|
32463
|
+
if (current.length > 0) args.push(current);
|
|
32464
|
+
if (args.length === 0) {
|
|
32465
|
+
throw new CloudTokenError("cloud_token_command_invalid", "token command is empty");
|
|
32466
|
+
}
|
|
32467
|
+
return args;
|
|
32468
|
+
}
|
|
32469
|
+
function isCloudTokenEnvName(value) {
|
|
32470
|
+
return TOKEN_ENV_NAME.test(value);
|
|
32471
|
+
}
|
|
32472
|
+
function resolveCloudHubToken(binding, env = process.env) {
|
|
32473
|
+
if (!binding.cloud) {
|
|
32474
|
+
throw new CloudTokenError("cloud_token_missing", "cloud hub token is missing; the local hub-env token was not used");
|
|
32475
|
+
}
|
|
32476
|
+
if (binding.tokenEnv) {
|
|
32477
|
+
const value = env[binding.tokenEnv]?.trim();
|
|
32478
|
+
if (value) return value;
|
|
32479
|
+
}
|
|
32480
|
+
if (binding.tokenCommand) return runTokenCommand(binding.tokenCommand, env);
|
|
32481
|
+
const source = binding.tokenEnv ? `${binding.tokenEnv} is unset or empty` : "no token source is configured";
|
|
32482
|
+
throw new CloudTokenError(
|
|
32483
|
+
"cloud_token_missing",
|
|
32484
|
+
`cloud hub token is missing: ${source}; the local hub-env token was not used`
|
|
32485
|
+
);
|
|
32486
|
+
}
|
|
32487
|
+
function runTokenCommand(command, env) {
|
|
32488
|
+
const argv = splitTokenCommand(command);
|
|
32489
|
+
const [program, ...args] = argv;
|
|
32490
|
+
const result = spawnSync6(program, args, {
|
|
32491
|
+
encoding: "utf8",
|
|
32492
|
+
shell: false,
|
|
32493
|
+
timeout: TOKEN_COMMAND_TIMEOUT_MS,
|
|
32494
|
+
maxBuffer: TOKEN_COMMAND_MAX_BUFFER,
|
|
32495
|
+
env,
|
|
32496
|
+
windowsHide: true
|
|
32497
|
+
});
|
|
32498
|
+
if (result.error || result.status !== 0) {
|
|
32499
|
+
throw new CloudTokenError(
|
|
32500
|
+
"cloud_token_command_failed",
|
|
32501
|
+
"token command failed; the local hub-env token was not used"
|
|
32502
|
+
);
|
|
32503
|
+
}
|
|
32504
|
+
const stdout = result.stdout ?? "";
|
|
32505
|
+
if (stdout.trim().length === 0 || stdout.trim() !== stdout.trim().split(/\r?\n/)[0]) {
|
|
32506
|
+
throw new CloudTokenError(
|
|
32507
|
+
"cloud_token_command_failed",
|
|
32508
|
+
"token command did not print a single token; the local hub-env token was not used"
|
|
32509
|
+
);
|
|
32510
|
+
}
|
|
32511
|
+
return stdout.trim();
|
|
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
|
+
}
|
|
32113
32524
|
function isIsoTimestamp(value) {
|
|
32114
32525
|
if (Number.isNaN(Date.parse(value))) return false;
|
|
32115
32526
|
return value === new Date(value).toISOString();
|
|
32116
32527
|
}
|
|
32117
32528
|
function readHubBinding(env = process.env) {
|
|
32118
32529
|
const file = hubBindingFile(env);
|
|
32119
|
-
if (!
|
|
32530
|
+
if (!existsSync16(file)) return void 0;
|
|
32120
32531
|
let parsed;
|
|
32121
32532
|
try {
|
|
32122
|
-
parsed = JSON.parse(
|
|
32533
|
+
parsed = JSON.parse(readFileSync14(file, "utf8"));
|
|
32123
32534
|
} catch {
|
|
32124
32535
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
32125
32536
|
}
|
|
@@ -32128,7 +32539,9 @@ function readHubBinding(env = process.env) {
|
|
|
32128
32539
|
}
|
|
32129
32540
|
const row = parsed;
|
|
32130
32541
|
const keys = Object.keys(row);
|
|
32131
|
-
|
|
32542
|
+
const allowed = /* @__PURE__ */ new Set(["schema", "url", "boundAt", "cloud", "tokenEnv", "tokenCommand"]);
|
|
32543
|
+
const cloudish = keys.some((key) => key === "cloud" || key === "tokenEnv" || key === "tokenCommand");
|
|
32544
|
+
if (keys.some((key) => !allowed.has(key)) || !cloudish && keys.length !== 3 || row.schema !== HUB_BINDING_SCHEMA || typeof row.url !== "string" || typeof row.boundAt !== "string" || !isIsoTimestamp(row.boundAt)) {
|
|
32132
32545
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
32133
32546
|
}
|
|
32134
32547
|
let url;
|
|
@@ -32137,13 +32550,230 @@ function readHubBinding(env = process.env) {
|
|
|
32137
32550
|
} catch {
|
|
32138
32551
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
32139
32552
|
}
|
|
32140
|
-
return { schema: HUB_BINDING_SCHEMA, url, boundAt: row.boundAt };
|
|
32553
|
+
if (!cloudish) return { schema: HUB_BINDING_SCHEMA, url, boundAt: row.boundAt };
|
|
32554
|
+
if (row.cloud !== true) throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
32555
|
+
let tokenEnv;
|
|
32556
|
+
let tokenCommand;
|
|
32557
|
+
if (row.tokenEnv !== void 0) {
|
|
32558
|
+
if (typeof row.tokenEnv !== "string" || !isCloudTokenEnvName(row.tokenEnv)) {
|
|
32559
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
32560
|
+
}
|
|
32561
|
+
tokenEnv = row.tokenEnv;
|
|
32562
|
+
}
|
|
32563
|
+
if (row.tokenCommand !== void 0) {
|
|
32564
|
+
if (typeof row.tokenCommand !== "string") throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
32565
|
+
try {
|
|
32566
|
+
splitTokenCommand(row.tokenCommand);
|
|
32567
|
+
} catch {
|
|
32568
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
32569
|
+
}
|
|
32570
|
+
tokenCommand = row.tokenCommand;
|
|
32571
|
+
}
|
|
32572
|
+
if (!tokenEnv && !tokenCommand) throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
32573
|
+
return {
|
|
32574
|
+
schema: HUB_BINDING_SCHEMA,
|
|
32575
|
+
url,
|
|
32576
|
+
boundAt: row.boundAt,
|
|
32577
|
+
cloud: true,
|
|
32578
|
+
...tokenEnv ? { tokenEnv } : {},
|
|
32579
|
+
...tokenCommand ? { tokenCommand } : {}
|
|
32580
|
+
};
|
|
32581
|
+
}
|
|
32582
|
+
|
|
32583
|
+
// plugins/kxm/src/hub-env.ts
|
|
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";
|
|
32587
|
+
|
|
32588
|
+
// plugins/kxm/src/hub-identity.ts
|
|
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
|
+
};
|
|
32141
32774
|
}
|
|
32142
32775
|
|
|
32143
32776
|
// plugins/kxm/src/hub-env.ts
|
|
32144
|
-
import { existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync14, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
|
|
32145
|
-
import { homedir as homedir3 } from "node:os";
|
|
32146
|
-
import { dirname as dirname9, isAbsolute as isAbsolute7, join as join19, resolve as resolve10 } from "node:path";
|
|
32147
32777
|
var HUB_ENV_SCHEMA = "kxm.hub-env.v1";
|
|
32148
32778
|
var HubEnvError = class extends Error {
|
|
32149
32779
|
constructor(message) {
|
|
@@ -32155,27 +32785,27 @@ function resolveUserStateRoot2(env) {
|
|
|
32155
32785
|
const explicit = env.KXM_STATE_HOME?.trim();
|
|
32156
32786
|
if (explicit) {
|
|
32157
32787
|
if (!isAbsolute7(explicit)) throw new HubEnvError("local_state_root_not_absolute");
|
|
32158
|
-
return
|
|
32788
|
+
return resolve12(explicit);
|
|
32159
32789
|
}
|
|
32160
32790
|
if (process.platform === "win32") {
|
|
32161
32791
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
32162
|
-
const base2 = localAppData && isAbsolute7(localAppData) ? localAppData :
|
|
32163
|
-
return
|
|
32792
|
+
const base2 = localAppData && isAbsolute7(localAppData) ? localAppData : join21(homedir4(), "AppData", "Local");
|
|
32793
|
+
return resolve12(base2, "KXM");
|
|
32164
32794
|
}
|
|
32165
|
-
if (process.platform === "darwin") return
|
|
32795
|
+
if (process.platform === "darwin") return resolve12(homedir4(), "Library", "Application Support", "KXM");
|
|
32166
32796
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
32167
|
-
const base = xdgState && isAbsolute7(xdgState) ? xdgState :
|
|
32168
|
-
return
|
|
32797
|
+
const base = xdgState && isAbsolute7(xdgState) ? xdgState : join21(homedir4(), ".local", "state");
|
|
32798
|
+
return resolve12(base, "kxm");
|
|
32169
32799
|
}
|
|
32170
32800
|
function hubEnvFile(env = process.env) {
|
|
32171
|
-
return
|
|
32801
|
+
return join21(resolveUserStateRoot2(env), "hub-env.json");
|
|
32172
32802
|
}
|
|
32173
32803
|
function readHubEnvRecord(env = process.env) {
|
|
32174
32804
|
const file = hubEnvFile(env);
|
|
32175
|
-
if (!
|
|
32805
|
+
if (!existsSync18(file)) return void 0;
|
|
32176
32806
|
let parsed;
|
|
32177
32807
|
try {
|
|
32178
|
-
parsed = JSON.parse(
|
|
32808
|
+
parsed = JSON.parse(readFileSync16(file, "utf8"));
|
|
32179
32809
|
} catch (error) {
|
|
32180
32810
|
throw new HubEnvError(`hub env file is malformed at ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
32181
32811
|
}
|
|
@@ -32207,16 +32837,31 @@ function readHubEnvRecord(env = process.env) {
|
|
|
32207
32837
|
...record2.projectTokens !== void 0 ? { projectTokens: record2.projectTokens } : {}
|
|
32208
32838
|
};
|
|
32209
32839
|
}
|
|
32210
|
-
function
|
|
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
|
+
);
|
|
32850
|
+
}
|
|
32851
|
+
function resolveClientHubAuthToken(env, project, cwd = process.cwd(), opRead) {
|
|
32852
|
+
const cloud = cloudModeToken(cwd, env, void 0, opRead);
|
|
32853
|
+
if (cloud) return cloud;
|
|
32211
32854
|
const envToken = env.KXM_AUTH_TOKEN?.trim();
|
|
32212
32855
|
if (envToken) return envToken;
|
|
32856
|
+
const fromConfig = resolveKeyReference(describeHubConnection(cwd, env).endpoint?.key, env, opRead);
|
|
32857
|
+
if (fromConfig) return fromConfig.value;
|
|
32213
32858
|
const record2 = readHubEnvRecord(env);
|
|
32214
32859
|
return record2?.projectTokens?.[project]?.trim() || record2?.authToken?.trim() || void 0;
|
|
32215
32860
|
}
|
|
32216
32861
|
|
|
32217
32862
|
// plugins/kxm/src/logger.ts
|
|
32218
|
-
import { appendFileSync, existsSync as
|
|
32219
|
-
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";
|
|
32220
32865
|
var LOG_LEVEL_PRIORITY = {
|
|
32221
32866
|
debug: 10,
|
|
32222
32867
|
info: 20,
|
|
@@ -32253,7 +32898,7 @@ function redactLogValue(val, key) {
|
|
|
32253
32898
|
function rotateLogFiles(filePath, maxFiles) {
|
|
32254
32899
|
for (let i = maxFiles; i >= 1; i--) {
|
|
32255
32900
|
const current = `${filePath}.${i}`;
|
|
32256
|
-
if (
|
|
32901
|
+
if (existsSync19(current)) {
|
|
32257
32902
|
if (i >= maxFiles) {
|
|
32258
32903
|
try {
|
|
32259
32904
|
unlinkSync2(current);
|
|
@@ -32267,7 +32912,7 @@ function rotateLogFiles(filePath, maxFiles) {
|
|
|
32267
32912
|
}
|
|
32268
32913
|
}
|
|
32269
32914
|
}
|
|
32270
|
-
if (
|
|
32915
|
+
if (existsSync19(filePath)) {
|
|
32271
32916
|
try {
|
|
32272
32917
|
renameSync4(filePath, `${filePath}.1`);
|
|
32273
32918
|
} catch {
|
|
@@ -32284,7 +32929,7 @@ function createLogger(options) {
|
|
|
32284
32929
|
const shouldStdout = options.stdout ?? !isDaemon;
|
|
32285
32930
|
const correlationDefaults = options.correlation ?? {};
|
|
32286
32931
|
let currentSize = 0;
|
|
32287
|
-
if (filePath &&
|
|
32932
|
+
if (filePath && existsSync19(filePath)) {
|
|
32288
32933
|
try {
|
|
32289
32934
|
currentSize = statSync5(filePath).size;
|
|
32290
32935
|
} catch {
|
|
@@ -32322,7 +32967,7 @@ function createLogger(options) {
|
|
|
32322
32967
|
currentSize = 0;
|
|
32323
32968
|
}
|
|
32324
32969
|
try {
|
|
32325
|
-
|
|
32970
|
+
mkdirSync9(dirname12(filePath), { recursive: true });
|
|
32326
32971
|
appendFileSync(filePath, line, { encoding: "utf8", mode: 384 });
|
|
32327
32972
|
currentSize += lineBytes;
|
|
32328
32973
|
} catch {
|
|
@@ -32365,13 +33010,13 @@ function createLogger(options) {
|
|
|
32365
33010
|
|
|
32366
33011
|
// plugins/kxm/src/runtime-supervisor.ts
|
|
32367
33012
|
function kxmSupervisorTokenFile(paths) {
|
|
32368
|
-
return
|
|
33013
|
+
return join22(paths.runtimeDir, "supervisor.token");
|
|
32369
33014
|
}
|
|
32370
33015
|
function publishKxmSupervisorToken(paths, token) {
|
|
32371
33016
|
const file = kxmSupervisorTokenFile(paths);
|
|
32372
|
-
|
|
33017
|
+
mkdirSync10(dirname13(file), { recursive: true, mode: 448 });
|
|
32373
33018
|
const temp = `${file}.${process.pid}.tmp`;
|
|
32374
|
-
|
|
33019
|
+
writeFileSync10(temp, `${token}
|
|
32375
33020
|
`, { encoding: "utf8", mode: 384 });
|
|
32376
33021
|
try {
|
|
32377
33022
|
chmodSync2(temp, 384);
|
|
@@ -32393,7 +33038,7 @@ function readKxmSupervisorToken(paths) {
|
|
|
32393
33038
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
32394
33039
|
throw runtimeError("runtime_path_invalid", file, "supervisor token file must be a regular file, not a link");
|
|
32395
33040
|
}
|
|
32396
|
-
const token =
|
|
33041
|
+
const token = readFileSync17(file, "utf8").trim();
|
|
32397
33042
|
return token.length >= 32 ? token : void 0;
|
|
32398
33043
|
}
|
|
32399
33044
|
function processAlive(pid) {
|
|
@@ -32407,16 +33052,16 @@ function processAlive(pid) {
|
|
|
32407
33052
|
var HEARTBEAT_STALE_MS = 15e3;
|
|
32408
33053
|
var SUPERVISOR_ERROR_MAX_AGE_MS = 3e4;
|
|
32409
33054
|
function supervisorErrorFile(paths) {
|
|
32410
|
-
return
|
|
33055
|
+
return join22(paths.runtimeDir, "supervisor.error");
|
|
32411
33056
|
}
|
|
32412
33057
|
function clearSupervisorError(paths) {
|
|
32413
33058
|
const file = supervisorErrorFile(paths);
|
|
32414
|
-
if (
|
|
33059
|
+
if (existsSync20(file)) rmSync4(file, { force: true });
|
|
32415
33060
|
}
|
|
32416
33061
|
function recordSupervisorError(paths, message) {
|
|
32417
33062
|
try {
|
|
32418
|
-
|
|
32419
|
-
|
|
33063
|
+
mkdirSync10(paths.runtimeDir, { recursive: true, mode: 448 });
|
|
33064
|
+
writeFileSync10(supervisorErrorFile(paths), `${message}
|
|
32420
33065
|
`, { encoding: "utf8", mode: 384 });
|
|
32421
33066
|
} catch {
|
|
32422
33067
|
}
|
|
@@ -32428,7 +33073,7 @@ function readRecentSupervisorError(paths) {
|
|
|
32428
33073
|
const ageMs = Date.now() - stat.mtimeMs;
|
|
32429
33074
|
if (ageMs > SUPERVISOR_ERROR_MAX_AGE_MS) return void 0;
|
|
32430
33075
|
try {
|
|
32431
|
-
return
|
|
33076
|
+
return readFileSync17(file, "utf8").trim();
|
|
32432
33077
|
} catch {
|
|
32433
33078
|
return void 0;
|
|
32434
33079
|
}
|
|
@@ -32467,7 +33112,7 @@ function supervisorStatusOf(record2) {
|
|
|
32467
33112
|
};
|
|
32468
33113
|
}
|
|
32469
33114
|
function kxmSupervisorStatus(paths, options = {}) {
|
|
32470
|
-
if (!
|
|
33115
|
+
if (!existsSync20(paths.registryDb)) return { running: false };
|
|
32471
33116
|
if (options.readOnly) {
|
|
32472
33117
|
const database = openReadOnlyDatabase(paths.registryDb);
|
|
32473
33118
|
try {
|
|
@@ -32533,7 +33178,7 @@ async function ensureKxmSupervisor(options = {}) {
|
|
|
32533
33178
|
throw runtimeError("runtime_supervisor_unreachable", paths.registryDb, `runtime supervisor pid ${status.pid} is registered as running but cannot be probed`);
|
|
32534
33179
|
}
|
|
32535
33180
|
clearSupervisorError(paths);
|
|
32536
|
-
const scriptPath =
|
|
33181
|
+
const scriptPath = join22(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
|
|
32537
33182
|
const spawnImpl = options.spawnImpl ?? ((script, env) => {
|
|
32538
33183
|
const child = spawn3(process.execPath, [script], {
|
|
32539
33184
|
detached: true,
|
|
@@ -32618,8 +33263,8 @@ async function waitForDriveSessions(settled, graceMs) {
|
|
|
32618
33263
|
try {
|
|
32619
33264
|
await Promise.race([
|
|
32620
33265
|
Promise.allSettled(settled),
|
|
32621
|
-
new Promise((
|
|
32622
|
-
timeout = setTimeout(
|
|
33266
|
+
new Promise((resolve15) => {
|
|
33267
|
+
timeout = setTimeout(resolve15, graceMs);
|
|
32623
33268
|
timeout.unref?.();
|
|
32624
33269
|
})
|
|
32625
33270
|
]);
|
|
@@ -32756,7 +33401,7 @@ function syncFailureText(error) {
|
|
|
32756
33401
|
return `${code ? `${code}: ` : ""}${message}`.replace(/(kxm_[A-Za-z0-9_]+|[A-Za-z0-9._-]{40,})/g, "[redacted]").slice(0, 300);
|
|
32757
33402
|
}
|
|
32758
33403
|
function runtimeSupervisorLogFile(paths) {
|
|
32759
|
-
return
|
|
33404
|
+
return join22(paths.runtimeDir, "logs", "kxm-runtime.jsonl");
|
|
32760
33405
|
}
|
|
32761
33406
|
async function startKxmRuntimeSupervisor(options = {}) {
|
|
32762
33407
|
const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -32772,8 +33417,8 @@ async function startKxmRuntimeSupervisor(options = {}) {
|
|
|
32772
33417
|
}
|
|
32773
33418
|
}
|
|
32774
33419
|
async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now, env) {
|
|
32775
|
-
|
|
32776
|
-
|
|
33420
|
+
mkdirSync10(paths.runtimeDir, { recursive: true, mode: 448 });
|
|
33421
|
+
mkdirSync10(paths.projectsDir, { recursive: true, mode: 448 });
|
|
32777
33422
|
const logger = createLogger({
|
|
32778
33423
|
component: "runtime",
|
|
32779
33424
|
path: runtimeSupervisorLogFile(paths),
|
|
@@ -32789,8 +33434,12 @@ async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now, e
|
|
|
32789
33434
|
const contexts = /* @__PURE__ */ new Map();
|
|
32790
33435
|
const syncStatuses = /* @__PURE__ */ new Map();
|
|
32791
33436
|
const registerSyncCredentials = (context) => {
|
|
32792
|
-
|
|
32793
|
-
|
|
33437
|
+
try {
|
|
33438
|
+
const hubToken = resolveClientHubAuthToken(env, context.projectId);
|
|
33439
|
+
if (hubToken) context.eventStore.syncRedactor.register(hubToken);
|
|
33440
|
+
} catch (error) {
|
|
33441
|
+
if (!(error instanceof CloudTokenError)) throw error;
|
|
33442
|
+
}
|
|
32794
33443
|
for (const key of Object.keys(env)) {
|
|
32795
33444
|
if (key.startsWith("KXM_") && (key.endsWith("_TOKEN") || key.endsWith("_KEY")) || key.endsWith("_API_KEY") || key.endsWith("_SECRET")) {
|
|
32796
33445
|
const value = env[key]?.trim();
|
|
@@ -32881,8 +33530,8 @@ async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now, e
|
|
|
32881
33530
|
openRunIds = unsettledRunIds(existing2);
|
|
32882
33531
|
} else {
|
|
32883
33532
|
const registration = registry.projectByRoot(projectRoot);
|
|
32884
|
-
const eventsPath =
|
|
32885
|
-
if (registration &&
|
|
33533
|
+
const eventsPath = join22(paths.projectsDir, registration?.projectKey ?? projectRuntimeKey(projectRoot), "run-events.db");
|
|
33534
|
+
if (registration && existsSync20(eventsPath)) {
|
|
32886
33535
|
const store = new KxmRunEventStore(eventsPath);
|
|
32887
33536
|
try {
|
|
32888
33537
|
openRunIds = store.runsForProject(registration.projectId, 1e4).filter((run) => !SETTLED_RUN_STATUS.has(run.status)).map((run) => run.runId);
|
|
@@ -33398,7 +34047,7 @@ function handoffSuffix(handoff) {
|
|
|
33398
34047
|
|
|
33399
34048
|
// plugins/kxm/src/pi-producer.ts
|
|
33400
34049
|
import { spawn as spawn4 } from "node:child_process";
|
|
33401
|
-
import { join as
|
|
34050
|
+
import { join as join23 } from "node:path";
|
|
33402
34051
|
import { StringDecoder } from "node:string_decoder";
|
|
33403
34052
|
function formatPiSessionKey(params) {
|
|
33404
34053
|
if (params.agentId === "coordinator") {
|
|
@@ -33614,8 +34263,8 @@ var PiSession = class {
|
|
|
33614
34263
|
}
|
|
33615
34264
|
const id = `cmd_${++this.commandCounter}`;
|
|
33616
34265
|
const payload = { ...command, id };
|
|
33617
|
-
return new Promise((
|
|
33618
|
-
this.pendingCommands.set(id, { resolve:
|
|
34266
|
+
return new Promise((resolve15, reject) => {
|
|
34267
|
+
this.pendingCommands.set(id, { resolve: resolve15, reject });
|
|
33619
34268
|
try {
|
|
33620
34269
|
this.process.stdin.write(JSON.stringify(payload) + "\n");
|
|
33621
34270
|
} catch (err) {
|
|
@@ -33635,7 +34284,7 @@ var PiSession = class {
|
|
|
33635
34284
|
return { outcome: "cancelled", text: "aborted", usage: {} };
|
|
33636
34285
|
}
|
|
33637
34286
|
this.status = "busy";
|
|
33638
|
-
return new Promise((
|
|
34287
|
+
return new Promise((resolve15, reject) => {
|
|
33639
34288
|
let signalCleanup;
|
|
33640
34289
|
if (signal) {
|
|
33641
34290
|
const onAbort = () => {
|
|
@@ -33649,7 +34298,7 @@ var PiSession = class {
|
|
|
33649
34298
|
signalCleanup = () => signal.removeEventListener("abort", onAbort);
|
|
33650
34299
|
}
|
|
33651
34300
|
this.activePrompt = {
|
|
33652
|
-
resolve:
|
|
34301
|
+
resolve: resolve15,
|
|
33653
34302
|
reject,
|
|
33654
34303
|
allowedOutcomes,
|
|
33655
34304
|
text: "",
|
|
@@ -33772,7 +34421,7 @@ function createKxmPiProducer(options = {}) {
|
|
|
33772
34421
|
const args = ["--mode", "rpc", "--name", displayName];
|
|
33773
34422
|
if (options.sessionDir) {
|
|
33774
34423
|
const safeDirName = key.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
33775
|
-
args.push("--session-dir",
|
|
34424
|
+
args.push("--session-dir", join23(options.sessionDir, request.runId, safeDirName));
|
|
33776
34425
|
}
|
|
33777
34426
|
if (model) {
|
|
33778
34427
|
args.push("--model", model);
|
|
@@ -33901,8 +34550,8 @@ function createKxmPiProducer(options = {}) {
|
|
|
33901
34550
|
|
|
33902
34551
|
// plugins/kxm/src/improve.ts
|
|
33903
34552
|
import { createHash as createHash17 } from "node:crypto";
|
|
33904
|
-
import { existsSync as
|
|
33905
|
-
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";
|
|
33906
34555
|
var CANDIDATE_SCHEMA = "kxm.candidate.v1";
|
|
33907
34556
|
var IMPROVEMENT_REPORT_SCHEMA = "kxm.improvement-report.v2";
|
|
33908
34557
|
var IMPROVEMENT_REPORT_V1_SCHEMA = "kxm.improvement-report.v1";
|
|
@@ -34158,8 +34807,8 @@ function groupRoutingRecords(records, options = {}) {
|
|
|
34158
34807
|
}).map((entry) => entry.row);
|
|
34159
34808
|
}
|
|
34160
34809
|
function buildImprovementReport(records, options = {}) {
|
|
34161
|
-
const projectRoot = options.projectRoot ?
|
|
34162
|
-
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");
|
|
34163
34812
|
const promotionPolicy = options.promotionPolicy ?? "manual_pr";
|
|
34164
34813
|
const groups = groupRoutingRecords(records, options);
|
|
34165
34814
|
const candidates = [];
|
|
@@ -34173,7 +34822,7 @@ function buildImprovementReport(records, options = {}) {
|
|
|
34173
34822
|
group.workflowId
|
|
34174
34823
|
);
|
|
34175
34824
|
const diffFileName = `${group.candidateId}.diff`;
|
|
34176
|
-
const diffFilePath =
|
|
34825
|
+
const diffFilePath = join24(candidatesDir, diffFileName);
|
|
34177
34826
|
const relDiffPath = relative5(projectRoot, diffFilePath).replace(/\\/g, "/");
|
|
34178
34827
|
const candidate = {
|
|
34179
34828
|
schema: CANDIDATE_SCHEMA,
|
|
@@ -34195,12 +34844,12 @@ function buildImprovementReport(records, options = {}) {
|
|
|
34195
34844
|
createdAt: nowIso()
|
|
34196
34845
|
};
|
|
34197
34846
|
if (!options.dryRun) {
|
|
34198
|
-
if (!
|
|
34199
|
-
|
|
34847
|
+
if (!existsSync21(candidatesDir)) {
|
|
34848
|
+
mkdirSync11(candidatesDir, { recursive: true });
|
|
34200
34849
|
}
|
|
34201
|
-
|
|
34202
|
-
const jsonFilePath =
|
|
34203
|
-
|
|
34850
|
+
writeFileSync11(diffFilePath, diff, "utf8");
|
|
34851
|
+
const jsonFilePath = join24(candidatesDir, `${group.candidateId}.json`);
|
|
34852
|
+
writeFileSync11(jsonFilePath, JSON.stringify(candidate, null, 2) + "\n", "utf8");
|
|
34204
34853
|
}
|
|
34205
34854
|
candidates.push(candidate);
|
|
34206
34855
|
}
|
|
@@ -34230,10 +34879,10 @@ function buildImprovementReport(records, options = {}) {
|
|
|
34230
34879
|
}
|
|
34231
34880
|
function writeImprovementReport(improvementsDir, report, dryRun = false) {
|
|
34232
34881
|
const stamp = report.createdAt.replace(/[:.]/g, "-");
|
|
34233
|
-
const path =
|
|
34882
|
+
const path = join24(improvementsDir, `${stamp}.json`);
|
|
34234
34883
|
if (!dryRun) {
|
|
34235
|
-
|
|
34236
|
-
|
|
34884
|
+
mkdirSync11(improvementsDir, { recursive: true });
|
|
34885
|
+
writeFileSync11(path, `${JSON.stringify(report, null, 2)}
|
|
34237
34886
|
`, { encoding: "utf8" });
|
|
34238
34887
|
}
|
|
34239
34888
|
return path;
|
|
@@ -34899,9 +35548,9 @@ Instructions for Operator:
|
|
|
34899
35548
|
};
|
|
34900
35549
|
|
|
34901
35550
|
// plugins/kxm/src/modes.ts
|
|
34902
|
-
var
|
|
34903
|
-
import { existsSync as
|
|
34904
|
-
import { join as
|
|
35551
|
+
var import_yaml13 = __toESM(require_dist(), 1);
|
|
35552
|
+
import { existsSync as existsSync22, readFileSync as readFileSync19 } from "node:fs";
|
|
35553
|
+
import { join as join25 } from "node:path";
|
|
34905
35554
|
var DEFAULT_MODES_CONFIG = Object.freeze({
|
|
34906
35555
|
schema: "kxm.modes.v1",
|
|
34907
35556
|
majorModes: {
|
|
@@ -34964,13 +35613,13 @@ function loadModesConfig(projectRoot) {
|
|
|
34964
35613
|
if (!projectRoot) {
|
|
34965
35614
|
return DEFAULT_MODES_CONFIG;
|
|
34966
35615
|
}
|
|
34967
|
-
const modesPath =
|
|
34968
|
-
if (!
|
|
35616
|
+
const modesPath = join25(projectRoot, ".kxm", "modes.yaml");
|
|
35617
|
+
if (!existsSync22(modesPath)) {
|
|
34969
35618
|
return DEFAULT_MODES_CONFIG;
|
|
34970
35619
|
}
|
|
34971
35620
|
try {
|
|
34972
|
-
const raw =
|
|
34973
|
-
const parsed = (0,
|
|
35621
|
+
const raw = readFileSync19(modesPath, "utf8");
|
|
35622
|
+
const parsed = (0, import_yaml13.parse)(raw);
|
|
34974
35623
|
if (parsed && parsed.schema === "kxm.modes.v1" && parsed.majorModes) {
|
|
34975
35624
|
return {
|
|
34976
35625
|
schema: "kxm.modes.v1",
|
|
@@ -35055,11 +35704,11 @@ function calculatePromptFootprint(resolved, projectRoot = process.cwd(), catalog
|
|
|
35055
35704
|
estimatedTokens: estimateTokens(baseSystemPromptChars)
|
|
35056
35705
|
});
|
|
35057
35706
|
for (const relPath of resolved.contextFiles) {
|
|
35058
|
-
const fullPath =
|
|
35707
|
+
const fullPath = join25(projectRoot, relPath);
|
|
35059
35708
|
let chars = 0;
|
|
35060
|
-
if (
|
|
35709
|
+
if (existsSync22(fullPath)) {
|
|
35061
35710
|
try {
|
|
35062
|
-
chars =
|
|
35711
|
+
chars = readFileSync19(fullPath, "utf8").length;
|
|
35063
35712
|
} catch {
|
|
35064
35713
|
chars = 0;
|
|
35065
35714
|
}
|
|
@@ -35190,10 +35839,10 @@ ${divider}
|
|
|
35190
35839
|
}
|
|
35191
35840
|
|
|
35192
35841
|
// plugins/kxm/src/ssh-remote.ts
|
|
35193
|
-
import { spawnSync as
|
|
35194
|
-
import { existsSync as
|
|
35195
|
-
import { homedir as
|
|
35196
|
-
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";
|
|
35197
35846
|
var MAX_SSH_OUTPUT_BYTES = 50 * 1024;
|
|
35198
35847
|
var MAX_SSH_OUTPUT_LINES = 2e3;
|
|
35199
35848
|
var DEFAULT_SOCKET_DIR = ".kxm/run/ssh-sockets";
|
|
@@ -35219,12 +35868,12 @@ function truncateSshOutput(raw) {
|
|
|
35219
35868
|
return { text, truncated };
|
|
35220
35869
|
}
|
|
35221
35870
|
function parseSshConfig(configPath) {
|
|
35222
|
-
const targetPath = configPath ??
|
|
35223
|
-
if (!
|
|
35871
|
+
const targetPath = configPath ?? join26(homedir5(), ".ssh", "config");
|
|
35872
|
+
if (!existsSync23(targetPath)) {
|
|
35224
35873
|
return [];
|
|
35225
35874
|
}
|
|
35226
35875
|
try {
|
|
35227
|
-
const content =
|
|
35876
|
+
const content = readFileSync20(targetPath, "utf-8");
|
|
35228
35877
|
const lines = content.split("\n");
|
|
35229
35878
|
const hosts = [];
|
|
35230
35879
|
let currentHosts = [];
|
|
@@ -35266,7 +35915,7 @@ function parseSshConfig(configPath) {
|
|
|
35266
35915
|
return [];
|
|
35267
35916
|
}
|
|
35268
35917
|
}
|
|
35269
|
-
function resolveSshHostG(host, execFn =
|
|
35918
|
+
function resolveSshHostG(host, execFn = spawnSync8) {
|
|
35270
35919
|
try {
|
|
35271
35920
|
const result = execFn("ssh", ["-G", host], { encoding: "utf-8" });
|
|
35272
35921
|
if (result.status !== 0 || !result.stdout) {
|
|
@@ -35301,15 +35950,15 @@ function resolveSshHostG(host, execFn = spawnSync6) {
|
|
|
35301
35950
|
}
|
|
35302
35951
|
}
|
|
35303
35952
|
function ensureSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
35304
|
-
const resolved =
|
|
35305
|
-
if (!
|
|
35306
|
-
|
|
35953
|
+
const resolved = resolve14(socketDir);
|
|
35954
|
+
if (!existsSync23(resolved)) {
|
|
35955
|
+
mkdirSync12(resolved, { recursive: true, mode: 448 });
|
|
35307
35956
|
}
|
|
35308
35957
|
return resolved;
|
|
35309
35958
|
}
|
|
35310
35959
|
function buildSshArgs(options) {
|
|
35311
35960
|
const socketDir = ensureSocketDir(options.socketDir ?? DEFAULT_SOCKET_DIR);
|
|
35312
|
-
const controlPath =
|
|
35961
|
+
const controlPath = join26(socketDir, "%C");
|
|
35313
35962
|
const persist2 = options.controlPersist ?? DEFAULT_CONTROL_PERSIST;
|
|
35314
35963
|
const args = [
|
|
35315
35964
|
"-o",
|
|
@@ -35332,9 +35981,9 @@ function buildSshArgs(options) {
|
|
|
35332
35981
|
args.push(options.host);
|
|
35333
35982
|
return args;
|
|
35334
35983
|
}
|
|
35335
|
-
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn =
|
|
35984
|
+
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync8) {
|
|
35336
35985
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
35337
|
-
const controlPath =
|
|
35986
|
+
const controlPath = join26(resolvedDir, "%C");
|
|
35338
35987
|
try {
|
|
35339
35988
|
const result = execFn("ssh", ["-O", "check", "-o", `ControlPath=${controlPath}`, host], {
|
|
35340
35989
|
encoding: "utf-8"
|
|
@@ -35344,9 +35993,9 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
35344
35993
|
return false;
|
|
35345
35994
|
}
|
|
35346
35995
|
}
|
|
35347
|
-
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn =
|
|
35996
|
+
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync8) {
|
|
35348
35997
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
35349
|
-
const controlPath =
|
|
35998
|
+
const controlPath = join26(resolvedDir, "%C");
|
|
35350
35999
|
try {
|
|
35351
36000
|
const result = execFn("ssh", ["-O", "stop", "-o", `ControlPath=${controlPath}`, host], {
|
|
35352
36001
|
encoding: "utf-8"
|
|
@@ -35362,7 +36011,7 @@ function pruneSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
|
35362
36011
|
try {
|
|
35363
36012
|
const entries = readdirSync11(resolvedDir);
|
|
35364
36013
|
for (const entry of entries) {
|
|
35365
|
-
const fullPath =
|
|
36014
|
+
const fullPath = join26(resolvedDir, entry);
|
|
35366
36015
|
try {
|
|
35367
36016
|
const stat = statSync6(fullPath);
|
|
35368
36017
|
if (stat.isSocket()) {
|
|
@@ -35378,7 +36027,7 @@ function pruneSocketDir(socketDir = DEFAULT_SOCKET_DIR) {
|
|
|
35378
36027
|
}
|
|
35379
36028
|
function executeSshRun(params) {
|
|
35380
36029
|
const startTime = Date.now();
|
|
35381
|
-
const execSyncFn = params.execFn ??
|
|
36030
|
+
const execSyncFn = params.execFn ?? spawnSync8;
|
|
35382
36031
|
if (params.action === "info") {
|
|
35383
36032
|
if (params.host) {
|
|
35384
36033
|
const hostInfo = resolveSshHostG(params.host, execSyncFn);
|