memorix 1.9.2 → 1.9.3

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/dist/sdk.js CHANGED
@@ -468,70 +468,79 @@ function getDatabase(dataDir) {
468
468
  loadBetterSqlite3();
469
469
  fs.mkdirSync(dataDir, { recursive: true });
470
470
  const dbPath = path3.join(dataDir, "memorix.db");
471
- const db2 = createDatabase(dbPath);
472
- db2.pragma("journal_mode = WAL");
473
- db2.pragma("busy_timeout = 5000");
474
- db2.pragma("foreign_keys = ON");
475
- db2.exec(CREATE_OBSERVATIONS_TABLE);
476
- db2.exec(CREATE_MINI_SKILLS_TABLE);
477
- db2.exec(CREATE_SESSIONS_TABLE);
478
- db2.exec(CREATE_META_TABLE);
479
- db2.exec(CREATE_TEAM_AGENTS_TABLE);
480
- db2.exec(CREATE_TEAM_TASKS_TABLE);
481
- db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
482
- db2.exec(CREATE_TEAM_MESSAGES_TABLE);
483
- db2.exec(CREATE_TEAM_LOCKS_TABLE);
484
- db2.exec(CREATE_TEAM_ROLES_TABLE);
485
- db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
486
- db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
487
- db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
488
- db2.exec(CREATE_CODE_FILES_TABLE);
489
- db2.exec(CREATE_CODE_SYMBOLS_TABLE);
490
- db2.exec(CREATE_CODE_EDGES_TABLE);
491
- db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
492
- db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
493
- db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
494
- db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
471
+ let db2;
495
472
  try {
496
- db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
497
- } catch {
498
- }
499
- try {
500
- db2.exec(`ALTER TABLE mini_skills ADD COLUMN updatedAt TEXT`);
501
- } catch {
502
- }
503
- try {
504
- db2.exec(`ALTER TABLE observations ADD COLUMN createdByAgentId TEXT`);
505
- } catch {
506
- }
507
- try {
508
- db2.exec(`ALTER TABLE observations ADD COLUMN writeGeneration INTEGER DEFAULT 0`);
509
- } catch {
510
- }
511
- try {
512
- db2.exec(`ALTER TABLE team_tasks ADD COLUMN required_role TEXT`);
513
- } catch {
514
- }
515
- try {
516
- db2.exec(`ALTER TABLE team_tasks ADD COLUMN preferred_role TEXT`);
517
- } catch {
518
- }
519
- try {
520
- db2.exec(`ALTER TABLE team_messages ADD COLUMN to_role TEXT`);
521
- } catch {
522
- }
523
- try {
524
- db2.exec(`ALTER TABLE team_messages ADD COLUMN handoff_status TEXT`);
525
- } catch {
473
+ db2 = createDatabase(dbPath);
474
+ db2.pragma("busy_timeout = 5000");
475
+ db2.pragma("journal_mode = WAL");
476
+ db2.pragma("foreign_keys = ON");
477
+ db2.exec(CREATE_OBSERVATIONS_TABLE);
478
+ db2.exec(CREATE_MINI_SKILLS_TABLE);
479
+ db2.exec(CREATE_SESSIONS_TABLE);
480
+ db2.exec(CREATE_META_TABLE);
481
+ db2.exec(CREATE_TEAM_AGENTS_TABLE);
482
+ db2.exec(CREATE_TEAM_TASKS_TABLE);
483
+ db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
484
+ db2.exec(CREATE_TEAM_MESSAGES_TABLE);
485
+ db2.exec(CREATE_TEAM_LOCKS_TABLE);
486
+ db2.exec(CREATE_TEAM_ROLES_TABLE);
487
+ db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
488
+ db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
489
+ db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
490
+ db2.exec(CREATE_CODE_FILES_TABLE);
491
+ db2.exec(CREATE_CODE_SYMBOLS_TABLE);
492
+ db2.exec(CREATE_CODE_EDGES_TABLE);
493
+ db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
494
+ db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
495
+ db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
496
+ db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
497
+ try {
498
+ db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
499
+ } catch {
500
+ }
501
+ try {
502
+ db2.exec(`ALTER TABLE mini_skills ADD COLUMN updatedAt TEXT`);
503
+ } catch {
504
+ }
505
+ try {
506
+ db2.exec(`ALTER TABLE observations ADD COLUMN createdByAgentId TEXT`);
507
+ } catch {
508
+ }
509
+ try {
510
+ db2.exec(`ALTER TABLE observations ADD COLUMN writeGeneration INTEGER DEFAULT 0`);
511
+ } catch {
512
+ }
513
+ try {
514
+ db2.exec(`ALTER TABLE team_tasks ADD COLUMN required_role TEXT`);
515
+ } catch {
516
+ }
517
+ try {
518
+ db2.exec(`ALTER TABLE team_tasks ADD COLUMN preferred_role TEXT`);
519
+ } catch {
520
+ }
521
+ try {
522
+ db2.exec(`ALTER TABLE team_messages ADD COLUMN to_role TEXT`);
523
+ } catch {
524
+ }
525
+ try {
526
+ db2.exec(`ALTER TABLE team_messages ADD COLUMN handoff_status TEXT`);
527
+ } catch {
528
+ }
529
+ applySchemaMigrations(db2);
530
+ db2.exec(CREATE_INDEXES);
531
+ initializeObservationLexicalIndex(db2);
532
+ db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
533
+ db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
534
+ db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
535
+ _dbCache.set(normalized, db2);
536
+ return db2;
537
+ } catch (error) {
538
+ try {
539
+ db2?.close();
540
+ } catch {
541
+ }
542
+ throw error;
526
543
  }
527
- applySchemaMigrations(db2);
528
- db2.exec(CREATE_INDEXES);
529
- initializeObservationLexicalIndex(db2);
530
- db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
531
- db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
532
- db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
533
- _dbCache.set(normalized, db2);
534
- return db2;
535
544
  }
536
545
  function closeDatabase(dataDir) {
537
546
  const normalized = path3.resolve(dataDir);
@@ -2369,6 +2378,74 @@ var init_types = __esm({
2369
2378
  }
2370
2379
  });
2371
2380
 
2381
+ // src/store/sqlite-reliability.ts
2382
+ function isTransientSqliteError(error) {
2383
+ const code = error?.code;
2384
+ if (typeof code === "string") {
2385
+ return /^SQLITE_BUSY(?:_|$)/i.test(code);
2386
+ }
2387
+ return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
2388
+ }
2389
+ function isSqliteUnavailableError(error) {
2390
+ return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
2391
+ }
2392
+ function degradedReadError(storeName) {
2393
+ return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
2394
+ }
2395
+ function degradedWriteError(storeName) {
2396
+ return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
2397
+ }
2398
+ function formatSqliteFailure(error) {
2399
+ return error instanceof Error && error.message ? error.message : String(error);
2400
+ }
2401
+ function delay(ms) {
2402
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
2403
+ }
2404
+ async function retrySqliteBusy(operation, label) {
2405
+ for (let attempt = 0; ; attempt++) {
2406
+ try {
2407
+ return await operation();
2408
+ } catch (error) {
2409
+ if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
2410
+ const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
2411
+ console.error(
2412
+ `[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
2413
+ );
2414
+ await delay(waitMs);
2415
+ }
2416
+ }
2417
+ }
2418
+ async function initializeSqliteStore(factory, dataDir, label) {
2419
+ try {
2420
+ loadBetterSqlite3();
2421
+ } catch (error) {
2422
+ throw new SqliteUnavailableError(error);
2423
+ }
2424
+ return retrySqliteBusy(async () => {
2425
+ const store = factory();
2426
+ await store.init(dataDir);
2427
+ return store;
2428
+ }, label);
2429
+ }
2430
+ var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
2431
+ var init_sqlite_reliability = __esm({
2432
+ "src/store/sqlite-reliability.ts"() {
2433
+ "use strict";
2434
+ init_esm_shims();
2435
+ init_sqlite_db();
2436
+ SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
2437
+ SqliteUnavailableError = class extends Error {
2438
+ code = "MEMORIX_SQLITE_UNAVAILABLE";
2439
+ constructor(cause) {
2440
+ super(
2441
+ cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
2442
+ );
2443
+ this.name = "SqliteUnavailableError";
2444
+ }
2445
+ };
2446
+ }
2447
+ });
2448
+
2372
2449
  // src/store/mini-skill-store.ts
2373
2450
  var mini_skill_store_exports = {};
2374
2451
  __export(mini_skill_store_exports, {
@@ -2440,16 +2517,18 @@ async function initMiniSkillStore(dataDir) {
2440
2517
  if (_store && _storeDataDir === dataDir) return _store;
2441
2518
  _store = null;
2442
2519
  _storeDataDir = null;
2520
+ let degradedReason = "SQLite runtime unavailable";
2443
2521
  try {
2444
- const store2 = new MiniSkillSqliteStore();
2445
- await store2.init(dataDir);
2522
+ const store2 = await initializeSqliteStore(() => new MiniSkillSqliteStore(), dataDir, "Mini-skill store");
2446
2523
  _store = store2;
2447
2524
  _storeDataDir = dataDir;
2448
2525
  return store2;
2449
2526
  } catch (err) {
2450
- console.error(`[memorix] MiniSkillSqliteStore unavailable, running in degraded read-only mode: ${err instanceof Error ? err.message : err}`);
2527
+ if (!isSqliteUnavailableError(err)) throw err;
2528
+ degradedReason = err instanceof Error ? err.message : String(err);
2529
+ console.error(`[memorix] MiniSkillSqliteStore unavailable, running in degraded read-only mode: ${degradedReason}`);
2451
2530
  }
2452
- const store = new MiniSkillGracefulDegrade();
2531
+ const store = new MiniSkillGracefulDegrade(degradedReason);
2453
2532
  await store.init(dataDir);
2454
2533
  _store = store;
2455
2534
  _storeDataDir = dataDir;
@@ -2461,6 +2540,7 @@ var init_mini_skill_store = __esm({
2461
2540
  "use strict";
2462
2541
  init_esm_shims();
2463
2542
  init_sqlite_db();
2543
+ init_sqlite_reliability();
2464
2544
  MiniSkillSqliteStore = class {
2465
2545
  db = null;
2466
2546
  dataDir = "";
@@ -2569,7 +2649,7 @@ var init_mini_skill_store = __esm({
2569
2649
  * SQLite serializes write transactions, so concurrent calls are safely sequenced.
2570
2650
  */
2571
2651
  async atomicInsertWithId(skillWithoutId) {
2572
- const result = this.db.transaction(() => {
2652
+ return retrySqliteBusy(async () => this.db.transaction(() => {
2573
2653
  const row = this.stmtGetMeta.get("mini_skills_next_id");
2574
2654
  const nextId2 = row ? parseInt(row.value, 10) : 1;
2575
2655
  const skill2 = { ...skillWithoutId, id: nextId2 };
@@ -2578,8 +2658,7 @@ var init_mini_skill_store = __esm({
2578
2658
  this.stmtBumpGeneration.run();
2579
2659
  this.knownGeneration = this.readGeneration();
2580
2660
  return skill2;
2581
- })();
2582
- return result;
2661
+ })(), "Mini-skill promotion");
2583
2662
  }
2584
2663
  // ── Freshness ────────────────────────────────────────────────────
2585
2664
  async ensureFresh() {
@@ -2598,10 +2677,17 @@ var init_mini_skill_store = __esm({
2598
2677
  }
2599
2678
  };
2600
2679
  MiniSkillGracefulDegrade = class {
2680
+ constructor(reason = "SQLite runtime unavailable") {
2681
+ this.reason = reason;
2682
+ }
2683
+ reason;
2601
2684
  warned = false;
2685
+ unavailableRead() {
2686
+ return degradedReadError("mini-skills");
2687
+ }
2602
2688
  warn() {
2603
2689
  if (!this.warned) {
2604
- console.error("[memorix] MiniSkillStore: SQLite unavailable \u2014 mini-skills are disabled (read-only empty). Install better-sqlite3 for full functionality.");
2690
+ console.error("[memorix] MiniSkillStore: SQLite unavailable \u2014 mini-skills cannot be read or written. Install a supported SQLite runtime.");
2605
2691
  this.warned = true;
2606
2692
  }
2607
2693
  }
@@ -2609,28 +2695,33 @@ var init_mini_skill_store = __esm({
2609
2695
  this.warn();
2610
2696
  }
2611
2697
  async loadAll() {
2612
- return [];
2698
+ throw this.unavailableRead();
2613
2699
  }
2614
2700
  async loadByProject(_projectId) {
2615
- return [];
2701
+ throw this.unavailableRead();
2616
2702
  }
2617
2703
  async loadIdCounter() {
2618
- return 1;
2704
+ throw this.unavailableRead();
2619
2705
  }
2620
2706
  async insert(_skill) {
2621
2707
  this.warn();
2708
+ throw degradedWriteError("mini-skills");
2622
2709
  }
2623
2710
  async update(_skill) {
2624
2711
  this.warn();
2712
+ throw degradedWriteError("mini-skills");
2625
2713
  }
2626
2714
  async remove(_id) {
2627
2715
  this.warn();
2716
+ throw degradedWriteError("mini-skills");
2628
2717
  }
2629
2718
  async saveIdCounter(_nextId) {
2719
+ this.warn();
2720
+ throw degradedWriteError("mini-skills");
2630
2721
  }
2631
2722
  async atomicInsertWithId(skillWithoutId) {
2632
2723
  this.warn();
2633
- return { ...skillWithoutId, id: 0 };
2724
+ throw degradedWriteError("mini-skills");
2634
2725
  }
2635
2726
  async ensureFresh() {
2636
2727
  return false;
@@ -2641,6 +2732,9 @@ var init_mini_skill_store = __esm({
2641
2732
  getBackendName() {
2642
2733
  return "degraded";
2643
2734
  }
2735
+ getBackendReason() {
2736
+ return this.reason;
2737
+ }
2644
2738
  };
2645
2739
  _store = null;
2646
2740
  _storeDataDir = null;
@@ -4843,10 +4937,10 @@ async function fetchWithRetry(url, apiKey, body, options = {}, attempt = 0, nati
4843
4937
  );
4844
4938
  }
4845
4939
  if (options.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
4846
- const delay2 = BASE_DELAY_MS * Math.pow(2, attempt);
4940
+ const delay3 = BASE_DELAY_MS * Math.pow(2, attempt);
4847
4941
  const retryAfter = response.headers.get("retry-after");
4848
4942
  const parsedRetryAfter = retryAfter ? parseInt(retryAfter, 10) * 1e3 : NaN;
4849
- const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay2;
4943
+ const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay3;
4850
4944
  console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
4851
4945
  await waitForRetry(waitMs, options.signal);
4852
4946
  return fetchWithRetry(url, apiKey, body, options, attempt + 1, nativeGemini);
@@ -6878,6 +6972,7 @@ var init_sqlite_store = __esm({
6878
6972
  "use strict";
6879
6973
  init_esm_shims();
6880
6974
  init_sqlite_db();
6975
+ init_sqlite_reliability();
6881
6976
  init_sqlite_fts();
6882
6977
  SqliteBackend = class {
6883
6978
  db = null;
@@ -7155,7 +7250,9 @@ var init_sqlite_store = __esm({
7155
7250
  // ── Compound atomic operation ────────────────────────────────────
7156
7251
  async atomic(fn) {
7157
7252
  const run = this._atomicQueue.catch(() => void 0).then(async () => {
7158
- this.db.prepare("BEGIN IMMEDIATE").run();
7253
+ await retrySqliteBusy(async () => {
7254
+ this.db.prepare("BEGIN IMMEDIATE").run();
7255
+ }, "Observation atomic write");
7159
7256
  try {
7160
7257
  const tx = {
7161
7258
  loadAll: async () => this.rawLoadAll(),
@@ -7254,15 +7351,15 @@ function resetObservationStore() {
7254
7351
  async function createObservationStore(dataDir) {
7255
7352
  try {
7256
7353
  const { SqliteBackend: SqliteBackend2 } = await Promise.resolve().then(() => (init_sqlite_store(), sqlite_store_exports));
7257
- const store2 = new SqliteBackend2();
7258
- await store2.init(dataDir);
7259
- return store2;
7354
+ return await initializeSqliteStore(() => new SqliteBackend2(), dataDir, "Observation store");
7260
7355
  } catch (err) {
7261
- console.error(`[memorix] SQLite backend unavailable \u2014 degraded mode (read-only): ${err instanceof Error ? err.message : err}`);
7356
+ if (!isSqliteUnavailableError(err)) throw err;
7357
+ const reason = formatSqliteFailure(err);
7358
+ console.error(`[memorix] SQLite module unavailable \u2014 degraded mode (reads/writes disabled): ${reason}`);
7359
+ const degraded = new DegradedBackend(reason);
7360
+ await degraded.init(dataDir);
7361
+ return degraded;
7262
7362
  }
7263
- const store = new DegradedBackend();
7264
- await store.init(dataDir);
7265
- return store;
7266
7363
  }
7267
7364
  async function initObservationStore(dataDir) {
7268
7365
  if (_store2 && _storeDataDir2 === dataDir) {
@@ -7286,36 +7383,44 @@ var init_obs_store = __esm({
7286
7383
  "src/store/obs-store.ts"() {
7287
7384
  "use strict";
7288
7385
  init_esm_shims();
7386
+ init_sqlite_reliability();
7289
7387
  _store2 = null;
7290
7388
  _storeDataDir2 = null;
7291
7389
  DegradedBackend = class {
7390
+ constructor(reason = "SQLite runtime unavailable") {
7391
+ this.reason = reason;
7392
+ }
7393
+ reason;
7292
7394
  dataDir = "";
7395
+ unavailableRead() {
7396
+ return degradedReadError("observations");
7397
+ }
7293
7398
  async init(dataDir) {
7294
7399
  this.dataDir = dataDir;
7295
7400
  }
7296
7401
  async loadAll() {
7297
- return [];
7402
+ throw this.unavailableRead();
7298
7403
  }
7299
7404
  async loadByProject(_projectId, _options) {
7300
- return [];
7405
+ throw this.unavailableRead();
7301
7406
  }
7302
7407
  async countByProject(_projectId, _options) {
7303
- return 0;
7408
+ throw this.unavailableRead();
7304
7409
  }
7305
7410
  async getById(_id) {
7306
- return void 0;
7411
+ throw this.unavailableRead();
7307
7412
  }
7308
7413
  async loadIdCounter() {
7309
- return 1;
7414
+ throw this.unavailableRead();
7310
7415
  }
7311
7416
  async countAll() {
7312
- return 0;
7417
+ throw this.unavailableRead();
7313
7418
  }
7314
7419
  async listProjectIds() {
7315
- return [];
7420
+ throw this.unavailableRead();
7316
7421
  }
7317
7422
  async searchLexical(_options) {
7318
- return [];
7423
+ throw this.unavailableRead();
7319
7424
  }
7320
7425
  hasLexicalIndex() {
7321
7426
  return false;
@@ -7324,25 +7429,25 @@ var init_obs_store = __esm({
7324
7429
  return false;
7325
7430
  }
7326
7431
  async insert(_obs) {
7327
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7432
+ throw degradedWriteError("observations");
7328
7433
  }
7329
7434
  async update(_obs) {
7330
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7435
+ throw degradedWriteError("observations");
7331
7436
  }
7332
7437
  async remove(_id) {
7333
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7438
+ throw degradedWriteError("observations");
7334
7439
  }
7335
7440
  async bulkReplace(_obs) {
7336
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7441
+ throw degradedWriteError("observations");
7337
7442
  }
7338
7443
  async bulkRemoveByIds(_ids) {
7339
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7444
+ throw degradedWriteError("observations");
7340
7445
  }
7341
7446
  async saveIdCounter(_nextId) {
7342
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7447
+ throw degradedWriteError("observations");
7343
7448
  }
7344
7449
  async atomic(_fn) {
7345
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7450
+ throw degradedWriteError("observations");
7346
7451
  }
7347
7452
  async ensureFresh() {
7348
7453
  return false;
@@ -7355,6 +7460,9 @@ var init_obs_store = __esm({
7355
7460
  getBackendName() {
7356
7461
  return "degraded";
7357
7462
  }
7463
+ getBackendReason() {
7464
+ return this.reason;
7465
+ }
7358
7466
  };
7359
7467
  }
7360
7468
  });
@@ -57009,10 +57117,10 @@ var require_retry3 = __commonJS({
57009
57117
  if (!await shouldRetryFn(err)) {
57010
57118
  return { shouldRetry: false, config: err.config };
57011
57119
  }
57012
- const delay2 = getNextRetryDelay(config);
57120
+ const delay3 = getNextRetryDelay(config);
57013
57121
  err.config.retryConfig.currentRetryAttempt += 1;
57014
- const backoff = config.retryBackoff ? config.retryBackoff(err, delay2) : new Promise((resolve5) => {
57015
- setTimeout(resolve5, delay2);
57122
+ const backoff = config.retryBackoff ? config.retryBackoff(err, delay3) : new Promise((resolve5) => {
57123
+ setTimeout(resolve5, delay3);
57016
57124
  });
57017
57125
  if (config.onRetryAttempt) {
57018
57126
  await config.onRetryAttempt(err);
@@ -98798,7 +98906,7 @@ async function retryBackoff(fn, strategy) {
98798
98906
  retryInterval = initialInterval * Math.pow(x2, exponent) + Math.random() * 1e3;
98799
98907
  }
98800
98908
  const d = Math.min(retryInterval, maxInterval);
98801
- await delay(d);
98909
+ await delay2(d);
98802
98910
  x2++;
98803
98911
  }
98804
98912
  }
@@ -98819,8 +98927,8 @@ function retryIntervalFromResponse(res) {
98819
98927
  }
98820
98928
  return 0;
98821
98929
  }
98822
- async function delay(delay2) {
98823
- return new Promise((resolve5) => setTimeout(resolve5, delay2));
98930
+ async function delay2(delay3) {
98931
+ return new Promise((resolve5) => setTimeout(resolve5, delay3));
98824
98932
  }
98825
98933
  var defaultBackoff, PermanentError, TemporaryError, codeRangeRE2;
98826
98934
  var init_retries = __esm({
@@ -154276,16 +154384,18 @@ async function initSessionStore(dataDir) {
154276
154384
  if (_store3 && _storeDataDir3 === dataDir) return _store3;
154277
154385
  _store3 = null;
154278
154386
  _storeDataDir3 = null;
154387
+ let degradedReason = "SQLite runtime unavailable";
154279
154388
  try {
154280
- const store2 = new SessionSqliteStore();
154281
- await store2.init(dataDir);
154389
+ const store2 = await initializeSqliteStore(() => new SessionSqliteStore(), dataDir, "Session store");
154282
154390
  _store3 = store2;
154283
154391
  _storeDataDir3 = dataDir;
154284
154392
  return store2;
154285
154393
  } catch (err) {
154286
- console.error(`[memorix] SessionSqliteStore unavailable, running in degraded read-only mode: ${err instanceof Error ? err.message : err}`);
154394
+ if (!isSqliteUnavailableError(err)) throw err;
154395
+ degradedReason = formatSqliteFailure(err);
154396
+ console.error(`[memorix] SessionSqliteStore unavailable, running in degraded read-only mode: ${degradedReason}`);
154287
154397
  }
154288
- const store = new SessionGracefulDegrade();
154398
+ const store = new SessionGracefulDegrade(degradedReason);
154289
154399
  await store.init(dataDir);
154290
154400
  _store3 = store;
154291
154401
  _storeDataDir3 = dataDir;
@@ -154297,6 +154407,7 @@ var init_session_store = __esm({
154297
154407
  "use strict";
154298
154408
  init_esm_shims();
154299
154409
  init_sqlite_db();
154410
+ init_sqlite_reliability();
154300
154411
  SessionSqliteStore = class {
154301
154412
  db = null;
154302
154413
  dataDir = "";
@@ -154385,7 +154496,7 @@ var init_session_store = __esm({
154385
154496
  }
154386
154497
  const stmtComplete = this._stmtCompleteActive;
154387
154498
  const stmtIns = this.stmtInsert;
154388
- const result = this.db.transaction(() => {
154499
+ return retrySqliteBusy(async () => this.db.transaction(() => {
154389
154500
  let completedCount = 0;
154390
154501
  for (const pid of projectIds) {
154391
154502
  const info = stmtComplete.run({ pid, now: now3 });
@@ -154393,18 +154504,24 @@ var init_session_store = __esm({
154393
154504
  }
154394
154505
  stmtIns.run(sessionToRow(newSession));
154395
154506
  return completedCount;
154396
- })();
154397
- return result;
154507
+ })(), "Session rollover");
154398
154508
  }
154399
154509
  getBackendName() {
154400
154510
  return "sqlite";
154401
154511
  }
154402
154512
  };
154403
154513
  SessionGracefulDegrade = class {
154514
+ constructor(reason = "SQLite runtime unavailable") {
154515
+ this.reason = reason;
154516
+ }
154517
+ reason;
154404
154518
  warned = false;
154519
+ unavailableRead() {
154520
+ return degradedReadError("sessions");
154521
+ }
154405
154522
  warn() {
154406
154523
  if (!this.warned) {
154407
- console.error("[memorix] SessionStore: SQLite unavailable \u2014 sessions are disabled (read-only empty). Install better-sqlite3 for full functionality.");
154524
+ console.error("[memorix] SessionStore: SQLite unavailable \u2014 sessions cannot be read or written. Install a supported SQLite runtime.");
154408
154525
  this.warned = true;
154409
154526
  }
154410
154527
  }
@@ -154412,33 +154529,39 @@ var init_session_store = __esm({
154412
154529
  this.warn();
154413
154530
  }
154414
154531
  async loadAll() {
154415
- return [];
154532
+ throw this.unavailableRead();
154416
154533
  }
154417
154534
  async getById(_id) {
154418
- return void 0;
154535
+ throw this.unavailableRead();
154419
154536
  }
154420
154537
  async loadByProject(_projectId) {
154421
- return [];
154538
+ throw this.unavailableRead();
154422
154539
  }
154423
154540
  async loadActive(_projectId) {
154424
- return [];
154541
+ throw this.unavailableRead();
154425
154542
  }
154426
154543
  async insert(_session) {
154427
154544
  this.warn();
154545
+ throw degradedWriteError("sessions");
154428
154546
  }
154429
154547
  async update(_session) {
154430
154548
  this.warn();
154549
+ throw degradedWriteError("sessions");
154431
154550
  }
154432
154551
  async bulkUpdate(_sessions) {
154433
154552
  this.warn();
154553
+ throw degradedWriteError("sessions");
154434
154554
  }
154435
154555
  async atomicRolloverInsert(_newSession, _projectIds, _now) {
154436
154556
  this.warn();
154437
- return 0;
154557
+ throw degradedWriteError("sessions");
154438
154558
  }
154439
154559
  getBackendName() {
154440
154560
  return "degraded";
154441
154561
  }
154562
+ getBackendReason() {
154563
+ return this.reason;
154564
+ }
154442
154565
  };
154443
154566
  _store3 = null;
154444
154567
  _storeDataDir3 = null;
@@ -169896,7 +170019,7 @@ var MCP_SERVER_INFO_META_KEY = "io.modelcontextprotocol/serverInfo";
169896
170019
  function getMcpServerInfo() {
169897
170020
  return {
169898
170021
  name: "memorix",
169899
- version: true ? "1.9.2" : "1.0.1"
170022
+ version: true ? "1.9.3" : "1.0.1"
169900
170023
  };
169901
170024
  }
169902
170025
  function createMcpDiscoverResult(capabilities, serverInfo) {