@kontextmind/kxm 0.7.165 → 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 +16 -0
- package/docs/concepts/trust-model.md +1 -1
- package/docs/glossary.md +2 -2
- package/docs/operations/troubleshooting.md +2 -2
- package/docs/operations.md +62 -8
- package/docs/reference/cli-reference.md +11 -11
- package/docs/reference/config-reference.md +36 -11
- package/docs/reference/configuration.md +2 -2
- package/docs/reference/tools.md +1 -1
- package/docs/start/quickstart-claude-code.md +2 -2
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/README.md +3 -3
- package/plugins/kxm/dist/claude-hook.js +417 -66
- package/plugins/kxm/dist/cli.js +1399 -900
- package/plugins/kxm/dist/extension.js +399 -64
- package/plugins/kxm/dist/mcp-server.js +622 -135
- package/plugins/kxm/dist/runtime-supervisor.js +668 -166
- package/plugins/kxm/dist/runtime.js +713 -211
- package/plugins/kxm/dist/server.js +466 -58
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +15 -7
- package/plugins/kxm/src/cli/hub.ts +80 -21
- package/plugins/kxm/src/cli/types.ts +8 -1
- package/plugins/kxm/src/cli.ts +41 -7
- package/plugins/kxm/src/config.ts +246 -3
- package/plugins/kxm/src/extension.ts +8 -7
- package/plugins/kxm/src/hub-autostart.ts +20 -0
- package/plugins/kxm/src/hub-env.ts +83 -31
- package/plugins/kxm/src/hub-identity.ts +337 -0
- package/plugins/kxm/src/mcp-server.ts +17 -15
- package/plugins/kxm/src/project-name.ts +6 -47
- package/plugins/kxm/src/server.ts +22 -4
- package/scripts/kxm-hub.mjs +5 -0
|
@@ -168,10 +168,10 @@ var require_code = __commonJS({
|
|
|
168
168
|
function interpolate(x) {
|
|
169
169
|
return typeof x == "number" || typeof x == "boolean" || x === null ? x : safeStringify(Array.isArray(x) ? x.join(",") : x);
|
|
170
170
|
}
|
|
171
|
-
function
|
|
171
|
+
function stringify2(x) {
|
|
172
172
|
return new _Code(safeStringify(x));
|
|
173
173
|
}
|
|
174
|
-
exports.stringify =
|
|
174
|
+
exports.stringify = stringify2;
|
|
175
175
|
function safeStringify(x) {
|
|
176
176
|
return JSON.stringify(x).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
177
177
|
}
|
|
@@ -2991,7 +2991,7 @@ var require_compile = __commonJS({
|
|
|
2991
2991
|
const schOrFunc = root.refs[ref];
|
|
2992
2992
|
if (schOrFunc)
|
|
2993
2993
|
return schOrFunc;
|
|
2994
|
-
let _sch =
|
|
2994
|
+
let _sch = resolve6.call(this, root, ref);
|
|
2995
2995
|
if (_sch === void 0) {
|
|
2996
2996
|
const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
|
|
2997
2997
|
const { schemaId } = this.opts;
|
|
@@ -3018,7 +3018,7 @@ var require_compile = __commonJS({
|
|
|
3018
3018
|
function sameSchemaEnv(s1, s2) {
|
|
3019
3019
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
3020
3020
|
}
|
|
3021
|
-
function
|
|
3021
|
+
function resolve6(root, ref) {
|
|
3022
3022
|
let sch;
|
|
3023
3023
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3024
3024
|
ref = sch;
|
|
@@ -3839,11 +3839,11 @@ var require_fast_uri = __commonJS({
|
|
|
3839
3839
|
normalizeString(uri, options);
|
|
3840
3840
|
} else if (typeof uri === "object") {
|
|
3841
3841
|
uri = /** @type {T} */
|
|
3842
|
-
|
|
3842
|
+
parse4(serialize(uri, options), options);
|
|
3843
3843
|
}
|
|
3844
3844
|
return uri;
|
|
3845
3845
|
}
|
|
3846
|
-
function
|
|
3846
|
+
function resolve6(baseURI, relativeURI, options) {
|
|
3847
3847
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3848
3848
|
const {
|
|
3849
3849
|
parsed: baseParsed,
|
|
@@ -3879,8 +3879,8 @@ var require_fast_uri = __commonJS({
|
|
|
3879
3879
|
function resolveComponent(base, relative, options, skipNormalization) {
|
|
3880
3880
|
const target = {};
|
|
3881
3881
|
if (!skipNormalization) {
|
|
3882
|
-
base =
|
|
3883
|
-
relative =
|
|
3882
|
+
base = parse4(serialize(base, options), options);
|
|
3883
|
+
relative = parse4(serialize(relative, options), options);
|
|
3884
3884
|
}
|
|
3885
3885
|
options = options || {};
|
|
3886
3886
|
if (!options.tolerant && relative.scheme) {
|
|
@@ -4172,7 +4172,7 @@ var require_fast_uri = __commonJS({
|
|
|
4172
4172
|
}
|
|
4173
4173
|
return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
|
|
4174
4174
|
}
|
|
4175
|
-
function
|
|
4175
|
+
function parse4(uri, opts) {
|
|
4176
4176
|
return parseWithStatus(uri, opts).parsed;
|
|
4177
4177
|
}
|
|
4178
4178
|
function normalizeString(uri, opts) {
|
|
@@ -4205,11 +4205,11 @@ var require_fast_uri = __commonJS({
|
|
|
4205
4205
|
var fastUri = {
|
|
4206
4206
|
SCHEMES,
|
|
4207
4207
|
normalize,
|
|
4208
|
-
resolve:
|
|
4208
|
+
resolve: resolve6,
|
|
4209
4209
|
resolveComponent,
|
|
4210
4210
|
equal,
|
|
4211
4211
|
serialize,
|
|
4212
|
-
parse:
|
|
4212
|
+
parse: parse4
|
|
4213
4213
|
};
|
|
4214
4214
|
module.exports = fastUri;
|
|
4215
4215
|
module.exports.default = fastUri;
|
|
@@ -8664,7 +8664,7 @@ var require_stringify = __commonJS({
|
|
|
8664
8664
|
props.push(doc.directives.tagString(tag));
|
|
8665
8665
|
return props.join(" ");
|
|
8666
8666
|
}
|
|
8667
|
-
function
|
|
8667
|
+
function stringify2(item, ctx, onComment, onChompKeep) {
|
|
8668
8668
|
if (identity.isPair(item))
|
|
8669
8669
|
return item.toString(ctx, onComment, onChompKeep);
|
|
8670
8670
|
if (identity.isAlias(item)) {
|
|
@@ -8693,7 +8693,7 @@ var require_stringify = __commonJS({
|
|
|
8693
8693
|
${ctx.indent}${str}`;
|
|
8694
8694
|
}
|
|
8695
8695
|
exports.createStringifyContext = createStringifyContext;
|
|
8696
|
-
exports.stringify =
|
|
8696
|
+
exports.stringify = stringify2;
|
|
8697
8697
|
}
|
|
8698
8698
|
});
|
|
8699
8699
|
|
|
@@ -8703,7 +8703,7 @@ var require_stringifyPair = __commonJS({
|
|
|
8703
8703
|
"use strict";
|
|
8704
8704
|
var identity = require_identity();
|
|
8705
8705
|
var Scalar = require_Scalar();
|
|
8706
|
-
var
|
|
8706
|
+
var stringify2 = require_stringify();
|
|
8707
8707
|
var stringifyComment = require_stringifyComment();
|
|
8708
8708
|
function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
|
|
8709
8709
|
const { allNullValues, doc, indent, indentStep, options: { commentString, indentSeq, simpleKeys } } = ctx;
|
|
@@ -8725,7 +8725,7 @@ var require_stringifyPair = __commonJS({
|
|
|
8725
8725
|
});
|
|
8726
8726
|
let keyCommentDone = false;
|
|
8727
8727
|
let chompKeep = false;
|
|
8728
|
-
let str =
|
|
8728
|
+
let str = stringify2.stringify(key, ctx, () => keyCommentDone = true, () => chompKeep = true);
|
|
8729
8729
|
if (!explicitKey && !ctx.inFlow && str.length > 1024) {
|
|
8730
8730
|
if (simpleKeys)
|
|
8731
8731
|
throw new Error("With simple keys, single line scalar must not span more than 1024 characters");
|
|
@@ -8777,7 +8777,7 @@ ${indent}:`;
|
|
|
8777
8777
|
ctx.indent = ctx.indent.substring(2);
|
|
8778
8778
|
}
|
|
8779
8779
|
let valueCommentDone = false;
|
|
8780
|
-
const valueStr =
|
|
8780
|
+
const valueStr = stringify2.stringify(value, ctx, () => valueCommentDone = true, () => chompKeep = true);
|
|
8781
8781
|
let ws = " ";
|
|
8782
8782
|
if (keyComment || vsb || vcb) {
|
|
8783
8783
|
ws = vsb ? "\n" : "";
|
|
@@ -8918,7 +8918,7 @@ var require_addPairToJSMap = __commonJS({
|
|
|
8918
8918
|
"use strict";
|
|
8919
8919
|
var log = require_log();
|
|
8920
8920
|
var merge2 = require_merge();
|
|
8921
|
-
var
|
|
8921
|
+
var stringify2 = require_stringify();
|
|
8922
8922
|
var identity = require_identity();
|
|
8923
8923
|
var toJS = require_toJS();
|
|
8924
8924
|
function addPairToJSMap(ctx, map, { key, value }) {
|
|
@@ -8954,7 +8954,7 @@ var require_addPairToJSMap = __commonJS({
|
|
|
8954
8954
|
if (typeof jsKey !== "object")
|
|
8955
8955
|
return String(jsKey);
|
|
8956
8956
|
if (identity.isNode(key) && ctx?.doc) {
|
|
8957
|
-
const strCtx =
|
|
8957
|
+
const strCtx = stringify2.createStringifyContext(ctx.doc, {});
|
|
8958
8958
|
strCtx.anchors = /* @__PURE__ */ new Set();
|
|
8959
8959
|
for (const node of ctx.anchors.keys())
|
|
8960
8960
|
strCtx.anchors.add(node.anchor);
|
|
@@ -9021,12 +9021,12 @@ var require_stringifyCollection = __commonJS({
|
|
|
9021
9021
|
"node_modules/yaml/dist/stringify/stringifyCollection.js"(exports) {
|
|
9022
9022
|
"use strict";
|
|
9023
9023
|
var identity = require_identity();
|
|
9024
|
-
var
|
|
9024
|
+
var stringify2 = require_stringify();
|
|
9025
9025
|
var stringifyComment = require_stringifyComment();
|
|
9026
9026
|
function stringifyCollection(collection, ctx, options) {
|
|
9027
9027
|
const flow = ctx.inFlow ?? collection.flow;
|
|
9028
|
-
const
|
|
9029
|
-
return
|
|
9028
|
+
const stringify3 = flow ? stringifyFlowCollection : stringifyBlockCollection;
|
|
9029
|
+
return stringify3(collection, ctx, options);
|
|
9030
9030
|
}
|
|
9031
9031
|
function stringifyBlockCollection({ comment, items }, ctx, { blockItemPrefix, flowChars, itemIndent, onChompKeep, onComment }) {
|
|
9032
9032
|
const { indent, options: { commentString } } = ctx;
|
|
@@ -9051,7 +9051,7 @@ var require_stringifyCollection = __commonJS({
|
|
|
9051
9051
|
}
|
|
9052
9052
|
}
|
|
9053
9053
|
chompKeep = false;
|
|
9054
|
-
let str2 =
|
|
9054
|
+
let str2 = stringify2.stringify(item, itemCtx, () => comment2 = null, () => chompKeep = true);
|
|
9055
9055
|
if (comment2)
|
|
9056
9056
|
str2 += stringifyComment.lineComment(str2, itemIndent, commentString(comment2));
|
|
9057
9057
|
if (chompKeep && comment2)
|
|
@@ -9118,7 +9118,7 @@ ${indent}${line}` : "\n";
|
|
|
9118
9118
|
}
|
|
9119
9119
|
if (comment)
|
|
9120
9120
|
reqNewline = true;
|
|
9121
|
-
let str =
|
|
9121
|
+
let str = stringify2.stringify(item, itemCtx, () => comment = null);
|
|
9122
9122
|
reqNewline || (reqNewline = lines.length > linesAtValue || str.includes("\n"));
|
|
9123
9123
|
if (i < items.length - 1) {
|
|
9124
9124
|
str += ",";
|
|
@@ -10479,7 +10479,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
10479
10479
|
"node_modules/yaml/dist/stringify/stringifyDocument.js"(exports) {
|
|
10480
10480
|
"use strict";
|
|
10481
10481
|
var identity = require_identity();
|
|
10482
|
-
var
|
|
10482
|
+
var stringify2 = require_stringify();
|
|
10483
10483
|
var stringifyComment = require_stringifyComment();
|
|
10484
10484
|
function stringifyDocument(doc, options) {
|
|
10485
10485
|
const lines = [];
|
|
@@ -10494,7 +10494,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
10494
10494
|
}
|
|
10495
10495
|
if (hasDirectives)
|
|
10496
10496
|
lines.push("---");
|
|
10497
|
-
const ctx =
|
|
10497
|
+
const ctx = stringify2.createStringifyContext(doc, options);
|
|
10498
10498
|
const { commentString } = ctx.options;
|
|
10499
10499
|
if (doc.commentBefore) {
|
|
10500
10500
|
if (lines.length !== 1)
|
|
@@ -10516,7 +10516,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
10516
10516
|
contentComment = doc.contents.comment;
|
|
10517
10517
|
}
|
|
10518
10518
|
const onChompKeep = contentComment ? void 0 : () => chompKeep = true;
|
|
10519
|
-
let body =
|
|
10519
|
+
let body = stringify2.stringify(doc.contents, ctx, () => contentComment = null, onChompKeep);
|
|
10520
10520
|
if (contentComment)
|
|
10521
10521
|
body += stringifyComment.lineComment(body, "", commentString(contentComment));
|
|
10522
10522
|
if ((body[0] === "|" || body[0] === ">") && lines[lines.length - 1] === "---") {
|
|
@@ -10524,7 +10524,7 @@ var require_stringifyDocument = __commonJS({
|
|
|
10524
10524
|
} else
|
|
10525
10525
|
lines.push(body);
|
|
10526
10526
|
} else {
|
|
10527
|
-
lines.push(
|
|
10527
|
+
lines.push(stringify2.stringify(doc.contents, ctx));
|
|
10528
10528
|
}
|
|
10529
10529
|
if (doc.directives?.docEnd) {
|
|
10530
10530
|
if (doc.comment) {
|
|
@@ -12660,7 +12660,7 @@ var require_cst_scalar = __commonJS({
|
|
|
12660
12660
|
var require_cst_stringify = __commonJS({
|
|
12661
12661
|
"node_modules/yaml/dist/parse/cst-stringify.js"(exports) {
|
|
12662
12662
|
"use strict";
|
|
12663
|
-
var
|
|
12663
|
+
var stringify2 = (cst) => "type" in cst ? stringifyToken(cst) : stringifyItem(cst);
|
|
12664
12664
|
function stringifyToken(token) {
|
|
12665
12665
|
switch (token.type) {
|
|
12666
12666
|
case "block-scalar": {
|
|
@@ -12713,7 +12713,7 @@ var require_cst_stringify = __commonJS({
|
|
|
12713
12713
|
res += stringifyToken(value);
|
|
12714
12714
|
return res;
|
|
12715
12715
|
}
|
|
12716
|
-
exports.stringify =
|
|
12716
|
+
exports.stringify = stringify2;
|
|
12717
12717
|
}
|
|
12718
12718
|
});
|
|
12719
12719
|
|
|
@@ -14424,7 +14424,7 @@ var require_public_api = __commonJS({
|
|
|
14424
14424
|
}
|
|
14425
14425
|
return doc;
|
|
14426
14426
|
}
|
|
14427
|
-
function
|
|
14427
|
+
function parse4(src, reviver, options) {
|
|
14428
14428
|
let _reviver = void 0;
|
|
14429
14429
|
if (typeof reviver === "function") {
|
|
14430
14430
|
_reviver = reviver;
|
|
@@ -14443,7 +14443,7 @@ var require_public_api = __commonJS({
|
|
|
14443
14443
|
}
|
|
14444
14444
|
return doc.toJS(Object.assign({ reviver: _reviver }, options));
|
|
14445
14445
|
}
|
|
14446
|
-
function
|
|
14446
|
+
function stringify2(value, replacer, options) {
|
|
14447
14447
|
let _replacer = null;
|
|
14448
14448
|
if (typeof replacer === "function" || Array.isArray(replacer)) {
|
|
14449
14449
|
_replacer = replacer;
|
|
@@ -14465,10 +14465,10 @@ var require_public_api = __commonJS({
|
|
|
14465
14465
|
return value.toString(options);
|
|
14466
14466
|
return new Document.Document(value, _replacer, options).toString(options);
|
|
14467
14467
|
}
|
|
14468
|
-
exports.parse =
|
|
14468
|
+
exports.parse = parse4;
|
|
14469
14469
|
exports.parseAllDocuments = parseAllDocuments;
|
|
14470
14470
|
exports.parseDocument = parseDocument;
|
|
14471
|
-
exports.stringify =
|
|
14471
|
+
exports.stringify = stringify2;
|
|
14472
14472
|
}
|
|
14473
14473
|
});
|
|
14474
14474
|
|
|
@@ -14526,7 +14526,7 @@ var require_dist2 = __commonJS({
|
|
|
14526
14526
|
|
|
14527
14527
|
// plugins/kxm/src/mcp-server.ts
|
|
14528
14528
|
import { statSync } from "node:fs";
|
|
14529
|
-
import { join as
|
|
14529
|
+
import { join as join6 } from "node:path";
|
|
14530
14530
|
|
|
14531
14531
|
// node_modules/zod/v4/core/core.js
|
|
14532
14532
|
var _a;
|
|
@@ -21846,7 +21846,7 @@ var Protocol = class {
|
|
|
21846
21846
|
return;
|
|
21847
21847
|
}
|
|
21848
21848
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
21849
|
-
await new Promise((
|
|
21849
|
+
await new Promise((resolve6) => setTimeout(resolve6, pollInterval));
|
|
21850
21850
|
options?.signal?.throwIfAborted();
|
|
21851
21851
|
}
|
|
21852
21852
|
} catch (error2) {
|
|
@@ -21863,7 +21863,7 @@ var Protocol = class {
|
|
|
21863
21863
|
*/
|
|
21864
21864
|
request(request, resultSchema, options) {
|
|
21865
21865
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
21866
|
-
return new Promise((
|
|
21866
|
+
return new Promise((resolve6, reject) => {
|
|
21867
21867
|
const earlyReject = (error2) => {
|
|
21868
21868
|
reject(error2);
|
|
21869
21869
|
};
|
|
@@ -21941,7 +21941,7 @@ var Protocol = class {
|
|
|
21941
21941
|
if (!parseResult.success) {
|
|
21942
21942
|
reject(parseResult.error);
|
|
21943
21943
|
} else {
|
|
21944
|
-
|
|
21944
|
+
resolve6(parseResult.data);
|
|
21945
21945
|
}
|
|
21946
21946
|
} catch (error2) {
|
|
21947
21947
|
reject(error2);
|
|
@@ -22202,12 +22202,12 @@ var Protocol = class {
|
|
|
22202
22202
|
}
|
|
22203
22203
|
} catch {
|
|
22204
22204
|
}
|
|
22205
|
-
return new Promise((
|
|
22205
|
+
return new Promise((resolve6, reject) => {
|
|
22206
22206
|
if (signal.aborted) {
|
|
22207
22207
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
22208
22208
|
return;
|
|
22209
22209
|
}
|
|
22210
|
-
const timeoutId = setTimeout(
|
|
22210
|
+
const timeoutId = setTimeout(resolve6, interval);
|
|
22211
22211
|
signal.addEventListener("abort", () => {
|
|
22212
22212
|
clearTimeout(timeoutId);
|
|
22213
22213
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -23083,12 +23083,12 @@ var StdioServerTransport = class {
|
|
|
23083
23083
|
this.onclose?.();
|
|
23084
23084
|
}
|
|
23085
23085
|
send(message) {
|
|
23086
|
-
return new Promise((
|
|
23086
|
+
return new Promise((resolve6) => {
|
|
23087
23087
|
const json = serializeMessage(message);
|
|
23088
23088
|
if (this._stdout.write(json)) {
|
|
23089
|
-
|
|
23089
|
+
resolve6();
|
|
23090
23090
|
} else {
|
|
23091
|
-
this._stdout.once("drain",
|
|
23091
|
+
this._stdout.once("drain", resolve6);
|
|
23092
23092
|
}
|
|
23093
23093
|
});
|
|
23094
23094
|
}
|
|
@@ -23504,7 +23504,7 @@ var HubClient = class {
|
|
|
23504
23504
|
if (signal?.aborted) throw new MeshWaitError("aborted", messageId);
|
|
23505
23505
|
const message = await this.getMessage(messageId);
|
|
23506
23506
|
if (["replied", "cancelled", "expired", "error"].includes(message.status)) return message;
|
|
23507
|
-
await new Promise((
|
|
23507
|
+
await new Promise((resolve6, reject) => {
|
|
23508
23508
|
const onAbort = () => {
|
|
23509
23509
|
signal?.removeEventListener("abort", onAbort);
|
|
23510
23510
|
clearTimeout(timer);
|
|
@@ -23512,7 +23512,7 @@ var HubClient = class {
|
|
|
23512
23512
|
};
|
|
23513
23513
|
const timer = setTimeout(() => {
|
|
23514
23514
|
signal?.removeEventListener("abort", onAbort);
|
|
23515
|
-
|
|
23515
|
+
resolve6();
|
|
23516
23516
|
}, Math.min(500, Math.max(1, deadline - Date.now())));
|
|
23517
23517
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
23518
23518
|
if (signal?.aborted) onAbort();
|
|
@@ -23567,7 +23567,7 @@ var HubClient = class {
|
|
|
23567
23567
|
} catch (error2) {
|
|
23568
23568
|
if (this.stopped || error2 instanceof Error && error2.name === "AbortError") return;
|
|
23569
23569
|
}
|
|
23570
|
-
if (!this.stopped) await new Promise((
|
|
23570
|
+
if (!this.stopped) await new Promise((resolve6) => setTimeout(resolve6, this.options.reconnectMs));
|
|
23571
23571
|
}
|
|
23572
23572
|
}
|
|
23573
23573
|
headers(includeIdentity = true) {
|
|
@@ -23654,15 +23654,330 @@ async function hubJsonRequest(options, path, init, headers) {
|
|
|
23654
23654
|
}
|
|
23655
23655
|
|
|
23656
23656
|
// plugins/kxm/src/hub-env.ts
|
|
23657
|
-
import { existsSync as
|
|
23658
|
-
import { homedir as
|
|
23659
|
-
import { dirname as
|
|
23657
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
23658
|
+
import { homedir as homedir3 } from "node:os";
|
|
23659
|
+
import { dirname as dirname4, isAbsolute as isAbsolute2, join as join4, resolve as resolve4 } from "node:path";
|
|
23660
|
+
|
|
23661
|
+
// plugins/kxm/src/config.ts
|
|
23662
|
+
var import_yaml = __toESM(require_dist2(), 1);
|
|
23663
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
23664
|
+
import { tmpdir, homedir } from "node:os";
|
|
23665
|
+
import { dirname, join, resolve } from "node:path";
|
|
23666
|
+
var KXM_CONFIG_SCHEMA = "kxm.config.v1";
|
|
23667
|
+
var KxmHubConfigError = class extends Error {
|
|
23668
|
+
code = "hub_config_invalid";
|
|
23669
|
+
constructor(message) {
|
|
23670
|
+
super(message);
|
|
23671
|
+
this.name = "KxmHubConfigError";
|
|
23672
|
+
}
|
|
23673
|
+
};
|
|
23674
|
+
var HUB_ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
23675
|
+
var HUB_OP_REF = /^op:\/\/\S+\/\S+\/\S+$/;
|
|
23676
|
+
var LITERAL_SECRET_KEY = /^(token|secret|password|authToken|auth_token|apiKey|api_key|api_token|bearer|credential|access_token)$/i;
|
|
23677
|
+
function isHubKeyEnvName(value) {
|
|
23678
|
+
return HUB_ENV_NAME.test(value);
|
|
23679
|
+
}
|
|
23680
|
+
function isHubOpReference(value) {
|
|
23681
|
+
return HUB_OP_REF.test(value);
|
|
23682
|
+
}
|
|
23683
|
+
var IMPROVEMENT_PROMOTION_POLICIES = ["manual_pr", "critic_quorum", "auto_threshold"];
|
|
23684
|
+
var DEFAULT_KXM_CONFIG = {
|
|
23685
|
+
schema: KXM_CONFIG_SCHEMA,
|
|
23686
|
+
user: {
|
|
23687
|
+
theme: "dark",
|
|
23688
|
+
preferredCritics: ["reviewer-arch", "reviewer-cli"],
|
|
23689
|
+
tokenBudget: 16e3
|
|
23690
|
+
},
|
|
23691
|
+
defaults: {
|
|
23692
|
+
workflow: "software-engineering/feature-implementation",
|
|
23693
|
+
harness: "pi"
|
|
23694
|
+
},
|
|
23695
|
+
dash: {
|
|
23696
|
+
defaultScreen: "agents",
|
|
23697
|
+
refreshIntervalMs: 1e3,
|
|
23698
|
+
autoOpen: false
|
|
23699
|
+
},
|
|
23700
|
+
sync: {
|
|
23701
|
+
defaultTracker: "none"
|
|
23702
|
+
},
|
|
23703
|
+
hub: {
|
|
23704
|
+
autoStart: "background"
|
|
23705
|
+
},
|
|
23706
|
+
improvement: {
|
|
23707
|
+
promotionPolicy: "manual_pr",
|
|
23708
|
+
telemetryHalfLifeDays: 14,
|
|
23709
|
+
autoThreshold: {
|
|
23710
|
+
minRuns: 10,
|
|
23711
|
+
minPassRate: 0.95,
|
|
23712
|
+
minCostSavings: 0.5
|
|
23713
|
+
}
|
|
23714
|
+
},
|
|
23715
|
+
routing: {
|
|
23716
|
+
shadowExecution: {
|
|
23717
|
+
enabled: false,
|
|
23718
|
+
sampleRate: 0.05,
|
|
23719
|
+
candidateModels: []
|
|
23720
|
+
},
|
|
23721
|
+
circuitBreaker: {
|
|
23722
|
+
mode: "soft_demotion",
|
|
23723
|
+
failureThreshold: 3,
|
|
23724
|
+
windowSeconds: 3600,
|
|
23725
|
+
cooldownSeconds: 1800,
|
|
23726
|
+
penaltyMultiplier: 5
|
|
23727
|
+
}
|
|
23728
|
+
},
|
|
23729
|
+
telemetry: {
|
|
23730
|
+
federated: true,
|
|
23731
|
+
anonymize: true
|
|
23732
|
+
}
|
|
23733
|
+
};
|
|
23734
|
+
function userConfigDirectory(overrideDir) {
|
|
23735
|
+
if (overrideDir) return resolve(overrideDir);
|
|
23736
|
+
return resolve(process.env.KXM_USER_CONFIG_DIR?.trim() || join(homedir(), ".config", "kxm"));
|
|
23737
|
+
}
|
|
23738
|
+
function repoConfigDirectory(repoRoot) {
|
|
23739
|
+
return resolve(repoRoot, ".kxm");
|
|
23740
|
+
}
|
|
23741
|
+
function deepMerge(target, source) {
|
|
23742
|
+
const result = { ...target };
|
|
23743
|
+
for (const [key, val] of Object.entries(source)) {
|
|
23744
|
+
if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
23745
|
+
const existing = result[key] && typeof result[key] === "object" && !Array.isArray(result[key]) ? result[key] : {};
|
|
23746
|
+
result[key] = deepMerge(existing, val);
|
|
23747
|
+
} else if (val !== void 0) {
|
|
23748
|
+
result[key] = val;
|
|
23749
|
+
}
|
|
23750
|
+
}
|
|
23751
|
+
return result;
|
|
23752
|
+
}
|
|
23753
|
+
function literalSecretMessage(path) {
|
|
23754
|
+
return `refusing literal hub token at ${path}: store an op:// reference (key.op) or an environment variable name (key.env), never the token`;
|
|
23755
|
+
}
|
|
23756
|
+
function rejectLiteralHubSecrets(value, path) {
|
|
23757
|
+
if (Array.isArray(value)) {
|
|
23758
|
+
value.forEach((item, index) => rejectLiteralHubSecrets(item, `${path}[${index}]`));
|
|
23759
|
+
return;
|
|
23760
|
+
}
|
|
23761
|
+
if (!value || typeof value !== "object") return;
|
|
23762
|
+
for (const [key, child] of Object.entries(value)) {
|
|
23763
|
+
const childPath = `${path}.${key}`;
|
|
23764
|
+
if (typeof child === "string" && (key === "key" || LITERAL_SECRET_KEY.test(key))) {
|
|
23765
|
+
throw new KxmHubConfigError(literalSecretMessage(childPath));
|
|
23766
|
+
}
|
|
23767
|
+
if (child && typeof child === "object") rejectLiteralHubSecrets(child, childPath);
|
|
23768
|
+
}
|
|
23769
|
+
}
|
|
23770
|
+
function parseKeyRef(raw, path) {
|
|
23771
|
+
if (raw === void 0) return void 0;
|
|
23772
|
+
if (typeof raw === "string") throw new KxmHubConfigError(literalSecretMessage(path));
|
|
23773
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
23774
|
+
throw new KxmHubConfigError(`${path} must be a key reference with op and/or env, never a token`);
|
|
23775
|
+
}
|
|
23776
|
+
const row = raw;
|
|
23777
|
+
for (const key of Object.keys(row)) {
|
|
23778
|
+
if (key !== "op" && key !== "env") {
|
|
23779
|
+
throw new KxmHubConfigError(literalSecretMessage(`${path}.${key}`));
|
|
23780
|
+
}
|
|
23781
|
+
}
|
|
23782
|
+
const ref = {};
|
|
23783
|
+
if (row.op !== void 0) {
|
|
23784
|
+
if (typeof row.op !== "string" || !isHubOpReference(row.op)) {
|
|
23785
|
+
throw new KxmHubConfigError(`${path}.op must be an op://vault/item/field reference, not a token`);
|
|
23786
|
+
}
|
|
23787
|
+
ref.op = row.op;
|
|
23788
|
+
}
|
|
23789
|
+
if (row.env !== void 0) {
|
|
23790
|
+
if (typeof row.env !== "string" || !isHubKeyEnvName(row.env)) {
|
|
23791
|
+
throw new KxmHubConfigError(`${path}.env must be an environment variable name, not a token`);
|
|
23792
|
+
}
|
|
23793
|
+
ref.env = row.env;
|
|
23794
|
+
}
|
|
23795
|
+
if (!ref.op && !ref.env) throw new KxmHubConfigError(`${path} needs key.op, key.env, or both`);
|
|
23796
|
+
return ref;
|
|
23797
|
+
}
|
|
23798
|
+
function parseEndpoint(raw, path) {
|
|
23799
|
+
if (raw === void 0) return void 0;
|
|
23800
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
23801
|
+
throw new KxmHubConfigError(`${path} must be an object with url, project, and key`);
|
|
23802
|
+
}
|
|
23803
|
+
const row = raw;
|
|
23804
|
+
const endpoint = {};
|
|
23805
|
+
if (row.url !== void 0) {
|
|
23806
|
+
if (typeof row.url !== "string" || !isHubUrl(row.url)) {
|
|
23807
|
+
throw new KxmHubConfigError(`${path}.url must be an http or https URL without credentials, query, or fragment`);
|
|
23808
|
+
}
|
|
23809
|
+
endpoint.url = row.url.replace(/\/$/, "");
|
|
23810
|
+
}
|
|
23811
|
+
if (row.project !== void 0) {
|
|
23812
|
+
if (typeof row.project !== "string" || !isHubProjectId(row.project)) {
|
|
23813
|
+
throw new KxmHubConfigError(`${path}.project must be a single-line project id, not a token`);
|
|
23814
|
+
}
|
|
23815
|
+
endpoint.project = row.project.trim();
|
|
23816
|
+
}
|
|
23817
|
+
const key = parseKeyRef(row.key, `${path}.key`);
|
|
23818
|
+
if (key) endpoint.key = key;
|
|
23819
|
+
for (const name of Object.keys(row)) {
|
|
23820
|
+
if (name !== "url" && name !== "project" && name !== "key") {
|
|
23821
|
+
if (typeof row[name] === "string") throw new KxmHubConfigError(literalSecretMessage(`${path}.${name}`));
|
|
23822
|
+
throw new KxmHubConfigError(`${path}.${name} is not a hub endpoint field`);
|
|
23823
|
+
}
|
|
23824
|
+
}
|
|
23825
|
+
return endpoint;
|
|
23826
|
+
}
|
|
23827
|
+
function isHubUrl(raw) {
|
|
23828
|
+
try {
|
|
23829
|
+
const parsed = new URL(raw);
|
|
23830
|
+
return (parsed.protocol === "http:" || parsed.protocol === "https:") && parsed.username === "" && parsed.password === "" && parsed.search === "" && parsed.hash === "" && !raw.includes("?") && !raw.includes("#");
|
|
23831
|
+
} catch {
|
|
23832
|
+
return false;
|
|
23833
|
+
}
|
|
23834
|
+
}
|
|
23835
|
+
function isHubProjectId(raw) {
|
|
23836
|
+
const value = raw.trim();
|
|
23837
|
+
return value.length > 0 && value.length <= 200 && !/[\s\r\n]/.test(value);
|
|
23838
|
+
}
|
|
23839
|
+
function parseProjectMap(raw) {
|
|
23840
|
+
if (raw === void 0) return void 0;
|
|
23841
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
23842
|
+
throw new KxmHubConfigError("hub.projects must be a map of project id to key reference, never a token");
|
|
23843
|
+
}
|
|
23844
|
+
const projects = {};
|
|
23845
|
+
for (const [project, value] of Object.entries(raw)) {
|
|
23846
|
+
if (!isHubProjectId(project)) {
|
|
23847
|
+
throw new KxmHubConfigError(`hub.projects key ${JSON.stringify(project)} must be a project id, not a token`);
|
|
23848
|
+
}
|
|
23849
|
+
const ref = parseKeyRef(value, `hub.projects.${project}`);
|
|
23850
|
+
if (!ref) throw new KxmHubConfigError(`hub.projects.${project} needs an op:// reference or an environment variable name`);
|
|
23851
|
+
projects[project.trim()] = ref;
|
|
23852
|
+
}
|
|
23853
|
+
return projects;
|
|
23854
|
+
}
|
|
23855
|
+
function normalizeHubConfig(raw) {
|
|
23856
|
+
const autoStart = raw?.autoStart;
|
|
23857
|
+
const hub = {
|
|
23858
|
+
autoStart: autoStart === "off" || autoStart === "background" ? autoStart : DEFAULT_KXM_CONFIG.hub.autoStart
|
|
23859
|
+
};
|
|
23860
|
+
if (raw === void 0) return hub;
|
|
23861
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
23862
|
+
throw new KxmHubConfigError("hub must be an object");
|
|
23863
|
+
}
|
|
23864
|
+
rejectLiteralHubSecrets(raw, "hub");
|
|
23865
|
+
const row = raw;
|
|
23866
|
+
if (row.mode !== void 0) {
|
|
23867
|
+
if (row.mode !== "local" && row.mode !== "cloud") {
|
|
23868
|
+
throw new KxmHubConfigError("hub.mode must be local or cloud");
|
|
23869
|
+
}
|
|
23870
|
+
hub.mode = row.mode;
|
|
23871
|
+
}
|
|
23872
|
+
const local = parseEndpoint(row.local, "hub.local");
|
|
23873
|
+
const cloud = parseEndpoint(row.cloud, "hub.cloud");
|
|
23874
|
+
const projects = parseProjectMap(row.projects);
|
|
23875
|
+
if (local) hub.local = local;
|
|
23876
|
+
if (cloud) hub.cloud = cloud;
|
|
23877
|
+
if (projects && Object.keys(projects).length > 0) hub.projects = projects;
|
|
23878
|
+
return hub;
|
|
23879
|
+
}
|
|
23880
|
+
function findConfigRoot(start) {
|
|
23881
|
+
let dir = resolve(start);
|
|
23882
|
+
for (; ; ) {
|
|
23883
|
+
if (existsSync(join(dir, ".kxm", "project.yaml")) || existsSync(join(dir, ".kxm", "config.yaml"))) return dir;
|
|
23884
|
+
const parent = dirname(dir);
|
|
23885
|
+
if (parent === dir) return resolve(start);
|
|
23886
|
+
dir = parent;
|
|
23887
|
+
}
|
|
23888
|
+
}
|
|
23889
|
+
function userConfigDirForEnv(env) {
|
|
23890
|
+
const explicit = env.KXM_USER_CONFIG_DIR?.trim();
|
|
23891
|
+
if (explicit) return explicit;
|
|
23892
|
+
if (env === process.env) return void 0;
|
|
23893
|
+
return join(tmpdir(), "kxm-no-user-config");
|
|
23894
|
+
}
|
|
23895
|
+
function loadHubSettings(start, env = process.env) {
|
|
23896
|
+
const userConfigDir = userConfigDirForEnv(env);
|
|
23897
|
+
return loadKxmConfig(findConfigRoot(start), userConfigDir === void 0 ? {} : { userConfigDir }).hub;
|
|
23898
|
+
}
|
|
23899
|
+
function recordOf(raw) {
|
|
23900
|
+
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
23901
|
+
}
|
|
23902
|
+
function finiteNumber(value) {
|
|
23903
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
23904
|
+
}
|
|
23905
|
+
function normalizeImprovementConfig(raw) {
|
|
23906
|
+
const value = recordOf(raw);
|
|
23907
|
+
const threshold = recordOf(value.autoThreshold);
|
|
23908
|
+
const policy = value.promotionPolicy;
|
|
23909
|
+
const halfLife = finiteNumber(value.telemetryHalfLifeDays);
|
|
23910
|
+
const minRuns = finiteNumber(threshold.minRuns);
|
|
23911
|
+
const minPassRate = finiteNumber(threshold.minPassRate);
|
|
23912
|
+
const minCostSavings = finiteNumber(threshold.minCostSavings);
|
|
23913
|
+
return {
|
|
23914
|
+
promotionPolicy: IMPROVEMENT_PROMOTION_POLICIES.includes(policy) ? policy : "manual_pr",
|
|
23915
|
+
telemetryHalfLifeDays: halfLife !== void 0 && halfLife > 0 && halfLife <= 3650 ? halfLife : 14,
|
|
23916
|
+
autoThreshold: {
|
|
23917
|
+
minRuns: minRuns !== void 0 && Number.isInteger(minRuns) && minRuns >= 1 && minRuns <= 1e6 ? minRuns : 10,
|
|
23918
|
+
minPassRate: minPassRate !== void 0 && minPassRate >= 0 && minPassRate <= 1 ? minPassRate : 0.95,
|
|
23919
|
+
minCostSavings: minCostSavings !== void 0 && minCostSavings >= 0 ? minCostSavings : 0.5
|
|
23920
|
+
}
|
|
23921
|
+
};
|
|
23922
|
+
}
|
|
23923
|
+
function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
|
|
23924
|
+
const userDir = userConfigDirectory(options.userConfigDir);
|
|
23925
|
+
const userConfigFile = join(userDir, "config.yaml");
|
|
23926
|
+
const repoDir = repoConfigDirectory(repoRoot);
|
|
23927
|
+
const repoConfigFile = join(repoDir, "config.yaml");
|
|
23928
|
+
let userRaw = {};
|
|
23929
|
+
let userLoadedPath;
|
|
23930
|
+
if (existsSync(userConfigFile)) {
|
|
23931
|
+
try {
|
|
23932
|
+
const text = readFileSync(userConfigFile, "utf8");
|
|
23933
|
+
userRaw = (0, import_yaml.parse)(text) ?? {};
|
|
23934
|
+
userLoadedPath = userConfigFile;
|
|
23935
|
+
} catch (error2) {
|
|
23936
|
+
throw new Error(`invalid user config YAML at ${userConfigFile}`, { cause: error2 });
|
|
23937
|
+
}
|
|
23938
|
+
}
|
|
23939
|
+
let repoRaw = {};
|
|
23940
|
+
let repoLoadedPath;
|
|
23941
|
+
if (existsSync(repoConfigFile)) {
|
|
23942
|
+
try {
|
|
23943
|
+
const text = readFileSync(repoConfigFile, "utf8");
|
|
23944
|
+
repoRaw = (0, import_yaml.parse)(text) ?? {};
|
|
23945
|
+
repoLoadedPath = repoConfigFile;
|
|
23946
|
+
} catch (error2) {
|
|
23947
|
+
throw new Error(`invalid project config YAML at ${repoConfigFile}`, { cause: error2 });
|
|
23948
|
+
}
|
|
23949
|
+
}
|
|
23950
|
+
const baseCopy = JSON.parse(JSON.stringify(DEFAULT_KXM_CONFIG));
|
|
23951
|
+
const mergedUser = deepMerge(baseCopy, userRaw);
|
|
23952
|
+
const mergedAll = deepMerge(mergedUser, repoRaw);
|
|
23953
|
+
return {
|
|
23954
|
+
schema: KXM_CONFIG_SCHEMA,
|
|
23955
|
+
user: mergedAll.user ?? {},
|
|
23956
|
+
defaults: mergedAll.defaults ?? {},
|
|
23957
|
+
dash: mergedAll.dash ?? {},
|
|
23958
|
+
sync: mergedAll.sync ?? {},
|
|
23959
|
+
hub: normalizeHubConfig(mergedAll.hub),
|
|
23960
|
+
improvement: normalizeImprovementConfig(mergedAll.improvement),
|
|
23961
|
+
routing: mergedAll.routing ?? DEFAULT_KXM_CONFIG.routing,
|
|
23962
|
+
telemetry: mergedAll.telemetry ?? DEFAULT_KXM_CONFIG.telemetry,
|
|
23963
|
+
loadedFrom: {
|
|
23964
|
+
userConfigPath: userLoadedPath,
|
|
23965
|
+
repoConfigPath: repoLoadedPath
|
|
23966
|
+
}
|
|
23967
|
+
};
|
|
23968
|
+
}
|
|
23969
|
+
|
|
23970
|
+
// plugins/kxm/src/hub-identity.ts
|
|
23971
|
+
var import_yaml2 = __toESM(require_dist2(), 1);
|
|
23972
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
23973
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
23974
|
+
import { basename, dirname as dirname3, join as join3, resolve as resolve3 } from "node:path";
|
|
23660
23975
|
|
|
23661
23976
|
// plugins/kxm/src/hub-binding.ts
|
|
23662
23977
|
import { spawnSync } from "node:child_process";
|
|
23663
|
-
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
23664
|
-
import { homedir } from "node:os";
|
|
23665
|
-
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
23978
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
23979
|
+
import { homedir as homedir2 } from "node:os";
|
|
23980
|
+
import { dirname as dirname2, isAbsolute, join as join2, resolve as resolve2 } from "node:path";
|
|
23666
23981
|
var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
23667
23982
|
var CloudTokenError = class extends Error {
|
|
23668
23983
|
code;
|
|
@@ -23685,20 +24000,20 @@ function resolveUserStateRoot(env) {
|
|
|
23685
24000
|
const explicit = env.KXM_STATE_HOME?.trim();
|
|
23686
24001
|
if (explicit) {
|
|
23687
24002
|
if (!isAbsolute(explicit)) throw new HubBindingError("local_state_root_not_absolute");
|
|
23688
|
-
return
|
|
24003
|
+
return resolve2(explicit);
|
|
23689
24004
|
}
|
|
23690
24005
|
if (process.platform === "win32") {
|
|
23691
24006
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
23692
|
-
const base2 = localAppData && isAbsolute(localAppData) ? localAppData :
|
|
23693
|
-
return
|
|
24007
|
+
const base2 = localAppData && isAbsolute(localAppData) ? localAppData : join2(homedir2(), "AppData", "Local");
|
|
24008
|
+
return resolve2(base2, "KXM");
|
|
23694
24009
|
}
|
|
23695
|
-
if (process.platform === "darwin") return
|
|
24010
|
+
if (process.platform === "darwin") return resolve2(homedir2(), "Library", "Application Support", "KXM");
|
|
23696
24011
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
23697
|
-
const base = xdgState && isAbsolute(xdgState) ? xdgState :
|
|
23698
|
-
return
|
|
24012
|
+
const base = xdgState && isAbsolute(xdgState) ? xdgState : join2(homedir2(), ".local", "state");
|
|
24013
|
+
return resolve2(base, "kxm");
|
|
23699
24014
|
}
|
|
23700
24015
|
function hubBindingFile(env = process.env) {
|
|
23701
|
-
return
|
|
24016
|
+
return join2(resolveUserStateRoot(env), "hub-binding.json");
|
|
23702
24017
|
}
|
|
23703
24018
|
function validateHubUrl(raw) {
|
|
23704
24019
|
let parsed;
|
|
@@ -23753,17 +24068,6 @@ function splitTokenCommand(raw) {
|
|
|
23753
24068
|
function isCloudTokenEnvName(value) {
|
|
23754
24069
|
return TOKEN_ENV_NAME.test(value);
|
|
23755
24070
|
}
|
|
23756
|
-
function resolveHubServerUrl(env = process.env) {
|
|
23757
|
-
const fromEnv = env.KXM_SERVER_URL?.trim();
|
|
23758
|
-
if (fromEnv) return fromEnv.replace(/\/$/, "");
|
|
23759
|
-
try {
|
|
23760
|
-
const binding = readHubBinding(env);
|
|
23761
|
-
if (binding?.url) return binding.url;
|
|
23762
|
-
} catch (error2) {
|
|
23763
|
-
if (!(error2 instanceof HubBindingError)) throw error2;
|
|
23764
|
-
}
|
|
23765
|
-
return "http://127.0.0.1:7331";
|
|
23766
|
-
}
|
|
23767
24071
|
function resolveCloudHubToken(binding, env = process.env) {
|
|
23768
24072
|
if (!binding.cloud) {
|
|
23769
24073
|
throw new CloudTokenError("cloud_token_missing", "cloud hub token is missing; the local hub-env token was not used");
|
|
@@ -23805,16 +24109,27 @@ function runTokenCommand(command, env) {
|
|
|
23805
24109
|
}
|
|
23806
24110
|
return stdout.trim();
|
|
23807
24111
|
}
|
|
24112
|
+
function hubBindingScope(url) {
|
|
24113
|
+
let host;
|
|
24114
|
+
try {
|
|
24115
|
+
host = new URL(url).hostname.toLowerCase();
|
|
24116
|
+
} catch {
|
|
24117
|
+
return "remote";
|
|
24118
|
+
}
|
|
24119
|
+
if (host === "localhost" || host === "::1" || host === "[::1]" || host.endsWith(".localhost")) return "loopback";
|
|
24120
|
+
const v4 = /^127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/.exec(host);
|
|
24121
|
+
return v4 && [v4[1], v4[2], v4[3]].every((part) => Number(part) <= 255) ? "loopback" : "remote";
|
|
24122
|
+
}
|
|
23808
24123
|
function isIsoTimestamp(value) {
|
|
23809
24124
|
if (Number.isNaN(Date.parse(value))) return false;
|
|
23810
24125
|
return value === new Date(value).toISOString();
|
|
23811
24126
|
}
|
|
23812
24127
|
function readHubBinding(env = process.env) {
|
|
23813
24128
|
const file = hubBindingFile(env);
|
|
23814
|
-
if (!
|
|
24129
|
+
if (!existsSync2(file)) return void 0;
|
|
23815
24130
|
let parsed;
|
|
23816
24131
|
try {
|
|
23817
|
-
parsed = JSON.parse(
|
|
24132
|
+
parsed = JSON.parse(readFileSync2(file, "utf8"));
|
|
23818
24133
|
} catch {
|
|
23819
24134
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
23820
24135
|
}
|
|
@@ -23864,31 +24179,23 @@ function readHubBinding(env = process.env) {
|
|
|
23864
24179
|
};
|
|
23865
24180
|
}
|
|
23866
24181
|
|
|
23867
|
-
// plugins/kxm/src/
|
|
23868
|
-
var
|
|
23869
|
-
|
|
23870
|
-
|
|
23871
|
-
function defaultProjectName(cwd, env = process.env, explicit) {
|
|
23872
|
-
const fromExplicit = explicit?.trim();
|
|
23873
|
-
if (fromExplicit) return fromExplicit;
|
|
23874
|
-
const fromEnv = env.KXM_PROJECT?.trim();
|
|
23875
|
-
if (fromEnv) return fromEnv;
|
|
23876
|
-
const fromProject = readProjectYamlId(cwd);
|
|
23877
|
-
if (fromProject) return fromProject;
|
|
24182
|
+
// plugins/kxm/src/hub-identity.ts
|
|
24183
|
+
var OP_TIMEOUT_MS = 15e3;
|
|
24184
|
+
var OP_MAX_BUFFER = 4096;
|
|
24185
|
+
function normalizeUrl(raw) {
|
|
23878
24186
|
try {
|
|
23879
|
-
|
|
23880
|
-
if (typeof pkg.name === "string" && pkg.name.trim().length > 0) return pkg.name.trim();
|
|
24187
|
+
return validateHubUrl(raw);
|
|
23881
24188
|
} catch {
|
|
24189
|
+
return void 0;
|
|
23882
24190
|
}
|
|
23883
|
-
return basename(cwd);
|
|
23884
24191
|
}
|
|
23885
|
-
function
|
|
23886
|
-
let dir =
|
|
24192
|
+
function projectYamlId(start) {
|
|
24193
|
+
let dir = resolve3(start);
|
|
23887
24194
|
for (; ; ) {
|
|
23888
|
-
const file =
|
|
23889
|
-
if (
|
|
24195
|
+
const file = join3(dir, ".kxm", "project.yaml");
|
|
24196
|
+
if (existsSync3(file)) {
|
|
23890
24197
|
try {
|
|
23891
|
-
const doc = (0,
|
|
24198
|
+
const doc = (0, import_yaml2.parse)(readFileSync3(file, "utf8"));
|
|
23892
24199
|
if (doc && typeof doc === "object" && !Array.isArray(doc) && typeof doc.id === "string" && doc.id.trim()) {
|
|
23893
24200
|
return doc.id.trim();
|
|
23894
24201
|
}
|
|
@@ -23896,11 +24203,173 @@ function readProjectYamlId(start) {
|
|
|
23896
24203
|
}
|
|
23897
24204
|
return void 0;
|
|
23898
24205
|
}
|
|
23899
|
-
const parent =
|
|
24206
|
+
const parent = dirname3(dir);
|
|
23900
24207
|
if (parent === dir) return void 0;
|
|
23901
24208
|
dir = parent;
|
|
23902
24209
|
}
|
|
23903
24210
|
}
|
|
24211
|
+
function packageName(cwd) {
|
|
24212
|
+
try {
|
|
24213
|
+
const pkg = JSON.parse(readFileSync3(join3(cwd, "package.json"), "utf8"));
|
|
24214
|
+
if (typeof pkg.name === "string" && pkg.name.trim().length > 0) return pkg.name.trim();
|
|
24215
|
+
} catch {
|
|
24216
|
+
}
|
|
24217
|
+
return void 0;
|
|
24218
|
+
}
|
|
24219
|
+
function activeBinding(env) {
|
|
24220
|
+
try {
|
|
24221
|
+
return readHubBinding(env);
|
|
24222
|
+
} catch (error2) {
|
|
24223
|
+
if (error2 instanceof HubBindingError) return void 0;
|
|
24224
|
+
throw error2;
|
|
24225
|
+
}
|
|
24226
|
+
}
|
|
24227
|
+
function endpointFor(mode, settings) {
|
|
24228
|
+
return mode === "cloud" ? settings.cloud : settings.local;
|
|
24229
|
+
}
|
|
24230
|
+
function resolveProjectIdentity(cwd, env = process.env, explicit) {
|
|
24231
|
+
const fromExplicit = explicit?.trim();
|
|
24232
|
+
if (fromExplicit) return { project: fromExplicit, source: "flag", sourceLabel: "--project" };
|
|
24233
|
+
const fromEnv = env.KXM_PROJECT?.trim();
|
|
24234
|
+
if (fromEnv) return { project: fromEnv, source: "env", sourceLabel: "KXM_PROJECT" };
|
|
24235
|
+
const settings = loadHubSettings(cwd, env);
|
|
24236
|
+
const mode = settings.mode ?? (activeBinding(env)?.cloud ? "cloud" : "local");
|
|
24237
|
+
const fromConfig = endpointFor(mode, settings)?.project?.trim();
|
|
24238
|
+
if (fromConfig) {
|
|
24239
|
+
return { project: fromConfig, source: "config", sourceLabel: `.kxm/config.yaml hub.${mode}.project` };
|
|
24240
|
+
}
|
|
24241
|
+
const fromProject = projectYamlId(cwd);
|
|
24242
|
+
if (fromProject) return { project: fromProject, source: "project.yaml", sourceLabel: ".kxm/project.yaml id" };
|
|
24243
|
+
const fromPackage = packageName(cwd);
|
|
24244
|
+
if (fromPackage) return { project: fromPackage, source: "package.json", sourceLabel: "package.json name" };
|
|
24245
|
+
return { project: basename(cwd), source: "directory", sourceLabel: "directory name" };
|
|
24246
|
+
}
|
|
24247
|
+
function opReferenceFromTokenCommand(command) {
|
|
24248
|
+
try {
|
|
24249
|
+
const args = splitTokenCommand(command);
|
|
24250
|
+
if (args[0] === "op" && args[1] === "read" && args[2] && isHubOpReference(args[2])) return args[2];
|
|
24251
|
+
} catch {
|
|
24252
|
+
return void 0;
|
|
24253
|
+
}
|
|
24254
|
+
return void 0;
|
|
24255
|
+
}
|
|
24256
|
+
function defaultOpRead(reference, env) {
|
|
24257
|
+
if (!isHubOpReference(reference)) {
|
|
24258
|
+
throw new CloudTokenError("cloud_token_command_invalid", `refusing to resolve ${reference}; an op:// reference is required`);
|
|
24259
|
+
}
|
|
24260
|
+
const result = spawnSync2("op", ["read", reference], {
|
|
24261
|
+
encoding: "utf8",
|
|
24262
|
+
shell: false,
|
|
24263
|
+
timeout: OP_TIMEOUT_MS,
|
|
24264
|
+
maxBuffer: OP_MAX_BUFFER,
|
|
24265
|
+
env,
|
|
24266
|
+
windowsHide: true
|
|
24267
|
+
});
|
|
24268
|
+
if (result.error || result.status !== 0) {
|
|
24269
|
+
throw new CloudTokenError(
|
|
24270
|
+
"cloud_token_command_failed",
|
|
24271
|
+
`op read failed for ${reference}; the token was not saved`
|
|
24272
|
+
);
|
|
24273
|
+
}
|
|
24274
|
+
const line = (result.stdout ?? "").trim();
|
|
24275
|
+
if (!line || line.split(/\r?\n/).length !== 1) {
|
|
24276
|
+
throw new CloudTokenError(
|
|
24277
|
+
"cloud_token_command_failed",
|
|
24278
|
+
`op read did not print a single token for ${reference}; the token was not saved`
|
|
24279
|
+
);
|
|
24280
|
+
}
|
|
24281
|
+
return line;
|
|
24282
|
+
}
|
|
24283
|
+
function resolveKeyReference(ref, env, opRead = defaultOpRead) {
|
|
24284
|
+
if (!ref) return void 0;
|
|
24285
|
+
if (ref.env) {
|
|
24286
|
+
const value = env[ref.env]?.trim();
|
|
24287
|
+
if (value) return { value, source: `env:${ref.env}` };
|
|
24288
|
+
}
|
|
24289
|
+
if (ref.op) {
|
|
24290
|
+
const value = opRead(ref.op, env).trim();
|
|
24291
|
+
if (!value || value.split(/\r?\n/).length !== 1) {
|
|
24292
|
+
throw new CloudTokenError("cloud_token_command_failed", `op read did not print a single token for ${ref.op}`);
|
|
24293
|
+
}
|
|
24294
|
+
return { value, source: `op:${ref.op}` };
|
|
24295
|
+
}
|
|
24296
|
+
return void 0;
|
|
24297
|
+
}
|
|
24298
|
+
function keySourceFor(input) {
|
|
24299
|
+
const ref = input.endpoint?.key;
|
|
24300
|
+
if (input.mode === "local" && input.env.KXM_AUTH_TOKEN?.trim()) return "env:KXM_AUTH_TOKEN";
|
|
24301
|
+
if (ref?.env && input.env[ref.env]?.trim()) return `env:${ref.env}`;
|
|
24302
|
+
if (ref?.op) return `op:${ref.op}`;
|
|
24303
|
+
if (ref?.env) return `env:${ref.env}`;
|
|
24304
|
+
if (input.mode === "cloud") {
|
|
24305
|
+
if (input.binding?.tokenEnv) return `env:${input.binding.tokenEnv}`;
|
|
24306
|
+
if (input.binding?.tokenCommand) {
|
|
24307
|
+
const op = opReferenceFromTokenCommand(input.binding.tokenCommand);
|
|
24308
|
+
return op ? `op:${op}` : "command";
|
|
24309
|
+
}
|
|
24310
|
+
return "missing";
|
|
24311
|
+
}
|
|
24312
|
+
if (input.hasSavedProjectToken?.(input.project)) return "hub-env";
|
|
24313
|
+
return "missing";
|
|
24314
|
+
}
|
|
24315
|
+
function describeHubConnection(cwd, env = process.env, hooks = {}) {
|
|
24316
|
+
const settings = loadHubSettings(cwd, env);
|
|
24317
|
+
const binding = activeBinding(env);
|
|
24318
|
+
const mode = settings.mode ?? (binding?.cloud ? "cloud" : "local");
|
|
24319
|
+
const modeSource = settings.mode ? "config" : binding?.cloud ? "binding" : "default";
|
|
24320
|
+
const endpoint = endpointFor(mode, settings);
|
|
24321
|
+
const fromEnv = env.KXM_SERVER_URL?.trim();
|
|
24322
|
+
const fromConfig = endpoint?.url?.trim();
|
|
24323
|
+
const fromBinding = binding?.url;
|
|
24324
|
+
let url = "http://127.0.0.1:7331";
|
|
24325
|
+
let urlSource = "default";
|
|
24326
|
+
if (fromEnv) {
|
|
24327
|
+
url = fromEnv.replace(/\/$/, "");
|
|
24328
|
+
urlSource = "env";
|
|
24329
|
+
} else if (fromConfig) {
|
|
24330
|
+
url = fromConfig.replace(/\/$/, "");
|
|
24331
|
+
urlSource = "config";
|
|
24332
|
+
} else if (fromBinding) {
|
|
24333
|
+
url = fromBinding;
|
|
24334
|
+
urlSource = "binding";
|
|
24335
|
+
}
|
|
24336
|
+
const identity = resolveProjectIdentity(cwd, env, hooks.explicitProject);
|
|
24337
|
+
const configuredCloudUrl = settings.cloud?.url ?? (binding?.cloud ? binding.url : void 0);
|
|
24338
|
+
let scope;
|
|
24339
|
+
if (mode === "cloud") {
|
|
24340
|
+
const override = fromEnv ? normalizeUrl(fromEnv) : void 0;
|
|
24341
|
+
const named = configuredCloudUrl ? normalizeUrl(configuredCloudUrl) : void 0;
|
|
24342
|
+
scope = override && named && override !== named ? hubBindingScope(url) : "remote";
|
|
24343
|
+
} else {
|
|
24344
|
+
scope = hubBindingScope(url);
|
|
24345
|
+
}
|
|
24346
|
+
return {
|
|
24347
|
+
...identity,
|
|
24348
|
+
mode,
|
|
24349
|
+
modeSource,
|
|
24350
|
+
url,
|
|
24351
|
+
urlSource,
|
|
24352
|
+
scope,
|
|
24353
|
+
...endpoint ? { endpoint } : {},
|
|
24354
|
+
...binding ? { binding } : {},
|
|
24355
|
+
keySource: keySourceFor({
|
|
24356
|
+
mode,
|
|
24357
|
+
env,
|
|
24358
|
+
...endpoint ? { endpoint } : {},
|
|
24359
|
+
...binding ? { binding } : {},
|
|
24360
|
+
project: identity.project,
|
|
24361
|
+
...hooks.hasSavedProjectToken ? { hasSavedProjectToken: hooks.hasSavedProjectToken } : {}
|
|
24362
|
+
})
|
|
24363
|
+
};
|
|
24364
|
+
}
|
|
24365
|
+
function projectTokenMissingMessage(identity) {
|
|
24366
|
+
return [
|
|
24367
|
+
`kxm has no project token for project ${identity.project} (from ${identity.sourceLabel}).`,
|
|
24368
|
+
`Ask the user to set this project's token. Set KXM_AUTH_TOKEN, or set hub.local.project or hub.cloud.project in .kxm/config.yaml to the project key the hub already knows, or add a key reference under hub.projects.${identity.project} (key.op is an op:// reference, key.env is an environment variable name, never the token) and restart the hub.`,
|
|
24369
|
+
"KXM_PROJECT or --project overrides the id for one command.",
|
|
24370
|
+
"An agent never uses the hub admin token."
|
|
24371
|
+
].join(" ");
|
|
24372
|
+
}
|
|
23904
24373
|
|
|
23905
24374
|
// plugins/kxm/src/hub-env.ts
|
|
23906
24375
|
var HUB_ENV_SCHEMA = "kxm.hub-env.v1";
|
|
@@ -23914,27 +24383,27 @@ function resolveUserStateRoot2(env) {
|
|
|
23914
24383
|
const explicit = env.KXM_STATE_HOME?.trim();
|
|
23915
24384
|
if (explicit) {
|
|
23916
24385
|
if (!isAbsolute2(explicit)) throw new HubEnvError("local_state_root_not_absolute");
|
|
23917
|
-
return
|
|
24386
|
+
return resolve4(explicit);
|
|
23918
24387
|
}
|
|
23919
24388
|
if (process.platform === "win32") {
|
|
23920
24389
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
23921
|
-
const base2 = localAppData && isAbsolute2(localAppData) ? localAppData :
|
|
23922
|
-
return
|
|
24390
|
+
const base2 = localAppData && isAbsolute2(localAppData) ? localAppData : join4(homedir3(), "AppData", "Local");
|
|
24391
|
+
return resolve4(base2, "KXM");
|
|
23923
24392
|
}
|
|
23924
|
-
if (process.platform === "darwin") return
|
|
24393
|
+
if (process.platform === "darwin") return resolve4(homedir3(), "Library", "Application Support", "KXM");
|
|
23925
24394
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
23926
|
-
const base = xdgState && isAbsolute2(xdgState) ? xdgState :
|
|
23927
|
-
return
|
|
24395
|
+
const base = xdgState && isAbsolute2(xdgState) ? xdgState : join4(homedir3(), ".local", "state");
|
|
24396
|
+
return resolve4(base, "kxm");
|
|
23928
24397
|
}
|
|
23929
24398
|
function hubEnvFile(env = process.env) {
|
|
23930
|
-
return
|
|
24399
|
+
return join4(resolveUserStateRoot2(env), "hub-env.json");
|
|
23931
24400
|
}
|
|
23932
24401
|
function readHubEnvRecord(env = process.env) {
|
|
23933
24402
|
const file = hubEnvFile(env);
|
|
23934
|
-
if (!
|
|
24403
|
+
if (!existsSync4(file)) return void 0;
|
|
23935
24404
|
let parsed;
|
|
23936
24405
|
try {
|
|
23937
|
-
parsed = JSON.parse(
|
|
24406
|
+
parsed = JSON.parse(readFileSync4(file, "utf8"));
|
|
23938
24407
|
} catch (error2) {
|
|
23939
24408
|
throw new HubEnvError(`hub env file is malformed at ${file}: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
23940
24409
|
}
|
|
@@ -23966,33 +24435,48 @@ function readHubEnvRecord(env = process.env) {
|
|
|
23966
24435
|
...record2.projectTokens !== void 0 ? { projectTokens: record2.projectTokens } : {}
|
|
23967
24436
|
};
|
|
23968
24437
|
}
|
|
23969
|
-
function
|
|
23970
|
-
|
|
23971
|
-
|
|
23972
|
-
|
|
23973
|
-
|
|
23974
|
-
|
|
23975
|
-
|
|
23976
|
-
|
|
23977
|
-
|
|
23978
|
-
|
|
23979
|
-
throw error2;
|
|
23980
|
-
}
|
|
24438
|
+
function cloudModeToken(cwd, env, explicitProject, opRead) {
|
|
24439
|
+
const connection = describeHubConnection(cwd, env, explicitProject === void 0 ? {} : { explicitProject });
|
|
24440
|
+
if (connection.mode !== "cloud") return void 0;
|
|
24441
|
+
const fromConfig = resolveKeyReference(connection.endpoint?.key, env, opRead);
|
|
24442
|
+
if (fromConfig) return fromConfig.value;
|
|
24443
|
+
if (connection.binding?.cloud) return resolveCloudHubToken(connection.binding, env);
|
|
24444
|
+
throw new CloudTokenError(
|
|
24445
|
+
"cloud_token_missing",
|
|
24446
|
+
"cloud hub token is missing; the local hub-env token was not used"
|
|
24447
|
+
);
|
|
23981
24448
|
}
|
|
23982
|
-
function resolveAgentHubAuthToken(env, project) {
|
|
23983
|
-
const cloud =
|
|
23984
|
-
if (cloud) return
|
|
24449
|
+
function resolveAgentHubAuthToken(env, project, cwd = process.cwd(), opRead) {
|
|
24450
|
+
const cloud = cloudModeToken(cwd, env, void 0, opRead);
|
|
24451
|
+
if (cloud) return cloud;
|
|
23985
24452
|
const envToken = env.KXM_AUTH_TOKEN?.trim();
|
|
23986
24453
|
if (envToken) return envToken;
|
|
24454
|
+
const fromConfig = resolveKeyReference(describeHubConnection(cwd, env).endpoint?.key, env, opRead);
|
|
24455
|
+
if (fromConfig) return fromConfig.value;
|
|
23987
24456
|
const tokens = readHubEnvRecord(env)?.projectTokens;
|
|
23988
24457
|
if (!tokens || !Object.hasOwn(tokens, project)) return void 0;
|
|
23989
24458
|
return tokens[project]?.trim() || void 0;
|
|
23990
24459
|
}
|
|
24460
|
+
var AgentProjectTokenMissingError = class extends Error {
|
|
24461
|
+
code = "project_token_missing";
|
|
24462
|
+
project;
|
|
24463
|
+
projectSource;
|
|
24464
|
+
hint;
|
|
24465
|
+
constructor(projectOrIdentity) {
|
|
24466
|
+
const identity = typeof projectOrIdentity === "string" ? { project: projectOrIdentity, source: "env", sourceLabel: "the project id sent to the hub" } : projectOrIdentity;
|
|
24467
|
+
const message = projectTokenMissingMessage(identity);
|
|
24468
|
+
super(message);
|
|
24469
|
+
this.name = "AgentProjectTokenMissingError";
|
|
24470
|
+
this.project = identity.project;
|
|
24471
|
+
this.projectSource = typeof projectOrIdentity === "string" ? "unknown" : identity.source;
|
|
24472
|
+
this.hint = message;
|
|
24473
|
+
}
|
|
24474
|
+
};
|
|
23991
24475
|
|
|
23992
24476
|
// plugins/kxm/src/commands.ts
|
|
23993
|
-
import { chmodSync, existsSync as
|
|
23994
|
-
import { homedir as
|
|
23995
|
-
import { dirname as
|
|
24477
|
+
import { chmodSync, existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5, unlinkSync, writeFileSync as writeFileSync4 } from "node:fs";
|
|
24478
|
+
import { homedir as homedir4 } from "node:os";
|
|
24479
|
+
import { dirname as dirname5, join as join5, resolve as resolve5 } from "node:path";
|
|
23996
24480
|
function forwardedHops(handling) {
|
|
23997
24481
|
if (!handling?.length) return void 0;
|
|
23998
24482
|
return {
|
|
@@ -24755,11 +25239,11 @@ function parseSessionToken(token) {
|
|
|
24755
25239
|
return void 0;
|
|
24756
25240
|
}
|
|
24757
25241
|
function resolveUserConfigDirectory(overrideDir) {
|
|
24758
|
-
if (overrideDir) return
|
|
24759
|
-
return
|
|
25242
|
+
if (overrideDir) return resolve5(overrideDir);
|
|
25243
|
+
return resolve5(process.env.KXM_USER_CONFIG_DIR?.trim() || join5(homedir4(), ".config", "kxm"));
|
|
24760
25244
|
}
|
|
24761
25245
|
function sessionTokenPath(userConfigDir) {
|
|
24762
|
-
return
|
|
25246
|
+
return join5(resolveUserConfigDirectory(userConfigDir), "session.token");
|
|
24763
25247
|
}
|
|
24764
25248
|
function matchToolPattern(pattern, toolName) {
|
|
24765
25249
|
if (pattern === "*" || pattern === toolName) return true;
|
|
@@ -24852,10 +25336,10 @@ function enforceToolPolicy(commandName, env = process.env, options) {
|
|
|
24852
25336
|
return { allowed: true };
|
|
24853
25337
|
}
|
|
24854
25338
|
const tokenFile = sessionTokenPath(env.KXM_USER_CONFIG_DIR);
|
|
24855
|
-
if (
|
|
25339
|
+
if (existsSync5(tokenFile)) {
|
|
24856
25340
|
let tokenRaw;
|
|
24857
25341
|
try {
|
|
24858
|
-
tokenRaw =
|
|
25342
|
+
tokenRaw = readFileSync5(tokenFile, "utf8").trim();
|
|
24859
25343
|
} catch {
|
|
24860
25344
|
return { allowed: false, error: "session_token_invalid", detail: "Session token file on disk could not be read" };
|
|
24861
25345
|
}
|
|
@@ -24897,7 +25381,7 @@ function sessionTokenFixHint(policy) {
|
|
|
24897
25381
|
}
|
|
24898
25382
|
|
|
24899
25383
|
// plugins/kxm/src/mcp-server.ts
|
|
24900
|
-
var VERSION = "0.7.
|
|
25384
|
+
var VERSION = "0.7.166";
|
|
24901
25385
|
var CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
|
|
24902
25386
|
var inbox = /* @__PURE__ */ new Map();
|
|
24903
25387
|
var notifiedInbox = /* @__PURE__ */ new Set();
|
|
@@ -24927,10 +25411,13 @@ function asRecord2(value) {
|
|
|
24927
25411
|
}
|
|
24928
25412
|
function sessionIdentity() {
|
|
24929
25413
|
const projectDir = process.env.KXM_PROJECT_DIR || process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
25414
|
+
const connection = describeHubConnection(projectDir, process.env);
|
|
24930
25415
|
return {
|
|
24931
25416
|
projectDir,
|
|
24932
|
-
project:
|
|
24933
|
-
|
|
25417
|
+
project: connection.project,
|
|
25418
|
+
projectSource: connection.source,
|
|
25419
|
+
sourceLabel: connection.sourceLabel,
|
|
25420
|
+
serverUrl: connection.url
|
|
24934
25421
|
};
|
|
24935
25422
|
}
|
|
24936
25423
|
async function announce(message) {
|
|
@@ -25000,12 +25487,10 @@ async function ensureClient() {
|
|
|
25000
25487
|
if (meshClient?.agent) return meshClient;
|
|
25001
25488
|
if (starting) return starting;
|
|
25002
25489
|
starting = (async () => {
|
|
25003
|
-
const { project, serverUrl } = sessionIdentity();
|
|
25004
|
-
const authToken = resolveAgentHubAuthToken(process.env, project);
|
|
25490
|
+
const { project, projectDir, serverUrl } = sessionIdentity();
|
|
25491
|
+
const authToken = resolveAgentHubAuthToken(process.env, project, projectDir);
|
|
25005
25492
|
if (!authToken) {
|
|
25006
|
-
throw new
|
|
25007
|
-
`KXM has no project token for project ${project} on this machine. Ask the user to set the kxm plugin auth_token (${CONFIGURE_PLUGIN}) or to add ${project} to the hub KXM_PROJECT_TOKENS, listing every existing project too because that variable replaces the saved map.`
|
|
25008
|
-
);
|
|
25493
|
+
throw new AgentProjectTokenMissingError(resolveProjectIdentity(projectDir, process.env));
|
|
25009
25494
|
}
|
|
25010
25495
|
const name = process.env.KXM_AGENT_NAME?.trim() || `claude-${process.pid}`;
|
|
25011
25496
|
try {
|
|
@@ -25048,8 +25533,10 @@ async function connectedClient() {
|
|
|
25048
25533
|
}
|
|
25049
25534
|
}
|
|
25050
25535
|
function toolErrorText(error2) {
|
|
25051
|
-
if (error2 instanceof
|
|
25052
|
-
|
|
25536
|
+
if (error2 instanceof AgentProjectTokenMissingError) return error2.message;
|
|
25537
|
+
if (error2 instanceof HubHttpError && (error2.code === "invalid_auth" || error2.code === "project_token_missing")) {
|
|
25538
|
+
const identity = sessionIdentity();
|
|
25539
|
+
return `KXM hub rejected the project token for project ${identity.project} (from ${identity.sourceLabel}). Set hub.local.project or hub.cloud.project in .kxm/config.yaml to the key the hub already knows, and set hub.local.key or hub.cloud.key to an op:// reference or an environment variable name. Ask the user before changing the kxm plugin auth_token (${CONFIGURE_PLUGIN}). Never put the token in config.`;
|
|
25053
25540
|
}
|
|
25054
25541
|
return error2 instanceof Error ? error2.message : String(error2);
|
|
25055
25542
|
}
|
|
@@ -25083,8 +25570,8 @@ mcp.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
|
25083
25570
|
function registersAtStartup() {
|
|
25084
25571
|
const { projectDir, project } = sessionIdentity();
|
|
25085
25572
|
try {
|
|
25086
|
-
if (!statSync(
|
|
25087
|
-
if (!resolveAgentHubAuthToken(process.env, project)) return false;
|
|
25573
|
+
if (!statSync(join6(projectDir, ".kxm")).isDirectory()) return false;
|
|
25574
|
+
if (!resolveAgentHubAuthToken(process.env, project, projectDir)) return false;
|
|
25088
25575
|
} catch {
|
|
25089
25576
|
return false;
|
|
25090
25577
|
}
|