@kontextmind/kxm 0.7.78 → 0.7.80

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.
@@ -18326,20 +18326,30 @@ function restoreDatabaseFile(backupPath, targetPath, storeId, expectedSchemaVers
18326
18326
  integrity: "ok"
18327
18327
  };
18328
18328
  }
18329
+ var KXM_BACKUP_CEILINGS = {
18330
+ "hub-store": 5,
18331
+ registry: 1,
18332
+ "binding-store": 1,
18333
+ events: 7
18334
+ };
18335
+ function kxmBackupCeiling(storeId) {
18336
+ if (storeId.startsWith("events:")) return KXM_BACKUP_CEILINGS.events;
18337
+ return KXM_BACKUP_CEILINGS[storeId] ?? KXM_BACKUP_CEILINGS["hub-store"];
18338
+ }
18329
18339
  function discoverProjectStores(projectRoot, options = {}) {
18330
18340
  const root = resolve3(projectRoot);
18331
18341
  const stores = [];
18332
18342
  const hubPath = options.hubDataPath ? resolve3(options.hubDataPath) : join4(root, ".kxm", "state", "kxm.db");
18333
18343
  if (existsSync4(hubPath)) {
18334
- stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: 5 });
18344
+ stores.push({ storeId: "hub-store", sourcePath: hubPath, maxSupportedVersion: kxmBackupCeiling("hub-store") });
18335
18345
  }
18336
18346
  const registryPath = join4(root, ".kxm", "runtime", "registry.db");
18337
18347
  if (existsSync4(registryPath)) {
18338
- stores.push({ storeId: "registry", sourcePath: registryPath, maxSupportedVersion: 1 });
18348
+ stores.push({ storeId: "registry", sourcePath: registryPath, maxSupportedVersion: kxmBackupCeiling("registry") });
18339
18349
  }
18340
18350
  const bindingsPath = join4(root, ".kxm", "runtime", "bindings.db");
18341
18351
  if (existsSync4(bindingsPath)) {
18342
- stores.push({ storeId: "binding-store", sourcePath: bindingsPath, maxSupportedVersion: 1 });
18352
+ stores.push({ storeId: "binding-store", sourcePath: bindingsPath, maxSupportedVersion: kxmBackupCeiling("binding-store") });
18343
18353
  }
18344
18354
  const eventsDir = join4(root, ".kxm", "runtime", "events");
18345
18355
  if (existsSync4(eventsDir)) {
@@ -18350,7 +18360,7 @@ function discoverProjectStores(projectRoot, options = {}) {
18350
18360
  stores.push({
18351
18361
  storeId: `events:${key}`,
18352
18362
  sourcePath: join4(eventsDir, entry.name),
18353
- maxSupportedVersion: 6
18363
+ maxSupportedVersion: kxmBackupCeiling(`events:${key}`)
18354
18364
  });
18355
18365
  }
18356
18366
  }
@@ -18437,12 +18447,7 @@ function restoreBackup(manifestPathOrDir, options = {}) {
18437
18447
  `backup file ${store.backupFile} sha256 ${actualSha256} does not match manifest hash ${store.sha256}`
18438
18448
  );
18439
18449
  }
18440
- let maxSupported = 5;
18441
- if (store.storeId === "registry" || store.storeId === "binding-store") {
18442
- maxSupported = 1;
18443
- } else if (store.storeId.startsWith("events:")) {
18444
- maxSupported = 6;
18445
- }
18450
+ const maxSupported = kxmBackupCeiling(store.storeId);
18446
18451
  let targetPath = store.sourcePath;
18447
18452
  if (options.projectRoot && manifest.projectRoot && targetPath.startsWith(manifest.projectRoot)) {
18448
18453
  const rel = targetPath.slice(manifest.projectRoot.length).replace(/^[\\/]+/, "");
@@ -18720,7 +18725,7 @@ function verifyKxmDriveReceipt(receipt, events, foldedStatus, binding) {
18720
18725
  if (reasons.length === 0) return { verified: true };
18721
18726
  return { verified: false, divergence: reasons.join("; ") };
18722
18727
  }
18723
- var KXM_EVENT_STORE_SCHEMA_VERSION = 6;
18728
+ var KXM_EVENT_STORE_SCHEMA_VERSION = 7;
18724
18729
  var KXM_DRIVE_RECEIPT_SCHEMA = "kxm.drive-receipt.v1";
18725
18730
  var DRIVE_RECEIPT_MAX_BYTES = 8 * 1024;
18726
18731
  var EVENT_STORE_TABLES = {
@@ -18826,7 +18831,17 @@ var EVENT_STORE_TABLES = {
18826
18831
  "record"
18827
18832
  ],
18828
18833
  project_controls: ["project_id", "paused", "reason", "updated_at", "actor", "schema", "record"],
18829
- outbox: ["seq", "run_id", "sequence", "sync_event", "attempted_at", "acked_at"]
18834
+ outbox: [
18835
+ "seq",
18836
+ "run_id",
18837
+ "sequence",
18838
+ "sync_event",
18839
+ "attempted_at",
18840
+ "attempt_count",
18841
+ "acked_at",
18842
+ "refused_code",
18843
+ "refused_at"
18844
+ ]
18830
18845
  };
18831
18846
  var KXM_EVENT_STORE_TABLE_NAMES = Object.keys(EVENT_STORE_TABLES).sort();
18832
18847
  var EVENT_STORE_SCHEMA = `
@@ -19020,10 +19035,14 @@ CREATE TABLE IF NOT EXISTS outbox (
19020
19035
  sequence INTEGER NOT NULL,
19021
19036
  sync_event TEXT NOT NULL,
19022
19037
  attempted_at TEXT,
19038
+ attempt_count INTEGER NOT NULL DEFAULT 0,
19023
19039
  acked_at TEXT,
19040
+ refused_code TEXT,
19041
+ refused_at TEXT,
19024
19042
  UNIQUE (run_id, sequence)
19025
19043
  ) STRICT;
19026
- CREATE INDEX outbox_pending ON outbox(seq) WHERE acked_at IS NULL;
19044
+ CREATE INDEX outbox_pending ON outbox(seq) WHERE acked_at IS NULL AND refused_code IS NULL;
19045
+ CREATE INDEX outbox_refused ON outbox(seq) WHERE refused_code IS NOT NULL;
19027
19046
  `;
19028
19047
  var KxmRunEventStore = class {
19029
19048
  path;
@@ -19163,37 +19182,108 @@ var KxmRunEventStore = class {
19163
19182
  const syncEvent = deriveKxmSyncEvent(event, { redactor: this.syncRedactor });
19164
19183
  this.database.prepare("INSERT INTO outbox (run_id, sequence, sync_event) VALUES (?, ?, ?)").run(event.runId, event.sequence, kxmSyncEventBytes(syncEvent));
19165
19184
  }
19166
- /** Unacknowledged outbox rows after `afterSeq`, in outbox order, oldest first. */
19185
+ /**
19186
+ * Retryable outbox rows after `afterSeq`, in outbox order, oldest first.
19187
+ * Acked and durably refused rows are never returned: a refused row is not
19188
+ * waiting for a retry, it is waiting for an operator.
19189
+ */
19167
19190
  pendingOutbox(limit = 100, afterSeq = 0) {
19168
19191
  const rows = this.database.prepare(`
19169
- SELECT seq, run_id, sequence, sync_event, attempted_at, acked_at
19170
- FROM outbox WHERE acked_at IS NULL AND seq > ? ORDER BY seq ASC LIMIT ?
19192
+ SELECT seq, run_id, sequence, sync_event, attempt_count, attempted_at, acked_at, refused_code, refused_at
19193
+ FROM outbox WHERE acked_at IS NULL AND refused_code IS NULL AND seq > ? ORDER BY seq ASC LIMIT ?
19171
19194
  `).all(afterSeq, limit);
19172
19195
  return rows.map(outboxFromRow);
19173
19196
  }
19174
- /** Every outbox row of one run, acknowledged or not, in sequence order. */
19197
+ /** Every outbox row of one run, in any state, in sequence order. */
19175
19198
  outboxForRun(runId) {
19176
19199
  const rows = this.database.prepare(`
19177
- SELECT seq, run_id, sequence, sync_event, attempted_at, acked_at
19200
+ SELECT seq, run_id, sequence, sync_event, attempt_count, attempted_at, acked_at, refused_code, refused_at
19178
19201
  FROM outbox WHERE run_id = ? ORDER BY sequence ASC
19179
19202
  `).all(runId);
19180
19203
  return rows.map(outboxFromRow);
19181
19204
  }
19205
+ /**
19206
+ * Count one attempt against each row. Refused rows are never re-counted: they
19207
+ * are out of the queue, and a tick that reaches them again would mean the
19208
+ * refusal was cleared (which resets the count).
19209
+ */
19182
19210
  markOutboxAttempted(seqs, at) {
19183
- const statement = this.database.prepare("UPDATE outbox SET attempted_at = ? WHERE seq = ? AND acked_at IS NULL");
19211
+ const statement = this.database.prepare(`
19212
+ UPDATE outbox SET attempted_at = ?, attempt_count = attempt_count + 1
19213
+ WHERE seq = ? AND acked_at IS NULL AND refused_code IS NULL
19214
+ `);
19184
19215
  this.transaction(() => {
19185
19216
  for (const seq of seqs) statement.run(at, seq);
19186
19217
  });
19187
19218
  }
19188
19219
  /** Advance the cursor: the hub holds these rows now. Returns rows newly acked. */
19189
19220
  ackOutbox(seqs, at) {
19190
- const statement = this.database.prepare("UPDATE outbox SET acked_at = ? WHERE seq = ? AND acked_at IS NULL");
19221
+ const statement = this.database.prepare("UPDATE outbox SET acked_at = ?, refused_code = NULL, refused_at = NULL WHERE seq = ? AND acked_at IS NULL");
19191
19222
  return this.transaction(() => {
19192
19223
  let changed = 0;
19193
19224
  for (const seq of seqs) changed += Number(statement.run(at, seq).changes);
19194
19225
  return changed;
19195
19226
  });
19196
19227
  }
19228
+ /**
19229
+ * Record a durable hub refusal: the answer will not change if the same bytes
19230
+ * are sent again. Returns rows newly moved out of the pending queue.
19231
+ */
19232
+ refuseOutbox(refusals, at) {
19233
+ const statement = this.database.prepare(`
19234
+ UPDATE outbox SET refused_code = ?, refused_at = ?
19235
+ WHERE seq = ? AND acked_at IS NULL AND refused_code IS NULL
19236
+ `);
19237
+ return this.transaction(() => {
19238
+ let changed = 0;
19239
+ for (const refusal of refusals) changed += Number(statement.run(refusal.code, at, refusal.seq).changes);
19240
+ return changed;
19241
+ });
19242
+ }
19243
+ /**
19244
+ * Operator revive: put refused rows back in the pending queue with a fresh
19245
+ * attempt budget. Used after the hub-side state is corrected — the Runtime
19246
+ * must not decide on its own that a refusal has become retryable.
19247
+ */
19248
+ retryRefusedOutbox() {
19249
+ return Number(this.database.prepare(`
19250
+ UPDATE outbox SET refused_code = NULL, refused_at = NULL, attempted_at = NULL, attempt_count = 0
19251
+ WHERE acked_at IS NULL AND refused_code IS NOT NULL
19252
+ `).run().changes);
19253
+ }
19254
+ /**
19255
+ * The outbox as one read model: what is still retryable, what the hub holds,
19256
+ * and what the hub refused with which codes. This is what makes a stalled
19257
+ * sync answerable without opening SQLite.
19258
+ */
19259
+ outboxStatus() {
19260
+ const counts = this.database.prepare(`
19261
+ SELECT
19262
+ COALESCE(SUM(acked_at IS NULL AND refused_code IS NULL), 0) AS pending,
19263
+ COALESCE(SUM(acked_at IS NOT NULL), 0) AS acked,
19264
+ COALESCE(SUM(acked_at IS NULL AND refused_code IS NOT NULL), 0) AS refused,
19265
+ MAX(attempted_at) AS last_attempt_at
19266
+ FROM outbox
19267
+ `).get();
19268
+ const refusals = this.database.prepare(`
19269
+ SELECT refused_code AS code, COUNT(*) AS count
19270
+ FROM outbox WHERE acked_at IS NULL AND refused_code IS NOT NULL
19271
+ GROUP BY refused_code ORDER BY count DESC, code ASC
19272
+ `).all();
19273
+ const oldest = this.database.prepare(`
19274
+ SELECT seq FROM outbox WHERE acked_at IS NULL AND refused_code IS NULL ORDER BY seq ASC LIMIT 1
19275
+ `).get();
19276
+ return {
19277
+ pending: counts.pending,
19278
+ acked: counts.acked,
19279
+ refused: counts.refused,
19280
+ ...counts.last_attempt_at !== null ? { lastAttemptAt: counts.last_attempt_at } : {},
19281
+ ...oldest ? { oldestPendingSeq: oldest.seq } : {},
19282
+ // Mapped, not spread: node:sqlite rows are null-prototype objects, and this
19283
+ // read model is handed straight to the CLI and the supervisor's JSON answer.
19284
+ refusals: refusals.map((refusal) => ({ code: refusal.code, count: refusal.count }))
19285
+ };
19286
+ }
19197
19287
  events(runId, afterSequence = 0, limit = 200) {
19198
19288
  const rows = this.database.prepare(`
19199
19289
  SELECT project_id, run_id, sequence, event_id, event_type, command_id, occurred_at, recorded_at, monotonic_ns, config_revision, memory_revision, executor_policy_revision, tool_policy_revision, payload, schema, home_runtime_id
@@ -19715,8 +19805,11 @@ function outboxFromRow(row) {
19715
19805
  runId: row.run_id,
19716
19806
  sequence: row.sequence,
19717
19807
  syncEvent: row.sync_event,
19808
+ attemptCount: row.attempt_count,
19718
19809
  ...row.attempted_at !== null ? { attemptedAt: row.attempted_at } : {},
19719
- ...row.acked_at !== null ? { ackedAt: row.acked_at } : {}
19810
+ ...row.acked_at !== null ? { ackedAt: row.acked_at } : {},
19811
+ ...row.refused_code !== null ? { refusedCode: row.refused_code } : {},
19812
+ ...row.refused_at !== null ? { refusedAt: row.refused_at } : {}
19720
19813
  };
19721
19814
  }
19722
19815
  function runFromRow(row) {
@@ -23356,9 +23449,9 @@ function assertKxmConfigError(error) {
23356
23449
  // plugins/kxm/src/runtime-supervisor.ts
23357
23450
  import { spawn as spawn3 } from "node:child_process";
23358
23451
  import { createHash as createHash13, createHmac, randomBytes as randomBytes3, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
23359
- import { chmodSync as chmodSync2, existsSync as existsSync12, lstatSync as lstatSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync10, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "node:fs";
23452
+ import { chmodSync as chmodSync2, existsSync as existsSync13, lstatSync as lstatSync5, mkdirSync as mkdirSync7, readFileSync as readFileSync10, renameSync as renameSync4, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "node:fs";
23360
23453
  import { createServer } from "node:http";
23361
- import { dirname as dirname8, isAbsolute as isAbsolute6, join as join15 } from "node:path";
23454
+ import { dirname as dirname9, isAbsolute as isAbsolute6, join as join15 } from "node:path";
23362
23455
 
23363
23456
  // plugins/kxm/src/oneshot-producer.ts
23364
23457
  import { join as join12 } from "node:path";
@@ -27988,13 +28081,162 @@ function resolveClientHubAuthToken(env, project) {
27988
28081
  return record2?.projectTokens?.[project]?.trim() || record2?.authToken?.trim() || void 0;
27989
28082
  }
27990
28083
 
28084
+ // plugins/kxm/src/logger.ts
28085
+ import { appendFileSync, existsSync as existsSync12, mkdirSync as mkdirSync6, renameSync as renameSync3, statSync as statSync3, unlinkSync as unlinkSync2 } from "node:fs";
28086
+ import { dirname as dirname8 } from "node:path";
28087
+ var LOG_LEVEL_PRIORITY = {
28088
+ debug: 10,
28089
+ info: 20,
28090
+ warn: 30,
28091
+ error: 40
28092
+ };
28093
+ var DEFAULT_LOG_MAX_BYTES = 10 * 1024 * 1024;
28094
+ var DEFAULT_LOG_MAX_FILES = 3;
28095
+ var SENSITIVE_KEY_PATTERN = /(?:^|_)(?:token|secret|password|apiKey|api_key|authorization|bearer)(?:$|_)/i;
28096
+ var ALLOWED_EXACT_KEYS = /* @__PURE__ */ new Set(["auth", "authType", "authMethod", "authArgs", "canUpdate", "status"]);
28097
+ function redactLogValue(val, key) {
28098
+ if (val === null || val === void 0) return val;
28099
+ if (typeof val === "string") {
28100
+ if (key && SENSITIVE_KEY_PATTERN.test(key) && !ALLOWED_EXACT_KEYS.has(key)) {
28101
+ return "[redacted]";
28102
+ }
28103
+ return redactSecrets(val);
28104
+ }
28105
+ if (typeof val === "number" || typeof val === "boolean") {
28106
+ return val;
28107
+ }
28108
+ if (Array.isArray(val)) {
28109
+ return val.map((item) => redactLogValue(item, key));
28110
+ }
28111
+ if (typeof val === "object") {
28112
+ const out = {};
28113
+ for (const [k, v] of Object.entries(val)) {
28114
+ out[k] = redactLogValue(v, k);
28115
+ }
28116
+ return out;
28117
+ }
28118
+ return String(val);
28119
+ }
28120
+ function rotateLogFiles(filePath, maxFiles) {
28121
+ for (let i = maxFiles; i >= 1; i--) {
28122
+ const current = `${filePath}.${i}`;
28123
+ if (existsSync12(current)) {
28124
+ if (i >= maxFiles) {
28125
+ try {
28126
+ unlinkSync2(current);
28127
+ } catch {
28128
+ }
28129
+ } else {
28130
+ try {
28131
+ renameSync3(current, `${filePath}.${i + 1}`);
28132
+ } catch {
28133
+ }
28134
+ }
28135
+ }
28136
+ }
28137
+ if (existsSync12(filePath)) {
28138
+ try {
28139
+ renameSync3(filePath, `${filePath}.1`);
28140
+ } catch {
28141
+ }
28142
+ }
28143
+ }
28144
+ function createLogger(options) {
28145
+ const component = options.component;
28146
+ const filePath = options.path;
28147
+ const maxBytes = Math.max(100, options.maxBytes ?? DEFAULT_LOG_MAX_BYTES);
28148
+ const maxFiles = Math.max(1, options.maxFiles ?? DEFAULT_LOG_MAX_FILES);
28149
+ const configuredLevel = options.level ?? "info";
28150
+ const isDaemon = Boolean(options.daemon ?? (process.env.KXM_DAEMON === "1" || process.env.KXM_DAEMON === "true"));
28151
+ const shouldStdout = options.stdout ?? !isDaemon;
28152
+ const correlationDefaults = options.correlation ?? {};
28153
+ let currentSize = 0;
28154
+ if (filePath && existsSync12(filePath)) {
28155
+ try {
28156
+ currentSize = statSync3(filePath).size;
28157
+ } catch {
28158
+ currentSize = 0;
28159
+ }
28160
+ }
28161
+ function emit(level, entryOrEvent, extra) {
28162
+ const minPriority = LOG_LEVEL_PRIORITY[configuredLevel] ?? LOG_LEVEL_PRIORITY.info;
28163
+ const currentPriority = LOG_LEVEL_PRIORITY[level] ?? LOG_LEVEL_PRIORITY.info;
28164
+ if (currentPriority < minPriority) return;
28165
+ let base;
28166
+ if (typeof entryOrEvent === "string") {
28167
+ base = { event: entryOrEvent, ...extra };
28168
+ } else {
28169
+ base = { ...entryOrEvent, ...extra };
28170
+ }
28171
+ const timestamp = typeof base.timestamp === "string" ? base.timestamp : (/* @__PURE__ */ new Date()).toISOString();
28172
+ delete base.timestamp;
28173
+ delete base.level;
28174
+ delete base.component;
28175
+ const payload = {
28176
+ timestamp,
28177
+ level,
28178
+ component,
28179
+ ...correlationDefaults,
28180
+ ...base
28181
+ };
28182
+ const sanitized = redactLogValue(payload);
28183
+ const line = `${JSON.stringify(sanitized)}
28184
+ `;
28185
+ if (filePath) {
28186
+ const lineBytes = Buffer.byteLength(line, "utf8");
28187
+ if (currentSize + lineBytes > maxBytes) {
28188
+ rotateLogFiles(filePath, maxFiles);
28189
+ currentSize = 0;
28190
+ }
28191
+ try {
28192
+ mkdirSync6(dirname8(filePath), { recursive: true });
28193
+ appendFileSync(filePath, line, { encoding: "utf8", mode: 384 });
28194
+ currentSize += lineBytes;
28195
+ } catch {
28196
+ }
28197
+ }
28198
+ if (shouldStdout) {
28199
+ process.stdout.write(line);
28200
+ }
28201
+ }
28202
+ const logFn = ((entryOrEvent, extra) => {
28203
+ let lvl = "info";
28204
+ if (typeof entryOrEvent === "object" && entryOrEvent !== null && typeof entryOrEvent.level === "string") {
28205
+ const candidate = entryOrEvent.level.toLowerCase();
28206
+ if (candidate === "debug" || candidate === "info" || candidate === "warn" || candidate === "error") {
28207
+ lvl = candidate;
28208
+ }
28209
+ }
28210
+ emit(lvl, entryOrEvent, extra);
28211
+ });
28212
+ logFn.info = (entryOrEvent, extra) => emit("info", entryOrEvent, extra);
28213
+ logFn.warn = (entryOrEvent, extra) => emit("warn", entryOrEvent, extra);
28214
+ logFn.error = (entryOrEvent, extra) => emit("error", entryOrEvent, extra);
28215
+ logFn.debug = (entryOrEvent, extra) => emit("debug", entryOrEvent, extra);
28216
+ logFn.child = (sub) => {
28217
+ return createLogger({
28218
+ ...options,
28219
+ component: sub.component ? `${component}.${sub.component}` : component,
28220
+ correlation: { ...correlationDefaults, ...sub.correlation }
28221
+ });
28222
+ };
28223
+ logFn.close = () => {
28224
+ };
28225
+ Object.defineProperty(logFn, "options", {
28226
+ value: Object.freeze({ ...options }),
28227
+ writable: false,
28228
+ enumerable: true
28229
+ });
28230
+ return logFn;
28231
+ }
28232
+
27991
28233
  // plugins/kxm/src/runtime-supervisor.ts
27992
28234
  function kxmSupervisorTokenFile(paths) {
27993
28235
  return join15(paths.runtimeDir, "supervisor.token");
27994
28236
  }
27995
28237
  function publishKxmSupervisorToken(paths, token) {
27996
28238
  const file = kxmSupervisorTokenFile(paths);
27997
- mkdirSync6(dirname8(file), { recursive: true, mode: 448 });
28239
+ mkdirSync7(dirname9(file), { recursive: true, mode: 448 });
27998
28240
  const temp = `${file}.${process.pid}.tmp`;
27999
28241
  writeFileSync6(temp, `${token}
28000
28242
  `, { encoding: "utf8", mode: 384 });
@@ -28002,7 +28244,7 @@ function publishKxmSupervisorToken(paths, token) {
28002
28244
  chmodSync2(temp, 384);
28003
28245
  } catch {
28004
28246
  }
28005
- renameSync3(temp, file);
28247
+ renameSync4(temp, file);
28006
28248
  try {
28007
28249
  chmodSync2(file, 384);
28008
28250
  } catch {
@@ -28036,11 +28278,11 @@ function supervisorErrorFile(paths) {
28036
28278
  }
28037
28279
  function clearSupervisorError(paths) {
28038
28280
  const file = supervisorErrorFile(paths);
28039
- if (existsSync12(file)) rmSync3(file, { force: true });
28281
+ if (existsSync13(file)) rmSync3(file, { force: true });
28040
28282
  }
28041
28283
  function recordSupervisorError(paths, message) {
28042
28284
  try {
28043
- mkdirSync6(paths.runtimeDir, { recursive: true, mode: 448 });
28285
+ mkdirSync7(paths.runtimeDir, { recursive: true, mode: 448 });
28044
28286
  writeFileSync6(supervisorErrorFile(paths), `${message}
28045
28287
  `, { encoding: "utf8", mode: 384 });
28046
28288
  } catch {
@@ -28059,7 +28301,7 @@ function readRecentSupervisorError(paths) {
28059
28301
  }
28060
28302
  }
28061
28303
  function kxmSupervisorStatus(paths) {
28062
- if (!existsSync12(paths.registryDb)) return { running: false };
28304
+ if (!existsSync13(paths.registryDb)) return { running: false };
28063
28305
  const registry = new KxmRuntimeRegistry(paths.registryDb);
28064
28306
  try {
28065
28307
  const record2 = registry.supervisor();
@@ -28240,6 +28482,8 @@ var DEFAULT_RUNTIME_SYNC_INTERVAL_MS = 1e4;
28240
28482
  var MIN_RUNTIME_SYNC_INTERVAL_MS = 250;
28241
28483
  var MAX_RUNTIME_SYNC_INTERVAL_MS = 6e4;
28242
28484
  var OUTBOX_PUSH_BATCH = 32;
28485
+ var OUTBOX_PUSH_BATCH_BYTES = 2e5;
28486
+ var RUNTIME_SYNC_MAX_BACKOFF_MS = 5 * 6e4;
28243
28487
  function runtimeSyncIntervalMs(env = process.env) {
28244
28488
  const raw = env.KXM_RUNTIME_SYNC_INTERVAL_MS?.trim();
28245
28489
  if (!raw) return DEFAULT_RUNTIME_SYNC_INTERVAL_MS;
@@ -28247,16 +28491,72 @@ function runtimeSyncIntervalMs(env = process.env) {
28247
28491
  if (!Number.isInteger(parsed)) return DEFAULT_RUNTIME_SYNC_INTERVAL_MS;
28248
28492
  return Math.min(MAX_RUNTIME_SYNC_INTERVAL_MS, Math.max(MIN_RUNTIME_SYNC_INTERVAL_MS, parsed));
28249
28493
  }
28494
+ function isDurableRefusal(outcome) {
28495
+ return outcome === "conflict" || outcome === "rejected";
28496
+ }
28497
+ function isOversizeRefusal(error) {
28498
+ return error instanceof HubHttpError && (error.statusCode === 413 || error.code === "sync_batch_too_large" || error.code === "payload_too_large");
28499
+ }
28250
28500
  async function syncKxmOutbox(eventStore, client, options = {}) {
28251
28501
  const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
28252
- const batchSize = options.batchSize ?? OUTBOX_PUSH_BATCH;
28253
- const result = { pushed: 0, acked: 0, conflicts: 0, rejected: 0 };
28502
+ const batchSize = Math.max(1, options.batchSize ?? OUTBOX_PUSH_BATCH);
28503
+ const result = { pushed: 0, acked: 0, refused: 0, refusals: [], unconfirmed: 0, blocked: false };
28504
+ const refuse = (row, code) => {
28505
+ if (eventStore.refuseOutbox([{ seq: row.seq, code }], now()) === 0) return;
28506
+ result.refused += 1;
28507
+ result.refusals.push({ runId: row.runId, sequence: row.sequence, code });
28508
+ };
28509
+ const deliver = async (batch) => {
28510
+ const payload = [];
28511
+ const sendable = [];
28512
+ for (const row of batch) {
28513
+ try {
28514
+ payload.push(JSON.parse(row.syncEvent));
28515
+ sendable.push(row);
28516
+ } catch {
28517
+ refuse(row, "sync_row_unreadable");
28518
+ }
28519
+ }
28520
+ if (sendable.length === 0) return true;
28521
+ eventStore.markOutboxAttempted(sendable.map((row) => row.seq), now());
28522
+ let response;
28523
+ try {
28524
+ response = await client.pushSyncEvents(payload);
28525
+ } catch (error) {
28526
+ if (isOversizeRefusal(error)) {
28527
+ if (sendable.length > 1) {
28528
+ for (const row of sendable) {
28529
+ if (!await deliver([row])) return false;
28530
+ }
28531
+ return true;
28532
+ }
28533
+ refuse(sendable[0], "sync_row_too_large");
28534
+ return true;
28535
+ }
28536
+ result.blockedReason = syncFailureText(error);
28537
+ return false;
28538
+ }
28539
+ result.pushed += sendable.length;
28540
+ const acked = [];
28541
+ sendable.forEach((row, index) => {
28542
+ const entry = response.results[index];
28543
+ const describesRow = entry !== void 0 && (entry.runId === void 0 || entry.runId === row.runId) && (entry.sequence === void 0 || entry.sequence === row.sequence);
28544
+ if (!entry || !describesRow) {
28545
+ result.unconfirmed += 1;
28546
+ return;
28547
+ }
28548
+ if (entry.outcome === "accepted" || entry.outcome === "duplicate") acked.push(row.seq);
28549
+ else if (isDurableRefusal(entry.outcome)) refuse(row, entry.code ?? `sync_${entry.outcome}`);
28550
+ else result.unconfirmed += 1;
28551
+ });
28552
+ result.acked += eventStore.ackOutbox(acked, now());
28553
+ return true;
28554
+ };
28254
28555
  let afterSeq = 0;
28255
28556
  for (; ; ) {
28256
28557
  const rows = eventStore.pendingOutbox(batchSize, afterSeq);
28257
28558
  if (rows.length === 0) return result;
28258
- const MAX_BATCH_BYTES = 2e5;
28259
- let byteBudget = MAX_BATCH_BYTES;
28559
+ let byteBudget = OUTBOX_PUSH_BATCH_BYTES;
28260
28560
  let sendCount = 0;
28261
28561
  for (const row of rows) {
28262
28562
  const rowBytes = Buffer.byteLength(row.syncEvent, "utf8") + 64;
@@ -28264,21 +28564,12 @@ async function syncKxmOutbox(eventStore, client, options = {}) {
28264
28564
  byteBudget -= rowBytes;
28265
28565
  sendCount += 1;
28266
28566
  }
28267
- const batch = rows.slice(0, sendCount);
28268
- if (batch.length === 0) batch.push(rows[0]);
28567
+ const batch = rows.slice(0, Math.max(1, sendCount));
28269
28568
  afterSeq = batch[batch.length - 1].seq;
28270
- eventStore.markOutboxAttempted(batch.map((row) => row.seq), now());
28271
- const response = await client.pushSyncEvents(batch.map((row) => JSON.parse(row.syncEvent)));
28272
- result.pushed += batch.length;
28273
- const outcomes = new Map(response.results.map((entry) => [`${entry.runId}\0${entry.sequence}`, entry.outcome]));
28274
- const acked = [];
28275
- for (const row of batch) {
28276
- const outcome = outcomes.get(`${row.runId}\0${row.sequence}`);
28277
- if (outcome === "accepted" || outcome === "duplicate") acked.push(row.seq);
28278
- else if (outcome === "conflict") result.conflicts += 1;
28279
- else result.rejected += 1;
28569
+ if (!await deliver(batch)) {
28570
+ result.blocked = true;
28571
+ return result;
28280
28572
  }
28281
- result.acked += eventStore.ackOutbox(acked, now());
28282
28573
  }
28283
28574
  }
28284
28575
  function runtimeHubClientFor(context, env) {
@@ -28293,11 +28584,24 @@ function runtimeHubClientFor(context, env) {
28293
28584
  ...authToken ? { authToken } : {}
28294
28585
  });
28295
28586
  }
28587
+ function syncBackoffMs(consecutiveStalls, intervalMs) {
28588
+ if (consecutiveStalls <= 0) return 0;
28589
+ return Math.min(RUNTIME_SYNC_MAX_BACKOFF_MS, intervalMs * 2 ** Math.min(5, consecutiveStalls - 1));
28590
+ }
28591
+ function syncFailureText(error) {
28592
+ const code = error instanceof HubHttpError ? `${error.statusCode} ${error.code ?? "error"}` : void 0;
28593
+ const message = error instanceof Error ? error.message : String(error);
28594
+ return `${code ? `${code}: ` : ""}${message}`.replace(/(kxm_[A-Za-z0-9_]+|[A-Za-z0-9._-]{40,})/g, "[redacted]").slice(0, 300);
28595
+ }
28596
+ function runtimeSupervisorLogFile(paths) {
28597
+ return join15(paths.runtimeDir, "logs", "kxm-runtime.jsonl");
28598
+ }
28296
28599
  async function startKxmRuntimeSupervisor(options = {}) {
28297
28600
  const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
28601
+ const env = options.env ?? process.env;
28298
28602
  const paths = kxmRuntimePaths(options.stateRoot !== void 0 ? { stateRoot: options.stateRoot } : {});
28299
28603
  try {
28300
- return await startKxmRuntimeSupervisorInner(paths, options.port, now);
28604
+ return await startKxmRuntimeSupervisorInner(paths, options.port, now, env);
28301
28605
  } catch (error) {
28302
28606
  if (!(error instanceof KxmConfigError && error.issues.some((issue3) => issue3.code === "runtime_supervisor_conflict"))) {
28303
28607
  recordSupervisorError(paths, error.message);
@@ -28305,9 +28609,15 @@ async function startKxmRuntimeSupervisor(options = {}) {
28305
28609
  throw error;
28306
28610
  }
28307
28611
  }
28308
- async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now) {
28309
- mkdirSync6(paths.runtimeDir, { recursive: true, mode: 448 });
28310
- mkdirSync6(paths.projectsDir, { recursive: true, mode: 448 });
28612
+ async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now, env) {
28613
+ mkdirSync7(paths.runtimeDir, { recursive: true, mode: 448 });
28614
+ mkdirSync7(paths.projectsDir, { recursive: true, mode: 448 });
28615
+ const logger = createLogger({
28616
+ component: "runtime",
28617
+ path: runtimeSupervisorLogFile(paths),
28618
+ stdout: false,
28619
+ maxBytes: 2 * 1024 * 1024
28620
+ });
28311
28621
  const token = randomBytes3(32).toString("hex");
28312
28622
  const tokenHash = hashKxmSupervisorToken(token);
28313
28623
  const registry = new KxmRuntimeRegistry(paths.registryDb);
@@ -28315,12 +28625,13 @@ async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now) {
28315
28625
  const requestedPort = requestedPortOption ?? 0;
28316
28626
  let activeRuntimeId = runtimeId;
28317
28627
  const contexts = /* @__PURE__ */ new Map();
28628
+ const syncStatuses = /* @__PURE__ */ new Map();
28318
28629
  const registerSyncCredentials = (context) => {
28319
- const hubToken = resolveClientHubAuthToken(process.env, context.projectId);
28630
+ const hubToken = resolveClientHubAuthToken(env, context.projectId);
28320
28631
  if (hubToken) context.eventStore.syncRedactor.register(hubToken);
28321
- for (const key of Object.keys(process.env)) {
28632
+ for (const key of Object.keys(env)) {
28322
28633
  if (key.startsWith("KXM_") && (key.endsWith("_TOKEN") || key.endsWith("_KEY")) || key.endsWith("_API_KEY") || key.endsWith("_SECRET")) {
28323
- const value = process.env[key]?.trim();
28634
+ const value = env[key]?.trim();
28324
28635
  if (value) context.eventStore.syncRedactor.register(value);
28325
28636
  }
28326
28637
  }
@@ -28370,6 +28681,28 @@ async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now) {
28370
28681
  });
28371
28682
  return;
28372
28683
  }
28684
+ if (request.method === "GET" && url.pathname === "/v1/sync/status") {
28685
+ const projectRoot = url.searchParams.get("projectRoot");
28686
+ const statuses = [...syncStatuses.values()].filter((status) => projectRoot === null || status.projectRoot === projectRoot).sort((left, right) => left.projectId.localeCompare(right.projectId));
28687
+ sendJson(response, 200, { ok: true, runtimeId: activeRuntimeId, projects: statuses });
28688
+ return;
28689
+ }
28690
+ if (request.method === "POST" && url.pathname === "/v1/sync/retry") {
28691
+ const body = await readJsonBody(request);
28692
+ const projectRoot = typeof body.projectRoot === "string" ? body.projectRoot : "";
28693
+ const context = contextFor(projectRoot);
28694
+ const key = projectRuntimeKey(context.projectRoot);
28695
+ const retried = context.eventStore.retryRefusedOutbox();
28696
+ const status = syncStatuses.get(key);
28697
+ if (status) {
28698
+ const cleared = { ...status, outbox: context.eventStore.outboxStatus(), consecutiveFailures: 0 };
28699
+ delete cleared.nextAttemptAt;
28700
+ syncStatuses.set(key, cleared);
28701
+ }
28702
+ logger({ event: "runtime_sync_retry", projectId: context.projectId, retried });
28703
+ sendJson(response, 200, { ok: true, projectId: context.projectId, retried, outbox: context.eventStore.outboxStatus() });
28704
+ return;
28705
+ }
28373
28706
  if (request.method === "POST" && url.pathname === "/v1/runs") {
28374
28707
  const body = await readJsonBody(request);
28375
28708
  const projectRoot = typeof body.projectRoot === "string" ? body.projectRoot : "";
@@ -28669,26 +29002,93 @@ async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now) {
28669
29002
  try {
28670
29003
  contextFor(reg.projectRoot);
28671
29004
  } catch {
29005
+ logger.warn({
29006
+ event: "runtime_sync_context_unavailable",
29007
+ projectId: reg.projectId,
29008
+ message: `cannot reopen ${reg.projectRoot}: its outbox rows stay pending`
29009
+ });
28672
29010
  }
28673
29011
  }
29012
+ const recordSyncStatus = (context, next) => {
29013
+ const key = projectRuntimeKey(context.projectRoot);
29014
+ const previous = syncStatuses.get(key);
29015
+ syncStatuses.set(key, next);
29016
+ const changed = previous === void 0 || previous.state !== next.state || next.lastError !== void 0 && previous?.lastError !== next.lastError || JSON.stringify(next.outbox.refusals) !== JSON.stringify(previous?.outbox.refusals ?? []);
29017
+ if (!changed) return;
29018
+ const stalledState = next.state === "blocked" || next.state === "refusing";
29019
+ const entry = {
29020
+ event: stalledState ? "runtime_sync_stalled" : "runtime_sync_state",
29021
+ projectId: next.projectId,
29022
+ runtimeId: next.homeRuntimeId,
29023
+ state: next.state,
29024
+ pending: next.outbox.pending,
29025
+ acked: next.outbox.acked,
29026
+ refused: next.outbox.refused,
29027
+ ...next.outbox.refusals.length > 0 ? { refusals: next.outbox.refusals } : {},
29028
+ ...next.hubUrl ? { hubUrl: next.hubUrl } : {},
29029
+ ...next.lastError ? { reason: next.lastError } : {},
29030
+ ...next.nextAttemptAt ? { nextAttemptAt: next.nextAttemptAt } : {}
29031
+ };
29032
+ if (stalledState) logger.warn(entry);
29033
+ else logger.info(entry);
29034
+ };
28674
29035
  let syncing = false;
28675
29036
  const syncTimer = setInterval(() => {
28676
29037
  if (syncing || stopping) return;
28677
29038
  syncing = true;
28678
29039
  void (async () => {
28679
29040
  for (const context of [...contexts.values()]) {
29041
+ const key = projectRuntimeKey(context.projectRoot);
29042
+ const prior = syncStatuses.get(key);
29043
+ if (prior?.nextAttemptAt && Date.parse(prior.nextAttemptAt) > Date.parse(now())) continue;
29044
+ const base = {
29045
+ projectId: context.projectId,
29046
+ projectRoot: context.projectRoot,
29047
+ homeRuntimeId: context.homeRuntimeId,
29048
+ outbox: context.eventStore.outboxStatus(),
29049
+ consecutiveFailures: 0
29050
+ };
28680
29051
  try {
28681
- const client = runtimeHubClientFor(context, process.env);
28682
- if (!client) continue;
29052
+ const client = runtimeHubClientFor(context, env);
29053
+ if (!client) {
29054
+ recordSyncStatus(context, { ...base, state: "no_hub" });
29055
+ continue;
29056
+ }
28683
29057
  await client.heartbeat();
28684
- await syncKxmOutbox(context.eventStore, client, { now });
28685
- } catch {
29058
+ const pass = await syncKxmOutbox(context.eventStore, client, { now });
29059
+ const outbox = context.eventStore.outboxStatus();
29060
+ const failures = pass.blocked || pass.unconfirmed > 0 ? (prior?.consecutiveFailures ?? 0) + 1 : 0;
29061
+ const delayMs = syncBackoffMs(failures, runtimeSyncIntervalMs(env));
29062
+ recordSyncStatus(context, {
29063
+ ...base,
29064
+ hubUrl: client.options.serverUrl,
29065
+ outbox,
29066
+ state: pass.blocked ? "blocked" : outbox.refused > 0 || pass.unconfirmed > 0 ? "refusing" : "ok",
29067
+ lastCompletedAt: now(),
29068
+ lastPushed: pass.pushed,
29069
+ lastAcked: pass.acked,
29070
+ lastRefused: pass.refused,
29071
+ lastUnconfirmed: pass.unconfirmed,
29072
+ consecutiveFailures: failures,
29073
+ ...pass.blockedReason !== void 0 ? { lastError: pass.blockedReason } : {},
29074
+ ...delayMs > 0 ? { nextAttemptAt: new Date(Date.parse(now()) + delayMs).toISOString() } : {}
29075
+ });
29076
+ } catch (error) {
29077
+ const failures = (prior?.consecutiveFailures ?? 0) + 1;
29078
+ const delayMs = syncBackoffMs(failures, runtimeSyncIntervalMs(env));
29079
+ recordSyncStatus(context, {
29080
+ ...base,
29081
+ state: "blocked",
29082
+ consecutiveFailures: failures,
29083
+ lastError: syncFailureText(error),
29084
+ nextAttemptAt: new Date(Date.parse(now()) + delayMs).toISOString()
29085
+ });
28686
29086
  }
28687
29087
  }
28688
29088
  })().finally(() => {
28689
29089
  syncing = false;
28690
29090
  });
28691
- }, runtimeSyncIntervalMs());
29091
+ }, runtimeSyncIntervalMs(env));
28692
29092
  syncTimer.unref();
28693
29093
  let stopping = false;
28694
29094
  const stop = async () => {
@@ -28723,6 +29123,7 @@ async function startKxmRuntimeSupervisorInner(paths, requestedPortOption, now) {
28723
29123
  }
28724
29124
  for (const context of contexts.values()) closeKxmRuntimeContext(context);
28725
29125
  contexts.clear();
29126
+ logger.close();
28726
29127
  const closed = new Promise((resolveStop) => server.close(() => resolveStop()));
28727
29128
  server.closeIdleConnections?.();
28728
29129
  await closed;
@@ -29261,155 +29662,6 @@ function createKxmPiProducer(options = {}) {
29261
29662
  return producer;
29262
29663
  }
29263
29664
 
29264
- // plugins/kxm/src/logger.ts
29265
- import { appendFileSync, existsSync as existsSync13, mkdirSync as mkdirSync7, renameSync as renameSync4, statSync as statSync3, unlinkSync as unlinkSync2 } from "node:fs";
29266
- import { dirname as dirname9 } from "node:path";
29267
- var LOG_LEVEL_PRIORITY = {
29268
- debug: 10,
29269
- info: 20,
29270
- warn: 30,
29271
- error: 40
29272
- };
29273
- var DEFAULT_LOG_MAX_BYTES = 10 * 1024 * 1024;
29274
- var DEFAULT_LOG_MAX_FILES = 3;
29275
- var SENSITIVE_KEY_PATTERN = /(?:^|_)(?:token|secret|password|apiKey|api_key|authorization|bearer)(?:$|_)/i;
29276
- var ALLOWED_EXACT_KEYS = /* @__PURE__ */ new Set(["auth", "authType", "authMethod", "authArgs", "canUpdate", "status"]);
29277
- function redactLogValue(val, key) {
29278
- if (val === null || val === void 0) return val;
29279
- if (typeof val === "string") {
29280
- if (key && SENSITIVE_KEY_PATTERN.test(key) && !ALLOWED_EXACT_KEYS.has(key)) {
29281
- return "[redacted]";
29282
- }
29283
- return redactSecrets(val);
29284
- }
29285
- if (typeof val === "number" || typeof val === "boolean") {
29286
- return val;
29287
- }
29288
- if (Array.isArray(val)) {
29289
- return val.map((item) => redactLogValue(item, key));
29290
- }
29291
- if (typeof val === "object") {
29292
- const out = {};
29293
- for (const [k, v] of Object.entries(val)) {
29294
- out[k] = redactLogValue(v, k);
29295
- }
29296
- return out;
29297
- }
29298
- return String(val);
29299
- }
29300
- function rotateLogFiles(filePath, maxFiles) {
29301
- for (let i = maxFiles; i >= 1; i--) {
29302
- const current = `${filePath}.${i}`;
29303
- if (existsSync13(current)) {
29304
- if (i >= maxFiles) {
29305
- try {
29306
- unlinkSync2(current);
29307
- } catch {
29308
- }
29309
- } else {
29310
- try {
29311
- renameSync4(current, `${filePath}.${i + 1}`);
29312
- } catch {
29313
- }
29314
- }
29315
- }
29316
- }
29317
- if (existsSync13(filePath)) {
29318
- try {
29319
- renameSync4(filePath, `${filePath}.1`);
29320
- } catch {
29321
- }
29322
- }
29323
- }
29324
- function createLogger(options) {
29325
- const component = options.component;
29326
- const filePath = options.path;
29327
- const maxBytes = Math.max(100, options.maxBytes ?? DEFAULT_LOG_MAX_BYTES);
29328
- const maxFiles = Math.max(1, options.maxFiles ?? DEFAULT_LOG_MAX_FILES);
29329
- const configuredLevel = options.level ?? "info";
29330
- const isDaemon = Boolean(options.daemon ?? (process.env.KXM_DAEMON === "1" || process.env.KXM_DAEMON === "true"));
29331
- const shouldStdout = options.stdout ?? !isDaemon;
29332
- const correlationDefaults = options.correlation ?? {};
29333
- let currentSize = 0;
29334
- if (filePath && existsSync13(filePath)) {
29335
- try {
29336
- currentSize = statSync3(filePath).size;
29337
- } catch {
29338
- currentSize = 0;
29339
- }
29340
- }
29341
- function emit(level, entryOrEvent, extra) {
29342
- const minPriority = LOG_LEVEL_PRIORITY[configuredLevel] ?? LOG_LEVEL_PRIORITY.info;
29343
- const currentPriority = LOG_LEVEL_PRIORITY[level] ?? LOG_LEVEL_PRIORITY.info;
29344
- if (currentPriority < minPriority) return;
29345
- let base;
29346
- if (typeof entryOrEvent === "string") {
29347
- base = { event: entryOrEvent, ...extra };
29348
- } else {
29349
- base = { ...entryOrEvent, ...extra };
29350
- }
29351
- const timestamp = typeof base.timestamp === "string" ? base.timestamp : (/* @__PURE__ */ new Date()).toISOString();
29352
- delete base.timestamp;
29353
- delete base.level;
29354
- delete base.component;
29355
- const payload = {
29356
- timestamp,
29357
- level,
29358
- component,
29359
- ...correlationDefaults,
29360
- ...base
29361
- };
29362
- const sanitized = redactLogValue(payload);
29363
- const line = `${JSON.stringify(sanitized)}
29364
- `;
29365
- if (filePath) {
29366
- const lineBytes = Buffer.byteLength(line, "utf8");
29367
- if (currentSize + lineBytes > maxBytes) {
29368
- rotateLogFiles(filePath, maxFiles);
29369
- currentSize = 0;
29370
- }
29371
- try {
29372
- mkdirSync7(dirname9(filePath), { recursive: true });
29373
- appendFileSync(filePath, line, { encoding: "utf8", mode: 384 });
29374
- currentSize += lineBytes;
29375
- } catch {
29376
- }
29377
- }
29378
- if (shouldStdout) {
29379
- process.stdout.write(line);
29380
- }
29381
- }
29382
- const logFn = ((entryOrEvent, extra) => {
29383
- let lvl = "info";
29384
- if (typeof entryOrEvent === "object" && entryOrEvent !== null && typeof entryOrEvent.level === "string") {
29385
- const candidate = entryOrEvent.level.toLowerCase();
29386
- if (candidate === "debug" || candidate === "info" || candidate === "warn" || candidate === "error") {
29387
- lvl = candidate;
29388
- }
29389
- }
29390
- emit(lvl, entryOrEvent, extra);
29391
- });
29392
- logFn.info = (entryOrEvent, extra) => emit("info", entryOrEvent, extra);
29393
- logFn.warn = (entryOrEvent, extra) => emit("warn", entryOrEvent, extra);
29394
- logFn.error = (entryOrEvent, extra) => emit("error", entryOrEvent, extra);
29395
- logFn.debug = (entryOrEvent, extra) => emit("debug", entryOrEvent, extra);
29396
- logFn.child = (sub) => {
29397
- return createLogger({
29398
- ...options,
29399
- component: sub.component ? `${component}.${sub.component}` : component,
29400
- correlation: { ...correlationDefaults, ...sub.correlation }
29401
- });
29402
- };
29403
- logFn.close = () => {
29404
- };
29405
- Object.defineProperty(logFn, "options", {
29406
- value: Object.freeze({ ...options }),
29407
- writable: false,
29408
- enumerable: true
29409
- });
29410
- return logFn;
29411
- }
29412
-
29413
29665
  // plugins/kxm/src/improve.ts
29414
29666
  import { createHash as createHash14 } from "node:crypto";
29415
29667
  import { existsSync as existsSync14, mkdirSync as mkdirSync8, writeFileSync as writeFileSync7 } from "node:fs";
@@ -31041,6 +31293,7 @@ export {
31041
31293
  IMPROVEMENT_REPORT_SCHEMA,
31042
31294
  IMPROVEMENT_REPORT_V1_SCHEMA,
31043
31295
  KXM_ABSENT_MEMORY_REVISION,
31296
+ KXM_BACKUP_CEILINGS,
31044
31297
  KXM_DRIVE_RECEIPT_SCHEMA,
31045
31298
  KXM_EVENT_STORE_SCHEMA_VERSION,
31046
31299
  KXM_EVENT_STORE_TABLE_NAMES,
@@ -31119,6 +31372,7 @@ export {
31119
31372
  isKxmRuntimeContextClosed,
31120
31373
  isTransactionContention,
31121
31374
  isWindowsHarnessShim,
31375
+ kxmBackupCeiling,
31122
31376
  kxmDeclaredExecutorIds,
31123
31377
  kxmDeclaredRepositoryIds,
31124
31378
  kxmEventBase,