@kontextmind/kxm 0.7.167 → 0.7.169
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 +30 -0
- package/docs/contributing/ci-and-release.md +6 -1
- package/docs/operations/runtime-sync.md +2 -1
- package/docs/operations/troubleshooting.md +4 -0
- package/docs/operations/upgrade.md +18 -3
- package/docs/operations.md +70 -7
- package/docs/reference/cli-reference.md +21 -6
- package/docs/reference/config-reference.md +28 -13
- package/docs/start/install.md +1 -1
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/claude-hook.js +170 -36
- package/plugins/kxm/dist/cli.js +451 -132
- package/plugins/kxm/dist/extension.js +184 -53
- package/plugins/kxm/dist/mcp-server.js +97 -40
- package/plugins/kxm/dist/runtime-supervisor.js +240 -47
- package/plugins/kxm/dist/runtime.js +240 -47
- package/plugins/kxm/dist/server.js +9 -0
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/kxm-definitions/SKILL.md +3 -2
- package/plugins/kxm/skills/kxm-harness-auth/SKILL.md +4 -2
- package/plugins/kxm/skills/kxm-hub-ops/SKILL.md +9 -4
- package/plugins/kxm/src/cli/hub.ts +42 -7
- package/plugins/kxm/src/cli/system.ts +3 -1
- package/plugins/kxm/src/cli/types.ts +5 -3
- package/plugins/kxm/src/cli.ts +2 -1
- package/plugins/kxm/src/engine.ts +105 -8
- package/plugins/kxm/src/hub-binding.ts +301 -55
- package/plugins/kxm/src/hub-identity.ts +17 -9
- package/plugins/kxm/src/kxm-update.ts +29 -6
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/project-config.ts +63 -1
- package/plugins/kxm/src/runtime-supervisor.ts +22 -4
- package/scripts/kxm-publish-npm.mjs +47 -1
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -9409,7 +9409,7 @@ var init_config = __esm({
|
|
|
9409
9409
|
});
|
|
9410
9410
|
|
|
9411
9411
|
// plugins/kxm/src/hub-binding.ts
|
|
9412
|
-
import { spawnSync } from "node:child_process";
|
|
9412
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
9413
9413
|
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
9414
9414
|
import { homedir as homedir2 } from "node:os";
|
|
9415
9415
|
import { dirname as dirname3, isAbsolute, join as join4, resolve as resolve2 } from "node:path";
|
|
@@ -9432,6 +9432,9 @@ function resolveUserStateRoot(env) {
|
|
|
9432
9432
|
function hubBindingFile(env = process.env) {
|
|
9433
9433
|
return join4(resolveUserStateRoot(env), "hub-binding.json");
|
|
9434
9434
|
}
|
|
9435
|
+
function hubBindingCloudFile(env = process.env) {
|
|
9436
|
+
return join4(resolveUserStateRoot(env), "hub-binding.cloud.json");
|
|
9437
|
+
}
|
|
9435
9438
|
function validateHubUrl(raw) {
|
|
9436
9439
|
let parsed;
|
|
9437
9440
|
try {
|
|
@@ -9517,7 +9520,7 @@ function resolveCloudHubToken(binding, env = process.env) {
|
|
|
9517
9520
|
function runTokenCommand(command, env) {
|
|
9518
9521
|
const argv = splitTokenCommand(command);
|
|
9519
9522
|
const [program2, ...args] = argv;
|
|
9520
|
-
const result =
|
|
9523
|
+
const result = spawnSync2(program2, args, {
|
|
9521
9524
|
encoding: "utf8",
|
|
9522
9525
|
shell: false,
|
|
9523
9526
|
timeout: TOKEN_COMMAND_TIMEOUT_MS,
|
|
@@ -9560,33 +9563,35 @@ function isAbortError(error) {
|
|
|
9560
9563
|
error && typeof error === "object" && ("name" in error && error.name === "AbortError" || "code" in error && error.code === "ABORT_ERR")
|
|
9561
9564
|
);
|
|
9562
9565
|
}
|
|
9563
|
-
function
|
|
9564
|
-
|
|
9565
|
-
|
|
9566
|
+
function bindingFallbackWarning(file, reason) {
|
|
9567
|
+
return `hub binding at ${file} ${reason}; falling back to the local hub. Restart the Runtime supervisor, the hub, and workers after upgrading and before a cloud bind.`;
|
|
9568
|
+
}
|
|
9569
|
+
function writeBindingJson(file, value) {
|
|
9570
|
+
mkdirSync3(dirname3(file), { recursive: true, mode: 448 });
|
|
9571
|
+
const temporary = join4(dirname3(file), `.${file.endsWith("cloud.json") ? "hub-binding-cloud" : "hub-binding"}-${process.pid}.tmp`);
|
|
9572
|
+
try {
|
|
9573
|
+
writeFileSync3(temporary, `${JSON.stringify(value, null, 2)}
|
|
9574
|
+
`, { encoding: "utf8", mode: 384 });
|
|
9575
|
+
renameSync(temporary, file);
|
|
9576
|
+
} finally {
|
|
9577
|
+
rmSync(temporary, { force: true });
|
|
9578
|
+
}
|
|
9579
|
+
}
|
|
9580
|
+
function parseBindingObject(file) {
|
|
9581
|
+
if (!existsSync4(file)) return new HubBindingError(`missing hub binding at ${file}`);
|
|
9566
9582
|
let parsed;
|
|
9567
9583
|
try {
|
|
9568
9584
|
parsed = JSON.parse(readFileSync3(file, "utf8"));
|
|
9569
9585
|
} catch {
|
|
9570
|
-
|
|
9586
|
+
return new HubBindingError(`malformed hub binding at ${file}`);
|
|
9571
9587
|
}
|
|
9572
9588
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
9573
|
-
|
|
9574
|
-
}
|
|
9575
|
-
const row = parsed;
|
|
9576
|
-
const keys = Object.keys(row);
|
|
9577
|
-
const allowed = /* @__PURE__ */ new Set(["schema", "url", "boundAt", "cloud", "tokenEnv", "tokenCommand"]);
|
|
9578
|
-
const cloudish = keys.some((key) => key === "cloud" || key === "tokenEnv" || key === "tokenCommand");
|
|
9579
|
-
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)) {
|
|
9580
|
-
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
9581
|
-
}
|
|
9582
|
-
let url;
|
|
9583
|
-
try {
|
|
9584
|
-
url = validateHubUrl(row.url);
|
|
9585
|
-
} catch {
|
|
9586
|
-
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
9589
|
+
return new HubBindingError(`malformed hub binding at ${file}`);
|
|
9587
9590
|
}
|
|
9588
|
-
|
|
9589
|
-
|
|
9591
|
+
return parsed;
|
|
9592
|
+
}
|
|
9593
|
+
function cloudRecordFromRow(file, row, url, boundAt) {
|
|
9594
|
+
if (row.cloud !== true) return void 0;
|
|
9590
9595
|
let tokenEnv;
|
|
9591
9596
|
let tokenCommand;
|
|
9592
9597
|
if (row.tokenEnv !== void 0) {
|
|
@@ -9608,33 +9613,203 @@ function readHubBinding(env = process.env) {
|
|
|
9608
9613
|
return {
|
|
9609
9614
|
schema: HUB_BINDING_SCHEMA,
|
|
9610
9615
|
url,
|
|
9611
|
-
boundAt
|
|
9616
|
+
boundAt,
|
|
9612
9617
|
cloud: true,
|
|
9613
9618
|
...tokenEnv ? { tokenEnv } : {},
|
|
9614
9619
|
...tokenCommand ? { tokenCommand } : {}
|
|
9615
9620
|
};
|
|
9616
9621
|
}
|
|
9617
|
-
function
|
|
9622
|
+
function readLegacyV1HubBinding(env = process.env) {
|
|
9618
9623
|
const file = hubBindingFile(env);
|
|
9619
|
-
|
|
9620
|
-
const
|
|
9624
|
+
if (!existsSync4(file)) return void 0;
|
|
9625
|
+
const parsed = parseBindingObject(file);
|
|
9626
|
+
if (parsed instanceof HubBindingError) throw parsed;
|
|
9627
|
+
const keys = Object.keys(parsed);
|
|
9628
|
+
if (keys.length !== 3 || keys.some((key) => !LEGACY_BINDING_KEYS.includes(key)) || parsed.schema !== HUB_BINDING_SCHEMA || typeof parsed.url !== "string" || typeof parsed.boundAt !== "string" || !isIsoTimestamp(parsed.boundAt)) {
|
|
9629
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
9630
|
+
}
|
|
9631
|
+
let url;
|
|
9621
9632
|
try {
|
|
9622
|
-
|
|
9623
|
-
|
|
9624
|
-
|
|
9625
|
-
}
|
|
9626
|
-
|
|
9633
|
+
url = validateHubUrl(parsed.url);
|
|
9634
|
+
} catch {
|
|
9635
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
9636
|
+
}
|
|
9637
|
+
return { schema: HUB_BINDING_SCHEMA, url, boundAt: parsed.boundAt };
|
|
9638
|
+
}
|
|
9639
|
+
function interpretBindingFile(file) {
|
|
9640
|
+
if (!existsSync4(file)) return {};
|
|
9641
|
+
const parsed = parseBindingObject(file);
|
|
9642
|
+
if (parsed instanceof HubBindingError) throw parsed;
|
|
9643
|
+
const keys = Object.keys(parsed);
|
|
9644
|
+
const unknown = keys.filter((key) => !BINDING_KEYS.has(key));
|
|
9645
|
+
if (parsed.schema !== HUB_BINDING_SCHEMA || unknown.length > 0) {
|
|
9646
|
+
return { warning: bindingFallbackWarning(file, `is newer than this build understands (${String(parsed.schema)})`) };
|
|
9647
|
+
}
|
|
9648
|
+
if (typeof parsed.url !== "string" || typeof parsed.boundAt !== "string" || !isIsoTimestamp(parsed.boundAt)) {
|
|
9649
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
9650
|
+
}
|
|
9651
|
+
let url;
|
|
9652
|
+
try {
|
|
9653
|
+
url = validateHubUrl(parsed.url);
|
|
9654
|
+
} catch {
|
|
9655
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
9656
|
+
}
|
|
9657
|
+
const cloudish = keys.some((key) => key === "cloud" || key === "tokenEnv" || key === "tokenCommand");
|
|
9658
|
+
if (!cloudish) {
|
|
9659
|
+
if (keys.length !== 3) throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
9660
|
+
return { record: { schema: HUB_BINDING_SCHEMA, url, boundAt: parsed.boundAt } };
|
|
9661
|
+
}
|
|
9662
|
+
const record = cloudRecordFromRow(file, parsed, url, parsed.boundAt);
|
|
9663
|
+
if (!record) throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
9664
|
+
return { record, legacyCloud: true };
|
|
9665
|
+
}
|
|
9666
|
+
function loadHubBinding(env = process.env) {
|
|
9667
|
+
const cloudFile = hubBindingCloudFile(env);
|
|
9668
|
+
const cloud = interpretBindingFile(cloudFile);
|
|
9669
|
+
if (cloud.warning && !cloud.record) {
|
|
9670
|
+
const local = existsSync4(hubBindingFile(env)) ? interpretBindingFile(hubBindingFile(env)) : {};
|
|
9671
|
+
if (local.record && !local.record.cloud) return { record: local.record, warning: cloud.warning };
|
|
9672
|
+
return { warning: cloud.warning };
|
|
9673
|
+
}
|
|
9674
|
+
if (cloud.record?.cloud) return { record: cloud.record, ...cloud.warning ? { warning: cloud.warning } : {} };
|
|
9675
|
+
const main = interpretBindingFile(hubBindingFile(env));
|
|
9676
|
+
if (main.legacyCloud && main.record) {
|
|
9677
|
+
writeBindingJson(cloudFile, main.record);
|
|
9678
|
+
rmSync(hubBindingFile(env), { force: true });
|
|
9679
|
+
return {
|
|
9680
|
+
record: main.record,
|
|
9681
|
+
warning: bindingFallbackWarning(
|
|
9682
|
+
hubBindingFile(env),
|
|
9683
|
+
"stored a cloud bind in the pre-0.7.160 file"
|
|
9684
|
+
)
|
|
9685
|
+
};
|
|
9627
9686
|
}
|
|
9687
|
+
return { ...main.record ? { record: main.record } : {}, ...main.warning ? { warning: main.warning } : {} };
|
|
9688
|
+
}
|
|
9689
|
+
function readHubBinding(env = process.env) {
|
|
9690
|
+
return loadHubBinding(env).record;
|
|
9691
|
+
}
|
|
9692
|
+
function writeHubBinding(record, env = process.env) {
|
|
9693
|
+
if (record.cloud) {
|
|
9694
|
+
const file2 = hubBindingCloudFile(env);
|
|
9695
|
+
writeBindingJson(file2, record);
|
|
9696
|
+
const main = hubBindingFile(env);
|
|
9697
|
+
if (existsSync4(main)) {
|
|
9698
|
+
try {
|
|
9699
|
+
const legacy = readLegacyV1HubBinding(env);
|
|
9700
|
+
if (!legacy || legacy.url === record.url) rmSync(main, { force: true });
|
|
9701
|
+
} catch (error) {
|
|
9702
|
+
if (!(error instanceof HubBindingError)) throw error;
|
|
9703
|
+
rmSync(main, { force: true });
|
|
9704
|
+
}
|
|
9705
|
+
}
|
|
9706
|
+
return file2;
|
|
9707
|
+
}
|
|
9708
|
+
rmSync(hubBindingCloudFile(env), { force: true });
|
|
9709
|
+
const file = hubBindingFile(env);
|
|
9710
|
+
writeBindingJson(file, {
|
|
9711
|
+
schema: HUB_BINDING_SCHEMA,
|
|
9712
|
+
url: record.url,
|
|
9713
|
+
boundAt: record.boundAt
|
|
9714
|
+
});
|
|
9628
9715
|
return file;
|
|
9629
9716
|
}
|
|
9630
9717
|
function removeHubBinding(env = process.env) {
|
|
9631
|
-
const
|
|
9718
|
+
const files = [hubBindingFile(env), hubBindingCloudFile(env)];
|
|
9719
|
+
let removed = false;
|
|
9720
|
+
for (const file of files) {
|
|
9721
|
+
try {
|
|
9722
|
+
rmSync(file);
|
|
9723
|
+
removed = true;
|
|
9724
|
+
} catch (error) {
|
|
9725
|
+
if (error.code !== "ENOENT") throw error;
|
|
9726
|
+
}
|
|
9727
|
+
}
|
|
9728
|
+
return removed;
|
|
9729
|
+
}
|
|
9730
|
+
function contentTypeBase(header) {
|
|
9731
|
+
return (header ?? "").split(";")[0].trim().toLowerCase();
|
|
9732
|
+
}
|
|
9733
|
+
function looksLikeHtml(contentType, body) {
|
|
9734
|
+
if (contentType === "text/html" || contentType === "application/xhtml+xml") return true;
|
|
9735
|
+
const sample = body.slice(0, 800).trim().toLowerCase();
|
|
9736
|
+
return sample.startsWith("<!doctype html") || sample.startsWith("<html") || sample.includes("<form") && (sample.includes("login") || sample.includes("authentik") || sample.includes("password"));
|
|
9737
|
+
}
|
|
9738
|
+
function jsonObject(text) {
|
|
9632
9739
|
try {
|
|
9633
|
-
|
|
9634
|
-
return
|
|
9740
|
+
const parsed = JSON.parse(text);
|
|
9741
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
9742
|
+
return parsed;
|
|
9743
|
+
} catch {
|
|
9744
|
+
return void 0;
|
|
9745
|
+
}
|
|
9746
|
+
}
|
|
9747
|
+
function hubEndpointShape(role, body) {
|
|
9748
|
+
if (role === "health") return body.ok === true && typeof body.agents === "number";
|
|
9749
|
+
return body.ok === true && (body.storage === "sqlite" || body.storage === "memory");
|
|
9750
|
+
}
|
|
9751
|
+
function classifyHubResponse(input) {
|
|
9752
|
+
const contentType = contentTypeBase(input.contentType);
|
|
9753
|
+
if (input.status >= 300 && input.status < 400) {
|
|
9754
|
+
return {
|
|
9755
|
+
ok: false,
|
|
9756
|
+
status: input.status,
|
|
9757
|
+
kind: "redirect",
|
|
9758
|
+
detail: `HTTP ${input.status} redirect; this looks like an auth proxy or a redirect, not a kxm hub`,
|
|
9759
|
+
body: { error: "auth_proxy", detail: `HTTP ${input.status} redirect` }
|
|
9760
|
+
};
|
|
9761
|
+
}
|
|
9762
|
+
if (looksLikeHtml(contentType, input.bodyText)) {
|
|
9763
|
+
return {
|
|
9764
|
+
ok: false,
|
|
9765
|
+
status: input.status,
|
|
9766
|
+
kind: "auth_proxy",
|
|
9767
|
+
detail: `HTTP ${input.status} returned an HTML login page${contentType ? ` (${contentType})` : ""}; this looks like an auth proxy, not a kxm hub`,
|
|
9768
|
+
body: { error: "auth_proxy", detail: "HTML login page" }
|
|
9769
|
+
};
|
|
9770
|
+
}
|
|
9771
|
+
const jsonType = contentType === "application/json" || contentType === "text/plain" || contentType === "";
|
|
9772
|
+
const body = jsonType ? jsonObject(input.bodyText) : void 0;
|
|
9773
|
+
if (body && hubEndpointShape(input.role, body) && input.status >= 200 && input.status < 300) {
|
|
9774
|
+
if (contentType !== "" && contentType !== "application/json" && contentType !== "text/plain") {
|
|
9775
|
+
return {
|
|
9776
|
+
ok: false,
|
|
9777
|
+
status: input.status,
|
|
9778
|
+
kind: "not_hub",
|
|
9779
|
+
detail: `HTTP ${input.status} content-type ${contentType} is not application/json`,
|
|
9780
|
+
body: { error: "not_hub", detail: contentType }
|
|
9781
|
+
};
|
|
9782
|
+
}
|
|
9783
|
+
return { ok: true, status: input.status, kind: "hub", detail: "kxm hub", body };
|
|
9784
|
+
}
|
|
9785
|
+
const typeNote = contentType && contentType !== "application/json" ? ` content-type ${contentType}` : "";
|
|
9786
|
+
return {
|
|
9787
|
+
ok: false,
|
|
9788
|
+
status: input.status,
|
|
9789
|
+
kind: "not_hub",
|
|
9790
|
+
detail: `HTTP ${input.status}${typeNote} is not a kxm hub ${input.role} response`,
|
|
9791
|
+
body: { error: "not_hub", detail: `HTTP ${input.status}${typeNote}` }
|
|
9792
|
+
};
|
|
9793
|
+
}
|
|
9794
|
+
async function readHubEndpoint(url, role, fetchImpl, init = {}) {
|
|
9795
|
+
try {
|
|
9796
|
+
const response = await fetchImpl(`${url}/${role}`, {
|
|
9797
|
+
...init.headers ? { headers: init.headers } : {},
|
|
9798
|
+
...init.signal ? { signal: init.signal } : {},
|
|
9799
|
+
redirect: "manual"
|
|
9800
|
+
});
|
|
9801
|
+
const bodyText = await response.text();
|
|
9802
|
+
return classifyHubResponse({
|
|
9803
|
+
role,
|
|
9804
|
+
status: response.status,
|
|
9805
|
+
contentType: response.headers.get("content-type"),
|
|
9806
|
+
bodyText
|
|
9807
|
+
});
|
|
9635
9808
|
} catch (error) {
|
|
9636
|
-
if (error
|
|
9637
|
-
|
|
9809
|
+
if (isAbortError(error)) {
|
|
9810
|
+
return { ok: false, status: 0, kind: "timeout", detail: "no reply within the probe budget", body: { error: "hub_unreachable" } };
|
|
9811
|
+
}
|
|
9812
|
+
return { ok: false, status: 0, kind: "unreachable", detail: "nothing answered", body: { error: "hub_unreachable" } };
|
|
9638
9813
|
}
|
|
9639
9814
|
}
|
|
9640
9815
|
async function probeHubHealth(url, fetchImpl, timeoutMs = HUB_HEALTH_PROBE_MS) {
|
|
@@ -9642,25 +9817,14 @@ async function probeHubHealth(url, fetchImpl, timeoutMs = HUB_HEALTH_PROBE_MS) {
|
|
|
9642
9817
|
const controller = new AbortController();
|
|
9643
9818
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
9644
9819
|
try {
|
|
9645
|
-
const
|
|
9646
|
-
|
|
9647
|
-
|
|
9648
|
-
try {
|
|
9649
|
-
body = await response.json();
|
|
9650
|
-
} catch {
|
|
9651
|
-
return { health: "unknown", probeMs: Date.now() - started };
|
|
9652
|
-
}
|
|
9653
|
-
if (body && typeof body === "object" && body.ok === true) {
|
|
9654
|
-
return { health: "on", probeMs: Date.now() - started };
|
|
9655
|
-
}
|
|
9656
|
-
return { health: "unknown", probeMs: Date.now() - started };
|
|
9657
|
-
} catch (error) {
|
|
9658
|
-
return { health: isAbortError(error) ? "unknown" : "off", probeMs: Date.now() - started };
|
|
9820
|
+
const verdict = await readHubEndpoint(url, "health", fetchImpl, { signal: controller.signal });
|
|
9821
|
+
const health = verdict.kind === "hub" ? "on" : verdict.kind === "unreachable" ? "off" : "unknown";
|
|
9822
|
+
return { health, probeMs: Date.now() - started, kind: verdict.kind, detail: verdict.detail, status: verdict.status };
|
|
9659
9823
|
} finally {
|
|
9660
9824
|
clearTimeout(timer);
|
|
9661
9825
|
}
|
|
9662
9826
|
}
|
|
9663
|
-
var HUB_BINDING_SCHEMA, HUB_HEALTH_PROBE_MS, CloudTokenError, TOKEN_ENV_NAME, TOKEN_COMMAND_TIMEOUT_MS, TOKEN_COMMAND_MAX_BUFFER, HubBindingError;
|
|
9827
|
+
var HUB_BINDING_SCHEMA, HUB_HEALTH_PROBE_MS, CloudTokenError, TOKEN_ENV_NAME, TOKEN_COMMAND_TIMEOUT_MS, TOKEN_COMMAND_MAX_BUFFER, HubBindingError, LEGACY_BINDING_KEYS, BINDING_KEYS;
|
|
9664
9828
|
var init_hub_binding = __esm({
|
|
9665
9829
|
"plugins/kxm/src/hub-binding.ts"() {
|
|
9666
9830
|
"use strict";
|
|
@@ -9683,11 +9847,13 @@ var init_hub_binding = __esm({
|
|
|
9683
9847
|
this.name = "HubBindingError";
|
|
9684
9848
|
}
|
|
9685
9849
|
};
|
|
9850
|
+
LEGACY_BINDING_KEYS = ["schema", "url", "boundAt"];
|
|
9851
|
+
BINDING_KEYS = /* @__PURE__ */ new Set([...LEGACY_BINDING_KEYS, "cloud", "tokenEnv", "tokenCommand"]);
|
|
9686
9852
|
}
|
|
9687
9853
|
});
|
|
9688
9854
|
|
|
9689
9855
|
// plugins/kxm/src/hub-identity.ts
|
|
9690
|
-
import { spawnSync as
|
|
9856
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
9691
9857
|
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "node:fs";
|
|
9692
9858
|
import { basename, dirname as dirname4, join as join5, resolve as resolve3 } from "node:path";
|
|
9693
9859
|
function normalizeUrl(raw) {
|
|
@@ -9768,7 +9934,7 @@ function defaultOpRead(reference, env) {
|
|
|
9768
9934
|
if (!isHubOpReference(reference)) {
|
|
9769
9935
|
throw new CloudTokenError("cloud_token_command_invalid", `refusing to resolve ${reference}; an op:// reference is required`);
|
|
9770
9936
|
}
|
|
9771
|
-
const result =
|
|
9937
|
+
const result = spawnSync3("op", ["read", reference], {
|
|
9772
9938
|
encoding: "utf8",
|
|
9773
9939
|
shell: false,
|
|
9774
9940
|
timeout: OP_TIMEOUT_MS,
|
|
@@ -9808,18 +9974,24 @@ function resolveKeyReference(ref, env, opRead = defaultOpRead) {
|
|
|
9808
9974
|
}
|
|
9809
9975
|
function keySourceFor(input) {
|
|
9810
9976
|
const ref = input.endpoint?.key;
|
|
9811
|
-
|
|
9812
|
-
|
|
9813
|
-
|
|
9814
|
-
|
|
9977
|
+
const envName = (name) => {
|
|
9978
|
+
if (!name) return void 0;
|
|
9979
|
+
return input.env[name]?.trim() ? `env:${name}` : void 0;
|
|
9980
|
+
};
|
|
9815
9981
|
if (input.mode === "cloud") {
|
|
9816
|
-
|
|
9817
|
-
if (
|
|
9818
|
-
|
|
9819
|
-
|
|
9820
|
-
|
|
9982
|
+
const fromEnv2 = envName(ref?.env);
|
|
9983
|
+
if (fromEnv2) return fromEnv2;
|
|
9984
|
+
if (ref?.op) return `op:${ref.op}`;
|
|
9985
|
+
const fromBindingEnv = envName(input.binding?.tokenEnv);
|
|
9986
|
+
if (fromBindingEnv) return fromBindingEnv;
|
|
9987
|
+
if (input.binding?.tokenCommand) return "token-command";
|
|
9821
9988
|
return "missing";
|
|
9822
9989
|
}
|
|
9990
|
+
const fromAuth = envName("KXM_AUTH_TOKEN");
|
|
9991
|
+
if (fromAuth) return fromAuth;
|
|
9992
|
+
const fromEnv = envName(ref?.env);
|
|
9993
|
+
if (fromEnv) return fromEnv;
|
|
9994
|
+
if (ref?.op) return `op:${ref.op}`;
|
|
9823
9995
|
if (input.hasSavedProjectToken?.(input.project)) return "hub-env";
|
|
9824
9996
|
return "missing";
|
|
9825
9997
|
}
|
|
@@ -18919,7 +19091,7 @@ var init_oneshot_process = __esm({
|
|
|
18919
19091
|
});
|
|
18920
19092
|
|
|
18921
19093
|
// plugins/kxm/src/harness.ts
|
|
18922
|
-
import { spawnSync as
|
|
19094
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
18923
19095
|
import { existsSync as existsSync9 } from "node:fs";
|
|
18924
19096
|
import { win32 as win32Path } from "node:path";
|
|
18925
19097
|
function reportedModelId(value) {
|
|
@@ -19208,7 +19380,7 @@ function findWinNpmInnerExe(cliId, options = {}) {
|
|
|
19208
19380
|
function defaultRunner(env) {
|
|
19209
19381
|
return (command, args, timeoutMs) => {
|
|
19210
19382
|
try {
|
|
19211
|
-
const result =
|
|
19383
|
+
const result = spawnSync4(command, [...args], {
|
|
19212
19384
|
encoding: "utf8",
|
|
19213
19385
|
timeout: timeoutMs,
|
|
19214
19386
|
windowsHide: true,
|
|
@@ -19942,7 +20114,7 @@ var init_harness = __esm({
|
|
|
19942
20114
|
});
|
|
19943
20115
|
|
|
19944
20116
|
// plugins/kxm/src/project-config.ts
|
|
19945
|
-
import { spawnSync as
|
|
20117
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
19946
20118
|
import { createHash as createHash7 } from "node:crypto";
|
|
19947
20119
|
import { existsSync as existsSync10, lstatSync, readFileSync as readFileSync8, readdirSync as readdirSync2, realpathSync } from "node:fs";
|
|
19948
20120
|
import { basename as basename2, dirname as dirname7, extname, isAbsolute as isAbsolute3, join as join9, relative, resolve as resolve6, sep } from "node:path";
|
|
@@ -19950,6 +20122,21 @@ import { pathToFileURL } from "node:url";
|
|
|
19950
20122
|
function defaultKxmSchemaDir() {
|
|
19951
20123
|
return join9(findKxmRepoRoot(import.meta.url), "schemas");
|
|
19952
20124
|
}
|
|
20125
|
+
function toolPresetProfile(preset) {
|
|
20126
|
+
if (!Object.hasOwn(TOOL_PRESET_PROFILES, preset)) return void 0;
|
|
20127
|
+
return TOOL_PRESET_PROFILES[preset];
|
|
20128
|
+
}
|
|
20129
|
+
function toolPresetExceedsRoleMessage(preset, roleId, rolePermission, rolePreset) {
|
|
20130
|
+
const profile = toolPresetProfile(preset);
|
|
20131
|
+
if (profile !== "edit") return void 0;
|
|
20132
|
+
if (rolePermission === "read-only") {
|
|
20133
|
+
return `tools.preset ${preset} exceeds role ${roleId} permission read-only`;
|
|
20134
|
+
}
|
|
20135
|
+
if (rolePreset !== void 0 && toolPresetProfile(rolePreset) === "read-only") {
|
|
20136
|
+
return `tools.preset ${preset} exceeds role ${roleId} preset ${rolePreset}`;
|
|
20137
|
+
}
|
|
20138
|
+
return void 0;
|
|
20139
|
+
}
|
|
19953
20140
|
function compareCodeUnits4(left, right) {
|
|
19954
20141
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
19955
20142
|
}
|
|
@@ -20235,6 +20422,15 @@ function objectValue(value) {
|
|
|
20235
20422
|
function stringValue(value) {
|
|
20236
20423
|
return typeof value === "string" ? value : void 0;
|
|
20237
20424
|
}
|
|
20425
|
+
function roleById(roles, roleId) {
|
|
20426
|
+
const direct = roles.get(roleId);
|
|
20427
|
+
if (direct) return direct;
|
|
20428
|
+
const folded = roleId.toLocaleLowerCase("en-US");
|
|
20429
|
+
for (const role of roles.values()) {
|
|
20430
|
+
if ((role.id ?? "").toLocaleLowerCase("en-US") === folded) return role;
|
|
20431
|
+
}
|
|
20432
|
+
return void 0;
|
|
20433
|
+
}
|
|
20238
20434
|
function numberValue(value, fallback) {
|
|
20239
20435
|
return typeof value === "number" ? value : fallback;
|
|
20240
20436
|
}
|
|
@@ -20745,10 +20941,29 @@ function validateBundle(project, repositories, agents, models, workflows, enviro
|
|
|
20745
20941
|
if (executor && !executors.has(executor)) issues.push(issue3("reference", "executor_unknown", agent.logicalPath, `executor ${executor} is not registered`));
|
|
20746
20942
|
const preset = stringValue(objectValue(agent.value.tools)?.preset);
|
|
20747
20943
|
if (preset && !presets.has(preset)) issues.push(issue3("reference", "tool_preset_unknown", agent.logicalPath, `tool preset ${preset} is not registered`));
|
|
20944
|
+
const roleId = stringValue(agent.value.role);
|
|
20945
|
+
const role = roleId ? roleById(roles, roleId) : void 0;
|
|
20946
|
+
const rolePermission = stringValue(role?.value.permission);
|
|
20947
|
+
if (preset && role && (rolePermission === "edit" || rolePermission === "read-only")) {
|
|
20948
|
+
const message = toolPresetExceedsRoleMessage(
|
|
20949
|
+
preset,
|
|
20950
|
+
role.id ?? roleId ?? "role",
|
|
20951
|
+
rolePermission,
|
|
20952
|
+
stringValue(objectValue(role.value.tools)?.preset)
|
|
20953
|
+
);
|
|
20954
|
+
if (message) issues.push(issue3("semantic", "tool_preset_exceeds_role", agent.logicalPath, message));
|
|
20955
|
+
}
|
|
20748
20956
|
for (const repositoryId of Object.keys(objectValue(agent.value.repositories) ?? {})) {
|
|
20749
20957
|
if (!repositoryIds.has(repositoryId)) issues.push(issue3("reference", "repository_unknown", agent.logicalPath, `references unknown repository ${repositoryId}`));
|
|
20750
20958
|
}
|
|
20751
20959
|
}
|
|
20960
|
+
for (const role of roles.values()) {
|
|
20961
|
+
const permission = stringValue(role.value.permission);
|
|
20962
|
+
const rolePreset = stringValue(objectValue(role.value.tools)?.preset);
|
|
20963
|
+
if (permission === "read-only" && rolePreset && toolPresetProfile(rolePreset) === "edit") {
|
|
20964
|
+
issues.push(issue3("semantic", "tool_preset_exceeds_role", role.logicalPath, `tools.preset ${rolePreset} exceeds permission read-only`));
|
|
20965
|
+
}
|
|
20966
|
+
}
|
|
20752
20967
|
validateModelReferences(models, issues);
|
|
20753
20968
|
const defaultWorkflow = stringValue(project.value.defaultWorkflow) ?? "default";
|
|
20754
20969
|
if (!lookupKxmResource(workflows.values(), defaultWorkflow, "workflow")) issues.push(issue3("reference", "default_workflow_unknown", project.logicalPath, `default workflow ${defaultWorkflow} does not exist`));
|
|
@@ -20821,7 +21036,7 @@ function developerCeilings() {
|
|
|
20821
21036
|
const script = join9(findKxmRepoRoot(import.meta.url), "scripts", "harness-run.mjs");
|
|
20822
21037
|
let loaded;
|
|
20823
21038
|
try {
|
|
20824
|
-
loaded =
|
|
21039
|
+
loaded = spawnSync5(process.execPath, ["--input-type=module", "-e", `const m = await import(${JSON.stringify(pathToFileURL(script).href)}); process.stdout.write(JSON.stringify({ROUTES:m.ROUTES,NATIVE_PI_BRAKE_PROVIDERS:m.NATIVE_PI_BRAKE_PROVIDERS,PI_ALLOWED_PROVIDERS:m.PI_ALLOWED_PROVIDERS,PI_NATIVE_VENDOR_PROVIDERS:m.PI_NATIVE_VENDOR_PROVIDERS}))`], {
|
|
20825
21040
|
encoding: "utf8",
|
|
20826
21041
|
timeout: 15e3
|
|
20827
21042
|
});
|
|
@@ -20917,7 +21132,7 @@ function gitEnvironment() {
|
|
|
20917
21132
|
function discoverGitRoot(start = process.cwd()) {
|
|
20918
21133
|
let current = resolve6(start);
|
|
20919
21134
|
if (existsSync10(current) && !lstatSync(current).isDirectory()) current = dirname7(current);
|
|
20920
|
-
const result =
|
|
21135
|
+
const result = spawnSync5("git", ["-C", current, "rev-parse", "--show-toplevel"], {
|
|
20921
21136
|
encoding: "utf8",
|
|
20922
21137
|
env: gitEnvironment(),
|
|
20923
21138
|
timeout: 5e3,
|
|
@@ -21226,7 +21441,7 @@ function planKxmInitialization(start = process.cwd(), options = {}) {
|
|
|
21226
21441
|
}
|
|
21227
21442
|
return { mode: "create", inspectedFrom, projectRoot: candidateRoot, changesRequired: true, issues: [], legacyInputs: [] };
|
|
21228
21443
|
}
|
|
21229
|
-
var import__, KxmConfigError, DEFAULT_SCHEMA_DIR, RESOURCE_SCHEMA, IDENTIFIER2, WINDOWS_RESERVED, BUILTIN_EXECUTORS, BUILTIN_TOOL_PRESETS, SECRET_VALUE_PATTERNS, KxmSchemaRegistry, cachedRunEventRegistry, GATE_STEP_OUTCOMES, LEGACY_CONFIG_FILES;
|
|
21444
|
+
var import__, KxmConfigError, DEFAULT_SCHEMA_DIR, RESOURCE_SCHEMA, IDENTIFIER2, WINDOWS_RESERVED, BUILTIN_EXECUTORS, TOOL_PRESET_PROFILES, BUILTIN_TOOL_PRESETS, SECRET_VALUE_PATTERNS, KxmSchemaRegistry, cachedRunEventRegistry, GATE_STEP_OUTCOMES, LEGACY_CONFIG_FILES;
|
|
21230
21445
|
var init_project_config = __esm({
|
|
21231
21446
|
"plugins/kxm/src/project-config.ts"() {
|
|
21232
21447
|
"use strict";
|
|
@@ -21260,7 +21475,13 @@ var init_project_config = __esm({
|
|
|
21260
21475
|
IDENTIFIER2 = /^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/;
|
|
21261
21476
|
WINDOWS_RESERVED = /^(?:con|prn|aux|nul|com[1-9¹²³]|lpt[1-9¹²³]|conin\$|conout\$|clock\$)$/i;
|
|
21262
21477
|
BUILTIN_EXECUTORS = ["local", "ssh", "exe-dev"];
|
|
21263
|
-
|
|
21478
|
+
TOOL_PRESET_PROFILES = Object.freeze({
|
|
21479
|
+
coordinator: "read-only",
|
|
21480
|
+
"read-only": "read-only",
|
|
21481
|
+
"workspace-writer": "edit",
|
|
21482
|
+
"tests-writer": "edit"
|
|
21483
|
+
});
|
|
21484
|
+
BUILTIN_TOOL_PRESETS = Object.keys(TOOL_PRESET_PROFILES);
|
|
21264
21485
|
SECRET_VALUE_PATTERNS = [
|
|
21265
21486
|
/-----BEGIN (?:[A-Z ]+ )?PRIVATE KEY-----/,
|
|
21266
21487
|
/\b(?:ghp|github_pat)_[A-Za-z0-9_]{20,}\b/,
|
|
@@ -21437,7 +21658,7 @@ var init_sqlite = __esm({
|
|
|
21437
21658
|
});
|
|
21438
21659
|
|
|
21439
21660
|
// plugins/kxm/src/bindings.ts
|
|
21440
|
-
import { spawnSync as
|
|
21661
|
+
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
21441
21662
|
import { createHash as createHash8, randomUUID as randomUUID3 } from "node:crypto";
|
|
21442
21663
|
import {
|
|
21443
21664
|
chmodSync as chmodSync2,
|
|
@@ -21639,7 +21860,7 @@ function projectOperationLockFile(projectRoot) {
|
|
|
21639
21860
|
for (const key of Object.keys(env)) {
|
|
21640
21861
|
if (key.toLocaleUpperCase("en-US").startsWith("GIT_")) delete env[key];
|
|
21641
21862
|
}
|
|
21642
|
-
const result =
|
|
21863
|
+
const result = spawnSync6("git", ["-C", projectRoot, "rev-parse", "--absolute-git-dir"], {
|
|
21643
21864
|
encoding: "utf8",
|
|
21644
21865
|
env,
|
|
21645
21866
|
timeout: 5e3,
|
|
@@ -22816,7 +23037,7 @@ var init_database = __esm({
|
|
|
22816
23037
|
});
|
|
22817
23038
|
|
|
22818
23039
|
// plugins/kxm/src/runtime-store.ts
|
|
22819
|
-
import { spawnSync as
|
|
23040
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
22820
23041
|
import { createHash as createHash12, randomUUID as randomUUID4 } from "node:crypto";
|
|
22821
23042
|
import { existsSync as existsSync14, lstatSync as lstatSync4, mkdirSync as mkdirSync8, readFileSync as readFileSync11, realpathSync as realpathSync4, statSync, writeFileSync as writeFileSync8 } from "node:fs";
|
|
22822
23043
|
import { dirname as dirname10, isAbsolute as isAbsolute6, resolve as resolve11 } from "node:path";
|
|
@@ -22856,7 +23077,7 @@ function gitEnv() {
|
|
|
22856
23077
|
return Object.fromEntries(Object.entries(process.env).filter(([name]) => !name.toUpperCase().startsWith("GIT_")));
|
|
22857
23078
|
}
|
|
22858
23079
|
function gitCommonDirectory(projectRoot) {
|
|
22859
|
-
const result =
|
|
23080
|
+
const result = spawnSync7("git", ["-C", projectRoot, "rev-parse", "--git-common-dir"], {
|
|
22860
23081
|
encoding: "utf8",
|
|
22861
23082
|
env: gitEnv(),
|
|
22862
23083
|
timeout: 3e4,
|
|
@@ -27537,6 +27758,68 @@ function unsupportedAgentStepTimeout(step, limitMs) {
|
|
|
27537
27758
|
detail: "step timeoutMs is wider than project limits.agentStepTimeoutMs"
|
|
27538
27759
|
};
|
|
27539
27760
|
}
|
|
27761
|
+
function narrowerPermission(left, right) {
|
|
27762
|
+
return left === "read-only" || right === "read-only" ? "read-only" : "edit";
|
|
27763
|
+
}
|
|
27764
|
+
function stepRepositoryPermission(step) {
|
|
27765
|
+
return Object.values(step.repositories).some((access) => access === "write") ? "edit" : "read-only";
|
|
27766
|
+
}
|
|
27767
|
+
function stepAccessDetail(step) {
|
|
27768
|
+
const entries = Object.entries(step.repositories);
|
|
27769
|
+
if (entries.length === 0) return "none";
|
|
27770
|
+
return entries.map(([id, access]) => `${id} ${access}`).sort((left, right) => left < right ? -1 : left > right ? 1 : 0).join(", ");
|
|
27771
|
+
}
|
|
27772
|
+
function yamlToolsPreset(doc) {
|
|
27773
|
+
const tools = doc?.tools;
|
|
27774
|
+
if (!tools || typeof tools !== "object" || Array.isArray(tools)) return void 0;
|
|
27775
|
+
const preset = tools.preset;
|
|
27776
|
+
return typeof preset === "string" && preset.length > 0 ? preset : void 0;
|
|
27777
|
+
}
|
|
27778
|
+
function resolveToolDispatch(projectRoot, step, agentId) {
|
|
27779
|
+
const stepPermission = stepRepositoryPermission(step);
|
|
27780
|
+
if (step.kind !== "agent" && step.kind !== "moa") return { permission: stepPermission };
|
|
27781
|
+
const agentFile = findYamlBasename(join19(projectRoot, ".kxm", "agents"), agentId, "agent") ?? agentId;
|
|
27782
|
+
const agent = readYamlFile(join19(projectRoot, ".kxm", "agents", `${agentFile}.yaml`));
|
|
27783
|
+
const roleId = typeof agent?.role === "string" ? agent.role : "";
|
|
27784
|
+
if (!roleId) return { permission: stepPermission };
|
|
27785
|
+
const roleDoc = readYamlFile(join19(projectRoot, ".kxm", "roles", `${roleId}.yaml`));
|
|
27786
|
+
const rawPermission = roleDoc?.permission;
|
|
27787
|
+
const rolePermission = rawPermission === "edit" || rawPermission === "read-only" ? rawPermission : void 0;
|
|
27788
|
+
if (!rolePermission) return { permission: stepPermission };
|
|
27789
|
+
const rolePreset = yamlToolsPreset(roleDoc);
|
|
27790
|
+
const agentPreset = yamlToolsPreset(agent);
|
|
27791
|
+
const rolePresetProfile = rolePreset ? toolPresetProfile(rolePreset) : void 0;
|
|
27792
|
+
if (rolePreset && rolePresetProfile === "edit" && rolePermission === "read-only") {
|
|
27793
|
+
return {
|
|
27794
|
+
error: {
|
|
27795
|
+
reason: "step_unsupported",
|
|
27796
|
+
field: "tools.preset",
|
|
27797
|
+
detail: `tools.preset ${rolePreset} exceeds role ${roleId} permission read-only`
|
|
27798
|
+
}
|
|
27799
|
+
};
|
|
27800
|
+
}
|
|
27801
|
+
if (agentPreset) {
|
|
27802
|
+
const exceeds = toolPresetExceedsRoleMessage(agentPreset, roleId, rolePermission, rolePreset);
|
|
27803
|
+
if (exceeds) {
|
|
27804
|
+
return { error: { reason: "step_unsupported", field: "tools.preset", detail: exceeds } };
|
|
27805
|
+
}
|
|
27806
|
+
}
|
|
27807
|
+
let chain = rolePermission;
|
|
27808
|
+
if (rolePresetProfile) chain = narrowerPermission(chain, rolePresetProfile);
|
|
27809
|
+
const agentProfile = agentPreset ? toolPresetProfile(agentPreset) : void 0;
|
|
27810
|
+
if (agentProfile) chain = narrowerPermission(chain, agentProfile);
|
|
27811
|
+
const permission = narrowerPermission(chain, stepPermission);
|
|
27812
|
+
if (stepPermission === "edit" && permission === "read-only") {
|
|
27813
|
+
return {
|
|
27814
|
+
error: {
|
|
27815
|
+
reason: "step_unsupported",
|
|
27816
|
+
field: "permission",
|
|
27817
|
+
detail: `role permission ${rolePermission} resolves to ${chain}; step access ${stepAccessDetail(step)}`
|
|
27818
|
+
}
|
|
27819
|
+
};
|
|
27820
|
+
}
|
|
27821
|
+
return { permission };
|
|
27822
|
+
}
|
|
27540
27823
|
function kxmLiveRunPrerequisites(bundle, workflowId, projectRoot) {
|
|
27541
27824
|
const workflow = lookupKxmResource(bundle.workflows.values(), workflowId, "workflow");
|
|
27542
27825
|
if (!workflow) throw runtimeError("run_workflow_unknown", workflowId, `workflow ${workflowId} does not exist in this project`);
|
|
@@ -27564,6 +27847,11 @@ function kxmLiveRunPrerequisites(bundle, workflowId, projectRoot) {
|
|
|
27564
27847
|
if (step.kind !== "agent" && step.kind !== "moa") continue;
|
|
27565
27848
|
const agentIds = step.assignments.allowedAgents.length > 0 ? step.assignments.allowedAgents : [step.agent];
|
|
27566
27849
|
for (const agentId of agentIds) {
|
|
27850
|
+
const toolDispatch = resolveToolDispatch(projectRoot, step, agentId);
|
|
27851
|
+
if ("error" in toolDispatch) {
|
|
27852
|
+
prerequisites.push({ ...toolDispatch.error, stepId });
|
|
27853
|
+
continue;
|
|
27854
|
+
}
|
|
27567
27855
|
const route = resolveProducerRoute(projectRoot, step, agentId);
|
|
27568
27856
|
if ("error" in route) {
|
|
27569
27857
|
const detail = route.error.detail === "producer_route_unsupported: agent step model is not honored" ? `${agentId}: agent step model is not honored; remove model from the step` : `${agentId}: ${route.error.detail}; set role in .kxm/agents/${agentId}.yaml and admit the route model with kxm routes admit --model <provider/model>`;
|
|
@@ -27571,7 +27859,7 @@ function kxmLiveRunPrerequisites(bundle, workflowId, projectRoot) {
|
|
|
27571
27859
|
continue;
|
|
27572
27860
|
}
|
|
27573
27861
|
const harness = route.harness;
|
|
27574
|
-
const permission =
|
|
27862
|
+
const permission = toolDispatch.permission;
|
|
27575
27863
|
if (!BUILTIN_HARNESSES.some((entry) => entry.id === harness && entry.oneShot) || !oneShotPermissionArgs(harness, permission)) {
|
|
27576
27864
|
prerequisites.push({ reason: "step_unsupported", stepId, field: "harness", detail: `${agentId}: ${harness} has no audited ${permission} one-shot profile; use a supported workflow or execute this work directly in ${harness}, without substituting another harness` });
|
|
27577
27865
|
continue;
|
|
@@ -28369,10 +28657,13 @@ function runtimeFrom(ctx, command) {
|
|
|
28369
28657
|
const envServerUrl = ctx.env.KXM_SERVER_URL?.trim();
|
|
28370
28658
|
let boundHubUrl;
|
|
28371
28659
|
try {
|
|
28372
|
-
|
|
28660
|
+
const loaded = loadHubBinding(ctx.env);
|
|
28661
|
+
if (loaded.warning) ctx.io.stderr(`kxm: ${loaded.warning}
|
|
28662
|
+
`);
|
|
28663
|
+
boundHubUrl = loaded.record?.url;
|
|
28373
28664
|
} catch (error) {
|
|
28374
28665
|
if (error instanceof HubBindingError) {
|
|
28375
|
-
ctx.io.stderr(`kxm: ignoring malformed hub binding at ${hubBindingFile(ctx.env)};
|
|
28666
|
+
ctx.io.stderr(`kxm: ignoring malformed hub binding at ${hubBindingFile(ctx.env)}; falling back to the local hub. Run kxm hub bind <url> again
|
|
28376
28667
|
`);
|
|
28377
28668
|
} else {
|
|
28378
28669
|
throw error;
|
|
@@ -28621,7 +28912,7 @@ var init_vision_gate = __esm({
|
|
|
28621
28912
|
});
|
|
28622
28913
|
|
|
28623
28914
|
// plugins/kxm/src/permission.ts
|
|
28624
|
-
import { spawnSync as
|
|
28915
|
+
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
28625
28916
|
import { createHash as createHash17 } from "node:crypto";
|
|
28626
28917
|
import { existsSync as existsSync27, mkdtempSync, mkdirSync as mkdirSync20, readFileSync as readFileSync25, rmSync as rmSync8, writeFileSync as writeFileSync19 } from "node:fs";
|
|
28627
28918
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
@@ -29095,7 +29386,7 @@ function gitEnvironment2() {
|
|
|
29095
29386
|
return Object.fromEntries(Object.entries(process.env).filter(([name]) => !name.toUpperCase().startsWith("GIT_")));
|
|
29096
29387
|
}
|
|
29097
29388
|
function git(root, args) {
|
|
29098
|
-
const result =
|
|
29389
|
+
const result = spawnSync8("git", ["-C", root, ...args], {
|
|
29099
29390
|
encoding: "utf8",
|
|
29100
29391
|
env: gitEnvironment2(),
|
|
29101
29392
|
timeout: 15e3,
|
|
@@ -29113,7 +29404,7 @@ function git(root, args) {
|
|
|
29113
29404
|
return result.stdout;
|
|
29114
29405
|
}
|
|
29115
29406
|
function gitBuffer(root, args) {
|
|
29116
|
-
const result =
|
|
29407
|
+
const result = spawnSync8("git", ["-C", root, ...args], {
|
|
29117
29408
|
env: gitEnvironment2(),
|
|
29118
29409
|
timeout: 15e3,
|
|
29119
29410
|
windowsHide: true,
|
|
@@ -29311,7 +29602,7 @@ function loadBaseProjectDeclarations(projectFile) {
|
|
|
29311
29602
|
return members;
|
|
29312
29603
|
}
|
|
29313
29604
|
function initShadowGitRoot(directory) {
|
|
29314
|
-
const result =
|
|
29605
|
+
const result = spawnSync8("git", ["-c", "init.defaultBranch=main", "init", "--quiet", directory], {
|
|
29315
29606
|
encoding: "utf8",
|
|
29316
29607
|
env: gitEnvironment2(),
|
|
29317
29608
|
timeout: 1e4,
|
|
@@ -35174,6 +35465,7 @@ function useColor() {
|
|
|
35174
35465
|
var program = new Command();
|
|
35175
35466
|
|
|
35176
35467
|
// plugins/kxm/src/kxm-update.ts
|
|
35468
|
+
import { spawnSync } from "node:child_process";
|
|
35177
35469
|
import { createHash } from "node:crypto";
|
|
35178
35470
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
35179
35471
|
import { join } from "node:path";
|
|
@@ -35192,6 +35484,18 @@ var KxmUpdateConfigError = class extends Error {
|
|
|
35192
35484
|
function kxmReleaseAssetName(version) {
|
|
35193
35485
|
return `kxm-${version}.tgz`;
|
|
35194
35486
|
}
|
|
35487
|
+
function kxmReleaseDownloadUrl(version, name = kxmReleaseAssetName(version)) {
|
|
35488
|
+
return `https://github.com/kontextmind/kxm/releases/download/v${version}/${name}`;
|
|
35489
|
+
}
|
|
35490
|
+
function ghReleaseDownloadAvailable(env = process.env) {
|
|
35491
|
+
const result = spawnSync("gh", ["--version"], {
|
|
35492
|
+
encoding: "utf8",
|
|
35493
|
+
env,
|
|
35494
|
+
windowsHide: true,
|
|
35495
|
+
timeout: 15e3
|
|
35496
|
+
});
|
|
35497
|
+
return !result.error && result.status === 0;
|
|
35498
|
+
}
|
|
35195
35499
|
function readInstalledKxmVersion(root) {
|
|
35196
35500
|
const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
35197
35501
|
if (typeof pkg.version !== "string" || !parseSemver(pkg.version)) {
|
|
@@ -35340,13 +35644,17 @@ function verifyReleaseAssetDigest(path4, sha256) {
|
|
|
35340
35644
|
return false;
|
|
35341
35645
|
}
|
|
35342
35646
|
}
|
|
35343
|
-
function planKxmPackageUpdate(source, latest, releaseDir, asset) {
|
|
35647
|
+
function planKxmPackageUpdate(source, latest, releaseDir, asset, downloader = "gh") {
|
|
35344
35648
|
if (source === "npm") {
|
|
35345
35649
|
return [{ kind: "install", command: "npm", args: ["install", "--global", "--omit=peer", `@kontextmind/kxm@${latest}`] }];
|
|
35346
35650
|
}
|
|
35347
35651
|
const name = asset?.name ?? kxmReleaseAssetName(latest);
|
|
35348
35652
|
const steps = [
|
|
35349
|
-
{
|
|
35653
|
+
downloader === "curl" ? {
|
|
35654
|
+
kind: "download",
|
|
35655
|
+
command: "curl",
|
|
35656
|
+
args: ["--fail", "--silent", "--show-error", "--location", "--output", join(releaseDir, name), kxmReleaseDownloadUrl(latest, name)]
|
|
35657
|
+
} : {
|
|
35350
35658
|
kind: "download",
|
|
35351
35659
|
command: "gh",
|
|
35352
35660
|
args: ["release", "download", `v${latest}`, "--repo", "kontextmind/kxm", "--pattern", name, "--dir", releaseDir, "--clobber"]
|
|
@@ -40076,7 +40384,7 @@ init_project();
|
|
|
40076
40384
|
init_repo_root();
|
|
40077
40385
|
init_harness();
|
|
40078
40386
|
init_types();
|
|
40079
|
-
import { spawnSync as
|
|
40387
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
40080
40388
|
var PLUGIN_SUPPORTED_HARNESSES = Object.freeze(["pi", "omp", "claude"]);
|
|
40081
40389
|
async function cmdPluginInstall(runtime, options) {
|
|
40082
40390
|
const repoRoot = findKxmRepoRoot(import.meta.url);
|
|
@@ -40115,7 +40423,7 @@ async function cmdPluginInstall(runtime, options) {
|
|
|
40115
40423
|
detail: `would install kxm plugin into pi: ${command} ${args.join(" ")}`
|
|
40116
40424
|
});
|
|
40117
40425
|
} else {
|
|
40118
|
-
const run = runtime.io.spawnSync ? runtime.io.spawnSync(command, args) :
|
|
40426
|
+
const run = runtime.io.spawnSync ? runtime.io.spawnSync(command, args) : spawnSync9(command, args, { encoding: "utf8", windowsHide: true, env: runtime.env });
|
|
40119
40427
|
if (run.error || run.status !== 0 && run.status !== null) {
|
|
40120
40428
|
results.push({
|
|
40121
40429
|
harness: "pi",
|
|
@@ -40146,7 +40454,7 @@ async function cmdPluginInstall(runtime, options) {
|
|
|
40146
40454
|
detail: `would install kxm plugin into omp: ${command} ${args.join(" ")}`
|
|
40147
40455
|
});
|
|
40148
40456
|
} else {
|
|
40149
|
-
const run = runtime.io.spawnSync ? runtime.io.spawnSync(command, args) :
|
|
40457
|
+
const run = runtime.io.spawnSync ? runtime.io.spawnSync(command, args) : spawnSync9(command, args, { encoding: "utf8", windowsHide: true, env: runtime.env });
|
|
40150
40458
|
if (run.error || run.status !== 0 && run.status !== null) {
|
|
40151
40459
|
results.push({
|
|
40152
40460
|
harness: "omp",
|
|
@@ -40181,9 +40489,9 @@ async function cmdPluginInstall(runtime, options) {
|
|
|
40181
40489
|
if (runtime.io.spawnSync) {
|
|
40182
40490
|
runtime.io.spawnSync(command, marketplaceArgs);
|
|
40183
40491
|
} else {
|
|
40184
|
-
|
|
40492
|
+
spawnSync9(command, marketplaceArgs, { encoding: "utf8", windowsHide: true, env: runtime.env });
|
|
40185
40493
|
}
|
|
40186
|
-
const run = runtime.io.spawnSync ? runtime.io.spawnSync(command, installArgs) :
|
|
40494
|
+
const run = runtime.io.spawnSync ? runtime.io.spawnSync(command, installArgs) : spawnSync9(command, installArgs, { encoding: "utf8", windowsHide: true, env: runtime.env });
|
|
40187
40495
|
if (run.error || run.status !== 0 && run.status !== null) {
|
|
40188
40496
|
results.push({
|
|
40189
40497
|
harness: "claude",
|
|
@@ -40307,7 +40615,7 @@ init_project_config();
|
|
|
40307
40615
|
init_runtime_store();
|
|
40308
40616
|
init_runtime_supervisor();
|
|
40309
40617
|
init_types();
|
|
40310
|
-
import { spawnSync as
|
|
40618
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
40311
40619
|
import { chmodSync as chmodSync6, existsSync as existsSync33, mkdirSync as mkdirSync24, readFileSync as readFileSync30, writeFileSync as writeFileSync22 } from "node:fs";
|
|
40312
40620
|
import { basename as basename8, dirname as dirname18, join as join37, resolve as resolve25 } from "node:path";
|
|
40313
40621
|
var LANE_SCHEMA = "kxm.lanes.v1";
|
|
@@ -40322,7 +40630,7 @@ function gitEnv2() {
|
|
|
40322
40630
|
return Object.fromEntries(Object.entries(process.env).filter(([name]) => !name.toUpperCase().startsWith("GIT_")));
|
|
40323
40631
|
}
|
|
40324
40632
|
function git2(cwd, args) {
|
|
40325
|
-
const result =
|
|
40633
|
+
const result = spawnSync10("git", ["-C", cwd, ...args], {
|
|
40326
40634
|
encoding: "utf8",
|
|
40327
40635
|
env: gitEnv2(),
|
|
40328
40636
|
timeout: 3e4,
|
|
@@ -40897,7 +41205,7 @@ function cmdLand(runtime, options = {}) {
|
|
|
40897
41205
|
// plugins/kxm/src/cli/assign.ts
|
|
40898
41206
|
init_project_config();
|
|
40899
41207
|
init_types();
|
|
40900
|
-
import { spawnSync as
|
|
41208
|
+
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
40901
41209
|
import { existsSync as existsSync34 } from "node:fs";
|
|
40902
41210
|
import { join as join39 } from "node:path";
|
|
40903
41211
|
var kxmAssignCliSeams = {};
|
|
@@ -40983,7 +41291,7 @@ async function cmdAssign(runtime, subcommand, args) {
|
|
|
40983
41291
|
return 0;
|
|
40984
41292
|
}
|
|
40985
41293
|
const spawn6 = kxmAssignCliSeams.spawn ?? ((commandName, commandArgs, options) => {
|
|
40986
|
-
const result2 =
|
|
41294
|
+
const result2 = spawnSync11(commandName, commandArgs, {
|
|
40987
41295
|
cwd: options.cwd,
|
|
40988
41296
|
stdio: options.stdio,
|
|
40989
41297
|
env: options.env,
|
|
@@ -49448,7 +49756,7 @@ var MAX_RENDER_WRITE_CHARS = 1024 * 1024;
|
|
|
49448
49756
|
// plugins/kxm/src/tui.ts
|
|
49449
49757
|
import { mkdirSync as mkdirSync25 } from "node:fs";
|
|
49450
49758
|
import { join as join44, resolve as resolve27, dirname as dirname20 } from "node:path";
|
|
49451
|
-
import { spawnSync as
|
|
49759
|
+
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
49452
49760
|
|
|
49453
49761
|
// packages/core/tui/src/types/surface.ts
|
|
49454
49762
|
var KXM_TUI_LIMITS = Object.freeze({
|
|
@@ -50005,16 +50313,16 @@ function applyMeshTuiKey(view, key, itemCount = 0) {
|
|
|
50005
50313
|
function copyToClipboard(text) {
|
|
50006
50314
|
try {
|
|
50007
50315
|
if (process.platform === "darwin") {
|
|
50008
|
-
const proc =
|
|
50316
|
+
const proc = spawnSync12("pbcopy", { input: text, encoding: "utf8", windowsHide: true });
|
|
50009
50317
|
return proc.status === 0;
|
|
50010
50318
|
}
|
|
50011
50319
|
if (process.platform === "win32") {
|
|
50012
|
-
const proc =
|
|
50320
|
+
const proc = spawnSync12("clip", { input: text, encoding: "utf8", windowsHide: true });
|
|
50013
50321
|
return proc.status === 0;
|
|
50014
50322
|
}
|
|
50015
|
-
const wl =
|
|
50323
|
+
const wl = spawnSync12("wl-copy", [text], { encoding: "utf8", windowsHide: true });
|
|
50016
50324
|
if (wl.status === 0) return true;
|
|
50017
|
-
const xclip =
|
|
50325
|
+
const xclip = spawnSync12("xclip", ["-selection", "clipboard"], { input: text, encoding: "utf8", windowsHide: true });
|
|
50018
50326
|
return xclip.status === 0;
|
|
50019
50327
|
} catch {
|
|
50020
50328
|
return false;
|
|
@@ -50022,7 +50330,7 @@ function copyToClipboard(text) {
|
|
|
50022
50330
|
}
|
|
50023
50331
|
function spawnDegradeWorktree(repoRoot, runId, options) {
|
|
50024
50332
|
const runner = options?.execFn ?? ((cmd, args) => {
|
|
50025
|
-
const res =
|
|
50333
|
+
const res = spawnSync12(cmd, args, {
|
|
50026
50334
|
cwd: repoRoot,
|
|
50027
50335
|
encoding: "utf8",
|
|
50028
50336
|
windowsHide: true,
|
|
@@ -50806,7 +51114,7 @@ async function runMeshTui(input) {
|
|
|
50806
51114
|
}
|
|
50807
51115
|
|
|
50808
51116
|
// plugins/kxm/src/session-work.ts
|
|
50809
|
-
import { spawnSync as
|
|
51117
|
+
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
50810
51118
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
50811
51119
|
import { existsSync as existsSync36, mkdirSync as mkdirSync26, readFileSync as readFileSync32, renameSync as renameSync8, writeFileSync as writeFileSync23 } from "node:fs";
|
|
50812
51120
|
import { join as join45 } from "node:path";
|
|
@@ -50867,10 +51175,10 @@ function formatShipLine(ship) {
|
|
|
50867
51175
|
}
|
|
50868
51176
|
function readGitShip(cwd) {
|
|
50869
51177
|
try {
|
|
50870
|
-
const dirty =
|
|
51178
|
+
const dirty = spawnSync13("git", ["--no-optional-locks", "-C", cwd, "status", "--porcelain"], { encoding: "utf8", windowsHide: true });
|
|
50871
51179
|
if (dirty.status !== 0) return void 0;
|
|
50872
51180
|
const isDirty = dirty.stdout.trim().length > 0;
|
|
50873
|
-
const upstream =
|
|
51181
|
+
const upstream = spawnSync13("git", ["-C", cwd, "rev-list", "--count", "@{u}..HEAD"], { encoding: "utf8", windowsHide: true });
|
|
50874
51182
|
if (upstream.status === 0) {
|
|
50875
51183
|
return {
|
|
50876
51184
|
dirty: isDirty,
|
|
@@ -50878,9 +51186,9 @@ function readGitShip(cwd) {
|
|
|
50878
51186
|
};
|
|
50879
51187
|
}
|
|
50880
51188
|
for (const baseRef of ["origin/HEAD", "main", "origin/main", "master", "origin/master"]) {
|
|
50881
|
-
const mb =
|
|
51189
|
+
const mb = spawnSync13("git", ["-C", cwd, "merge-base", baseRef, "HEAD"], { encoding: "utf8", windowsHide: true });
|
|
50882
51190
|
if (mb.status === 0 && mb.stdout.trim()) {
|
|
50883
|
-
const count =
|
|
51191
|
+
const count = spawnSync13("git", ["-C", cwd, "rev-list", "--count", `${mb.stdout.trim()}..HEAD`], { encoding: "utf8", windowsHide: true });
|
|
50884
51192
|
if (count.status === 0) {
|
|
50885
51193
|
return {
|
|
50886
51194
|
dirty: isDirty,
|
|
@@ -51424,20 +51732,6 @@ init_repo_root();
|
|
|
51424
51732
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
51425
51733
|
import { dirname as dirname22 } from "node:path";
|
|
51426
51734
|
import { homedir as homedir7 } from "node:os";
|
|
51427
|
-
async function hubGet(url, fetchImpl, headers) {
|
|
51428
|
-
try {
|
|
51429
|
-
const response = await fetchImpl(url, headers ? { headers } : void 0);
|
|
51430
|
-
const text = redactSecrets((await response.text()).slice(0, 8e3));
|
|
51431
|
-
let body = text;
|
|
51432
|
-
try {
|
|
51433
|
-
body = JSON.parse(text);
|
|
51434
|
-
} catch {
|
|
51435
|
-
}
|
|
51436
|
-
return { ok: response.ok, status: response.status, body };
|
|
51437
|
-
} catch {
|
|
51438
|
-
return { ok: false, status: 0, body: { error: "hub_unreachable" } };
|
|
51439
|
-
}
|
|
51440
|
-
}
|
|
51441
51735
|
function installProbeFrom(runtime) {
|
|
51442
51736
|
const partial = runtime.io.installProbe ?? {};
|
|
51443
51737
|
const moduleDir = partial.moduleDir ?? dirname22(fileURLToPath3(import.meta.url));
|
|
@@ -51512,8 +51806,11 @@ async function cmdStatus(runtime) {
|
|
|
51512
51806
|
}
|
|
51513
51807
|
if (!(error instanceof HubBindingError)) throw error;
|
|
51514
51808
|
}
|
|
51515
|
-
const health = await
|
|
51516
|
-
const ready = await
|
|
51809
|
+
const health = await readHubEndpoint(runtime.serverUrl, "health", runtime.fetchImpl, headers ? { headers } : {});
|
|
51810
|
+
const ready = await readHubEndpoint(runtime.serverUrl, "ready", runtime.fetchImpl, headers ? { headers } : {});
|
|
51811
|
+
const proxyKind = [health.kind, ready.kind].find((kind) => kind === "redirect" || kind === "auth_proxy");
|
|
51812
|
+
const notHub = !proxyKind && (health.kind === "not_hub" || ready.kind === "not_hub");
|
|
51813
|
+
const probeNote = proxyKind === "redirect" ? " \xB7 auth proxy or redirect" : proxyKind === "auth_proxy" ? " \xB7 auth proxy (HTML login page)" : notHub ? " \xB7 not a kxm hub" : "";
|
|
51517
51814
|
const effectiveScope = connection.scope;
|
|
51518
51815
|
const overridden = connection.urlSource === "env";
|
|
51519
51816
|
const identity = {
|
|
@@ -51537,7 +51834,7 @@ async function cmdStatus(runtime) {
|
|
|
51537
51834
|
runtime.io,
|
|
51538
51835
|
runtime.json,
|
|
51539
51836
|
payload,
|
|
51540
|
-
`hub health=${health.ok} ready=${ready.ok} \xB7 ${effectiveScope} hub${overridden ? " (KXM_SERVER_URL)" : ""} \xB7 mode=${identity.mode} project=${identity.project} (${connection.sourceLabel}) key=${identity.keySource}`
|
|
51837
|
+
`hub health=${health.ok} ready=${ready.ok} \xB7 ${effectiveScope} hub${overridden ? " (KXM_SERVER_URL)" : ""} \xB7 mode=${identity.mode} project=${identity.project} (${connection.sourceLabel}) key=${identity.keySource}${probeNote}`
|
|
51541
51838
|
);
|
|
51542
51839
|
return payload.ok ? 0 : 1;
|
|
51543
51840
|
}
|
|
@@ -51748,7 +52045,7 @@ async function cmdHubBind(runtime, rawUrl, options = {}) {
|
|
|
51748
52045
|
return 2;
|
|
51749
52046
|
}
|
|
51750
52047
|
}
|
|
51751
|
-
const file = hubBindingFile(runtime.env);
|
|
52048
|
+
const file = cloud ? hubBindingCloudFile(runtime.env) : hubBindingFile(runtime.env);
|
|
51752
52049
|
const bindingCommand = tokenCommand ?? (cloud && keyOp ? `op read ${keyOp}` : void 0);
|
|
51753
52050
|
const cloudFields = cloud ? { cloud: true, ...tokenEnv ? { tokenEnv } : {}, ...bindingCommand ? { tokenCommand: bindingCommand } : {} } : {};
|
|
51754
52051
|
const record = {
|
|
@@ -51773,6 +52070,27 @@ async function cmdHubBind(runtime, rawUrl, options = {}) {
|
|
|
51773
52070
|
);
|
|
51774
52071
|
return 0;
|
|
51775
52072
|
}
|
|
52073
|
+
const probe = await probeHubHealth(url, runtime.fetchImpl);
|
|
52074
|
+
const acceptable = probe.kind === "hub" || probe.kind === "timeout" || probe.kind === "unreachable";
|
|
52075
|
+
if (!acceptable && options.force !== true) {
|
|
52076
|
+
print(
|
|
52077
|
+
runtime.io,
|
|
52078
|
+
runtime.json,
|
|
52079
|
+
{
|
|
52080
|
+
ok: false,
|
|
52081
|
+
command: "hub bind",
|
|
52082
|
+
error: "hub_not_kxm",
|
|
52083
|
+
url,
|
|
52084
|
+
scope,
|
|
52085
|
+
kind: probe.kind,
|
|
52086
|
+
status: probe.status,
|
|
52087
|
+
detail: probe.detail,
|
|
52088
|
+
nextAction: "bind_a_kxm_hub_or_pass_force"
|
|
52089
|
+
},
|
|
52090
|
+
`refusing to bind ${url}: ${probe.detail}; no binding was written. Pass --force to bind anyway`
|
|
52091
|
+
);
|
|
52092
|
+
return 2;
|
|
52093
|
+
}
|
|
51776
52094
|
try {
|
|
51777
52095
|
writeHubEndpoint(runtime.dirs.workdir, {
|
|
51778
52096
|
mode: cloud ? "cloud" : "local",
|
|
@@ -51793,12 +52111,12 @@ async function cmdHubBind(runtime, rawUrl, options = {}) {
|
|
|
51793
52111
|
throw error;
|
|
51794
52112
|
}
|
|
51795
52113
|
writeHubBinding({ ...record, boundAt: (/* @__PURE__ */ new Date()).toISOString() }, runtime.env);
|
|
51796
|
-
const
|
|
52114
|
+
const healthText = acceptable ? formatHubBindHealth(probe.health) : `${probe.detail} (--force)`;
|
|
51797
52115
|
print(
|
|
51798
52116
|
runtime.io,
|
|
51799
52117
|
runtime.json,
|
|
51800
|
-
{ ok: true, command: "hub bind", url, scope, file, configFile, project: identity.project, health, probeMs, ...cloudFields },
|
|
51801
|
-
`bound hub ${url} \xB7 ${scope} \xB7 ${
|
|
52118
|
+
{ ok: true, command: "hub bind", url, scope, file, configFile, project: identity.project, health: probe.health, probeMs: probe.probeMs, kind: probe.kind, ...cloudFields },
|
|
52119
|
+
`bound hub ${url} \xB7 ${scope} \xB7 ${healthText}${cloud ? cloudNote : scope === "remote" ? " \xB7 token leaves this machine" : ""}`
|
|
51802
52120
|
);
|
|
51803
52121
|
return 0;
|
|
51804
52122
|
}
|
|
@@ -52231,7 +52549,7 @@ init_redact();
|
|
|
52231
52549
|
init_telemetry();
|
|
52232
52550
|
init_routing();
|
|
52233
52551
|
init_prices();
|
|
52234
|
-
import { spawnSync as
|
|
52552
|
+
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
52235
52553
|
import { createHash as createHash19 } from "node:crypto";
|
|
52236
52554
|
import { existsSync as existsSync47, mkdtempSync as mkdtempSync3, readFileSync as readFileSync41, rmSync as rmSync13 } from "node:fs";
|
|
52237
52555
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
@@ -53110,7 +53428,7 @@ ${divider}
|
|
|
53110
53428
|
|
|
53111
53429
|
// plugins/kxm/src/ssh-remote.ts
|
|
53112
53430
|
init_safety_integrity();
|
|
53113
|
-
import { spawnSync as
|
|
53431
|
+
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
53114
53432
|
import { existsSync as existsSync44, mkdirSync as mkdirSync30, readFileSync as readFileSync39, readdirSync as readdirSync14, rmSync as rmSync12, statSync as statSync7 } from "node:fs";
|
|
53115
53433
|
import { homedir as homedir8 } from "node:os";
|
|
53116
53434
|
import { join as join52, resolve as resolve31 } from "node:path";
|
|
@@ -53186,7 +53504,7 @@ function parseSshConfig(configPath) {
|
|
|
53186
53504
|
return [];
|
|
53187
53505
|
}
|
|
53188
53506
|
}
|
|
53189
|
-
function resolveSshHostG(host, execFn =
|
|
53507
|
+
function resolveSshHostG(host, execFn = spawnSync14) {
|
|
53190
53508
|
try {
|
|
53191
53509
|
const result = execFn("ssh", ["-G", host], { encoding: "utf-8" });
|
|
53192
53510
|
if (result.status !== 0 || !result.stdout) {
|
|
@@ -53252,7 +53570,7 @@ function buildSshArgs(options) {
|
|
|
53252
53570
|
args.push(options.host);
|
|
53253
53571
|
return args;
|
|
53254
53572
|
}
|
|
53255
|
-
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn =
|
|
53573
|
+
function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync14) {
|
|
53256
53574
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
53257
53575
|
const controlPath = join52(resolvedDir, "%C");
|
|
53258
53576
|
try {
|
|
@@ -53264,7 +53582,7 @@ function checkControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
53264
53582
|
return false;
|
|
53265
53583
|
}
|
|
53266
53584
|
}
|
|
53267
|
-
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn =
|
|
53585
|
+
function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawnSync14) {
|
|
53268
53586
|
const resolvedDir = ensureSocketDir(socketDir);
|
|
53269
53587
|
const controlPath = join52(resolvedDir, "%C");
|
|
53270
53588
|
try {
|
|
@@ -53278,7 +53596,7 @@ function closeControlSocket(host, socketDir = DEFAULT_SOCKET_DIR, execFn = spawn
|
|
|
53278
53596
|
}
|
|
53279
53597
|
function executeSshRun(params) {
|
|
53280
53598
|
const startTime = Date.now();
|
|
53281
|
-
const execSyncFn = params.execFn ??
|
|
53599
|
+
const execSyncFn = params.execFn ?? spawnSync14;
|
|
53282
53600
|
if (params.action === "info") {
|
|
53283
53601
|
if (params.host) {
|
|
53284
53602
|
const hostInfo = resolveSshHostG(params.host, execSyncFn);
|
|
@@ -54423,7 +54741,7 @@ init_types();
|
|
|
54423
54741
|
init_repo_root();
|
|
54424
54742
|
function cliSpawn(runtime, command, args, extra) {
|
|
54425
54743
|
if (runtime.io.spawnSync) return runtime.io.spawnSync(command, args);
|
|
54426
|
-
const result =
|
|
54744
|
+
const result = spawnSync15(command, [...args], {
|
|
54427
54745
|
encoding: "utf8",
|
|
54428
54746
|
windowsHide: true,
|
|
54429
54747
|
shell: process.platform === "win32",
|
|
@@ -54463,7 +54781,8 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
54463
54781
|
}
|
|
54464
54782
|
const releaseDir = mkdtempSync3(join55(tmpdir3(), "kxm-pkg-update-"));
|
|
54465
54783
|
try {
|
|
54466
|
-
const
|
|
54784
|
+
const downloader = notice.source === "github" && !ghReleaseDownloadAvailable(runtime.env) ? "curl" : "gh";
|
|
54785
|
+
const planned = planKxmPackageUpdate(notice.source, notice.latest, releaseDir, notice.asset, downloader);
|
|
54467
54786
|
if (runtime.dryRun) {
|
|
54468
54787
|
return { ok: true, detail: planned.map(formatPackageUpdateStep).join(" && ") };
|
|
54469
54788
|
}
|
|
@@ -56042,7 +56361,7 @@ function createProgram(ctx, result, argv) {
|
|
|
56042
56361
|
addGlobalOptions(hub.command("stop").description("Request managed hub and worker shutdown")).option("--wait-ms <ms>", "How long to wait for PID files to clear").action(async function hubStopAction(options) {
|
|
56043
56362
|
result.code = await cmdStop(runtimeFrom(ctx, this), options.waitMs);
|
|
56044
56363
|
});
|
|
56045
|
-
addGlobalOptions(hub.command("bind").description("Bind this machine to a running hub").argument("<url>", "Hub base URL (http or https)")).option("--cloud", "Mark the hub remote even when the URL is a loopback forward").option("--token-env <name>", "Environment variable that holds the hub token; the token is not stored").option("--token-command <command>", "Program that prints the hub token; the token is not stored").option("--key-op <ref>", "op:// reference for the hub token; resolved with op read, never stored").action(async function hubBindAction(url, options) {
|
|
56364
|
+
addGlobalOptions(hub.command("bind").description("Bind this machine to a running hub").argument("<url>", "Hub base URL (http or https)")).option("--cloud", "Mark the hub remote even when the URL is a loopback forward").option("--token-env <name>", "Environment variable that holds the hub token; the token is not stored").option("--token-command <command>", "Program that prints the hub token; the token is not stored").option("--key-op <ref>", "op:// reference for the hub token; resolved with op read, never stored").option("--force", "Bind even when the URL is not a kxm hub").action(async function hubBindAction(url, options) {
|
|
56046
56365
|
result.code = await cmdHubBind(runtimeFrom(ctx, this), url, options);
|
|
56047
56366
|
});
|
|
56048
56367
|
addGlobalOptions(hub.command("unbind").description("Remove this machine's hub binding")).action(bind(cmdHubUnbind));
|