@kontextmind/kxm 0.7.72 → 0.7.74
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/docs/contracts/synchronization.md +6 -3
- package/docs/operations.md +35 -4
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +307 -235
- package/plugins/kxm/dist/client.js +67 -36
- package/plugins/kxm/dist/core.js +2 -0
- package/plugins/kxm/dist/extension.js +40 -37
- package/plugins/kxm/dist/mcp-server.js +40 -37
- package/plugins/kxm/dist/runtime-supervisor.js +917 -141
- package/plugins/kxm/dist/runtime.js +977 -237
- package/plugins/kxm/dist/server.js +16206 -8256
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/client.ts +85 -3
- package/plugins/kxm/src/database.ts +4 -4
- package/plugins/kxm/src/external-effects.ts +30 -5
- package/plugins/kxm/src/hub.ts +221 -0
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/project-config.ts +15 -0
- package/plugins/kxm/src/protocol.ts +27 -0
- package/plugins/kxm/src/runtime-store.ts +109 -1
- package/plugins/kxm/src/runtime-supervisor.ts +150 -0
- package/plugins/kxm/src/store.ts +207 -4
- package/plugins/kxm/src/sync-transform.ts +380 -0
package/plugins/kxm/dist/cli.js
CHANGED
|
@@ -19594,46 +19594,49 @@ var HubClient = class {
|
|
|
19594
19594
|
await this.register();
|
|
19595
19595
|
}
|
|
19596
19596
|
async request(path4, init = {}, includeIdentity = true) {
|
|
19597
|
-
|
|
19598
|
-
|
|
19599
|
-
|
|
19600
|
-
|
|
19597
|
+
return await hubJsonRequest(this.options, path4, init, this.headers(includeIdentity));
|
|
19598
|
+
}
|
|
19599
|
+
};
|
|
19600
|
+
async function hubJsonRequest(options, path4, init, headers) {
|
|
19601
|
+
const requestTimeoutMs = options.requestTimeoutMs ?? 15e3;
|
|
19602
|
+
const timeoutSignal = AbortSignal.timeout(requestTimeoutMs);
|
|
19603
|
+
const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
|
|
19604
|
+
let response;
|
|
19605
|
+
try {
|
|
19606
|
+
response = await (options.fetchImpl ?? fetch)(`${options.serverUrl.replace(/\/$/, "")}${path4}`, {
|
|
19607
|
+
...init,
|
|
19608
|
+
signal,
|
|
19609
|
+
headers: { ...headers, ...init.headers ?? {} }
|
|
19610
|
+
});
|
|
19611
|
+
} catch (error) {
|
|
19612
|
+
if (timeoutSignal.aborted) throw new Error(`request timed out after ${requestTimeoutMs}ms`);
|
|
19613
|
+
throw error;
|
|
19614
|
+
}
|
|
19615
|
+
const text = await response.text();
|
|
19616
|
+
let body = {};
|
|
19617
|
+
if (text) {
|
|
19601
19618
|
try {
|
|
19602
|
-
|
|
19603
|
-
|
|
19604
|
-
|
|
19605
|
-
headers: { ...this.headers(includeIdentity), ...init.headers ?? {} }
|
|
19606
|
-
});
|
|
19607
|
-
} catch (error) {
|
|
19608
|
-
if (timeoutSignal.aborted) throw new Error(`request timed out after ${requestTimeoutMs}ms`);
|
|
19609
|
-
throw error;
|
|
19610
|
-
}
|
|
19611
|
-
const text = await response.text();
|
|
19612
|
-
let body = {};
|
|
19613
|
-
if (text) {
|
|
19614
|
-
try {
|
|
19615
|
-
body = JSON.parse(text);
|
|
19616
|
-
} catch {
|
|
19617
|
-
throw new Error(`hub returned invalid JSON with HTTP ${response.status}`);
|
|
19618
|
-
}
|
|
19619
|
-
}
|
|
19620
|
-
if (!response.ok) {
|
|
19621
|
-
const extras = {};
|
|
19622
|
-
for (const key of ["operation", "nextAction", "assignedCoordinatorName"]) {
|
|
19623
|
-
if (typeof body[key] === "string") extras[key] = body[key];
|
|
19624
|
-
}
|
|
19625
|
-
if (body.lease && typeof body.lease === "object") extras.lease = body.lease;
|
|
19626
|
-
throw new HubHttpError(
|
|
19627
|
-
response.status,
|
|
19628
|
-
String(body.error ?? `HTTP ${response.status}`),
|
|
19629
|
-
typeof body.code === "string" ? body.code : void 0,
|
|
19630
|
-
response.headers.get("x-request-id") ?? void 0,
|
|
19631
|
-
Object.keys(extras).length > 0 ? extras : void 0
|
|
19632
|
-
);
|
|
19619
|
+
body = JSON.parse(text);
|
|
19620
|
+
} catch {
|
|
19621
|
+
throw new Error(`hub returned invalid JSON with HTTP ${response.status}`);
|
|
19633
19622
|
}
|
|
19634
|
-
return body;
|
|
19635
19623
|
}
|
|
19636
|
-
|
|
19624
|
+
if (!response.ok) {
|
|
19625
|
+
const extras = {};
|
|
19626
|
+
for (const key of ["operation", "nextAction", "assignedCoordinatorName"]) {
|
|
19627
|
+
if (typeof body[key] === "string") extras[key] = body[key];
|
|
19628
|
+
}
|
|
19629
|
+
if (body.lease && typeof body.lease === "object") extras.lease = body.lease;
|
|
19630
|
+
throw new HubHttpError(
|
|
19631
|
+
response.status,
|
|
19632
|
+
String(body.error ?? `HTTP ${response.status}`),
|
|
19633
|
+
typeof body.code === "string" ? body.code : void 0,
|
|
19634
|
+
response.headers.get("x-request-id") ?? void 0,
|
|
19635
|
+
Object.keys(extras).length > 0 ? extras : void 0
|
|
19636
|
+
);
|
|
19637
|
+
}
|
|
19638
|
+
return body;
|
|
19639
|
+
}
|
|
19637
19640
|
|
|
19638
19641
|
// plugins/kxm/src/hub-env.ts
|
|
19639
19642
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
@@ -22167,6 +22170,7 @@ var KxmSchemaRegistry = class {
|
|
|
22167
22170
|
driveReceiptValidator;
|
|
22168
22171
|
coordinatorValidator;
|
|
22169
22172
|
intakeMessageValidator;
|
|
22173
|
+
syncEventValidator;
|
|
22170
22174
|
constructor(schemasDir = DEFAULT_SCHEMA_DIR) {
|
|
22171
22175
|
this.schemasDir = resolve3(schemasDir);
|
|
22172
22176
|
this.ajv = new import__.Ajv2020({ allErrors: true, strict: true, strictRequired: false });
|
|
@@ -22183,6 +22187,7 @@ var KxmSchemaRegistry = class {
|
|
|
22183
22187
|
const driveReceiptFile = "drive-receipt.schema.json";
|
|
22184
22188
|
const coordinatorFile = "coordinator.schema.json";
|
|
22185
22189
|
const intakeMessageFile = "intake-message.schema.json";
|
|
22190
|
+
const syncEventFile = "sync-event.schema.json";
|
|
22186
22191
|
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, localBindingsFile)));
|
|
22187
22192
|
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, templateProvenanceFile)));
|
|
22188
22193
|
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, initOperationFile)));
|
|
@@ -22191,6 +22196,7 @@ var KxmSchemaRegistry = class {
|
|
|
22191
22196
|
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, driveReceiptFile)));
|
|
22192
22197
|
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, coordinatorFile)));
|
|
22193
22198
|
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, intakeMessageFile)));
|
|
22199
|
+
this.ajv.addSchema(readJsonObject(join6(this.schemasDir, syncEventFile)));
|
|
22194
22200
|
for (const [kind, definition] of Object.entries(RESOURCE_SCHEMA)) {
|
|
22195
22201
|
const validator = this.ajv.getSchema(`https://schemas.kxm.dev/${definition.file}`);
|
|
22196
22202
|
if (!validator) throw new Error(`schema did not compile: ${definition.file}`);
|
|
@@ -22204,6 +22210,7 @@ var KxmSchemaRegistry = class {
|
|
|
22204
22210
|
const driveReceiptValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${driveReceiptFile}`);
|
|
22205
22211
|
const coordinatorValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${coordinatorFile}`);
|
|
22206
22212
|
const intakeMessageValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${intakeMessageFile}`);
|
|
22213
|
+
const syncEventValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${syncEventFile}`);
|
|
22207
22214
|
if (!localBindingsValidator) throw new Error(`schema did not compile: ${localBindingsFile}`);
|
|
22208
22215
|
if (!templateProvenanceValidator) throw new Error(`schema did not compile: ${templateProvenanceFile}`);
|
|
22209
22216
|
if (!initOperationValidator) throw new Error(`schema did not compile: ${initOperationFile}`);
|
|
@@ -22212,6 +22219,7 @@ var KxmSchemaRegistry = class {
|
|
|
22212
22219
|
if (!driveReceiptValidator) throw new Error(`schema did not compile: ${driveReceiptFile}`);
|
|
22213
22220
|
if (!coordinatorValidator) throw new Error(`schema did not compile: ${coordinatorFile}`);
|
|
22214
22221
|
if (!intakeMessageValidator) throw new Error(`schema did not compile: ${intakeMessageFile}`);
|
|
22222
|
+
if (!syncEventValidator) throw new Error(`schema did not compile: ${syncEventFile}`);
|
|
22215
22223
|
this.localBindingsValidator = localBindingsValidator;
|
|
22216
22224
|
this.templateProvenanceValidator = templateProvenanceValidator;
|
|
22217
22225
|
this.initOperationValidator = initOperationValidator;
|
|
@@ -22220,6 +22228,7 @@ var KxmSchemaRegistry = class {
|
|
|
22220
22228
|
this.driveReceiptValidator = driveReceiptValidator;
|
|
22221
22229
|
this.coordinatorValidator = coordinatorValidator;
|
|
22222
22230
|
this.intakeMessageValidator = intakeMessageValidator;
|
|
22231
|
+
this.syncEventValidator = syncEventValidator;
|
|
22223
22232
|
}
|
|
22224
22233
|
validate(kind, value, file) {
|
|
22225
22234
|
const definition = RESOURCE_SCHEMA[kind];
|
|
@@ -23258,12 +23267,12 @@ function planKxmInitialization(start = process.cwd(), options = {}) {
|
|
|
23258
23267
|
|
|
23259
23268
|
// plugins/kxm/src/runtime-supervisor.ts
|
|
23260
23269
|
import { spawn as spawn2 } from "node:child_process";
|
|
23261
|
-
import { createHash as
|
|
23262
|
-
import { chmodSync as chmodSync4, existsSync as
|
|
23263
|
-
import { dirname as
|
|
23270
|
+
import { createHash as createHash12, createHmac, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
23271
|
+
import { chmodSync as chmodSync4, existsSync as existsSync13, lstatSync as lstatSync6, mkdirSync as mkdirSync9, readFileSync as readFileSync12, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "node:fs";
|
|
23272
|
+
import { dirname as dirname9, isAbsolute as isAbsolute6, join as join13 } from "node:path";
|
|
23264
23273
|
|
|
23265
23274
|
// plugins/kxm/src/runtime-store.ts
|
|
23266
|
-
import { createHash as
|
|
23275
|
+
import { createHash as createHash10, randomUUID as randomUUID4 } from "node:crypto";
|
|
23267
23276
|
import { existsSync as existsSync9, lstatSync as lstatSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync8, realpathSync as realpathSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
23268
23277
|
import { dirname as dirname7, join as join9, resolve as resolve6 } from "node:path";
|
|
23269
23278
|
|
|
@@ -23620,8 +23629,88 @@ function writeKxmLocalBindings(projectRoot, projectId, repositories, options = {
|
|
|
23620
23629
|
return { file, written: true, record };
|
|
23621
23630
|
}
|
|
23622
23631
|
|
|
23632
|
+
// plugins/kxm/src/sync-transform.ts
|
|
23633
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
23634
|
+
|
|
23635
|
+
// plugins/kxm/src/redact.ts
|
|
23636
|
+
var SECRET_PATTERNS = [
|
|
23637
|
+
/\bsk-[A-Za-z0-9_-]{8,}\b/g,
|
|
23638
|
+
/\bsk-ant-[A-Za-z0-9_-]{8,}\b/g,
|
|
23639
|
+
/\bghp_[A-Za-z0-9_]{20,}\b/g,
|
|
23640
|
+
/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g,
|
|
23641
|
+
/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/gi,
|
|
23642
|
+
/\bBearer\s+[A-Za-z0-9._~+/=-]+\b/gi,
|
|
23643
|
+
/\bya29\.[A-Za-z0-9._~+/-]+=*/g,
|
|
23644
|
+
/\b1\/\/[A-Za-z0-9_-]+/g,
|
|
23645
|
+
/\b1\/[A-Za-z0-9_-]{20,}/g,
|
|
23646
|
+
/("?(?:access_token|refresh_token|id_token|sessionKey|session_key|claude_oauth_token|anthropicApiKey)"?\s*[:=]\s*")[^"]*(")/gi,
|
|
23647
|
+
/\bKXM_[A-Z0-9_]*(TOKEN|SECRET|KEY)[A-Z0-9_]*=\S+/gi,
|
|
23648
|
+
/\b(GITHUB_TOKEN|GH_TOKEN|KXM_AUTH_TOKEN|KXM_WORKFLOW_SIGNAL_SECRET|ANTHROPIC_API_KEY|ANTHROPIC_AUTH_TOKEN|CLAUDE_API_KEY)=\S+/gi,
|
|
23649
|
+
/\b[A-Fa-f0-9]{64}\b/g
|
|
23650
|
+
];
|
|
23651
|
+
function redactSecrets(value) {
|
|
23652
|
+
let result = value;
|
|
23653
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
23654
|
+
result = result.replace(pattern, "[redacted]");
|
|
23655
|
+
}
|
|
23656
|
+
return result;
|
|
23657
|
+
}
|
|
23658
|
+
function redactStringList(values, maxItems = 32) {
|
|
23659
|
+
return values.slice(0, maxItems).map((value) => redactSecrets(value).slice(0, 500));
|
|
23660
|
+
}
|
|
23661
|
+
|
|
23662
|
+
// plugins/kxm/src/sync-transform.ts
|
|
23663
|
+
var KXM_DEFAULT_SYNC_POLICY = Object.freeze({
|
|
23664
|
+
prompts: "title-only",
|
|
23665
|
+
results: "bounded-summary",
|
|
23666
|
+
evidence: "references",
|
|
23667
|
+
artifacts: "metadata",
|
|
23668
|
+
fileChanges: "paths-only",
|
|
23669
|
+
rawLogs: false,
|
|
23670
|
+
diffs: false,
|
|
23671
|
+
environmentValues: false
|
|
23672
|
+
});
|
|
23673
|
+
var KXM_DEFAULT_SYNC_POLICY_REVISION = `sha256:${createHash8("sha256").update(kxmCanonicalJson(KXM_DEFAULT_SYNC_POLICY), "utf8").digest("hex")}`;
|
|
23674
|
+
var SCALAR_FIELDS = [
|
|
23675
|
+
"workflowId",
|
|
23676
|
+
"promptHash",
|
|
23677
|
+
"status",
|
|
23678
|
+
"previousStatus",
|
|
23679
|
+
"outcome",
|
|
23680
|
+
"stepId",
|
|
23681
|
+
"stepAttempt",
|
|
23682
|
+
"fromStepId",
|
|
23683
|
+
"toStepId",
|
|
23684
|
+
"assignmentId",
|
|
23685
|
+
"attemptId",
|
|
23686
|
+
"agentId",
|
|
23687
|
+
"instanceNo",
|
|
23688
|
+
"scopeEpoch",
|
|
23689
|
+
"resolutionAction"
|
|
23690
|
+
];
|
|
23691
|
+
var CARRIED_FIELDS = /* @__PURE__ */ new Set([
|
|
23692
|
+
...SCALAR_FIELDS,
|
|
23693
|
+
"displayTitle",
|
|
23694
|
+
"summary",
|
|
23695
|
+
"reason",
|
|
23696
|
+
"executor",
|
|
23697
|
+
"model",
|
|
23698
|
+
"timing",
|
|
23699
|
+
"usage",
|
|
23700
|
+
"evidenceRefs",
|
|
23701
|
+
"artifacts",
|
|
23702
|
+
"receipt",
|
|
23703
|
+
"error",
|
|
23704
|
+
"effect",
|
|
23705
|
+
"lease",
|
|
23706
|
+
"actor",
|
|
23707
|
+
"resolvedBy",
|
|
23708
|
+
"suppliedRefs",
|
|
23709
|
+
"counts"
|
|
23710
|
+
]);
|
|
23711
|
+
|
|
23623
23712
|
// plugins/kxm/src/database.ts
|
|
23624
|
-
import { createHash as
|
|
23713
|
+
import { createHash as createHash9, randomBytes } from "node:crypto";
|
|
23625
23714
|
import {
|
|
23626
23715
|
chmodSync as chmodSync3,
|
|
23627
23716
|
copyFileSync,
|
|
@@ -23774,7 +23863,7 @@ function checkIntegrity(database) {
|
|
|
23774
23863
|
}
|
|
23775
23864
|
function fileSha256(filePath) {
|
|
23776
23865
|
const bytes = readFileSync7(filePath);
|
|
23777
|
-
return `sha256:${
|
|
23866
|
+
return `sha256:${createHash9("sha256").update(bytes).digest("hex")}`;
|
|
23778
23867
|
}
|
|
23779
23868
|
function backupDatabaseFile(sourcePath, targetPath, storeId) {
|
|
23780
23869
|
const resolvedSource = resolve5(sourcePath);
|
|
@@ -23896,7 +23985,7 @@ function discoverProjectStores(projectRoot, options = {}) {
|
|
|
23896
23985
|
const stores = [];
|
|
23897
23986
|
const hubPath = options.hubDataPath ? resolve5(options.hubDataPath) : join8(root, ".kxm", "state", "kxm.db");
|
|
23898
23987
|
if (existsSync8(hubPath)) {
|
|
23899
|
-
stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion:
|
|
23988
|
+
stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: 5 });
|
|
23900
23989
|
}
|
|
23901
23990
|
const registryPath = join8(root, ".kxm", "runtime", "registry.db");
|
|
23902
23991
|
if (existsSync8(registryPath)) {
|
|
@@ -23915,7 +24004,7 @@ function discoverProjectStores(projectRoot, options = {}) {
|
|
|
23915
24004
|
stores.push({
|
|
23916
24005
|
storeId: `events:${key}`,
|
|
23917
24006
|
sourcePath: join8(eventsDir, entry.name),
|
|
23918
|
-
maxSupportedVersion:
|
|
24007
|
+
maxSupportedVersion: 6
|
|
23919
24008
|
});
|
|
23920
24009
|
}
|
|
23921
24010
|
}
|
|
@@ -23958,7 +24047,7 @@ function createBackup(options = {}) {
|
|
|
23958
24047
|
stores: backedUpStores
|
|
23959
24048
|
};
|
|
23960
24049
|
const manifestJson = JSON.stringify(manifest, null, 2) + "\n";
|
|
23961
|
-
const manifestSha256 = `sha256:${
|
|
24050
|
+
const manifestSha256 = `sha256:${createHash9("sha256").update(manifestJson, "utf8").digest("hex")}`;
|
|
23962
24051
|
manifest.manifestSha256 = manifestSha256;
|
|
23963
24052
|
const finalJson = JSON.stringify(manifest, null, 2) + "\n";
|
|
23964
24053
|
const manifestPath = join8(outDir, "manifest.json");
|
|
@@ -24002,11 +24091,11 @@ function restoreBackup(manifestPathOrDir, options = {}) {
|
|
|
24002
24091
|
`backup file ${store.backupFile} sha256 ${actualSha256} does not match manifest hash ${store.sha256}`
|
|
24003
24092
|
);
|
|
24004
24093
|
}
|
|
24005
|
-
let maxSupported =
|
|
24094
|
+
let maxSupported = 5;
|
|
24006
24095
|
if (store.storeId === "registry" || store.storeId === "binding-store") {
|
|
24007
24096
|
maxSupported = 1;
|
|
24008
24097
|
} else if (store.storeId.startsWith("events:")) {
|
|
24009
|
-
maxSupported =
|
|
24098
|
+
maxSupported = 6;
|
|
24010
24099
|
}
|
|
24011
24100
|
let targetPath = store.sourcePath;
|
|
24012
24101
|
if (options.projectRoot && manifest.projectRoot && targetPath.startsWith(manifest.projectRoot)) {
|
|
@@ -24054,7 +24143,7 @@ function projectRuntimeKey(projectRoot) {
|
|
|
24054
24143
|
canonical2 = resolve6(projectRoot);
|
|
24055
24144
|
}
|
|
24056
24145
|
const folded = process.platform === "win32" ? canonical2.toLocaleLowerCase("en-US") : canonical2;
|
|
24057
|
-
return
|
|
24146
|
+
return createHash10("sha256").update(folded, "utf8").digest("hex").slice(0, 24);
|
|
24058
24147
|
}
|
|
24059
24148
|
var KXM_REGISTRY_SCHEMA_VERSION = 1;
|
|
24060
24149
|
var REGISTRY_TABLES = {
|
|
@@ -24174,6 +24263,15 @@ var KxmRuntimeRegistry = class {
|
|
|
24174
24263
|
return this.readSupervisorRow();
|
|
24175
24264
|
}
|
|
24176
24265
|
/** Register or revalidate a project's home binding. Home Runtime is immutable. */
|
|
24266
|
+
/** All projects registered to this Runtime, for restart recovery: the
|
|
24267
|
+
* supervisor needs to reopen their contexts so pending outbox rows resume
|
|
24268
|
+
* syncing and presence keeps beating. */
|
|
24269
|
+
projectsForRuntime(homeRuntimeId) {
|
|
24270
|
+
const rows = this.database.prepare(
|
|
24271
|
+
"SELECT project_root, project_id FROM projects WHERE home_runtime_id = ? ORDER BY registered_at"
|
|
24272
|
+
).all(homeRuntimeId);
|
|
24273
|
+
return rows.map((row) => ({ projectRoot: row.project_root, projectId: row.project_id }));
|
|
24274
|
+
}
|
|
24177
24275
|
registerProject(registration) {
|
|
24178
24276
|
const projectRoot = resolve6(registration.projectRoot);
|
|
24179
24277
|
const projectKey = projectRuntimeKey(projectRoot);
|
|
@@ -24350,7 +24448,8 @@ var EVENT_STORE_TABLES = {
|
|
|
24350
24448
|
"schema",
|
|
24351
24449
|
"record"
|
|
24352
24450
|
],
|
|
24353
|
-
project_controls: ["project_id", "paused", "reason", "updated_at", "actor", "schema", "record"]
|
|
24451
|
+
project_controls: ["project_id", "paused", "reason", "updated_at", "actor", "schema", "record"],
|
|
24452
|
+
outbox: ["seq", "run_id", "sequence", "sync_event", "attempted_at", "acked_at"]
|
|
24354
24453
|
};
|
|
24355
24454
|
var KXM_EVENT_STORE_TABLE_NAMES = Object.keys(EVENT_STORE_TABLES).sort();
|
|
24356
24455
|
|
|
@@ -24867,7 +24966,7 @@ var RECORD_LIMIT = 16 * 1024 * 1024;
|
|
|
24867
24966
|
|
|
24868
24967
|
// plugins/kxm/src/prices.ts
|
|
24869
24968
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
24870
|
-
import { createHash as
|
|
24969
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
24871
24970
|
import { existsSync as existsSync10, readFileSync as readFileSync9, statSync } from "node:fs";
|
|
24872
24971
|
import { join as join10 } from "node:path";
|
|
24873
24972
|
|
|
@@ -24930,7 +25029,7 @@ function hashPriceCatalog(catalog) {
|
|
|
24930
25029
|
}))
|
|
24931
25030
|
})).sort((a, b2) => a.id.localeCompare(b2.id))
|
|
24932
25031
|
};
|
|
24933
|
-
return
|
|
25032
|
+
return createHash11("sha256").update(JSON.stringify(canonical2), "utf8").digest("hex");
|
|
24934
25033
|
}
|
|
24935
25034
|
function parsePriceCatalog(text) {
|
|
24936
25035
|
const parsed = (0, import_yaml3.parse)(text);
|
|
@@ -25736,9 +25835,144 @@ function formatRoutingReport(report2, options = {}) {
|
|
|
25736
25835
|
return lines.join("\n");
|
|
25737
25836
|
}
|
|
25738
25837
|
|
|
25838
|
+
// plugins/kxm/src/hub-binding.ts
|
|
25839
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync11, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
|
|
25840
|
+
import { homedir as homedir4 } from "node:os";
|
|
25841
|
+
import { dirname as dirname8, isAbsolute as isAbsolute5, join as join12, resolve as resolve8 } from "node:path";
|
|
25842
|
+
var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
25843
|
+
var HUB_HEALTH_PROBE_MS = 300;
|
|
25844
|
+
var HubBindingError = class extends Error {
|
|
25845
|
+
constructor(message) {
|
|
25846
|
+
super(message);
|
|
25847
|
+
this.name = "HubBindingError";
|
|
25848
|
+
}
|
|
25849
|
+
};
|
|
25850
|
+
function resolveUserStateRoot2(env) {
|
|
25851
|
+
const explicit = env.KXM_STATE_HOME?.trim();
|
|
25852
|
+
if (explicit) {
|
|
25853
|
+
if (!isAbsolute5(explicit)) throw new HubBindingError("local_state_root_not_absolute");
|
|
25854
|
+
return resolve8(explicit);
|
|
25855
|
+
}
|
|
25856
|
+
if (process.platform === "win32") {
|
|
25857
|
+
const localAppData = env.LOCALAPPDATA?.trim();
|
|
25858
|
+
const base2 = localAppData && isAbsolute5(localAppData) ? localAppData : join12(homedir4(), "AppData", "Local");
|
|
25859
|
+
return resolve8(base2, "KXM");
|
|
25860
|
+
}
|
|
25861
|
+
if (process.platform === "darwin") return resolve8(homedir4(), "Library", "Application Support", "KXM");
|
|
25862
|
+
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
25863
|
+
const base = xdgState && isAbsolute5(xdgState) ? xdgState : join12(homedir4(), ".local", "state");
|
|
25864
|
+
return resolve8(base, "kxm");
|
|
25865
|
+
}
|
|
25866
|
+
function hubBindingFile(env = process.env) {
|
|
25867
|
+
return join12(resolveUserStateRoot2(env), "hub-binding.json");
|
|
25868
|
+
}
|
|
25869
|
+
function validateHubUrl(raw) {
|
|
25870
|
+
let parsed;
|
|
25871
|
+
try {
|
|
25872
|
+
parsed = new URL(raw);
|
|
25873
|
+
} catch {
|
|
25874
|
+
throw new HubBindingError("hub_url_invalid");
|
|
25875
|
+
}
|
|
25876
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "" || raw.includes("?") || raw.includes("#")) {
|
|
25877
|
+
throw new HubBindingError("hub_url_invalid");
|
|
25878
|
+
}
|
|
25879
|
+
return parsed.href.replace(/\/$/, "");
|
|
25880
|
+
}
|
|
25881
|
+
function hubBindingScope(url) {
|
|
25882
|
+
let host;
|
|
25883
|
+
try {
|
|
25884
|
+
host = new URL(url).hostname.toLowerCase();
|
|
25885
|
+
} catch {
|
|
25886
|
+
return "remote";
|
|
25887
|
+
}
|
|
25888
|
+
if (host === "localhost" || host === "::1" || host === "[::1]" || host.endsWith(".localhost")) return "loopback";
|
|
25889
|
+
const v4 = /^127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/.exec(host);
|
|
25890
|
+
return v4 && [v4[1], v4[2], v4[3]].every((part) => Number(part) <= 255) ? "loopback" : "remote";
|
|
25891
|
+
}
|
|
25892
|
+
function isIsoTimestamp(value) {
|
|
25893
|
+
if (Number.isNaN(Date.parse(value))) return false;
|
|
25894
|
+
return value === new Date(value).toISOString();
|
|
25895
|
+
}
|
|
25896
|
+
function isAbortError(error) {
|
|
25897
|
+
return Boolean(
|
|
25898
|
+
error && typeof error === "object" && ("name" in error && error.name === "AbortError" || "code" in error && error.code === "ABORT_ERR")
|
|
25899
|
+
);
|
|
25900
|
+
}
|
|
25901
|
+
function readHubBinding(env = process.env) {
|
|
25902
|
+
const file = hubBindingFile(env);
|
|
25903
|
+
if (!existsSync12(file)) return void 0;
|
|
25904
|
+
let parsed;
|
|
25905
|
+
try {
|
|
25906
|
+
parsed = JSON.parse(readFileSync11(file, "utf8"));
|
|
25907
|
+
} catch {
|
|
25908
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
25909
|
+
}
|
|
25910
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
25911
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
25912
|
+
}
|
|
25913
|
+
const row = parsed;
|
|
25914
|
+
const keys = Object.keys(row);
|
|
25915
|
+
if (keys.length !== 3 || row.schema !== HUB_BINDING_SCHEMA || typeof row.url !== "string" || typeof row.boundAt !== "string" || !isIsoTimestamp(row.boundAt)) {
|
|
25916
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
25917
|
+
}
|
|
25918
|
+
let url;
|
|
25919
|
+
try {
|
|
25920
|
+
url = validateHubUrl(row.url);
|
|
25921
|
+
} catch {
|
|
25922
|
+
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
25923
|
+
}
|
|
25924
|
+
return { schema: HUB_BINDING_SCHEMA, url, boundAt: row.boundAt };
|
|
25925
|
+
}
|
|
25926
|
+
function writeHubBinding(record, env = process.env) {
|
|
25927
|
+
const file = hubBindingFile(env);
|
|
25928
|
+
mkdirSync8(dirname8(file), { recursive: true, mode: 448 });
|
|
25929
|
+
const temporary = join12(dirname8(file), `.hub-binding-${process.pid}.tmp`);
|
|
25930
|
+
try {
|
|
25931
|
+
writeFileSync8(temporary, `${JSON.stringify(record, null, 2)}
|
|
25932
|
+
`, { encoding: "utf8", mode: 384 });
|
|
25933
|
+
renameSync3(temporary, file);
|
|
25934
|
+
} finally {
|
|
25935
|
+
rmSync3(temporary, { force: true });
|
|
25936
|
+
}
|
|
25937
|
+
return file;
|
|
25938
|
+
}
|
|
25939
|
+
function removeHubBinding(env = process.env) {
|
|
25940
|
+
const file = hubBindingFile(env);
|
|
25941
|
+
try {
|
|
25942
|
+
rmSync3(file);
|
|
25943
|
+
return true;
|
|
25944
|
+
} catch (error) {
|
|
25945
|
+
if (error.code === "ENOENT") return false;
|
|
25946
|
+
throw error;
|
|
25947
|
+
}
|
|
25948
|
+
}
|
|
25949
|
+
async function probeHubHealth(url, fetchImpl, timeoutMs = HUB_HEALTH_PROBE_MS) {
|
|
25950
|
+
const started = Date.now();
|
|
25951
|
+
const controller = new AbortController();
|
|
25952
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
25953
|
+
try {
|
|
25954
|
+
const response = await fetchImpl(`${url}/health`, { signal: controller.signal });
|
|
25955
|
+
if (!response.ok) return { health: "unknown", probeMs: Date.now() - started };
|
|
25956
|
+
let body;
|
|
25957
|
+
try {
|
|
25958
|
+
body = await response.json();
|
|
25959
|
+
} catch {
|
|
25960
|
+
return { health: "unknown", probeMs: Date.now() - started };
|
|
25961
|
+
}
|
|
25962
|
+
if (body && typeof body === "object" && body.ok === true) {
|
|
25963
|
+
return { health: "on", probeMs: Date.now() - started };
|
|
25964
|
+
}
|
|
25965
|
+
return { health: "unknown", probeMs: Date.now() - started };
|
|
25966
|
+
} catch (error) {
|
|
25967
|
+
return { health: isAbortError(error) ? "unknown" : "off", probeMs: Date.now() - started };
|
|
25968
|
+
} finally {
|
|
25969
|
+
clearTimeout(timer);
|
|
25970
|
+
}
|
|
25971
|
+
}
|
|
25972
|
+
|
|
25739
25973
|
// plugins/kxm/src/runtime-supervisor.ts
|
|
25740
25974
|
function kxmSupervisorTokenFile(paths) {
|
|
25741
|
-
return
|
|
25975
|
+
return join13(paths.runtimeDir, "supervisor.token");
|
|
25742
25976
|
}
|
|
25743
25977
|
function readKxmSupervisorToken(paths) {
|
|
25744
25978
|
const file = kxmSupervisorTokenFile(paths);
|
|
@@ -25747,7 +25981,7 @@ function readKxmSupervisorToken(paths) {
|
|
|
25747
25981
|
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
25748
25982
|
throw runtimeError("runtime_path_invalid", file, "supervisor token file must be a regular file, not a link");
|
|
25749
25983
|
}
|
|
25750
|
-
const token =
|
|
25984
|
+
const token = readFileSync12(file, "utf8").trim();
|
|
25751
25985
|
return token.length >= 32 ? token : void 0;
|
|
25752
25986
|
}
|
|
25753
25987
|
function processAlive(pid) {
|
|
@@ -25761,11 +25995,11 @@ function processAlive(pid) {
|
|
|
25761
25995
|
var HEARTBEAT_STALE_MS = 15e3;
|
|
25762
25996
|
var SUPERVISOR_ERROR_MAX_AGE_MS = 3e4;
|
|
25763
25997
|
function supervisorErrorFile(paths) {
|
|
25764
|
-
return
|
|
25998
|
+
return join13(paths.runtimeDir, "supervisor.error");
|
|
25765
25999
|
}
|
|
25766
26000
|
function clearSupervisorError(paths) {
|
|
25767
26001
|
const file = supervisorErrorFile(paths);
|
|
25768
|
-
if (
|
|
26002
|
+
if (existsSync13(file)) rmSync4(file, { force: true });
|
|
25769
26003
|
}
|
|
25770
26004
|
function readRecentSupervisorError(paths) {
|
|
25771
26005
|
const file = supervisorErrorFile(paths);
|
|
@@ -25774,13 +26008,13 @@ function readRecentSupervisorError(paths) {
|
|
|
25774
26008
|
const ageMs = Date.now() - stat.mtimeMs;
|
|
25775
26009
|
if (ageMs > SUPERVISOR_ERROR_MAX_AGE_MS) return void 0;
|
|
25776
26010
|
try {
|
|
25777
|
-
return
|
|
26011
|
+
return readFileSync12(file, "utf8").trim();
|
|
25778
26012
|
} catch {
|
|
25779
26013
|
return void 0;
|
|
25780
26014
|
}
|
|
25781
26015
|
}
|
|
25782
26016
|
function kxmSupervisorStatus(paths) {
|
|
25783
|
-
if (!
|
|
26017
|
+
if (!existsSync13(paths.registryDb)) return { running: false };
|
|
25784
26018
|
const registry = new KxmRuntimeRegistry(paths.registryDb);
|
|
25785
26019
|
try {
|
|
25786
26020
|
const record = registry.supervisor();
|
|
@@ -25850,7 +26084,7 @@ async function ensureKxmSupervisor(options = {}) {
|
|
|
25850
26084
|
throw runtimeError("runtime_supervisor_unreachable", paths.registryDb, `runtime supervisor pid ${status.pid} is registered as running but cannot be probed`);
|
|
25851
26085
|
}
|
|
25852
26086
|
clearSupervisorError(paths);
|
|
25853
|
-
const scriptPath =
|
|
26087
|
+
const scriptPath = join13(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
|
|
25854
26088
|
const spawnImpl = options.spawnImpl ?? ((script, env) => {
|
|
25855
26089
|
const child = spawn2(process.execPath, [script], {
|
|
25856
26090
|
detached: true,
|
|
@@ -25905,36 +26139,9 @@ async function kxmRuntimeRequest(handle, method, path4, body) {
|
|
|
25905
26139
|
import { spawn as spawn3 } from "node:child_process";
|
|
25906
26140
|
import { join as join15, resolve as resolve9 } from "node:path";
|
|
25907
26141
|
|
|
25908
|
-
// plugins/kxm/src/redact.ts
|
|
25909
|
-
var SECRET_PATTERNS = [
|
|
25910
|
-
/\bsk-[A-Za-z0-9_-]{8,}\b/g,
|
|
25911
|
-
/\bsk-ant-[A-Za-z0-9_-]{8,}\b/g,
|
|
25912
|
-
/\bghp_[A-Za-z0-9_]{20,}\b/g,
|
|
25913
|
-
/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g,
|
|
25914
|
-
/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/gi,
|
|
25915
|
-
/\bBearer\s+[A-Za-z0-9._~+/=-]+\b/gi,
|
|
25916
|
-
/\bya29\.[A-Za-z0-9._~+/-]+=*/g,
|
|
25917
|
-
/\b1\/\/[A-Za-z0-9_-]+/g,
|
|
25918
|
-
/\b1\/[A-Za-z0-9_-]{20,}/g,
|
|
25919
|
-
/("?(?:access_token|refresh_token|id_token|sessionKey|session_key|claude_oauth_token|anthropicApiKey)"?\s*[:=]\s*")[^"]*(")/gi,
|
|
25920
|
-
/\bKXM_[A-Z0-9_]*(TOKEN|SECRET|KEY)[A-Z0-9_]*=\S+/gi,
|
|
25921
|
-
/\b(GITHUB_TOKEN|GH_TOKEN|KXM_AUTH_TOKEN|KXM_WORKFLOW_SIGNAL_SECRET|ANTHROPIC_API_KEY|ANTHROPIC_AUTH_TOKEN|CLAUDE_API_KEY)=\S+/gi,
|
|
25922
|
-
/\b[A-Fa-f0-9]{64}\b/g
|
|
25923
|
-
];
|
|
25924
|
-
function redactSecrets(value) {
|
|
25925
|
-
let result = value;
|
|
25926
|
-
for (const pattern of SECRET_PATTERNS) {
|
|
25927
|
-
result = result.replace(pattern, "[redacted]");
|
|
25928
|
-
}
|
|
25929
|
-
return result;
|
|
25930
|
-
}
|
|
25931
|
-
function redactStringList(values, maxItems = 32) {
|
|
25932
|
-
return values.slice(0, maxItems).map((value) => redactSecrets(value).slice(0, 500));
|
|
25933
|
-
}
|
|
25934
|
-
|
|
25935
26142
|
// plugins/kxm/src/telemetry.ts
|
|
25936
|
-
import { appendFileSync, mkdirSync as
|
|
25937
|
-
import { dirname as
|
|
26143
|
+
import { appendFileSync, mkdirSync as mkdirSync10, readFileSync as readFileSync13 } from "node:fs";
|
|
26144
|
+
import { dirname as dirname10, join as join14 } from "node:path";
|
|
25938
26145
|
var TELEMETRY_SCHEMA = "kxm.telemetry.v1";
|
|
25939
26146
|
function inferImprovementTarget(input) {
|
|
25940
26147
|
const explicit = input.env?.KXM_IMPROVE_TARGET?.trim();
|
|
@@ -25944,12 +26151,12 @@ function inferImprovementTarget(input) {
|
|
|
25944
26151
|
return project || workflowId ? "project" : "cli";
|
|
25945
26152
|
}
|
|
25946
26153
|
function appendTelemetry(path4, event) {
|
|
25947
|
-
|
|
26154
|
+
mkdirSync10(dirname10(path4), { recursive: true });
|
|
25948
26155
|
appendFileSync(path4, `${JSON.stringify(event)}
|
|
25949
26156
|
`, { encoding: "utf8", mode: 384 });
|
|
25950
26157
|
}
|
|
25951
26158
|
function telemetryPath(logsDir) {
|
|
25952
|
-
return
|
|
26159
|
+
return join14(logsDir, "telemetry.jsonl");
|
|
25953
26160
|
}
|
|
25954
26161
|
function makeTelemetryEvent(input) {
|
|
25955
26162
|
return {
|
|
@@ -25964,7 +26171,7 @@ function makeTelemetryEvent(input) {
|
|
|
25964
26171
|
function readRoutingRecords(path4) {
|
|
25965
26172
|
const records = [];
|
|
25966
26173
|
try {
|
|
25967
|
-
const raw =
|
|
26174
|
+
const raw = readFileSync13(path4, "utf8");
|
|
25968
26175
|
for (const line of raw.split(/\r?\n/)) {
|
|
25969
26176
|
if (!line.trim()) continue;
|
|
25970
26177
|
try {
|
|
@@ -26040,141 +26247,6 @@ function workerResult(worker, payload) {
|
|
|
26040
26247
|
};
|
|
26041
26248
|
}
|
|
26042
26249
|
|
|
26043
|
-
// plugins/kxm/src/hub-binding.ts
|
|
26044
|
-
import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync13, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "node:fs";
|
|
26045
|
-
import { homedir as homedir4 } from "node:os";
|
|
26046
|
-
import { dirname as dirname10, isAbsolute as isAbsolute6, join as join14, resolve as resolve8 } from "node:path";
|
|
26047
|
-
var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
|
|
26048
|
-
var HUB_HEALTH_PROBE_MS = 300;
|
|
26049
|
-
var HubBindingError = class extends Error {
|
|
26050
|
-
constructor(message) {
|
|
26051
|
-
super(message);
|
|
26052
|
-
this.name = "HubBindingError";
|
|
26053
|
-
}
|
|
26054
|
-
};
|
|
26055
|
-
function resolveUserStateRoot2(env) {
|
|
26056
|
-
const explicit = env.KXM_STATE_HOME?.trim();
|
|
26057
|
-
if (explicit) {
|
|
26058
|
-
if (!isAbsolute6(explicit)) throw new HubBindingError("local_state_root_not_absolute");
|
|
26059
|
-
return resolve8(explicit);
|
|
26060
|
-
}
|
|
26061
|
-
if (process.platform === "win32") {
|
|
26062
|
-
const localAppData = env.LOCALAPPDATA?.trim();
|
|
26063
|
-
const base2 = localAppData && isAbsolute6(localAppData) ? localAppData : join14(homedir4(), "AppData", "Local");
|
|
26064
|
-
return resolve8(base2, "KXM");
|
|
26065
|
-
}
|
|
26066
|
-
if (process.platform === "darwin") return resolve8(homedir4(), "Library", "Application Support", "KXM");
|
|
26067
|
-
const xdgState = env.XDG_STATE_HOME?.trim();
|
|
26068
|
-
const base = xdgState && isAbsolute6(xdgState) ? xdgState : join14(homedir4(), ".local", "state");
|
|
26069
|
-
return resolve8(base, "kxm");
|
|
26070
|
-
}
|
|
26071
|
-
function hubBindingFile(env = process.env) {
|
|
26072
|
-
return join14(resolveUserStateRoot2(env), "hub-binding.json");
|
|
26073
|
-
}
|
|
26074
|
-
function validateHubUrl(raw) {
|
|
26075
|
-
let parsed;
|
|
26076
|
-
try {
|
|
26077
|
-
parsed = new URL(raw);
|
|
26078
|
-
} catch {
|
|
26079
|
-
throw new HubBindingError("hub_url_invalid");
|
|
26080
|
-
}
|
|
26081
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "" || raw.includes("?") || raw.includes("#")) {
|
|
26082
|
-
throw new HubBindingError("hub_url_invalid");
|
|
26083
|
-
}
|
|
26084
|
-
return parsed.href.replace(/\/$/, "");
|
|
26085
|
-
}
|
|
26086
|
-
function hubBindingScope(url) {
|
|
26087
|
-
let host;
|
|
26088
|
-
try {
|
|
26089
|
-
host = new URL(url).hostname.toLowerCase();
|
|
26090
|
-
} catch {
|
|
26091
|
-
return "remote";
|
|
26092
|
-
}
|
|
26093
|
-
if (host === "localhost" || host === "::1" || host === "[::1]" || host.endsWith(".localhost")) return "loopback";
|
|
26094
|
-
const v4 = /^127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/.exec(host);
|
|
26095
|
-
return v4 && [v4[1], v4[2], v4[3]].every((part) => Number(part) <= 255) ? "loopback" : "remote";
|
|
26096
|
-
}
|
|
26097
|
-
function isIsoTimestamp(value) {
|
|
26098
|
-
if (Number.isNaN(Date.parse(value))) return false;
|
|
26099
|
-
return value === new Date(value).toISOString();
|
|
26100
|
-
}
|
|
26101
|
-
function isAbortError(error) {
|
|
26102
|
-
return Boolean(
|
|
26103
|
-
error && typeof error === "object" && ("name" in error && error.name === "AbortError" || "code" in error && error.code === "ABORT_ERR")
|
|
26104
|
-
);
|
|
26105
|
-
}
|
|
26106
|
-
function readHubBinding(env = process.env) {
|
|
26107
|
-
const file = hubBindingFile(env);
|
|
26108
|
-
if (!existsSync13(file)) return void 0;
|
|
26109
|
-
let parsed;
|
|
26110
|
-
try {
|
|
26111
|
-
parsed = JSON.parse(readFileSync13(file, "utf8"));
|
|
26112
|
-
} catch {
|
|
26113
|
-
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
26114
|
-
}
|
|
26115
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
26116
|
-
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
26117
|
-
}
|
|
26118
|
-
const row = parsed;
|
|
26119
|
-
const keys = Object.keys(row);
|
|
26120
|
-
if (keys.length !== 3 || row.schema !== HUB_BINDING_SCHEMA || typeof row.url !== "string" || typeof row.boundAt !== "string" || !isIsoTimestamp(row.boundAt)) {
|
|
26121
|
-
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
26122
|
-
}
|
|
26123
|
-
let url;
|
|
26124
|
-
try {
|
|
26125
|
-
url = validateHubUrl(row.url);
|
|
26126
|
-
} catch {
|
|
26127
|
-
throw new HubBindingError(`malformed hub binding at ${file}`);
|
|
26128
|
-
}
|
|
26129
|
-
return { schema: HUB_BINDING_SCHEMA, url, boundAt: row.boundAt };
|
|
26130
|
-
}
|
|
26131
|
-
function writeHubBinding(record, env = process.env) {
|
|
26132
|
-
const file = hubBindingFile(env);
|
|
26133
|
-
mkdirSync10(dirname10(file), { recursive: true, mode: 448 });
|
|
26134
|
-
const temporary = join14(dirname10(file), `.hub-binding-${process.pid}.tmp`);
|
|
26135
|
-
try {
|
|
26136
|
-
writeFileSync9(temporary, `${JSON.stringify(record, null, 2)}
|
|
26137
|
-
`, { encoding: "utf8", mode: 384 });
|
|
26138
|
-
renameSync4(temporary, file);
|
|
26139
|
-
} finally {
|
|
26140
|
-
rmSync4(temporary, { force: true });
|
|
26141
|
-
}
|
|
26142
|
-
return file;
|
|
26143
|
-
}
|
|
26144
|
-
function removeHubBinding(env = process.env) {
|
|
26145
|
-
const file = hubBindingFile(env);
|
|
26146
|
-
try {
|
|
26147
|
-
rmSync4(file);
|
|
26148
|
-
return true;
|
|
26149
|
-
} catch (error) {
|
|
26150
|
-
if (error.code === "ENOENT") return false;
|
|
26151
|
-
throw error;
|
|
26152
|
-
}
|
|
26153
|
-
}
|
|
26154
|
-
async function probeHubHealth(url, fetchImpl, timeoutMs = HUB_HEALTH_PROBE_MS) {
|
|
26155
|
-
const started = Date.now();
|
|
26156
|
-
const controller = new AbortController();
|
|
26157
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
26158
|
-
try {
|
|
26159
|
-
const response = await fetchImpl(`${url}/health`, { signal: controller.signal });
|
|
26160
|
-
if (!response.ok) return { health: "unknown", probeMs: Date.now() - started };
|
|
26161
|
-
let body;
|
|
26162
|
-
try {
|
|
26163
|
-
body = await response.json();
|
|
26164
|
-
} catch {
|
|
26165
|
-
return { health: "unknown", probeMs: Date.now() - started };
|
|
26166
|
-
}
|
|
26167
|
-
if (body && typeof body === "object" && body.ok === true) {
|
|
26168
|
-
return { health: "on", probeMs: Date.now() - started };
|
|
26169
|
-
}
|
|
26170
|
-
return { health: "unknown", probeMs: Date.now() - started };
|
|
26171
|
-
} catch (error) {
|
|
26172
|
-
return { health: isAbortError(error) ? "unknown" : "off", probeMs: Date.now() - started };
|
|
26173
|
-
} finally {
|
|
26174
|
-
clearTimeout(timer);
|
|
26175
|
-
}
|
|
26176
|
-
}
|
|
26177
|
-
|
|
26178
26250
|
// plugins/kxm/src/cli/types.ts
|
|
26179
26251
|
function spawnScript(scriptName, extraEnv = {}) {
|
|
26180
26252
|
return new Promise((resolveExit) => {
|
|
@@ -29956,7 +30028,7 @@ import { dirname as dirname15, isAbsolute as isAbsolute7, join as join24, relati
|
|
|
29956
30028
|
|
|
29957
30029
|
// plugins/kxm/src/permission.ts
|
|
29958
30030
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
29959
|
-
import { createHash as
|
|
30031
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
29960
30032
|
import { existsSync as existsSync20, mkdtempSync, mkdirSync as mkdirSync17, readFileSync as readFileSync20, rmSync as rmSync7, writeFileSync as writeFileSync16 } from "node:fs";
|
|
29961
30033
|
import { tmpdir } from "node:os";
|
|
29962
30034
|
import { dirname as dirname14, join as join23, resolve as resolve17, sep as sep3 } from "node:path";
|
|
@@ -30162,7 +30234,7 @@ function kxmProseEntries(resource) {
|
|
|
30162
30234
|
return entries;
|
|
30163
30235
|
}
|
|
30164
30236
|
function valueHash(canonicalValue) {
|
|
30165
|
-
return `sha256:${
|
|
30237
|
+
return `sha256:${createHash13("sha256").update(canonicalValue, "utf8").digest("hex")}`;
|
|
30166
30238
|
}
|
|
30167
30239
|
function rankDirection(rank, baseValue, candidateValue) {
|
|
30168
30240
|
const base = JSON.parse(baseValue);
|
|
@@ -30482,7 +30554,7 @@ function loadKxmProjectAtRevision(root, revision, options = {}) {
|
|
|
30482
30554
|
const paths = listing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
|
|
30483
30555
|
const shadow = mkdtempSync(join23(tmpdir(), "kxm-permission-base-"));
|
|
30484
30556
|
const shadowResolved = resolve17(shadow);
|
|
30485
|
-
const shadowMembersDir = `.kxm-shadow-members-${
|
|
30557
|
+
const shadowMembersDir = `.kxm-shadow-members-${createHash13("sha256").update(shadowResolved, "utf8").digest("hex").slice(0, 8)}`;
|
|
30486
30558
|
try {
|
|
30487
30559
|
for (const path4 of paths) {
|
|
30488
30560
|
const segments = path4.split("/");
|
|
@@ -33379,7 +33451,7 @@ remains Grok.
|
|
|
33379
33451
|
|
|
33380
33452
|
// plugins/kxm/src/skills.ts
|
|
33381
33453
|
var import_yaml14 = __toESM(require_dist(), 1);
|
|
33382
|
-
import { createHash as
|
|
33454
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
33383
33455
|
import { existsSync as existsSync25, mkdirSync as mkdirSync20, readdirSync as readdirSync10, readFileSync as readFileSync24, renameSync as renameSync7, rmSync as rmSync9, statSync as statSync3, writeFileSync as writeFileSync19 } from "node:fs";
|
|
33384
33456
|
import { join as join29 } from "node:path";
|
|
33385
33457
|
var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
|
|
@@ -33404,7 +33476,7 @@ var SkillLifecycleError = class extends Error {
|
|
|
33404
33476
|
}
|
|
33405
33477
|
};
|
|
33406
33478
|
function skillContentSha256(content) {
|
|
33407
|
-
return
|
|
33479
|
+
return createHash14("sha256").update(content, "utf8").digest("hex");
|
|
33408
33480
|
}
|
|
33409
33481
|
function skillIdFor(name, contentSha256) {
|
|
33410
33482
|
const slug = name.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
@@ -45044,14 +45116,14 @@ async function cmdSessionStart(runtime, options) {
|
|
|
45044
45116
|
|
|
45045
45117
|
// plugins/kxm/src/cli/system.ts
|
|
45046
45118
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
45047
|
-
import { createHash as
|
|
45119
|
+
import { createHash as createHash16 } from "node:crypto";
|
|
45048
45120
|
import { existsSync as existsSync37, mkdtempSync as mkdtempSync2, readFileSync as readFileSync36, rmSync as rmSync12 } from "node:fs";
|
|
45049
45121
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
45050
45122
|
import { join as join47, resolve as resolve28 } from "node:path";
|
|
45051
45123
|
import { createInterface as createInterface3 } from "node:readline";
|
|
45052
45124
|
|
|
45053
45125
|
// plugins/kxm/src/improve.ts
|
|
45054
|
-
import { createHash as
|
|
45126
|
+
import { createHash as createHash15 } from "node:crypto";
|
|
45055
45127
|
import { existsSync as existsSync32, mkdirSync as mkdirSync26, writeFileSync as writeFileSync24 } from "node:fs";
|
|
45056
45128
|
import { join as join42, relative as relative6, resolve as resolve25 } from "node:path";
|
|
45057
45129
|
var CANDIDATE_SCHEMA = "kxm.candidate.v1";
|
|
@@ -45199,7 +45271,7 @@ function groupRoutingRecords(records, options = {}) {
|
|
|
45199
45271
|
const isCandidate = recurrence >= minRecurrence && verifyPassRate >= minPassRate;
|
|
45200
45272
|
const candidateKind = isCandidate ? classifyCandidateKind(group.stepId, group.agentRole) : void 0;
|
|
45201
45273
|
const safeSlug = group.stepId.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 16) || "step";
|
|
45202
|
-
const keyHash =
|
|
45274
|
+
const keyHash = createHash15("sha256").update(`${group.workflowHash}:${group.stepId}:${group.agentRole}:${group.promptHash}`).digest("hex").slice(0, 10);
|
|
45203
45275
|
const candidateId = isCandidate && candidateKind ? `cand_${candidateKind.replace(/-/g, "_")}_${safeSlug}_${keyHash}` : void 0;
|
|
45204
45276
|
rows.push({
|
|
45205
45277
|
workflowHash: group.workflowHash,
|
|
@@ -46874,7 +46946,7 @@ function applyKxmPackageUpdate(runtime, notice) {
|
|
|
46874
46946
|
for (const step of planned) {
|
|
46875
46947
|
if (step.kind === "verify") {
|
|
46876
46948
|
if (!verifyReleaseAssetDigest(step.path, step.sha256)) {
|
|
46877
|
-
const actual = existsSync37(step.path) ?
|
|
46949
|
+
const actual = existsSync37(step.path) ? createHash16("sha256").update(readFileSync36(step.path)).digest("hex") : "missing";
|
|
46878
46950
|
return {
|
|
46879
46951
|
ok: false,
|
|
46880
46952
|
error: "release_digest_mismatch",
|