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
@@ -388,70 +388,79 @@ function getDatabase(dataDir) {
388
388
  loadBetterSqlite3();
389
389
  fs.mkdirSync(dataDir, { recursive: true });
390
390
  const dbPath = path3.join(dataDir, "memorix.db");
391
- const db2 = createDatabase(dbPath);
392
- db2.pragma("journal_mode = WAL");
393
- db2.pragma("busy_timeout = 5000");
394
- db2.pragma("foreign_keys = ON");
395
- db2.exec(CREATE_OBSERVATIONS_TABLE);
396
- db2.exec(CREATE_MINI_SKILLS_TABLE);
397
- db2.exec(CREATE_SESSIONS_TABLE);
398
- db2.exec(CREATE_META_TABLE);
399
- db2.exec(CREATE_TEAM_AGENTS_TABLE);
400
- db2.exec(CREATE_TEAM_TASKS_TABLE);
401
- db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
402
- db2.exec(CREATE_TEAM_MESSAGES_TABLE);
403
- db2.exec(CREATE_TEAM_LOCKS_TABLE);
404
- db2.exec(CREATE_TEAM_ROLES_TABLE);
405
- db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
406
- db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
407
- db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
408
- db2.exec(CREATE_CODE_FILES_TABLE);
409
- db2.exec(CREATE_CODE_SYMBOLS_TABLE);
410
- db2.exec(CREATE_CODE_EDGES_TABLE);
411
- db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
412
- db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
413
- db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
414
- db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
391
+ let db2;
415
392
  try {
416
- db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
417
- } catch {
418
- }
419
- try {
420
- db2.exec(`ALTER TABLE mini_skills ADD COLUMN updatedAt TEXT`);
421
- } catch {
422
- }
423
- try {
424
- db2.exec(`ALTER TABLE observations ADD COLUMN createdByAgentId TEXT`);
425
- } catch {
426
- }
427
- try {
428
- db2.exec(`ALTER TABLE observations ADD COLUMN writeGeneration INTEGER DEFAULT 0`);
429
- } catch {
430
- }
431
- try {
432
- db2.exec(`ALTER TABLE team_tasks ADD COLUMN required_role TEXT`);
433
- } catch {
434
- }
435
- try {
436
- db2.exec(`ALTER TABLE team_tasks ADD COLUMN preferred_role TEXT`);
437
- } catch {
438
- }
439
- try {
440
- db2.exec(`ALTER TABLE team_messages ADD COLUMN to_role TEXT`);
441
- } catch {
442
- }
443
- try {
444
- db2.exec(`ALTER TABLE team_messages ADD COLUMN handoff_status TEXT`);
445
- } catch {
393
+ db2 = createDatabase(dbPath);
394
+ db2.pragma("busy_timeout = 5000");
395
+ db2.pragma("journal_mode = WAL");
396
+ db2.pragma("foreign_keys = ON");
397
+ db2.exec(CREATE_OBSERVATIONS_TABLE);
398
+ db2.exec(CREATE_MINI_SKILLS_TABLE);
399
+ db2.exec(CREATE_SESSIONS_TABLE);
400
+ db2.exec(CREATE_META_TABLE);
401
+ db2.exec(CREATE_TEAM_AGENTS_TABLE);
402
+ db2.exec(CREATE_TEAM_TASKS_TABLE);
403
+ db2.exec(CREATE_TEAM_TASK_DEPS_TABLE);
404
+ db2.exec(CREATE_TEAM_MESSAGES_TABLE);
405
+ db2.exec(CREATE_TEAM_LOCKS_TABLE);
406
+ db2.exec(CREATE_TEAM_ROLES_TABLE);
407
+ db2.exec(CREATE_GRAPH_ENTITIES_TABLE);
408
+ db2.exec(CREATE_GRAPH_RELATIONS_TABLE);
409
+ db2.exec(CREATE_CHAT_TRANSCRIPT_TABLE);
410
+ db2.exec(CREATE_CODE_FILES_TABLE);
411
+ db2.exec(CREATE_CODE_SYMBOLS_TABLE);
412
+ db2.exec(CREATE_CODE_EDGES_TABLE);
413
+ db2.exec(CREATE_OBSERVATION_CODE_REFS_TABLE);
414
+ db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
415
+ db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
416
+ db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
417
+ try {
418
+ db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
419
+ } catch {
420
+ }
421
+ try {
422
+ db2.exec(`ALTER TABLE mini_skills ADD COLUMN updatedAt TEXT`);
423
+ } catch {
424
+ }
425
+ try {
426
+ db2.exec(`ALTER TABLE observations ADD COLUMN createdByAgentId TEXT`);
427
+ } catch {
428
+ }
429
+ try {
430
+ db2.exec(`ALTER TABLE observations ADD COLUMN writeGeneration INTEGER DEFAULT 0`);
431
+ } catch {
432
+ }
433
+ try {
434
+ db2.exec(`ALTER TABLE team_tasks ADD COLUMN required_role TEXT`);
435
+ } catch {
436
+ }
437
+ try {
438
+ db2.exec(`ALTER TABLE team_tasks ADD COLUMN preferred_role TEXT`);
439
+ } catch {
440
+ }
441
+ try {
442
+ db2.exec(`ALTER TABLE team_messages ADD COLUMN to_role TEXT`);
443
+ } catch {
444
+ }
445
+ try {
446
+ db2.exec(`ALTER TABLE team_messages ADD COLUMN handoff_status TEXT`);
447
+ } catch {
448
+ }
449
+ applySchemaMigrations(db2);
450
+ db2.exec(CREATE_INDEXES);
451
+ initializeObservationLexicalIndex(db2);
452
+ db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
453
+ db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
454
+ db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
455
+ _dbCache.set(normalized, db2);
456
+ return db2;
457
+ } catch (error) {
458
+ try {
459
+ db2?.close();
460
+ } catch {
461
+ }
462
+ throw error;
446
463
  }
447
- applySchemaMigrations(db2);
448
- db2.exec(CREATE_INDEXES);
449
- initializeObservationLexicalIndex(db2);
450
- db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
451
- db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
452
- db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
453
- _dbCache.set(normalized, db2);
454
- return db2;
455
464
  }
456
465
  function closeAllDatabases() {
457
466
  for (const [key, db2] of _dbCache) {
@@ -2964,6 +2973,74 @@ var init_provider = __esm({
2964
2973
  }
2965
2974
  });
2966
2975
 
2976
+ // src/store/sqlite-reliability.ts
2977
+ function isTransientSqliteError(error) {
2978
+ const code = error?.code;
2979
+ if (typeof code === "string") {
2980
+ return /^SQLITE_BUSY(?:_|$)/i.test(code);
2981
+ }
2982
+ return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
2983
+ }
2984
+ function isSqliteUnavailableError(error) {
2985
+ return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
2986
+ }
2987
+ function degradedReadError(storeName) {
2988
+ return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
2989
+ }
2990
+ function degradedWriteError(storeName) {
2991
+ return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
2992
+ }
2993
+ function formatSqliteFailure(error) {
2994
+ return error instanceof Error && error.message ? error.message : String(error);
2995
+ }
2996
+ function delay(ms) {
2997
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
2998
+ }
2999
+ async function retrySqliteBusy(operation, label) {
3000
+ for (let attempt = 0; ; attempt++) {
3001
+ try {
3002
+ return await operation();
3003
+ } catch (error) {
3004
+ if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
3005
+ const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
3006
+ console.error(
3007
+ `[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
3008
+ );
3009
+ await delay(waitMs);
3010
+ }
3011
+ }
3012
+ }
3013
+ async function initializeSqliteStore(factory, dataDir, label) {
3014
+ try {
3015
+ loadBetterSqlite3();
3016
+ } catch (error) {
3017
+ throw new SqliteUnavailableError(error);
3018
+ }
3019
+ return retrySqliteBusy(async () => {
3020
+ const store = factory();
3021
+ await store.init(dataDir);
3022
+ return store;
3023
+ }, label);
3024
+ }
3025
+ var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
3026
+ var init_sqlite_reliability = __esm({
3027
+ "src/store/sqlite-reliability.ts"() {
3028
+ "use strict";
3029
+ init_esm_shims();
3030
+ init_sqlite_db();
3031
+ SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
3032
+ SqliteUnavailableError = class extends Error {
3033
+ code = "MEMORIX_SQLITE_UNAVAILABLE";
3034
+ constructor(cause) {
3035
+ super(
3036
+ cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
3037
+ );
3038
+ this.name = "SqliteUnavailableError";
3039
+ }
3040
+ };
3041
+ }
3042
+ });
3043
+
2967
3044
  // src/store/sqlite-store.ts
2968
3045
  var sqlite_store_exports = {};
2969
3046
  __export(sqlite_store_exports, {
@@ -3055,6 +3132,7 @@ var init_sqlite_store = __esm({
3055
3132
  "use strict";
3056
3133
  init_esm_shims();
3057
3134
  init_sqlite_db();
3135
+ init_sqlite_reliability();
3058
3136
  init_sqlite_fts();
3059
3137
  SqliteBackend = class {
3060
3138
  db = null;
@@ -3332,7 +3410,9 @@ var init_sqlite_store = __esm({
3332
3410
  // ── Compound atomic operation ────────────────────────────────────
3333
3411
  async atomic(fn) {
3334
3412
  const run = this._atomicQueue.catch(() => void 0).then(async () => {
3335
- this.db.prepare("BEGIN IMMEDIATE").run();
3413
+ await retrySqliteBusy(async () => {
3414
+ this.db.prepare("BEGIN IMMEDIATE").run();
3415
+ }, "Observation atomic write");
3336
3416
  try {
3337
3417
  const tx = {
3338
3418
  loadAll: async () => this.rawLoadAll(),
@@ -3431,15 +3511,15 @@ function resetObservationStore() {
3431
3511
  async function createObservationStore(dataDir) {
3432
3512
  try {
3433
3513
  const { SqliteBackend: SqliteBackend2 } = await Promise.resolve().then(() => (init_sqlite_store(), sqlite_store_exports));
3434
- const store2 = new SqliteBackend2();
3435
- await store2.init(dataDir);
3436
- return store2;
3514
+ return await initializeSqliteStore(() => new SqliteBackend2(), dataDir, "Observation store");
3437
3515
  } catch (err) {
3438
- console.error(`[memorix] SQLite backend unavailable \u2014 degraded mode (read-only): ${err instanceof Error ? err.message : err}`);
3516
+ if (!isSqliteUnavailableError(err)) throw err;
3517
+ const reason = formatSqliteFailure(err);
3518
+ console.error(`[memorix] SQLite module unavailable \u2014 degraded mode (reads/writes disabled): ${reason}`);
3519
+ const degraded = new DegradedBackend(reason);
3520
+ await degraded.init(dataDir);
3521
+ return degraded;
3439
3522
  }
3440
- const store = new DegradedBackend();
3441
- await store.init(dataDir);
3442
- return store;
3443
3523
  }
3444
3524
  async function initObservationStore(dataDir) {
3445
3525
  if (_store && _storeDataDir === dataDir) {
@@ -3463,36 +3543,44 @@ var init_obs_store = __esm({
3463
3543
  "src/store/obs-store.ts"() {
3464
3544
  "use strict";
3465
3545
  init_esm_shims();
3546
+ init_sqlite_reliability();
3466
3547
  _store = null;
3467
3548
  _storeDataDir = null;
3468
3549
  DegradedBackend = class {
3550
+ constructor(reason = "SQLite runtime unavailable") {
3551
+ this.reason = reason;
3552
+ }
3553
+ reason;
3469
3554
  dataDir = "";
3555
+ unavailableRead() {
3556
+ return degradedReadError("observations");
3557
+ }
3470
3558
  async init(dataDir) {
3471
3559
  this.dataDir = dataDir;
3472
3560
  }
3473
3561
  async loadAll() {
3474
- return [];
3562
+ throw this.unavailableRead();
3475
3563
  }
3476
3564
  async loadByProject(_projectId, _options) {
3477
- return [];
3565
+ throw this.unavailableRead();
3478
3566
  }
3479
3567
  async countByProject(_projectId, _options) {
3480
- return 0;
3568
+ throw this.unavailableRead();
3481
3569
  }
3482
3570
  async getById(_id) {
3483
- return void 0;
3571
+ throw this.unavailableRead();
3484
3572
  }
3485
3573
  async loadIdCounter() {
3486
- return 1;
3574
+ throw this.unavailableRead();
3487
3575
  }
3488
3576
  async countAll() {
3489
- return 0;
3577
+ throw this.unavailableRead();
3490
3578
  }
3491
3579
  async listProjectIds() {
3492
- return [];
3580
+ throw this.unavailableRead();
3493
3581
  }
3494
3582
  async searchLexical(_options) {
3495
- return [];
3583
+ throw this.unavailableRead();
3496
3584
  }
3497
3585
  hasLexicalIndex() {
3498
3586
  return false;
@@ -3501,25 +3589,25 @@ var init_obs_store = __esm({
3501
3589
  return false;
3502
3590
  }
3503
3591
  async insert(_obs) {
3504
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
3592
+ throw degradedWriteError("observations");
3505
3593
  }
3506
3594
  async update(_obs) {
3507
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
3595
+ throw degradedWriteError("observations");
3508
3596
  }
3509
3597
  async remove(_id) {
3510
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
3598
+ throw degradedWriteError("observations");
3511
3599
  }
3512
3600
  async bulkReplace(_obs) {
3513
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
3601
+ throw degradedWriteError("observations");
3514
3602
  }
3515
3603
  async bulkRemoveByIds(_ids) {
3516
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
3604
+ throw degradedWriteError("observations");
3517
3605
  }
3518
3606
  async saveIdCounter(_nextId) {
3519
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
3607
+ throw degradedWriteError("observations");
3520
3608
  }
3521
3609
  async atomic(_fn) {
3522
- throw new Error("[memorix] Cannot write observations: SQLite backend unavailable (degraded mode)");
3610
+ throw degradedWriteError("observations");
3523
3611
  }
3524
3612
  async ensureFresh() {
3525
3613
  return false;
@@ -3532,6 +3620,9 @@ var init_obs_store = __esm({
3532
3620
  getBackendName() {
3533
3621
  return "degraded";
3534
3622
  }
3623
+ getBackendReason() {
3624
+ return this.reason;
3625
+ }
3535
3626
  };
3536
3627
  }
3537
3628
  });
@@ -4761,10 +4852,10 @@ async function fetchWithRetry(url, apiKey, body, options = {}, attempt = 0, nati
4761
4852
  );
4762
4853
  }
4763
4854
  if (options.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
4764
- const delay2 = BASE_DELAY_MS * Math.pow(2, attempt);
4855
+ const delay3 = BASE_DELAY_MS * Math.pow(2, attempt);
4765
4856
  const retryAfter = response.headers.get("retry-after");
4766
4857
  const parsedRetryAfter = retryAfter ? parseInt(retryAfter, 10) * 1e3 : NaN;
4767
- const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay2;
4858
+ const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay3;
4768
4859
  console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
4769
4860
  await waitForRetry(waitMs, options.signal);
4770
4861
  return fetchWithRetry(url, apiKey, body, options, attempt + 1, nativeGemini);
@@ -9418,7 +9509,8 @@ function clampCursor(afterId) {
9418
9509
  }
9419
9510
  async function loadConsolidationPage(projectId, options) {
9420
9511
  const limit2 = clampBatchSize(options.limit);
9421
- const page = await getObservationStore().loadByProject(projectId, {
9512
+ const store = options.store ?? getObservationStore();
9513
+ const page = await store.loadByProject(projectId, {
9422
9514
  status: "active",
9423
9515
  afterId: clampCursor(options.afterId),
9424
9516
  limit: limit2 + 1
@@ -9478,7 +9570,7 @@ async function findConsolidationCandidates(_projectDir, projectId, opts) {
9478
9570
  return findClusters(page.observations, threshold);
9479
9571
  }
9480
9572
  async function executeConsolidation(_projectDir, projectId, opts) {
9481
- const store = getObservationStore();
9573
+ const store = opts?.store ?? getObservationStore();
9482
9574
  const page = await loadConsolidationPage(projectId, opts ?? {});
9483
9575
  const clusters = findClusters(page.observations, opts?.threshold ?? DEFAULT_SIMILARITY_THRESHOLD);
9484
9576
  if (clusters.length === 0) {
@@ -55304,10 +55396,10 @@ var require_retry3 = __commonJS({
55304
55396
  if (!await shouldRetryFn(err)) {
55305
55397
  return { shouldRetry: false, config: err.config };
55306
55398
  }
55307
- const delay2 = getNextRetryDelay(config);
55399
+ const delay3 = getNextRetryDelay(config);
55308
55400
  err.config.retryConfig.currentRetryAttempt += 1;
55309
- const backoff = config.retryBackoff ? config.retryBackoff(err, delay2) : new Promise((resolve2) => {
55310
- setTimeout(resolve2, delay2);
55401
+ const backoff = config.retryBackoff ? config.retryBackoff(err, delay3) : new Promise((resolve2) => {
55402
+ setTimeout(resolve2, delay3);
55311
55403
  });
55312
55404
  if (config.onRetryAttempt) {
55313
55405
  await config.onRetryAttempt(err);
@@ -97093,7 +97185,7 @@ async function retryBackoff(fn, strategy) {
97093
97185
  retryInterval = initialInterval * Math.pow(x2, exponent) + Math.random() * 1e3;
97094
97186
  }
97095
97187
  const d = Math.min(retryInterval, maxInterval);
97096
- await delay(d);
97188
+ await delay2(d);
97097
97189
  x2++;
97098
97190
  }
97099
97191
  }
@@ -97114,8 +97206,8 @@ function retryIntervalFromResponse(res) {
97114
97206
  }
97115
97207
  return 0;
97116
97208
  }
97117
- async function delay(delay2) {
97118
- return new Promise((resolve2) => setTimeout(resolve2, delay2));
97209
+ async function delay2(delay3) {
97210
+ return new Promise((resolve2) => setTimeout(resolve2, delay3));
97119
97211
  }
97120
97212
  var defaultBackoff, PermanentError, TemporaryError, codeRangeRE2;
97121
97213
  var init_retries = __esm({
@@ -147104,7 +147196,7 @@ __export(lite_provider_exports, {
147104
147196
  refreshProjectLite: () => refreshProjectLite
147105
147197
  });
147106
147198
  import { createHash as createHash10 } from "crypto";
147107
- import { readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
147199
+ import { existsSync as existsSync12, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
147108
147200
  import { join as join4, relative as relative2 } from "path";
147109
147201
  function hashText2(text2) {
147110
147202
  return createHash10("sha256").update(text2).digest("hex");
@@ -147121,6 +147213,9 @@ function resolveMaxFileBytes(value) {
147121
147213
  if (!Number.isFinite(value)) return DEFAULT_CODEGRAPH_MAX_FILE_BYTES;
147122
147214
  return Math.max(1, Math.floor(value));
147123
147215
  }
147216
+ function isPythonVirtualenvDir(dir) {
147217
+ return existsSync12(join4(dir, "pyvenv.cfg"));
147218
+ }
147124
147219
  function walk(root, exclude, maxFiles) {
147125
147220
  const out = [];
147126
147221
  const visit = (dir) => {
@@ -147138,6 +147233,7 @@ function walk(root, exclude, maxFiles) {
147138
147233
  if (entry.isDirectory()) {
147139
147234
  if (entry.name === ".git" || entry.name === ".worktrees" || entry.name === ".tmp" || entry.name === "node_modules") continue;
147140
147235
  if (rel === ".claude/worktrees" || rel.startsWith(".claude/worktrees/")) continue;
147236
+ if (isPythonVirtualenvDir(abs)) continue;
147141
147237
  visit(abs);
147142
147238
  if (out.length >= maxFiles) return;
147143
147239
  continue;
@@ -150657,7 +150753,7 @@ __export(vector_backfill_runner_exports, {
150657
150753
  import { spawn as spawn4 } from "child_process";
150658
150754
  import {
150659
150755
  closeSync,
150660
- existsSync as existsSync12,
150756
+ existsSync as existsSync13,
150661
150757
  mkdirSync as mkdirSync2,
150662
150758
  openSync,
150663
150759
  readFileSync as readFileSync9,
@@ -150785,7 +150881,7 @@ function releaseVectorBackfillLock(lockPath = process.env.MEMORIX_VECTOR_BACKFIL
150785
150881
  }
150786
150882
  function launchDetachedVectorBackfill(request, options = {}) {
150787
150883
  const runnerPath = options.runnerPath ?? resolveVectorBackfillRunnerPath();
150788
- const exists = options.exists ?? existsSync12;
150884
+ const exists = options.exists ?? existsSync13;
150789
150885
  if (!exists(runnerPath)) return false;
150790
150886
  const lock = acquireVectorBackfillLock(request.dataDir, request.projectId, options.lockPath);
150791
150887
  if (!lock) return false;