@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
|
@@ -2987,7 +2987,7 @@ var require_compile = __commonJS({
|
|
|
2987
2987
|
const schOrFunc = root.refs[ref];
|
|
2988
2988
|
if (schOrFunc)
|
|
2989
2989
|
return schOrFunc;
|
|
2990
|
-
let _sch =
|
|
2990
|
+
let _sch = resolve13.call(this, root, ref);
|
|
2991
2991
|
if (_sch === void 0) {
|
|
2992
2992
|
const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
2993
2993
|
const { schemaId } = this.opts;
|
|
@@ -3014,7 +3014,7 @@ var require_compile = __commonJS({
|
|
|
3014
3014
|
function sameSchemaEnv(s1, s2) {
|
|
3015
3015
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
3016
3016
|
}
|
|
3017
|
-
function
|
|
3017
|
+
function resolve13(root, ref) {
|
|
3018
3018
|
let sch;
|
|
3019
3019
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3020
3020
|
ref = sch;
|
|
@@ -3839,7 +3839,7 @@ var require_fast_uri = __commonJS({
|
|
|
3839
3839
|
}
|
|
3840
3840
|
return uri;
|
|
3841
3841
|
}
|
|
3842
|
-
function
|
|
3842
|
+
function resolve13(baseURI, relativeURI, options) {
|
|
3843
3843
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3844
3844
|
const {
|
|
3845
3845
|
parsed: baseParsed,
|
|
@@ -4201,7 +4201,7 @@ var require_fast_uri = __commonJS({
|
|
|
4201
4201
|
var fastUri = {
|
|
4202
4202
|
SCHEMES,
|
|
4203
4203
|
normalize,
|
|
4204
|
-
resolve:
|
|
4204
|
+
resolve: resolve13,
|
|
4205
4205
|
resolveComponent,
|
|
4206
4206
|
equal,
|
|
4207
4207
|
serialize,
|
|
@@ -14781,9 +14781,9 @@ var require_dist = __commonJS({
|
|
|
14781
14781
|
// plugins/kxm/src/runtime-supervisor.ts
|
|
14782
14782
|
import { spawn as spawn3 } from "node:child_process";
|
|
14783
14783
|
import { createHash as createHash15, createHmac, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
14784
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
14784
|
+
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";
|
|
14785
14785
|
import { createServer } from "node:http";
|
|
14786
|
-
import { dirname as
|
|
14786
|
+
import { dirname as dirname13, isAbsolute as isAbsolute8, join as join22 } from "node:path";
|
|
14787
14787
|
|
|
14788
14788
|
// plugins/kxm/src/repo-root.ts
|
|
14789
14789
|
import { existsSync } from "node:fs";
|
|
@@ -16097,7 +16097,7 @@ function defaultSpawn(command, args, options) {
|
|
|
16097
16097
|
if (options.signal?.aborted) {
|
|
16098
16098
|
return Promise.resolve({ stdout: "", stderr: "", code: null, started: false, observedChildExit: false, error: new Error("process_aborted") });
|
|
16099
16099
|
}
|
|
16100
|
-
return new Promise((
|
|
16100
|
+
return new Promise((resolve13) => {
|
|
16101
16101
|
const stdout = [];
|
|
16102
16102
|
const stderr = [];
|
|
16103
16103
|
let outputBytes = 0;
|
|
@@ -16128,7 +16128,7 @@ function defaultSpawn(command, args, options) {
|
|
|
16128
16128
|
const started = Boolean(child?.pid);
|
|
16129
16129
|
if (started && !observedChildExit) error ??= new Error("process_exit_unobserved");
|
|
16130
16130
|
const unverifiedDescendants = stopping || started && !observedChildExit;
|
|
16131
|
-
|
|
16131
|
+
resolve13({
|
|
16132
16132
|
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
16133
16133
|
stderr: Buffer.concat(stderr).toString("utf8"),
|
|
16134
16134
|
code,
|
|
@@ -17976,8 +17976,8 @@ function validateWorkflow(workflow, agents, models, repositories, gates, issues)
|
|
|
17976
17976
|
const writable = Object.values(objectValue(step.repositories) ?? {}).filter((access) => access === "write").length;
|
|
17977
17977
|
if (maxWriteRepositories > writable) issues.push(issue3("semantic", "write_repository_bound_invalid", file, `${stepId} maxWriteRepositories exceeds writable repository scope`));
|
|
17978
17978
|
}
|
|
17979
|
-
const
|
|
17980
|
-
const minimumPassed =
|
|
17979
|
+
const join23 = objectValue(step.join);
|
|
17980
|
+
const minimumPassed = join23 && typeof join23.minimumPassed === "number" ? join23.minimumPassed : void 0;
|
|
17981
17981
|
if (minimumPassed !== void 0 && minimumPassed > maximum) issues.push(issue3("semantic", "join_impossible", file, `${stepId} minimumPassed exceeds assignment maximum`));
|
|
17982
17982
|
const distinctBy = names(assignment?.distinctBy);
|
|
17983
17983
|
if (distinctBy.length > 0) {
|
|
@@ -22557,7 +22557,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
22557
22557
|
const maxAttempts = compileCountField(step.maxAttempts, 1, `${id}.maxAttempts`, id, sink);
|
|
22558
22558
|
const timeoutMs = compileOptionalDuration(step.timeoutMs, `${id}.timeoutMs`, id, sink);
|
|
22559
22559
|
const assignments = compileAssignments(step, id, agent, sink);
|
|
22560
|
-
const
|
|
22560
|
+
const join23 = compileJoin(step, id, sink);
|
|
22561
22561
|
const requiredEvidence = compileEvidence(step, id, sink);
|
|
22562
22562
|
const transitions = compileTransitions(step, id, index, stepIndex, sink);
|
|
22563
22563
|
const outcomes = Object.keys(transitions).sort(compareCodeUnits5);
|
|
@@ -22585,7 +22585,7 @@ function compileStep(step, index, stepIndex, requirePlanHash, sink) {
|
|
|
22585
22585
|
transitions: orderedTransitions,
|
|
22586
22586
|
requiresPlanHash: requirePlanHash.includes(id),
|
|
22587
22587
|
assignments,
|
|
22588
|
-
join:
|
|
22588
|
+
join: join23
|
|
22589
22589
|
};
|
|
22590
22590
|
if (kind === "agent" || kind === "moa") {
|
|
22591
22591
|
if (!agent) return void 0;
|
|
@@ -22635,15 +22635,15 @@ function compileAssignments(step, stepId, primaryAgentId, sink) {
|
|
|
22635
22635
|
};
|
|
22636
22636
|
}
|
|
22637
22637
|
function compileJoin(step, stepId, sink) {
|
|
22638
|
-
const
|
|
22639
|
-
if (!
|
|
22640
|
-
const declared = stringValue2(
|
|
22638
|
+
const join23 = objectValue2(step.join);
|
|
22639
|
+
if (!join23) return { strategy: "all" };
|
|
22640
|
+
const declared = stringValue2(join23.strategy);
|
|
22641
22641
|
const strategy = declared && JOIN_STRATEGIES.has(declared) ? declared : "all";
|
|
22642
|
-
const minimumPassed = compileOptionalCount(
|
|
22642
|
+
const minimumPassed = compileOptionalCount(join23.minimumPassed, `${stepId}.join.minimumPassed`, stepId, sink);
|
|
22643
22643
|
const compiled = {
|
|
22644
22644
|
strategy,
|
|
22645
22645
|
...minimumPassed !== void 0 ? { minimumPassed } : {},
|
|
22646
|
-
...typeof
|
|
22646
|
+
...typeof join23.cancelRemaining === "boolean" ? { cancelRemaining: join23.cancelRemaining } : {}
|
|
22647
22647
|
};
|
|
22648
22648
|
return compiled;
|
|
22649
22649
|
}
|
|
@@ -23996,12 +23996,12 @@ function enqueueKxmScheduledRun(storePath, runId, configRevision, bound, start)
|
|
|
23996
23996
|
if (owner.admitted.has(runId) || owner.queue.some((item) => item.runId === runId)) {
|
|
23997
23997
|
return Promise.reject(runtimeError("run_busy", runId, `run ${runId} is already admitted or queued`));
|
|
23998
23998
|
}
|
|
23999
|
-
return new Promise((
|
|
23999
|
+
return new Promise((resolve13, reject) => {
|
|
24000
24000
|
owner.queue.push({
|
|
24001
24001
|
runId,
|
|
24002
24002
|
configRevision,
|
|
24003
24003
|
bound,
|
|
24004
|
-
start: (token) => start(token).then(
|
|
24004
|
+
start: (token) => start(token).then(resolve13, reject),
|
|
24005
24005
|
fail: (error) => reject(error)
|
|
24006
24006
|
});
|
|
24007
24007
|
pump(storePath, owner);
|
|
@@ -24794,38 +24794,344 @@ function loadPriceCatalog(rootOrPath) {
|
|
|
24794
24794
|
// plugins/kxm/src/engine.ts
|
|
24795
24795
|
var import_yaml11 = __toESM(require_dist(), 1);
|
|
24796
24796
|
import { createHash as createHash14, randomBytes, timingSafeEqual } from "node:crypto";
|
|
24797
|
-
import { existsSync as
|
|
24798
|
-
import { join as
|
|
24797
|
+
import { existsSync as existsSync15, readFileSync as readFileSync13 } from "node:fs";
|
|
24798
|
+
import { join as join18 } from "node:path";
|
|
24799
24799
|
|
|
24800
24800
|
// plugins/kxm/src/routes.ts
|
|
24801
24801
|
var import_yaml7 = __toESM(require_dist(), 1);
|
|
24802
|
-
import { existsSync as
|
|
24803
|
-
import { join as
|
|
24802
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, readdirSync as readdirSync6 } from "node:fs";
|
|
24803
|
+
import { join as join12 } from "node:path";
|
|
24804
24804
|
|
|
24805
24805
|
// plugins/kxm/src/role.ts
|
|
24806
24806
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
24807
24807
|
|
|
24808
24808
|
// plugins/kxm/src/config.ts
|
|
24809
24809
|
var import_yaml5 = __toESM(require_dist(), 1);
|
|
24810
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "node:fs";
|
|
24811
|
+
import { tmpdir, homedir as homedir2 } from "node:os";
|
|
24812
|
+
import { dirname as dirname6, join as join11, resolve as resolve7 } from "node:path";
|
|
24813
|
+
var KXM_CONFIG_SCHEMA = "kxm.config.v1";
|
|
24814
|
+
var KxmHubConfigError = class extends Error {
|
|
24815
|
+
code = "hub_config_invalid";
|
|
24816
|
+
constructor(message) {
|
|
24817
|
+
super(message);
|
|
24818
|
+
this.name = "KxmHubConfigError";
|
|
24819
|
+
}
|
|
24820
|
+
};
|
|
24821
|
+
var HUB_ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
24822
|
+
var HUB_OP_REF = /^op:\/\/\S+\/\S+\/\S+$/;
|
|
24823
|
+
var LITERAL_SECRET_KEY = /^(token|secret|password|authToken|auth_token|apiKey|api_key|api_token|bearer|credential|access_token)$/i;
|
|
24824
|
+
function isHubKeyEnvName(value) {
|
|
24825
|
+
return HUB_ENV_NAME.test(value);
|
|
24826
|
+
}
|
|
24827
|
+
function isHubOpReference(value) {
|
|
24828
|
+
return HUB_OP_REF.test(value);
|
|
24829
|
+
}
|
|
24830
|
+
var IMPROVEMENT_PROMOTION_POLICIES = ["manual_pr", "critic_quorum", "auto_threshold"];
|
|
24831
|
+
var DEFAULT_KXM_CONFIG = {
|
|
24832
|
+
schema: KXM_CONFIG_SCHEMA,
|
|
24833
|
+
user: {
|
|
24834
|
+
theme: "dark",
|
|
24835
|
+
preferredCritics: ["reviewer-arch", "reviewer-cli"],
|
|
24836
|
+
tokenBudget: 16e3
|
|
24837
|
+
},
|
|
24838
|
+
defaults: {
|
|
24839
|
+
workflow: "software-engineering/feature-implementation",
|
|
24840
|
+
harness: "pi"
|
|
24841
|
+
},
|
|
24842
|
+
dash: {
|
|
24843
|
+
defaultScreen: "agents",
|
|
24844
|
+
refreshIntervalMs: 1e3,
|
|
24845
|
+
autoOpen: false
|
|
24846
|
+
},
|
|
24847
|
+
sync: {
|
|
24848
|
+
defaultTracker: "none"
|
|
24849
|
+
},
|
|
24850
|
+
hub: {
|
|
24851
|
+
autoStart: "background"
|
|
24852
|
+
},
|
|
24853
|
+
improvement: {
|
|
24854
|
+
promotionPolicy: "manual_pr",
|
|
24855
|
+
telemetryHalfLifeDays: 14,
|
|
24856
|
+
autoThreshold: {
|
|
24857
|
+
minRuns: 10,
|
|
24858
|
+
minPassRate: 0.95,
|
|
24859
|
+
minCostSavings: 0.5
|
|
24860
|
+
}
|
|
24861
|
+
},
|
|
24862
|
+
routing: {
|
|
24863
|
+
shadowExecution: {
|
|
24864
|
+
enabled: false,
|
|
24865
|
+
sampleRate: 0.05,
|
|
24866
|
+
candidateModels: []
|
|
24867
|
+
},
|
|
24868
|
+
circuitBreaker: {
|
|
24869
|
+
mode: "soft_demotion",
|
|
24870
|
+
failureThreshold: 3,
|
|
24871
|
+
windowSeconds: 3600,
|
|
24872
|
+
cooldownSeconds: 1800,
|
|
24873
|
+
penaltyMultiplier: 5
|
|
24874
|
+
}
|
|
24875
|
+
},
|
|
24876
|
+
telemetry: {
|
|
24877
|
+
federated: true,
|
|
24878
|
+
anonymize: true
|
|
24879
|
+
}
|
|
24880
|
+
};
|
|
24881
|
+
function userConfigDirectory(overrideDir) {
|
|
24882
|
+
if (overrideDir) return resolve7(overrideDir);
|
|
24883
|
+
return resolve7(process.env.KXM_USER_CONFIG_DIR?.trim() || join11(homedir2(), ".config", "kxm"));
|
|
24884
|
+
}
|
|
24885
|
+
function repoConfigDirectory(repoRoot) {
|
|
24886
|
+
return resolve7(repoRoot, ".kxm");
|
|
24887
|
+
}
|
|
24888
|
+
function deepMerge(target, source) {
|
|
24889
|
+
const result = { ...target };
|
|
24890
|
+
for (const [key, val] of Object.entries(source)) {
|
|
24891
|
+
if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
24892
|
+
const existing = result[key] && typeof result[key] === "object" && !Array.isArray(result[key]) ? result[key] : {};
|
|
24893
|
+
result[key] = deepMerge(existing, val);
|
|
24894
|
+
} else if (val !== void 0) {
|
|
24895
|
+
result[key] = val;
|
|
24896
|
+
}
|
|
24897
|
+
}
|
|
24898
|
+
return result;
|
|
24899
|
+
}
|
|
24900
|
+
function literalSecretMessage(path) {
|
|
24901
|
+
return `refusing literal hub token at ${path}: store an op:// reference (key.op) or an environment variable name (key.env), never the token`;
|
|
24902
|
+
}
|
|
24903
|
+
function rejectLiteralHubSecrets(value, path) {
|
|
24904
|
+
if (Array.isArray(value)) {
|
|
24905
|
+
value.forEach((item, index) => rejectLiteralHubSecrets(item, `${path}[${index}]`));
|
|
24906
|
+
return;
|
|
24907
|
+
}
|
|
24908
|
+
if (!value || typeof value !== "object") return;
|
|
24909
|
+
for (const [key, child] of Object.entries(value)) {
|
|
24910
|
+
const childPath = `${path}.${key}`;
|
|
24911
|
+
if (typeof child === "string" && (key === "key" || LITERAL_SECRET_KEY.test(key))) {
|
|
24912
|
+
throw new KxmHubConfigError(literalSecretMessage(childPath));
|
|
24913
|
+
}
|
|
24914
|
+
if (child && typeof child === "object") rejectLiteralHubSecrets(child, childPath);
|
|
24915
|
+
}
|
|
24916
|
+
}
|
|
24917
|
+
function parseKeyRef(raw, path) {
|
|
24918
|
+
if (raw === void 0) return void 0;
|
|
24919
|
+
if (typeof raw === "string") throw new KxmHubConfigError(literalSecretMessage(path));
|
|
24920
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
24921
|
+
throw new KxmHubConfigError(`${path} must be a key reference with op and/or env, never a token`);
|
|
24922
|
+
}
|
|
24923
|
+
const row = raw;
|
|
24924
|
+
for (const key of Object.keys(row)) {
|
|
24925
|
+
if (key !== "op" && key !== "env") {
|
|
24926
|
+
throw new KxmHubConfigError(literalSecretMessage(`${path}.${key}`));
|
|
24927
|
+
}
|
|
24928
|
+
}
|
|
24929
|
+
const ref = {};
|
|
24930
|
+
if (row.op !== void 0) {
|
|
24931
|
+
if (typeof row.op !== "string" || !isHubOpReference(row.op)) {
|
|
24932
|
+
throw new KxmHubConfigError(`${path}.op must be an op://vault/item/field reference, not a token`);
|
|
24933
|
+
}
|
|
24934
|
+
ref.op = row.op;
|
|
24935
|
+
}
|
|
24936
|
+
if (row.env !== void 0) {
|
|
24937
|
+
if (typeof row.env !== "string" || !isHubKeyEnvName(row.env)) {
|
|
24938
|
+
throw new KxmHubConfigError(`${path}.env must be an environment variable name, not a token`);
|
|
24939
|
+
}
|
|
24940
|
+
ref.env = row.env;
|
|
24941
|
+
}
|
|
24942
|
+
if (!ref.op && !ref.env) throw new KxmHubConfigError(`${path} needs key.op, key.env, or both`);
|
|
24943
|
+
return ref;
|
|
24944
|
+
}
|
|
24945
|
+
function parseEndpoint(raw, path) {
|
|
24946
|
+
if (raw === void 0) return void 0;
|
|
24947
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
24948
|
+
throw new KxmHubConfigError(`${path} must be an object with url, project, and key`);
|
|
24949
|
+
}
|
|
24950
|
+
const row = raw;
|
|
24951
|
+
const endpoint = {};
|
|
24952
|
+
if (row.url !== void 0) {
|
|
24953
|
+
if (typeof row.url !== "string" || !isHubUrl(row.url)) {
|
|
24954
|
+
throw new KxmHubConfigError(`${path}.url must be an http or https URL without credentials, query, or fragment`);
|
|
24955
|
+
}
|
|
24956
|
+
endpoint.url = row.url.replace(/\/$/, "");
|
|
24957
|
+
}
|
|
24958
|
+
if (row.project !== void 0) {
|
|
24959
|
+
if (typeof row.project !== "string" || !isHubProjectId(row.project)) {
|
|
24960
|
+
throw new KxmHubConfigError(`${path}.project must be a single-line project id, not a token`);
|
|
24961
|
+
}
|
|
24962
|
+
endpoint.project = row.project.trim();
|
|
24963
|
+
}
|
|
24964
|
+
const key = parseKeyRef(row.key, `${path}.key`);
|
|
24965
|
+
if (key) endpoint.key = key;
|
|
24966
|
+
for (const name of Object.keys(row)) {
|
|
24967
|
+
if (name !== "url" && name !== "project" && name !== "key") {
|
|
24968
|
+
if (typeof row[name] === "string") throw new KxmHubConfigError(literalSecretMessage(`${path}.${name}`));
|
|
24969
|
+
throw new KxmHubConfigError(`${path}.${name} is not a hub endpoint field`);
|
|
24970
|
+
}
|
|
24971
|
+
}
|
|
24972
|
+
return endpoint;
|
|
24973
|
+
}
|
|
24974
|
+
function isHubUrl(raw) {
|
|
24975
|
+
try {
|
|
24976
|
+
const parsed = new URL(raw);
|
|
24977
|
+
return (parsed.protocol === "http:" || parsed.protocol === "https:") && parsed.username === "" && parsed.password === "" && parsed.search === "" && parsed.hash === "" && !raw.includes("?") && !raw.includes("#");
|
|
24978
|
+
} catch {
|
|
24979
|
+
return false;
|
|
24980
|
+
}
|
|
24981
|
+
}
|
|
24982
|
+
function isHubProjectId(raw) {
|
|
24983
|
+
const value = raw.trim();
|
|
24984
|
+
return value.length > 0 && value.length <= 200 && !/[\s\r\n]/.test(value);
|
|
24985
|
+
}
|
|
24986
|
+
function parseProjectMap(raw) {
|
|
24987
|
+
if (raw === void 0) return void 0;
|
|
24988
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
24989
|
+
throw new KxmHubConfigError("hub.projects must be a map of project id to key reference, never a token");
|
|
24990
|
+
}
|
|
24991
|
+
const projects = {};
|
|
24992
|
+
for (const [project, value] of Object.entries(raw)) {
|
|
24993
|
+
if (!isHubProjectId(project)) {
|
|
24994
|
+
throw new KxmHubConfigError(`hub.projects key ${JSON.stringify(project)} must be a project id, not a token`);
|
|
24995
|
+
}
|
|
24996
|
+
const ref = parseKeyRef(value, `hub.projects.${project}`);
|
|
24997
|
+
if (!ref) throw new KxmHubConfigError(`hub.projects.${project} needs an op:// reference or an environment variable name`);
|
|
24998
|
+
projects[project.trim()] = ref;
|
|
24999
|
+
}
|
|
25000
|
+
return projects;
|
|
25001
|
+
}
|
|
25002
|
+
function normalizeHubConfig(raw) {
|
|
25003
|
+
const autoStart = raw?.autoStart;
|
|
25004
|
+
const hub = {
|
|
25005
|
+
autoStart: autoStart === "off" || autoStart === "background" ? autoStart : DEFAULT_KXM_CONFIG.hub.autoStart
|
|
25006
|
+
};
|
|
25007
|
+
if (raw === void 0) return hub;
|
|
25008
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
25009
|
+
throw new KxmHubConfigError("hub must be an object");
|
|
25010
|
+
}
|
|
25011
|
+
rejectLiteralHubSecrets(raw, "hub");
|
|
25012
|
+
const row = raw;
|
|
25013
|
+
if (row.mode !== void 0) {
|
|
25014
|
+
if (row.mode !== "local" && row.mode !== "cloud") {
|
|
25015
|
+
throw new KxmHubConfigError("hub.mode must be local or cloud");
|
|
25016
|
+
}
|
|
25017
|
+
hub.mode = row.mode;
|
|
25018
|
+
}
|
|
25019
|
+
const local = parseEndpoint(row.local, "hub.local");
|
|
25020
|
+
const cloud = parseEndpoint(row.cloud, "hub.cloud");
|
|
25021
|
+
const projects = parseProjectMap(row.projects);
|
|
25022
|
+
if (local) hub.local = local;
|
|
25023
|
+
if (cloud) hub.cloud = cloud;
|
|
25024
|
+
if (projects && Object.keys(projects).length > 0) hub.projects = projects;
|
|
25025
|
+
return hub;
|
|
25026
|
+
}
|
|
25027
|
+
function findConfigRoot(start) {
|
|
25028
|
+
let dir = resolve7(start);
|
|
25029
|
+
for (; ; ) {
|
|
25030
|
+
if (existsSync10(join11(dir, ".kxm", "project.yaml")) || existsSync10(join11(dir, ".kxm", "config.yaml"))) return dir;
|
|
25031
|
+
const parent = dirname6(dir);
|
|
25032
|
+
if (parent === dir) return resolve7(start);
|
|
25033
|
+
dir = parent;
|
|
25034
|
+
}
|
|
25035
|
+
}
|
|
25036
|
+
function userConfigDirForEnv(env) {
|
|
25037
|
+
const explicit = env.KXM_USER_CONFIG_DIR?.trim();
|
|
25038
|
+
if (explicit) return explicit;
|
|
25039
|
+
if (env === process.env) return void 0;
|
|
25040
|
+
return join11(tmpdir(), "kxm-no-user-config");
|
|
25041
|
+
}
|
|
25042
|
+
function loadHubSettings(start, env = process.env) {
|
|
25043
|
+
const userConfigDir = userConfigDirForEnv(env);
|
|
25044
|
+
return loadKxmConfig(findConfigRoot(start), userConfigDir === void 0 ? {} : { userConfigDir }).hub;
|
|
25045
|
+
}
|
|
25046
|
+
function recordOf(raw) {
|
|
25047
|
+
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
25048
|
+
}
|
|
25049
|
+
function finiteNumber(value) {
|
|
25050
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
25051
|
+
}
|
|
25052
|
+
function normalizeImprovementConfig(raw) {
|
|
25053
|
+
const value = recordOf(raw);
|
|
25054
|
+
const threshold = recordOf(value.autoThreshold);
|
|
25055
|
+
const policy = value.promotionPolicy;
|
|
25056
|
+
const halfLife = finiteNumber(value.telemetryHalfLifeDays);
|
|
25057
|
+
const minRuns = finiteNumber(threshold.minRuns);
|
|
25058
|
+
const minPassRate = finiteNumber(threshold.minPassRate);
|
|
25059
|
+
const minCostSavings = finiteNumber(threshold.minCostSavings);
|
|
25060
|
+
return {
|
|
25061
|
+
promotionPolicy: IMPROVEMENT_PROMOTION_POLICIES.includes(policy) ? policy : "manual_pr",
|
|
25062
|
+
telemetryHalfLifeDays: halfLife !== void 0 && halfLife > 0 && halfLife <= 3650 ? halfLife : 14,
|
|
25063
|
+
autoThreshold: {
|
|
25064
|
+
minRuns: minRuns !== void 0 && Number.isInteger(minRuns) && minRuns >= 1 && minRuns <= 1e6 ? minRuns : 10,
|
|
25065
|
+
minPassRate: minPassRate !== void 0 && minPassRate >= 0 && minPassRate <= 1 ? minPassRate : 0.95,
|
|
25066
|
+
minCostSavings: minCostSavings !== void 0 && minCostSavings >= 0 ? minCostSavings : 0.5
|
|
25067
|
+
}
|
|
25068
|
+
};
|
|
25069
|
+
}
|
|
25070
|
+
function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
|
|
25071
|
+
const userDir = userConfigDirectory(options.userConfigDir);
|
|
25072
|
+
const userConfigFile = join11(userDir, "config.yaml");
|
|
25073
|
+
const repoDir = repoConfigDirectory(repoRoot);
|
|
25074
|
+
const repoConfigFile = join11(repoDir, "config.yaml");
|
|
25075
|
+
let userRaw = {};
|
|
25076
|
+
let userLoadedPath;
|
|
25077
|
+
if (existsSync10(userConfigFile)) {
|
|
25078
|
+
try {
|
|
25079
|
+
const text = readFileSync8(userConfigFile, "utf8");
|
|
25080
|
+
userRaw = (0, import_yaml5.parse)(text) ?? {};
|
|
25081
|
+
userLoadedPath = userConfigFile;
|
|
25082
|
+
} catch (error) {
|
|
25083
|
+
throw new Error(`invalid user config YAML at ${userConfigFile}`, { cause: error });
|
|
25084
|
+
}
|
|
25085
|
+
}
|
|
25086
|
+
let repoRaw = {};
|
|
25087
|
+
let repoLoadedPath;
|
|
25088
|
+
if (existsSync10(repoConfigFile)) {
|
|
25089
|
+
try {
|
|
25090
|
+
const text = readFileSync8(repoConfigFile, "utf8");
|
|
25091
|
+
repoRaw = (0, import_yaml5.parse)(text) ?? {};
|
|
25092
|
+
repoLoadedPath = repoConfigFile;
|
|
25093
|
+
} catch (error) {
|
|
25094
|
+
throw new Error(`invalid project config YAML at ${repoConfigFile}`, { cause: error });
|
|
25095
|
+
}
|
|
25096
|
+
}
|
|
25097
|
+
const baseCopy = JSON.parse(JSON.stringify(DEFAULT_KXM_CONFIG));
|
|
25098
|
+
const mergedUser = deepMerge(baseCopy, userRaw);
|
|
25099
|
+
const mergedAll = deepMerge(mergedUser, repoRaw);
|
|
25100
|
+
return {
|
|
25101
|
+
schema: KXM_CONFIG_SCHEMA,
|
|
25102
|
+
user: mergedAll.user ?? {},
|
|
25103
|
+
defaults: mergedAll.defaults ?? {},
|
|
25104
|
+
dash: mergedAll.dash ?? {},
|
|
25105
|
+
sync: mergedAll.sync ?? {},
|
|
25106
|
+
hub: normalizeHubConfig(mergedAll.hub),
|
|
25107
|
+
improvement: normalizeImprovementConfig(mergedAll.improvement),
|
|
25108
|
+
routing: mergedAll.routing ?? DEFAULT_KXM_CONFIG.routing,
|
|
25109
|
+
telemetry: mergedAll.telemetry ?? DEFAULT_KXM_CONFIG.telemetry,
|
|
25110
|
+
loadedFrom: {
|
|
25111
|
+
userConfigPath: userLoadedPath,
|
|
25112
|
+
repoConfigPath: repoLoadedPath
|
|
25113
|
+
}
|
|
25114
|
+
};
|
|
25115
|
+
}
|
|
24810
25116
|
|
|
24811
25117
|
// plugins/kxm/src/routes.ts
|
|
24812
25118
|
var RETIRED_POLICY = ".kxm/producers.yaml";
|
|
24813
25119
|
var empty = () => ({ schema: "kxm.routes.v2", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), admitted: [], disabled: [] });
|
|
24814
25120
|
function loadRoutePolicy(root) {
|
|
24815
|
-
if (
|
|
24816
|
-
const path =
|
|
24817
|
-
if (!
|
|
24818
|
-
const value = (0, import_yaml7.parse)(
|
|
25121
|
+
if (existsSync11(join12(root, RETIRED_POLICY))) throw new Error(`retired ${RETIRED_POLICY} present; use .kxm/routes.yaml (kxm.routes.v2)`);
|
|
25122
|
+
const path = join12(root, ".kxm", "routes.yaml");
|
|
25123
|
+
if (!existsSync11(path)) return empty();
|
|
25124
|
+
const value = (0, import_yaml7.parse)(readFileSync9(path, "utf8"));
|
|
24819
25125
|
if (value?.schema !== "kxm.routes.v2" || !Array.isArray(value.admitted)) throw new Error("invalid .kxm/routes.yaml");
|
|
24820
25126
|
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") : [] };
|
|
24821
25127
|
}
|
|
24822
25128
|
function listRoleBindings(root) {
|
|
24823
|
-
const dir =
|
|
25129
|
+
const dir = join12(root, ".kxm", "roles");
|
|
24824
25130
|
const result = {};
|
|
24825
|
-
if (!
|
|
25131
|
+
if (!existsSync11(dir)) return result;
|
|
24826
25132
|
for (const file of readdirSync6(dir).filter((name) => name.endsWith(".yaml"))) {
|
|
24827
25133
|
const role = file.slice(0, -5);
|
|
24828
|
-
const value = (0, import_yaml7.parse)(
|
|
25134
|
+
const value = (0, import_yaml7.parse)(readFileSync9(join12(dir, file), "utf8"));
|
|
24829
25135
|
result[role] = (value.roster ?? []).map((entry) => entry.route).filter((route) => typeof route === "string");
|
|
24830
25136
|
}
|
|
24831
25137
|
return result;
|
|
@@ -24833,8 +25139,8 @@ function listRoleBindings(root) {
|
|
|
24833
25139
|
|
|
24834
25140
|
// plugins/kxm/src/route-fallback.ts
|
|
24835
25141
|
var import_yaml8 = __toESM(require_dist(), 1);
|
|
24836
|
-
import { existsSync as
|
|
24837
|
-
import { join as
|
|
25142
|
+
import { existsSync as existsSync12, readdirSync as readdirSync7, readFileSync as readFileSync10 } from "node:fs";
|
|
25143
|
+
import { join as join13 } from "node:path";
|
|
24838
25144
|
|
|
24839
25145
|
// plugins/kxm/src/route-switch.ts
|
|
24840
25146
|
var WALKABLE_CLASSES = ["rate_limit", "transport", "provider_unavailable", "context_overflow"];
|
|
@@ -25034,9 +25340,9 @@ ${lines.join("\n")}`;
|
|
|
25034
25340
|
${block}`;
|
|
25035
25341
|
}
|
|
25036
25342
|
function readYaml(file) {
|
|
25037
|
-
if (!
|
|
25343
|
+
if (!existsSync12(file)) return void 0;
|
|
25038
25344
|
try {
|
|
25039
|
-
const parsed = (0, import_yaml8.parse)(
|
|
25345
|
+
const parsed = (0, import_yaml8.parse)(readFileSync10(file, "utf8"));
|
|
25040
25346
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
25041
25347
|
return parsed;
|
|
25042
25348
|
} catch {
|
|
@@ -25048,7 +25354,7 @@ function stringList(value) {
|
|
|
25048
25354
|
}
|
|
25049
25355
|
function readSelectors(projectRoot, value) {
|
|
25050
25356
|
if (!Array.isArray(value)) return [];
|
|
25051
|
-
const modelsDir =
|
|
25357
|
+
const modelsDir = join13(projectRoot, ".kxm", "models");
|
|
25052
25358
|
const selectors = [];
|
|
25053
25359
|
for (const item of value) {
|
|
25054
25360
|
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
@@ -25067,9 +25373,9 @@ function readSelectors(projectRoot, value) {
|
|
|
25067
25373
|
return selectors;
|
|
25068
25374
|
}
|
|
25069
25375
|
function loadChainModel(projectRoot, routeId2, writerIds) {
|
|
25070
|
-
const modelsDir =
|
|
25376
|
+
const modelsDir = join13(projectRoot, ".kxm", "models");
|
|
25071
25377
|
const fileId = findYamlBasename(modelsDir, routeId2, "route") ?? routeId2;
|
|
25072
|
-
const doc = readYaml(
|
|
25378
|
+
const doc = readYaml(join13(modelsDir, `${fileId}.yaml`));
|
|
25073
25379
|
if (!doc || doc.schema !== "kxm.model.v2") return void 0;
|
|
25074
25380
|
const harness = typeof doc.harness === "string" ? doc.harness : "";
|
|
25075
25381
|
const model = typeof doc.model === "string" ? doc.model : "";
|
|
@@ -25096,7 +25402,7 @@ function loadChainModel(projectRoot, routeId2, writerIds) {
|
|
|
25096
25402
|
};
|
|
25097
25403
|
}
|
|
25098
25404
|
function canonicalRoster(projectRoot, entries) {
|
|
25099
|
-
const modelsDir =
|
|
25405
|
+
const modelsDir = join13(projectRoot, ".kxm", "models");
|
|
25100
25406
|
return entries.map((entry) => {
|
|
25101
25407
|
const route = findYamlBasename(modelsDir, entry.route, "route") ?? entry.route;
|
|
25102
25408
|
return entry.effort ? { route, effort: entry.effort } : { route };
|
|
@@ -25115,10 +25421,10 @@ function rosterEntries(doc) {
|
|
|
25115
25421
|
return entries;
|
|
25116
25422
|
}
|
|
25117
25423
|
function loadModelsFor(projectRoot, roster, writerIds) {
|
|
25118
|
-
const modelsDir =
|
|
25424
|
+
const modelsDir = join13(projectRoot, ".kxm", "models");
|
|
25119
25425
|
const wanted = /* @__PURE__ */ new Set();
|
|
25120
25426
|
for (const entry of roster) wanted.add(entry.route);
|
|
25121
|
-
if (
|
|
25427
|
+
if (existsSync12(modelsDir)) {
|
|
25122
25428
|
for (const name of readdirSync7(modelsDir)) {
|
|
25123
25429
|
if (!name.endsWith(".yaml") || name === "inventory.yaml") continue;
|
|
25124
25430
|
wanted.add(name.slice(0, -5));
|
|
@@ -25135,12 +25441,12 @@ function loadModelsFor(projectRoot, roster, writerIds) {
|
|
|
25135
25441
|
return models;
|
|
25136
25442
|
}
|
|
25137
25443
|
function criticVendors(projectRoot, writerIds) {
|
|
25138
|
-
const dir =
|
|
25139
|
-
if (!
|
|
25444
|
+
const dir = join13(projectRoot, ".kxm", "roles");
|
|
25445
|
+
if (!existsSync12(dir)) return [];
|
|
25140
25446
|
const vendors = [];
|
|
25141
25447
|
for (const name of readdirSync7(dir)) {
|
|
25142
25448
|
if (!name.endsWith(".yaml")) continue;
|
|
25143
|
-
const doc = readYaml(
|
|
25449
|
+
const doc = readYaml(join13(dir, name));
|
|
25144
25450
|
const purpose = doc?.purpose;
|
|
25145
25451
|
if (purpose !== "reviewer-arch" && purpose !== "reviewer-cli") continue;
|
|
25146
25452
|
const first = rosterEntries(doc)[0];
|
|
@@ -25151,12 +25457,12 @@ function criticVendors(projectRoot, writerIds) {
|
|
|
25151
25457
|
return vendors;
|
|
25152
25458
|
}
|
|
25153
25459
|
function loadAgentFallback(projectRoot, agentId, options) {
|
|
25154
|
-
const agentsDir =
|
|
25460
|
+
const agentsDir = join13(projectRoot, ".kxm", "agents");
|
|
25155
25461
|
const agentFile = findYamlBasename(agentsDir, agentId, "agent") ?? agentId;
|
|
25156
|
-
const agent = readYaml(
|
|
25462
|
+
const agent = readYaml(join13(agentsDir, `${agentFile}.yaml`));
|
|
25157
25463
|
const roleId = typeof agent?.role === "string" ? agent.role : "";
|
|
25158
25464
|
if (!roleId) return void 0;
|
|
25159
|
-
const role = readYaml(
|
|
25465
|
+
const role = readYaml(join13(projectRoot, ".kxm", "roles", `${roleId}.yaml`));
|
|
25160
25466
|
if (!role) return void 0;
|
|
25161
25467
|
const policyRecord = role.policy && typeof role.policy === "object" ? role.policy.fallback : void 0;
|
|
25162
25468
|
const policy = parseFallbackPolicy(policyRecord);
|
|
@@ -25167,7 +25473,7 @@ function loadAgentFallback(projectRoot, agentId, options) {
|
|
|
25167
25473
|
let cursor = typeof role.extends === "string" ? role.extends : "";
|
|
25168
25474
|
while (cursor && !seenRoles.has(cursor)) {
|
|
25169
25475
|
seenRoles.add(cursor);
|
|
25170
|
-
const parent = readYaml(
|
|
25476
|
+
const parent = readYaml(join13(projectRoot, ".kxm", "roles", `${cursor}.yaml`));
|
|
25171
25477
|
extendsRoster = extendsRoster.concat(canonicalRoster(projectRoot, rosterEntries(parent)));
|
|
25172
25478
|
cursor = typeof parent?.extends === "string" ? parent.extends : "";
|
|
25173
25479
|
}
|
|
@@ -25515,7 +25821,7 @@ function pruneContextPacket(packet, tokenBudget) {
|
|
|
25515
25821
|
// plugins/kxm/src/dispatch-context.ts
|
|
25516
25822
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
25517
25823
|
import { readdirSync as readdirSync10 } from "node:fs";
|
|
25518
|
-
import { extname as extname3, join as
|
|
25824
|
+
import { extname as extname3, join as join16 } from "node:path";
|
|
25519
25825
|
|
|
25520
25826
|
// plugins/kxm/src/protocol.ts
|
|
25521
25827
|
var DEFAULT_MESSAGE_TTL_MS = 24 * 60 * 6e4;
|
|
@@ -26144,8 +26450,8 @@ function memoryRecordToContextItem(record2, project) {
|
|
|
26144
26450
|
|
|
26145
26451
|
// plugins/kxm/src/memory.ts
|
|
26146
26452
|
var import_yaml9 = __toESM(require_dist(), 1);
|
|
26147
|
-
import { existsSync as
|
|
26148
|
-
import { extname as extname2, join as
|
|
26453
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync5, readdirSync as readdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "node:fs";
|
|
26454
|
+
import { extname as extname2, join as join14, resolve as resolve8 } from "node:path";
|
|
26149
26455
|
var MEMORY_SCHEMA = "kxm.memory.v1";
|
|
26150
26456
|
var VALID_SCOPES = /* @__PURE__ */ new Set(["agent", "project", "run", "operator"]);
|
|
26151
26457
|
var VALID_AUTHORITIES = /* @__PURE__ */ new Set(["instruction", "evidence", "promoted"]);
|
|
@@ -26243,21 +26549,21 @@ function parseMemoryRecord(raw, filename = "memory.md") {
|
|
|
26243
26549
|
};
|
|
26244
26550
|
}
|
|
26245
26551
|
function memoryDirectories(repoRoot) {
|
|
26246
|
-
const root =
|
|
26247
|
-
const memoryDir =
|
|
26248
|
-
const candidatesDir =
|
|
26552
|
+
const root = resolve8(repoRoot);
|
|
26553
|
+
const memoryDir = join14(root, ".kxm", "memory");
|
|
26554
|
+
const candidatesDir = join14(memoryDir, "candidates");
|
|
26249
26555
|
return { memoryDir, candidatesDir };
|
|
26250
26556
|
}
|
|
26251
26557
|
function loadAuthoredMemory(repoRoot) {
|
|
26252
26558
|
const { memoryDir } = memoryDirectories(repoRoot);
|
|
26253
|
-
if (!
|
|
26559
|
+
if (!existsSync13(memoryDir)) return [];
|
|
26254
26560
|
const records = [];
|
|
26255
26561
|
const entries = readdirSync8(memoryDir, { withFileTypes: true });
|
|
26256
26562
|
for (const entry of entries) {
|
|
26257
26563
|
if (entry.isFile() && extname2(entry.name) === ".md") {
|
|
26258
|
-
const fullPath =
|
|
26564
|
+
const fullPath = join14(memoryDir, entry.name);
|
|
26259
26565
|
try {
|
|
26260
|
-
const text =
|
|
26566
|
+
const text = readFileSync11(fullPath, "utf8");
|
|
26261
26567
|
const record2 = parseMemoryRecord(text, entry.name);
|
|
26262
26568
|
if (record2.lifecycle === "active") {
|
|
26263
26569
|
records.push(record2);
|
|
@@ -26273,8 +26579,8 @@ function loadAuthoredMemory(repoRoot) {
|
|
|
26273
26579
|
// plugins/kxm/src/skills.ts
|
|
26274
26580
|
var import_yaml10 = __toESM(require_dist(), 1);
|
|
26275
26581
|
import { createHash as createHash11 } from "node:crypto";
|
|
26276
|
-
import { existsSync as
|
|
26277
|
-
import { dirname as
|
|
26582
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync6, readdirSync as readdirSync9, readFileSync as readFileSync12, renameSync, rmSync, statSync as statSync3, writeFileSync as writeFileSync7 } from "node:fs";
|
|
26583
|
+
import { dirname as dirname8, join as join15 } from "node:path";
|
|
26278
26584
|
var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
|
|
26279
26585
|
var SKILL_EVALUATION_SCHEMA = "kxm.skill-evaluation.v1";
|
|
26280
26586
|
var SKILL_DECISION_SCHEMA = "kxm.skill-decision.v1";
|
|
@@ -26376,24 +26682,24 @@ var SkillLifecycle = class {
|
|
|
26376
26682
|
this.planned.push({ action: "write", target: file });
|
|
26377
26683
|
return;
|
|
26378
26684
|
}
|
|
26379
|
-
|
|
26380
|
-
|
|
26685
|
+
mkdirSync6(dirname8(file), { recursive: true });
|
|
26686
|
+
writeFileSync7(file, content);
|
|
26381
26687
|
}
|
|
26382
26688
|
dir(state) {
|
|
26383
|
-
return
|
|
26689
|
+
return join15(this.root, state === "candidate" ? "candidates" : `${state}s`.replace("rejecteds", "rejected").replace("promoteds", "promoted"));
|
|
26384
26690
|
}
|
|
26385
26691
|
historyFile(id) {
|
|
26386
|
-
return
|
|
26692
|
+
return join15(this.root, "history", `${id}.jsonl`);
|
|
26387
26693
|
}
|
|
26388
26694
|
paths(state, id) {
|
|
26389
|
-
const dir =
|
|
26390
|
-
return { dir, metadata:
|
|
26695
|
+
const dir = join15(this.dir(state), id);
|
|
26696
|
+
return { dir, metadata: join15(dir, "metadata.json"), skill: join15(dir, "SKILL.md") };
|
|
26391
26697
|
}
|
|
26392
26698
|
appendHistory(id, record2) {
|
|
26393
26699
|
const line = `${JSON.stringify(record2)}
|
|
26394
26700
|
`;
|
|
26395
|
-
if (
|
|
26396
|
-
const existing =
|
|
26701
|
+
if (existsSync14(this.historyFile(id))) {
|
|
26702
|
+
const existing = readFileSync12(this.historyFile(id), "utf8");
|
|
26397
26703
|
const lines = existing.split("\n").filter((entry) => entry.trim());
|
|
26398
26704
|
this.write(this.historyFile(id), [...lines.slice(-499), line.trim()].join("\n") + "\n");
|
|
26399
26705
|
} else {
|
|
@@ -26402,28 +26708,28 @@ var SkillLifecycle = class {
|
|
|
26402
26708
|
}
|
|
26403
26709
|
history(id) {
|
|
26404
26710
|
const file = this.historyFile(id);
|
|
26405
|
-
if (!
|
|
26406
|
-
return
|
|
26711
|
+
if (!existsSync14(file)) return [];
|
|
26712
|
+
return readFileSync12(file, "utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
26407
26713
|
}
|
|
26408
26714
|
readMetadata(state, id) {
|
|
26409
26715
|
const { metadata } = this.paths(state, id);
|
|
26410
|
-
if (!
|
|
26716
|
+
if (!existsSync14(metadata)) {
|
|
26411
26717
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${state}`);
|
|
26412
26718
|
}
|
|
26413
|
-
return JSON.parse(
|
|
26719
|
+
return JSON.parse(readFileSync12(metadata, "utf8"));
|
|
26414
26720
|
}
|
|
26415
26721
|
move(from, to, id) {
|
|
26416
|
-
const fromDir =
|
|
26417
|
-
const toDir =
|
|
26418
|
-
if (!
|
|
26722
|
+
const fromDir = join15(this.dir(from), id);
|
|
26723
|
+
const toDir = join15(this.dir(to), id);
|
|
26724
|
+
if (!existsSync14(fromDir)) {
|
|
26419
26725
|
throw new SkillLifecycleError("skill_not_found", `skill ${id} not found in ${from}`);
|
|
26420
26726
|
}
|
|
26421
26727
|
if (this.dryRun) {
|
|
26422
26728
|
this.planned.push({ action: "move", target: `${fromDir} -> ${toDir}` });
|
|
26423
26729
|
return;
|
|
26424
26730
|
}
|
|
26425
|
-
|
|
26426
|
-
if (
|
|
26731
|
+
mkdirSync6(this.dir(to), { recursive: true });
|
|
26732
|
+
if (existsSync14(toDir)) rmSync(toDir, { recursive: true, force: true });
|
|
26427
26733
|
renameSync(fromDir, toDir);
|
|
26428
26734
|
}
|
|
26429
26735
|
/** Submit a new skill candidate. Content is redacted of secret material at
|
|
@@ -26466,7 +26772,7 @@ var SkillLifecycle = class {
|
|
|
26466
26772
|
const contentSha256 = skillContentSha256(content);
|
|
26467
26773
|
const id = skillIdFor(name, contentSha256);
|
|
26468
26774
|
const { metadata, skill } = this.paths("candidate", id);
|
|
26469
|
-
if (
|
|
26775
|
+
if (existsSync14(metadata)) {
|
|
26470
26776
|
throw new SkillLifecycleError(
|
|
26471
26777
|
"skill_candidate_exists",
|
|
26472
26778
|
`identical candidate ${id} already exists; changed behavior requires changed content`
|
|
@@ -26575,11 +26881,11 @@ var SkillLifecycle = class {
|
|
|
26575
26881
|
};
|
|
26576
26882
|
const candidatePaths = this.paths("candidate", candidateId);
|
|
26577
26883
|
const promotedPaths = this.paths("promoted", candidateId);
|
|
26578
|
-
const skillContent =
|
|
26579
|
-
const metadataContent =
|
|
26884
|
+
const skillContent = readFileSync12(candidatePaths.skill, "utf8");
|
|
26885
|
+
const metadataContent = readFileSync12(candidatePaths.metadata, "utf8");
|
|
26580
26886
|
this.write(promotedPaths.skill, skillContent);
|
|
26581
26887
|
this.write(promotedPaths.metadata, metadataContent);
|
|
26582
|
-
const patchPath =
|
|
26888
|
+
const patchPath = join15(this.root, "patches", `${candidateId}.patch`);
|
|
26583
26889
|
const relSkillPath = `.kxm/skills/promoted/${candidateId}/SKILL.md`;
|
|
26584
26890
|
const relMetaPath = `.kxm/skills/promoted/${candidateId}/metadata.json`;
|
|
26585
26891
|
const patch = `${createUnifiedPatch(relSkillPath, skillContent)}${createUnifiedPatch(relMetaPath, metadataContent)}`;
|
|
@@ -26607,7 +26913,7 @@ var SkillLifecycle = class {
|
|
|
26607
26913
|
verify(state, id) {
|
|
26608
26914
|
const metadata = this.readMetadata(state, id);
|
|
26609
26915
|
const { skill } = this.paths(state, id);
|
|
26610
|
-
const content =
|
|
26916
|
+
const content = readFileSync12(skill, "utf8");
|
|
26611
26917
|
if (skillContentSha256(content) !== metadata.contentSha256) {
|
|
26612
26918
|
throw new SkillLifecycleError(
|
|
26613
26919
|
"skill_integrity_violation",
|
|
@@ -26625,7 +26931,7 @@ var SkillLifecycle = class {
|
|
|
26625
26931
|
}
|
|
26626
26932
|
list(state) {
|
|
26627
26933
|
const dir = this.dir(state);
|
|
26628
|
-
if (!
|
|
26934
|
+
if (!existsSync14(dir)) return [];
|
|
26629
26935
|
const ids = readdirSorted(dir);
|
|
26630
26936
|
return ids.map((id) => {
|
|
26631
26937
|
try {
|
|
@@ -26638,7 +26944,7 @@ var SkillLifecycle = class {
|
|
|
26638
26944
|
read(state, id) {
|
|
26639
26945
|
const metadata = this.readMetadata(state, id);
|
|
26640
26946
|
const { skill } = this.paths(state, id);
|
|
26641
|
-
return { metadata, content:
|
|
26947
|
+
return { metadata, content: readFileSync12(skill, "utf8") };
|
|
26642
26948
|
}
|
|
26643
26949
|
};
|
|
26644
26950
|
function boundedList(value, field) {
|
|
@@ -26653,7 +26959,7 @@ function boundedList(value, field) {
|
|
|
26653
26959
|
return [...new Set(refs)];
|
|
26654
26960
|
}
|
|
26655
26961
|
function readdirSorted(dir) {
|
|
26656
|
-
return readdirSync9(dir).filter((entry) => statSync3(
|
|
26962
|
+
return readdirSync9(dir).filter((entry) => statSync3(join15(dir, entry)).isDirectory()).sort();
|
|
26657
26963
|
}
|
|
26658
26964
|
|
|
26659
26965
|
// plugins/kxm/src/dispatch-context.ts
|
|
@@ -26694,7 +27000,7 @@ function contextRoleForAgent(agentId) {
|
|
|
26694
27000
|
return agentId;
|
|
26695
27001
|
}
|
|
26696
27002
|
function dispatchContextPresent(projectRoot) {
|
|
26697
|
-
return hasTopLevelMarkdown(
|
|
27003
|
+
return hasTopLevelMarkdown(join16(projectRoot, ".kxm", "memory")) || hasAnyEntry(join16(projectRoot, ".kxm", "skills", "promoted"));
|
|
26698
27004
|
}
|
|
26699
27005
|
function hasTopLevelMarkdown(dir) {
|
|
26700
27006
|
try {
|
|
@@ -26770,7 +27076,7 @@ function loadDispatchContextSources(input) {
|
|
|
26770
27076
|
}
|
|
26771
27077
|
const promoted = [];
|
|
26772
27078
|
try {
|
|
26773
|
-
const lifecycle = new SkillLifecycle(
|
|
27079
|
+
const lifecycle = new SkillLifecycle(join16(projectRoot, ".kxm", "skills"));
|
|
26774
27080
|
for (const metadata of lifecycle.list("promoted")) {
|
|
26775
27081
|
try {
|
|
26776
27082
|
promoted.push(lifecycle.verify("promoted", metadata.id));
|
|
@@ -26853,18 +27159,18 @@ function assembleDispatchContext(sources, input) {
|
|
|
26853
27159
|
}
|
|
26854
27160
|
|
|
26855
27161
|
// plugins/kxm/src/engine-artifacts.ts
|
|
26856
|
-
import { join as
|
|
27162
|
+
import { join as join17 } from "node:path";
|
|
26857
27163
|
|
|
26858
27164
|
// plugins/kxm/src/artifacts-exist.ts
|
|
26859
27165
|
import { lstatSync as lstatSync5, realpathSync as realpathSync4, statSync as statSync4 } from "node:fs";
|
|
26860
|
-
import { isAbsolute as isAbsolute5, relative as relative4, resolve as
|
|
27166
|
+
import { isAbsolute as isAbsolute5, relative as relative4, resolve as resolve9 } from "node:path";
|
|
26861
27167
|
function staysUnder(root, candidate) {
|
|
26862
27168
|
const child = relative4(root, candidate);
|
|
26863
27169
|
return child === "" || !isAbsolute5(child) && child !== ".." && !child.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`);
|
|
26864
27170
|
}
|
|
26865
27171
|
function verifyArtifactExists(rootInput, pathInput) {
|
|
26866
|
-
const lexicalRoot =
|
|
26867
|
-
const lexicalPath =
|
|
27172
|
+
const lexicalRoot = resolve9(rootInput);
|
|
27173
|
+
const lexicalPath = resolve9(pathInput);
|
|
26868
27174
|
if (!staysUnder(lexicalRoot, lexicalPath)) {
|
|
26869
27175
|
return { ok: false, error: "artifact_outside_workspace_assets", path: lexicalPath };
|
|
26870
27176
|
}
|
|
@@ -26900,14 +27206,14 @@ function verifyArtifactExists(rootInput, pathInput) {
|
|
|
26900
27206
|
// plugins/kxm/src/engine-artifacts.ts
|
|
26901
27207
|
var kxmArtifactsGateSeams = {};
|
|
26902
27208
|
function evaluateArtifactsGate(context, definition) {
|
|
26903
|
-
const root =
|
|
27209
|
+
const root = join17(context.projectRoot, ".kxm", "assets");
|
|
26904
27210
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
26905
27211
|
const startTime = process.hrtime.bigint();
|
|
26906
27212
|
let checkedCount = 0;
|
|
26907
27213
|
let failedCount = 0;
|
|
26908
27214
|
for (const [index, path] of definition.paths.entries()) {
|
|
26909
27215
|
checkedCount += 1;
|
|
26910
|
-
const result = verifyArtifactExists(root,
|
|
27216
|
+
const result = verifyArtifactExists(root, join17(root, path));
|
|
26911
27217
|
if (!result.ok) failedCount += 1;
|
|
26912
27218
|
kxmArtifactsGateSeams.afterPathChecked?.({ path, index, checkedCount, failedCount });
|
|
26913
27219
|
}
|
|
@@ -27052,8 +27358,8 @@ var CommandObserver = class {
|
|
|
27052
27358
|
this.requestStop("error", "lost-close");
|
|
27053
27359
|
}
|
|
27054
27360
|
run() {
|
|
27055
|
-
return new Promise((
|
|
27056
|
-
this.resolveOutcome =
|
|
27361
|
+
return new Promise((resolve13) => {
|
|
27362
|
+
this.resolveOutcome = resolve13;
|
|
27057
27363
|
try {
|
|
27058
27364
|
this.start();
|
|
27059
27365
|
} catch (error) {
|
|
@@ -28380,8 +28686,8 @@ var KxmRunScheduler = class _KxmRunScheduler {
|
|
|
28380
28686
|
resolve: (_value) => void 0,
|
|
28381
28687
|
reject: (_error) => void 0
|
|
28382
28688
|
};
|
|
28383
|
-
const settled = new Promise((
|
|
28384
|
-
pending.resolve =
|
|
28689
|
+
const settled = new Promise((resolve13, reject) => {
|
|
28690
|
+
pending.resolve = resolve13;
|
|
28385
28691
|
pending.reject = reject;
|
|
28386
28692
|
});
|
|
28387
28693
|
void settled.then(void 0, () => void 0);
|
|
@@ -28920,9 +29226,9 @@ function readYamlFile(file) {
|
|
|
28920
29226
|
return readModelDocument(file);
|
|
28921
29227
|
}
|
|
28922
29228
|
function readModelDocument(file) {
|
|
28923
|
-
if (!
|
|
29229
|
+
if (!existsSync15(file)) return void 0;
|
|
28924
29230
|
try {
|
|
28925
|
-
const parsed = (0, import_yaml11.parse)(
|
|
29231
|
+
const parsed = (0, import_yaml11.parse)(readFileSync13(file, "utf8"));
|
|
28926
29232
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
28927
29233
|
return parsed;
|
|
28928
29234
|
} catch {
|
|
@@ -28953,8 +29259,8 @@ function resolveProducerRoute(projectRoot, step, agentId) {
|
|
|
28953
29259
|
}
|
|
28954
29260
|
};
|
|
28955
29261
|
}
|
|
28956
|
-
const agentFile = findYamlBasename(
|
|
28957
|
-
const agent = readYamlFile(
|
|
29262
|
+
const agentFile = findYamlBasename(join18(projectRoot, ".kxm", "agents"), agentId, "agent") ?? agentId;
|
|
29263
|
+
const agent = readYamlFile(join18(projectRoot, ".kxm", "agents", `${agentFile}.yaml`));
|
|
28958
29264
|
const role = typeof agent?.role === "string" ? agent.role : "";
|
|
28959
29265
|
if (!role) {
|
|
28960
29266
|
return {
|
|
@@ -28965,7 +29271,7 @@ function resolveProducerRoute(projectRoot, step, agentId) {
|
|
|
28965
29271
|
}
|
|
28966
29272
|
};
|
|
28967
29273
|
}
|
|
28968
|
-
const roleDoc = readYamlFile(
|
|
29274
|
+
const roleDoc = readYamlFile(join18(projectRoot, ".kxm", "roles", `${role}.yaml`));
|
|
28969
29275
|
const roster = Array.isArray(roleDoc?.roster) ? roleDoc.roster : void 0;
|
|
28970
29276
|
if (!roster) {
|
|
28971
29277
|
return {
|
|
@@ -28981,8 +29287,8 @@ function resolveProducerRoute(projectRoot, step, agentId) {
|
|
|
28981
29287
|
if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
|
|
28982
29288
|
const record2 = entry;
|
|
28983
29289
|
if (typeof record2.route !== "string" || record2.route.length === 0) continue;
|
|
28984
|
-
const routeFile = findYamlBasename(
|
|
28985
|
-
const modelPath =
|
|
29290
|
+
const routeFile = findYamlBasename(join18(projectRoot, ".kxm", "models"), record2.route, "route") ?? record2.route;
|
|
29291
|
+
const modelPath = join18(projectRoot, ".kxm", "models", `${routeFile}.yaml`);
|
|
28986
29292
|
const doc = readModelDocument(modelPath);
|
|
28987
29293
|
if (!doc) {
|
|
28988
29294
|
return {
|
|
@@ -31321,10 +31627,22 @@ var RuntimeHubClient = class {
|
|
|
31321
31627
|
};
|
|
31322
31628
|
|
|
31323
31629
|
// plugins/kxm/src/hub-binding.ts
|
|
31324
|
-
import {
|
|
31325
|
-
import {
|
|
31326
|
-
import {
|
|
31630
|
+
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
31631
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync14, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync8 } from "node:fs";
|
|
31632
|
+
import { homedir as homedir3 } from "node:os";
|
|
31633
|
+
import { dirname as dirname9, isAbsolute as isAbsolute6, join as join19, resolve as resolve10 } from "node:path";
|
|
31327
31634
|
var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
31635
|
+
var CloudTokenError = class extends Error {
|
|
31636
|
+
code;
|
|
31637
|
+
constructor(code, message) {
|
|
31638
|
+
super(message);
|
|
31639
|
+
this.name = "CloudTokenError";
|
|
31640
|
+
this.code = code;
|
|
31641
|
+
}
|
|
31642
|
+
};
|
|
31643
|
+
var TOKEN_ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
31644
|
+
var TOKEN_COMMAND_TIMEOUT_MS = 15e3;
|
|
31645
|
+
var TOKEN_COMMAND_MAX_BUFFER = 4096;
|
|
31328
31646
|
var HubBindingError = class extends Error {
|
|
31329
31647
|
constructor(message) {
|
|
31330
31648
|
super(message);
|
|
@@ -31335,20 +31653,20 @@ function resolveUserStateRoot(env) {
|
|
|
31335
31653
|
const explicit = env.KXM_STATE_HOME?.trim();
|
|
31336
31654
|
if (explicit) {
|
|
31337
31655
|
if (!isAbsolute6(explicit)) throw new HubBindingError("local_state_root_not_absolute");
|
|
31338
|
-
return
|
|
31656
|
+
return resolve10(explicit);
|
|
31339
31657
|
}
|
|
31340
31658
|
if (process.platform === "win32") {
|
|
31341
31659
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
31342
|
-
const base2 = localAppData && isAbsolute6(localAppData) ? localAppData :
|
|
31343
|
-
return
|
|
31660
|
+
const base2 = localAppData && isAbsolute6(localAppData) ? localAppData : join19(homedir3(), "AppData", "Local");
|
|
31661
|
+
return resolve10(base2, "KXM");
|
|
31344
31662
|
}
|
|
31345
|
-
if (process.platform === "darwin") return
|
|
31663
|
+
if (process.platform === "darwin") return resolve10(homedir3(), "Library", "Application Support", "KXM");
|
|
31346
31664
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
31347
|
-
const base = xdgState && isAbsolute6(xdgState) ? xdgState :
|
|
31348
|
-
return
|
|
31665
|
+
const base = xdgState && isAbsolute6(xdgState) ? xdgState : join19(homedir3(), ".local", "state");
|
|
31666
|
+
return resolve10(base, "kxm");
|
|
31349
31667
|
}
|
|
31350
31668
|
function hubBindingFile(env = process.env) {
|
|
31351
|
-
return
|
|
31669
|
+
return join19(resolveUserStateRoot(env), "hub-binding.json");
|
|
31352
31670
|
}
|
|
31353
31671
|
function validateHubUrl(raw) {
|
|
31354
31672
|
let parsed;
|
|
@@ -31362,16 +31680,109 @@ function validateHubUrl(raw) {
|
|
|
31362
31680
|
}
|
|
31363
31681
|
return parsed.href.replace(/\/$/, "");
|
|
31364
31682
|
}
|
|
31683
|
+
function splitTokenCommand(raw) {
|
|
31684
|
+
if (/[|&;<>$`\n\r]/.test(raw)) {
|
|
31685
|
+
throw new CloudTokenError(
|
|
31686
|
+
"cloud_token_command_invalid",
|
|
31687
|
+
"token command must be a program and arguments, not a shell pipeline"
|
|
31688
|
+
);
|
|
31689
|
+
}
|
|
31690
|
+
const args = [];
|
|
31691
|
+
let current = "";
|
|
31692
|
+
let quote;
|
|
31693
|
+
for (const ch of raw) {
|
|
31694
|
+
if (quote) {
|
|
31695
|
+
if (ch === quote) quote = void 0;
|
|
31696
|
+
else current += ch;
|
|
31697
|
+
continue;
|
|
31698
|
+
}
|
|
31699
|
+
if (ch === "'" || ch === '"') {
|
|
31700
|
+
quote = ch;
|
|
31701
|
+
continue;
|
|
31702
|
+
}
|
|
31703
|
+
if (ch === " " || ch === " ") {
|
|
31704
|
+
if (current.length > 0) {
|
|
31705
|
+
args.push(current);
|
|
31706
|
+
current = "";
|
|
31707
|
+
}
|
|
31708
|
+
continue;
|
|
31709
|
+
}
|
|
31710
|
+
current += ch;
|
|
31711
|
+
}
|
|
31712
|
+
if (quote) {
|
|
31713
|
+
throw new CloudTokenError("cloud_token_command_invalid", "token command has an unclosed quote");
|
|
31714
|
+
}
|
|
31715
|
+
if (current.length > 0) args.push(current);
|
|
31716
|
+
if (args.length === 0) {
|
|
31717
|
+
throw new CloudTokenError("cloud_token_command_invalid", "token command is empty");
|
|
31718
|
+
}
|
|
31719
|
+
return args;
|
|
31720
|
+
}
|
|
31721
|
+
function isCloudTokenEnvName(value) {
|
|
31722
|
+
return TOKEN_ENV_NAME.test(value);
|
|
31723
|
+
}
|
|
31724
|
+
function resolveCloudHubToken(binding, env = process.env) {
|
|
31725
|
+
if (!binding.cloud) {
|
|
31726
|
+
throw new CloudTokenError("cloud_token_missing", "cloud hub token is missing; the local hub-env token was not used");
|
|
31727
|
+
}
|
|
31728
|
+
if (binding.tokenEnv) {
|
|
31729
|
+
const value = env[binding.tokenEnv]?.trim();
|
|
31730
|
+
if (value) return value;
|
|
31731
|
+
}
|
|
31732
|
+
if (binding.tokenCommand) return runTokenCommand(binding.tokenCommand, env);
|
|
31733
|
+
const source = binding.tokenEnv ? `${binding.tokenEnv} is unset or empty` : "no token source is configured";
|
|
31734
|
+
throw new CloudTokenError(
|
|
31735
|
+
"cloud_token_missing",
|
|
31736
|
+
`cloud hub token is missing: ${source}; the local hub-env token was not used`
|
|
31737
|
+
);
|
|
31738
|
+
}
|
|
31739
|
+
function runTokenCommand(command, env) {
|
|
31740
|
+
const argv = splitTokenCommand(command);
|
|
31741
|
+
const [program, ...args] = argv;
|
|
31742
|
+
const result = spawnSync6(program, args, {
|
|
31743
|
+
encoding: "utf8",
|
|
31744
|
+
shell: false,
|
|
31745
|
+
timeout: TOKEN_COMMAND_TIMEOUT_MS,
|
|
31746
|
+
maxBuffer: TOKEN_COMMAND_MAX_BUFFER,
|
|
31747
|
+
env,
|
|
31748
|
+
windowsHide: true
|
|
31749
|
+
});
|
|
31750
|
+
if (result.error || result.status !== 0) {
|
|
31751
|
+
throw new CloudTokenError(
|
|
31752
|
+
"cloud_token_command_failed",
|
|
31753
|
+
"token command failed; the local hub-env token was not used"
|
|
31754
|
+
);
|
|
31755
|
+
}
|
|
31756
|
+
const stdout = result.stdout ?? "";
|
|
31757
|
+
if (stdout.trim().length === 0 || stdout.trim() !== stdout.trim().split(/\r?\n/)[0]) {
|
|
31758
|
+
throw new CloudTokenError(
|
|
31759
|
+
"cloud_token_command_failed",
|
|
31760
|
+
"token command did not print a single token; the local hub-env token was not used"
|
|
31761
|
+
);
|
|
31762
|
+
}
|
|
31763
|
+
return stdout.trim();
|
|
31764
|
+
}
|
|
31765
|
+
function hubBindingScope(url) {
|
|
31766
|
+
let host;
|
|
31767
|
+
try {
|
|
31768
|
+
host = new URL(url).hostname.toLowerCase();
|
|
31769
|
+
} catch {
|
|
31770
|
+
return "remote";
|
|
31771
|
+
}
|
|
31772
|
+
if (host === "localhost" || host === "::1" || host === "[::1]" || host.endsWith(".localhost")) return "loopback";
|
|
31773
|
+
const v4 = /^127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/.exec(host);
|
|
31774
|
+
return v4 && [v4[1], v4[2], v4[3]].every((part) => Number(part) <= 255) ? "loopback" : "remote";
|
|
31775
|
+
}
|
|
31365
31776
|
function isIsoTimestamp(value) {
|
|
31366
31777
|
if (Number.isNaN(Date.parse(value))) return false;
|
|
31367
31778
|
return value === new Date(value).toISOString();
|
|
31368
31779
|
}
|
|
31369
31780
|
function readHubBinding(env = process.env) {
|
|
31370
31781
|
const file = hubBindingFile(env);
|
|
31371
|
-
if (!
|
|
31782
|
+
if (!existsSync16(file)) return void 0;
|
|
31372
31783
|
let parsed;
|
|
31373
31784
|
try {
|
|
31374
|
-
parsed = JSON.parse(
|
|
31785
|
+
parsed = JSON.parse(readFileSync14(file, "utf8"));
|
|
31375
31786
|
} catch {
|
|
31376
31787
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
31377
31788
|
}
|
|
@@ -31380,7 +31791,9 @@ function readHubBinding(env = process.env) {
|
|
|
31380
31791
|
}
|
|
31381
31792
|
const row = parsed;
|
|
31382
31793
|
const keys = Object.keys(row);
|
|
31383
|
-
|
|
31794
|
+
const allowed = /* @__PURE__ */ new Set(["schema", "url", "boundAt", "cloud", "tokenEnv", "tokenCommand"]);
|
|
31795
|
+
const cloudish = keys.some((key) => key === "cloud" || key === "tokenEnv" || key === "tokenCommand");
|
|
31796
|
+
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)) {
|
|
31384
31797
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
31385
31798
|
}
|
|
31386
31799
|
let url;
|
|
@@ -31389,13 +31802,230 @@ function readHubBinding(env = process.env) {
|
|
|
31389
31802
|
} catch {
|
|
31390
31803
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
31391
31804
|
}
|
|
31392
|
-
return { schema: HUB_BINDING_SCHEMA, url, boundAt: row.boundAt };
|
|
31805
|
+
if (!cloudish) return { schema: HUB_BINDING_SCHEMA, url, boundAt: row.boundAt };
|
|
31806
|
+
if (row.cloud !== true) throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
31807
|
+
let tokenEnv;
|
|
31808
|
+
let tokenCommand;
|
|
31809
|
+
if (row.tokenEnv !== void 0) {
|
|
31810
|
+
if (typeof row.tokenEnv !== "string" || !isCloudTokenEnvName(row.tokenEnv)) {
|
|
31811
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
31812
|
+
}
|
|
31813
|
+
tokenEnv = row.tokenEnv;
|
|
31814
|
+
}
|
|
31815
|
+
if (row.tokenCommand !== void 0) {
|
|
31816
|
+
if (typeof row.tokenCommand !== "string") throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
31817
|
+
try {
|
|
31818
|
+
splitTokenCommand(row.tokenCommand);
|
|
31819
|
+
} catch {
|
|
31820
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
31821
|
+
}
|
|
31822
|
+
tokenCommand = row.tokenCommand;
|
|
31823
|
+
}
|
|
31824
|
+
if (!tokenEnv && !tokenCommand) throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
31825
|
+
return {
|
|
31826
|
+
schema: HUB_BINDING_SCHEMA,
|
|
31827
|
+
url,
|
|
31828
|
+
boundAt: row.boundAt,
|
|
31829
|
+
cloud: true,
|
|
31830
|
+
...tokenEnv ? { tokenEnv } : {},
|
|
31831
|
+
...tokenCommand ? { tokenCommand } : {}
|
|
31832
|
+
};
|
|
31833
|
+
}
|
|
31834
|
+
|
|
31835
|
+
// plugins/kxm/src/hub-env.ts
|
|
31836
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync8, readFileSync as readFileSync16, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync9 } from "node:fs";
|
|
31837
|
+
import { homedir as homedir4 } from "node:os";
|
|
31838
|
+
import { dirname as dirname11, isAbsolute as isAbsolute7, join as join21, resolve as resolve12 } from "node:path";
|
|
31839
|
+
|
|
31840
|
+
// plugins/kxm/src/hub-identity.ts
|
|
31841
|
+
var import_yaml12 = __toESM(require_dist(), 1);
|
|
31842
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
31843
|
+
import { existsSync as existsSync17, readFileSync as readFileSync15 } from "node:fs";
|
|
31844
|
+
import { basename as basename4, dirname as dirname10, join as join20, resolve as resolve11 } from "node:path";
|
|
31845
|
+
var OP_TIMEOUT_MS = 15e3;
|
|
31846
|
+
var OP_MAX_BUFFER = 4096;
|
|
31847
|
+
function normalizeUrl(raw) {
|
|
31848
|
+
try {
|
|
31849
|
+
return validateHubUrl(raw);
|
|
31850
|
+
} catch {
|
|
31851
|
+
return void 0;
|
|
31852
|
+
}
|
|
31853
|
+
}
|
|
31854
|
+
function projectYamlId(start) {
|
|
31855
|
+
let dir = resolve11(start);
|
|
31856
|
+
for (; ; ) {
|
|
31857
|
+
const file = join20(dir, ".kxm", "project.yaml");
|
|
31858
|
+
if (existsSync17(file)) {
|
|
31859
|
+
try {
|
|
31860
|
+
const doc = (0, import_yaml12.parse)(readFileSync15(file, "utf8"));
|
|
31861
|
+
if (doc && typeof doc === "object" && !Array.isArray(doc) && typeof doc.id === "string" && doc.id.trim()) {
|
|
31862
|
+
return doc.id.trim();
|
|
31863
|
+
}
|
|
31864
|
+
} catch {
|
|
31865
|
+
}
|
|
31866
|
+
return void 0;
|
|
31867
|
+
}
|
|
31868
|
+
const parent = dirname10(dir);
|
|
31869
|
+
if (parent === dir) return void 0;
|
|
31870
|
+
dir = parent;
|
|
31871
|
+
}
|
|
31872
|
+
}
|
|
31873
|
+
function packageName(cwd) {
|
|
31874
|
+
try {
|
|
31875
|
+
const pkg = JSON.parse(readFileSync15(join20(cwd, "package.json"), "utf8"));
|
|
31876
|
+
if (typeof pkg.name === "string" && pkg.name.trim().length > 0) return pkg.name.trim();
|
|
31877
|
+
} catch {
|
|
31878
|
+
}
|
|
31879
|
+
return void 0;
|
|
31880
|
+
}
|
|
31881
|
+
function activeBinding(env) {
|
|
31882
|
+
try {
|
|
31883
|
+
return readHubBinding(env);
|
|
31884
|
+
} catch (error) {
|
|
31885
|
+
if (error instanceof HubBindingError) return void 0;
|
|
31886
|
+
throw error;
|
|
31887
|
+
}
|
|
31888
|
+
}
|
|
31889
|
+
function endpointFor(mode, settings) {
|
|
31890
|
+
return mode === "cloud" ? settings.cloud : settings.local;
|
|
31891
|
+
}
|
|
31892
|
+
function resolveProjectIdentity(cwd, env = process.env, explicit) {
|
|
31893
|
+
const fromExplicit = explicit?.trim();
|
|
31894
|
+
if (fromExplicit) return { project: fromExplicit, source: "flag", sourceLabel: "--project" };
|
|
31895
|
+
const fromEnv = env.KXM_PROJECT?.trim();
|
|
31896
|
+
if (fromEnv) return { project: fromEnv, source: "env", sourceLabel: "KXM_PROJECT" };
|
|
31897
|
+
const settings = loadHubSettings(cwd, env);
|
|
31898
|
+
const mode = settings.mode ?? (activeBinding(env)?.cloud ? "cloud" : "local");
|
|
31899
|
+
const fromConfig = endpointFor(mode, settings)?.project?.trim();
|
|
31900
|
+
if (fromConfig) {
|
|
31901
|
+
return { project: fromConfig, source: "config", sourceLabel: `.kxm/config.yaml hub.${mode}.project` };
|
|
31902
|
+
}
|
|
31903
|
+
const fromProject = projectYamlId(cwd);
|
|
31904
|
+
if (fromProject) return { project: fromProject, source: "project.yaml", sourceLabel: ".kxm/project.yaml id" };
|
|
31905
|
+
const fromPackage = packageName(cwd);
|
|
31906
|
+
if (fromPackage) return { project: fromPackage, source: "package.json", sourceLabel: "package.json name" };
|
|
31907
|
+
return { project: basename4(cwd), source: "directory", sourceLabel: "directory name" };
|
|
31908
|
+
}
|
|
31909
|
+
function opReferenceFromTokenCommand(command) {
|
|
31910
|
+
try {
|
|
31911
|
+
const args = splitTokenCommand(command);
|
|
31912
|
+
if (args[0] === "op" && args[1] === "read" && args[2] && isHubOpReference(args[2])) return args[2];
|
|
31913
|
+
} catch {
|
|
31914
|
+
return void 0;
|
|
31915
|
+
}
|
|
31916
|
+
return void 0;
|
|
31917
|
+
}
|
|
31918
|
+
function defaultOpRead(reference, env) {
|
|
31919
|
+
if (!isHubOpReference(reference)) {
|
|
31920
|
+
throw new CloudTokenError("cloud_token_command_invalid", `refusing to resolve ${reference}; an op:// reference is required`);
|
|
31921
|
+
}
|
|
31922
|
+
const result = spawnSync7("op", ["read", reference], {
|
|
31923
|
+
encoding: "utf8",
|
|
31924
|
+
shell: false,
|
|
31925
|
+
timeout: OP_TIMEOUT_MS,
|
|
31926
|
+
maxBuffer: OP_MAX_BUFFER,
|
|
31927
|
+
env,
|
|
31928
|
+
windowsHide: true
|
|
31929
|
+
});
|
|
31930
|
+
if (result.error || result.status !== 0) {
|
|
31931
|
+
throw new CloudTokenError(
|
|
31932
|
+
"cloud_token_command_failed",
|
|
31933
|
+
`op read failed for ${reference}; the token was not saved`
|
|
31934
|
+
);
|
|
31935
|
+
}
|
|
31936
|
+
const line = (result.stdout ?? "").trim();
|
|
31937
|
+
if (!line || line.split(/\r?\n/).length !== 1) {
|
|
31938
|
+
throw new CloudTokenError(
|
|
31939
|
+
"cloud_token_command_failed",
|
|
31940
|
+
`op read did not print a single token for ${reference}; the token was not saved`
|
|
31941
|
+
);
|
|
31942
|
+
}
|
|
31943
|
+
return line;
|
|
31944
|
+
}
|
|
31945
|
+
function resolveKeyReference(ref, env, opRead = defaultOpRead) {
|
|
31946
|
+
if (!ref) return void 0;
|
|
31947
|
+
if (ref.env) {
|
|
31948
|
+
const value = env[ref.env]?.trim();
|
|
31949
|
+
if (value) return { value, source: `env:${ref.env}` };
|
|
31950
|
+
}
|
|
31951
|
+
if (ref.op) {
|
|
31952
|
+
const value = opRead(ref.op, env).trim();
|
|
31953
|
+
if (!value || value.split(/\r?\n/).length !== 1) {
|
|
31954
|
+
throw new CloudTokenError("cloud_token_command_failed", `op read did not print a single token for ${ref.op}`);
|
|
31955
|
+
}
|
|
31956
|
+
return { value, source: `op:${ref.op}` };
|
|
31957
|
+
}
|
|
31958
|
+
return void 0;
|
|
31959
|
+
}
|
|
31960
|
+
function keySourceFor(input) {
|
|
31961
|
+
const ref = input.endpoint?.key;
|
|
31962
|
+
if (input.mode === "local" && input.env.KXM_AUTH_TOKEN?.trim()) return "env:KXM_AUTH_TOKEN";
|
|
31963
|
+
if (ref?.env && input.env[ref.env]?.trim()) return `env:${ref.env}`;
|
|
31964
|
+
if (ref?.op) return `op:${ref.op}`;
|
|
31965
|
+
if (ref?.env) return `env:${ref.env}`;
|
|
31966
|
+
if (input.mode === "cloud") {
|
|
31967
|
+
if (input.binding?.tokenEnv) return `env:${input.binding.tokenEnv}`;
|
|
31968
|
+
if (input.binding?.tokenCommand) {
|
|
31969
|
+
const op = opReferenceFromTokenCommand(input.binding.tokenCommand);
|
|
31970
|
+
return op ? `op:${op}` : "command";
|
|
31971
|
+
}
|
|
31972
|
+
return "missing";
|
|
31973
|
+
}
|
|
31974
|
+
if (input.hasSavedProjectToken?.(input.project)) return "hub-env";
|
|
31975
|
+
return "missing";
|
|
31976
|
+
}
|
|
31977
|
+
function describeHubConnection(cwd, env = process.env, hooks = {}) {
|
|
31978
|
+
const settings = loadHubSettings(cwd, env);
|
|
31979
|
+
const binding = activeBinding(env);
|
|
31980
|
+
const mode = settings.mode ?? (binding?.cloud ? "cloud" : "local");
|
|
31981
|
+
const modeSource = settings.mode ? "config" : binding?.cloud ? "binding" : "default";
|
|
31982
|
+
const endpoint = endpointFor(mode, settings);
|
|
31983
|
+
const fromEnv = env.KXM_SERVER_URL?.trim();
|
|
31984
|
+
const fromConfig = endpoint?.url?.trim();
|
|
31985
|
+
const fromBinding = binding?.url;
|
|
31986
|
+
let url = "http://127.0.0.1:7331";
|
|
31987
|
+
let urlSource = "default";
|
|
31988
|
+
if (fromEnv) {
|
|
31989
|
+
url = fromEnv.replace(/\/$/, "");
|
|
31990
|
+
urlSource = "env";
|
|
31991
|
+
} else if (fromConfig) {
|
|
31992
|
+
url = fromConfig.replace(/\/$/, "");
|
|
31993
|
+
urlSource = "config";
|
|
31994
|
+
} else if (fromBinding) {
|
|
31995
|
+
url = fromBinding;
|
|
31996
|
+
urlSource = "binding";
|
|
31997
|
+
}
|
|
31998
|
+
const identity = resolveProjectIdentity(cwd, env, hooks.explicitProject);
|
|
31999
|
+
const configuredCloudUrl = settings.cloud?.url ?? (binding?.cloud ? binding.url : void 0);
|
|
32000
|
+
let scope;
|
|
32001
|
+
if (mode === "cloud") {
|
|
32002
|
+
const override = fromEnv ? normalizeUrl(fromEnv) : void 0;
|
|
32003
|
+
const named = configuredCloudUrl ? normalizeUrl(configuredCloudUrl) : void 0;
|
|
32004
|
+
scope = override && named && override !== named ? hubBindingScope(url) : "remote";
|
|
32005
|
+
} else {
|
|
32006
|
+
scope = hubBindingScope(url);
|
|
32007
|
+
}
|
|
32008
|
+
return {
|
|
32009
|
+
...identity,
|
|
32010
|
+
mode,
|
|
32011
|
+
modeSource,
|
|
32012
|
+
url,
|
|
32013
|
+
urlSource,
|
|
32014
|
+
scope,
|
|
32015
|
+
...endpoint ? { endpoint } : {},
|
|
32016
|
+
...binding ? { binding } : {},
|
|
32017
|
+
keySource: keySourceFor({
|
|
32018
|
+
mode,
|
|
32019
|
+
env,
|
|
32020
|
+
...endpoint ? { endpoint } : {},
|
|
32021
|
+
...binding ? { binding } : {},
|
|
32022
|
+
project: identity.project,
|
|
32023
|
+
...hooks.hasSavedProjectToken ? { hasSavedProjectToken: hooks.hasSavedProjectToken } : {}
|
|
32024
|
+
})
|
|
32025
|
+
};
|
|
31393
32026
|
}
|
|
31394
32027
|
|
|
31395
32028
|
// plugins/kxm/src/hub-env.ts
|
|
31396
|
-
import { existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync14, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
|
|
31397
|
-
import { homedir as homedir3 } from "node:os";
|
|
31398
|
-
import { dirname as dirname9, isAbsolute as isAbsolute7, join as join19, resolve as resolve10 } from "node:path";
|
|
31399
32029
|
var HUB_ENV_SCHEMA = "kxm.hub-env.v1";
|
|
31400
32030
|
var HubEnvError = class extends Error {
|
|
31401
32031
|
constructor(message) {
|
|
@@ -31407,27 +32037,27 @@ function resolveUserStateRoot2(env) {
|
|
|
31407
32037
|
const explicit = env.KXM_STATE_HOME?.trim();
|
|
31408
32038
|
if (explicit) {
|
|
31409
32039
|
if (!isAbsolute7(explicit)) throw new HubEnvError("local_state_root_not_absolute");
|
|
31410
|
-
return
|
|
32040
|
+
return resolve12(explicit);
|
|
31411
32041
|
}
|
|
31412
32042
|
if (process.platform === "win32") {
|
|
31413
32043
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
31414
|
-
const base2 = localAppData && isAbsolute7(localAppData) ? localAppData :
|
|
31415
|
-
return
|
|
32044
|
+
const base2 = localAppData && isAbsolute7(localAppData) ? localAppData : join21(homedir4(), "AppData", "Local");
|
|
32045
|
+
return resolve12(base2, "KXM");
|
|
31416
32046
|
}
|
|
31417
|
-
if (process.platform === "darwin") return
|
|
32047
|
+
if (process.platform === "darwin") return resolve12(homedir4(), "Library", "Application Support", "KXM");
|
|
31418
32048
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
31419
|
-
const base = xdgState && isAbsolute7(xdgState) ? xdgState :
|
|
31420
|
-
return
|
|
32049
|
+
const base = xdgState && isAbsolute7(xdgState) ? xdgState : join21(homedir4(), ".local", "state");
|
|
32050
|
+
return resolve12(base, "kxm");
|
|
31421
32051
|
}
|
|
31422
32052
|
function hubEnvFile(env = process.env) {
|
|
31423
|
-
return
|
|
32053
|
+
return join21(resolveUserStateRoot2(env), "hub-env.json");
|
|
31424
32054
|
}
|
|
31425
32055
|
function readHubEnvRecord(env = process.env) {
|
|
31426
32056
|
const file = hubEnvFile(env);
|
|
31427
|
-
if (!
|
|
32057
|
+
if (!existsSync18(file)) return void 0;
|
|
31428
32058
|
let parsed;
|
|
31429
32059
|
try {
|
|
31430
|
-
parsed = JSON.parse(
|
|
32060
|
+
parsed = JSON.parse(readFileSync16(file, "utf8"));
|
|
31431
32061
|
} catch (error) {
|
|
31432
32062
|
throw new HubEnvError(`hub env file is malformed at ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
31433
32063
|
}
|
|
@@ -31459,16 +32089,31 @@ function readHubEnvRecord(env = process.env) {
|
|
|
31459
32089
|
...record2.projectTokens !== void 0 ? { projectTokens: record2.projectTokens } : {}
|
|
31460
32090
|
};
|
|
31461
32091
|
}
|
|
31462
|
-
function
|
|
32092
|
+
function cloudModeToken(cwd, env, explicitProject, opRead) {
|
|
32093
|
+
const connection = describeHubConnection(cwd, env, explicitProject === void 0 ? {} : { explicitProject });
|
|
32094
|
+
if (connection.mode !== "cloud") return void 0;
|
|
32095
|
+
const fromConfig = resolveKeyReference(connection.endpoint?.key, env, opRead);
|
|
32096
|
+
if (fromConfig) return fromConfig.value;
|
|
32097
|
+
if (connection.binding?.cloud) return resolveCloudHubToken(connection.binding, env);
|
|
32098
|
+
throw new CloudTokenError(
|
|
32099
|
+
"cloud_token_missing",
|
|
32100
|
+
"cloud hub token is missing; the local hub-env token was not used"
|
|
32101
|
+
);
|
|
32102
|
+
}
|
|
32103
|
+
function resolveClientHubAuthToken(env, project, cwd = process.cwd(), opRead) {
|
|
32104
|
+
const cloud = cloudModeToken(cwd, env, void 0, opRead);
|
|
32105
|
+
if (cloud) return cloud;
|
|
31463
32106
|
const envToken = env.KXM_AUTH_TOKEN?.trim();
|
|
31464
32107
|
if (envToken) return envToken;
|
|
32108
|
+
const fromConfig = resolveKeyReference(describeHubConnection(cwd, env).endpoint?.key, env, opRead);
|
|
32109
|
+
if (fromConfig) return fromConfig.value;
|
|
31465
32110
|
const record2 = readHubEnvRecord(env);
|
|
31466
32111
|
return record2?.projectTokens?.[project]?.trim() || record2?.authToken?.trim() || void 0;
|
|
31467
32112
|
}
|
|
31468
32113
|
|
|
31469
32114
|
// plugins/kxm/src/logger.ts
|
|
31470
|
-
import { appendFileSync, existsSync as
|
|
31471
|
-
import { dirname as
|
|
32115
|
+
import { appendFileSync, existsSync as existsSync19, mkdirSync as mkdirSync9, renameSync as renameSync4, statSync as statSync5, unlinkSync as unlinkSync2 } from "node:fs";
|
|
32116
|
+
import { dirname as dirname12 } from "node:path";
|
|
31472
32117
|
var LOG_LEVEL_PRIORITY = {
|
|
31473
32118
|
debug: 10,
|
|
31474
32119
|
info: 20,
|
|
@@ -31505,7 +32150,7 @@ function redactLogValue(val, key) {
|
|
|
31505
32150
|
function rotateLogFiles(filePath, maxFiles) {
|
|
31506
32151
|
for (let i = maxFiles; i >= 1; i--) {
|
|
31507
32152
|
const current = `${filePath}.${i}`;
|
|
31508
|
-
if (
|
|
32153
|
+
if (existsSync19(current)) {
|
|
31509
32154
|
if (i >= maxFiles) {
|
|
31510
32155
|
try {
|
|
31511
32156
|
unlinkSync2(current);
|
|
@@ -31519,7 +32164,7 @@ function rotateLogFiles(filePath, maxFiles) {
|
|
|
31519
32164
|
}
|
|
31520
32165
|
}
|
|
31521
32166
|
}
|
|
31522
|
-
if (
|
|
32167
|
+
if (existsSync19(filePath)) {
|
|
31523
32168
|
try {
|
|
31524
32169
|
renameSync4(filePath, `${filePath}.1`);
|
|
31525
32170
|
} catch {
|
|
@@ -31536,7 +32181,7 @@ function createLogger(options) {
|
|
|
31536
32181
|
const shouldStdout = options.stdout ?? !isDaemon;
|
|
31537
32182
|
const correlationDefaults = options.correlation ?? {};
|
|
31538
32183
|
let currentSize = 0;
|
|
31539
|
-
if (filePath &&
|
|
32184
|
+
if (filePath && existsSync19(filePath)) {
|
|
31540
32185
|
try {
|
|
31541
32186
|
currentSize = statSync5(filePath).size;
|
|
31542
32187
|
} catch {
|
|
@@ -31574,7 +32219,7 @@ function createLogger(options) {
|
|
|
31574
32219
|
currentSize = 0;
|
|
31575
32220
|
}
|
|
31576
32221
|
try {
|
|
31577
|
-
|
|
32222
|
+
mkdirSync9(dirname12(filePath), { recursive: true });
|
|
31578
32223
|
appendFileSync(filePath, line, { encoding: "utf8", mode: 384 });
|
|
31579
32224
|
currentSize += lineBytes;
|
|
31580
32225
|
} catch {
|
|
@@ -31617,13 +32262,13 @@ function createLogger(options) {
|
|
|
31617
32262
|
|
|
31618
32263
|
// plugins/kxm/src/runtime-supervisor.ts
|
|
31619
32264
|
function kxmSupervisorTokenFile(paths) {
|
|
31620
|
-
return
|
|
32265
|
+
return join22(paths.runtimeDir, "supervisor.token");
|
|
31621
32266
|
}
|
|
31622
32267
|
function publishKxmSupervisorToken(paths, token) {
|
|
31623
32268
|
const file = kxmSupervisorTokenFile(paths);
|
|
31624
|
-
|
|
32269
|
+
mkdirSync10(dirname13(file), { recursive: true, mode: 448 });
|
|
31625
32270
|
const temp = `${file}.${process.pid}.tmp`;
|
|
31626
|
-
|
|
32271
|
+
writeFileSync10(temp, `${token}
|
|
31627
32272
|
`, { encoding: "utf8", mode: 384 });
|
|
31628
32273
|
try {
|
|
31629
32274
|
chmodSync2(temp, 384);
|
|
@@ -31645,7 +32290,7 @@ function readKxmSupervisorToken(paths) {
|
|
|
31645
32290
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
31646
32291
|
throw runtimeError("runtime_path_invalid", file, "supervisor token file must be a regular file, not a link");
|
|
31647
32292
|
}
|
|
31648
|
-
const token =
|
|
32293
|
+
const token = readFileSync17(file, "utf8").trim();
|
|
31649
32294
|
return token.length >= 32 ? token : void 0;
|
|
31650
32295
|
}
|
|
31651
32296
|
function processAlive(pid) {
|
|
@@ -31659,16 +32304,16 @@ function processAlive(pid) {
|
|
|
31659
32304
|
var HEARTBEAT_STALE_MS = 15e3;
|
|
31660
32305
|
var SUPERVISOR_ERROR_MAX_AGE_MS = 3e4;
|
|
31661
32306
|
function supervisorErrorFile(paths) {
|
|
31662
|
-
return
|
|
32307
|
+
return join22(paths.runtimeDir, "supervisor.error");
|
|
31663
32308
|
}
|
|
31664
32309
|
function clearSupervisorError(paths) {
|
|
31665
32310
|
const file = supervisorErrorFile(paths);
|
|
31666
|
-
if (
|
|
32311
|
+
if (existsSync20(file)) rmSync4(file, { force: true });
|
|
31667
32312
|
}
|
|
31668
32313
|
function recordSupervisorError(paths, message) {
|
|
31669
32314
|
try {
|
|
31670
|
-
|
|
31671
|
-
|
|
32315
|
+
mkdirSync10(paths.runtimeDir, { recursive: true, mode: 448 });
|
|
32316
|
+
writeFileSync10(supervisorErrorFile(paths), `${message}
|
|
31672
32317
|
`, { encoding: "utf8", mode: 384 });
|
|
31673
32318
|
} catch {
|
|
31674
32319
|
}
|
|
@@ -31680,7 +32325,7 @@ function readRecentSupervisorError(paths) {
|
|
|
31680
32325
|
const ageMs = Date.now() - stat.mtimeMs;
|
|
31681
32326
|
if (ageMs > SUPERVISOR_ERROR_MAX_AGE_MS) return void 0;
|
|
31682
32327
|
try {
|
|
31683
|
-
return
|
|
32328
|
+
return readFileSync17(file, "utf8").trim();
|
|
31684
32329
|
} catch {
|
|
31685
32330
|
return void 0;
|
|
31686
32331
|
}
|
|
@@ -31719,7 +32364,7 @@ function supervisorStatusOf(record2) {
|
|
|
31719
32364
|
};
|
|
31720
32365
|
}
|
|
31721
32366
|
function kxmSupervisorStatus(paths, options = {}) {
|
|
31722
|
-
if (!
|
|
32367
|
+
if (!existsSync20(paths.registryDb)) return { running: false };
|
|
31723
32368
|
if (options.readOnly) {
|
|
31724
32369
|
const database = openReadOnlyDatabase(paths.registryDb);
|
|
31725
32370
|
try {
|
|
@@ -31785,7 +32430,7 @@ async function ensureKxmSupervisor(options = {}) {
|
|
|
31785
32430
|
throw runtimeError("runtime_supervisor_unreachable", paths.registryDb, `runtime supervisor pid ${status.pid} is registered as running but cannot be probed`);
|
|
31786
32431
|
}
|
|
31787
32432
|
clearSupervisorError(paths);
|
|
31788
|
-
const scriptPath =
|
|
32433
|
+
const scriptPath = join22(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
|
|
31789
32434
|
const spawnImpl = options.spawnImpl ?? ((script, env) => {
|
|
31790
32435
|
const child = spawn3(process.execPath, [script], {
|
|
31791
32436
|
detached: true,
|
|
@@ -31870,8 +32515,8 @@ async function waitForDriveSessions(settled, graceMs) {
|
|
|
31870
32515
|
try {
|
|
31871
32516
|
await Promise.race([
|
|
31872
32517
|
Promise.allSettled(settled),
|
|
31873
|
-
new Promise((
|
|
31874
|
-
timeout = setTimeout(
|
|
32518
|
+
new Promise((resolve13) => {
|
|
32519
|
+
timeout = setTimeout(resolve13, graceMs);
|
|
31875
32520
|
timeout.unref?.();
|
|
31876
32521
|
})
|
|
31877
32522
|
]);
|
|
@@ -32008,7 +32653,7 @@ function syncFailureText(error) {
|
|
|
32008
32653
|
return `${code ? `${code}: ` : ""}${message}`.replace(/(kxm_[A-Za-z0-9_]+|[A-Za-z0-9._-]{40,})/g, "[redacted]").slice(0, 300);
|
|
32009
32654
|
}
|
|
32010
32655
|
function runtimeSupervisorLogFile(paths) {
|
|
32011
|
-
return
|
|
32656
|
+
return join22(paths.runtimeDir, "logs", "kxm-runtime.jsonl");
|
|
32012
32657
|
}
|
|
32013
32658
|
async function startKxmRuntimeSupervisor(options = {}) {
|
|
32014
32659
|
const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -32024,8 +32669,8 @@ async function startKxmRuntimeSupervisor(options = {}) {
|
|
|
32024
32669
|
}
|
|
32025
32670
|
}
|
|
32026
32671
|
async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now, env) {
|
|
32027
|
-
|
|
32028
|
-
|
|
32672
|
+
mkdirSync10(paths.runtimeDir, { recursive: true, mode: 448 });
|
|
32673
|
+
mkdirSync10(paths.projectsDir, { recursive: true, mode: 448 });
|
|
32029
32674
|
const logger = createLogger({
|
|
32030
32675
|
component: "runtime",
|
|
32031
32676
|
path: runtimeSupervisorLogFile(paths),
|
|
@@ -32041,8 +32686,12 @@ async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now, e
|
|
|
32041
32686
|
const contexts = /* @__PURE__ */ new Map();
|
|
32042
32687
|
const syncStatuses = /* @__PURE__ */ new Map();
|
|
32043
32688
|
const registerSyncCredentials = (context) => {
|
|
32044
|
-
|
|
32045
|
-
|
|
32689
|
+
try {
|
|
32690
|
+
const hubToken = resolveClientHubAuthToken(env, context.projectId);
|
|
32691
|
+
if (hubToken) context.eventStore.syncRedactor.register(hubToken);
|
|
32692
|
+
} catch (error) {
|
|
32693
|
+
if (!(error instanceof CloudTokenError)) throw error;
|
|
32694
|
+
}
|
|
32046
32695
|
for (const key of Object.keys(env)) {
|
|
32047
32696
|
if (key.startsWith("KXM_") && (key.endsWith("_TOKEN") || key.endsWith("_KEY")) || key.endsWith("_API_KEY") || key.endsWith("_SECRET")) {
|
|
32048
32697
|
const value = env[key]?.trim();
|
|
@@ -32133,8 +32782,8 @@ async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now, e
|
|
|
32133
32782
|
openRunIds = unsettledRunIds(existing2);
|
|
32134
32783
|
} else {
|
|
32135
32784
|
const registration = registry.projectByRoot(projectRoot);
|
|
32136
|
-
const eventsPath =
|
|
32137
|
-
if (registration &&
|
|
32785
|
+
const eventsPath = join22(paths.projectsDir, registration?.projectKey ?? projectRuntimeKey(projectRoot), "run-events.db");
|
|
32786
|
+
if (registration && existsSync20(eventsPath)) {
|
|
32138
32787
|
const store = new KxmRunEventStore(eventsPath);
|
|
32139
32788
|
try {
|
|
32140
32789
|
openRunIds = store.runsForProject(registration.projectId, 1e4).filter((run) => !SETTLED_RUN_STATUS.has(run.status)).map((run) => run.runId);
|