@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
|
@@ -10319,7 +10319,7 @@ var require_compile = __commonJS({
|
|
|
10319
10319
|
const schOrFunc = root.refs[ref];
|
|
10320
10320
|
if (schOrFunc)
|
|
10321
10321
|
return schOrFunc;
|
|
10322
|
-
let _sch =
|
|
10322
|
+
let _sch = resolve9.call(this, root, ref);
|
|
10323
10323
|
if (_sch === void 0) {
|
|
10324
10324
|
const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
|
|
10325
10325
|
const { schemaId } = this.opts;
|
|
@@ -10346,7 +10346,7 @@ var require_compile = __commonJS({
|
|
|
10346
10346
|
function sameSchemaEnv(s1, s2) {
|
|
10347
10347
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
10348
10348
|
}
|
|
10349
|
-
function
|
|
10349
|
+
function resolve9(root, ref) {
|
|
10350
10350
|
let sch;
|
|
10351
10351
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
10352
10352
|
ref = sch;
|
|
@@ -11171,7 +11171,7 @@ var require_fast_uri = __commonJS({
|
|
|
11171
11171
|
}
|
|
11172
11172
|
return uri;
|
|
11173
11173
|
}
|
|
11174
|
-
function
|
|
11174
|
+
function resolve9(baseURI, relativeURI, options) {
|
|
11175
11175
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
11176
11176
|
const {
|
|
11177
11177
|
parsed: baseParsed,
|
|
@@ -11533,7 +11533,7 @@ var require_fast_uri = __commonJS({
|
|
|
11533
11533
|
var fastUri = {
|
|
11534
11534
|
SCHEMES,
|
|
11535
11535
|
normalize,
|
|
11536
|
-
resolve:
|
|
11536
|
+
resolve: resolve9,
|
|
11537
11537
|
resolveComponent,
|
|
11538
11538
|
equal,
|
|
11539
11539
|
serialize,
|
|
@@ -14523,9 +14523,9 @@ var require_dist2 = __commonJS({
|
|
|
14523
14523
|
});
|
|
14524
14524
|
|
|
14525
14525
|
// plugins/kxm/src/extension.ts
|
|
14526
|
-
import { spawnSync as
|
|
14527
|
-
import { existsSync as
|
|
14528
|
-
import { dirname as
|
|
14526
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
14527
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync14, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync7 } from "node:fs";
|
|
14528
|
+
import { dirname as dirname8, join as join15 } from "node:path";
|
|
14529
14529
|
|
|
14530
14530
|
// plugins/kxm/src/commands.ts
|
|
14531
14531
|
import { chmodSync, existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
@@ -14967,7 +14967,7 @@ var HubClient = class {
|
|
|
14967
14967
|
if (signal?.aborted) throw new MeshWaitError("aborted", messageId);
|
|
14968
14968
|
const message = await this.getMessage(messageId);
|
|
14969
14969
|
if (["replied", "cancelled", "expired", "error"].includes(message.status)) return message;
|
|
14970
|
-
await new Promise((
|
|
14970
|
+
await new Promise((resolve9, reject) => {
|
|
14971
14971
|
const onAbort = () => {
|
|
14972
14972
|
signal?.removeEventListener("abort", onAbort);
|
|
14973
14973
|
clearTimeout(timer);
|
|
@@ -14975,7 +14975,7 @@ var HubClient = class {
|
|
|
14975
14975
|
};
|
|
14976
14976
|
const timer = setTimeout(() => {
|
|
14977
14977
|
signal?.removeEventListener("abort", onAbort);
|
|
14978
|
-
|
|
14978
|
+
resolve9();
|
|
14979
14979
|
}, Math.min(500, Math.max(1, deadline - Date.now())));
|
|
14980
14980
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
14981
14981
|
if (signal?.aborted) onAbort();
|
|
@@ -15030,7 +15030,7 @@ var HubClient = class {
|
|
|
15030
15030
|
} catch (error2) {
|
|
15031
15031
|
if (this.stopped || error2 instanceof Error && error2.name === "AbortError") return;
|
|
15032
15032
|
}
|
|
15033
|
-
if (!this.stopped) await new Promise((
|
|
15033
|
+
if (!this.stopped) await new Promise((resolve9) => setTimeout(resolve9, this.options.reconnectMs));
|
|
15034
15034
|
}
|
|
15035
15035
|
}
|
|
15036
15036
|
headers(includeIdentity = true) {
|
|
@@ -15995,9 +15995,25 @@ function enforceToolPolicy(commandName, env = process.env, options) {
|
|
|
15995
15995
|
// plugins/kxm/src/config.ts
|
|
15996
15996
|
var import_yaml = __toESM(require_dist(), 1);
|
|
15997
15997
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
15998
|
-
import { homedir as homedir2 } from "node:os";
|
|
15998
|
+
import { tmpdir, homedir as homedir2 } from "node:os";
|
|
15999
15999
|
import { dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
|
|
16000
16000
|
var KXM_CONFIG_SCHEMA = "kxm.config.v1";
|
|
16001
|
+
var KxmHubConfigError = class extends Error {
|
|
16002
|
+
code = "hub_config_invalid";
|
|
16003
|
+
constructor(message) {
|
|
16004
|
+
super(message);
|
|
16005
|
+
this.name = "KxmHubConfigError";
|
|
16006
|
+
}
|
|
16007
|
+
};
|
|
16008
|
+
var HUB_ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
16009
|
+
var HUB_OP_REF = /^op:\/\/\S+\/\S+\/\S+$/;
|
|
16010
|
+
var LITERAL_SECRET_KEY = /^(token|secret|password|authToken|auth_token|apiKey|api_key|api_token|bearer|credential|access_token)$/i;
|
|
16011
|
+
function isHubKeyEnvName(value) {
|
|
16012
|
+
return HUB_ENV_NAME.test(value);
|
|
16013
|
+
}
|
|
16014
|
+
function isHubOpReference(value) {
|
|
16015
|
+
return HUB_OP_REF.test(value);
|
|
16016
|
+
}
|
|
16001
16017
|
var IMPROVEMENT_PROMOTION_POLICIES = ["manual_pr", "critic_quorum", "auto_threshold"];
|
|
16002
16018
|
var DEFAULT_KXM_CONFIG = {
|
|
16003
16019
|
schema: KXM_CONFIG_SCHEMA,
|
|
@@ -16068,9 +16084,151 @@ function deepMerge(target, source) {
|
|
|
16068
16084
|
}
|
|
16069
16085
|
return result2;
|
|
16070
16086
|
}
|
|
16087
|
+
function literalSecretMessage(path) {
|
|
16088
|
+
return `refusing literal hub token at ${path}: store an op:// reference (key.op) or an environment variable name (key.env), never the token`;
|
|
16089
|
+
}
|
|
16090
|
+
function rejectLiteralHubSecrets(value, path) {
|
|
16091
|
+
if (Array.isArray(value)) {
|
|
16092
|
+
value.forEach((item, index) => rejectLiteralHubSecrets(item, `${path}[${index}]`));
|
|
16093
|
+
return;
|
|
16094
|
+
}
|
|
16095
|
+
if (!value || typeof value !== "object") return;
|
|
16096
|
+
for (const [key, child] of Object.entries(value)) {
|
|
16097
|
+
const childPath = `${path}.${key}`;
|
|
16098
|
+
if (typeof child === "string" && (key === "key" || LITERAL_SECRET_KEY.test(key))) {
|
|
16099
|
+
throw new KxmHubConfigError(literalSecretMessage(childPath));
|
|
16100
|
+
}
|
|
16101
|
+
if (child && typeof child === "object") rejectLiteralHubSecrets(child, childPath);
|
|
16102
|
+
}
|
|
16103
|
+
}
|
|
16104
|
+
function parseKeyRef(raw, path) {
|
|
16105
|
+
if (raw === void 0) return void 0;
|
|
16106
|
+
if (typeof raw === "string") throw new KxmHubConfigError(literalSecretMessage(path));
|
|
16107
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
16108
|
+
throw new KxmHubConfigError(`${path} must be a key reference with op and/or env, never a token`);
|
|
16109
|
+
}
|
|
16110
|
+
const row = raw;
|
|
16111
|
+
for (const key of Object.keys(row)) {
|
|
16112
|
+
if (key !== "op" && key !== "env") {
|
|
16113
|
+
throw new KxmHubConfigError(literalSecretMessage(`${path}.${key}`));
|
|
16114
|
+
}
|
|
16115
|
+
}
|
|
16116
|
+
const ref = {};
|
|
16117
|
+
if (row.op !== void 0) {
|
|
16118
|
+
if (typeof row.op !== "string" || !isHubOpReference(row.op)) {
|
|
16119
|
+
throw new KxmHubConfigError(`${path}.op must be an op://vault/item/field reference, not a token`);
|
|
16120
|
+
}
|
|
16121
|
+
ref.op = row.op;
|
|
16122
|
+
}
|
|
16123
|
+
if (row.env !== void 0) {
|
|
16124
|
+
if (typeof row.env !== "string" || !isHubKeyEnvName(row.env)) {
|
|
16125
|
+
throw new KxmHubConfigError(`${path}.env must be an environment variable name, not a token`);
|
|
16126
|
+
}
|
|
16127
|
+
ref.env = row.env;
|
|
16128
|
+
}
|
|
16129
|
+
if (!ref.op && !ref.env) throw new KxmHubConfigError(`${path} needs key.op, key.env, or both`);
|
|
16130
|
+
return ref;
|
|
16131
|
+
}
|
|
16132
|
+
function parseEndpoint(raw, path) {
|
|
16133
|
+
if (raw === void 0) return void 0;
|
|
16134
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
16135
|
+
throw new KxmHubConfigError(`${path} must be an object with url, project, and key`);
|
|
16136
|
+
}
|
|
16137
|
+
const row = raw;
|
|
16138
|
+
const endpoint = {};
|
|
16139
|
+
if (row.url !== void 0) {
|
|
16140
|
+
if (typeof row.url !== "string" || !isHubUrl(row.url)) {
|
|
16141
|
+
throw new KxmHubConfigError(`${path}.url must be an http or https URL without credentials, query, or fragment`);
|
|
16142
|
+
}
|
|
16143
|
+
endpoint.url = row.url.replace(/\/$/, "");
|
|
16144
|
+
}
|
|
16145
|
+
if (row.project !== void 0) {
|
|
16146
|
+
if (typeof row.project !== "string" || !isHubProjectId(row.project)) {
|
|
16147
|
+
throw new KxmHubConfigError(`${path}.project must be a single-line project id, not a token`);
|
|
16148
|
+
}
|
|
16149
|
+
endpoint.project = row.project.trim();
|
|
16150
|
+
}
|
|
16151
|
+
const key = parseKeyRef(row.key, `${path}.key`);
|
|
16152
|
+
if (key) endpoint.key = key;
|
|
16153
|
+
for (const name of Object.keys(row)) {
|
|
16154
|
+
if (name !== "url" && name !== "project" && name !== "key") {
|
|
16155
|
+
if (typeof row[name] === "string") throw new KxmHubConfigError(literalSecretMessage(`${path}.${name}`));
|
|
16156
|
+
throw new KxmHubConfigError(`${path}.${name} is not a hub endpoint field`);
|
|
16157
|
+
}
|
|
16158
|
+
}
|
|
16159
|
+
return endpoint;
|
|
16160
|
+
}
|
|
16161
|
+
function isHubUrl(raw) {
|
|
16162
|
+
try {
|
|
16163
|
+
const parsed = new URL(raw);
|
|
16164
|
+
return (parsed.protocol === "http:" || parsed.protocol === "https:") && parsed.username === "" && parsed.password === "" && parsed.search === "" && parsed.hash === "" && !raw.includes("?") && !raw.includes("#");
|
|
16165
|
+
} catch {
|
|
16166
|
+
return false;
|
|
16167
|
+
}
|
|
16168
|
+
}
|
|
16169
|
+
function isHubProjectId(raw) {
|
|
16170
|
+
const value = raw.trim();
|
|
16171
|
+
return value.length > 0 && value.length <= 200 && !/[\s\r\n]/.test(value);
|
|
16172
|
+
}
|
|
16173
|
+
function parseProjectMap(raw) {
|
|
16174
|
+
if (raw === void 0) return void 0;
|
|
16175
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
16176
|
+
throw new KxmHubConfigError("hub.projects must be a map of project id to key reference, never a token");
|
|
16177
|
+
}
|
|
16178
|
+
const projects = {};
|
|
16179
|
+
for (const [project, value] of Object.entries(raw)) {
|
|
16180
|
+
if (!isHubProjectId(project)) {
|
|
16181
|
+
throw new KxmHubConfigError(`hub.projects key ${JSON.stringify(project)} must be a project id, not a token`);
|
|
16182
|
+
}
|
|
16183
|
+
const ref = parseKeyRef(value, `hub.projects.${project}`);
|
|
16184
|
+
if (!ref) throw new KxmHubConfigError(`hub.projects.${project} needs an op:// reference or an environment variable name`);
|
|
16185
|
+
projects[project.trim()] = ref;
|
|
16186
|
+
}
|
|
16187
|
+
return projects;
|
|
16188
|
+
}
|
|
16071
16189
|
function normalizeHubConfig(raw) {
|
|
16072
16190
|
const autoStart = raw?.autoStart;
|
|
16073
|
-
|
|
16191
|
+
const hub = {
|
|
16192
|
+
autoStart: autoStart === "off" || autoStart === "background" ? autoStart : DEFAULT_KXM_CONFIG.hub.autoStart
|
|
16193
|
+
};
|
|
16194
|
+
if (raw === void 0) return hub;
|
|
16195
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
16196
|
+
throw new KxmHubConfigError("hub must be an object");
|
|
16197
|
+
}
|
|
16198
|
+
rejectLiteralHubSecrets(raw, "hub");
|
|
16199
|
+
const row = raw;
|
|
16200
|
+
if (row.mode !== void 0) {
|
|
16201
|
+
if (row.mode !== "local" && row.mode !== "cloud") {
|
|
16202
|
+
throw new KxmHubConfigError("hub.mode must be local or cloud");
|
|
16203
|
+
}
|
|
16204
|
+
hub.mode = row.mode;
|
|
16205
|
+
}
|
|
16206
|
+
const local = parseEndpoint(row.local, "hub.local");
|
|
16207
|
+
const cloud = parseEndpoint(row.cloud, "hub.cloud");
|
|
16208
|
+
const projects = parseProjectMap(row.projects);
|
|
16209
|
+
if (local) hub.local = local;
|
|
16210
|
+
if (cloud) hub.cloud = cloud;
|
|
16211
|
+
if (projects && Object.keys(projects).length > 0) hub.projects = projects;
|
|
16212
|
+
return hub;
|
|
16213
|
+
}
|
|
16214
|
+
function findConfigRoot(start) {
|
|
16215
|
+
let dir = resolve2(start);
|
|
16216
|
+
for (; ; ) {
|
|
16217
|
+
if (existsSync2(join2(dir, ".kxm", "project.yaml")) || existsSync2(join2(dir, ".kxm", "config.yaml"))) return dir;
|
|
16218
|
+
const parent = dirname2(dir);
|
|
16219
|
+
if (parent === dir) return resolve2(start);
|
|
16220
|
+
dir = parent;
|
|
16221
|
+
}
|
|
16222
|
+
}
|
|
16223
|
+
function userConfigDirForEnv(env) {
|
|
16224
|
+
const explicit = env.KXM_USER_CONFIG_DIR?.trim();
|
|
16225
|
+
if (explicit) return explicit;
|
|
16226
|
+
if (env === process.env) return void 0;
|
|
16227
|
+
return join2(tmpdir(), "kxm-no-user-config");
|
|
16228
|
+
}
|
|
16229
|
+
function loadHubSettings(start, env = process.env) {
|
|
16230
|
+
const userConfigDir = userConfigDirForEnv(env);
|
|
16231
|
+
return loadKxmConfig(findConfigRoot(start), userConfigDir === void 0 ? {} : { userConfigDir }).hub;
|
|
16074
16232
|
}
|
|
16075
16233
|
function recordOf(raw) {
|
|
16076
16234
|
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
@@ -16145,15 +16303,27 @@ function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
|
|
|
16145
16303
|
|
|
16146
16304
|
// plugins/kxm/src/hub-autostart.ts
|
|
16147
16305
|
import { spawn } from "node:child_process";
|
|
16148
|
-
import { closeSync, mkdirSync as mkdirSync5, openSync, readFileSync as
|
|
16149
|
-
import { join as
|
|
16306
|
+
import { closeSync, mkdirSync as mkdirSync5, openSync, readFileSync as readFileSync6 } from "node:fs";
|
|
16307
|
+
import { join as join7, resolve as resolve6 } from "node:path";
|
|
16150
16308
|
|
|
16151
16309
|
// plugins/kxm/src/hub-binding.ts
|
|
16310
|
+
import { spawnSync } from "node:child_process";
|
|
16152
16311
|
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
16153
16312
|
import { homedir as homedir3 } from "node:os";
|
|
16154
16313
|
import { dirname as dirname3, isAbsolute, join as join3, resolve as resolve3 } from "node:path";
|
|
16155
16314
|
var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
16156
16315
|
var HUB_HEALTH_PROBE_MS = 300;
|
|
16316
|
+
var CloudTokenError = class extends Error {
|
|
16317
|
+
code;
|
|
16318
|
+
constructor(code, message) {
|
|
16319
|
+
super(message);
|
|
16320
|
+
this.name = "CloudTokenError";
|
|
16321
|
+
this.code = code;
|
|
16322
|
+
}
|
|
16323
|
+
};
|
|
16324
|
+
var TOKEN_ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
16325
|
+
var TOKEN_COMMAND_TIMEOUT_MS = 15e3;
|
|
16326
|
+
var TOKEN_COMMAND_MAX_BUFFER = 4096;
|
|
16157
16327
|
var HubBindingError = class extends Error {
|
|
16158
16328
|
constructor(message) {
|
|
16159
16329
|
super(message);
|
|
@@ -16191,6 +16361,99 @@ function validateHubUrl(raw) {
|
|
|
16191
16361
|
}
|
|
16192
16362
|
return parsed.href.replace(/\/$/, "");
|
|
16193
16363
|
}
|
|
16364
|
+
function splitTokenCommand(raw) {
|
|
16365
|
+
if (/[|&;<>$`\n\r]/.test(raw)) {
|
|
16366
|
+
throw new CloudTokenError(
|
|
16367
|
+
"cloud_token_command_invalid",
|
|
16368
|
+
"token command must be a program and arguments, not a shell pipeline"
|
|
16369
|
+
);
|
|
16370
|
+
}
|
|
16371
|
+
const args = [];
|
|
16372
|
+
let current = "";
|
|
16373
|
+
let quote;
|
|
16374
|
+
for (const ch of raw) {
|
|
16375
|
+
if (quote) {
|
|
16376
|
+
if (ch === quote) quote = void 0;
|
|
16377
|
+
else current += ch;
|
|
16378
|
+
continue;
|
|
16379
|
+
}
|
|
16380
|
+
if (ch === "'" || ch === '"') {
|
|
16381
|
+
quote = ch;
|
|
16382
|
+
continue;
|
|
16383
|
+
}
|
|
16384
|
+
if (ch === " " || ch === " ") {
|
|
16385
|
+
if (current.length > 0) {
|
|
16386
|
+
args.push(current);
|
|
16387
|
+
current = "";
|
|
16388
|
+
}
|
|
16389
|
+
continue;
|
|
16390
|
+
}
|
|
16391
|
+
current += ch;
|
|
16392
|
+
}
|
|
16393
|
+
if (quote) {
|
|
16394
|
+
throw new CloudTokenError("cloud_token_command_invalid", "token command has an unclosed quote");
|
|
16395
|
+
}
|
|
16396
|
+
if (current.length > 0) args.push(current);
|
|
16397
|
+
if (args.length === 0) {
|
|
16398
|
+
throw new CloudTokenError("cloud_token_command_invalid", "token command is empty");
|
|
16399
|
+
}
|
|
16400
|
+
return args;
|
|
16401
|
+
}
|
|
16402
|
+
function isCloudTokenEnvName(value) {
|
|
16403
|
+
return TOKEN_ENV_NAME.test(value);
|
|
16404
|
+
}
|
|
16405
|
+
function resolveCloudHubToken(binding, env = process.env) {
|
|
16406
|
+
if (!binding.cloud) {
|
|
16407
|
+
throw new CloudTokenError("cloud_token_missing", "cloud hub token is missing; the local hub-env token was not used");
|
|
16408
|
+
}
|
|
16409
|
+
if (binding.tokenEnv) {
|
|
16410
|
+
const value = env[binding.tokenEnv]?.trim();
|
|
16411
|
+
if (value) return value;
|
|
16412
|
+
}
|
|
16413
|
+
if (binding.tokenCommand) return runTokenCommand(binding.tokenCommand, env);
|
|
16414
|
+
const source = binding.tokenEnv ? `${binding.tokenEnv} is unset or empty` : "no token source is configured";
|
|
16415
|
+
throw new CloudTokenError(
|
|
16416
|
+
"cloud_token_missing",
|
|
16417
|
+
`cloud hub token is missing: ${source}; the local hub-env token was not used`
|
|
16418
|
+
);
|
|
16419
|
+
}
|
|
16420
|
+
function runTokenCommand(command, env) {
|
|
16421
|
+
const argv = splitTokenCommand(command);
|
|
16422
|
+
const [program, ...args] = argv;
|
|
16423
|
+
const result2 = spawnSync(program, args, {
|
|
16424
|
+
encoding: "utf8",
|
|
16425
|
+
shell: false,
|
|
16426
|
+
timeout: TOKEN_COMMAND_TIMEOUT_MS,
|
|
16427
|
+
maxBuffer: TOKEN_COMMAND_MAX_BUFFER,
|
|
16428
|
+
env,
|
|
16429
|
+
windowsHide: true
|
|
16430
|
+
});
|
|
16431
|
+
if (result2.error || result2.status !== 0) {
|
|
16432
|
+
throw new CloudTokenError(
|
|
16433
|
+
"cloud_token_command_failed",
|
|
16434
|
+
"token command failed; the local hub-env token was not used"
|
|
16435
|
+
);
|
|
16436
|
+
}
|
|
16437
|
+
const stdout = result2.stdout ?? "";
|
|
16438
|
+
if (stdout.trim().length === 0 || stdout.trim() !== stdout.trim().split(/\r?\n/)[0]) {
|
|
16439
|
+
throw new CloudTokenError(
|
|
16440
|
+
"cloud_token_command_failed",
|
|
16441
|
+
"token command did not print a single token; the local hub-env token was not used"
|
|
16442
|
+
);
|
|
16443
|
+
}
|
|
16444
|
+
return stdout.trim();
|
|
16445
|
+
}
|
|
16446
|
+
function hubBindingScope(url) {
|
|
16447
|
+
let host;
|
|
16448
|
+
try {
|
|
16449
|
+
host = new URL(url).hostname.toLowerCase();
|
|
16450
|
+
} catch {
|
|
16451
|
+
return "remote";
|
|
16452
|
+
}
|
|
16453
|
+
if (host === "localhost" || host === "::1" || host === "[::1]" || host.endsWith(".localhost")) return "loopback";
|
|
16454
|
+
const v4 = /^127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/.exec(host);
|
|
16455
|
+
return v4 && [v4[1], v4[2], v4[3]].every((part) => Number(part) <= 255) ? "loopback" : "remote";
|
|
16456
|
+
}
|
|
16194
16457
|
function isIsoTimestamp(value) {
|
|
16195
16458
|
if (Number.isNaN(Date.parse(value))) return false;
|
|
16196
16459
|
return value === new Date(value).toISOString();
|
|
@@ -16214,7 +16477,9 @@ function readHubBinding(env = process.env) {
|
|
|
16214
16477
|
}
|
|
16215
16478
|
const row = parsed;
|
|
16216
16479
|
const keys = Object.keys(row);
|
|
16217
|
-
|
|
16480
|
+
const allowed = /* @__PURE__ */ new Set(["schema", "url", "boundAt", "cloud", "tokenEnv", "tokenCommand"]);
|
|
16481
|
+
const cloudish = keys.some((key) => key === "cloud" || key === "tokenEnv" || key === "tokenCommand");
|
|
16482
|
+
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)) {
|
|
16218
16483
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
16219
16484
|
}
|
|
16220
16485
|
let url;
|
|
@@ -16223,7 +16488,34 @@ function readHubBinding(env = process.env) {
|
|
|
16223
16488
|
} catch {
|
|
16224
16489
|
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
16225
16490
|
}
|
|
16226
|
-
return { schema: HUB_BINDING_SCHEMA, url, boundAt: row.boundAt };
|
|
16491
|
+
if (!cloudish) return { schema: HUB_BINDING_SCHEMA, url, boundAt: row.boundAt };
|
|
16492
|
+
if (row.cloud !== true) throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
16493
|
+
let tokenEnv;
|
|
16494
|
+
let tokenCommand;
|
|
16495
|
+
if (row.tokenEnv !== void 0) {
|
|
16496
|
+
if (typeof row.tokenEnv !== "string" || !isCloudTokenEnvName(row.tokenEnv)) {
|
|
16497
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
16498
|
+
}
|
|
16499
|
+
tokenEnv = row.tokenEnv;
|
|
16500
|
+
}
|
|
16501
|
+
if (row.tokenCommand !== void 0) {
|
|
16502
|
+
if (typeof row.tokenCommand !== "string") throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
16503
|
+
try {
|
|
16504
|
+
splitTokenCommand(row.tokenCommand);
|
|
16505
|
+
} catch {
|
|
16506
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
16507
|
+
}
|
|
16508
|
+
tokenCommand = row.tokenCommand;
|
|
16509
|
+
}
|
|
16510
|
+
if (!tokenEnv && !tokenCommand) throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
16511
|
+
return {
|
|
16512
|
+
schema: HUB_BINDING_SCHEMA,
|
|
16513
|
+
url,
|
|
16514
|
+
boundAt: row.boundAt,
|
|
16515
|
+
cloud: true,
|
|
16516
|
+
...tokenEnv ? { tokenEnv } : {},
|
|
16517
|
+
...tokenCommand ? { tokenCommand } : {}
|
|
16518
|
+
};
|
|
16227
16519
|
}
|
|
16228
16520
|
async function probeHubHealth(url, fetchImpl, timeoutMs = HUB_HEALTH_PROBE_MS) {
|
|
16229
16521
|
const started = Date.now();
|
|
@@ -16249,11 +16541,207 @@ async function probeHubHealth(url, fetchImpl, timeoutMs = HUB_HEALTH_PROBE_MS) {
|
|
|
16249
16541
|
}
|
|
16250
16542
|
}
|
|
16251
16543
|
|
|
16544
|
+
// plugins/kxm/src/hub-identity.ts
|
|
16545
|
+
var import_yaml2 = __toESM(require_dist(), 1);
|
|
16546
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
16547
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
16548
|
+
import { basename, dirname as dirname4, join as join4, resolve as resolve4 } from "node:path";
|
|
16549
|
+
var OP_TIMEOUT_MS = 15e3;
|
|
16550
|
+
var OP_MAX_BUFFER = 4096;
|
|
16551
|
+
function normalizeUrl(raw) {
|
|
16552
|
+
try {
|
|
16553
|
+
return validateHubUrl(raw);
|
|
16554
|
+
} catch {
|
|
16555
|
+
return void 0;
|
|
16556
|
+
}
|
|
16557
|
+
}
|
|
16558
|
+
function projectYamlId(start) {
|
|
16559
|
+
let dir = resolve4(start);
|
|
16560
|
+
for (; ; ) {
|
|
16561
|
+
const file = join4(dir, ".kxm", "project.yaml");
|
|
16562
|
+
if (existsSync4(file)) {
|
|
16563
|
+
try {
|
|
16564
|
+
const doc = (0, import_yaml2.parse)(readFileSync4(file, "utf8"));
|
|
16565
|
+
if (doc && typeof doc === "object" && !Array.isArray(doc) && typeof doc.id === "string" && doc.id.trim()) {
|
|
16566
|
+
return doc.id.trim();
|
|
16567
|
+
}
|
|
16568
|
+
} catch {
|
|
16569
|
+
}
|
|
16570
|
+
return void 0;
|
|
16571
|
+
}
|
|
16572
|
+
const parent = dirname4(dir);
|
|
16573
|
+
if (parent === dir) return void 0;
|
|
16574
|
+
dir = parent;
|
|
16575
|
+
}
|
|
16576
|
+
}
|
|
16577
|
+
function packageName(cwd) {
|
|
16578
|
+
try {
|
|
16579
|
+
const pkg = JSON.parse(readFileSync4(join4(cwd, "package.json"), "utf8"));
|
|
16580
|
+
if (typeof pkg.name === "string" && pkg.name.trim().length > 0) return pkg.name.trim();
|
|
16581
|
+
} catch {
|
|
16582
|
+
}
|
|
16583
|
+
return void 0;
|
|
16584
|
+
}
|
|
16585
|
+
function activeBinding(env) {
|
|
16586
|
+
try {
|
|
16587
|
+
return readHubBinding(env);
|
|
16588
|
+
} catch (error2) {
|
|
16589
|
+
if (error2 instanceof HubBindingError) return void 0;
|
|
16590
|
+
throw error2;
|
|
16591
|
+
}
|
|
16592
|
+
}
|
|
16593
|
+
function endpointFor(mode, settings) {
|
|
16594
|
+
return mode === "cloud" ? settings.cloud : settings.local;
|
|
16595
|
+
}
|
|
16596
|
+
function resolveProjectIdentity(cwd, env = process.env, explicit) {
|
|
16597
|
+
const fromExplicit = explicit?.trim();
|
|
16598
|
+
if (fromExplicit) return { project: fromExplicit, source: "flag", sourceLabel: "--project" };
|
|
16599
|
+
const fromEnv = env.KXM_PROJECT?.trim();
|
|
16600
|
+
if (fromEnv) return { project: fromEnv, source: "env", sourceLabel: "KXM_PROJECT" };
|
|
16601
|
+
const settings = loadHubSettings(cwd, env);
|
|
16602
|
+
const mode = settings.mode ?? (activeBinding(env)?.cloud ? "cloud" : "local");
|
|
16603
|
+
const fromConfig = endpointFor(mode, settings)?.project?.trim();
|
|
16604
|
+
if (fromConfig) {
|
|
16605
|
+
return { project: fromConfig, source: "config", sourceLabel: `.kxm/config.yaml hub.${mode}.project` };
|
|
16606
|
+
}
|
|
16607
|
+
const fromProject = projectYamlId(cwd);
|
|
16608
|
+
if (fromProject) return { project: fromProject, source: "project.yaml", sourceLabel: ".kxm/project.yaml id" };
|
|
16609
|
+
const fromPackage = packageName(cwd);
|
|
16610
|
+
if (fromPackage) return { project: fromPackage, source: "package.json", sourceLabel: "package.json name" };
|
|
16611
|
+
return { project: basename(cwd), source: "directory", sourceLabel: "directory name" };
|
|
16612
|
+
}
|
|
16613
|
+
function opReferenceFromTokenCommand(command) {
|
|
16614
|
+
try {
|
|
16615
|
+
const args = splitTokenCommand(command);
|
|
16616
|
+
if (args[0] === "op" && args[1] === "read" && args[2] && isHubOpReference(args[2])) return args[2];
|
|
16617
|
+
} catch {
|
|
16618
|
+
return void 0;
|
|
16619
|
+
}
|
|
16620
|
+
return void 0;
|
|
16621
|
+
}
|
|
16622
|
+
function defaultOpRead(reference, env) {
|
|
16623
|
+
if (!isHubOpReference(reference)) {
|
|
16624
|
+
throw new CloudTokenError("cloud_token_command_invalid", `refusing to resolve ${reference}; an op:// reference is required`);
|
|
16625
|
+
}
|
|
16626
|
+
const result2 = spawnSync2("op", ["read", reference], {
|
|
16627
|
+
encoding: "utf8",
|
|
16628
|
+
shell: false,
|
|
16629
|
+
timeout: OP_TIMEOUT_MS,
|
|
16630
|
+
maxBuffer: OP_MAX_BUFFER,
|
|
16631
|
+
env,
|
|
16632
|
+
windowsHide: true
|
|
16633
|
+
});
|
|
16634
|
+
if (result2.error || result2.status !== 0) {
|
|
16635
|
+
throw new CloudTokenError(
|
|
16636
|
+
"cloud_token_command_failed",
|
|
16637
|
+
`op read failed for ${reference}; the token was not saved`
|
|
16638
|
+
);
|
|
16639
|
+
}
|
|
16640
|
+
const line = (result2.stdout ?? "").trim();
|
|
16641
|
+
if (!line || line.split(/\r?\n/).length !== 1) {
|
|
16642
|
+
throw new CloudTokenError(
|
|
16643
|
+
"cloud_token_command_failed",
|
|
16644
|
+
`op read did not print a single token for ${reference}; the token was not saved`
|
|
16645
|
+
);
|
|
16646
|
+
}
|
|
16647
|
+
return line;
|
|
16648
|
+
}
|
|
16649
|
+
function resolveKeyReference(ref, env, opRead = defaultOpRead) {
|
|
16650
|
+
if (!ref) return void 0;
|
|
16651
|
+
if (ref.env) {
|
|
16652
|
+
const value = env[ref.env]?.trim();
|
|
16653
|
+
if (value) return { value, source: `env:${ref.env}` };
|
|
16654
|
+
}
|
|
16655
|
+
if (ref.op) {
|
|
16656
|
+
const value = opRead(ref.op, env).trim();
|
|
16657
|
+
if (!value || value.split(/\r?\n/).length !== 1) {
|
|
16658
|
+
throw new CloudTokenError("cloud_token_command_failed", `op read did not print a single token for ${ref.op}`);
|
|
16659
|
+
}
|
|
16660
|
+
return { value, source: `op:${ref.op}` };
|
|
16661
|
+
}
|
|
16662
|
+
return void 0;
|
|
16663
|
+
}
|
|
16664
|
+
function keySourceFor(input) {
|
|
16665
|
+
const ref = input.endpoint?.key;
|
|
16666
|
+
if (input.mode === "local" && input.env.KXM_AUTH_TOKEN?.trim()) return "env:KXM_AUTH_TOKEN";
|
|
16667
|
+
if (ref?.env && input.env[ref.env]?.trim()) return `env:${ref.env}`;
|
|
16668
|
+
if (ref?.op) return `op:${ref.op}`;
|
|
16669
|
+
if (ref?.env) return `env:${ref.env}`;
|
|
16670
|
+
if (input.mode === "cloud") {
|
|
16671
|
+
if (input.binding?.tokenEnv) return `env:${input.binding.tokenEnv}`;
|
|
16672
|
+
if (input.binding?.tokenCommand) {
|
|
16673
|
+
const op = opReferenceFromTokenCommand(input.binding.tokenCommand);
|
|
16674
|
+
return op ? `op:${op}` : "command";
|
|
16675
|
+
}
|
|
16676
|
+
return "missing";
|
|
16677
|
+
}
|
|
16678
|
+
if (input.hasSavedProjectToken?.(input.project)) return "hub-env";
|
|
16679
|
+
return "missing";
|
|
16680
|
+
}
|
|
16681
|
+
function describeHubConnection(cwd, env = process.env, hooks = {}) {
|
|
16682
|
+
const settings = loadHubSettings(cwd, env);
|
|
16683
|
+
const binding = activeBinding(env);
|
|
16684
|
+
const mode = settings.mode ?? (binding?.cloud ? "cloud" : "local");
|
|
16685
|
+
const modeSource = settings.mode ? "config" : binding?.cloud ? "binding" : "default";
|
|
16686
|
+
const endpoint = endpointFor(mode, settings);
|
|
16687
|
+
const fromEnv = env.KXM_SERVER_URL?.trim();
|
|
16688
|
+
const fromConfig = endpoint?.url?.trim();
|
|
16689
|
+
const fromBinding = binding?.url;
|
|
16690
|
+
let url = "http://127.0.0.1:7331";
|
|
16691
|
+
let urlSource = "default";
|
|
16692
|
+
if (fromEnv) {
|
|
16693
|
+
url = fromEnv.replace(/\/$/, "");
|
|
16694
|
+
urlSource = "env";
|
|
16695
|
+
} else if (fromConfig) {
|
|
16696
|
+
url = fromConfig.replace(/\/$/, "");
|
|
16697
|
+
urlSource = "config";
|
|
16698
|
+
} else if (fromBinding) {
|
|
16699
|
+
url = fromBinding;
|
|
16700
|
+
urlSource = "binding";
|
|
16701
|
+
}
|
|
16702
|
+
const identity = resolveProjectIdentity(cwd, env, hooks.explicitProject);
|
|
16703
|
+
const configuredCloudUrl = settings.cloud?.url ?? (binding?.cloud ? binding.url : void 0);
|
|
16704
|
+
let scope;
|
|
16705
|
+
if (mode === "cloud") {
|
|
16706
|
+
const override = fromEnv ? normalizeUrl(fromEnv) : void 0;
|
|
16707
|
+
const named = configuredCloudUrl ? normalizeUrl(configuredCloudUrl) : void 0;
|
|
16708
|
+
scope = override && named && override !== named ? hubBindingScope(url) : "remote";
|
|
16709
|
+
} else {
|
|
16710
|
+
scope = hubBindingScope(url);
|
|
16711
|
+
}
|
|
16712
|
+
return {
|
|
16713
|
+
...identity,
|
|
16714
|
+
mode,
|
|
16715
|
+
modeSource,
|
|
16716
|
+
url,
|
|
16717
|
+
urlSource,
|
|
16718
|
+
scope,
|
|
16719
|
+
...endpoint ? { endpoint } : {},
|
|
16720
|
+
...binding ? { binding } : {},
|
|
16721
|
+
keySource: keySourceFor({
|
|
16722
|
+
mode,
|
|
16723
|
+
env,
|
|
16724
|
+
...endpoint ? { endpoint } : {},
|
|
16725
|
+
...binding ? { binding } : {},
|
|
16726
|
+
project: identity.project,
|
|
16727
|
+
...hooks.hasSavedProjectToken ? { hasSavedProjectToken: hooks.hasSavedProjectToken } : {}
|
|
16728
|
+
})
|
|
16729
|
+
};
|
|
16730
|
+
}
|
|
16731
|
+
function projectTokenMissingMessage(identity) {
|
|
16732
|
+
return [
|
|
16733
|
+
`kxm has no project token for project ${identity.project} (from ${identity.sourceLabel}).`,
|
|
16734
|
+
`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.`,
|
|
16735
|
+
"KXM_PROJECT or --project overrides the id for one command.",
|
|
16736
|
+
"An agent never uses the hub admin token."
|
|
16737
|
+
].join(" ");
|
|
16738
|
+
}
|
|
16739
|
+
|
|
16252
16740
|
// plugins/kxm/src/hub-env.ts
|
|
16253
|
-
import { existsSync as
|
|
16741
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
16254
16742
|
import { homedir as homedir4 } from "node:os";
|
|
16255
16743
|
import { randomBytes } from "node:crypto";
|
|
16256
|
-
import { dirname as
|
|
16744
|
+
import { dirname as dirname5, isAbsolute as isAbsolute2, join as join5, resolve as resolve5 } from "node:path";
|
|
16257
16745
|
var HUB_ENV_SCHEMA = "kxm.hub-env.v1";
|
|
16258
16746
|
var HubEnvError = class extends Error {
|
|
16259
16747
|
constructor(message) {
|
|
@@ -16265,30 +16753,30 @@ function resolveUserStateRoot2(env) {
|
|
|
16265
16753
|
const explicit = env.KXM_STATE_HOME?.trim();
|
|
16266
16754
|
if (explicit) {
|
|
16267
16755
|
if (!isAbsolute2(explicit)) throw new HubEnvError("local_state_root_not_absolute");
|
|
16268
|
-
return
|
|
16756
|
+
return resolve5(explicit);
|
|
16269
16757
|
}
|
|
16270
16758
|
if (process.platform === "win32") {
|
|
16271
16759
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
16272
|
-
const base2 = localAppData && isAbsolute2(localAppData) ? localAppData :
|
|
16273
|
-
return
|
|
16760
|
+
const base2 = localAppData && isAbsolute2(localAppData) ? localAppData : join5(homedir4(), "AppData", "Local");
|
|
16761
|
+
return resolve5(base2, "KXM");
|
|
16274
16762
|
}
|
|
16275
|
-
if (process.platform === "darwin") return
|
|
16763
|
+
if (process.platform === "darwin") return resolve5(homedir4(), "Library", "Application Support", "KXM");
|
|
16276
16764
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
16277
|
-
const base = xdgState && isAbsolute2(xdgState) ? xdgState :
|
|
16278
|
-
return
|
|
16765
|
+
const base = xdgState && isAbsolute2(xdgState) ? xdgState : join5(homedir4(), ".local", "state");
|
|
16766
|
+
return resolve5(base, "kxm");
|
|
16279
16767
|
}
|
|
16280
16768
|
function hubEnvFile(env = process.env) {
|
|
16281
|
-
return
|
|
16769
|
+
return join5(resolveUserStateRoot2(env), "hub-env.json");
|
|
16282
16770
|
}
|
|
16283
16771
|
function generateHubAuthToken() {
|
|
16284
16772
|
return `kxm_admin_${randomBytes(24).toString("base64url")}`;
|
|
16285
16773
|
}
|
|
16286
16774
|
function readHubEnvRecord(env = process.env) {
|
|
16287
16775
|
const file = hubEnvFile(env);
|
|
16288
|
-
if (!
|
|
16776
|
+
if (!existsSync5(file)) return void 0;
|
|
16289
16777
|
let parsed;
|
|
16290
16778
|
try {
|
|
16291
|
-
parsed = JSON.parse(
|
|
16779
|
+
parsed = JSON.parse(readFileSync5(file, "utf8"));
|
|
16292
16780
|
} catch (error2) {
|
|
16293
16781
|
throw new HubEnvError(`hub env file is malformed at ${file}: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
16294
16782
|
}
|
|
@@ -16322,9 +16810,9 @@ function readHubEnvRecord(env = process.env) {
|
|
|
16322
16810
|
}
|
|
16323
16811
|
function writeHubEnvRecord(record2, env = process.env) {
|
|
16324
16812
|
const file = hubEnvFile(env);
|
|
16325
|
-
const directory =
|
|
16813
|
+
const directory = dirname5(file);
|
|
16326
16814
|
mkdirSync4(directory, { recursive: true });
|
|
16327
|
-
const temporary =
|
|
16815
|
+
const temporary = join5(directory, `.hub-env-${process.pid}.tmp`);
|
|
16328
16816
|
writeFileSync4(temporary, `${JSON.stringify(record2, void 0, 2)}
|
|
16329
16817
|
`, { encoding: "utf8", mode: 384 });
|
|
16330
16818
|
try {
|
|
@@ -16393,9 +16881,24 @@ function resolveHubCredentials(options = {}) {
|
|
|
16393
16881
|
written: needsPersist === true
|
|
16394
16882
|
};
|
|
16395
16883
|
}
|
|
16396
|
-
function
|
|
16884
|
+
function cloudModeToken(cwd, env, explicitProject, opRead) {
|
|
16885
|
+
const connection = describeHubConnection(cwd, env, explicitProject === void 0 ? {} : { explicitProject });
|
|
16886
|
+
if (connection.mode !== "cloud") return void 0;
|
|
16887
|
+
const fromConfig = resolveKeyReference(connection.endpoint?.key, env, opRead);
|
|
16888
|
+
if (fromConfig) return fromConfig.value;
|
|
16889
|
+
if (connection.binding?.cloud) return resolveCloudHubToken(connection.binding, env);
|
|
16890
|
+
throw new CloudTokenError(
|
|
16891
|
+
"cloud_token_missing",
|
|
16892
|
+
"cloud hub token is missing; the local hub-env token was not used"
|
|
16893
|
+
);
|
|
16894
|
+
}
|
|
16895
|
+
function resolveAgentHubAuthToken(env, project, cwd = process.cwd(), opRead) {
|
|
16896
|
+
const cloud = cloudModeToken(cwd, env, void 0, opRead);
|
|
16897
|
+
if (cloud) return cloud;
|
|
16397
16898
|
const envToken = env.KXM_AUTH_TOKEN?.trim();
|
|
16398
16899
|
if (envToken) return envToken;
|
|
16900
|
+
const fromConfig = resolveKeyReference(describeHubConnection(cwd, env).endpoint?.key, env, opRead);
|
|
16901
|
+
if (fromConfig) return fromConfig.value;
|
|
16399
16902
|
const tokens = readHubEnvRecord(env)?.projectTokens;
|
|
16400
16903
|
if (!tokens || !Object.hasOwn(tokens, project)) return void 0;
|
|
16401
16904
|
return tokens[project]?.trim() || void 0;
|
|
@@ -16403,26 +16906,30 @@ function resolveAgentHubAuthToken(env, project) {
|
|
|
16403
16906
|
var AgentProjectTokenMissingError = class extends Error {
|
|
16404
16907
|
code = "project_token_missing";
|
|
16405
16908
|
project;
|
|
16406
|
-
|
|
16407
|
-
|
|
16408
|
-
|
|
16409
|
-
|
|
16909
|
+
projectSource;
|
|
16910
|
+
hint;
|
|
16911
|
+
constructor(projectOrIdentity) {
|
|
16912
|
+
const identity = typeof projectOrIdentity === "string" ? { project: projectOrIdentity, source: "env", sourceLabel: "the project id sent to the hub" } : projectOrIdentity;
|
|
16913
|
+
const message = projectTokenMissingMessage(identity);
|
|
16914
|
+
super(message);
|
|
16410
16915
|
this.name = "AgentProjectTokenMissingError";
|
|
16411
|
-
this.project = project;
|
|
16916
|
+
this.project = identity.project;
|
|
16917
|
+
this.projectSource = typeof projectOrIdentity === "string" ? "unknown" : identity.source;
|
|
16918
|
+
this.hint = message;
|
|
16412
16919
|
}
|
|
16413
16920
|
};
|
|
16414
16921
|
|
|
16415
16922
|
// plugins/kxm/src/repo-root.ts
|
|
16416
|
-
import { existsSync as
|
|
16417
|
-
import { dirname as
|
|
16923
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
16924
|
+
import { dirname as dirname6, join as join6 } from "node:path";
|
|
16418
16925
|
import { fileURLToPath } from "node:url";
|
|
16419
16926
|
var ROOT_MARKERS = ["scripts/kxm-hub.mjs", "scripts/kxm.mjs"];
|
|
16420
16927
|
var MAX_WALK_DEPTH = 10;
|
|
16421
16928
|
function tryFindKxmRepoRoot(fromUrl = import.meta.url) {
|
|
16422
|
-
let dir =
|
|
16929
|
+
let dir = dirname6(fileURLToPath(fromUrl));
|
|
16423
16930
|
for (let depth = 0; depth < MAX_WALK_DEPTH; depth += 1) {
|
|
16424
|
-
if (ROOT_MARKERS.some((marker) =>
|
|
16425
|
-
const parent =
|
|
16931
|
+
if (ROOT_MARKERS.some((marker) => existsSync6(join6(dir, marker)))) return dir;
|
|
16932
|
+
const parent = dirname6(dir);
|
|
16426
16933
|
if (parent === dir) break;
|
|
16427
16934
|
dir = parent;
|
|
16428
16935
|
}
|
|
@@ -16455,7 +16962,7 @@ function defaultProcessExists(pid) {
|
|
|
16455
16962
|
function readLiveHubClaim(stateDir, processExists2 = defaultProcessExists) {
|
|
16456
16963
|
let parsed;
|
|
16457
16964
|
try {
|
|
16458
|
-
parsed = JSON.parse(
|
|
16965
|
+
parsed = JSON.parse(readFileSync6(join7(stateDir, "hub.pid"), "utf8"));
|
|
16459
16966
|
} catch {
|
|
16460
16967
|
return void 0;
|
|
16461
16968
|
}
|
|
@@ -16470,7 +16977,7 @@ function readLiveHubClaim(stateDir, processExists2 = defaultProcessExists) {
|
|
|
16470
16977
|
};
|
|
16471
16978
|
}
|
|
16472
16979
|
function defaultHubWrapperScriptPath(moduleUrl = import.meta.url) {
|
|
16473
|
-
return
|
|
16980
|
+
return join7(findKxmRepoRoot(moduleUrl), "scripts", "kxm-hub.mjs");
|
|
16474
16981
|
}
|
|
16475
16982
|
function defaultHubSpawner(command, args, options) {
|
|
16476
16983
|
const child = spawn(command, [...args], options);
|
|
@@ -16479,7 +16986,7 @@ function defaultHubSpawner(command, args, options) {
|
|
|
16479
16986
|
}
|
|
16480
16987
|
function logTail(logPath, maxChars = 2e3) {
|
|
16481
16988
|
try {
|
|
16482
|
-
return redactSecrets(
|
|
16989
|
+
return redactSecrets(readFileSync6(logPath, "utf8").trim().slice(-maxChars));
|
|
16483
16990
|
} catch {
|
|
16484
16991
|
return "";
|
|
16485
16992
|
}
|
|
@@ -16492,11 +16999,28 @@ async function ensureHubRunning(options) {
|
|
|
16492
16999
|
if (binding) {
|
|
16493
17000
|
const { health } = await probeHubHealth(binding.url, fetchImpl);
|
|
16494
17001
|
if (health === "on") return { status: "bound-healthy", url: binding.url };
|
|
17002
|
+
if (binding.cloud) return { status: "failed", reason: "cloud_hub_unreachable", logPath: "" };
|
|
17003
|
+
}
|
|
17004
|
+
if (!binding?.cloud) {
|
|
17005
|
+
try {
|
|
17006
|
+
const connection = describeHubConnection(options.cwd, env);
|
|
17007
|
+
if (connection.mode === "cloud") {
|
|
17008
|
+
const { health } = await probeHubHealth(connection.url, fetchImpl);
|
|
17009
|
+
if (health === "on") return { status: "bound-healthy", url: connection.url };
|
|
17010
|
+
return { status: "failed", reason: "cloud_hub_unreachable", logPath: "" };
|
|
17011
|
+
}
|
|
17012
|
+
} catch (error2) {
|
|
17013
|
+
return {
|
|
17014
|
+
status: "failed",
|
|
17015
|
+
reason: error2 instanceof Error ? error2.message : "hub_config_invalid",
|
|
17016
|
+
logPath: ""
|
|
17017
|
+
};
|
|
17018
|
+
}
|
|
16495
17019
|
}
|
|
16496
|
-
const workdir =
|
|
16497
|
-
const workspaceDir =
|
|
16498
|
-
const stateDir =
|
|
16499
|
-
const logsDir =
|
|
17020
|
+
const workdir = resolve6(env.KXM_WORKDIR?.trim() || options.cwd);
|
|
17021
|
+
const workspaceDir = resolve6(workdir, env.KXM_WORKSPACE_DIR?.trim() || ".kxm");
|
|
17022
|
+
const stateDir = resolve6(workdir, env.KXM_STATE_DIR?.trim() || join7(workspaceDir, "state"));
|
|
17023
|
+
const logsDir = resolve6(workdir, env.KXM_LOGS_DIR?.trim() || join7(workspaceDir, "logs"));
|
|
16500
17024
|
const processExists2 = options.processExists ?? defaultProcessExists;
|
|
16501
17025
|
const live = readLiveHubClaim(stateDir, processExists2);
|
|
16502
17026
|
if (live) return { status: "claim-alive", pid: live.pid };
|
|
@@ -16506,7 +17030,7 @@ async function ensureHubRunning(options) {
|
|
|
16506
17030
|
if (health === "on") return { status: "url-healthy", url: serverUrl };
|
|
16507
17031
|
}
|
|
16508
17032
|
const credentials = resolveHubCredentials({ env });
|
|
16509
|
-
const logPath =
|
|
17033
|
+
const logPath = join7(logsDir, HUB_AUTOSTART_LOG_NAME);
|
|
16510
17034
|
mkdirSync5(logsDir, { recursive: true });
|
|
16511
17035
|
const logFd = openSync(logPath, "a");
|
|
16512
17036
|
let child;
|
|
@@ -16553,20 +17077,6 @@ async function ensureHubRunning(options) {
|
|
|
16553
17077
|
}
|
|
16554
17078
|
}
|
|
16555
17079
|
|
|
16556
|
-
// plugins/kxm/src/project-name.ts
|
|
16557
|
-
import { readFileSync as readFileSync6 } from "node:fs";
|
|
16558
|
-
import { basename, join as join7 } from "node:path";
|
|
16559
|
-
function defaultProjectName(cwd, env = process.env) {
|
|
16560
|
-
const fromEnv = env.KXM_PROJECT?.trim();
|
|
16561
|
-
if (fromEnv) return fromEnv;
|
|
16562
|
-
try {
|
|
16563
|
-
const pkg = JSON.parse(readFileSync6(join7(cwd, "package.json"), "utf8"));
|
|
16564
|
-
if (typeof pkg.name === "string" && pkg.name.trim().length > 0) return pkg.name.trim();
|
|
16565
|
-
} catch {
|
|
16566
|
-
}
|
|
16567
|
-
return basename(cwd);
|
|
16568
|
-
}
|
|
16569
|
-
|
|
16570
17080
|
// plugins/kxm/src/nous-pi.ts
|
|
16571
17081
|
import { readFile } from "node:fs/promises";
|
|
16572
17082
|
|
|
@@ -18437,7 +18947,7 @@ function closeServerGracefully(server) {
|
|
|
18437
18947
|
server.close();
|
|
18438
18948
|
}
|
|
18439
18949
|
function startCallbackServer(expectedState) {
|
|
18440
|
-
return new Promise((
|
|
18950
|
+
return new Promise((resolve9, reject) => {
|
|
18441
18951
|
let settled = false;
|
|
18442
18952
|
let timeout;
|
|
18443
18953
|
let resolveCode;
|
|
@@ -18516,7 +19026,7 @@ function startCallbackServer(expectedState) {
|
|
|
18516
19026
|
finish(() => rejectCode(new Error("OAuth callback timed out waiting for browser login")));
|
|
18517
19027
|
close();
|
|
18518
19028
|
}, OAUTH_CALLBACK_TIMEOUT_MS);
|
|
18519
|
-
|
|
19029
|
+
resolve9({ server, waitForCode: () => codePromise, cleanup });
|
|
18520
19030
|
});
|
|
18521
19031
|
});
|
|
18522
19032
|
}
|
|
@@ -19135,8 +19645,8 @@ var AssistantMessageEventStream = class {
|
|
|
19135
19645
|
finalResultPromise;
|
|
19136
19646
|
resolveFinalResult;
|
|
19137
19647
|
constructor() {
|
|
19138
|
-
this.finalResultPromise = new Promise((
|
|
19139
|
-
this.resolveFinalResult =
|
|
19648
|
+
this.finalResultPromise = new Promise((resolve9) => {
|
|
19649
|
+
this.resolveFinalResult = resolve9;
|
|
19140
19650
|
});
|
|
19141
19651
|
}
|
|
19142
19652
|
push(event) {
|
|
@@ -19166,8 +19676,8 @@ var AssistantMessageEventStream = class {
|
|
|
19166
19676
|
} else if (this.done) {
|
|
19167
19677
|
return;
|
|
19168
19678
|
} else {
|
|
19169
|
-
const next = await new Promise((
|
|
19170
|
-
this.waiting.push(
|
|
19679
|
+
const next = await new Promise((resolve9) => {
|
|
19680
|
+
this.waiting.push(resolve9);
|
|
19171
19681
|
});
|
|
19172
19682
|
if (next.done) return;
|
|
19173
19683
|
if (next.value) yield next.value;
|
|
@@ -20486,8 +20996,8 @@ var AssistantMessageEventStream2 = class {
|
|
|
20486
20996
|
finalResultPromise;
|
|
20487
20997
|
resolveFinalResult;
|
|
20488
20998
|
constructor() {
|
|
20489
|
-
this.finalResultPromise = new Promise((
|
|
20490
|
-
this.resolveFinalResult =
|
|
20999
|
+
this.finalResultPromise = new Promise((resolve9) => {
|
|
21000
|
+
this.resolveFinalResult = resolve9;
|
|
20491
21001
|
});
|
|
20492
21002
|
}
|
|
20493
21003
|
push(event) {
|
|
@@ -20517,8 +21027,8 @@ var AssistantMessageEventStream2 = class {
|
|
|
20517
21027
|
} else if (this.done) {
|
|
20518
21028
|
return;
|
|
20519
21029
|
} else {
|
|
20520
|
-
const next = await new Promise((
|
|
20521
|
-
this.waiting.push(
|
|
21030
|
+
const next = await new Promise((resolve9) => {
|
|
21031
|
+
this.waiting.push(resolve9);
|
|
20522
21032
|
});
|
|
20523
21033
|
if (next.done) return;
|
|
20524
21034
|
if (next.value) yield next.value;
|
|
@@ -20544,11 +21054,11 @@ function emptyUsage() {
|
|
|
20544
21054
|
}
|
|
20545
21055
|
|
|
20546
21056
|
// plugins/kxm/src/providers/claude-bridge/config.ts
|
|
20547
|
-
import { existsSync as
|
|
21057
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
|
|
20548
21058
|
import { homedir as homedir5 } from "node:os";
|
|
20549
21059
|
import { join as join8 } from "node:path";
|
|
20550
21060
|
function tryParseJson(path) {
|
|
20551
|
-
if (!
|
|
21061
|
+
if (!existsSync7(path)) return {};
|
|
20552
21062
|
try {
|
|
20553
21063
|
return JSON.parse(readFileSync7(path, "utf-8"));
|
|
20554
21064
|
} catch (error2) {
|
|
@@ -33576,7 +34086,7 @@ var Protocol = class {
|
|
|
33576
34086
|
return;
|
|
33577
34087
|
}
|
|
33578
34088
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
33579
|
-
await new Promise((
|
|
34089
|
+
await new Promise((resolve9) => setTimeout(resolve9, pollInterval));
|
|
33580
34090
|
options?.signal?.throwIfAborted();
|
|
33581
34091
|
}
|
|
33582
34092
|
} catch (error2) {
|
|
@@ -33593,7 +34103,7 @@ var Protocol = class {
|
|
|
33593
34103
|
*/
|
|
33594
34104
|
request(request, resultSchema, options) {
|
|
33595
34105
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
33596
|
-
return new Promise((
|
|
34106
|
+
return new Promise((resolve9, reject) => {
|
|
33597
34107
|
const earlyReject = (error2) => {
|
|
33598
34108
|
reject(error2);
|
|
33599
34109
|
};
|
|
@@ -33671,7 +34181,7 @@ var Protocol = class {
|
|
|
33671
34181
|
if (!parseResult.success) {
|
|
33672
34182
|
reject(parseResult.error);
|
|
33673
34183
|
} else {
|
|
33674
|
-
|
|
34184
|
+
resolve9(parseResult.data);
|
|
33675
34185
|
}
|
|
33676
34186
|
} catch (error2) {
|
|
33677
34187
|
reject(error2);
|
|
@@ -33932,12 +34442,12 @@ var Protocol = class {
|
|
|
33932
34442
|
}
|
|
33933
34443
|
} catch {
|
|
33934
34444
|
}
|
|
33935
|
-
return new Promise((
|
|
34445
|
+
return new Promise((resolve9, reject) => {
|
|
33936
34446
|
if (signal.aborted) {
|
|
33937
34447
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
33938
34448
|
return;
|
|
33939
34449
|
}
|
|
33940
|
-
const timeoutId = setTimeout(
|
|
34450
|
+
const timeoutId = setTimeout(resolve9, interval);
|
|
33941
34451
|
signal.addEventListener("abort", () => {
|
|
33942
34452
|
clearTimeout(timeoutId);
|
|
33943
34453
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -35028,7 +35538,7 @@ var McpServer = class {
|
|
|
35028
35538
|
let task = createTaskResult.task;
|
|
35029
35539
|
const pollInterval = task.pollInterval ?? 5e3;
|
|
35030
35540
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
35031
|
-
await new Promise((
|
|
35541
|
+
await new Promise((resolve9) => setTimeout(resolve9, pollInterval));
|
|
35032
35542
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
35033
35543
|
if (!updatedTask) {
|
|
35034
35544
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -35646,8 +36156,8 @@ function makePromptStream() {
|
|
|
35646
36156
|
try {
|
|
35647
36157
|
while (true) {
|
|
35648
36158
|
while (queue.length === 0 && !done && !failure) {
|
|
35649
|
-
await new Promise((
|
|
35650
|
-
wake =
|
|
36159
|
+
await new Promise((resolve9) => {
|
|
36160
|
+
wake = resolve9;
|
|
35651
36161
|
});
|
|
35652
36162
|
}
|
|
35653
36163
|
if (failure) throw failure;
|
|
@@ -35668,8 +36178,8 @@ function makePromptStream() {
|
|
|
35668
36178
|
}
|
|
35669
36179
|
return {
|
|
35670
36180
|
stream: gen(),
|
|
35671
|
-
push: (msg) => failure || done ? Promise.reject(failure ?? new Error("prompt stream closed")) : new Promise((
|
|
35672
|
-
queue.push({ msg, resolve:
|
|
36181
|
+
push: (msg) => failure || done ? Promise.reject(failure ?? new Error("prompt stream closed")) : new Promise((resolve9, reject) => {
|
|
36182
|
+
queue.push({ msg, resolve: resolve9, reject });
|
|
35673
36183
|
kick();
|
|
35674
36184
|
}),
|
|
35675
36185
|
end: () => {
|
|
@@ -36080,8 +36590,8 @@ function buildMcpServers(tools, queryCtx) {
|
|
|
36080
36590
|
queryCtx.pendingResults.delete(toolCallId);
|
|
36081
36591
|
return result2;
|
|
36082
36592
|
}
|
|
36083
|
-
return new Promise((
|
|
36084
|
-
queryCtx.pendingToolCalls.set(toolCallId, { toolName: tool.name, resolve:
|
|
36593
|
+
return new Promise((resolve9) => {
|
|
36594
|
+
queryCtx.pendingToolCalls.set(toolCallId, { toolName: tool.name, resolve: resolve9 });
|
|
36085
36595
|
});
|
|
36086
36596
|
}
|
|
36087
36597
|
}));
|
|
@@ -36601,20 +37111,20 @@ async function consumeWorkerRecoveryEnvelope(client, stateDir, agentName, projec
|
|
|
36601
37111
|
}
|
|
36602
37112
|
|
|
36603
37113
|
// plugins/kxm/src/session-work.ts
|
|
36604
|
-
import { spawnSync } from "node:child_process";
|
|
37114
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
36605
37115
|
import { randomUUID } from "node:crypto";
|
|
36606
|
-
import { existsSync as
|
|
37116
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync12, renameSync as renameSync4, writeFileSync as writeFileSync6 } from "node:fs";
|
|
36607
37117
|
import { join as join13 } from "node:path";
|
|
36608
37118
|
|
|
36609
37119
|
// plugins/kxm/src/local-snapshot.ts
|
|
36610
|
-
import { existsSync as
|
|
37120
|
+
import { existsSync as existsSync9, readdirSync, readFileSync as readFileSync10 } from "node:fs";
|
|
36611
37121
|
import { homedir as homedir6 } from "node:os";
|
|
36612
|
-
import { isAbsolute as isAbsolute3, join as join11, resolve as
|
|
37122
|
+
import { isAbsolute as isAbsolute3, join as join11, resolve as resolve8 } from "node:path";
|
|
36613
37123
|
|
|
36614
37124
|
// plugins/kxm/src/sqlite.ts
|
|
36615
|
-
import { existsSync as
|
|
37125
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
36616
37126
|
import { createRequire as createRequire2 } from "node:module";
|
|
36617
|
-
import { resolve as
|
|
37127
|
+
import { resolve as resolve7 } from "node:path";
|
|
36618
37128
|
import { pathToFileURL } from "node:url";
|
|
36619
37129
|
var requireFromHere = createRequire2(import.meta.url);
|
|
36620
37130
|
function loadNative() {
|
|
@@ -36653,15 +37163,15 @@ var DatabaseSync = class {
|
|
|
36653
37163
|
}
|
|
36654
37164
|
};
|
|
36655
37165
|
function openReadOnlyDatabase(path) {
|
|
36656
|
-
if (
|
|
36657
|
-
const uri = pathToFileURL(
|
|
37166
|
+
if (existsSync8(`${path}-wal`)) return new DatabaseSync(path, { readOnly: true });
|
|
37167
|
+
const uri = pathToFileURL(resolve7(path));
|
|
36658
37168
|
uri.searchParams.set("immutable", "1");
|
|
36659
37169
|
return new DatabaseSync(uri.href, { readOnly: true });
|
|
36660
37170
|
}
|
|
36661
37171
|
|
|
36662
37172
|
// plugins/kxm/src/telemetry.ts
|
|
36663
37173
|
import { appendFileSync, mkdirSync as mkdirSync6, readFileSync as readFileSync9 } from "node:fs";
|
|
36664
|
-
import { dirname as
|
|
37174
|
+
import { dirname as dirname7, join as join10 } from "node:path";
|
|
36665
37175
|
function telemetryPath(logsDir) {
|
|
36666
37176
|
return join10(logsDir, "telemetry.jsonl");
|
|
36667
37177
|
}
|
|
@@ -36825,34 +37335,34 @@ function readOpenMessageMetadata(database, where = OPEN_MESSAGE_WHERE, params =
|
|
|
36825
37335
|
function resolveKxmSnapshotPaths(cwd, env = process.env) {
|
|
36826
37336
|
const stateDir = env.KXM_STATE_DIR?.trim() || join11(cwd, ".kxm", "state");
|
|
36827
37337
|
const configured = env.KXM_DATA_PATH?.trim();
|
|
36828
|
-
const dataPath = configured ?
|
|
37338
|
+
const dataPath = configured ? resolve8(cwd, configured) : join11(stateDir, "kxm.db");
|
|
36829
37339
|
return { dataPath, stateDir };
|
|
36830
37340
|
}
|
|
36831
37341
|
function resolveKxmStateRoot(stateDir, options) {
|
|
36832
|
-
if (options?.kxmStateRoot &&
|
|
36833
|
-
return
|
|
37342
|
+
if (options?.kxmStateRoot && existsSync9(options.kxmStateRoot)) {
|
|
37343
|
+
return resolve8(options.kxmStateRoot);
|
|
36834
37344
|
}
|
|
36835
|
-
if (
|
|
37345
|
+
if (existsSync9(join11(stateDir, "runtime", "registry.db")) || existsSync9(join11(stateDir, "runtime", "projects"))) {
|
|
36836
37346
|
return stateDir;
|
|
36837
37347
|
}
|
|
36838
37348
|
const env = options?.env ?? process.env;
|
|
36839
37349
|
const explicit = env.KXM_STATE_HOME?.trim() || env.KXM_USER_STATE_DIR?.trim() || env.KXM_STATE_ROOT?.trim();
|
|
36840
|
-
if (explicit && isAbsolute3(explicit) &&
|
|
36841
|
-
return
|
|
37350
|
+
if (explicit && isAbsolute3(explicit) && existsSync9(resolve8(explicit))) {
|
|
37351
|
+
return resolve8(explicit);
|
|
36842
37352
|
}
|
|
36843
37353
|
let base;
|
|
36844
37354
|
if (process.platform === "win32") {
|
|
36845
37355
|
const localAppData = env.LOCALAPPDATA?.trim();
|
|
36846
37356
|
base = localAppData && isAbsolute3(localAppData) ? localAppData : join11(homedir6(), "AppData", "Local");
|
|
36847
|
-
base =
|
|
37357
|
+
base = resolve8(base, "KXM");
|
|
36848
37358
|
} else if (process.platform === "darwin") {
|
|
36849
|
-
base =
|
|
37359
|
+
base = resolve8(homedir6(), "Library", "Application Support", "KXM");
|
|
36850
37360
|
} else {
|
|
36851
37361
|
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
36852
37362
|
base = xdgState && isAbsolute3(xdgState) ? xdgState : join11(homedir6(), ".local", "state");
|
|
36853
|
-
base =
|
|
37363
|
+
base = resolve8(base, "kxm");
|
|
36854
37364
|
}
|
|
36855
|
-
if (
|
|
37365
|
+
if (existsSync9(base)) return base;
|
|
36856
37366
|
return void 0;
|
|
36857
37367
|
}
|
|
36858
37368
|
function readRuntimeRuns(eventDb, projectId) {
|
|
@@ -36885,7 +37395,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
36885
37395
|
let legacyRuns = [];
|
|
36886
37396
|
let legacyRunTotal = 0;
|
|
36887
37397
|
let plans = [];
|
|
36888
|
-
if (
|
|
37398
|
+
if (existsSync9(dataPath)) {
|
|
36889
37399
|
hasLegacy = true;
|
|
36890
37400
|
const database = openReadOnlyDatabase(dataPath);
|
|
36891
37401
|
try {
|
|
@@ -36920,7 +37430,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
36920
37430
|
const registryDbPath = join11(runtimeDir, "registry.db");
|
|
36921
37431
|
const projectsDir = join11(runtimeDir, "projects");
|
|
36922
37432
|
const projectKeys = /* @__PURE__ */ new Set();
|
|
36923
|
-
if (
|
|
37433
|
+
if (existsSync9(registryDbPath)) {
|
|
36924
37434
|
hasKxm = true;
|
|
36925
37435
|
try {
|
|
36926
37436
|
const regDb = openReadOnlyDatabase(registryDbPath);
|
|
@@ -36936,7 +37446,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
36936
37446
|
} catch {
|
|
36937
37447
|
}
|
|
36938
37448
|
}
|
|
36939
|
-
if (!scope &&
|
|
37449
|
+
if (!scope && existsSync9(projectsDir)) {
|
|
36940
37450
|
try {
|
|
36941
37451
|
for (const entry of readdirSync(projectsDir, { withFileTypes: true })) {
|
|
36942
37452
|
if (entry.isDirectory()) {
|
|
@@ -36949,7 +37459,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
36949
37459
|
for (const key of projectKeys) {
|
|
36950
37460
|
if (scope && !RUNTIME_PROJECT_KEY.test(key)) continue;
|
|
36951
37461
|
const eventDbPath = join11(projectsDir, key, "run-events.db");
|
|
36952
|
-
if (
|
|
37462
|
+
if (existsSync9(eventDbPath)) {
|
|
36953
37463
|
hasKxm = true;
|
|
36954
37464
|
try {
|
|
36955
37465
|
const eventDb = openReadOnlyDatabase(eventDbPath);
|
|
@@ -36967,7 +37477,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
36967
37477
|
}
|
|
36968
37478
|
}
|
|
36969
37479
|
const pids = [];
|
|
36970
|
-
if (
|
|
37480
|
+
if (existsSync9(stateDir)) {
|
|
36971
37481
|
for (const file of readdirSync(stateDir).filter((name) => name.endsWith(".pid"))) {
|
|
36972
37482
|
try {
|
|
36973
37483
|
const record2 = JSON.parse(readFileSync10(join11(stateDir, file), "utf8"));
|
|
@@ -37010,7 +37520,7 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
37010
37520
|
source = "legacy";
|
|
37011
37521
|
}
|
|
37012
37522
|
const telemetryFile = join11(stateDir, "telemetry.jsonl");
|
|
37013
|
-
const spend =
|
|
37523
|
+
const spend = existsSync9(telemetryFile) ? readRoutingRecords(telemetryFile) : [];
|
|
37014
37524
|
return {
|
|
37015
37525
|
source,
|
|
37016
37526
|
agents: agents.sort((a, b) => Number(b.online) - Number(a.online) || a.name.localeCompare(b.name)),
|
|
@@ -37025,13 +37535,13 @@ function loadLocalMeshSnapshot(dataPath, stateDir, options) {
|
|
|
37025
37535
|
}
|
|
37026
37536
|
|
|
37027
37537
|
// plugins/kxm/src/kxm-update.ts
|
|
37028
|
-
import { existsSync as
|
|
37538
|
+
import { existsSync as existsSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync5, mkdirSync as mkdirSync7 } from "node:fs";
|
|
37029
37539
|
import { join as join12 } from "node:path";
|
|
37030
37540
|
var KXM_UPDATE_CACHE = "update-check.json";
|
|
37031
37541
|
var CACHE_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
37032
37542
|
function readUpdateCache(stateDir, now = Date.now()) {
|
|
37033
37543
|
const path = join12(stateDir, KXM_UPDATE_CACHE);
|
|
37034
|
-
if (!
|
|
37544
|
+
if (!existsSync10(path)) return void 0;
|
|
37035
37545
|
try {
|
|
37036
37546
|
const row = JSON.parse(readFileSync11(path, "utf8"));
|
|
37037
37547
|
if (typeof row.checkedAt !== "number" || !row.notice || now - row.checkedAt > CACHE_TTL_MS) return void 0;
|
|
@@ -37099,10 +37609,10 @@ function formatShipLine(ship) {
|
|
|
37099
37609
|
}
|
|
37100
37610
|
function readGitShip(cwd) {
|
|
37101
37611
|
try {
|
|
37102
|
-
const dirty =
|
|
37612
|
+
const dirty = spawnSync3("git", ["--no-optional-locks", "-C", cwd, "status", "--porcelain"], { encoding: "utf8", windowsHide: true });
|
|
37103
37613
|
if (dirty.status !== 0) return void 0;
|
|
37104
37614
|
const isDirty2 = dirty.stdout.trim().length > 0;
|
|
37105
|
-
const upstream =
|
|
37615
|
+
const upstream = spawnSync3("git", ["-C", cwd, "rev-list", "--count", "@{u}..HEAD"], { encoding: "utf8", windowsHide: true });
|
|
37106
37616
|
if (upstream.status === 0) {
|
|
37107
37617
|
return {
|
|
37108
37618
|
dirty: isDirty2,
|
|
@@ -37110,9 +37620,9 @@ function readGitShip(cwd) {
|
|
|
37110
37620
|
};
|
|
37111
37621
|
}
|
|
37112
37622
|
for (const baseRef of ["origin/HEAD", "main", "origin/main", "master", "origin/master"]) {
|
|
37113
|
-
const mb =
|
|
37623
|
+
const mb = spawnSync3("git", ["-C", cwd, "merge-base", baseRef, "HEAD"], { encoding: "utf8", windowsHide: true });
|
|
37114
37624
|
if (mb.status === 0 && mb.stdout.trim()) {
|
|
37115
|
-
const count =
|
|
37625
|
+
const count = spawnSync3("git", ["-C", cwd, "rev-list", "--count", `${mb.stdout.trim()}..HEAD`], { encoding: "utf8", windowsHide: true });
|
|
37116
37626
|
if (count.status === 0) {
|
|
37117
37627
|
return {
|
|
37118
37628
|
dirty: isDirty2,
|
|
@@ -37202,7 +37712,7 @@ function buildSessionBrief(snapshot, current, hub, ship, updateLatest, cost, ses
|
|
|
37202
37712
|
function readCachedSessionBrief(stateDir) {
|
|
37203
37713
|
const file = join13(stateDir, "session-brief.json");
|
|
37204
37714
|
try {
|
|
37205
|
-
if (!
|
|
37715
|
+
if (!existsSync11(file)) return void 0;
|
|
37206
37716
|
const raw = readFileSync12(file, "utf8");
|
|
37207
37717
|
const parsed = JSON.parse(raw);
|
|
37208
37718
|
if (parsed && parsed.schema === "kxm.session-brief.v1" && typeof parsed.generatedAt === "string") {
|
|
@@ -37229,7 +37739,7 @@ function writeCachedSessionBrief(stateDir, brief) {
|
|
|
37229
37739
|
function estimateSessionCost(stateDir) {
|
|
37230
37740
|
try {
|
|
37231
37741
|
const telemetryFile = join13(stateDir, "telemetry.jsonl");
|
|
37232
|
-
if (!
|
|
37742
|
+
if (!existsSync11(telemetryFile)) return void 0;
|
|
37233
37743
|
const records = readRoutingRecords(telemetryFile);
|
|
37234
37744
|
if (records.length === 0) return void 0;
|
|
37235
37745
|
let totalCost = 0;
|
|
@@ -37404,11 +37914,11 @@ function kxmSlashCompletions(prefix) {
|
|
|
37404
37914
|
}
|
|
37405
37915
|
|
|
37406
37916
|
// plugins/kxm/src/workflow-tui.ts
|
|
37407
|
-
import { existsSync as
|
|
37917
|
+
import { existsSync as existsSync12, readFileSync as readFileSync13 } from "node:fs";
|
|
37408
37918
|
import { join as join14 } from "node:path";
|
|
37409
37919
|
function loadActiveWorkflowProgress(repoRoot = process.cwd(), targetRunId) {
|
|
37410
37920
|
const dbPath = join14(repoConfigDirectory(repoRoot), "state", "kxm.db");
|
|
37411
|
-
if (!
|
|
37921
|
+
if (!existsSync12(dbPath)) return void 0;
|
|
37412
37922
|
let db;
|
|
37413
37923
|
try {
|
|
37414
37924
|
db = new DatabaseSync(dbPath, { readOnly: true });
|
|
@@ -37445,7 +37955,7 @@ function loadActiveWorkflowProgress(repoRoot = process.cwd(), targetRunId) {
|
|
|
37445
37955
|
try {
|
|
37446
37956
|
const logsDir = join14(repoConfigDirectory(repoRoot), "logs");
|
|
37447
37957
|
const telemFile = telemetryPath(logsDir);
|
|
37448
|
-
if (
|
|
37958
|
+
if (existsSync12(telemFile)) {
|
|
37449
37959
|
const records = readRoutingRecords(telemFile);
|
|
37450
37960
|
const routingRunId = (routing) => "runId" in routing ? routing.runId : routing.workflowRunId;
|
|
37451
37961
|
let matching = records.filter((r) => routingRunId(r.routing) === runId);
|
|
@@ -37737,7 +38247,7 @@ function piMeshExtension(pi) {
|
|
|
37737
38247
|
messageId: message.id,
|
|
37738
38248
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
37739
38249
|
};
|
|
37740
|
-
mkdirSync9(
|
|
38250
|
+
mkdirSync9(dirname8(path), { recursive: true });
|
|
37741
38251
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
37742
38252
|
writeFileSync7(tmp, `${JSON.stringify(request)}
|
|
37743
38253
|
`, { encoding: "utf8", mode: 384 });
|
|
@@ -37768,7 +38278,7 @@ function piMeshExtension(pi) {
|
|
|
37768
38278
|
removeMatchingLegacyRecoveryContext();
|
|
37769
38279
|
return;
|
|
37770
38280
|
}
|
|
37771
|
-
mkdirSync9(
|
|
38281
|
+
mkdirSync9(dirname8(path), { recursive: true });
|
|
37772
38282
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
37773
38283
|
writeFileSync7(tmp, `${JSON.stringify({ version: 1, agentName, project: projectName, runId: runId ?? null, stageId: recoveryStageId ?? null, activeMessageIds, pendingMessageIds, artifactPointers: recoveryArtifacts.slice(0, 16), updatedAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
37774
38284
|
`, { encoding: "utf8", mode: 384 });
|
|
@@ -37818,7 +38328,7 @@ function piMeshExtension(pi) {
|
|
|
37818
38328
|
ctx2.ui.setEditorText?.(item.prompt);
|
|
37819
38329
|
}
|
|
37820
38330
|
async function showKxmHub(ctx2) {
|
|
37821
|
-
const url = (process.
|
|
38331
|
+
const url = describeHubConnection(process.cwd(), process.env).url;
|
|
37822
38332
|
let health = "unreachable";
|
|
37823
38333
|
try {
|
|
37824
38334
|
const response = await fetch(`${url}/health`);
|
|
@@ -38108,8 +38618,9 @@ function piMeshExtension(pi) {
|
|
|
38108
38618
|
return;
|
|
38109
38619
|
}
|
|
38110
38620
|
currentPiSessionId = ctx2.sessionManager?.getSessionId();
|
|
38111
|
-
const
|
|
38112
|
-
const
|
|
38621
|
+
const identity = resolveProjectIdentity(ctx2.cwd, process.env);
|
|
38622
|
+
const serverUrl = describeHubConnection(ctx2.cwd, process.env).url;
|
|
38623
|
+
const project = identity.project;
|
|
38113
38624
|
const name = process.env.KXM_AGENT_NAME ?? pi.getSessionName() ?? `pi-${process.pid}`;
|
|
38114
38625
|
agentName = name;
|
|
38115
38626
|
projectName = project;
|
|
@@ -38135,14 +38646,15 @@ function piMeshExtension(pi) {
|
|
|
38135
38646
|
}
|
|
38136
38647
|
let hubAuthToken;
|
|
38137
38648
|
try {
|
|
38138
|
-
hubAuthToken = resolveAgentHubAuthToken(process.env, project);
|
|
38649
|
+
hubAuthToken = resolveAgentHubAuthToken(process.env, project, ctx2.cwd);
|
|
38139
38650
|
} catch (error2) {
|
|
38140
|
-
|
|
38651
|
+
const detail = error2 instanceof CloudTokenError ? error2.message : `kxm could not read persisted hub credentials: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
38652
|
+
ctx2.ui.notify(detail, "error");
|
|
38141
38653
|
await applySessionChrome(ctx2, event, true);
|
|
38142
38654
|
return;
|
|
38143
38655
|
}
|
|
38144
38656
|
if (!hubAuthToken) {
|
|
38145
|
-
ctx2.ui.notify(new AgentProjectTokenMissingError(
|
|
38657
|
+
ctx2.ui.notify(new AgentProjectTokenMissingError(identity).message, "error");
|
|
38146
38658
|
await applySessionChrome(ctx2, event, true);
|
|
38147
38659
|
return;
|
|
38148
38660
|
}
|
|
@@ -38356,12 +38868,12 @@ function piMeshExtension(pi) {
|
|
|
38356
38868
|
if (command === "memory") {
|
|
38357
38869
|
const cwd = typeof ctx2.cwd === "string" ? ctx2.cwd : process.cwd();
|
|
38358
38870
|
const kxmBin = process.env.KXM_BIN || "kxm";
|
|
38359
|
-
const res =
|
|
38871
|
+
const res = spawnSync4(kxmBin, ["memory", "brief"], { cwd, encoding: "utf8", windowsHide: true });
|
|
38360
38872
|
let memText = res.status === 0 && res.stdout ? res.stdout.trim() : "";
|
|
38361
38873
|
if (!memText) {
|
|
38362
38874
|
const script = join15(cwd, "scripts", "kxm.mjs");
|
|
38363
|
-
if (
|
|
38364
|
-
const scriptRes =
|
|
38875
|
+
if (existsSync13(script)) {
|
|
38876
|
+
const scriptRes = spawnSync4(process.execPath, [script, "memory", "brief"], { cwd, encoding: "utf8", windowsHide: true });
|
|
38365
38877
|
if (scriptRes.status === 0 && scriptRes.stdout) memText = scriptRes.stdout.trim();
|
|
38366
38878
|
}
|
|
38367
38879
|
}
|