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
@@ -550,70 +550,79 @@ function getDatabase(dataDir) {
550
550
  loadBetterSqlite3();
551
551
  fs.mkdirSync(dataDir, { recursive: true });
552
552
  const dbPath = path3.join(dataDir, "memorix.db");
553
- const db2 = createDatabase(dbPath);
554
- db2.pragma("journal_mode = WAL");
555
- db2.pragma("busy_timeout = 5000");
556
- db2.pragma("foreign_keys = ON");
557
- db2.exec(CREATE_OBSERVATIONS_TABLE);
558
- db2.exec(CREATE_MINI_SKILLS_TABLE);
559
- db2.exec(CREATE_SESSIONS_TABLE);
560
- db2.exec(CREATE_META_TABLE);
561
- db2.exec(CREATE_TEAM_AGENTS_TABLE);
562
- db2.exec(CREATE_TEAM_TASKS_TABLE);
563
- db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
564
- db2.exec(CREATE_TEAM_MESSAGES_TABLE);
565
- db2.exec(CREATE_TEAM_LOCKS_TABLE);
566
- db2.exec(CREATE_TEAM_ROLES_TABLE);
567
- db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
568
- db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
569
- db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
570
- db2.exec(CREATE_CODE_FILES_TABLE);
571
- db2.exec(CREATE_CODE_SYMBOLS_TABLE);
572
- db2.exec(CREATE_CODE_EDGES_TABLE);
573
- db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
574
- db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
575
- db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
576
- db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
553
+ let db2;
577
554
  try {
578
- db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
579
- } catch {
580
- }
581
- try {
582
- db2.exec(`ALTER TABLE mini_skills ADD COLUMN updatedAt TEXT`);
583
- } catch {
584
- }
585
- try {
586
- db2.exec(`ALTER TABLE observations ADD COLUMN createdByAgentId TEXT`);
587
- } catch {
588
- }
589
- try {
590
- db2.exec(`ALTER TABLE observations ADD COLUMN writeGeneration INTEGER DEFAULT 0`);
591
- } catch {
592
- }
593
- try {
594
- db2.exec(`ALTER TABLE team_tasks ADD COLUMN required_role TEXT`);
595
- } catch {
596
- }
597
- try {
598
- db2.exec(`ALTER TABLE team_tasks ADD COLUMN preferred_role TEXT`);
599
- } catch {
600
- }
601
- try {
602
- db2.exec(`ALTER TABLE team_messages ADD COLUMN to_role TEXT`);
603
- } catch {
604
- }
605
- try {
606
- db2.exec(`ALTER TABLE team_messages ADD COLUMN handoff_status TEXT`);
607
- } catch {
555
+ db2 = createDatabase(dbPath);
556
+ db2.pragma("busy_timeout = 5000");
557
+ db2.pragma("journal_mode = WAL");
558
+ db2.pragma("foreign_keys = ON");
559
+ db2.exec(CREATE_OBSERVATIONS_TABLE);
560
+ db2.exec(CREATE_MINI_SKILLS_TABLE);
561
+ db2.exec(CREATE_SESSIONS_TABLE);
562
+ db2.exec(CREATE_META_TABLE);
563
+ db2.exec(CREATE_TEAM_AGENTS_TABLE);
564
+ db2.exec(CREATE_TEAM_TASKS_TABLE);
565
+ db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
566
+ db2.exec(CREATE_TEAM_MESSAGES_TABLE);
567
+ db2.exec(CREATE_TEAM_LOCKS_TABLE);
568
+ db2.exec(CREATE_TEAM_ROLES_TABLE);
569
+ db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
570
+ db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
571
+ db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
572
+ db2.exec(CREATE_CODE_FILES_TABLE);
573
+ db2.exec(CREATE_CODE_SYMBOLS_TABLE);
574
+ db2.exec(CREATE_CODE_EDGES_TABLE);
575
+ db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
576
+ db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
577
+ db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
578
+ db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
579
+ try {
580
+ db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
581
+ } catch {
582
+ }
583
+ try {
584
+ db2.exec(`ALTER TABLE mini_skills ADD COLUMN updatedAt TEXT`);
585
+ } catch {
586
+ }
587
+ try {
588
+ db2.exec(`ALTER TABLE observations ADD COLUMN createdByAgentId TEXT`);
589
+ } catch {
590
+ }
591
+ try {
592
+ db2.exec(`ALTER TABLE observations ADD COLUMN writeGeneration INTEGER DEFAULT 0`);
593
+ } catch {
594
+ }
595
+ try {
596
+ db2.exec(`ALTER TABLE team_tasks ADD COLUMN required_role TEXT`);
597
+ } catch {
598
+ }
599
+ try {
600
+ db2.exec(`ALTER TABLE team_tasks ADD COLUMN preferred_role TEXT`);
601
+ } catch {
602
+ }
603
+ try {
604
+ db2.exec(`ALTER TABLE team_messages ADD COLUMN to_role TEXT`);
605
+ } catch {
606
+ }
607
+ try {
608
+ db2.exec(`ALTER TABLE team_messages ADD COLUMN handoff_status TEXT`);
609
+ } catch {
610
+ }
611
+ applySchemaMigrations(db2);
612
+ db2.exec(CREATE_INDEXES);
613
+ initializeObservationLexicalIndex(db2);
614
+ db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
615
+ db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
616
+ db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
617
+ _dbCache.set(normalized, db2);
618
+ return db2;
619
+ } catch (error) {
620
+ try {
621
+ db2?.close();
622
+ } catch {
623
+ }
624
+ throw error;
608
625
  }
609
- applySchemaMigrations(db2);
610
- db2.exec(CREATE_INDEXES);
611
- initializeObservationLexicalIndex(db2);
612
- db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
613
- db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
614
- db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
615
- _dbCache.set(normalized, db2);
616
- return db2;
617
626
  }
618
627
  function closeAllDatabases() {
619
628
  for (const [key, db2] of _dbCache) {
@@ -2616,6 +2625,74 @@ var init_types = __esm({
2616
2625
  }
2617
2626
  });
2618
2627
 
2628
+ // src/store/sqlite-reliability.ts
2629
+ function isTransientSqliteError(error) {
2630
+ const code = error?.code;
2631
+ if (typeof code === "string") {
2632
+ return /^SQLITE_BUSY(?:_|$)/i.test(code);
2633
+ }
2634
+ return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
2635
+ }
2636
+ function isSqliteUnavailableError(error) {
2637
+ return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
2638
+ }
2639
+ function degradedReadError(storeName) {
2640
+ return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
2641
+ }
2642
+ function degradedWriteError(storeName) {
2643
+ return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
2644
+ }
2645
+ function formatSqliteFailure(error) {
2646
+ return error instanceof Error && error.message ? error.message : String(error);
2647
+ }
2648
+ function delay(ms) {
2649
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
2650
+ }
2651
+ async function retrySqliteBusy(operation, label) {
2652
+ for (let attempt = 0; ; attempt++) {
2653
+ try {
2654
+ return await operation();
2655
+ } catch (error) {
2656
+ if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
2657
+ const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
2658
+ console.error(
2659
+ `[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
2660
+ );
2661
+ await delay(waitMs);
2662
+ }
2663
+ }
2664
+ }
2665
+ async function initializeSqliteStore(factory, dataDir, label) {
2666
+ try {
2667
+ loadBetterSqlite3();
2668
+ } catch (error) {
2669
+ throw new SqliteUnavailableError(error);
2670
+ }
2671
+ return retrySqliteBusy(async () => {
2672
+ const store = factory();
2673
+ await store.init(dataDir);
2674
+ return store;
2675
+ }, label);
2676
+ }
2677
+ var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
2678
+ var init_sqlite_reliability = __esm({
2679
+ "src/store/sqlite-reliability.ts"() {
2680
+ "use strict";
2681
+ init_esm_shims();
2682
+ init_sqlite_db();
2683
+ SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
2684
+ SqliteUnavailableError = class extends Error {
2685
+ code = "MEMORIX_SQLITE_UNAVAILABLE";
2686
+ constructor(cause) {
2687
+ super(
2688
+ cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
2689
+ );
2690
+ this.name = "SqliteUnavailableError";
2691
+ }
2692
+ };
2693
+ }
2694
+ });
2695
+
2619
2696
  // src/store/file-lock.ts
2620
2697
  import { promises as fs2 } from "fs";
2621
2698
  import { randomUUID as randomUUID3 } from "crypto";
@@ -4539,10 +4616,10 @@ async function fetchWithRetry(url, apiKey, body, options = {}, attempt = 0, nati
4539
4616
  );
4540
4617
  }
4541
4618
  if (options.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
4542
- const delay2 = BASE_DELAY_MS * Math.pow(2, attempt);
4619
+ const delay3 = BASE_DELAY_MS * Math.pow(2, attempt);
4543
4620
  const retryAfter = response.headers.get("retry-after");
4544
4621
  const parsedRetryAfter = retryAfter ? parseInt(retryAfter, 10) * 1e3 : NaN;
4545
- const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay2;
4622
+ const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay3;
4546
4623
  console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
4547
4624
  await waitForRetry(waitMs, options.signal);
4548
4625
  return fetchWithRetry(url, apiKey, body, options, attempt + 1, nativeGemini);
@@ -6574,6 +6651,7 @@ var init_sqlite_store = __esm({
6574
6651
  "use strict";
6575
6652
  init_esm_shims();
6576
6653
  init_sqlite_db();
6654
+ init_sqlite_reliability();
6577
6655
  init_sqlite_fts();
6578
6656
  SqliteBackend = class {
6579
6657
  db = null;
@@ -6851,7 +6929,9 @@ var init_sqlite_store = __esm({
6851
6929
  // ── Compound atomic operation ────────────────────────────────────
6852
6930
  async atomic(fn) {
6853
6931
  const run = this._atomicQueue.catch(() => void 0).then(async () => {
6854
- this.db.prepare("BEGIN IMMEDIATE").run();
6932
+ await retrySqliteBusy(async () => {
6933
+ this.db.prepare("BEGIN IMMEDIATE").run();
6934
+ }, "Observation atomic write");
6855
6935
  try {
6856
6936
  const tx = {
6857
6937
  loadAll: async () => this.rawLoadAll(),
@@ -6950,15 +7030,15 @@ function resetObservationStore() {
6950
7030
  async function createObservationStore(dataDir) {
6951
7031
  try {
6952
7032
  const { SqliteBackend: SqliteBackend2 } = await Promise.resolve().then(() => (init_sqlite_store(), sqlite_store_exports));
6953
- const store2 = new SqliteBackend2();
6954
- await store2.init(dataDir);
6955
- return store2;
7033
+ return await initializeSqliteStore(() => new SqliteBackend2(), dataDir, "Observation store");
6956
7034
  } catch (err) {
6957
- console.error(`[memorix] SQLite backend unavailable \u2014 degraded mode (read-only): ${err instanceof Error ? err.message : err}`);
7035
+ if (!isSqliteUnavailableError(err)) throw err;
7036
+ const reason = formatSqliteFailure(err);
7037
+ console.error(`[memorix] SQLite module unavailable \u2014 degraded mode (reads/writes disabled): ${reason}`);
7038
+ const degraded = new DegradedBackend(reason);
7039
+ await degraded.init(dataDir);
7040
+ return degraded;
6958
7041
  }
6959
- const store = new DegradedBackend();
6960
- await store.init(dataDir);
6961
- return store;
6962
7042
  }
6963
7043
  async function initObservationStore(dataDir) {
6964
7044
  if (_store2 && _storeDataDir === dataDir) {
@@ -6982,36 +7062,44 @@ var init_obs_store = __esm({
6982
7062
  "src/store/obs-store.ts"() {
6983
7063
  "use strict";
6984
7064
  init_esm_shims();
7065
+ init_sqlite_reliability();
6985
7066
  _store2 = null;
6986
7067
  _storeDataDir = null;
6987
7068
  DegradedBackend = class {
7069
+ constructor(reason = "SQLite runtime unavailable") {
7070
+ this.reason = reason;
7071
+ }
7072
+ reason;
6988
7073
  dataDir = "";
7074
+ unavailableRead() {
7075
+ return degradedReadError("observations");
7076
+ }
6989
7077
  async init(dataDir) {
6990
7078
  this.dataDir = dataDir;
6991
7079
  }
6992
7080
  async loadAll() {
6993
- return [];
7081
+ throw this.unavailableRead();
6994
7082
  }
6995
7083
  async loadByProject(_projectId, _options) {
6996
- return [];
7084
+ throw this.unavailableRead();
6997
7085
  }
6998
7086
  async countByProject(_projectId, _options) {
6999
- return 0;
7087
+ throw this.unavailableRead();
7000
7088
  }
7001
7089
  async getById(_id) {
7002
- return void 0;
7090
+ throw this.unavailableRead();
7003
7091
  }
7004
7092
  async loadIdCounter() {
7005
- return 1;
7093
+ throw this.unavailableRead();
7006
7094
  }
7007
7095
  async countAll() {
7008
- return 0;
7096
+ throw this.unavailableRead();
7009
7097
  }
7010
7098
  async listProjectIds() {
7011
- return [];
7099
+ throw this.unavailableRead();
7012
7100
  }
7013
7101
  async searchLexical(_options) {
7014
- return [];
7102
+ throw this.unavailableRead();
7015
7103
  }
7016
7104
  hasLexicalIndex() {
7017
7105
  return false;
@@ -7020,25 +7108,25 @@ var init_obs_store = __esm({
7020
7108
  return false;
7021
7109
  }
7022
7110
  async insert(_obs) {
7023
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7111
+ throw degradedWriteError("observations");
7024
7112
  }
7025
7113
  async update(_obs) {
7026
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7114
+ throw degradedWriteError("observations");
7027
7115
  }
7028
7116
  async remove(_id) {
7029
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7117
+ throw degradedWriteError("observations");
7030
7118
  }
7031
7119
  async bulkReplace(_obs) {
7032
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7120
+ throw degradedWriteError("observations");
7033
7121
  }
7034
7122
  async bulkRemoveByIds(_ids) {
7035
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7123
+ throw degradedWriteError("observations");
7036
7124
  }
7037
7125
  async saveIdCounter(_nextId) {
7038
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7126
+ throw degradedWriteError("observations");
7039
7127
  }
7040
7128
  async atomic(_fn) {
7041
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
7129
+ throw degradedWriteError("observations");
7042
7130
  }
7043
7131
  async ensureFresh() {
7044
7132
  return false;
@@ -7051,6 +7139,9 @@ var init_obs_store = __esm({
7051
7139
  getBackendName() {
7052
7140
  return "degraded";
7053
7141
  }
7142
+ getBackendReason() {
7143
+ return this.reason;
7144
+ }
7054
7145
  };
7055
7146
  }
7056
7147
  });
@@ -9870,7 +9961,8 @@ function clampCursor(afterId) {
9870
9961
  }
9871
9962
  async function loadConsolidationPage(projectId, options) {
9872
9963
  const limit2 = clampBatchSize(options.limit);
9873
- const page = await getObservationStore().loadByProject(projectId, {
9964
+ const store = options.store ?? getObservationStore();
9965
+ const page = await store.loadByProject(projectId, {
9874
9966
  status: "active",
9875
9967
  afterId: clampCursor(options.afterId),
9876
9968
  limit: limit2 + 1
@@ -9930,7 +10022,7 @@ async function findConsolidationCandidates(_projectDir, projectId, opts) {
9930
10022
  return findClusters(page.observations, threshold);
9931
10023
  }
9932
10024
  async function executeConsolidation(_projectDir, projectId, opts) {
9933
- const store = getObservationStore();
10025
+ const store = opts?.store ?? getObservationStore();
9934
10026
  const page = await loadConsolidationPage(projectId, opts ?? {});
9935
10027
  const clusters = findClusters(page.observations, opts?.threshold ?? DEFAULT_SIMILARITY_THRESHOLD);
9936
10028
  if (clusters.length === 0) {
@@ -55229,10 +55321,10 @@ var require_retry3 = __commonJS({
55229
55321
  if (!await shouldRetryFn(err)) {
55230
55322
  return { shouldRetry: false, config: err.config };
55231
55323
  }
55232
- const delay2 = getNextRetryDelay(config);
55324
+ const delay3 = getNextRetryDelay(config);
55233
55325
  err.config.retryConfig.currentRetryAttempt += 1;
55234
- const backoff = config.retryBackoff ? config.retryBackoff(err, delay2) : new Promise((resolve2) => {
55235
- setTimeout(resolve2, delay2);
55326
+ const backoff = config.retryBackoff ? config.retryBackoff(err, delay3) : new Promise((resolve2) => {
55327
+ setTimeout(resolve2, delay3);
55236
55328
  });
55237
55329
  if (config.onRetryAttempt) {
55238
55330
  await config.onRetryAttempt(err);
@@ -97018,7 +97110,7 @@ async function retryBackoff(fn, strategy) {
97018
97110
  retryInterval = initialInterval * Math.pow(x2, exponent) + Math.random() * 1e3;
97019
97111
  }
97020
97112
  const d = Math.min(retryInterval, maxInterval);
97021
- await delay(d);
97113
+ await delay2(d);
97022
97114
  x2++;
97023
97115
  }
97024
97116
  }
@@ -97039,8 +97131,8 @@ function retryIntervalFromResponse(res) {
97039
97131
  }
97040
97132
  return 0;
97041
97133
  }
97042
- async function delay(delay2) {
97043
- return new Promise((resolve2) => setTimeout(resolve2, delay2));
97134
+ async function delay2(delay3) {
97135
+ return new Promise((resolve2) => setTimeout(resolve2, delay3));
97044
97136
  }
97045
97137
  var defaultBackoff, PermanentError, TemporaryError, codeRangeRE2;
97046
97138
  var init_retries = __esm({
@@ -146735,7 +146827,7 @@ __export(lite_provider_exports, {
146735
146827
  refreshProjectLite: () => refreshProjectLite
146736
146828
  });
146737
146829
  import { createHash as createHash10 } from "crypto";
146738
- import { readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
146830
+ import { existsSync as existsSync10, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
146739
146831
  import { join as join4, relative as relative2 } from "path";
146740
146832
  function hashText2(text2) {
146741
146833
  return createHash10("sha256").update(text2).digest("hex");
@@ -146752,6 +146844,9 @@ function resolveMaxFileBytes(value) {
146752
146844
  if (!Number.isFinite(value)) return DEFAULT_CODEGRAPH_MAX_FILE_BYTES;
146753
146845
  return Math.max(1, Math.floor(value));
146754
146846
  }
146847
+ function isPythonVirtualenvDir(dir) {
146848
+ return existsSync10(join4(dir, "pyvenv.cfg"));
146849
+ }
146755
146850
  function walk(root, exclude, maxFiles) {
146756
146851
  const out = [];
146757
146852
  const visit = (dir) => {
@@ -146769,6 +146864,7 @@ function walk(root, exclude, maxFiles) {
146769
146864
  if (entry.isDirectory()) {
146770
146865
  if (entry.name === ".git" || entry.name === ".worktrees" || entry.name === ".tmp" || entry.name === "node_modules") continue;
146771
146866
  if (rel === ".claude/worktrees" || rel.startsWith(".claude/worktrees/")) continue;
146867
+ if (isPythonVirtualenvDir(abs)) continue;
146772
146868
  visit(abs);
146773
146869
  if (out.length >= maxFiles) return;
146774
146870
  continue;
@@ -150288,7 +150384,7 @@ __export(vector_backfill_runner_exports, {
150288
150384
  import { spawn as spawn2 } from "child_process";
150289
150385
  import {
150290
150386
  closeSync,
150291
- existsSync as existsSync10,
150387
+ existsSync as existsSync11,
150292
150388
  mkdirSync as mkdirSync2,
150293
150389
  openSync,
150294
150390
  readFileSync as readFileSync9,
@@ -150416,7 +150512,7 @@ function releaseVectorBackfillLock(lockPath = process.env.MEMORIX_VECTOR_BACKFIL
150416
150512
  }
150417
150513
  function launchDetachedVectorBackfill(request, options = {}) {
150418
150514
  const runnerPath = options.runnerPath ?? resolveVectorBackfillRunnerPath();
150419
- const exists = options.exists ?? existsSync10;
150515
+ const exists = options.exists ?? existsSync11;
150420
150516
  if (!exists(runnerPath)) return false;
150421
150517
  const lock = acquireVectorBackfillLock(request.dataDir, request.projectId, options.lockPath);
150422
150518
  if (!lock) return false;
@@ -151711,7 +151807,7 @@ __export(audio_jobs_exports, {
151711
151807
  transcribeAudio: () => transcribeAudio
151712
151808
  });
151713
151809
  import { spawn as spawn3 } from "child_process";
151714
- import { existsSync as existsSync11 } from "fs";
151810
+ import { existsSync as existsSync12 } from "fs";
151715
151811
  import path21 from "path";
151716
151812
  import { fileURLToPath as fileURLToPath4 } from "url";
151717
151813
  function safeError3(error) {
@@ -151962,7 +152058,7 @@ function resolveMediaAudioRunnerPath(moduleUrl = import.meta.url) {
151962
152058
  }
151963
152059
  function launchMediaAudioRunner(request, options = {}) {
151964
152060
  const runnerPath = options.runnerPath ?? resolveMediaAudioRunnerPath();
151965
- if (!existsSync11(runnerPath)) return { launched: false, reason: "Audio runner is unavailable until Memorix is built or reinstalled." };
152061
+ if (!existsSync12(runnerPath)) return { launched: false, reason: "Audio runner is unavailable until Memorix is built or reinstalled." };
151966
152062
  try {
151967
152063
  const child = spawn3(process.execPath, [runnerPath, JSON.stringify(request)], {
151968
152064
  cwd: request.projectRoot,