@kontextmind/kxm 0.7.71 → 0.7.73

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.
@@ -18360,6 +18360,8 @@ var MAX_MESSAGE_TTL_MS = 7 * 24 * 60 * 6e4;
18360
18360
  var DEFAULT_MESSAGE_RETENTION_MS = 7 * 24 * 60 * 6e4;
18361
18361
  var MAX_BODY_BYTES = 256 * 1024;
18362
18362
  var MAX_AGENT_HOST_CHARS = 64;
18363
+ var MAX_LEASE_TTL_MS = 10 * 6e4;
18364
+ var DEFAULT_LEASE_TTL_MS = 5 * 6e4;
18363
18365
  var ProtocolError = class extends Error {
18364
18366
  statusCode;
18365
18367
  code;
@@ -19396,6 +19398,37 @@ var HubClient = class {
19396
19398
  );
19397
19399
  return result.message;
19398
19400
  }
19401
+ // ----- Fenced leases over shared resources (P3) -----
19402
+ /**
19403
+ * Take or extend the lease over `resource` inside this client's project.
19404
+ *
19405
+ * The returned `fencingToken` is the whole point: hold it, present it on every
19406
+ * renewal, and present it again before committing anything shared. A hub that
19407
+ * has moved past it refuses, and the caller must stop rather than retry —
19408
+ * another holder owns the resource now. Rejects `HubHttpError` with code
19409
+ * `lease_held` when a live holder has it.
19410
+ */
19411
+ async acquireLease(resource, ttlMs) {
19412
+ return await this.request(`/v1/leases/${encodeURIComponent(resource)}/acquire`, {
19413
+ method: "POST",
19414
+ body: JSON.stringify(ttlMs === void 0 ? {} : { ttlMs })
19415
+ });
19416
+ }
19417
+ /** Extend a lease this client holds. The token never changes on renewal; a
19418
+ * `lease_superseded` or `lease_expired` refusal means it is gone. */
19419
+ async renewLease(resource, fencingToken, ttlMs) {
19420
+ return await this.request(`/v1/leases/${encodeURIComponent(resource)}/renew`, {
19421
+ method: "POST",
19422
+ body: JSON.stringify(ttlMs === void 0 ? { fencingToken } : { fencingToken, ttlMs })
19423
+ });
19424
+ }
19425
+ /** Give the resource back. */
19426
+ async releaseLease(resource, fencingToken) {
19427
+ return await this.request(`/v1/leases/${encodeURIComponent(resource)}/release`, {
19428
+ method: "POST",
19429
+ body: JSON.stringify({ fencingToken })
19430
+ });
19431
+ }
19399
19432
  async listWorkflows() {
19400
19433
  const result = await this.request("/v1/workflows");
19401
19434
  return result.runs;
@@ -19561,45 +19594,49 @@ var HubClient = class {
19561
19594
  await this.register();
19562
19595
  }
19563
19596
  async request(path4, init = {}, includeIdentity = true) {
19564
- const requestTimeoutMs = this.options.requestTimeoutMs ?? 15e3;
19565
- const timeoutSignal = AbortSignal.timeout(requestTimeoutMs);
19566
- const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
19567
- let response;
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) {
19568
19618
  try {
19569
- response = await (this.options.fetchImpl ?? fetch)(`${this.options.serverUrl.replace(/\/$/, "")}${path4}`, {
19570
- ...init,
19571
- signal,
19572
- headers: { ...this.headers(includeIdentity), ...init.headers ?? {} }
19573
- });
19574
- } catch (error) {
19575
- if (timeoutSignal.aborted) throw new Error(`request timed out after ${requestTimeoutMs}ms`);
19576
- throw error;
19577
- }
19578
- const text = await response.text();
19579
- let body = {};
19580
- if (text) {
19581
- try {
19582
- body = JSON.parse(text);
19583
- } catch {
19584
- throw new Error(`hub returned invalid JSON with HTTP ${response.status}`);
19585
- }
19586
- }
19587
- if (!response.ok) {
19588
- const extras = {};
19589
- for (const key of ["operation", "nextAction", "assignedCoordinatorName"]) {
19590
- if (typeof body[key] === "string") extras[key] = body[key];
19591
- }
19592
- throw new HubHttpError(
19593
- response.status,
19594
- String(body.error ?? `HTTP ${response.status}`),
19595
- typeof body.code === "string" ? body.code : void 0,
19596
- response.headers.get("x-request-id") ?? void 0,
19597
- Object.keys(extras).length > 0 ? extras : void 0
19598
- );
19619
+ body = JSON.parse(text);
19620
+ } catch {
19621
+ throw new Error(`hub returned invalid JSON with HTTP ${response.status}`);
19599
19622
  }
19600
- return body;
19601
19623
  }
19602
- };
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
+ }
19603
19640
 
19604
19641
  // plugins/kxm/src/hub-env.ts
19605
19642
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
@@ -22133,6 +22170,7 @@ var KxmSchemaRegistry = class {
22133
22170
  driveReceiptValidator;
22134
22171
  coordinatorValidator;
22135
22172
  intakeMessageValidator;
22173
+ syncEventValidator;
22136
22174
  constructor(schemasDir = DEFAULT_SCHEMA_DIR) {
22137
22175
  this.schemasDir = resolve3(schemasDir);
22138
22176
  this.ajv = new import__.Ajv2020({ allErrors: true, strict: true, strictRequired: false });
@@ -22149,6 +22187,7 @@ var KxmSchemaRegistry = class {
22149
22187
  const driveReceiptFile = "drive-receipt.schema.json";
22150
22188
  const coordinatorFile = "coordinator.schema.json";
22151
22189
  const intakeMessageFile = "intake-message.schema.json";
22190
+ const syncEventFile = "sync-event.schema.json";
22152
22191
  this.ajv.addSchema(readJsonObject(join6(this.schemasDir, localBindingsFile)));
22153
22192
  this.ajv.addSchema(readJsonObject(join6(this.schemasDir, templateProvenanceFile)));
22154
22193
  this.ajv.addSchema(readJsonObject(join6(this.schemasDir, initOperationFile)));
@@ -22157,6 +22196,7 @@ var KxmSchemaRegistry = class {
22157
22196
  this.ajv.addSchema(readJsonObject(join6(this.schemasDir, driveReceiptFile)));
22158
22197
  this.ajv.addSchema(readJsonObject(join6(this.schemasDir, coordinatorFile)));
22159
22198
  this.ajv.addSchema(readJsonObject(join6(this.schemasDir, intakeMessageFile)));
22199
+ this.ajv.addSchema(readJsonObject(join6(this.schemasDir, syncEventFile)));
22160
22200
  for (const [kind, definition] of Object.entries(RESOURCE_SCHEMA)) {
22161
22201
  const validator = this.ajv.getSchema(`https://schemas.kxm.dev/${definition.file}`);
22162
22202
  if (!validator) throw new Error(`schema did not compile: ${definition.file}`);
@@ -22170,6 +22210,7 @@ var KxmSchemaRegistry = class {
22170
22210
  const driveReceiptValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${driveReceiptFile}`);
22171
22211
  const coordinatorValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${coordinatorFile}`);
22172
22212
  const intakeMessageValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${intakeMessageFile}`);
22213
+ const syncEventValidator = this.ajv.getSchema(`https://schemas.kxm.dev/${syncEventFile}`);
22173
22214
  if (!localBindingsValidator) throw new Error(`schema did not compile: ${localBindingsFile}`);
22174
22215
  if (!templateProvenanceValidator) throw new Error(`schema did not compile: ${templateProvenanceFile}`);
22175
22216
  if (!initOperationValidator) throw new Error(`schema did not compile: ${initOperationFile}`);
@@ -22178,6 +22219,7 @@ var KxmSchemaRegistry = class {
22178
22219
  if (!driveReceiptValidator) throw new Error(`schema did not compile: ${driveReceiptFile}`);
22179
22220
  if (!coordinatorValidator) throw new Error(`schema did not compile: ${coordinatorFile}`);
22180
22221
  if (!intakeMessageValidator) throw new Error(`schema did not compile: ${intakeMessageFile}`);
22222
+ if (!syncEventValidator) throw new Error(`schema did not compile: ${syncEventFile}`);
22181
22223
  this.localBindingsValidator = localBindingsValidator;
22182
22224
  this.templateProvenanceValidator = templateProvenanceValidator;
22183
22225
  this.initOperationValidator = initOperationValidator;
@@ -22186,6 +22228,7 @@ var KxmSchemaRegistry = class {
22186
22228
  this.driveReceiptValidator = driveReceiptValidator;
22187
22229
  this.coordinatorValidator = coordinatorValidator;
22188
22230
  this.intakeMessageValidator = intakeMessageValidator;
22231
+ this.syncEventValidator = syncEventValidator;
22189
22232
  }
22190
22233
  validate(kind, value, file) {
22191
22234
  const definition = RESOURCE_SCHEMA[kind];
@@ -23224,12 +23267,12 @@ function planKxmInitialization(start = process.cwd(), options = {}) {
23224
23267
 
23225
23268
  // plugins/kxm/src/runtime-supervisor.ts
23226
23269
  import { spawn as spawn2 } from "node:child_process";
23227
- import { createHash as createHash11, createHmac, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
23228
- import { chmodSync as chmodSync4, existsSync as existsSync12, lstatSync as lstatSync6, mkdirSync as mkdirSync8, readFileSync as readFileSync11, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
23229
- import { dirname as dirname8, isAbsolute as isAbsolute5, join as join12 } from "node:path";
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";
23230
23273
 
23231
23274
  // plugins/kxm/src/runtime-store.ts
23232
- import { createHash as createHash9, randomUUID as randomUUID4 } from "node:crypto";
23275
+ import { createHash as createHash10, randomUUID as randomUUID4 } from "node:crypto";
23233
23276
  import { existsSync as existsSync9, lstatSync as lstatSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync8, realpathSync as realpathSync3, writeFileSync as writeFileSync6 } from "node:fs";
23234
23277
  import { dirname as dirname7, join as join9, resolve as resolve6 } from "node:path";
23235
23278
 
@@ -23586,8 +23629,88 @@ function writeKxmLocalBindings(projectRoot, projectId, repositories, options = {
23586
23629
  return { file, written: true, record };
23587
23630
  }
23588
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
+
23589
23712
  // plugins/kxm/src/database.ts
23590
- import { createHash as createHash8, randomBytes } from "node:crypto";
23713
+ import { createHash as createHash9, randomBytes } from "node:crypto";
23591
23714
  import {
23592
23715
  chmodSync as chmodSync3,
23593
23716
  copyFileSync,
@@ -23740,7 +23863,7 @@ function checkIntegrity(database) {
23740
23863
  }
23741
23864
  function fileSha256(filePath) {
23742
23865
  const bytes = readFileSync7(filePath);
23743
- return `sha256:${createHash8("sha256").update(bytes).digest("hex")}`;
23866
+ return `sha256:${createHash9("sha256").update(bytes).digest("hex")}`;
23744
23867
  }
23745
23868
  function backupDatabaseFile(sourcePath, targetPath, storeId) {
23746
23869
  const resolvedSource = resolve5(sourcePath);
@@ -23862,7 +23985,7 @@ function discoverProjectStores(projectRoot, options = {}) {
23862
23985
  const stores = [];
23863
23986
  const hubPath = options.hubDataPath ? resolve5(options.hubDataPath) : join8(root, ".kxm", "state", "kxm.db");
23864
23987
  if (existsSync8(hubPath)) {
23865
- stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: 3 });
23988
+ stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: 5 });
23866
23989
  }
23867
23990
  const registryPath = join8(root, ".kxm", "runtime", "registry.db");
23868
23991
  if (existsSync8(registryPath)) {
@@ -23881,7 +24004,7 @@ function discoverProjectStores(projectRoot, options = {}) {
23881
24004
  stores.push({
23882
24005
  storeId: `events:${key}`,
23883
24006
  sourcePath: join8(eventsDir, entry.name),
23884
- maxSupportedVersion: 4
24007
+ maxSupportedVersion: 6
23885
24008
  });
23886
24009
  }
23887
24010
  }
@@ -23924,7 +24047,7 @@ function createBackup(options = {}) {
23924
24047
  stores: backedUpStores
23925
24048
  };
23926
24049
  const manifestJson = JSON.stringify(manifest, null, 2) + "\n";
23927
- const manifestSha256 = `sha256:${createHash8("sha256").update(manifestJson, "utf8").digest("hex")}`;
24050
+ const manifestSha256 = `sha256:${createHash9("sha256").update(manifestJson, "utf8").digest("hex")}`;
23928
24051
  manifest.manifestSha256 = manifestSha256;
23929
24052
  const finalJson = JSON.stringify(manifest, null, 2) + "\n";
23930
24053
  const manifestPath = join8(outDir, "manifest.json");
@@ -23968,11 +24091,11 @@ function restoreBackup(manifestPathOrDir, options = {}) {
23968
24091
  `backup file ${store.backupFile} sha256 ${actualSha256} does not match manifest hash ${store.sha256}`
23969
24092
  );
23970
24093
  }
23971
- let maxSupported = 3;
24094
+ let maxSupported = 5;
23972
24095
  if (store.storeId === "registry" || store.storeId === "binding-store") {
23973
24096
  maxSupported = 1;
23974
24097
  } else if (store.storeId.startsWith("events:")) {
23975
- maxSupported = 5;
24098
+ maxSupported = 6;
23976
24099
  }
23977
24100
  let targetPath = store.sourcePath;
23978
24101
  if (options.projectRoot && manifest.projectRoot && targetPath.startsWith(manifest.projectRoot)) {
@@ -24020,7 +24143,7 @@ function projectRuntimeKey(projectRoot) {
24020
24143
  canonical2 = resolve6(projectRoot);
24021
24144
  }
24022
24145
  const folded = process.platform === "win32" ? canonical2.toLocaleLowerCase("en-US") : canonical2;
24023
- return createHash9("sha256").update(folded, "utf8").digest("hex").slice(0, 24);
24146
+ return createHash10("sha256").update(folded, "utf8").digest("hex").slice(0, 24);
24024
24147
  }
24025
24148
  var KXM_REGISTRY_SCHEMA_VERSION = 1;
24026
24149
  var REGISTRY_TABLES = {
@@ -24140,6 +24263,15 @@ var KxmRuntimeRegistry = class {
24140
24263
  return this.readSupervisorRow();
24141
24264
  }
24142
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
+ }
24143
24275
  registerProject(registration) {
24144
24276
  const projectRoot = resolve6(registration.projectRoot);
24145
24277
  const projectKey = projectRuntimeKey(projectRoot);
@@ -24316,7 +24448,8 @@ var EVENT_STORE_TABLES = {
24316
24448
  "schema",
24317
24449
  "record"
24318
24450
  ],
24319
- 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"]
24320
24453
  };
24321
24454
  var KXM_EVENT_STORE_TABLE_NAMES = Object.keys(EVENT_STORE_TABLES).sort();
24322
24455
 
@@ -24833,7 +24966,7 @@ var RECORD_LIMIT = 16 * 1024 * 1024;
24833
24966
 
24834
24967
  // plugins/kxm/src/prices.ts
24835
24968
  var import_yaml3 = __toESM(require_dist(), 1);
24836
- import { createHash as createHash10 } from "node:crypto";
24969
+ import { createHash as createHash11 } from "node:crypto";
24837
24970
  import { existsSync as existsSync10, readFileSync as readFileSync9, statSync } from "node:fs";
24838
24971
  import { join as join10 } from "node:path";
24839
24972
 
@@ -24896,7 +25029,7 @@ function hashPriceCatalog(catalog) {
24896
25029
  }))
24897
25030
  })).sort((a, b2) => a.id.localeCompare(b2.id))
24898
25031
  };
24899
- return createHash10("sha256").update(JSON.stringify(canonical2), "utf8").digest("hex");
25032
+ return createHash11("sha256").update(JSON.stringify(canonical2), "utf8").digest("hex");
24900
25033
  }
24901
25034
  function parsePriceCatalog(text) {
24902
25035
  const parsed = (0, import_yaml3.parse)(text);
@@ -25702,9 +25835,144 @@ function formatRoutingReport(report2, options = {}) {
25702
25835
  return lines.join("\n");
25703
25836
  }
25704
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
+
25705
25973
  // plugins/kxm/src/runtime-supervisor.ts
25706
25974
  function kxmSupervisorTokenFile(paths) {
25707
- return join12(paths.runtimeDir, "supervisor.token");
25975
+ return join13(paths.runtimeDir, "supervisor.token");
25708
25976
  }
25709
25977
  function readKxmSupervisorToken(paths) {
25710
25978
  const file = kxmSupervisorTokenFile(paths);
@@ -25713,7 +25981,7 @@ function readKxmSupervisorToken(paths) {
25713
25981
  if (stat.isSymbolicLink() || !stat.isFile()) {
25714
25982
  throw runtimeError("runtime_path_invalid", file, "supervisor token file must be a regular file, not a link");
25715
25983
  }
25716
- const token = readFileSync11(file, "utf8").trim();
25984
+ const token = readFileSync12(file, "utf8").trim();
25717
25985
  return token.length >= 32 ? token : void 0;
25718
25986
  }
25719
25987
  function processAlive(pid) {
@@ -25727,11 +25995,11 @@ function processAlive(pid) {
25727
25995
  var HEARTBEAT_STALE_MS = 15e3;
25728
25996
  var SUPERVISOR_ERROR_MAX_AGE_MS = 3e4;
25729
25997
  function supervisorErrorFile(paths) {
25730
- return join12(paths.runtimeDir, "supervisor.error");
25998
+ return join13(paths.runtimeDir, "supervisor.error");
25731
25999
  }
25732
26000
  function clearSupervisorError(paths) {
25733
26001
  const file = supervisorErrorFile(paths);
25734
- if (existsSync12(file)) rmSync3(file, { force: true });
26002
+ if (existsSync13(file)) rmSync4(file, { force: true });
25735
26003
  }
25736
26004
  function readRecentSupervisorError(paths) {
25737
26005
  const file = supervisorErrorFile(paths);
@@ -25740,13 +26008,13 @@ function readRecentSupervisorError(paths) {
25740
26008
  const ageMs = Date.now() - stat.mtimeMs;
25741
26009
  if (ageMs > SUPERVISOR_ERROR_MAX_AGE_MS) return void 0;
25742
26010
  try {
25743
- return readFileSync11(file, "utf8").trim();
26011
+ return readFileSync12(file, "utf8").trim();
25744
26012
  } catch {
25745
26013
  return void 0;
25746
26014
  }
25747
26015
  }
25748
26016
  function kxmSupervisorStatus(paths) {
25749
- if (!existsSync12(paths.registryDb)) return { running: false };
26017
+ if (!existsSync13(paths.registryDb)) return { running: false };
25750
26018
  const registry = new KxmRuntimeRegistry(paths.registryDb);
25751
26019
  try {
25752
26020
  const record = registry.supervisor();
@@ -25816,7 +26084,7 @@ async function ensureKxmSupervisor(options = {}) {
25816
26084
  throw runtimeError("runtime_supervisor_unreachable", paths.registryDb, `runtime supervisor pid ${status.pid} is registered as running but cannot be probed`);
25817
26085
  }
25818
26086
  clearSupervisorError(paths);
25819
- const scriptPath = join12(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
26087
+ const scriptPath = join13(findKxmRepoRoot(import.meta.url), "scripts", "kxm-runtime-supervisor.mjs");
25820
26088
  const spawnImpl = options.spawnImpl ?? ((script, env) => {
25821
26089
  const child = spawn2(process.execPath, [script], {
25822
26090
  detached: true,
@@ -25871,36 +26139,9 @@ async function kxmRuntimeRequest(handle, method, path4, body) {
25871
26139
  import { spawn as spawn3 } from "node:child_process";
25872
26140
  import { join as join15, resolve as resolve9 } from "node:path";
25873
26141
 
25874
- // plugins/kxm/src/redact.ts
25875
- var SECRET_PATTERNS = [
25876
- /\bsk-[A-Za-z0-9_-]{8,}\b/g,
25877
- /\bsk-ant-[A-Za-z0-9_-]{8,}\b/g,
25878
- /\bghp_[A-Za-z0-9_]{20,}\b/g,
25879
- /\bgithub_pat_[A-Za-z0-9_]{20,}\b/g,
25880
- /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/gi,
25881
- /\bBearer\s+[A-Za-z0-9._~+/=-]+\b/gi,
25882
- /\bya29\.[A-Za-z0-9._~+/-]+=*/g,
25883
- /\b1\/\/[A-Za-z0-9_-]+/g,
25884
- /\b1\/[A-Za-z0-9_-]{20,}/g,
25885
- /("?(?:access_token|refresh_token|id_token|sessionKey|session_key|claude_oauth_token|anthropicApiKey)"?\s*[:=]\s*")[^"]*(")/gi,
25886
- /\bKXM_[A-Z0-9_]*(TOKEN|SECRET|KEY)[A-Z0-9_]*=\S+/gi,
25887
- /\b(GITHUB_TOKEN|GH_TOKEN|KXM_AUTH_TOKEN|KXM_WORKFLOW_SIGNAL_SECRET|ANTHROPIC_API_KEY|ANTHROPIC_AUTH_TOKEN|CLAUDE_API_KEY)=\S+/gi,
25888
- /\b[A-Fa-f0-9]{64}\b/g
25889
- ];
25890
- function redactSecrets(value) {
25891
- let result = value;
25892
- for (const pattern of SECRET_PATTERNS) {
25893
- result = result.replace(pattern, "[redacted]");
25894
- }
25895
- return result;
25896
- }
25897
- function redactStringList(values, maxItems = 32) {
25898
- return values.slice(0, maxItems).map((value) => redactSecrets(value).slice(0, 500));
25899
- }
25900
-
25901
26142
  // plugins/kxm/src/telemetry.ts
25902
- import { appendFileSync, mkdirSync as mkdirSync9, readFileSync as readFileSync12 } from "node:fs";
25903
- import { dirname as dirname9, join as join13 } from "node:path";
26143
+ import { appendFileSync, mkdirSync as mkdirSync10, readFileSync as readFileSync13 } from "node:fs";
26144
+ import { dirname as dirname10, join as join14 } from "node:path";
25904
26145
  var TELEMETRY_SCHEMA = "kxm.telemetry.v1";
25905
26146
  function inferImprovementTarget(input) {
25906
26147
  const explicit = input.env?.KXM_IMPROVE_TARGET?.trim();
@@ -25910,12 +26151,12 @@ function inferImprovementTarget(input) {
25910
26151
  return project || workflowId ? "project" : "cli";
25911
26152
  }
25912
26153
  function appendTelemetry(path4, event) {
25913
- mkdirSync9(dirname9(path4), { recursive: true });
26154
+ mkdirSync10(dirname10(path4), { recursive: true });
25914
26155
  appendFileSync(path4, `${JSON.stringify(event)}
25915
26156
  `, { encoding: "utf8", mode: 384 });
25916
26157
  }
25917
26158
  function telemetryPath(logsDir) {
25918
- return join13(logsDir, "telemetry.jsonl");
26159
+ return join14(logsDir, "telemetry.jsonl");
25919
26160
  }
25920
26161
  function makeTelemetryEvent(input) {
25921
26162
  return {
@@ -25930,7 +26171,7 @@ function makeTelemetryEvent(input) {
25930
26171
  function readRoutingRecords(path4) {
25931
26172
  const records = [];
25932
26173
  try {
25933
- const raw = readFileSync12(path4, "utf8");
26174
+ const raw = readFileSync13(path4, "utf8");
25934
26175
  for (const line of raw.split(/\r?\n/)) {
25935
26176
  if (!line.trim()) continue;
25936
26177
  try {
@@ -26006,141 +26247,6 @@ function workerResult(worker, payload) {
26006
26247
  };
26007
26248
  }
26008
26249
 
26009
- // plugins/kxm/src/hub-binding.ts
26010
- import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync13, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "node:fs";
26011
- import { homedir as homedir4 } from "node:os";
26012
- import { dirname as dirname10, isAbsolute as isAbsolute6, join as join14, resolve as resolve8 } from "node:path";
26013
- var HUB_BINDING_SCHEMA = "kxm.hub-binding.v1";
26014
- var HUB_HEALTH_PROBE_MS = 300;
26015
- var HubBindingError = class extends Error {
26016
- constructor(message) {
26017
- super(message);
26018
- this.name = "HubBindingError";
26019
- }
26020
- };
26021
- function resolveUserStateRoot2(env) {
26022
- const explicit = env.KXM_STATE_HOME?.trim();
26023
- if (explicit) {
26024
- if (!isAbsolute6(explicit)) throw new HubBindingError("local_state_root_not_absolute");
26025
- return resolve8(explicit);
26026
- }
26027
- if (process.platform === "win32") {
26028
- const localAppData = env.LOCALAPPDATA?.trim();
26029
- const base2 = localAppData && isAbsolute6(localAppData) ? localAppData : join14(homedir4(), "AppData", "Local");
26030
- return resolve8(base2, "KXM");
26031
- }
26032
- if (process.platform === "darwin") return resolve8(homedir4(), "Library", "Application Support", "KXM");
26033
- const xdgState = env.XDG_STATE_HOME?.trim();
26034
- const base = xdgState && isAbsolute6(xdgState) ? xdgState : join14(homedir4(), ".local", "state");
26035
- return resolve8(base, "kxm");
26036
- }
26037
- function hubBindingFile(env = process.env) {
26038
- return join14(resolveUserStateRoot2(env), "hub-binding.json");
26039
- }
26040
- function validateHubUrl(raw) {
26041
- let parsed;
26042
- try {
26043
- parsed = new URL(raw);
26044
- } catch {
26045
- throw new HubBindingError("hub_url_invalid");
26046
- }
26047
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:" || parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "" || raw.includes("?") || raw.includes("#")) {
26048
- throw new HubBindingError("hub_url_invalid");
26049
- }
26050
- return parsed.href.replace(/\/$/, "");
26051
- }
26052
- function hubBindingScope(url) {
26053
- let host;
26054
- try {
26055
- host = new URL(url).hostname.toLowerCase();
26056
- } catch {
26057
- return "remote";
26058
- }
26059
- if (host === "localhost" || host === "::1" || host === "[::1]" || host.endsWith(".localhost")) return "loopback";
26060
- const v4 = /^127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/.exec(host);
26061
- return v4 && [v4[1], v4[2], v4[3]].every((part) => Number(part) <= 255) ? "loopback" : "remote";
26062
- }
26063
- function isIsoTimestamp(value) {
26064
- if (Number.isNaN(Date.parse(value))) return false;
26065
- return value === new Date(value).toISOString();
26066
- }
26067
- function isAbortError(error) {
26068
- return Boolean(
26069
- error && typeof error === "object" && ("name" in error && error.name === "AbortError" || "code" in error && error.code === "ABORT_ERR")
26070
- );
26071
- }
26072
- function readHubBinding(env = process.env) {
26073
- const file = hubBindingFile(env);
26074
- if (!existsSync13(file)) return void 0;
26075
- let parsed;
26076
- try {
26077
- parsed = JSON.parse(readFileSync13(file, "utf8"));
26078
- } catch {
26079
- throw new HubBindingError(`malformed hub binding at ${file}`);
26080
- }
26081
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
26082
- throw new HubBindingError(`malformed hub binding at ${file}`);
26083
- }
26084
- const row = parsed;
26085
- const keys = Object.keys(row);
26086
- if (keys.length !== 3 || row.schema !== HUB_BINDING_SCHEMA || typeof row.url !== "string" || typeof row.boundAt !== "string" || !isIsoTimestamp(row.boundAt)) {
26087
- throw new HubBindingError(`malformed hub binding at ${file}`);
26088
- }
26089
- let url;
26090
- try {
26091
- url = validateHubUrl(row.url);
26092
- } catch {
26093
- throw new HubBindingError(`malformed hub binding at ${file}`);
26094
- }
26095
- return { schema: HUB_BINDING_SCHEMA, url, boundAt: row.boundAt };
26096
- }
26097
- function writeHubBinding(record, env = process.env) {
26098
- const file = hubBindingFile(env);
26099
- mkdirSync10(dirname10(file), { recursive: true, mode: 448 });
26100
- const temporary = join14(dirname10(file), `.hub-binding-${process.pid}.tmp`);
26101
- try {
26102
- writeFileSync9(temporary, `${JSON.stringify(record, null, 2)}
26103
- `, { encoding: "utf8", mode: 384 });
26104
- renameSync4(temporary, file);
26105
- } finally {
26106
- rmSync4(temporary, { force: true });
26107
- }
26108
- return file;
26109
- }
26110
- function removeHubBinding(env = process.env) {
26111
- const file = hubBindingFile(env);
26112
- try {
26113
- rmSync4(file);
26114
- return true;
26115
- } catch (error) {
26116
- if (error.code === "ENOENT") return false;
26117
- throw error;
26118
- }
26119
- }
26120
- async function probeHubHealth(url, fetchImpl, timeoutMs = HUB_HEALTH_PROBE_MS) {
26121
- const started = Date.now();
26122
- const controller = new AbortController();
26123
- const timer = setTimeout(() => controller.abort(), timeoutMs);
26124
- try {
26125
- const response = await fetchImpl(`${url}/health`, { signal: controller.signal });
26126
- if (!response.ok) return { health: "unknown", probeMs: Date.now() - started };
26127
- let body;
26128
- try {
26129
- body = await response.json();
26130
- } catch {
26131
- return { health: "unknown", probeMs: Date.now() - started };
26132
- }
26133
- if (body && typeof body === "object" && body.ok === true) {
26134
- return { health: "on", probeMs: Date.now() - started };
26135
- }
26136
- return { health: "unknown", probeMs: Date.now() - started };
26137
- } catch (error) {
26138
- return { health: isAbortError(error) ? "unknown" : "off", probeMs: Date.now() - started };
26139
- } finally {
26140
- clearTimeout(timer);
26141
- }
26142
- }
26143
-
26144
26250
  // plugins/kxm/src/cli/types.ts
26145
26251
  function spawnScript(scriptName, extraEnv = {}) {
26146
26252
  return new Promise((resolveExit) => {
@@ -29922,7 +30028,7 @@ import { dirname as dirname15, isAbsolute as isAbsolute7, join as join24, relati
29922
30028
 
29923
30029
  // plugins/kxm/src/permission.ts
29924
30030
  import { spawnSync as spawnSync4 } from "node:child_process";
29925
- import { createHash as createHash12 } from "node:crypto";
30031
+ import { createHash as createHash13 } from "node:crypto";
29926
30032
  import { existsSync as existsSync20, mkdtempSync, mkdirSync as mkdirSync17, readFileSync as readFileSync20, rmSync as rmSync7, writeFileSync as writeFileSync16 } from "node:fs";
29927
30033
  import { tmpdir } from "node:os";
29928
30034
  import { dirname as dirname14, join as join23, resolve as resolve17, sep as sep3 } from "node:path";
@@ -30128,7 +30234,7 @@ function kxmProseEntries(resource) {
30128
30234
  return entries;
30129
30235
  }
30130
30236
  function valueHash(canonicalValue) {
30131
- return `sha256:${createHash12("sha256").update(canonicalValue, "utf8").digest("hex")}`;
30237
+ return `sha256:${createHash13("sha256").update(canonicalValue, "utf8").digest("hex")}`;
30132
30238
  }
30133
30239
  function rankDirection(rank, baseValue, candidateValue) {
30134
30240
  const base = JSON.parse(baseValue);
@@ -30448,7 +30554,7 @@ function loadKxmProjectAtRevision(root, revision, options = {}) {
30448
30554
  const paths = listing.split("\0").filter((line) => line.length > 0 && (line.startsWith(".kxm/") || line.includes("/.kxm/")));
30449
30555
  const shadow = mkdtempSync(join23(tmpdir(), "kxm-permission-base-"));
30450
30556
  const shadowResolved = resolve17(shadow);
30451
- const shadowMembersDir = `.kxm-shadow-members-${createHash12("sha256").update(shadowResolved, "utf8").digest("hex").slice(0, 8)}`;
30557
+ const shadowMembersDir = `.kxm-shadow-members-${createHash13("sha256").update(shadowResolved, "utf8").digest("hex").slice(0, 8)}`;
30452
30558
  try {
30453
30559
  for (const path4 of paths) {
30454
30560
  const segments = path4.split("/");
@@ -33345,7 +33451,7 @@ remains Grok.
33345
33451
 
33346
33452
  // plugins/kxm/src/skills.ts
33347
33453
  var import_yaml14 = __toESM(require_dist(), 1);
33348
- import { createHash as createHash13 } from "node:crypto";
33454
+ import { createHash as createHash14 } from "node:crypto";
33349
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";
33350
33456
  import { join as join29 } from "node:path";
33351
33457
  var SKILL_CANDIDATE_SCHEMA = "kxm.skill-candidate.v1";
@@ -33370,7 +33476,7 @@ var SkillLifecycleError = class extends Error {
33370
33476
  }
33371
33477
  };
33372
33478
  function skillContentSha256(content) {
33373
- return createHash13("sha256").update(content, "utf8").digest("hex");
33479
+ return createHash14("sha256").update(content, "utf8").digest("hex");
33374
33480
  }
33375
33481
  function skillIdFor(name, contentSha256) {
33376
33482
  const slug = name.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
@@ -42603,6 +42709,12 @@ function slugifyBranchPart(text, maxLength = 40) {
42603
42709
  if (cleaned.length <= maxLength) return cleaned;
42604
42710
  return cleaned.slice(0, maxLength).replace(/-+$/, "");
42605
42711
  }
42712
+ var SHARED_EFFECT_KINDS = Object.freeze([
42713
+ "git-push",
42714
+ "pr-create",
42715
+ "tracker-issue",
42716
+ "webhook"
42717
+ ]);
42606
42718
 
42607
42719
  // plugins/kxm/src/local-snapshot.ts
42608
42720
  import { existsSync as existsSync26, readdirSync as readdirSync11, readFileSync as readFileSync26 } from "node:fs";
@@ -45004,14 +45116,14 @@ async function cmdSessionStart(runtime, options) {
45004
45116
 
45005
45117
  // plugins/kxm/src/cli/system.ts
45006
45118
  import { spawnSync as spawnSync8 } from "node:child_process";
45007
- import { createHash as createHash15 } from "node:crypto";
45119
+ import { createHash as createHash16 } from "node:crypto";
45008
45120
  import { existsSync as existsSync37, mkdtempSync as mkdtempSync2, readFileSync as readFileSync36, rmSync as rmSync12 } from "node:fs";
45009
45121
  import { tmpdir as tmpdir2 } from "node:os";
45010
45122
  import { join as join47, resolve as resolve28 } from "node:path";
45011
45123
  import { createInterface as createInterface3 } from "node:readline";
45012
45124
 
45013
45125
  // plugins/kxm/src/improve.ts
45014
- import { createHash as createHash14 } from "node:crypto";
45126
+ import { createHash as createHash15 } from "node:crypto";
45015
45127
  import { existsSync as existsSync32, mkdirSync as mkdirSync26, writeFileSync as writeFileSync24 } from "node:fs";
45016
45128
  import { join as join42, relative as relative6, resolve as resolve25 } from "node:path";
45017
45129
  var CANDIDATE_SCHEMA = "kxm.candidate.v1";
@@ -45159,7 +45271,7 @@ function groupRoutingRecords(records, options = {}) {
45159
45271
  const isCandidate = recurrence >= minRecurrence && verifyPassRate >= minPassRate;
45160
45272
  const candidateKind = isCandidate ? classifyCandidateKind(group.stepId, group.agentRole) : void 0;
45161
45273
  const safeSlug = group.stepId.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 16) || "step";
45162
- const keyHash = createHash14("sha256").update(`${group.workflowHash}:${group.stepId}:${group.agentRole}:${group.promptHash}`).digest("hex").slice(0, 10);
45274
+ const keyHash = createHash15("sha256").update(`${group.workflowHash}:${group.stepId}:${group.agentRole}:${group.promptHash}`).digest("hex").slice(0, 10);
45163
45275
  const candidateId = isCandidate && candidateKind ? `cand_${candidateKind.replace(/-/g, "_")}_${safeSlug}_${keyHash}` : void 0;
45164
45276
  rows.push({
45165
45277
  workflowHash: group.workflowHash,
@@ -46834,7 +46946,7 @@ function applyKxmPackageUpdate(runtime, notice) {
46834
46946
  for (const step of planned) {
46835
46947
  if (step.kind === "verify") {
46836
46948
  if (!verifyReleaseAssetDigest(step.path, step.sha256)) {
46837
- const actual = existsSync37(step.path) ? createHash15("sha256").update(readFileSync36(step.path)).digest("hex") : "missing";
46949
+ const actual = existsSync37(step.path) ? createHash16("sha256").update(readFileSync36(step.path)).digest("hex") : "missing";
46838
46950
  return {
46839
46951
  ok: false,
46840
46952
  error: "release_digest_mismatch",