@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
|
@@ -568,6 +568,47 @@ function validateHubUrl(raw) {
|
|
|
568
568
|
}
|
|
569
569
|
return parsed.href.replace(/\/$/, "");
|
|
570
570
|
}
|
|
571
|
+
function splitTokenCommand(raw) {
|
|
572
|
+
if (/[|&;<>$`\n\r]/.test(raw)) {
|
|
573
|
+
throw new CloudTokenError(
|
|
574
|
+
"cloud_token_command_invalid",
|
|
575
|
+
"token command must be a program and arguments, not a shell pipeline"
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
const args = [];
|
|
579
|
+
let current = "";
|
|
580
|
+
let quote;
|
|
581
|
+
for (const ch of raw) {
|
|
582
|
+
if (quote) {
|
|
583
|
+
if (ch === quote) quote = void 0;
|
|
584
|
+
else current += ch;
|
|
585
|
+
continue;
|
|
586
|
+
}
|
|
587
|
+
if (ch === "'" || ch === '"') {
|
|
588
|
+
quote = ch;
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
if (ch === " " || ch === " ") {
|
|
592
|
+
if (current.length > 0) {
|
|
593
|
+
args.push(current);
|
|
594
|
+
current = "";
|
|
595
|
+
}
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
current += ch;
|
|
599
|
+
}
|
|
600
|
+
if (quote) {
|
|
601
|
+
throw new CloudTokenError("cloud_token_command_invalid", "token command has an unclosed quote");
|
|
602
|
+
}
|
|
603
|
+
if (current.length > 0) args.push(current);
|
|
604
|
+
if (args.length === 0) {
|
|
605
|
+
throw new CloudTokenError("cloud_token_command_invalid", "token command is empty");
|
|
606
|
+
}
|
|
607
|
+
return args;
|
|
608
|
+
}
|
|
609
|
+
function isCloudTokenEnvName(value) {
|
|
610
|
+
return TOKEN_ENV_NAME.test(value);
|
|
611
|
+
}
|
|
571
612
|
function isIsoTimestamp(value) {
|
|
572
613
|
if (Number.isNaN(Date.parse(value))) return false;
|
|
573
614
|
return value === new Date(value).toISOString();
|
|
@@ -591,7 +632,9 @@ function readHubBinding(env = process.env) {
|
|
|
591
632
|
}
|
|
592
633
|
const row = parsed;
|
|
593
634
|
const keys = Object.keys(row);
|
|
594
|
-
|
|
635
|
+
const allowed = /* @__PURE__ */ new Set(["schema", "url", "boundAt", "cloud", "tokenEnv", "tokenCommand"]);
|
|
636
|
+
const cloudish = keys.some((key) => key === "cloud" || key === "tokenEnv" || key === "tokenCommand");
|
|
637
|
+
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)) {
|
|
595
638
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
596
639
|
}
|
|
597
640
|
let url;
|
|
@@ -600,7 +643,34 @@ function readHubBinding(env = process.env) {
|
|
|
600
643
|
} catch {
|
|
601
644
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
602
645
|
}
|
|
603
|
-
return { schema: HUB_BINDING_SCHEMA, url, boundAt: row.boundAt };
|
|
646
|
+
if (!cloudish) return { schema: HUB_BINDING_SCHEMA, url, boundAt: row.boundAt };
|
|
647
|
+
if (row.cloud !== true) throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
648
|
+
let tokenEnv;
|
|
649
|
+
let tokenCommand;
|
|
650
|
+
if (row.tokenEnv !== void 0) {
|
|
651
|
+
if (typeof row.tokenEnv !== "string" || !isCloudTokenEnvName(row.tokenEnv)) {
|
|
652
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
653
|
+
}
|
|
654
|
+
tokenEnv = row.tokenEnv;
|
|
655
|
+
}
|
|
656
|
+
if (row.tokenCommand !== void 0) {
|
|
657
|
+
if (typeof row.tokenCommand !== "string") throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
658
|
+
try {
|
|
659
|
+
splitTokenCommand(row.tokenCommand);
|
|
660
|
+
} catch {
|
|
661
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
662
|
+
}
|
|
663
|
+
tokenCommand = row.tokenCommand;
|
|
664
|
+
}
|
|
665
|
+
if (!tokenEnv && !tokenCommand) throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
666
|
+
return {
|
|
667
|
+
schema: HUB_BINDING_SCHEMA,
|
|
668
|
+
url,
|
|
669
|
+
boundAt: row.boundAt,
|
|
670
|
+
cloud: true,
|
|
671
|
+
...tokenEnv ? { tokenEnv } : {},
|
|
672
|
+
...tokenCommand ? { tokenCommand } : {}
|
|
673
|
+
};
|
|
604
674
|
}
|
|
605
675
|
async function probeHubHealth(url, fetchImpl, timeoutMs = HUB_HEALTH_PROBE_MS) {
|
|
606
676
|
const started = Date.now();
|
|
@@ -625,12 +695,21 @@ async function probeHubHealth(url, fetchImpl, timeoutMs = HUB_HEALTH_PROBE_MS) {
|
|
|
625
695
|
clearTimeout(timer);
|
|
626
696
|
}
|
|
627
697
|
}
|
|
628
|
-
var HUB_BINDING_SCHEMA, HUB_HEALTH_PROBE_MS, HubBindingError;
|
|
698
|
+
var HUB_BINDING_SCHEMA, HUB_HEALTH_PROBE_MS, CloudTokenError, TOKEN_ENV_NAME, HubBindingError;
|
|
629
699
|
var init_hub_binding = __esm({
|
|
630
700
|
"plugins/kxm/src/hub-binding.ts"() {
|
|
631
701
|
"use strict";
|
|
632
702
|
HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
633
703
|
HUB_HEALTH_PROBE_MS = 300;
|
|
704
|
+
CloudTokenError = class extends Error {
|
|
705
|
+
code;
|
|
706
|
+
constructor(code, message) {
|
|
707
|
+
super(message);
|
|
708
|
+
this.name = "CloudTokenError";
|
|
709
|
+
this.code = code;
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
TOKEN_ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
634
713
|
HubBindingError = class extends Error {
|
|
635
714
|
constructor(message) {
|
|
636
715
|
super(message);
|
|
@@ -2556,7 +2635,7 @@ var require_stringify = __commonJS({
|
|
|
2556
2635
|
props.push(doc.directives.tagString(tag));
|
|
2557
2636
|
return props.join(" ");
|
|
2558
2637
|
}
|
|
2559
|
-
function
|
|
2638
|
+
function stringify3(item, ctx, onComment, onChompKeep) {
|
|
2560
2639
|
if (identity.isPair(item))
|
|
2561
2640
|
return item.toString(ctx, onComment, onChompKeep);
|
|
2562
2641
|
if (identity.isAlias(item)) {
|
|
@@ -2585,7 +2664,7 @@ var require_stringify = __commonJS({
|
|
|
2585
2664
|
${ctx.indent}${str}`;
|
|
2586
2665
|
}
|
|
2587
2666
|
exports.createStringifyContext = createStringifyContext;
|
|
2588
|
-
exports.stringify =
|
|
2667
|
+
exports.stringify = stringify3;
|
|
2589
2668
|
}
|
|
2590
2669
|
});
|
|
2591
2670
|
|
|
@@ -2595,7 +2674,7 @@ var require_stringifyPair = __commonJS({
|
|
|
2595
2674
|
"use strict";
|
|
2596
2675
|
var identity = require_identity();
|
|
2597
2676
|
var Scalar = require_Scalar();
|
|
2598
|
-
var
|
|
2677
|
+
var stringify3 = require_stringify();
|
|
2599
2678
|
var stringifyComment = require_stringifyComment();
|
|
2600
2679
|
function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
|
|
2601
2680
|
const { allNullValues, doc, indent, indentStep, options: { commentString, indentSeq, simpleKeys } } = ctx;
|
|
@@ -2617,7 +2696,7 @@ var require_stringifyPair = __commonJS({
|
|
|
2617
2696
|
});
|
|
2618
2697
|
let keyCommentDone = false;
|
|
2619
2698
|
let chompKeep = false;
|
|
2620
|
-
let str =
|
|
2699
|
+
let str = stringify3.stringify(key, ctx, () => keyCommentDone = true, () => chompKeep = true);
|
|
2621
2700
|
if (!explicitKey && !ctx.inFlow && str.length > 1024) {
|
|
2622
2701
|
if (simpleKeys)
|
|
2623
2702
|
throw new Error("With simple keys, single line scalar must not span more than 1024 characters");
|
|
@@ -2669,7 +2748,7 @@ ${indent}:`;
|
|
|
2669
2748
|
ctx.indent = ctx.indent.substring(2);
|
|
2670
2749
|
}
|
|
2671
2750
|
let valueCommentDone = false;
|
|
2672
|
-
const valueStr =
|
|
2751
|
+
const valueStr = stringify3.stringify(value, ctx, () => valueCommentDone = true, () => chompKeep = true);
|
|
2673
2752
|
let ws = " ";
|
|
2674
2753
|
if (keyComment || vsb || vcb) {
|
|
2675
2754
|
ws = vsb ? "\n" : "";
|
|
@@ -2810,7 +2889,7 @@ var require_addPairToJSMap = __commonJS({
|
|
|
2810
2889
|
"use strict";
|
|
2811
2890
|
var log = require_log();
|
|
2812
2891
|
var merge = require_merge();
|
|
2813
|
-
var
|
|
2892
|
+
var stringify3 = require_stringify();
|
|
2814
2893
|
var identity = require_identity();
|
|
2815
2894
|
var toJS = require_toJS();
|
|
2816
2895
|
function addPairToJSMap(ctx, map, { key, value }) {
|
|
@@ -2846,7 +2925,7 @@ var require_addPairToJSMap = __commonJS({
|
|
|
2846
2925
|
if (typeof jsKey !== "object")
|
|
2847
2926
|
return String(jsKey);
|
|
2848
2927
|
if (identity.isNode(key) && ctx?.doc) {
|
|
2849
|
-
const strCtx =
|
|
2928
|
+
const strCtx = stringify3.createStringifyContext(ctx.doc, {});
|
|
2850
2929
|
strCtx.anchors = /* @__PURE__ */ new Set();
|
|
2851
2930
|
for (const node of ctx.anchors.keys())
|
|
2852
2931
|
strCtx.anchors.add(node.anchor);
|
|
@@ -2913,12 +2992,12 @@ var require_stringifyCollection = __commonJS({
|
|
|
2913
2992
|
"node_modules/yaml/dist/stringify/stringifyCollection.js"(exports) {
|
|
2914
2993
|
"use strict";
|
|
2915
2994
|
var identity = require_identity();
|
|
2916
|
-
var
|
|
2995
|
+
var stringify3 = require_stringify();
|
|
2917
2996
|
var stringifyComment = require_stringifyComment();
|
|
2918
2997
|
function stringifyCollection(collection, ctx, options) {
|
|
2919
2998
|
const flow = ctx.inFlow ?? collection.flow;
|
|
2920
|
-
const
|
|
2921
|
-
return
|
|
2999
|
+
const stringify4 = flow ? stringifyFlowCollection : stringifyBlockCollection;
|
|
3000
|
+
return stringify4(collection, ctx, options);
|
|
2922
3001
|
}
|
|
2923
3002
|
function stringifyBlockCollection({ comment, items }, ctx, { blockItemPrefix, flowChars, itemIndent, onChompKeep, onComment }) {
|
|
2924
3003
|
const { indent, options: { commentString } } = ctx;
|
|
@@ -2943,7 +3022,7 @@ var require_stringifyCollection = __commonJS({
|
|
|
2943
3022
|
}
|
|
2944
3023
|
}
|
|
2945
3024
|
chompKeep = false;
|
|
2946
|
-
let str2 =
|
|
3025
|
+
let str2 = stringify3.stringify(item, itemCtx, () => comment2 = null, () => chompKeep = true);
|
|
2947
3026
|
if (comment2)
|
|
2948
3027
|
str2 += stringifyComment.lineComment(str2, itemIndent, commentString(comment2));
|
|
2949
3028
|
if (chompKeep && comment2)
|
|
@@ -3010,7 +3089,7 @@ ${indent}${line}` : "\n";
|
|
|
3010
3089
|
}
|
|
3011
3090
|
if (comment)
|
|
3012
3091
|
reqNewline = true;
|
|
3013
|
-
let str =
|
|
3092
|
+
let str = stringify3.stringify(item, itemCtx, () => comment = null);
|
|
3014
3093
|
reqNewline || (reqNewline = lines.length > linesAtValue || str.includes("\n"));
|
|
3015
3094
|
if (i < items.length - 1) {
|
|
3016
3095
|
str += ",";
|
|
@@ -4371,7 +4450,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
4371
4450
|
"node_modules/yaml/dist/stringify/stringifyDocument.js"(exports) {
|
|
4372
4451
|
"use strict";
|
|
4373
4452
|
var identity = require_identity();
|
|
4374
|
-
var
|
|
4453
|
+
var stringify3 = require_stringify();
|
|
4375
4454
|
var stringifyComment = require_stringifyComment();
|
|
4376
4455
|
function stringifyDocument(doc, options) {
|
|
4377
4456
|
const lines = [];
|
|
@@ -4386,7 +4465,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
4386
4465
|
}
|
|
4387
4466
|
if (hasDirectives)
|
|
4388
4467
|
lines.push("---");
|
|
4389
|
-
const ctx =
|
|
4468
|
+
const ctx = stringify3.createStringifyContext(doc, options);
|
|
4390
4469
|
const { commentString } = ctx.options;
|
|
4391
4470
|
if (doc.commentBefore) {
|
|
4392
4471
|
if (lines.length !== 1)
|
|
@@ -4408,7 +4487,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
4408
4487
|
contentComment = doc.contents.comment;
|
|
4409
4488
|
}
|
|
4410
4489
|
const onChompKeep = contentComment ? void 0 : () => chompKeep = true;
|
|
4411
|
-
let body =
|
|
4490
|
+
let body = stringify3.stringify(doc.contents, ctx, () => contentComment = null, onChompKeep);
|
|
4412
4491
|
if (contentComment)
|
|
4413
4492
|
body += stringifyComment.lineComment(body, "", commentString(contentComment));
|
|
4414
4493
|
if ((body[0] === "|" || body[0] === ">") && lines[lines.length - 1] === "---") {
|
|
@@ -4416,7 +4495,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
4416
4495
|
} else
|
|
4417
4496
|
lines.push(body);
|
|
4418
4497
|
} else {
|
|
4419
|
-
lines.push(
|
|
4498
|
+
lines.push(stringify3.stringify(doc.contents, ctx));
|
|
4420
4499
|
}
|
|
4421
4500
|
if (doc.directives?.docEnd) {
|
|
4422
4501
|
if (doc.comment) {
|
|
@@ -6552,7 +6631,7 @@ var require_cst_scalar = __commonJS({
|
|
|
6552
6631
|
var require_cst_stringify = __commonJS({
|
|
6553
6632
|
"node_modules/yaml/dist/parse/cst-stringify.js"(exports) {
|
|
6554
6633
|
"use strict";
|
|
6555
|
-
var
|
|
6634
|
+
var stringify3 = (cst) => "type" in cst ? stringifyToken(cst) : stringifyItem(cst);
|
|
6556
6635
|
function stringifyToken(token) {
|
|
6557
6636
|
switch (token.type) {
|
|
6558
6637
|
case "block-scalar": {
|
|
@@ -6605,7 +6684,7 @@ var require_cst_stringify = __commonJS({
|
|
|
6605
6684
|
res += stringifyToken(value);
|
|
6606
6685
|
return res;
|
|
6607
6686
|
}
|
|
6608
|
-
exports.stringify =
|
|
6687
|
+
exports.stringify = stringify3;
|
|
6609
6688
|
}
|
|
6610
6689
|
});
|
|
6611
6690
|
|
|
@@ -8316,7 +8395,7 @@ var require_public_api = __commonJS({
|
|
|
8316
8395
|
}
|
|
8317
8396
|
return doc;
|
|
8318
8397
|
}
|
|
8319
|
-
function
|
|
8398
|
+
function parse3(src, reviver, options) {
|
|
8320
8399
|
let _reviver = void 0;
|
|
8321
8400
|
if (typeof reviver === "function") {
|
|
8322
8401
|
_reviver = reviver;
|
|
@@ -8335,7 +8414,7 @@ var require_public_api = __commonJS({
|
|
|
8335
8414
|
}
|
|
8336
8415
|
return doc.toJS(Object.assign({ reviver: _reviver }, options));
|
|
8337
8416
|
}
|
|
8338
|
-
function
|
|
8417
|
+
function stringify3(value, replacer, options) {
|
|
8339
8418
|
let _replacer = null;
|
|
8340
8419
|
if (typeof replacer === "function" || Array.isArray(replacer)) {
|
|
8341
8420
|
_replacer = replacer;
|
|
@@ -8357,10 +8436,10 @@ var require_public_api = __commonJS({
|
|
|
8357
8436
|
return value.toString(options);
|
|
8358
8437
|
return new Document.Document(value, _replacer, options).toString(options);
|
|
8359
8438
|
}
|
|
8360
|
-
exports.parse =
|
|
8439
|
+
exports.parse = parse3;
|
|
8361
8440
|
exports.parseAllDocuments = parseAllDocuments;
|
|
8362
8441
|
exports.parseDocument = parseDocument;
|
|
8363
|
-
exports.stringify =
|
|
8442
|
+
exports.stringify = stringify3;
|
|
8364
8443
|
}
|
|
8365
8444
|
});
|
|
8366
8445
|
|
|
@@ -8765,26 +8844,402 @@ var init_memory = __esm({
|
|
|
8765
8844
|
}
|
|
8766
8845
|
});
|
|
8767
8846
|
|
|
8768
|
-
// plugins/kxm/src/
|
|
8769
|
-
|
|
8770
|
-
|
|
8771
|
-
|
|
8847
|
+
// plugins/kxm/src/config.ts
|
|
8848
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "node:fs";
|
|
8849
|
+
import { tmpdir, homedir as homedir3 } from "node:os";
|
|
8850
|
+
import { dirname as dirname3, join as join6, resolve as resolve5 } from "node:path";
|
|
8851
|
+
function isHubKeyEnvName(value) {
|
|
8852
|
+
return HUB_ENV_NAME.test(value);
|
|
8853
|
+
}
|
|
8854
|
+
function isHubOpReference(value) {
|
|
8855
|
+
return HUB_OP_REF.test(value);
|
|
8856
|
+
}
|
|
8857
|
+
function userConfigDirectory(overrideDir) {
|
|
8858
|
+
if (overrideDir) return resolve5(overrideDir);
|
|
8859
|
+
return resolve5(process.env.KXM_USER_CONFIG_DIR?.trim() || join6(homedir3(), ".config", "kxm"));
|
|
8860
|
+
}
|
|
8861
|
+
function repoConfigDirectory(repoRoot) {
|
|
8862
|
+
return resolve5(repoRoot, ".kxm");
|
|
8863
|
+
}
|
|
8864
|
+
function deepMerge(target, source) {
|
|
8865
|
+
const result = { ...target };
|
|
8866
|
+
for (const [key, val] of Object.entries(source)) {
|
|
8867
|
+
if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
8868
|
+
const existing = result[key] && typeof result[key] === "object" && !Array.isArray(result[key]) ? result[key] : {};
|
|
8869
|
+
result[key] = deepMerge(existing, val);
|
|
8870
|
+
} else if (val !== void 0) {
|
|
8871
|
+
result[key] = val;
|
|
8872
|
+
}
|
|
8873
|
+
}
|
|
8874
|
+
return result;
|
|
8875
|
+
}
|
|
8876
|
+
function literalSecretMessage(path) {
|
|
8877
|
+
return `refusing literal hub token at ${path}: store an op:// reference (key.op) or an environment variable name (key.env), never the token`;
|
|
8878
|
+
}
|
|
8879
|
+
function rejectLiteralHubSecrets(value, path) {
|
|
8880
|
+
if (Array.isArray(value)) {
|
|
8881
|
+
value.forEach((item, index) => rejectLiteralHubSecrets(item, `${path}[${index}]`));
|
|
8882
|
+
return;
|
|
8883
|
+
}
|
|
8884
|
+
if (!value || typeof value !== "object") return;
|
|
8885
|
+
for (const [key, child] of Object.entries(value)) {
|
|
8886
|
+
const childPath = `${path}.${key}`;
|
|
8887
|
+
if (typeof child === "string" && (key === "key" || LITERAL_SECRET_KEY.test(key))) {
|
|
8888
|
+
throw new KxmHubConfigError(literalSecretMessage(childPath));
|
|
8889
|
+
}
|
|
8890
|
+
if (child && typeof child === "object") rejectLiteralHubSecrets(child, childPath);
|
|
8891
|
+
}
|
|
8892
|
+
}
|
|
8893
|
+
function parseKeyRef(raw, path) {
|
|
8894
|
+
if (raw === void 0) return void 0;
|
|
8895
|
+
if (typeof raw === "string") throw new KxmHubConfigError(literalSecretMessage(path));
|
|
8896
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
8897
|
+
throw new KxmHubConfigError(`${path} must be a key reference with op and/or env, never a token`);
|
|
8898
|
+
}
|
|
8899
|
+
const row = raw;
|
|
8900
|
+
for (const key of Object.keys(row)) {
|
|
8901
|
+
if (key !== "op" && key !== "env") {
|
|
8902
|
+
throw new KxmHubConfigError(literalSecretMessage(`${path}.${key}`));
|
|
8903
|
+
}
|
|
8904
|
+
}
|
|
8905
|
+
const ref = {};
|
|
8906
|
+
if (row.op !== void 0) {
|
|
8907
|
+
if (typeof row.op !== "string" || !isHubOpReference(row.op)) {
|
|
8908
|
+
throw new KxmHubConfigError(`${path}.op must be an op://vault/item/field reference, not a token`);
|
|
8909
|
+
}
|
|
8910
|
+
ref.op = row.op;
|
|
8911
|
+
}
|
|
8912
|
+
if (row.env !== void 0) {
|
|
8913
|
+
if (typeof row.env !== "string" || !isHubKeyEnvName(row.env)) {
|
|
8914
|
+
throw new KxmHubConfigError(`${path}.env must be an environment variable name, not a token`);
|
|
8915
|
+
}
|
|
8916
|
+
ref.env = row.env;
|
|
8917
|
+
}
|
|
8918
|
+
if (!ref.op && !ref.env) throw new KxmHubConfigError(`${path} needs key.op, key.env, or both`);
|
|
8919
|
+
return ref;
|
|
8920
|
+
}
|
|
8921
|
+
function parseEndpoint(raw, path) {
|
|
8922
|
+
if (raw === void 0) return void 0;
|
|
8923
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
8924
|
+
throw new KxmHubConfigError(`${path} must be an object with url, project, and key`);
|
|
8925
|
+
}
|
|
8926
|
+
const row = raw;
|
|
8927
|
+
const endpoint = {};
|
|
8928
|
+
if (row.url !== void 0) {
|
|
8929
|
+
if (typeof row.url !== "string" || !isHubUrl(row.url)) {
|
|
8930
|
+
throw new KxmHubConfigError(`${path}.url must be an http or https URL without credentials, query, or fragment`);
|
|
8931
|
+
}
|
|
8932
|
+
endpoint.url = row.url.replace(/\/$/, "");
|
|
8933
|
+
}
|
|
8934
|
+
if (row.project !== void 0) {
|
|
8935
|
+
if (typeof row.project !== "string" || !isHubProjectId(row.project)) {
|
|
8936
|
+
throw new KxmHubConfigError(`${path}.project must be a single-line project id, not a token`);
|
|
8937
|
+
}
|
|
8938
|
+
endpoint.project = row.project.trim();
|
|
8939
|
+
}
|
|
8940
|
+
const key = parseKeyRef(row.key, `${path}.key`);
|
|
8941
|
+
if (key) endpoint.key = key;
|
|
8942
|
+
for (const name of Object.keys(row)) {
|
|
8943
|
+
if (name !== "url" && name !== "project" && name !== "key") {
|
|
8944
|
+
if (typeof row[name] === "string") throw new KxmHubConfigError(literalSecretMessage(`${path}.${name}`));
|
|
8945
|
+
throw new KxmHubConfigError(`${path}.${name} is not a hub endpoint field`);
|
|
8946
|
+
}
|
|
8947
|
+
}
|
|
8948
|
+
return endpoint;
|
|
8949
|
+
}
|
|
8950
|
+
function isHubUrl(raw) {
|
|
8951
|
+
try {
|
|
8952
|
+
const parsed = new URL(raw);
|
|
8953
|
+
return (parsed.protocol === "http:" || parsed.protocol === "https:") && parsed.username === "" && parsed.password === "" && parsed.search === "" && parsed.hash === "" && !raw.includes("?") && !raw.includes("#");
|
|
8954
|
+
} catch {
|
|
8955
|
+
return false;
|
|
8956
|
+
}
|
|
8957
|
+
}
|
|
8958
|
+
function isHubProjectId(raw) {
|
|
8959
|
+
const value = raw.trim();
|
|
8960
|
+
return value.length > 0 && value.length <= 200 && !/[\s\r\n]/.test(value);
|
|
8961
|
+
}
|
|
8962
|
+
function parseProjectMap(raw) {
|
|
8963
|
+
if (raw === void 0) return void 0;
|
|
8964
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
8965
|
+
throw new KxmHubConfigError("hub.projects must be a map of project id to key reference, never a token");
|
|
8966
|
+
}
|
|
8967
|
+
const projects = {};
|
|
8968
|
+
for (const [project, value] of Object.entries(raw)) {
|
|
8969
|
+
if (!isHubProjectId(project)) {
|
|
8970
|
+
throw new KxmHubConfigError(`hub.projects key ${JSON.stringify(project)} must be a project id, not a token`);
|
|
8971
|
+
}
|
|
8972
|
+
const ref = parseKeyRef(value, `hub.projects.${project}`);
|
|
8973
|
+
if (!ref) throw new KxmHubConfigError(`hub.projects.${project} needs an op:// reference or an environment variable name`);
|
|
8974
|
+
projects[project.trim()] = ref;
|
|
8975
|
+
}
|
|
8976
|
+
return projects;
|
|
8977
|
+
}
|
|
8978
|
+
function normalizeHubConfig(raw) {
|
|
8979
|
+
const autoStart = raw?.autoStart;
|
|
8980
|
+
const hub = {
|
|
8981
|
+
autoStart: autoStart === "off" || autoStart === "background" ? autoStart : DEFAULT_KXM_CONFIG.hub.autoStart
|
|
8982
|
+
};
|
|
8983
|
+
if (raw === void 0) return hub;
|
|
8984
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
8985
|
+
throw new KxmHubConfigError("hub must be an object");
|
|
8986
|
+
}
|
|
8987
|
+
rejectLiteralHubSecrets(raw, "hub");
|
|
8988
|
+
const row = raw;
|
|
8989
|
+
if (row.mode !== void 0) {
|
|
8990
|
+
if (row.mode !== "local" && row.mode !== "cloud") {
|
|
8991
|
+
throw new KxmHubConfigError("hub.mode must be local or cloud");
|
|
8992
|
+
}
|
|
8993
|
+
hub.mode = row.mode;
|
|
8994
|
+
}
|
|
8995
|
+
const local = parseEndpoint(row.local, "hub.local");
|
|
8996
|
+
const cloud = parseEndpoint(row.cloud, "hub.cloud");
|
|
8997
|
+
const projects = parseProjectMap(row.projects);
|
|
8998
|
+
if (local) hub.local = local;
|
|
8999
|
+
if (cloud) hub.cloud = cloud;
|
|
9000
|
+
if (projects && Object.keys(projects).length > 0) hub.projects = projects;
|
|
9001
|
+
return hub;
|
|
9002
|
+
}
|
|
9003
|
+
function findConfigRoot(start) {
|
|
9004
|
+
let dir = resolve5(start);
|
|
9005
|
+
for (; ; ) {
|
|
9006
|
+
if (existsSync7(join6(dir, ".kxm", "project.yaml")) || existsSync7(join6(dir, ".kxm", "config.yaml"))) return dir;
|
|
9007
|
+
const parent = dirname3(dir);
|
|
9008
|
+
if (parent === dir) return resolve5(start);
|
|
9009
|
+
dir = parent;
|
|
9010
|
+
}
|
|
9011
|
+
}
|
|
9012
|
+
function userConfigDirForEnv(env) {
|
|
9013
|
+
const explicit = env.KXM_USER_CONFIG_DIR?.trim();
|
|
9014
|
+
if (explicit) return explicit;
|
|
9015
|
+
if (env === process.env) return void 0;
|
|
9016
|
+
return join6(tmpdir(), "kxm-no-user-config");
|
|
9017
|
+
}
|
|
9018
|
+
function loadHubSettings(start, env = process.env) {
|
|
9019
|
+
const userConfigDir = userConfigDirForEnv(env);
|
|
9020
|
+
return loadKxmConfig(findConfigRoot(start), userConfigDir === void 0 ? {} : { userConfigDir }).hub;
|
|
9021
|
+
}
|
|
9022
|
+
function recordOf(raw) {
|
|
9023
|
+
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
9024
|
+
}
|
|
9025
|
+
function finiteNumber(value) {
|
|
9026
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
9027
|
+
}
|
|
9028
|
+
function normalizeImprovementConfig(raw) {
|
|
9029
|
+
const value = recordOf(raw);
|
|
9030
|
+
const threshold = recordOf(value.autoThreshold);
|
|
9031
|
+
const policy = value.promotionPolicy;
|
|
9032
|
+
const halfLife = finiteNumber(value.telemetryHalfLifeDays);
|
|
9033
|
+
const minRuns = finiteNumber(threshold.minRuns);
|
|
9034
|
+
const minPassRate = finiteNumber(threshold.minPassRate);
|
|
9035
|
+
const minCostSavings = finiteNumber(threshold.minCostSavings);
|
|
9036
|
+
return {
|
|
9037
|
+
promotionPolicy: IMPROVEMENT_PROMOTION_POLICIES.includes(policy) ? policy : "manual_pr",
|
|
9038
|
+
telemetryHalfLifeDays: halfLife !== void 0 && halfLife > 0 && halfLife <= 3650 ? halfLife : 14,
|
|
9039
|
+
autoThreshold: {
|
|
9040
|
+
minRuns: minRuns !== void 0 && Number.isInteger(minRuns) && minRuns >= 1 && minRuns <= 1e6 ? minRuns : 10,
|
|
9041
|
+
minPassRate: minPassRate !== void 0 && minPassRate >= 0 && minPassRate <= 1 ? minPassRate : 0.95,
|
|
9042
|
+
minCostSavings: minCostSavings !== void 0 && minCostSavings >= 0 ? minCostSavings : 0.5
|
|
9043
|
+
}
|
|
9044
|
+
};
|
|
9045
|
+
}
|
|
9046
|
+
function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
|
|
9047
|
+
const userDir = userConfigDirectory(options.userConfigDir);
|
|
9048
|
+
const userConfigFile = join6(userDir, "config.yaml");
|
|
9049
|
+
const repoDir = repoConfigDirectory(repoRoot);
|
|
9050
|
+
const repoConfigFile = join6(repoDir, "config.yaml");
|
|
9051
|
+
let userRaw = {};
|
|
9052
|
+
let userLoadedPath;
|
|
9053
|
+
if (existsSync7(userConfigFile)) {
|
|
9054
|
+
try {
|
|
9055
|
+
const text = readFileSync7(userConfigFile, "utf8");
|
|
9056
|
+
userRaw = (0, import_yaml2.parse)(text) ?? {};
|
|
9057
|
+
userLoadedPath = userConfigFile;
|
|
9058
|
+
} catch (error) {
|
|
9059
|
+
throw new Error(`invalid user config YAML at ${userConfigFile}`, { cause: error });
|
|
9060
|
+
}
|
|
9061
|
+
}
|
|
9062
|
+
let repoRaw = {};
|
|
9063
|
+
let repoLoadedPath;
|
|
9064
|
+
if (existsSync7(repoConfigFile)) {
|
|
9065
|
+
try {
|
|
9066
|
+
const text = readFileSync7(repoConfigFile, "utf8");
|
|
9067
|
+
repoRaw = (0, import_yaml2.parse)(text) ?? {};
|
|
9068
|
+
repoLoadedPath = repoConfigFile;
|
|
9069
|
+
} catch (error) {
|
|
9070
|
+
throw new Error(`invalid project config YAML at ${repoConfigFile}`, { cause: error });
|
|
9071
|
+
}
|
|
9072
|
+
}
|
|
9073
|
+
const baseCopy = JSON.parse(JSON.stringify(DEFAULT_KXM_CONFIG));
|
|
9074
|
+
const mergedUser = deepMerge(baseCopy, userRaw);
|
|
9075
|
+
const mergedAll = deepMerge(mergedUser, repoRaw);
|
|
9076
|
+
return {
|
|
9077
|
+
schema: KXM_CONFIG_SCHEMA,
|
|
9078
|
+
user: mergedAll.user ?? {},
|
|
9079
|
+
defaults: mergedAll.defaults ?? {},
|
|
9080
|
+
dash: mergedAll.dash ?? {},
|
|
9081
|
+
sync: mergedAll.sync ?? {},
|
|
9082
|
+
hub: normalizeHubConfig(mergedAll.hub),
|
|
9083
|
+
improvement: normalizeImprovementConfig(mergedAll.improvement),
|
|
9084
|
+
routing: mergedAll.routing ?? DEFAULT_KXM_CONFIG.routing,
|
|
9085
|
+
telemetry: mergedAll.telemetry ?? DEFAULT_KXM_CONFIG.telemetry,
|
|
9086
|
+
loadedFrom: {
|
|
9087
|
+
userConfigPath: userLoadedPath,
|
|
9088
|
+
repoConfigPath: repoLoadedPath
|
|
9089
|
+
}
|
|
9090
|
+
};
|
|
9091
|
+
}
|
|
9092
|
+
var import_yaml2, KXM_CONFIG_SCHEMA, KxmHubConfigError, HUB_ENV_NAME, HUB_OP_REF, LITERAL_SECRET_KEY, IMPROVEMENT_PROMOTION_POLICIES, DEFAULT_KXM_CONFIG;
|
|
9093
|
+
var init_config = __esm({
|
|
9094
|
+
"plugins/kxm/src/config.ts"() {
|
|
9095
|
+
"use strict";
|
|
9096
|
+
import_yaml2 = __toESM(require_dist(), 1);
|
|
9097
|
+
KXM_CONFIG_SCHEMA = "kxm.config.v1";
|
|
9098
|
+
KxmHubConfigError = class extends Error {
|
|
9099
|
+
code = "hub_config_invalid";
|
|
9100
|
+
constructor(message) {
|
|
9101
|
+
super(message);
|
|
9102
|
+
this.name = "KxmHubConfigError";
|
|
9103
|
+
}
|
|
9104
|
+
};
|
|
9105
|
+
HUB_ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
9106
|
+
HUB_OP_REF = /^op:\/\/\S+\/\S+\/\S+$/;
|
|
9107
|
+
LITERAL_SECRET_KEY = /^(token|secret|password|authToken|auth_token|apiKey|api_key|api_token|bearer|credential|access_token)$/i;
|
|
9108
|
+
IMPROVEMENT_PROMOTION_POLICIES = ["manual_pr", "critic_quorum", "auto_threshold"];
|
|
9109
|
+
DEFAULT_KXM_CONFIG = {
|
|
9110
|
+
schema: KXM_CONFIG_SCHEMA,
|
|
9111
|
+
user: {
|
|
9112
|
+
theme: "dark",
|
|
9113
|
+
preferredCritics: ["reviewer-arch", "reviewer-cli"],
|
|
9114
|
+
tokenBudget: 16e3
|
|
9115
|
+
},
|
|
9116
|
+
defaults: {
|
|
9117
|
+
workflow: "software-engineering/feature-implementation",
|
|
9118
|
+
harness: "pi"
|
|
9119
|
+
},
|
|
9120
|
+
dash: {
|
|
9121
|
+
defaultScreen: "agents",
|
|
9122
|
+
refreshIntervalMs: 1e3,
|
|
9123
|
+
autoOpen: false
|
|
9124
|
+
},
|
|
9125
|
+
sync: {
|
|
9126
|
+
defaultTracker: "none"
|
|
9127
|
+
},
|
|
9128
|
+
hub: {
|
|
9129
|
+
autoStart: "background"
|
|
9130
|
+
},
|
|
9131
|
+
improvement: {
|
|
9132
|
+
promotionPolicy: "manual_pr",
|
|
9133
|
+
telemetryHalfLifeDays: 14,
|
|
9134
|
+
autoThreshold: {
|
|
9135
|
+
minRuns: 10,
|
|
9136
|
+
minPassRate: 0.95,
|
|
9137
|
+
minCostSavings: 0.5
|
|
9138
|
+
}
|
|
9139
|
+
},
|
|
9140
|
+
routing: {
|
|
9141
|
+
shadowExecution: {
|
|
9142
|
+
enabled: false,
|
|
9143
|
+
sampleRate: 0.05,
|
|
9144
|
+
candidateModels: []
|
|
9145
|
+
},
|
|
9146
|
+
circuitBreaker: {
|
|
9147
|
+
mode: "soft_demotion",
|
|
9148
|
+
failureThreshold: 3,
|
|
9149
|
+
windowSeconds: 3600,
|
|
9150
|
+
cooldownSeconds: 1800,
|
|
9151
|
+
penaltyMultiplier: 5
|
|
9152
|
+
}
|
|
9153
|
+
},
|
|
9154
|
+
telemetry: {
|
|
9155
|
+
federated: true,
|
|
9156
|
+
anonymize: true
|
|
9157
|
+
}
|
|
9158
|
+
};
|
|
9159
|
+
}
|
|
8772
9160
|
});
|
|
8773
|
-
|
|
8774
|
-
|
|
8775
|
-
|
|
8776
|
-
|
|
8777
|
-
|
|
9161
|
+
|
|
9162
|
+
// plugins/kxm/src/hub-identity.ts
|
|
9163
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8 } from "node:fs";
|
|
9164
|
+
import { basename as basename2, dirname as dirname4, join as join7, resolve as resolve6 } from "node:path";
|
|
9165
|
+
function projectYamlId(start) {
|
|
9166
|
+
let dir = resolve6(start);
|
|
9167
|
+
for (; ; ) {
|
|
9168
|
+
const file = join7(dir, ".kxm", "project.yaml");
|
|
9169
|
+
if (existsSync8(file)) {
|
|
9170
|
+
try {
|
|
9171
|
+
const doc = (0, import_yaml3.parse)(readFileSync8(file, "utf8"));
|
|
9172
|
+
if (doc && typeof doc === "object" && !Array.isArray(doc) && typeof doc.id === "string" && doc.id.trim()) {
|
|
9173
|
+
return doc.id.trim();
|
|
9174
|
+
}
|
|
9175
|
+
} catch {
|
|
9176
|
+
}
|
|
9177
|
+
return void 0;
|
|
9178
|
+
}
|
|
9179
|
+
const parent = dirname4(dir);
|
|
9180
|
+
if (parent === dir) return void 0;
|
|
9181
|
+
dir = parent;
|
|
9182
|
+
}
|
|
9183
|
+
}
|
|
9184
|
+
function packageName(cwd) {
|
|
8778
9185
|
try {
|
|
8779
|
-
const pkg = JSON.parse(
|
|
9186
|
+
const pkg = JSON.parse(readFileSync8(join7(cwd, "package.json"), "utf8"));
|
|
8780
9187
|
if (typeof pkg.name === "string" && pkg.name.trim().length > 0) return pkg.name.trim();
|
|
8781
9188
|
} catch {
|
|
8782
9189
|
}
|
|
8783
|
-
return
|
|
9190
|
+
return void 0;
|
|
9191
|
+
}
|
|
9192
|
+
function activeBinding(env) {
|
|
9193
|
+
try {
|
|
9194
|
+
return readHubBinding(env);
|
|
9195
|
+
} catch (error) {
|
|
9196
|
+
if (error instanceof HubBindingError) return void 0;
|
|
9197
|
+
throw error;
|
|
9198
|
+
}
|
|
8784
9199
|
}
|
|
9200
|
+
function endpointFor(mode, settings) {
|
|
9201
|
+
return mode === "cloud" ? settings.cloud : settings.local;
|
|
9202
|
+
}
|
|
9203
|
+
function resolveProjectIdentity(cwd, env = process.env, explicit) {
|
|
9204
|
+
const fromExplicit = explicit?.trim();
|
|
9205
|
+
if (fromExplicit) return { project: fromExplicit, source: "flag", sourceLabel: "--project" };
|
|
9206
|
+
const fromEnv = env.KXM_PROJECT?.trim();
|
|
9207
|
+
if (fromEnv) return { project: fromEnv, source: "env", sourceLabel: "KXM_PROJECT" };
|
|
9208
|
+
const settings = loadHubSettings(cwd, env);
|
|
9209
|
+
const mode = settings.mode ?? (activeBinding(env)?.cloud ? "cloud" : "local");
|
|
9210
|
+
const fromConfig = endpointFor(mode, settings)?.project?.trim();
|
|
9211
|
+
if (fromConfig) {
|
|
9212
|
+
return { project: fromConfig, source: "config", sourceLabel: `.kxm/config.yaml hub.${mode}.project` };
|
|
9213
|
+
}
|
|
9214
|
+
const fromProject = projectYamlId(cwd);
|
|
9215
|
+
if (fromProject) return { project: fromProject, source: "project.yaml", sourceLabel: ".kxm/project.yaml id" };
|
|
9216
|
+
const fromPackage = packageName(cwd);
|
|
9217
|
+
if (fromPackage) return { project: fromPackage, source: "package.json", sourceLabel: "package.json name" };
|
|
9218
|
+
return { project: basename2(cwd), source: "directory", sourceLabel: "directory name" };
|
|
9219
|
+
}
|
|
9220
|
+
function defaultProjectName(cwd, env = process.env, explicit) {
|
|
9221
|
+
return resolveProjectIdentity(cwd, env, explicit).project;
|
|
9222
|
+
}
|
|
9223
|
+
var import_yaml3;
|
|
9224
|
+
var init_hub_identity = __esm({
|
|
9225
|
+
"plugins/kxm/src/hub-identity.ts"() {
|
|
9226
|
+
"use strict";
|
|
9227
|
+
import_yaml3 = __toESM(require_dist(), 1);
|
|
9228
|
+
init_config();
|
|
9229
|
+
init_hub_binding();
|
|
9230
|
+
}
|
|
9231
|
+
});
|
|
9232
|
+
|
|
9233
|
+
// plugins/kxm/src/project-name.ts
|
|
9234
|
+
var project_name_exports = {};
|
|
9235
|
+
__export(project_name_exports, {
|
|
9236
|
+
defaultProjectName: () => defaultProjectName,
|
|
9237
|
+
resolveProjectIdentity: () => resolveProjectIdentity
|
|
9238
|
+
});
|
|
8785
9239
|
var init_project_name = __esm({
|
|
8786
9240
|
"plugins/kxm/src/project-name.ts"() {
|
|
8787
9241
|
"use strict";
|
|
9242
|
+
init_hub_identity();
|
|
8788
9243
|
}
|
|
8789
9244
|
});
|
|
8790
9245
|
|
|
@@ -8930,9 +9385,9 @@ __export(commands_exports, {
|
|
|
8930
9385
|
timingSafeStringCompare: () => timingSafeStringCompare
|
|
8931
9386
|
});
|
|
8932
9387
|
import { createHash, randomUUID as randomUUID3, timingSafeEqual } from "node:crypto";
|
|
8933
|
-
import { chmodSync, existsSync as
|
|
8934
|
-
import { homedir as
|
|
8935
|
-
import { dirname as
|
|
9388
|
+
import { chmodSync, existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync9, unlinkSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
9389
|
+
import { homedir as homedir4 } from "node:os";
|
|
9390
|
+
import { dirname as dirname5, join as join8, resolve as resolve7 } from "node:path";
|
|
8936
9391
|
function forwardedHops(handling) {
|
|
8937
9392
|
if (!handling?.length) return void 0;
|
|
8938
9393
|
return {
|
|
@@ -9114,18 +9569,18 @@ function parseSessionToken(token) {
|
|
|
9114
9569
|
return void 0;
|
|
9115
9570
|
}
|
|
9116
9571
|
function resolveUserConfigDirectory(overrideDir) {
|
|
9117
|
-
if (overrideDir) return
|
|
9118
|
-
return
|
|
9572
|
+
if (overrideDir) return resolve7(overrideDir);
|
|
9573
|
+
return resolve7(process.env.KXM_USER_CONFIG_DIR?.trim() || join8(homedir4(), ".config", "kxm"));
|
|
9119
9574
|
}
|
|
9120
9575
|
function sessionTokenPath(userConfigDir) {
|
|
9121
|
-
return
|
|
9576
|
+
return join8(resolveUserConfigDirectory(userConfigDir), "session.token");
|
|
9122
9577
|
}
|
|
9123
9578
|
function persistSessionTokenToDisk(token, options) {
|
|
9124
9579
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
9125
|
-
const dir =
|
|
9126
|
-
|
|
9580
|
+
const dir = dirname5(filePath);
|
|
9581
|
+
mkdirSync7(dir, { recursive: true, mode: 448 });
|
|
9127
9582
|
const mode = options?.mode ?? 384;
|
|
9128
|
-
|
|
9583
|
+
writeFileSync6(filePath, `${token.trim()}
|
|
9129
9584
|
`, { encoding: "utf8", mode });
|
|
9130
9585
|
try {
|
|
9131
9586
|
chmodSync(filePath, mode);
|
|
@@ -9135,9 +9590,9 @@ function persistSessionTokenToDisk(token, options) {
|
|
|
9135
9590
|
}
|
|
9136
9591
|
function readSessionTokenFromDisk(options) {
|
|
9137
9592
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
9138
|
-
if (!
|
|
9593
|
+
if (!existsSync9(filePath)) return void 0;
|
|
9139
9594
|
try {
|
|
9140
|
-
const token =
|
|
9595
|
+
const token = readFileSync9(filePath, "utf8").trim();
|
|
9141
9596
|
if (!token) return void 0;
|
|
9142
9597
|
const payload = parseSessionToken(token);
|
|
9143
9598
|
if (!payload) return void 0;
|
|
@@ -9148,7 +9603,7 @@ function readSessionTokenFromDisk(options) {
|
|
|
9148
9603
|
}
|
|
9149
9604
|
function clearSessionTokenFromDisk(options) {
|
|
9150
9605
|
const filePath = sessionTokenPath(options?.userConfigDir);
|
|
9151
|
-
if (!
|
|
9606
|
+
if (!existsSync9(filePath)) return false;
|
|
9152
9607
|
try {
|
|
9153
9608
|
unlinkSync(filePath);
|
|
9154
9609
|
return true;
|
|
@@ -9247,10 +9702,10 @@ function enforceToolPolicy(commandName, env = process.env, options) {
|
|
|
9247
9702
|
return { allowed: true };
|
|
9248
9703
|
}
|
|
9249
9704
|
const tokenFile = sessionTokenPath(env.KXM_USER_CONFIG_DIR);
|
|
9250
|
-
if (
|
|
9705
|
+
if (existsSync9(tokenFile)) {
|
|
9251
9706
|
let tokenRaw;
|
|
9252
9707
|
try {
|
|
9253
|
-
tokenRaw =
|
|
9708
|
+
tokenRaw = readFileSync9(tokenFile, "utf8").trim();
|
|
9254
9709
|
} catch {
|
|
9255
9710
|
return { allowed: false, error: "session_token_invalid", detail: "Session token file on disk could not be read" };
|
|
9256
9711
|
}
|
|
@@ -9936,8 +10391,8 @@ var init_commands = __esm({
|
|
|
9936
10391
|
});
|
|
9937
10392
|
|
|
9938
10393
|
// plugins/kxm/src/claude-hook.ts
|
|
9939
|
-
import { readFileSync as
|
|
9940
|
-
import { join as
|
|
10394
|
+
import { readFileSync as readFileSync10, statSync } from "node:fs";
|
|
10395
|
+
import { join as join9, resolve as resolve8 } from "node:path";
|
|
9941
10396
|
|
|
9942
10397
|
// plugins/kxm/src/session-token-hint.ts
|
|
9943
10398
|
var ENV_TEXT = "KXM_SESSION_TOKEN in the environment Claude Code was launched from is malformed or expired, so every kxm_* tool fails with tool_policy_denied. Ask the user to unset or replace KXM_SESSION_TOKEN in the environment Claude Code was launched from, then restart Claude Code.";
|
|
@@ -10010,15 +10465,15 @@ function truncate2(text, max) {
|
|
|
10010
10465
|
}
|
|
10011
10466
|
async function sessionStartContext(input, env) {
|
|
10012
10467
|
const inputCwd = typeof input.cwd === "string" ? input.cwd.trim() : "";
|
|
10013
|
-
const root =
|
|
10014
|
-
if (!isDirectory(
|
|
10468
|
+
const root = resolve8(env.CLAUDE_PROJECT_DIR?.trim() || inputCwd || process.cwd());
|
|
10469
|
+
if (!isDirectory(join9(root, ".kxm"))) return void 0;
|
|
10015
10470
|
const [
|
|
10016
10471
|
{ resolveSessionHubStatus: resolveSessionHubStatus2 },
|
|
10017
10472
|
{ loadLocalMeshSnapshot: loadLocalMeshSnapshot2, resolveKxmSnapshotPaths: resolveKxmSnapshotPaths2 },
|
|
10018
10473
|
{ formatMemoryBriefText: formatMemoryBriefText2, generateMemoryBrief: generateMemoryBrief2 },
|
|
10019
10474
|
{ defaultProjectName: defaultProjectName2 },
|
|
10020
10475
|
{ enforceToolPolicy: enforceToolPolicy2 },
|
|
10021
|
-
{ parse:
|
|
10476
|
+
{ parse: parse3 }
|
|
10022
10477
|
] = await Promise.all([
|
|
10023
10478
|
Promise.resolve().then(() => (init_session_work(), session_work_exports)),
|
|
10024
10479
|
Promise.resolve().then(() => (init_local_snapshot(), local_snapshot_exports)),
|
|
@@ -10032,7 +10487,7 @@ async function sessionStartContext(input, env) {
|
|
|
10032
10487
|
const url = (env.CLAUDE_PLUGIN_OPTION_SERVER_URL?.trim() || DEFAULT_SERVER_URL).replace(/\/$/, "");
|
|
10033
10488
|
let runtimeProjectId;
|
|
10034
10489
|
try {
|
|
10035
|
-
const project =
|
|
10490
|
+
const project = parse3(readFileSync10(join9(root, ".kxm", "project.yaml"), "utf8"));
|
|
10036
10491
|
if (typeof project?.id === "string" && project.id.trim()) runtimeProjectId = project.id.trim();
|
|
10037
10492
|
} catch {
|
|
10038
10493
|
}
|