memorix 1.9.5 → 1.9.7

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 (64) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +6 -1
  3. package/README.zh-CN.md +6 -1
  4. package/dist/cli/index.js +1743 -348
  5. package/dist/index.d.ts +12 -7
  6. package/dist/index.js +1048 -266
  7. package/dist/maintenance-runner.js +339 -187
  8. package/dist/media-audio-runner.js +339 -187
  9. package/dist/media-video-runner.js +339 -187
  10. package/dist/memcode-runtime/CHANGELOG.md +53 -0
  11. package/dist/sdk.js +967 -241
  12. package/dist/vector-backfill-runner.js +339 -187
  13. package/docs/API_REFERENCE.md +36 -0
  14. package/docs/CONFIGURATION.md +43 -0
  15. package/docs/DEVELOPMENT.md +1 -1
  16. package/docs/KNOWN_ISSUES_AND_ROADMAP.md +49 -14
  17. package/docs/PERFORMANCE.md +46 -2
  18. package/docs/README.md +2 -1
  19. package/docs/SETUP.md +1 -1
  20. package/package.json +2 -1
  21. package/plugins/antigravity/memorix/plugin.json +1 -1
  22. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  23. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  24. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  25. package/plugins/copilot/memorix/plugin.json +1 -1
  26. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  27. package/plugins/hermes/memorix/plugin.yaml +1 -1
  28. package/plugins/omp/memorix/package.json +1 -1
  29. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  30. package/plugins/pi/memorix/package.json +1 -1
  31. package/server.json +2 -2
  32. package/src/cli/capability-map.ts +1 -0
  33. package/src/cli/command-guide.ts +13 -1
  34. package/src/cli/commands/context.ts +2 -0
  35. package/src/cli/commands/continuity.ts +155 -0
  36. package/src/cli/commands/init.ts +5 -2
  37. package/src/cli/commands/serve-http.ts +242 -42
  38. package/src/cli/index.ts +3 -1
  39. package/src/cli/tui/ConfigureView.tsx +2 -0
  40. package/src/codegraph/auto-context.ts +17 -0
  41. package/src/config/legacy-loader.ts +2 -2
  42. package/src/config/resolved-config.ts +8 -5
  43. package/src/config/yaml-loader.ts +20 -10
  44. package/src/embedding/api-provider.ts +4 -2
  45. package/src/embedding/fastembed-provider.ts +47 -14
  46. package/src/embedding/transformers-provider.ts +29 -7
  47. package/src/evaluation/memory-quality-gate.ts +90 -0
  48. package/src/hooks/official-skills.ts +2 -0
  49. package/src/knowledge/context-assembly.ts +1 -0
  50. package/src/knowledge/context-receipt.ts +15 -0
  51. package/src/knowledge/task-continuity.ts +413 -0
  52. package/src/knowledge/workset.ts +77 -0
  53. package/src/llm/provider.ts +2 -1
  54. package/src/orchestrate/coordinator.ts +60 -0
  55. package/src/orchestrate/effect-ledger.ts +160 -0
  56. package/src/orchestrate/pipeline-trace.ts +40 -6
  57. package/src/runtime/maintenance-jobs.ts +12 -6
  58. package/src/server/modern-mcp-bridge.ts +153 -27
  59. package/src/server/tool-profile.ts +3 -2
  60. package/src/server.ts +129 -5
  61. package/src/store/orama-store.ts +16 -1
  62. package/src/store/sqlite-db.ts +144 -4
  63. package/src/store/sqlite-fts.ts +38 -16
  64. package/src/team/team-store.ts +62 -27
@@ -155,15 +155,20 @@ var init_dotenv_loader = __esm({
155
155
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
156
156
  import { homedir as homedir2 } from "os";
157
157
  import { parse as parseYamlDocument } from "yaml";
158
+ function cacheKey(homeDir, projectRoot) {
159
+ return `${homeDir}\0${projectRoot ?? ""}`;
160
+ }
158
161
  function initProjectRoot(root) {
159
162
  globalProjectRoot = root;
160
- configCache.delete(root);
163
+ configCache.delete(cacheKey(homedir2(), root));
161
164
  }
162
- function loadYamlConfig(projectRoot) {
165
+ function loadYamlConfig(projectRoot, options = {}) {
166
+ const homeDir = options.homeDir ?? homedir2();
163
167
  const resolvedRoot = projectRoot === null ? null : projectRoot ?? globalProjectRoot ?? null;
164
- const cached = configCache.get(resolvedRoot ?? null);
168
+ const key = cacheKey(homeDir, resolvedRoot);
169
+ const cached = configCache.get(key);
165
170
  if (cached) return cached;
166
- const userYaml = getGlobalYamlPath(homedir2());
171
+ const userYaml = getGlobalYamlPath(homeDir);
167
172
  const projectYaml = resolvedRoot ? getProjectYamlPath(resolvedRoot) : null;
168
173
  let userConfig = {};
169
174
  let projectConfig = {};
@@ -195,7 +200,7 @@ function loadYamlConfig(projectRoot) {
195
200
  server: { ...userConfig.server, ...projectConfig.server },
196
201
  team: { ...userConfig.team, ...projectConfig.team }
197
202
  };
198
- configCache.set(resolvedRoot ?? null, merged);
203
+ configCache.set(key, merged);
199
204
  return merged;
200
205
  }
201
206
  function parseYaml(content) {
@@ -384,6 +389,74 @@ var init_launch_root = __esm({
384
389
  }
385
390
  });
386
391
 
392
+ // src/store/sqlite-reliability.ts
393
+ function isTransientSqliteError(error) {
394
+ const code = error?.code;
395
+ if (typeof code === "string") {
396
+ return /^SQLITE_BUSY(?:_|$)/i.test(code);
397
+ }
398
+ return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
399
+ }
400
+ function isSqliteUnavailableError(error) {
401
+ return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
402
+ }
403
+ function degradedReadError(storeName) {
404
+ return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
405
+ }
406
+ function degradedWriteError(storeName) {
407
+ return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
408
+ }
409
+ function formatSqliteFailure(error) {
410
+ return error instanceof Error && error.message ? error.message : String(error);
411
+ }
412
+ function delay(ms) {
413
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
414
+ }
415
+ async function retrySqliteBusy(operation, label) {
416
+ for (let attempt = 0; ; attempt++) {
417
+ try {
418
+ return await operation();
419
+ } catch (error) {
420
+ if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
421
+ const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
422
+ console.error(
423
+ `[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
424
+ );
425
+ await delay(waitMs);
426
+ }
427
+ }
428
+ }
429
+ async function initializeSqliteStore(factory, dataDir, label) {
430
+ try {
431
+ loadBetterSqlite3();
432
+ } catch (error) {
433
+ throw new SqliteUnavailableError(error);
434
+ }
435
+ return retrySqliteBusy(async () => {
436
+ const store = factory();
437
+ await store.init(dataDir);
438
+ return store;
439
+ }, label);
440
+ }
441
+ var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
442
+ var init_sqlite_reliability = __esm({
443
+ "src/store/sqlite-reliability.ts"() {
444
+ "use strict";
445
+ init_esm_shims();
446
+ init_sqlite_db();
447
+ SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
448
+ SqliteUnavailableError = class extends Error {
449
+ code = "MEMORIX_SQLITE_UNAVAILABLE";
450
+ constructor(cause) {
451
+ super(
452
+ cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
453
+ );
454
+ this.name = "SqliteUnavailableError";
455
+ }
456
+ };
457
+ }
458
+ });
459
+
387
460
  // src/store/sqlite-fts.ts
388
461
  function normalizeFtsToken(token) {
389
462
  return token.replace(/"/g, '""');
@@ -397,22 +470,27 @@ function buildFtsQuery(query) {
397
470
  function initializeObservationLexicalIndex(db2) {
398
471
  const known = ftsAvailability.get(db2);
399
472
  if (known !== void 0) return known;
400
- try {
401
- db2.exec(CREATE_OBSERVATION_FTS);
402
- const observationCount = Number(db2.prepare("SELECT COUNT(*) AS count FROM observations").get()?.count ?? 0);
403
- const indexedCount = Number(db2.prepare(`SELECT COUNT(*) AS count FROM ${FTS_TABLE}`).get()?.count ?? 0);
404
- if (observationCount !== indexedCount) {
405
- db2.exec(`INSERT INTO ${FTS_TABLE}(${FTS_TABLE}) VALUES ('rebuild')`);
473
+ let lastError;
474
+ for (let attempt = 1; attempt <= FTS_INIT_MAX_ATTEMPTS; attempt++) {
475
+ try {
476
+ db2.exec(CREATE_OBSERVATION_FTS);
477
+ const observationCount = Number(db2.prepare("SELECT COUNT(*) AS count FROM observations").get()?.count ?? 0);
478
+ const indexedCount = Number(db2.prepare(`SELECT COUNT(*) AS count FROM ${FTS_TABLE}`).get()?.count ?? 0);
479
+ if (observationCount !== indexedCount) {
480
+ db2.exec(`INSERT INTO ${FTS_TABLE}(${FTS_TABLE}) VALUES ('rebuild')`);
481
+ }
482
+ ftsAvailability.set(db2, true);
483
+ return true;
484
+ } catch (error) {
485
+ lastError = error;
486
+ if (!isTransientSqliteError(error) || attempt === FTS_INIT_MAX_ATTEMPTS) break;
406
487
  }
407
- ftsAvailability.set(db2, true);
408
- return true;
409
- } catch (error) {
410
- ftsAvailability.set(db2, false);
411
- console.warn(
412
- `[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${error instanceof Error ? error.message : String(error)}`
413
- );
414
- return false;
415
488
  }
489
+ ftsAvailability.set(db2, false);
490
+ console.warn(
491
+ `[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${lastError instanceof Error ? lastError.message : String(lastError)}`
492
+ );
493
+ return false;
416
494
  }
417
495
  function isObservationLexicalIndexEnabled(db2) {
418
496
  return ftsAvailability.get(db2) === true;
@@ -466,11 +544,12 @@ function searchObservationLexically(db2, options) {
466
544
  score: Math.max(0, Number(row.lexical_score ?? 0))
467
545
  }));
468
546
  }
469
- var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS;
547
+ var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS, FTS_INIT_MAX_ATTEMPTS;
470
548
  var init_sqlite_fts = __esm({
471
549
  "src/store/sqlite-fts.ts"() {
472
550
  "use strict";
473
551
  init_esm_shims();
552
+ init_sqlite_reliability();
474
553
  ftsAvailability = /* @__PURE__ */ new WeakMap();
475
554
  FTS_TABLE = "observations_fts";
476
555
  CREATE_OBSERVATION_FTS = `
@@ -504,6 +583,7 @@ CREATE TRIGGER IF NOT EXISTS observations_fts_au AFTER UPDATE ON observations BE
504
583
  VALUES (new.id, new.entityName, new.title, new.narrative, new.facts, new.filesModified, new.concepts, new.attachments);
505
584
  END;
506
585
  `;
586
+ FTS_INIT_MAX_ATTEMPTS = 3;
507
587
  }
508
588
  });
509
589
 
@@ -542,11 +622,21 @@ function applySchemaMigrations(db2) {
542
622
  apply();
543
623
  }
544
624
  }
625
+ function normalizeDataDir(dataDir) {
626
+ return path3.resolve(dataDir);
627
+ }
628
+ function touchDatabase(normalized, db2) {
629
+ _dbCache.delete(normalized);
630
+ _dbCache.set(normalized, db2);
631
+ }
545
632
  function getDatabase(dataDir) {
546
- const normalized = path3.resolve(dataDir);
633
+ const normalized = normalizeDataDir(dataDir);
547
634
  assertNotHomeDataDir(normalized);
548
635
  const existing = _dbCache.get(normalized);
549
- if (existing) return existing;
636
+ if (existing) {
637
+ touchDatabase(normalized, existing);
638
+ return existing;
639
+ }
550
640
  loadBetterSqlite3();
551
641
  fs.mkdirSync(dataDir, { recursive: true });
552
642
  const dbPath = path3.join(dataDir, "memorix.db");
@@ -576,6 +666,8 @@ function getDatabase(dataDir) {
576
666
  db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
577
667
  db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
578
668
  db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
669
+ db2.exec(CREATE_TASK_CONTINUITY_EVENTS_TABLE);
670
+ db2.exec(CREATE_AGENT_EFFECTS_TABLE);
579
671
  try {
580
672
  db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
581
673
  } catch {
@@ -614,7 +706,7 @@ function getDatabase(dataDir) {
614
706
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
615
707
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
616
708
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
617
- _dbCache.set(normalized, db2);
709
+ touchDatabase(normalized, db2);
618
710
  return db2;
619
711
  } catch (error) {
620
712
  try {
@@ -632,8 +724,9 @@ function closeAllDatabases() {
632
724
  }
633
725
  _dbCache.delete(key);
634
726
  }
727
+ _dbLeases.clear();
635
728
  }
636
- var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_LONG_TERM_MEMORIES_TABLE, CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE, CREATE_LONG_TERM_MEMORY_EVENTS_TABLE, CREATE_MEMORY_OUTCOME_SIGNALS_TABLE, CREATE_MEDIA_ASSETS_TABLE, CREATE_MEDIA_ASSET_LINKS_TABLE, CREATE_MEDIA_DERIVATIONS_TABLE, CREATE_MEDIA_EMBEDDING_PROFILES_TABLE, CREATE_MEDIA_EMBEDDINGS_TABLE, CREATE_MEDIA_JOBS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_EVIDENCE_CARDS_TABLE, CREATE_EVIDENCE_CARD_EVENTS_TABLE, CREATE_MEMORY_FEEDBACK_STATES_TABLE, CREATE_MEMORY_FEEDBACK_EVENTS_TABLE, CREATE_MCP_BINDINGS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache;
729
+ var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_LONG_TERM_MEMORIES_TABLE, CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE, CREATE_LONG_TERM_MEMORY_EVENTS_TABLE, CREATE_MEMORY_OUTCOME_SIGNALS_TABLE, CREATE_MEDIA_ASSETS_TABLE, CREATE_MEDIA_ASSET_LINKS_TABLE, CREATE_MEDIA_DERIVATIONS_TABLE, CREATE_MEDIA_EMBEDDING_PROFILES_TABLE, CREATE_MEDIA_EMBEDDINGS_TABLE, CREATE_MEDIA_JOBS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_EVIDENCE_CARDS_TABLE, CREATE_EVIDENCE_CARD_EVENTS_TABLE, CREATE_MEMORY_FEEDBACK_STATES_TABLE, CREATE_MEMORY_FEEDBACK_EVENTS_TABLE, CREATE_TASK_CONTINUITY_EVENTS_TABLE, CREATE_AGENT_EFFECTS_TABLE, CREATE_MCP_BINDINGS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache, _dbLeases;
637
730
  var init_sqlite_db = __esm({
638
731
  "src/store/sqlite-db.ts"() {
639
732
  "use strict";
@@ -1350,6 +1443,43 @@ CREATE TABLE IF NOT EXISTS memory_feedback_events (
1350
1443
  delta REAL NOT NULL DEFAULT 0,
1351
1444
  observed_at TEXT NOT NULL
1352
1445
  );
1446
+ `;
1447
+ CREATE_TASK_CONTINUITY_EVENTS_TABLE = `
1448
+ CREATE TABLE IF NOT EXISTS task_continuity_events (
1449
+ id TEXT PRIMARY KEY,
1450
+ project_id TEXT NOT NULL,
1451
+ task_id TEXT NOT NULL,
1452
+ task TEXT NOT NULL,
1453
+ kind TEXT NOT NULL,
1454
+ content TEXT NOT NULL,
1455
+ item_status TEXT,
1456
+ source_ref TEXT,
1457
+ evidence_json TEXT NOT NULL DEFAULT '[]',
1458
+ actor TEXT,
1459
+ created_at TEXT NOT NULL,
1460
+ event_key TEXT,
1461
+ item_key TEXT,
1462
+ supersedes_id TEXT
1463
+ );
1464
+ `;
1465
+ CREATE_AGENT_EFFECTS_TABLE = `
1466
+ CREATE TABLE IF NOT EXISTS agent_effects (
1467
+ id TEXT PRIMARY KEY,
1468
+ pipeline_id TEXT NOT NULL,
1469
+ task_id TEXT NOT NULL,
1470
+ attempt INTEGER NOT NULL,
1471
+ effect_key TEXT NOT NULL,
1472
+ tool TEXT NOT NULL,
1473
+ risk_tier TEXT NOT NULL,
1474
+ replay_policy TEXT NOT NULL,
1475
+ status TEXT NOT NULL,
1476
+ call_id TEXT,
1477
+ idempotency_key TEXT NOT NULL,
1478
+ input_fingerprint TEXT,
1479
+ detail TEXT,
1480
+ started_at INTEGER NOT NULL,
1481
+ finished_at INTEGER
1482
+ );
1353
1483
  `;
1354
1484
  CREATE_MCP_BINDINGS_TABLE = `
1355
1485
  CREATE TABLE IF NOT EXISTS mcp_bindings (
@@ -1428,7 +1558,18 @@ CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(projec
1428
1558
  CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
1429
1559
  CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
1430
1560
  CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
1561
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_project_task ON task_continuity_events(project_id, task_id, created_at ASC);
1562
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_project_recent ON task_continuity_events(project_id, created_at DESC);
1563
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_item ON task_continuity_events(project_id, task_id, kind, item_key, created_at DESC);
1564
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
1565
+ ON task_continuity_events(project_id, task_id, event_key)
1566
+ WHERE event_key IS NOT NULL;
1567
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_effect_identity
1568
+ ON agent_effects(pipeline_id, task_id, attempt, effect_key);
1569
+ CREATE INDEX IF NOT EXISTS idx_agent_effect_pipeline ON agent_effects(pipeline_id, started_at ASC);
1431
1570
  CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
1571
+ CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC);
1572
+ CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at);
1432
1573
  CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1433
1574
  ON maintenance_jobs(project_id, kind, dedupe_key)
1434
1575
  WHERE status IN ('pending', 'running', 'retry');
@@ -1599,6 +1740,8 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1599
1740
  db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
1600
1741
  db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC)");
1601
1742
  db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
1743
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC)");
1744
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at)");
1602
1745
  }
1603
1746
  },
1604
1747
  {
@@ -1609,9 +1752,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1609
1752
  addColumnIfMissing(db2, "code_symbols", "source", "source TEXT");
1610
1753
  addColumnIfMissing(db2, "code_edges", "source", "source TEXT");
1611
1754
  }
1755
+ },
1756
+ {
1757
+ id: "1.9-continuity-v2",
1758
+ apply: (db2) => {
1759
+ addColumnIfMissing(db2, "task_continuity_events", "event_key", "event_key TEXT");
1760
+ addColumnIfMissing(db2, "task_continuity_events", "item_key", "item_key TEXT");
1761
+ addColumnIfMissing(db2, "task_continuity_events", "supersedes_id", "supersedes_id TEXT");
1762
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_task_continuity_item ON task_continuity_events(project_id, task_id, kind, item_key, created_at DESC)");
1763
+ db2.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
1764
+ ON task_continuity_events(project_id, task_id, event_key)
1765
+ WHERE event_key IS NOT NULL`);
1766
+ }
1612
1767
  }
1613
1768
  ];
1614
1769
  _dbCache = /* @__PURE__ */ new Map();
1770
+ _dbLeases = /* @__PURE__ */ new Map();
1615
1771
  }
1616
1772
  });
1617
1773
 
@@ -2127,6 +2283,7 @@ var init_media_store = __esm({
2127
2283
  // src/runtime/maintenance-jobs.ts
2128
2284
  var maintenance_jobs_exports = {};
2129
2285
  __export(maintenance_jobs_exports, {
2286
+ DEFAULT_FAILED_HISTORY_RETENTION_MS: () => DEFAULT_FAILED_HISTORY_RETENTION_MS,
2130
2287
  MAINTENANCE_JOB_KINDS: () => MAINTENANCE_JOB_KINDS,
2131
2288
  MaintenanceJobStore: () => MaintenanceJobStore,
2132
2289
  MaintenanceJobWorker: () => MaintenanceJobWorker,
@@ -2176,7 +2333,7 @@ function normalizedKinds(kinds) {
2176
2333
  function getMaintenanceRetryDelayMs(attempts) {
2177
2334
  return Math.min(6e4, 1e3 * 2 ** Math.max(0, attempts - 1));
2178
2335
  }
2179
- var MAINTENANCE_JOB_KINDS, DEFAULT_MAX_ATTEMPTS, DEFAULT_LEASE_MS, DEFAULT_POLL_INTERVAL_MS, MAX_ERROR_LENGTH, DEFAULT_COMPLETED_HISTORY_RETENTION_MS, MaintenanceJobStore, MaintenanceJobWorker;
2336
+ var MAINTENANCE_JOB_KINDS, DEFAULT_MAX_ATTEMPTS, DEFAULT_LEASE_MS, DEFAULT_POLL_INTERVAL_MS, MAX_ERROR_LENGTH, DEFAULT_COMPLETED_HISTORY_RETENTION_MS, DEFAULT_FAILED_HISTORY_RETENTION_MS, MaintenanceJobStore, MaintenanceJobWorker;
2180
2337
  var init_maintenance_jobs = __esm({
2181
2338
  "src/runtime/maintenance-jobs.ts"() {
2182
2339
  "use strict";
@@ -2203,6 +2360,7 @@ var init_maintenance_jobs = __esm({
2203
2360
  DEFAULT_POLL_INTERVAL_MS = 2e3;
2204
2361
  MAX_ERROR_LENGTH = 1e3;
2205
2362
  DEFAULT_COMPLETED_HISTORY_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
2363
+ DEFAULT_FAILED_HISTORY_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
2206
2364
  MaintenanceJobStore = class {
2207
2365
  db;
2208
2366
  constructor(dataDir) {
@@ -2329,18 +2487,21 @@ var init_maintenance_jobs = __esm({
2329
2487
  }
2330
2488
  /**
2331
2489
  * Completed jobs are useful recent operator history, not permanent data.
2332
- * Failed jobs stay available for diagnosis until an operator explicitly
2333
- * resolves them or clears the database.
2490
+ * Failed diagnostics are retained longer, but are still bounded so a
2491
+ * permanently failing job kind cannot grow the database forever.
2334
2492
  */
2335
2493
  pruneCompletedHistory(options = {}) {
2336
2494
  const now3 = options.now ?? Date.now();
2337
2495
  const maxAgeMs = Number.isFinite(options.maxAgeMs) ? Math.max(0, Math.floor(options.maxAgeMs)) : DEFAULT_COMPLETED_HISTORY_RETENTION_MS;
2496
+ const failedMaxAgeMs = Number.isFinite(options.failedMaxAgeMs) ? Math.max(0, Math.floor(options.failedMaxAgeMs)) : DEFAULT_FAILED_HISTORY_RETENTION_MS;
2338
2497
  const result = this.db.prepare(`
2339
2498
  DELETE FROM maintenance_jobs
2340
- WHERE status = 'completed'
2499
+ WHERE (status = 'completed'
2341
2500
  AND completed_at IS NOT NULL
2342
- AND completed_at < ?
2343
- `).run(now3 - maxAgeMs);
2501
+ AND completed_at < ?)
2502
+ OR (status = 'failed'
2503
+ AND updated_at < ?)
2504
+ `).run(now3 - maxAgeMs, now3 - failedMaxAgeMs);
2344
2505
  return Number(result.changes ?? 0);
2345
2506
  }
2346
2507
  claimNext(options) {
@@ -2628,74 +2789,6 @@ var init_types = __esm({
2628
2789
  }
2629
2790
  });
2630
2791
 
2631
- // src/store/sqlite-reliability.ts
2632
- function isTransientSqliteError(error) {
2633
- const code = error?.code;
2634
- if (typeof code === "string") {
2635
- return /^SQLITE_BUSY(?:_|$)/i.test(code);
2636
- }
2637
- return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
2638
- }
2639
- function isSqliteUnavailableError(error) {
2640
- return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
2641
- }
2642
- function degradedReadError(storeName) {
2643
- return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
2644
- }
2645
- function degradedWriteError(storeName) {
2646
- return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
2647
- }
2648
- function formatSqliteFailure(error) {
2649
- return error instanceof Error && error.message ? error.message : String(error);
2650
- }
2651
- function delay(ms) {
2652
- return new Promise((resolve2) => setTimeout(resolve2, ms));
2653
- }
2654
- async function retrySqliteBusy(operation, label) {
2655
- for (let attempt = 0; ; attempt++) {
2656
- try {
2657
- return await operation();
2658
- } catch (error) {
2659
- if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
2660
- const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
2661
- console.error(
2662
- `[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
2663
- );
2664
- await delay(waitMs);
2665
- }
2666
- }
2667
- }
2668
- async function initializeSqliteStore(factory, dataDir, label) {
2669
- try {
2670
- loadBetterSqlite3();
2671
- } catch (error) {
2672
- throw new SqliteUnavailableError(error);
2673
- }
2674
- return retrySqliteBusy(async () => {
2675
- const store = factory();
2676
- await store.init(dataDir);
2677
- return store;
2678
- }, label);
2679
- }
2680
- var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
2681
- var init_sqlite_reliability = __esm({
2682
- "src/store/sqlite-reliability.ts"() {
2683
- "use strict";
2684
- init_esm_shims();
2685
- init_sqlite_db();
2686
- SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
2687
- SqliteUnavailableError = class extends Error {
2688
- code = "MEMORIX_SQLITE_UNAVAILABLE";
2689
- constructor(cause) {
2690
- super(
2691
- cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
2692
- );
2693
- this.name = "SqliteUnavailableError";
2694
- }
2695
- };
2696
- }
2697
- });
2698
-
2699
2792
  // src/store/file-lock.ts
2700
2793
  import { promises as fs2 } from "fs";
2701
2794
  import { randomUUID as randomUUID3 } from "crypto";
@@ -3114,9 +3207,9 @@ var init_detector = __esm({
3114
3207
  // src/config/legacy-loader.ts
3115
3208
  import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
3116
3209
  import { homedir as homedir3 } from "os";
3117
- function loadFileConfig() {
3210
+ function loadFileConfig(homeDir = homedir3()) {
3118
3211
  if (cachedConfig !== null) return cachedConfig;
3119
- const configPath = getLegacyConfigJsonPath(homedir3());
3212
+ const configPath = getLegacyConfigJsonPath(homeDir);
3120
3213
  try {
3121
3214
  if (existsSync5(configPath)) {
3122
3215
  cachedConfig = JSON.parse(readFileSync5(configPath, "utf-8"));
@@ -3146,15 +3239,15 @@ import { homedir as homedir4 } from "os";
3146
3239
  function loadTomlConfig(options = {}) {
3147
3240
  const homeDir = options.homeDir ?? homedir4();
3148
3241
  const projectRoot = options.projectRoot ?? null;
3149
- const cacheKey = `${homeDir}\0${projectRoot ?? ""}`;
3150
- const cached = configCache2.get(cacheKey);
3242
+ const cacheKey3 = `${homeDir}\0${projectRoot ?? ""}`;
3243
+ const cached = configCache2.get(cacheKey3);
3151
3244
  if (cached) return cached;
3152
3245
  const userToml = getGlobalConfigTomlPath(homeDir);
3153
3246
  const projectToml = projectRoot ? getProjectConfigTomlPath(projectRoot) : null;
3154
3247
  const userConfig = existsSync6(userToml) ? parseTomlConfig(readFileSync6(userToml, "utf8"), userToml) : {};
3155
3248
  const projectConfig = projectToml && existsSync6(projectToml) ? parseTomlConfig(readFileSync6(projectToml, "utf8"), projectToml) : {};
3156
3249
  const merged = mergeTomlConfig(userConfig, projectConfig);
3157
- configCache2.set(cacheKey, merged);
3250
+ configCache2.set(cacheKey3, merged);
3158
3251
  return merged;
3159
3252
  }
3160
3253
  function mergeTomlConfig(base, override) {
@@ -3275,8 +3368,8 @@ function getResolvedConfig(options = {}) {
3275
3368
  const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
3276
3369
  loadDotenv(projectRoot === null ? void 0 : projectRoot ?? void 0, { userHomeDir: homeDir });
3277
3370
  const toml = loadTomlConfig({ projectRoot: projectRoot ?? null, homeDir });
3278
- const yaml = loadYamlConfig(projectRoot ?? null);
3279
- const legacy = loadFileConfig();
3371
+ const yaml = loadYamlConfig(projectRoot ?? null, { homeDir });
3372
+ const legacy = loadFileConfig(homeDir);
3280
3373
  const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
3281
3374
  const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
3282
3375
  const memoryLlmProvider = first(
@@ -3298,15 +3391,17 @@ function getResolvedConfig(options = {}) {
3298
3391
  legacy.llm?.baseUrl
3299
3392
  );
3300
3393
  const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
3394
+ const isAtlasCloud = memoryLlmProvider === "atlascloud";
3301
3395
  const memoryLlmApiKey = first(
3302
3396
  process.env.MEMORIX_LLM_API_KEY,
3303
3397
  process.env.MEMORIX_API_KEY,
3304
3398
  toml.memory?.llm?.api_key,
3305
3399
  yaml.llm?.apiKey,
3306
3400
  legacy.llm?.apiKey,
3307
- process.env.OPENAI_API_KEY,
3308
- process.env.ANTHROPIC_API_KEY,
3309
- openRouterMemoryLlmApiKey
3401
+ // Never borrow another provider's credentials for the Atlas Cloud preset.
3402
+ isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
3403
+ isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
3404
+ isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
3310
3405
  );
3311
3406
  const resolved = {
3312
3407
  agent: {
@@ -3485,7 +3580,8 @@ function getEnvSourceNames() {
3485
3580
  "MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
3486
3581
  "MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
3487
3582
  "MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
3488
- "OPENROUTER_API_KEY"
3583
+ "OPENROUTER_API_KEY",
3584
+ "ATLASCLOUD_API_KEY"
3489
3585
  ].filter((name) => process.env[name]);
3490
3586
  }
3491
3587
  function isOpenRouterUrl(value) {
@@ -3704,12 +3800,45 @@ function textHash(text2) {
3704
3800
  async function loadDiskCache() {
3705
3801
  try {
3706
3802
  const raw = await readFile(CACHE_FILE, "utf-8");
3803
+ if (Buffer.byteLength(raw, "utf8") > MAX_CACHE_FILE_BYTES) {
3804
+ console.error("[memorix] FastEmbed cache exceeds the disk load limit; starting with an empty cache");
3805
+ return;
3806
+ }
3707
3807
  const entries = JSON.parse(raw);
3708
- for (const [k, v] of entries) cache.set(k, v);
3709
- console.error(`[memorix] Loaded ${entries.length} cached embeddings from disk`);
3808
+ if (!Array.isArray(entries)) return;
3809
+ for (const entry of entries) {
3810
+ if (!Array.isArray(entry) || typeof entry[0] !== "string" || !isVector(entry[1])) continue;
3811
+ cacheSet(entry[0], entry[1], false);
3812
+ }
3813
+ console.error(`[memorix] Loaded ${cache.size} cached embeddings from disk`);
3710
3814
  } catch {
3711
3815
  }
3712
3816
  }
3817
+ function isVector(value) {
3818
+ return Array.isArray(value) && value.every((entry) => typeof entry === "number");
3819
+ }
3820
+ function maxCachePayloadBytes() {
3821
+ const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
3822
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES;
3823
+ }
3824
+ function cacheSet(hash4, value, markDirty = true) {
3825
+ const incomingBytes = value.length * 8;
3826
+ if (incomingBytes > maxCachePayloadBytes()) return;
3827
+ const existing = cache.get(hash4);
3828
+ if (existing) cachePayloadBytes -= existing.length * 8;
3829
+ else {
3830
+ while (cache.size >= MAX_CACHE_SIZE || cachePayloadBytes + incomingBytes > maxCachePayloadBytes()) {
3831
+ const firstKey = cache.keys().next().value;
3832
+ if (firstKey === void 0) break;
3833
+ const old = cache.get(firstKey);
3834
+ cache.delete(firstKey);
3835
+ if (old) cachePayloadBytes -= old.length * 8;
3836
+ }
3837
+ }
3838
+ cache.set(hash4, value);
3839
+ cachePayloadBytes += incomingBytes;
3840
+ if (markDirty) diskCacheDirty = true;
3841
+ }
3713
3842
  async function saveDiskCache() {
3714
3843
  if (!diskCacheDirty) return;
3715
3844
  try {
@@ -3720,7 +3849,7 @@ async function saveDiskCache() {
3720
3849
  } catch {
3721
3850
  }
3722
3851
  }
3723
- var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, diskCacheDirty, FastEmbedProvider;
3852
+ var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, DEFAULT_CACHE_PAYLOAD_BYTES, MAX_CACHE_FILE_BYTES, cachePayloadBytes, diskCacheDirty, FastEmbedProvider;
3724
3853
  var init_fastembed_provider = __esm({
3725
3854
  "src/embedding/fastembed-provider.ts"() {
3726
3855
  "use strict";
@@ -3730,6 +3859,9 @@ var init_fastembed_provider = __esm({
3730
3859
  CACHE_FILE = join2(CACHE_DIR, ".embedding-cache.json");
3731
3860
  cache = /* @__PURE__ */ new Map();
3732
3861
  MAX_CACHE_SIZE = 5e3;
3862
+ DEFAULT_CACHE_PAYLOAD_BYTES = 64 * 1024 * 1024;
3863
+ MAX_CACHE_FILE_BYTES = 128 * 1024 * 1024;
3864
+ cachePayloadBytes = 0;
3733
3865
  diskCacheDirty = false;
3734
3866
  FastEmbedProvider = class _FastEmbedProvider {
3735
3867
  name = "fastembed-bge-small";
@@ -3771,7 +3903,7 @@ var init_fastembed_provider = __esm({
3771
3903
  if (result.length !== this.dimensions) {
3772
3904
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
3773
3905
  }
3774
- this.cacheSet(hash4, result);
3906
+ cacheSet(hash4, result);
3775
3907
  return result;
3776
3908
  }
3777
3909
  async embedBatch(texts) {
@@ -3796,7 +3928,7 @@ var init_fastembed_provider = __esm({
3796
3928
  const originalIdx = uncachedIndices[batchIdx];
3797
3929
  const plain = Array.from(vec);
3798
3930
  results[originalIdx] = plain;
3799
- this.cacheSet(textHash(uncachedTexts[batchIdx]), plain);
3931
+ cacheSet(textHash(uncachedTexts[batchIdx]), plain);
3800
3932
  batchIdx++;
3801
3933
  }
3802
3934
  }
@@ -3804,14 +3936,6 @@ var init_fastembed_provider = __esm({
3804
3936
  }
3805
3937
  return results;
3806
3938
  }
3807
- cacheSet(hash4, value) {
3808
- if (cache.size >= MAX_CACHE_SIZE) {
3809
- const firstKey = cache.keys().next().value;
3810
- if (firstKey !== void 0) cache.delete(firstKey);
3811
- }
3812
- cache.set(hash4, value);
3813
- diskCacheDirty = true;
3814
- }
3815
3939
  };
3816
3940
  }
3817
3941
  });
@@ -3821,7 +3945,15 @@ var transformers_provider_exports = {};
3821
3945
  __export(transformers_provider_exports, {
3822
3946
  TransformersProvider: () => TransformersProvider
3823
3947
  });
3824
- var cache2, MAX_CACHE_SIZE2, TransformersProvider;
3948
+ import { createHash as createHash2 } from "crypto";
3949
+ function cacheKey2(text2) {
3950
+ return createHash2("sha256").update(text2).digest("hex");
3951
+ }
3952
+ function maxCachePayloadBytes2() {
3953
+ const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
3954
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES2;
3955
+ }
3956
+ var cache2, MAX_CACHE_SIZE2, DEFAULT_CACHE_PAYLOAD_BYTES2, cachePayloadBytes2, TransformersProvider;
3825
3957
  var init_transformers_provider = __esm({
3826
3958
  "src/embedding/transformers-provider.ts"() {
3827
3959
  "use strict";
@@ -3829,6 +3961,8 @@ var init_transformers_provider = __esm({
3829
3961
  init_provider();
3830
3962
  cache2 = /* @__PURE__ */ new Map();
3831
3963
  MAX_CACHE_SIZE2 = 5e3;
3964
+ DEFAULT_CACHE_PAYLOAD_BYTES2 = 64 * 1024 * 1024;
3965
+ cachePayloadBytes2 = 0;
3832
3966
  TransformersProvider = class _TransformersProvider {
3833
3967
  name = "transformers-minilm";
3834
3968
  dimensions = 384;
@@ -3863,7 +3997,7 @@ var init_transformers_provider = __esm({
3863
3997
  return Promise.all(inputs.map((input) => this.embedInput(input, options)));
3864
3998
  }
3865
3999
  async embed(text2) {
3866
- const cached = cache2.get(text2);
4000
+ const cached = cache2.get(cacheKey2(text2));
3867
4001
  if (cached) return cached;
3868
4002
  const output = await this.extractor(text2, {
3869
4003
  pooling: "mean",
@@ -3873,7 +4007,7 @@ var init_transformers_provider = __esm({
3873
4007
  if (result.length !== this.dimensions) {
3874
4008
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
3875
4009
  }
3876
- this.cacheSet(text2, result);
4010
+ this.cacheSet(cacheKey2(text2), result);
3877
4011
  return result;
3878
4012
  }
3879
4013
  async embedBatch(texts) {
@@ -3881,7 +4015,7 @@ var init_transformers_provider = __esm({
3881
4015
  const uncachedIndices = [];
3882
4016
  const uncachedTexts = [];
3883
4017
  for (let i2 = 0; i2 < texts.length; i2++) {
3884
- const cached = cache2.get(texts[i2]);
4018
+ const cached = cache2.get(cacheKey2(texts[i2]));
3885
4019
  if (cached) {
3886
4020
  results[i2] = cached;
3887
4021
  } else {
@@ -3899,17 +4033,27 @@ var init_transformers_provider = __esm({
3899
4033
  const vec = Array.from(allVecs[i2]);
3900
4034
  const originalIdx = uncachedIndices[i2];
3901
4035
  results[originalIdx] = vec;
3902
- this.cacheSet(uncachedTexts[i2], vec);
4036
+ this.cacheSet(cacheKey2(uncachedTexts[i2]), vec);
3903
4037
  }
3904
4038
  }
3905
4039
  return results;
3906
4040
  }
3907
4041
  cacheSet(key, value) {
3908
- if (cache2.size >= MAX_CACHE_SIZE2) {
3909
- const firstKey = cache2.keys().next().value;
3910
- if (firstKey !== void 0) cache2.delete(firstKey);
4042
+ const incomingBytes = value.length * 8;
4043
+ if (incomingBytes > maxCachePayloadBytes2()) return;
4044
+ const existing = cache2.get(key);
4045
+ if (existing) cachePayloadBytes2 -= existing.length * 8;
4046
+ else {
4047
+ while (cache2.size >= MAX_CACHE_SIZE2 || cachePayloadBytes2 + incomingBytes > maxCachePayloadBytes2()) {
4048
+ const firstKey = cache2.keys().next().value;
4049
+ if (firstKey === void 0) break;
4050
+ const old = cache2.get(firstKey);
4051
+ cache2.delete(firstKey);
4052
+ if (old) cachePayloadBytes2 -= old.length * 8;
4053
+ }
3911
4054
  }
3912
4055
  cache2.set(key, value);
4056
+ cachePayloadBytes2 += incomingBytes;
3913
4057
  }
3914
4058
  };
3915
4059
  }
@@ -3931,7 +4075,7 @@ __export(api_provider_exports, {
3931
4075
  saveDiskCacheNow: () => saveDiskCacheNow,
3932
4076
  seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
3933
4077
  });
3934
- import { createHash as createHash2 } from "crypto";
4078
+ import { createHash as createHash3 } from "crypto";
3935
4079
  import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
3936
4080
  import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
3937
4081
  import { join as join3 } from "path";
@@ -3958,7 +4102,7 @@ function cacheStatFile() {
3958
4102
  function payloadBytes(vector) {
3959
4103
  return vector.length * BYTES_PER_DIM;
3960
4104
  }
3961
- function maxCachePayloadBytes() {
4105
+ function maxCachePayloadBytes3() {
3962
4106
  const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
3963
4107
  if (raw) {
3964
4108
  const parsed = Number.parseInt(raw, 10);
@@ -3968,7 +4112,7 @@ function maxCachePayloadBytes() {
3968
4112
  }
3969
4113
  function maxEntriesForDimensions(dimensions) {
3970
4114
  const dim = Math.max(1, Math.floor(dimensions));
3971
- const byBytes = Math.floor(maxCachePayloadBytes() / (dim * BYTES_PER_DIM));
4115
+ const byBytes = Math.floor(maxCachePayloadBytes3() / (dim * BYTES_PER_DIM));
3972
4116
  return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
3973
4117
  }
3974
4118
  function rememberDimensions(vector) {
@@ -3981,13 +4125,15 @@ function evictOldest() {
3981
4125
  if (firstKey === void 0) return;
3982
4126
  const old = cache3.get(firstKey);
3983
4127
  cache3.delete(firstKey);
3984
- if (old) cachePayloadBytes -= payloadBytes(old);
4128
+ if (old) cachePayloadBytes3 -= payloadBytes(old);
3985
4129
  }
3986
4130
  function evictToFit(incomingBytes, incomingDims) {
4131
+ if (incomingBytes > maxCachePayloadBytes3()) return false;
3987
4132
  const limit2 = maxEntriesForDimensions(incomingDims);
3988
- while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes + incomingBytes > maxCachePayloadBytes())) {
4133
+ while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes3 + incomingBytes > maxCachePayloadBytes3())) {
3989
4134
  evictOldest();
3990
4135
  }
4136
+ return true;
3991
4137
  }
3992
4138
  function isNumberArray(value) {
3993
4139
  return Array.isArray(value) && value.every((entry) => typeof entry === "number");
@@ -4014,12 +4160,12 @@ function cacheInsert(hash4, value, dirty) {
4014
4160
  const incoming = payloadBytes(value);
4015
4161
  const existing = cache3.get(hash4);
4016
4162
  if (existing) {
4017
- cachePayloadBytes -= payloadBytes(existing);
4163
+ cachePayloadBytes3 -= payloadBytes(existing);
4018
4164
  cache3.delete(hash4);
4019
4165
  }
4020
- evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
4166
+ if (!evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS)) return;
4021
4167
  cache3.set(hash4, value);
4022
- cachePayloadBytes += incoming;
4168
+ cachePayloadBytes3 += incoming;
4023
4169
  if (dirty) diskCacheDirty2 = true;
4024
4170
  }
4025
4171
  async function readCacheStat() {
@@ -4055,7 +4201,7 @@ function cacheNamespace(config) {
4055
4201
  ].join("|");
4056
4202
  }
4057
4203
  function textHash2(text2, namespace) {
4058
- return createHash2("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
4204
+ return createHash3("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
4059
4205
  }
4060
4206
  function inputIdentity(input, options = {}) {
4061
4207
  return JSON.stringify({
@@ -4397,7 +4543,7 @@ function getApiEmbeddingDiskCacheLoadCountForTests() {
4397
4543
  }
4398
4544
  function resetApiEmbeddingCacheForTests() {
4399
4545
  cache3.clear();
4400
- cachePayloadBytes = 0;
4546
+ cachePayloadBytes3 = 0;
4401
4547
  cacheDimensions = null;
4402
4548
  diskCacheEntryCount = 0;
4403
4549
  diskCacheLoaded = false;
@@ -4408,14 +4554,14 @@ function resetApiEmbeddingCacheForTests() {
4408
4554
  }
4409
4555
  function seedApiEmbeddingCacheForTests(entries) {
4410
4556
  cache3.clear();
4411
- cachePayloadBytes = 0;
4557
+ cachePayloadBytes3 = 0;
4412
4558
  cacheDimensions = null;
4413
4559
  for (const [key, value] of entries) cacheInsert(key, value, true);
4414
4560
  diskCacheLoaded = true;
4415
4561
  diskCacheDirty2 = true;
4416
4562
  }
4417
4563
  function getApiEmbeddingCachePayloadBytesForTests() {
4418
- return cachePayloadBytes;
4564
+ return cachePayloadBytes3;
4419
4565
  }
4420
4566
  function getApiEmbeddingJsonlLineCountCallsForTests() {
4421
4567
  return jsonlLineCountCalls;
@@ -4589,7 +4735,7 @@ function scheduleDiskSave() {
4589
4735
  diskSaveTimer = null;
4590
4736
  }, DISK_SAVE_DEBOUNCE_MS);
4591
4737
  }
4592
- function cacheSet(hash4, value) {
4738
+ function cacheSet2(hash4, value) {
4593
4739
  cacheInsert(hash4, value, true);
4594
4740
  }
4595
4741
  function resolveEnvEmbeddingApiKey() {
@@ -4709,7 +4855,7 @@ async function waitForRetry(waitMs, signal) {
4709
4855
  abortSignal.addEventListener("abort", onAbort, { once: true });
4710
4856
  });
4711
4857
  }
4712
- var cache3, MAX_CACHE_ENTRIES, MAX_CACHE_PAYLOAD_BYTES, BYTES_PER_DIM, DEFAULT_ASSUMED_DIMENSIONS, MAX_MIGRATION_VALUE_BYTES, cachePayloadBytes, cacheDimensions, diskCacheEntryCount, diskCacheDirty2, diskSaveTimer, diskCacheLoaded, diskCacheLoadPromise, diskCacheLoadCount, jsonlLineCountCalls, MAX_INPUT_CHARS, MAX_CONCURRENCY, DISK_SAVE_DEBOUNCE_MS, DEFAULT_MAX_BATCH_SIZE, DASHSCOPE_MAX_BATCH_SIZE, MAX_RETRIES2, BASE_DELAY_MS, EmbeddingAPIError, APIEmbeddingProvider;
4858
+ var cache3, MAX_CACHE_ENTRIES, MAX_CACHE_PAYLOAD_BYTES, BYTES_PER_DIM, DEFAULT_ASSUMED_DIMENSIONS, MAX_MIGRATION_VALUE_BYTES, cachePayloadBytes3, cacheDimensions, diskCacheEntryCount, diskCacheDirty2, diskSaveTimer, diskCacheLoaded, diskCacheLoadPromise, diskCacheLoadCount, jsonlLineCountCalls, MAX_INPUT_CHARS, MAX_CONCURRENCY, DISK_SAVE_DEBOUNCE_MS, DEFAULT_MAX_BATCH_SIZE, DASHSCOPE_MAX_BATCH_SIZE, MAX_RETRIES2, BASE_DELAY_MS, EmbeddingAPIError, APIEmbeddingProvider;
4713
4859
  var init_api_provider = __esm({
4714
4860
  "src/embedding/api-provider.ts"() {
4715
4861
  "use strict";
@@ -4721,7 +4867,7 @@ var init_api_provider = __esm({
4721
4867
  BYTES_PER_DIM = 8;
4722
4868
  DEFAULT_ASSUMED_DIMENSIONS = 4096;
4723
4869
  MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
4724
- cachePayloadBytes = 0;
4870
+ cachePayloadBytes3 = 0;
4725
4871
  cacheDimensions = null;
4726
4872
  diskCacheEntryCount = 0;
4727
4873
  diskCacheDirty2 = false;
@@ -4906,7 +5052,7 @@ var init_api_provider = __esm({
4906
5052
  } else {
4907
5053
  embedding = await apiCall();
4908
5054
  }
4909
- cacheSet(hash4, embedding);
5055
+ cacheSet2(hash4, embedding);
4910
5056
  scheduleDiskSave();
4911
5057
  return embedding;
4912
5058
  }
@@ -4954,7 +5100,7 @@ var init_api_provider = __esm({
4954
5100
  for (const item of response.data) {
4955
5101
  const originalIdx = chunkIndices[item.index];
4956
5102
  results[originalIdx] = item.embedding;
4957
- cacheSet(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
5103
+ cacheSet2(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
4958
5104
  }
4959
5105
  } catch (error) {
4960
5106
  const providerLimit = parseBatchLimit(error);
@@ -5032,7 +5178,7 @@ var init_api_provider = __esm({
5032
5178
  throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d; dimension mismatch`);
5033
5179
  }
5034
5180
  this.trackUsage(response);
5035
- cacheSet(hash4, embedding);
5181
+ cacheSet2(hash4, embedding);
5036
5182
  scheduleDiskSave();
5037
5183
  return embedding;
5038
5184
  }
@@ -6415,6 +6561,7 @@ var init_provider2 = __esm({
6415
6561
  openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
6416
6562
  anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
6417
6563
  openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
6564
+ atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
6418
6565
  custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
6419
6566
  };
6420
6567
  currentConfig = null;
@@ -7178,7 +7325,7 @@ var init_obs_store = __esm({
7178
7325
  });
7179
7326
 
7180
7327
  // src/search/semantic-index.ts
7181
- import { createHash as createHash3 } from "crypto";
7328
+ import { createHash as createHash4 } from "crypto";
7182
7329
  import { createRequire as createRequire3 } from "module";
7183
7330
  import path8 from "path";
7184
7331
  function createSemanticIndexProfile(provider2) {
@@ -7192,7 +7339,7 @@ function stateKey(dataDir, profile) {
7192
7339
  return `${path8.resolve(dataDir)}::${profile.key}`;
7193
7340
  }
7194
7341
  function tableName(profile) {
7195
- const digest2 = createHash3("sha256").update(profile.key).digest("hex").slice(0, 20);
7342
+ const digest2 = createHash4("sha256").update(profile.key).digest("hex").slice(0, 20);
7196
7343
  return `${TABLE_PREFIX}${digest2}`;
7197
7344
  }
7198
7345
  function indexRoot(dataDir) {
@@ -8534,6 +8681,7 @@ async function searchObservations(options) {
8534
8681
  };
8535
8682
  let queryVector = null;
8536
8683
  let embeddingProviderForSearch = null;
8684
+ let embeddingUnavailable = false;
8537
8685
  if (quality !== "fast" && embeddingEnabled && hasQuery && tier !== "fast") {
8538
8686
  try {
8539
8687
  const provider2 = await getEmbeddingProvider();
@@ -8541,6 +8689,7 @@ async function searchObservations(options) {
8541
8689
  embeddingProviderForSearch = provider2;
8542
8690
  const activeVectorDimensions = getVectorDimensions();
8543
8691
  if (activeVectorDimensions !== null && provider2.dimensions !== activeVectorDimensions) {
8692
+ embeddingUnavailable = true;
8544
8693
  rememberSearchMode(
8545
8694
  modeKey,
8546
8695
  `fulltext (embedding dimension mismatch: provider ${provider2.dimensions}d vs index ${activeVectorDimensions}d)`
@@ -8580,8 +8729,11 @@ async function searchObservations(options) {
8580
8729
  hybridWeights: isCJKHeavy ? { text: 0.2, vector: 0.8 } : { text: 0.6, vector: 0.4 }
8581
8730
  };
8582
8731
  }
8732
+ } else {
8733
+ embeddingUnavailable = true;
8583
8734
  }
8584
8735
  } catch (error) {
8736
+ embeddingUnavailable = true;
8585
8737
  rememberSearchMode(modeKey, "fulltext (embedding unavailable)");
8586
8738
  console.error("[memorix] Embedding failed or timed out, falling back to fulltext search");
8587
8739
  }
@@ -8589,7 +8741,7 @@ async function searchObservations(options) {
8589
8741
  mark("preSearch");
8590
8742
  let results;
8591
8743
  const persistentCorpusEligible = await shouldUsePersistentSearch(projectIds, options.projectId);
8592
- const canUsePersistentLexical = persistentCorpusEligible && Boolean(hasQuery) && !queryVector && (quality === "fast" || tier === "fast" || !embeddingEnabled);
8744
+ const canUsePersistentLexical = persistentCorpusEligible && Boolean(hasQuery) && !queryVector && (quality === "fast" || tier === "fast" || !embeddingEnabled || embeddingUnavailable);
8593
8745
  let persistent = persistentCorpusEligible && queryVector && embeddingProviderForSearch ? await searchPersistentSemantically(options, projectIds, requestLimit, queryVector, embeddingProviderForSearch) : canUsePersistentLexical ? await searchPersistentLexically(options, projectIds, requestLimit) : null;
8594
8746
  const durableStore = getOptionalObservationStore();
8595
8747
  if (!persistent && queryVector && durableStore?.hasLexicalIndex?.() && count(database) === 0) {
@@ -9270,7 +9422,7 @@ var init_lifecycle = __esm({
9270
9422
  });
9271
9423
 
9272
9424
  // src/store/evidence-store.ts
9273
- import { createHash as createHash4, randomUUID as randomUUID4 } from "crypto";
9425
+ import { createHash as createHash5, randomUUID as randomUUID4 } from "crypto";
9274
9426
  function safeJson(value, fallback) {
9275
9427
  if (typeof value !== "string" || value.length === 0) return fallback;
9276
9428
  try {
@@ -9304,7 +9456,7 @@ function rowToCard(row) {
9304
9456
  };
9305
9457
  }
9306
9458
  function observationHash(observation) {
9307
- return createHash4("sha256").update(JSON.stringify({
9459
+ return createHash5("sha256").update(JSON.stringify({
9308
9460
  projectId: observation.projectId,
9309
9461
  id: observation.id,
9310
9462
  title: observation.title,
@@ -9734,13 +9886,13 @@ __export(workspace_exports, {
9734
9886
  loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
9735
9887
  resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
9736
9888
  });
9737
- import { createHash as createHash5 } from "crypto";
9889
+ import { createHash as createHash6 } from "crypto";
9738
9890
  import { execFile } from "child_process";
9739
9891
  import { promises as fs6 } from "fs";
9740
9892
  import path10 from "path";
9741
9893
  import { promisify } from "util";
9742
9894
  function hash(value) {
9743
- return createHash5("sha256").update(value).digest("hex");
9895
+ return createHash6("sha256").update(value).digest("hex");
9744
9896
  }
9745
9897
  function workspaceId(projectId, mode) {
9746
9898
  return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
@@ -10348,14 +10500,14 @@ var init_types2 = __esm({
10348
10500
  });
10349
10501
 
10350
10502
  // src/media/asset-store.ts
10351
- import { createHash as createHash6, randomUUID as randomUUID6 } from "crypto";
10503
+ import { createHash as createHash7, randomUUID as randomUUID6 } from "crypto";
10352
10504
  import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
10353
10505
  import path11 from "path";
10354
10506
  function mediaRoot(dataDir) {
10355
10507
  return path11.resolve(dataDir, "media");
10356
10508
  }
10357
10509
  function projectStorageKey(projectId) {
10358
- return createHash6("sha256").update(projectId).digest("hex").slice(0, 16);
10510
+ return createHash7("sha256").update(projectId).digest("hex").slice(0, 16);
10359
10511
  }
10360
10512
  function validateUnderRoot(root, candidate) {
10361
10513
  const resolved = path11.resolve(candidate);
@@ -10464,7 +10616,7 @@ async function importMediaBuffer(input) {
10464
10616
  if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
10465
10617
  if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
10466
10618
  const detected = detectMedia(input.bytes.subarray(0, 32));
10467
- const sha256 = createHash6("sha256").update(input.bytes).digest("hex");
10619
+ const sha256 = createHash7("sha256").update(input.bytes).digest("hex");
10468
10620
  return importKnownMedia({
10469
10621
  dataDir: input.dataDir,
10470
10622
  projectId: input.projectId,
@@ -10482,7 +10634,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
10482
10634
  if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
10483
10635
  const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
10484
10636
  if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
10485
- const sha256 = createHash6("sha256").update(bytes).digest("hex");
10637
+ const sha256 = createHash7("sha256").update(bytes).digest("hex");
10486
10638
  if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
10487
10639
  return bytes;
10488
10640
  }
@@ -69178,16 +69330,16 @@ var require_jwtaccess = __commonJS({
69178
69330
  * @returns A string that returns the cached key.
69179
69331
  */
69180
69332
  getCachedKey(url, scopes) {
69181
- let cacheKey = url;
69333
+ let cacheKey3 = url;
69182
69334
  if (scopes && Array.isArray(scopes) && scopes.length) {
69183
- cacheKey = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
69335
+ cacheKey3 = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
69184
69336
  } else if (typeof scopes === "string") {
69185
- cacheKey = url ? `${url}_${scopes}` : scopes;
69337
+ cacheKey3 = url ? `${url}_${scopes}` : scopes;
69186
69338
  }
69187
- if (!cacheKey) {
69339
+ if (!cacheKey3) {
69188
69340
  throw Error("Scopes or url must be provided");
69189
69341
  }
69190
- return cacheKey;
69342
+ return cacheKey3;
69191
69343
  }
69192
69344
  /**
69193
69345
  * Get a non-expired access token, after refreshing if necessary.
@@ -75733,7 +75885,7 @@ var require_websocket = __commonJS({
75733
75885
  var http3 = __require("http");
75734
75886
  var net = __require("net");
75735
75887
  var tls = __require("tls");
75736
- var { randomBytes, createHash: createHash16 } = __require("crypto");
75888
+ var { randomBytes, createHash: createHash17 } = __require("crypto");
75737
75889
  var { Duplex, Readable: Readable2 } = __require("stream");
75738
75890
  var { URL: URL2 } = __require("url");
75739
75891
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -76401,7 +76553,7 @@ var require_websocket = __commonJS({
76401
76553
  abortHandshake(websocket, socket, "Invalid Upgrade header");
76402
76554
  return;
76403
76555
  }
76404
- const digest2 = createHash16("sha1").update(key + GUID).digest("base64");
76556
+ const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
76405
76557
  if (res.headers["sec-websocket-accept"] !== digest2) {
76406
76558
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
76407
76559
  return;
@@ -76773,7 +76925,7 @@ var require_websocket_server = __commonJS({
76773
76925
  var EventEmitter = __require("events");
76774
76926
  var http3 = __require("http");
76775
76927
  var { Duplex } = __require("stream");
76776
- var { createHash: createHash16 } = __require("crypto");
76928
+ var { createHash: createHash17 } = __require("crypto");
76777
76929
  var extension3 = require_extension();
76778
76930
  var PerMessageDeflate2 = require_permessage_deflate();
76779
76931
  var subprotocol2 = require_subprotocol();
@@ -77080,7 +77232,7 @@ var require_websocket_server = __commonJS({
77080
77232
  );
77081
77233
  }
77082
77234
  if (this._state > RUNNING) return abortHandshake(socket, 503);
77083
- const digest2 = createHash16("sha1").update(key + GUID).digest("base64");
77235
+ const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
77084
77236
  const headers = [
77085
77237
  "HTTP/1.1 101 Switching Protocols",
77086
77238
  "Upgrade: websocket",
@@ -145365,9 +145517,9 @@ var init_long_term = __esm({
145365
145517
  });
145366
145518
 
145367
145519
  // src/codegraph/ids.ts
145368
- import { createHash as createHash7 } from "crypto";
145520
+ import { createHash as createHash8 } from "crypto";
145369
145521
  function digest(input) {
145370
- return createHash7("sha256").update(input).digest("hex").slice(0, 16);
145522
+ return createHash8("sha256").update(input).digest("hex").slice(0, 16);
145371
145523
  }
145372
145524
  function normalizeCodePath(path23) {
145373
145525
  return path23.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
@@ -146415,7 +146567,7 @@ var init_store = __esm({
146415
146567
 
146416
146568
  // src/codegraph/code-state.ts
146417
146569
  import { execFile as execFile2 } from "child_process";
146418
- import { createHash as createHash8 } from "crypto";
146570
+ import { createHash as createHash9 } from "crypto";
146419
146571
  import { promisify as promisify3 } from "util";
146420
146572
  async function runGit(rootPath, args) {
146421
146573
  try {
@@ -146444,7 +146596,7 @@ function changedPathCount(status) {
146444
146596
  return count2;
146445
146597
  }
146446
146598
  function fingerprint(baseRevision, status) {
146447
- return createHash8("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
146599
+ return createHash9("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
146448
146600
  }
146449
146601
  async function collectCodeStateSnapshot(input) {
146450
146602
  const [revision, status] = await Promise.all([
@@ -146538,12 +146690,12 @@ var init_exclude3 = __esm({
146538
146690
  });
146539
146691
 
146540
146692
  // src/codegraph/semantic-provider.ts
146541
- import { createHash as createHash9 } from "crypto";
146693
+ import { createHash as createHash10 } from "crypto";
146542
146694
  import "fs";
146543
146695
  import { resolve } from "path";
146544
146696
  import ts from "typescript";
146545
146697
  function hashText(value) {
146546
- return createHash9("sha256").update(value).digest("hex");
146698
+ return createHash10("sha256").update(value).digest("hex");
146547
146699
  }
146548
146700
  function canonicalPath(value) {
146549
146701
  const normalized = resolve(value).replace(/\\/g, "/");
@@ -146888,11 +147040,11 @@ __export(lite_provider_exports, {
146888
147040
  indexProjectLite: () => indexProjectLite,
146889
147041
  refreshProjectLite: () => refreshProjectLite
146890
147042
  });
146891
- import { createHash as createHash10 } from "crypto";
147043
+ import { createHash as createHash11 } from "crypto";
146892
147044
  import { existsSync as existsSync10, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
146893
147045
  import { join as join4, relative as relative2 } from "path";
146894
147046
  function hashText2(text2) {
146895
- return createHash10("sha256").update(text2).digest("hex");
147047
+ return createHash11("sha256").update(text2).digest("hex");
146896
147048
  }
146897
147049
  function extension2(path23) {
146898
147050
  const index = path23.lastIndexOf(".");
@@ -147525,7 +147677,7 @@ var claim_store_exports = {};
147525
147677
  __export(claim_store_exports, {
147526
147678
  ClaimStore: () => ClaimStore
147527
147679
  });
147528
- import { createHash as createHash11, randomUUID as randomUUID12 } from "crypto";
147680
+ import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
147529
147681
  function optionalText3(value) {
147530
147682
  return typeof value === "string" && value ? value : void 0;
147531
147683
  }
@@ -147578,7 +147730,7 @@ function rowToEvent3(row) {
147578
147730
  };
147579
147731
  }
147580
147732
  function evidenceKey(input) {
147581
- return createHash11("sha256").update(JSON.stringify([
147733
+ return createHash12("sha256").update(JSON.stringify([
147582
147734
  input.evidenceKind,
147583
147735
  input.evidenceId,
147584
147736
  input.relation,
@@ -147776,7 +147928,7 @@ __export(claims_exports, {
147776
147928
  supersedeClaim: () => supersedeClaim,
147777
147929
  writeClaim: () => writeClaim
147778
147930
  });
147779
- import { createHash as createHash12, randomUUID as randomUUID13 } from "crypto";
147931
+ import { createHash as createHash13, randomUUID as randomUUID13 } from "crypto";
147780
147932
  function compactText2(value, field) {
147781
147933
  if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
147782
147934
  const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
@@ -147788,7 +147940,7 @@ function normalizedTerm(value) {
147788
147940
  return compactText2(value, "identity").toLocaleLowerCase("en-US");
147789
147941
  }
147790
147942
  function hashIdentity(parts) {
147791
- return createHash12("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
147943
+ return createHash13("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
147792
147944
  }
147793
147945
  function buildClaimIdentity(input) {
147794
147946
  const subject = normalizedTerm(input.subject);
@@ -148029,7 +148181,7 @@ function supersedeClaim(store, input) {
148029
148181
  });
148030
148182
  }
148031
148183
  function hashObservation(observation) {
148032
- return createHash12("sha256").update(JSON.stringify([
148184
+ return createHash13("sha256").update(JSON.stringify([
148033
148185
  observation.title,
148034
148186
  observation.narrative,
148035
148187
  observation.facts,
@@ -148273,11 +148425,11 @@ var init_frontmatter = __esm({
148273
148425
  });
148274
148426
 
148275
148427
  // src/knowledge/markdown.ts
148276
- import { createHash as createHash13 } from "crypto";
148428
+ import { createHash as createHash14 } from "crypto";
148277
148429
  import { promises as fs10 } from "fs";
148278
148430
  import path17 from "path";
148279
148431
  function hashContent(content) {
148280
- return createHash13("sha256").update(content).digest("hex");
148432
+ return createHash14("sha256").update(content).digest("hex");
148281
148433
  }
148282
148434
  function stringField(data, key) {
148283
148435
  const value = data[key];
@@ -148403,11 +148555,11 @@ __export(wiki_exports, {
148403
148555
  lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
148404
148556
  readKnowledgePage: () => readKnowledgePage
148405
148557
  });
148406
- import { createHash as createHash14 } from "crypto";
148558
+ import { createHash as createHash15 } from "crypto";
148407
148559
  import { promises as fs11 } from "fs";
148408
148560
  import path18 from "path";
148409
148561
  function hash2(value) {
148410
- return createHash14("sha256").update(value).digest("hex");
148562
+ return createHash15("sha256").update(value).digest("hex");
148411
148563
  }
148412
148564
  function now() {
148413
148565
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -149264,11 +149416,11 @@ __export(workflows_exports, {
149264
149416
  syncCanonicalWorkflows: () => syncCanonicalWorkflows,
149265
149417
  writeCanonicalWorkflow: () => writeCanonicalWorkflow
149266
149418
  });
149267
- import { createHash as createHash15 } from "crypto";
149419
+ import { createHash as createHash16 } from "crypto";
149268
149420
  import { promises as fs12 } from "fs";
149269
149421
  import path19 from "path";
149270
149422
  function hash3(value) {
149271
- return createHash15("sha256").update(value).digest("hex");
149423
+ return createHash16("sha256").update(value).digest("hex");
149272
149424
  }
149273
149425
  function now2() {
149274
149426
  return (/* @__PURE__ */ new Date()).toISOString();