memorix 1.9.1 → 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.
Files changed (46) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +17 -4
  3. package/README.zh-CN.md +8 -4
  4. package/dist/cli/index.js +448 -243
  5. package/dist/index.js +302 -165
  6. package/dist/maintenance-runner.js +194 -98
  7. package/dist/media-audio-runner.js +196 -100
  8. package/dist/media-video-runner.js +194 -98
  9. package/dist/memcode-runtime/CHANGELOG.md +22 -0
  10. package/dist/sdk.js +301 -164
  11. package/dist/vector-backfill-runner.js +194 -98
  12. package/docs/AGENT_OPERATOR_PLAYBOOK.md +15 -0
  13. package/docs/ARCHITECTURE.md +23 -0
  14. package/docs/DEVELOPMENT.md +1 -1
  15. package/docs/INTEGRATIONS.md +4 -0
  16. package/docs/PERFORMANCE.md +50 -0
  17. package/docs/README.md +1 -1
  18. package/docs/SETUP.md +5 -0
  19. package/package.json +1 -2
  20. package/plugins/antigravity/memorix/plugin.json +1 -1
  21. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  22. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  23. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  24. package/plugins/copilot/memorix/plugin.json +1 -1
  25. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  26. package/plugins/hermes/memorix/plugin.yaml +1 -1
  27. package/plugins/omp/memorix/package.json +1 -1
  28. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  29. package/plugins/pi/memorix/package.json +1 -1
  30. package/server.json +2 -2
  31. package/src/cli/commands/doctor.ts +78 -17
  32. package/src/cli/commands/memory.ts +2 -1
  33. package/src/cli/default-mode.ts +15 -0
  34. package/src/cli/index.ts +10 -1
  35. package/src/codegraph/lite-provider.ts +10 -1
  36. package/src/dashboard/maintenance.ts +11 -2
  37. package/src/memory/consolidation.ts +15 -6
  38. package/src/store/mini-skill-store.ts +31 -22
  39. package/src/store/obs-store.ts +46 -30
  40. package/src/store/session-store.ts +35 -21
  41. package/src/store/sqlite-db.ts +16 -7
  42. package/src/store/sqlite-reliability.ts +87 -0
  43. package/src/store/sqlite-store.ts +4 -1
  44. package/assets/star-history-dark.svg +0 -30
  45. package/assets/star-history-light.svg +0 -30
  46. package/assets/star-history.json +0 -712
package/dist/index.js CHANGED
@@ -452,70 +452,79 @@ function getDatabase(dataDir) {
452
452
  loadBetterSqlite3();
453
453
  fs.mkdirSync(dataDir, { recursive: true });
454
454
  const dbPath = path3.join(dataDir, "memorix.db");
455
- const db2 = createDatabase(dbPath);
456
- db2.pragma("journal_mode = WAL");
457
- db2.pragma("busy_timeout = 5000");
458
- db2.pragma("foreign_keys = ON");
459
- db2.exec(CREATE_OBSERVATIONS_TABLE);
460
- db2.exec(CREATE_MINI_SKILLS_TABLE);
461
- db2.exec(CREATE_SESSIONS_TABLE);
462
- db2.exec(CREATE_META_TABLE);
463
- db2.exec(CREATE_TEAM_AGENTS_TABLE);
464
- db2.exec(CREATE_TEAM_TASKS_TABLE);
465
- db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
466
- db2.exec(CREATE_TEAM_MESSAGES_TABLE);
467
- db2.exec(CREATE_TEAM_LOCKS_TABLE);
468
- db2.exec(CREATE_TEAM_ROLES_TABLE);
469
- db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
470
- db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
471
- db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
472
- db2.exec(CREATE_CODE_FILES_TABLE);
473
- db2.exec(CREATE_CODE_SYMBOLS_TABLE);
474
- db2.exec(CREATE_CODE_EDGES_TABLE);
475
- db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
476
- db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
477
- db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
478
- db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
455
+ let db2;
479
456
  try {
480
- db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
481
- } catch {
482
- }
483
- try {
484
- db2.exec(`ALTER TABLE mini_skills ADD COLUMN updatedAt TEXT`);
485
- } catch {
486
- }
487
- try {
488
- db2.exec(`ALTER TABLE observations ADD COLUMN createdByAgentId TEXT`);
489
- } catch {
490
- }
491
- try {
492
- db2.exec(`ALTER TABLE observations ADD COLUMN writeGeneration INTEGER DEFAULT 0`);
493
- } catch {
494
- }
495
- try {
496
- db2.exec(`ALTER TABLE team_tasks ADD COLUMN required_role TEXT`);
497
- } catch {
498
- }
499
- try {
500
- db2.exec(`ALTER TABLE team_tasks ADD COLUMN preferred_role TEXT`);
501
- } catch {
502
- }
503
- try {
504
- db2.exec(`ALTER TABLE team_messages ADD COLUMN to_role TEXT`);
505
- } catch {
506
- }
507
- try {
508
- db2.exec(`ALTER TABLE team_messages ADD COLUMN handoff_status TEXT`);
509
- } catch {
457
+ db2 = createDatabase(dbPath);
458
+ db2.pragma("busy_timeout = 5000");
459
+ db2.pragma("journal_mode = WAL");
460
+ db2.pragma("foreign_keys = ON");
461
+ db2.exec(CREATE_OBSERVATIONS_TABLE);
462
+ db2.exec(CREATE_MINI_SKILLS_TABLE);
463
+ db2.exec(CREATE_SESSIONS_TABLE);
464
+ db2.exec(CREATE_META_TABLE);
465
+ db2.exec(CREATE_TEAM_AGENTS_TABLE);
466
+ db2.exec(CREATE_TEAM_TASKS_TABLE);
467
+ db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
468
+ db2.exec(CREATE_TEAM_MESSAGES_TABLE);
469
+ db2.exec(CREATE_TEAM_LOCKS_TABLE);
470
+ db2.exec(CREATE_TEAM_ROLES_TABLE);
471
+ db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
472
+ db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
473
+ db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
474
+ db2.exec(CREATE_CODE_FILES_TABLE);
475
+ db2.exec(CREATE_CODE_SYMBOLS_TABLE);
476
+ db2.exec(CREATE_CODE_EDGES_TABLE);
477
+ db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
478
+ db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
479
+ db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
480
+ db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
481
+ try {
482
+ db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
483
+ } catch {
484
+ }
485
+ try {
486
+ db2.exec(`ALTER TABLE mini_skills ADD COLUMN updatedAt TEXT`);
487
+ } catch {
488
+ }
489
+ try {
490
+ db2.exec(`ALTER TABLE observations ADD COLUMN createdByAgentId TEXT`);
491
+ } catch {
492
+ }
493
+ try {
494
+ db2.exec(`ALTER TABLE observations ADD COLUMN writeGeneration INTEGER DEFAULT 0`);
495
+ } catch {
496
+ }
497
+ try {
498
+ db2.exec(`ALTER TABLE team_tasks ADD COLUMN required_role TEXT`);
499
+ } catch {
500
+ }
501
+ try {
502
+ db2.exec(`ALTER TABLE team_tasks ADD COLUMN preferred_role TEXT`);
503
+ } catch {
504
+ }
505
+ try {
506
+ db2.exec(`ALTER TABLE team_messages ADD COLUMN to_role TEXT`);
507
+ } catch {
508
+ }
509
+ try {
510
+ db2.exec(`ALTER TABLE team_messages ADD COLUMN handoff_status TEXT`);
511
+ } catch {
512
+ }
513
+ applySchemaMigrations(db2);
514
+ db2.exec(CREATE_INDEXES);
515
+ initializeObservationLexicalIndex(db2);
516
+ db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
517
+ db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
518
+ db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
519
+ _dbCache.set(normalized, db2);
520
+ return db2;
521
+ } catch (error) {
522
+ try {
523
+ db2?.close();
524
+ } catch {
525
+ }
526
+ throw error;
510
527
  }
511
- applySchemaMigrations(db2);
512
- db2.exec(CREATE_INDEXES);
513
- initializeObservationLexicalIndex(db2);
514
- db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
515
- db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
516
- db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
517
- _dbCache.set(normalized, db2);
518
- return db2;
519
528
  }
520
529
  function closeAllDatabases() {
521
530
  for (const [key, db2] of _dbCache) {
@@ -2329,6 +2338,74 @@ var init_types = __esm({
2329
2338
  }
2330
2339
  });
2331
2340
 
2341
+ // src/store/sqlite-reliability.ts
2342
+ function isTransientSqliteError(error) {
2343
+ const code = error?.code;
2344
+ if (typeof code === "string") {
2345
+ return /^SQLITE_BUSY(?:_|$)/i.test(code);
2346
+ }
2347
+ return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
2348
+ }
2349
+ function isSqliteUnavailableError(error) {
2350
+ return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
2351
+ }
2352
+ function degradedReadError(storeName) {
2353
+ return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
2354
+ }
2355
+ function degradedWriteError(storeName) {
2356
+ return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
2357
+ }
2358
+ function formatSqliteFailure(error) {
2359
+ return error instanceof Error && error.message ? error.message : String(error);
2360
+ }
2361
+ function delay(ms) {
2362
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
2363
+ }
2364
+ async function retrySqliteBusy(operation, label) {
2365
+ for (let attempt = 0; ; attempt++) {
2366
+ try {
2367
+ return await operation();
2368
+ } catch (error) {
2369
+ if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
2370
+ const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
2371
+ console.error(
2372
+ `[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
2373
+ );
2374
+ await delay(waitMs);
2375
+ }
2376
+ }
2377
+ }
2378
+ async function initializeSqliteStore(factory, dataDir, label) {
2379
+ try {
2380
+ loadBetterSqlite3();
2381
+ } catch (error) {
2382
+ throw new SqliteUnavailableError(error);
2383
+ }
2384
+ return retrySqliteBusy(async () => {
2385
+ const store = factory();
2386
+ await store.init(dataDir);
2387
+ return store;
2388
+ }, label);
2389
+ }
2390
+ var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
2391
+ var init_sqlite_reliability = __esm({
2392
+ "src/store/sqlite-reliability.ts"() {
2393
+ "use strict";
2394
+ init_esm_shims();
2395
+ init_sqlite_db();
2396
+ SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
2397
+ SqliteUnavailableError = class extends Error {
2398
+ code = "MEMORIX_SQLITE_UNAVAILABLE";
2399
+ constructor(cause) {
2400
+ super(
2401
+ cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
2402
+ );
2403
+ this.name = "SqliteUnavailableError";
2404
+ }
2405
+ };
2406
+ }
2407
+ });
2408
+
2332
2409
  // src/store/mini-skill-store.ts
2333
2410
  var mini_skill_store_exports = {};
2334
2411
  __export(mini_skill_store_exports, {
@@ -2400,16 +2477,18 @@ async function initMiniSkillStore(dataDir) {
2400
2477
  if (_store && _storeDataDir === dataDir) return _store;
2401
2478
  _store = null;
2402
2479
  _storeDataDir = null;
2480
+ let degradedReason = "SQLite runtime unavailable";
2403
2481
  try {
2404
- const store2 = new MiniSkillSqliteStore();
2405
- await store2.init(dataDir);
2482
+ const store2 = await initializeSqliteStore(() => new MiniSkillSqliteStore(), dataDir, "Mini-skill store");
2406
2483
  _store = store2;
2407
2484
  _storeDataDir = dataDir;
2408
2485
  return store2;
2409
2486
  } catch (err) {
2410
- console.error(`[memorix] MiniSkillSqliteStore unavailable, running in degraded read-only mode: ${err instanceof Error ? err.message : err}`);
2487
+ if (!isSqliteUnavailableError(err)) throw err;
2488
+ degradedReason = err instanceof Error ? err.message : String(err);
2489
+ console.error(`[memorix] MiniSkillSqliteStore unavailable, running in degraded read-only mode: ${degradedReason}`);
2411
2490
  }
2412
- const store = new MiniSkillGracefulDegrade();
2491
+ const store = new MiniSkillGracefulDegrade(degradedReason);
2413
2492
  await store.init(dataDir);
2414
2493
  _store = store;
2415
2494
  _storeDataDir = dataDir;
@@ -2421,6 +2500,7 @@ var init_mini_skill_store = __esm({
2421
2500
  "use strict";
2422
2501
  init_esm_shims();
2423
2502
  init_sqlite_db();
2503
+ init_sqlite_reliability();
2424
2504
  MiniSkillSqliteStore = class {
2425
2505
  db = null;
2426
2506
  dataDir = "";
@@ -2529,7 +2609,7 @@ var init_mini_skill_store = __esm({
2529
2609
  * SQLite serializes write transactions, so concurrent calls are safely sequenced.
2530
2610
  */
2531
2611
  async atomicInsertWithId(skillWithoutId) {
2532
- const result = this.db.transaction(() => {
2612
+ return retrySqliteBusy(async () => this.db.transaction(() => {
2533
2613
  const row = this.stmtGetMeta.get("mini_skills_next_id");
2534
2614
  const nextId2 = row ? parseInt(row.value, 10) : 1;
2535
2615
  const skill2 = { ...skillWithoutId, id: nextId2 };
@@ -2538,8 +2618,7 @@ var init_mini_skill_store = __esm({
2538
2618
  this.stmtBumpGeneration.run();
2539
2619
  this.knownGeneration = this.readGeneration();
2540
2620
  return skill2;
2541
- })();
2542
- return result;
2621
+ })(), "Mini-skill promotion");
2543
2622
  }
2544
2623
  // ── Freshness ────────────────────────────────────────────────────
2545
2624
  async ensureFresh() {
@@ -2558,10 +2637,17 @@ var init_mini_skill_store = __esm({
2558
2637
  }
2559
2638
  };
2560
2639
  MiniSkillGracefulDegrade = class {
2640
+ constructor(reason = "SQLite runtime unavailable") {
2641
+ this.reason = reason;
2642
+ }
2643
+ reason;
2561
2644
  warned = false;
2645
+ unavailableRead() {
2646
+ return degradedReadError("mini-skills");
2647
+ }
2562
2648
  warn() {
2563
2649
  if (!this.warned) {
2564
- console.error("[memorix] MiniSkillStore: SQLite unavailable \u2014 mini-skills are disabled (read-only empty). Install better-sqlite3 for full functionality.");
2650
+ console.error("[memorix] MiniSkillStore: SQLite unavailable \u2014 mini-skills cannot be read or written. Install a supported SQLite runtime.");
2565
2651
  this.warned = true;
2566
2652
  }
2567
2653
  }
@@ -2569,28 +2655,33 @@ var init_mini_skill_store = __esm({
2569
2655
  this.warn();
2570
2656
  }
2571
2657
  async loadAll() {
2572
- return [];
2658
+ throw this.unavailableRead();
2573
2659
  }
2574
2660
  async loadByProject(_projectId) {
2575
- return [];
2661
+ throw this.unavailableRead();
2576
2662
  }
2577
2663
  async loadIdCounter() {
2578
- return 1;
2664
+ throw this.unavailableRead();
2579
2665
  }
2580
2666
  async insert(_skill) {
2581
2667
  this.warn();
2668
+ throw degradedWriteError("mini-skills");
2582
2669
  }
2583
2670
  async update(_skill) {
2584
2671
  this.warn();
2672
+ throw degradedWriteError("mini-skills");
2585
2673
  }
2586
2674
  async remove(_id) {
2587
2675
  this.warn();
2676
+ throw degradedWriteError("mini-skills");
2588
2677
  }
2589
2678
  async saveIdCounter(_nextId) {
2679
+ this.warn();
2680
+ throw degradedWriteError("mini-skills");
2590
2681
  }
2591
2682
  async atomicInsertWithId(skillWithoutId) {
2592
2683
  this.warn();
2593
- return { ...skillWithoutId, id: 0 };
2684
+ throw degradedWriteError("mini-skills");
2594
2685
  }
2595
2686
  async ensureFresh() {
2596
2687
  return false;
@@ -2601,6 +2692,9 @@ var init_mini_skill_store = __esm({
2601
2692
  getBackendName() {
2602
2693
  return "degraded";
2603
2694
  }
2695
+ getBackendReason() {
2696
+ return this.reason;
2697
+ }
2604
2698
  };
2605
2699
  _store = null;
2606
2700
  _storeDataDir = null;
@@ -4855,10 +4949,10 @@ async function fetchWithRetry(url, apiKey, body, options = {}, attempt = 0, nati
4855
4949
  );
4856
4950
  }
4857
4951
  if (options.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
4858
- const delay2 = BASE_DELAY_MS * Math.pow(2, attempt);
4952
+ const delay3 = BASE_DELAY_MS * Math.pow(2, attempt);
4859
4953
  const retryAfter = response.headers.get("retry-after");
4860
4954
  const parsedRetryAfter = retryAfter ? parseInt(retryAfter, 10) * 1e3 : NaN;
4861
- const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay2;
4955
+ const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay3;
4862
4956
  console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
4863
4957
  await waitForRetry(waitMs, options.signal);
4864
4958
  return fetchWithRetry(url, apiKey, body, options, attempt + 1, nativeGemini);
@@ -6890,6 +6984,7 @@ var init_sqlite_store = __esm({
6890
6984
  "use strict";
6891
6985
  init_esm_shims();
6892
6986
  init_sqlite_db();
6987
+ init_sqlite_reliability();
6893
6988
  init_sqlite_fts();
6894
6989
  SqliteBackend = class {
6895
6990
  db = null;
@@ -7167,7 +7262,9 @@ var init_sqlite_store = __esm({
7167
7262
  // ── Compound atomic operation ────────────────────────────────────
7168
7263
  async atomic(fn) {
7169
7264
  const run = this._atomicQueue.catch(() => void 0).then(async () => {
7170
- this.db.prepare("BEGIN IMMEDIATE").run();
7265
+ await retrySqliteBusy(async () => {
7266
+ this.db.prepare("BEGIN IMMEDIATE").run();
7267
+ }, "Observation atomic write");
7171
7268
  try {
7172
7269
  const tx = {
7173
7270
  loadAll: async () => this.rawLoadAll(),
@@ -7266,15 +7363,15 @@ function resetObservationStore() {
7266
7363
  async function createObservationStore(dataDir) {
7267
7364
  try {
7268
7365
  const { SqliteBackend: SqliteBackend2 } = await Promise.resolve().then(() => (init_sqlite_store(), sqlite_store_exports));
7269
- const store2 = new SqliteBackend2();
7270
- await store2.init(dataDir);
7271
- return store2;
7366
+ return await initializeSqliteStore(() => new SqliteBackend2(), dataDir, "Observation store");
7272
7367
  } catch (err) {
7273
- console.error(`[memorix] SQLite backend unavailable \u2014 degraded mode (read-only): ${err instanceof Error ? err.message : err}`);
7368
+ if (!isSqliteUnavailableError(err)) throw err;
7369
+ const reason = formatSqliteFailure(err);
7370
+ console.error(`[memorix] SQLite module unavailable \u2014 degraded mode (reads/writes disabled): ${reason}`);
7371
+ const degraded = new DegradedBackend(reason);
7372
+ await degraded.init(dataDir);
7373
+ return degraded;
7274
7374
  }
7275
- const store = new DegradedBackend();
7276
- await store.init(dataDir);
7277
- return store;
7278
7375
  }
7279
7376
  async function initObservationStore(dataDir) {
7280
7377
  if (_store2 && _storeDataDir2 === dataDir) {
@@ -7298,36 +7395,44 @@ var init_obs_store = __esm({
7298
7395
  "src/store/obs-store.ts"() {
7299
7396
  "use strict";
7300
7397
  init_esm_shims();
7398
+ init_sqlite_reliability();
7301
7399
  _store2 = null;
7302
7400
  _storeDataDir2 = null;
7303
7401
  DegradedBackend = class {
7402
+ constructor(reason = "SQLite runtime unavailable") {
7403
+ this.reason = reason;
7404
+ }
7405
+ reason;
7304
7406
  dataDir = "";
7407
+ unavailableRead() {
7408
+ return degradedReadError("observations");
7409
+ }
7305
7410
  async init(dataDir) {
7306
7411
  this.dataDir = dataDir;
7307
7412
  }
7308
7413
  async loadAll() {
7309
- return [];
7414
+ throw this.unavailableRead();
7310
7415
  }
7311
7416
  async loadByProject(_projectId, _options) {
7312
- return [];
7417
+ throw this.unavailableRead();
7313
7418
  }
7314
7419
  async countByProject(_projectId, _options) {
7315
- return 0;
7420
+ throw this.unavailableRead();
7316
7421
  }
7317
7422
  async getById(_id) {
7318
- return void 0;
7423
+ throw this.unavailableRead();
7319
7424
  }
7320
7425
  async loadIdCounter() {
7321
- return 1;
7426
+ throw this.unavailableRead();
7322
7427
  }
7323
7428
  async countAll() {
7324
- return 0;
7429
+ throw this.unavailableRead();
7325
7430
  }
7326
7431
  async listProjectIds() {
7327
- return [];
7432
+ throw this.unavailableRead();
7328
7433
  }
7329
7434
  async searchLexical(_options) {
7330
- return [];
7435
+ throw this.unavailableRead();
7331
7436
  }
7332
7437
  hasLexicalIndex() {
7333
7438
  return false;
@@ -7336,25 +7441,25 @@ var init_obs_store = __esm({
7336
7441
  return false;
7337
7442
  }
7338
7443
  async insert(_obs) {
7339
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7444
+ throw degradedWriteError("observations");
7340
7445
  }
7341
7446
  async update(_obs) {
7342
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7447
+ throw degradedWriteError("observations");
7343
7448
  }
7344
7449
  async remove(_id) {
7345
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7450
+ throw degradedWriteError("observations");
7346
7451
  }
7347
7452
  async bulkReplace(_obs) {
7348
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7453
+ throw degradedWriteError("observations");
7349
7454
  }
7350
7455
  async bulkRemoveByIds(_ids) {
7351
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7456
+ throw degradedWriteError("observations");
7352
7457
  }
7353
7458
  async saveIdCounter(_nextId) {
7354
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7459
+ throw degradedWriteError("observations");
7355
7460
  }
7356
7461
  async atomic(_fn) {
7357
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7462
+ throw degradedWriteError("observations");
7358
7463
  }
7359
7464
  async ensureFresh() {
7360
7465
  return false;
@@ -7367,6 +7472,9 @@ var init_obs_store = __esm({
7367
7472
  getBackendName() {
7368
7473
  return "degraded";
7369
7474
  }
7475
+ getBackendReason() {
7476
+ return this.reason;
7477
+ }
7370
7478
  };
7371
7479
  }
7372
7480
  });
@@ -10882,7 +10990,8 @@ function clampCursor(afterId) {
10882
10990
  }
10883
10991
  async function loadConsolidationPage(projectId, options) {
10884
10992
  const limit2 = clampBatchSize(options.limit);
10885
- const page = await getObservationStore().loadByProject(projectId, {
10993
+ const store = options.store ?? getObservationStore();
10994
+ const page = await store.loadByProject(projectId, {
10886
10995
  status: "active",
10887
10996
  afterId: clampCursor(options.afterId),
10888
10997
  limit: limit2 + 1
@@ -10942,7 +11051,7 @@ async function findConsolidationCandidates(_projectDir, projectId, opts) {
10942
11051
  return findClusters(page.observations, threshold);
10943
11052
  }
10944
11053
  async function executeConsolidation(_projectDir, projectId, opts) {
10945
- const store = getObservationStore();
11054
+ const store = opts?.store ?? getObservationStore();
10946
11055
  const page = await loadConsolidationPage(projectId, opts ?? {});
10947
11056
  const clusters = findClusters(page.observations, opts?.threshold ?? DEFAULT_SIMILARITY_THRESHOLD);
10948
11057
  if (clusters.length === 0) {
@@ -56962,10 +57071,10 @@ var require_retry3 = __commonJS({
56962
57071
  if (!await shouldRetryFn(err)) {
56963
57072
  return { shouldRetry: false, config: err.config };
56964
57073
  }
56965
- const delay2 = getNextRetryDelay(config);
57074
+ const delay3 = getNextRetryDelay(config);
56966
57075
  err.config.retryConfig.currentRetryAttempt += 1;
56967
- const backoff = config.retryBackoff ? config.retryBackoff(err, delay2) : new Promise((resolve5) => {
56968
- setTimeout(resolve5, delay2);
57076
+ const backoff = config.retryBackoff ? config.retryBackoff(err, delay3) : new Promise((resolve5) => {
57077
+ setTimeout(resolve5, delay3);
56969
57078
  });
56970
57079
  if (config.onRetryAttempt) {
56971
57080
  await config.onRetryAttempt(err);
@@ -98751,7 +98860,7 @@ async function retryBackoff(fn, strategy) {
98751
98860
  retryInterval = initialInterval * Math.pow(x2, exponent) + Math.random() * 1e3;
98752
98861
  }
98753
98862
  const d = Math.min(retryInterval, maxInterval);
98754
- await delay(d);
98863
+ await delay2(d);
98755
98864
  x2++;
98756
98865
  }
98757
98866
  }
@@ -98772,8 +98881,8 @@ function retryIntervalFromResponse(res) {
98772
98881
  }
98773
98882
  return 0;
98774
98883
  }
98775
- async function delay(delay2) {
98776
- return new Promise((resolve5) => setTimeout(resolve5, delay2));
98884
+ async function delay2(delay3) {
98885
+ return new Promise((resolve5) => setTimeout(resolve5, delay3));
98777
98886
  }
98778
98887
  var defaultBackoff, PermanentError, TemporaryError, codeRangeRE2;
98779
98888
  var init_retries = __esm({
@@ -148882,7 +148991,7 @@ __export(lite_provider_exports, {
148882
148991
  refreshProjectLite: () => refreshProjectLite
148883
148992
  });
148884
148993
  import { createHash as createHash10 } from "crypto";
148885
- import { readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
148994
+ import { existsSync as existsSync12, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
148886
148995
  import { join as join4, relative as relative2 } from "path";
148887
148996
  function hashText2(text3) {
148888
148997
  return createHash10("sha256").update(text3).digest("hex");
@@ -148899,6 +149008,9 @@ function resolveMaxFileBytes(value) {
148899
149008
  if (!Number.isFinite(value)) return DEFAULT_CODEGRAPH_MAX_FILE_BYTES;
148900
149009
  return Math.max(1, Math.floor(value));
148901
149010
  }
149011
+ function isPythonVirtualenvDir(dir) {
149012
+ return existsSync12(join4(dir, "pyvenv.cfg"));
149013
+ }
148902
149014
  function walk(root, exclude, maxFiles) {
148903
149015
  const out = [];
148904
149016
  const visit = (dir) => {
@@ -148916,6 +149028,7 @@ function walk(root, exclude, maxFiles) {
148916
149028
  if (entry.isDirectory()) {
148917
149029
  if (entry.name === ".git" || entry.name === ".worktrees" || entry.name === ".tmp" || entry.name === "node_modules") continue;
148918
149030
  if (rel === ".claude/worktrees" || rel.startsWith(".claude/worktrees/")) continue;
149031
+ if (isPythonVirtualenvDir(abs)) continue;
148919
149032
  visit(abs);
148920
149033
  if (out.length >= maxFiles) return;
148921
149034
  continue;
@@ -152812,7 +152925,7 @@ __export(vector_backfill_runner_exports, {
152812
152925
  import { spawn as spawn4 } from "child_process";
152813
152926
  import {
152814
152927
  closeSync,
152815
- existsSync as existsSync12,
152928
+ existsSync as existsSync13,
152816
152929
  mkdirSync as mkdirSync2,
152817
152930
  openSync,
152818
152931
  readFileSync as readFileSync9,
@@ -152940,7 +153053,7 @@ function releaseVectorBackfillLock(lockPath = process.env.MEMORIX_VECTOR_BACKFIL
152940
153053
  }
152941
153054
  function launchDetachedVectorBackfill(request, options = {}) {
152942
153055
  const runnerPath = options.runnerPath ?? resolveVectorBackfillRunnerPath();
152943
- const exists = options.exists ?? existsSync12;
153056
+ const exists = options.exists ?? existsSync13;
152944
153057
  if (!exists(runnerPath)) return false;
152945
153058
  const lock = acquireVectorBackfillLock(request.dataDir, request.projectId, options.lockPath);
152946
153059
  if (!lock) return false;
@@ -154225,16 +154338,18 @@ async function initSessionStore(dataDir) {
154225
154338
  if (_store3 && _storeDataDir3 === dataDir) return _store3;
154226
154339
  _store3 = null;
154227
154340
  _storeDataDir3 = null;
154341
+ let degradedReason = "SQLite runtime unavailable";
154228
154342
  try {
154229
- const store2 = new SessionSqliteStore();
154230
- await store2.init(dataDir);
154343
+ const store2 = await initializeSqliteStore(() => new SessionSqliteStore(), dataDir, "Session store");
154231
154344
  _store3 = store2;
154232
154345
  _storeDataDir3 = dataDir;
154233
154346
  return store2;
154234
154347
  } catch (err) {
154235
- console.error(`[memorix] SessionSqliteStore unavailable, running in degraded read-only mode: ${err instanceof Error ? err.message : err}`);
154348
+ if (!isSqliteUnavailableError(err)) throw err;
154349
+ degradedReason = formatSqliteFailure(err);
154350
+ console.error(`[memorix] SessionSqliteStore unavailable, running in degraded read-only mode: ${degradedReason}`);
154236
154351
  }
154237
- const store = new SessionGracefulDegrade();
154352
+ const store = new SessionGracefulDegrade(degradedReason);
154238
154353
  await store.init(dataDir);
154239
154354
  _store3 = store;
154240
154355
  _storeDataDir3 = dataDir;
@@ -154246,6 +154361,7 @@ var init_session_store = __esm({
154246
154361
  "use strict";
154247
154362
  init_esm_shims();
154248
154363
  init_sqlite_db();
154364
+ init_sqlite_reliability();
154249
154365
  SessionSqliteStore = class {
154250
154366
  db = null;
154251
154367
  dataDir = "";
@@ -154334,7 +154450,7 @@ var init_session_store = __esm({
154334
154450
  }
154335
154451
  const stmtComplete = this._stmtCompleteActive;
154336
154452
  const stmtIns = this.stmtInsert;
154337
- const result = this.db.transaction(() => {
154453
+ return retrySqliteBusy(async () => this.db.transaction(() => {
154338
154454
  let completedCount = 0;
154339
154455
  for (const pid of projectIds) {
154340
154456
  const info = stmtComplete.run({ pid, now: now3 });
@@ -154342,18 +154458,24 @@ var init_session_store = __esm({
154342
154458
  }
154343
154459
  stmtIns.run(sessionToRow(newSession));
154344
154460
  return completedCount;
154345
- })();
154346
- return result;
154461
+ })(), "Session rollover");
154347
154462
  }
154348
154463
  getBackendName() {
154349
154464
  return "sqlite";
154350
154465
  }
154351
154466
  };
154352
154467
  SessionGracefulDegrade = class {
154468
+ constructor(reason = "SQLite runtime unavailable") {
154469
+ this.reason = reason;
154470
+ }
154471
+ reason;
154353
154472
  warned = false;
154473
+ unavailableRead() {
154474
+ return degradedReadError("sessions");
154475
+ }
154354
154476
  warn() {
154355
154477
  if (!this.warned) {
154356
- console.error("[memorix] SessionStore: SQLite unavailable \u2014 sessions are disabled (read-only empty). Install better-sqlite3 for full functionality.");
154478
+ console.error("[memorix] SessionStore: SQLite unavailable \u2014 sessions cannot be read or written. Install a supported SQLite runtime.");
154357
154479
  this.warned = true;
154358
154480
  }
154359
154481
  }
@@ -154361,33 +154483,39 @@ var init_session_store = __esm({
154361
154483
  this.warn();
154362
154484
  }
154363
154485
  async loadAll() {
154364
- return [];
154486
+ throw this.unavailableRead();
154365
154487
  }
154366
154488
  async getById(_id) {
154367
- return void 0;
154489
+ throw this.unavailableRead();
154368
154490
  }
154369
154491
  async loadByProject(_projectId) {
154370
- return [];
154492
+ throw this.unavailableRead();
154371
154493
  }
154372
154494
  async loadActive(_projectId) {
154373
- return [];
154495
+ throw this.unavailableRead();
154374
154496
  }
154375
154497
  async insert(_session) {
154376
154498
  this.warn();
154499
+ throw degradedWriteError("sessions");
154377
154500
  }
154378
154501
  async update(_session) {
154379
154502
  this.warn();
154503
+ throw degradedWriteError("sessions");
154380
154504
  }
154381
154505
  async bulkUpdate(_sessions) {
154382
154506
  this.warn();
154507
+ throw degradedWriteError("sessions");
154383
154508
  }
154384
154509
  async atomicRolloverInsert(_newSession, _projectIds, _now) {
154385
154510
  this.warn();
154386
- return 0;
154511
+ throw degradedWriteError("sessions");
154387
154512
  }
154388
154513
  getBackendName() {
154389
154514
  return "degraded";
154390
154515
  }
154516
+ getBackendReason() {
154517
+ return this.reason;
154518
+ }
154391
154519
  };
154392
154520
  _store3 = null;
154393
154521
  _storeDataDir3 = null;
@@ -157861,7 +157989,7 @@ var init_sanitizer = __esm({
157861
157989
  });
157862
157990
 
157863
157991
  // src/workspace/applier.ts
157864
- import { existsSync as existsSync13, mkdirSync as mkdirSync3, copyFileSync, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, renameSync } from "fs";
157992
+ import { existsSync as existsSync14, mkdirSync as mkdirSync3, copyFileSync, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, renameSync } from "fs";
157865
157993
  import { dirname } from "path";
157866
157994
  var WorkspaceSyncApplier;
157867
157995
  var init_applier = __esm({
@@ -157892,7 +158020,7 @@ var init_applier = __esm({
157892
158020
  for (const file of files) {
157893
158021
  try {
157894
158022
  const dir = dirname(file.filePath);
157895
- if (!existsSync13(dir)) {
158023
+ if (!existsSync14(dir)) {
157896
158024
  mkdirSync3(dir, { recursive: true });
157897
158025
  }
157898
158026
  } catch (err) {
@@ -157901,7 +158029,7 @@ var init_applier = __esm({
157901
158029
  }
157902
158030
  }
157903
158031
  for (const file of files) {
157904
- if (existsSync13(file.filePath)) {
158032
+ if (existsSync14(file.filePath)) {
157905
158033
  try {
157906
158034
  const backupPath = file.filePath + `.backup-${Date.now()}`;
157907
158035
  copyFileSync(file.filePath, backupPath);
@@ -157952,7 +158080,7 @@ var init_applier = __esm({
157952
158080
  cleanBackups(backups) {
157953
158081
  for (const backup of backups) {
157954
158082
  try {
157955
- if (existsSync13(backup.backupPath)) {
158083
+ if (existsSync14(backup.backupPath)) {
157956
158084
  unlinkSync2(backup.backupPath);
157957
158085
  }
157958
158086
  } catch {
@@ -157964,7 +158092,7 @@ var init_applier = __esm({
157964
158092
  });
157965
158093
 
157966
158094
  // src/workspace/engine.ts
157967
- import { readFileSync as readFileSync10, readdirSync as readdirSync3, existsSync as existsSync14, cpSync, mkdirSync as mkdirSync4 } from "fs";
158095
+ import { readFileSync as readFileSync10, readdirSync as readdirSync3, existsSync as existsSync15, cpSync, mkdirSync as mkdirSync4 } from "fs";
157968
158096
  import { join as join19 } from "path";
157969
158097
  import { homedir as homedir21 } from "os";
157970
158098
  var WorkspaceSyncEngine;
@@ -158044,7 +158172,7 @@ var init_engine4 = __esm({
158044
158172
  }
158045
158173
  const merged = /* @__PURE__ */ new Map();
158046
158174
  for (const path38 of pathsToCheck) {
158047
- if (existsSync14(path38)) {
158175
+ if (existsSync15(path38)) {
158048
158176
  try {
158049
158177
  const content = readFileSync10(path38, "utf-8");
158050
158178
  const servers = adapter.parse(content);
@@ -158098,7 +158226,7 @@ var init_engine4 = __esm({
158098
158226
  const adapter = this.adapters.get(target);
158099
158227
  const configPath = adapter.getConfigPath(this.projectRoot);
158100
158228
  let configContent;
158101
- if (target === "antigravity" && existsSync14(configPath)) {
158229
+ if (target === "antigravity" && existsSync15(configPath)) {
158102
158230
  try {
158103
158231
  const existing = JSON.parse(readFileSync10(configPath, "utf-8"));
158104
158232
  const generated = JSON.parse(adapter.generate(result.mcpServers.scanned));
@@ -158174,13 +158302,13 @@ var init_engine4 = __esm({
158174
158302
  join19(home, dir)
158175
158303
  ];
158176
158304
  for (const skillsRoot of paths) {
158177
- if (!existsSync14(skillsRoot)) continue;
158305
+ if (!existsSync15(skillsRoot)) continue;
158178
158306
  try {
158179
158307
  const entries = readdirSync3(skillsRoot, { withFileTypes: true });
158180
158308
  for (const entry of entries) {
158181
158309
  if (!entry.isDirectory()) continue;
158182
158310
  const skillMd = join19(skillsRoot, entry.name, "SKILL.md");
158183
- if (!existsSync14(skillMd)) continue;
158311
+ if (!existsSync15(skillMd)) continue;
158184
158312
  let description = "";
158185
158313
  try {
158186
158314
  const content = readFileSync10(skillMd, "utf-8");
@@ -158229,7 +158357,7 @@ var init_engine4 = __esm({
158229
158357
  for (const skill2 of skills) {
158230
158358
  if (skill2.sourceAgent === target) continue;
158231
158359
  const dest = join19(targetDir, skill2.name);
158232
- if (existsSync14(dest)) {
158360
+ if (existsSync15(dest)) {
158233
158361
  skipped.push(`${skill2.name} (already exists in ${target})`);
158234
158362
  continue;
158235
158363
  }
@@ -158245,7 +158373,7 @@ var init_engine4 = __esm({
158245
158373
  scanWorkflows() {
158246
158374
  const workflows = [];
158247
158375
  const wfDir = join19(this.projectRoot, ".windsurf", "workflows");
158248
- if (!existsSync14(wfDir)) return workflows;
158376
+ if (!existsSync15(wfDir)) return workflows;
158249
158377
  try {
158250
158378
  const files = readdirSync3(wfDir).filter((f3) => f3.endsWith(".md"));
158251
158379
  for (const file of files) {
@@ -159643,7 +159771,7 @@ var init_request_context = __esm({
159643
159771
  function getMcpServerInfo() {
159644
159772
  return {
159645
159773
  name: "memorix",
159646
- version: true ? "1.9.1" : "1.0.1"
159774
+ version: true ? "1.9.3" : "1.0.1"
159647
159775
  };
159648
159776
  }
159649
159777
  function createMcpDiscoverResult(capabilities, serverInfo) {
@@ -159711,7 +159839,7 @@ __export(behavior_exports, {
159711
159839
  getBehaviorConfig: () => getBehaviorConfig,
159712
159840
  resetBehaviorConfigCache: () => resetBehaviorConfigCache
159713
159841
  });
159714
- import { existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
159842
+ import { existsSync as existsSync16, readFileSync as readFileSync11 } from "fs";
159715
159843
  import { homedir as homedir22 } from "os";
159716
159844
  function isSessionInject(value) {
159717
159845
  return value === "full" || value === "minimal" || value === "silent";
@@ -159722,7 +159850,7 @@ function isFormationMode(value) {
159722
159850
  function legacyBehavior(homeDir) {
159723
159851
  const configPath = getLegacyConfigJsonPath(homeDir);
159724
159852
  try {
159725
- if (!existsSync15(configPath)) return {};
159853
+ if (!existsSync16(configPath)) return {};
159726
159854
  const parsed = JSON.parse(readFileSync11(configPath, "utf-8"));
159727
159855
  return parsed.behavior && typeof parsed.behavior === "object" && !Array.isArray(parsed.behavior) ? parsed.behavior : {};
159728
159856
  } catch {
@@ -161076,11 +161204,11 @@ __export(current_facts_exports, {
161076
161204
  formatGitFact: () => formatGitFact
161077
161205
  });
161078
161206
  import { execFileSync } from "child_process";
161079
- import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
161207
+ import { existsSync as existsSync17, readFileSync as readFileSync12 } from "fs";
161080
161208
  import path29 from "path";
161081
161209
  function readTextIfExists(filePath) {
161082
161210
  try {
161083
- if (!existsSync16(filePath)) return null;
161211
+ if (!existsSync17(filePath)) return null;
161084
161212
  return readFileSync12(filePath, "utf8");
161085
161213
  } catch {
161086
161214
  return null;
@@ -161371,7 +161499,7 @@ __export(external_provider_exports, {
161371
161499
  runExternalCodeGraphLifecycle: () => runExternalCodeGraphLifecycle
161372
161500
  });
161373
161501
  import { spawn as spawn5 } from "child_process";
161374
- import { existsSync as existsSync17, readFileSync as readFileSync13 } from "fs";
161502
+ import { existsSync as existsSync18, readFileSync as readFileSync13 } from "fs";
161375
161503
  import { delimiter, dirname as dirname2, extname, isAbsolute as isAbsolute3, join as join20, relative as relative4, resolve as resolve3, sep } from "path";
161376
161504
  function boundedTimeout(value) {
161377
161505
  if (!Number.isFinite(value)) return DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS;
@@ -161408,13 +161536,13 @@ function resolveCommandCandidates(command) {
161408
161536
  }
161409
161537
  function resolveLaunch(command) {
161410
161538
  for (const candidate of resolveCommandCandidates(command)) {
161411
- if (!existsSync17(candidate)) continue;
161539
+ if (!existsSync18(candidate)) continue;
161412
161540
  const extension3 = extname(candidate).toLowerCase();
161413
161541
  if (extension3 === ".cmd") {
161414
161542
  const bundleRoot = resolve3(dirname2(candidate), "..");
161415
161543
  const node = join20(bundleRoot, "node.exe");
161416
161544
  const entry = join20(bundleRoot, "lib", "dist", "bin", "codegraph.js");
161417
- if (existsSync17(node) && existsSync17(entry)) {
161545
+ if (existsSync18(node) && existsSync18(entry)) {
161418
161546
  return { executable: node, prefixArgs: ["--liftoff-only", entry] };
161419
161547
  }
161420
161548
  try {
@@ -161423,7 +161551,7 @@ function resolveLaunch(command) {
161423
161551
  if (match2?.[1]) {
161424
161552
  const base = dirname2(candidate).endsWith(sep) ? dirname2(candidate) : dirname2(candidate) + sep;
161425
161553
  const entry2 = resolve3(match2[1].replace(/%(?:~)?dp0%?/gi, base));
161426
- if (existsSync17(entry2)) return { executable: process.execPath, prefixArgs: [entry2] };
161554
+ if (existsSync18(entry2)) return { executable: process.execPath, prefixArgs: [entry2] };
161427
161555
  }
161428
161556
  } catch {
161429
161557
  }
@@ -161571,7 +161699,7 @@ async function inspectExternalCodeGraph(input) {
161571
161699
  const health2 = { state: "disabled", reason: "External CodeGraph is disabled by configuration." };
161572
161700
  return { health: health2, quality: providerQuality({ mode, health: health2 }) };
161573
161701
  }
161574
- if (!existsSync17(join20(input.projectRoot, ".codegraph"))) {
161702
+ if (!existsSync18(join20(input.projectRoot, ".codegraph"))) {
161575
161703
  const health2 = { state: "not-detected", reason: "No local .codegraph index is present for this project." };
161576
161704
  return { health: health2, quality: providerQuality({ mode, health: health2 }) };
161577
161705
  }
@@ -161607,7 +161735,7 @@ async function runExternalCodeGraphLifecycle(input) {
161607
161735
  };
161608
161736
  }
161609
161737
  const indexPath = join20(input.projectRoot, ".codegraph");
161610
- if (input.action === "sync" && !existsSync17(indexPath)) {
161738
+ if (input.action === "sync" && !existsSync18(indexPath)) {
161611
161739
  const health = { state: "not-detected", reason: "No local .codegraph index is present for this project." };
161612
161740
  return {
161613
161741
  action: input.action,
@@ -161617,7 +161745,7 @@ async function runExternalCodeGraphLifecycle(input) {
161617
161745
  quality: providerQuality({ mode, health })
161618
161746
  };
161619
161747
  }
161620
- if (input.action === "init" && existsSync17(indexPath)) {
161748
+ if (input.action === "init" && existsSync18(indexPath)) {
161621
161749
  const inspected2 = await inspectExternalCodeGraph(input);
161622
161750
  return {
161623
161751
  action: input.action,
@@ -162678,7 +162806,7 @@ __export(auto_context_exports, {
162678
162806
  formatAutoProjectContextSummary: () => formatAutoProjectContextSummary,
162679
162807
  formatLegacyAutoProjectContextPrompt: () => formatLegacyAutoProjectContextPrompt
162680
162808
  });
162681
- import { existsSync as existsSync18, statSync as statSync5 } from "fs";
162809
+ import { existsSync as existsSync19, statSync as statSync5 } from "fs";
162682
162810
  import path30 from "path";
162683
162811
  function activeProjectObservations(observations2, projectId) {
162684
162812
  return observations2.filter((obs) => obs.projectId === projectId && (obs.status ?? "active") === "active");
@@ -163024,7 +163152,7 @@ function existingLensCandidates(rootPath, lens) {
163024
163152
  for (const candidate of lensPathCandidates(lens)) {
163025
163153
  const absolute = path30.join(rootPath, candidate);
163026
163154
  try {
163027
- if (!existsSync18(absolute)) continue;
163155
+ if (!existsSync19(absolute)) continue;
163028
163156
  const stat5 = statSync5(absolute);
163029
163157
  if (stat5.isFile()) out.push(candidate);
163030
163158
  if (stat5.isDirectory()) out.push(candidate.replace(/\\/g, "/"));
@@ -163558,7 +163686,7 @@ var engine_exports2 = {};
163558
163686
  __export(engine_exports2, {
163559
163687
  SkillsEngine: () => SkillsEngine
163560
163688
  });
163561
- import { existsSync as existsSync19, readFileSync as readFileSync14, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, readdirSync as readdirSync4 } from "fs";
163689
+ import { existsSync as existsSync20, readFileSync as readFileSync14, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, readdirSync as readdirSync4 } from "fs";
163562
163690
  import { join as join21 } from "path";
163563
163691
  import { homedir as homedir23 } from "os";
163564
163692
  var SKILLS_DIRS, SKILL_WORTHY_TYPES, MIN_OBS_FOR_SKILL, MIN_SCORE_FOR_SKILL, LOW_SIGNAL_TITLE_PATTERNS, LOW_SIGNAL_ENTITY_PATTERNS, COMMAND_TRACE_PATTERNS2, SkillsEngine;
@@ -163639,7 +163767,7 @@ var init_engine5 = __esm({
163639
163767
  paths.push(join21(home, dir));
163640
163768
  }
163641
163769
  for (const skillsRoot of paths) {
163642
- if (!existsSync19(skillsRoot)) continue;
163770
+ if (!existsSync20(skillsRoot)) continue;
163643
163771
  try {
163644
163772
  const entries = readdirSync4(skillsRoot, { withFileTypes: true });
163645
163773
  for (const entry of entries) {
@@ -163647,7 +163775,7 @@ var init_engine5 = __esm({
163647
163775
  const name = entry.name;
163648
163776
  if (seen.has(name)) continue;
163649
163777
  const skillMd = join21(skillsRoot, name, "SKILL.md");
163650
- if (!existsSync19(skillMd)) continue;
163778
+ if (!existsSync20(skillMd)) continue;
163651
163779
  try {
163652
163780
  const content = readFileSync14(skillMd, "utf-8");
163653
163781
  const description = this.parseDescription(content);
@@ -165448,7 +165576,8 @@ async function executeDeduplicate(context, payload, token) {
165448
165576
  async function previewConsolidate(context) {
165449
165577
  const clusters = await findConsolidationCandidates(
165450
165578
  context.projectRoot ?? context.dataDir,
165451
- context.projectId
165579
+ context.projectId,
165580
+ { store: context.store }
165452
165581
  );
165453
165582
  const payload = { clusterIds: normalizeClusters(clusters.map((cluster) => cluster.ids)) };
165454
165583
  return {
@@ -165471,11 +165600,19 @@ async function executeConsolidate(context, payload, token) {
165471
165600
  const clusterIds = record80.clusterIds.map((ids, index) => payloadIds(ids, `clusterIds[${index}]`));
165472
165601
  const normalized = { clusterIds: normalizeClusters(clusterIds) };
165473
165602
  verify("consolidate", context.projectId, normalized, token);
165474
- const current = await findConsolidationCandidates(context.projectRoot ?? context.dataDir, context.projectId);
165603
+ const current = await findConsolidationCandidates(
165604
+ context.projectRoot ?? context.dataDir,
165605
+ context.projectId,
165606
+ { store: context.store }
165607
+ );
165475
165608
  if (JSON.stringify(normalized.clusterIds) !== JSON.stringify(normalizeClusters(current.map((cluster) => cluster.ids)))) {
165476
165609
  throw new DashboardMaintenanceError("Memory changed after the preview. Refresh before consolidating.", 409);
165477
165610
  }
165478
- const result = await executeConsolidation(context.projectRoot ?? context.dataDir, context.projectId);
165611
+ const result = await executeConsolidation(
165612
+ context.projectRoot ?? context.dataDir,
165613
+ context.projectId,
165614
+ { store: context.store }
165615
+ );
165479
165616
  return { action: "consolidate", projectId: context.projectId, ...result };
165480
165617
  }
165481
165618
  async function retentionCandidates(context) {
@@ -166632,7 +166769,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
166632
166769
  }
166633
166770
  case "/config": {
166634
166771
  const os6 = await import("os");
166635
- const { existsSync: existsSync22 } = await import("fs");
166772
+ const { existsSync: existsSync23 } = await import("fs");
166636
166773
  const { join: join26 } = await import("path");
166637
166774
  const configProjectRoot = effectiveProjectRoot;
166638
166775
  const resolved = getResolvedConfig({ projectRoot: configProjectRoot });
@@ -166660,7 +166797,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
166660
166797
  if (fpath === null) {
166661
166798
  files[key] = { exists: false, path: "unavailable", unavailable: true };
166662
166799
  } else {
166663
- files[key] = { exists: existsSync22(fpath), path: fpath };
166800
+ files[key] = { exists: existsSync23(fpath), path: fpath };
166664
166801
  }
166665
166802
  }
166666
166803
  } catch {
@@ -167470,7 +167607,7 @@ var init_task_graph = __esm({
167470
167607
 
167471
167608
  // src/orchestrate/context-collector.ts
167472
167609
  import { execFileSync as execFileSync2 } from "child_process";
167473
- import { readFileSync as readFileSync15, existsSync as existsSync20 } from "fs";
167610
+ import { readFileSync as readFileSync15, existsSync as existsSync21 } from "fs";
167474
167611
  import { join as join22 } from "path";
167475
167612
  function normalizeEntryLimit(value, fallback) {
167476
167613
  if (!Number.isSafeInteger(value) || value < 1) return fallback;
@@ -167547,7 +167684,7 @@ function collectFileTree(projectDir2, maxEntries) {
167547
167684
  function collectDependencies(projectDir2) {
167548
167685
  try {
167549
167686
  const pkgPath = join22(projectDir2, "package.json");
167550
- if (!existsSync20(pkgPath)) return "";
167687
+ if (!existsSync21(pkgPath)) return "";
167551
167688
  const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
167552
167689
  const parts = [];
167553
167690
  if (pkg.dependencies && Object.keys(pkg.dependencies).length > 0) {
@@ -170048,11 +170185,11 @@ __export(hooks_path_exports, {
170048
170185
  resolveGitDir: () => resolveGitDir,
170049
170186
  resolveHooksDir: () => resolveHooksDir
170050
170187
  });
170051
- import { existsSync as existsSync21, readFileSync as readFileSync16, statSync as statSync6, mkdirSync as mkdirSync6 } from "fs";
170188
+ import { existsSync as existsSync22, readFileSync as readFileSync16, statSync as statSync6, mkdirSync as mkdirSync6 } from "fs";
170052
170189
  import path35 from "path";
170053
170190
  function resolveGitDir(projectRoot) {
170054
170191
  const dotGit = path35.join(projectRoot, ".git");
170055
- if (!existsSync21(dotGit)) return null;
170192
+ if (!existsSync22(dotGit)) return null;
170056
170193
  const stat5 = statSync6(dotGit);
170057
170194
  if (stat5.isDirectory()) {
170058
170195
  return dotGit;
@@ -170064,7 +170201,7 @@ function resolveGitDir(projectRoot) {
170064
170201
  if (match2) {
170065
170202
  const gitdir = match2[1].trim();
170066
170203
  const resolved = path35.isAbsolute(gitdir) ? gitdir : path35.resolve(projectRoot, gitdir);
170067
- if (existsSync21(resolved)) {
170204
+ if (existsSync22(resolved)) {
170068
170205
  return resolved;
170069
170206
  }
170070
170207
  }
@@ -174659,10 +174796,10 @@ Preview: ${analysis.description.slice(0, 300)}${analysis.description.length > 30
174659
174796
  const { ensureHooksDir: ensureHooksDir2 } = await Promise.resolve().then(() => (init_hooks_path(), hooks_path_exports));
174660
174797
  const resolved = ensureHooksDir2(project.rootPath);
174661
174798
  if (resolved) {
174662
- const { existsSync: existsSync22, readFileSync: readFileSync17, writeFileSync: writeFileSync5, chmodSync } = await import("fs");
174799
+ const { existsSync: existsSync23, readFileSync: readFileSync17, writeFileSync: writeFileSync5, chmodSync } = await import("fs");
174663
174800
  const { hookPath } = resolved;
174664
174801
  const HOOK_MARKER = "# [memorix-git-hook]";
174665
- const needsInstall = !existsSync22(hookPath) || !readFileSync17(hookPath, "utf-8").includes(HOOK_MARKER);
174802
+ const needsInstall = !existsSync23(hookPath) || !readFileSync17(hookPath, "utf-8").includes(HOOK_MARKER);
174666
174803
  if (needsInstall) {
174667
174804
  const hookScript = `#!/bin/sh
174668
174805
  ${HOOK_MARKER}
@@ -174671,7 +174808,7 @@ if command -v memorix >/dev/null 2>&1; then
174671
174808
  memorix ingest commit --auto >/dev/null 2>&1 &
174672
174809
  fi
174673
174810
  `;
174674
- if (existsSync22(hookPath)) {
174811
+ if (existsSync23(hookPath)) {
174675
174812
  const existing = readFileSync17(hookPath, "utf-8");
174676
174813
  writeFileSync5(hookPath, existing.trimEnd() + `
174677
174814
 
@@ -175343,7 +175480,7 @@ var init_serve_shared = __esm({
175343
175480
 
175344
175481
  // src/cli/version.ts
175345
175482
  function getCliVersion() {
175346
- return true ? "1.9.1" : pkg.version;
175483
+ return true ? "1.9.3" : pkg.version;
175347
175484
  }
175348
175485
  var init_version3 = __esm({
175349
175486
  "src/cli/version.ts"() {