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) {
@@ -414,6 +419,74 @@ var init_launch_root = __esm({
414
419
  }
415
420
  });
416
421
 
422
+ // src/store/sqlite-reliability.ts
423
+ function isTransientSqliteError(error) {
424
+ const code = error?.code;
425
+ if (typeof code === "string") {
426
+ return /^SQLITE_BUSY(?:_|$)/i.test(code);
427
+ }
428
+ return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
429
+ }
430
+ function isSqliteUnavailableError(error) {
431
+ return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
432
+ }
433
+ function degradedReadError(storeName) {
434
+ return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
435
+ }
436
+ function degradedWriteError(storeName) {
437
+ return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
438
+ }
439
+ function formatSqliteFailure(error) {
440
+ return error instanceof Error && error.message ? error.message : String(error);
441
+ }
442
+ function delay(ms) {
443
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
444
+ }
445
+ async function retrySqliteBusy(operation, label) {
446
+ for (let attempt = 0; ; attempt++) {
447
+ try {
448
+ return await operation();
449
+ } catch (error) {
450
+ if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
451
+ const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
452
+ console.error(
453
+ `[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
454
+ );
455
+ await delay(waitMs);
456
+ }
457
+ }
458
+ }
459
+ async function initializeSqliteStore(factory, dataDir, label) {
460
+ try {
461
+ loadBetterSqlite3();
462
+ } catch (error) {
463
+ throw new SqliteUnavailableError(error);
464
+ }
465
+ return retrySqliteBusy(async () => {
466
+ const store = factory();
467
+ await store.init(dataDir);
468
+ return store;
469
+ }, label);
470
+ }
471
+ var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
472
+ var init_sqlite_reliability = __esm({
473
+ "src/store/sqlite-reliability.ts"() {
474
+ "use strict";
475
+ init_esm_shims();
476
+ init_sqlite_db();
477
+ SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
478
+ SqliteUnavailableError = class extends Error {
479
+ code = "MEMORIX_SQLITE_UNAVAILABLE";
480
+ constructor(cause) {
481
+ super(
482
+ cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
483
+ );
484
+ this.name = "SqliteUnavailableError";
485
+ }
486
+ };
487
+ }
488
+ });
489
+
417
490
  // src/store/sqlite-fts.ts
418
491
  function normalizeFtsToken(token) {
419
492
  return token.replace(/"/g, '""');
@@ -427,22 +500,27 @@ function buildFtsQuery(query) {
427
500
  function initializeObservationLexicalIndex(db2) {
428
501
  const known = ftsAvailability.get(db2);
429
502
  if (known !== void 0) return known;
430
- try {
431
- db2.exec(CREATE_OBSERVATION_FTS);
432
- const observationCount = Number(db2.prepare("SELECT COUNT(*) AS count FROM observations").get()?.count ?? 0);
433
- const indexedCount = Number(db2.prepare(`SELECT COUNT(*) AS count FROM ${FTS_TABLE}`).get()?.count ?? 0);
434
- if (observationCount !== indexedCount) {
435
- db2.exec(`INSERT INTO ${FTS_TABLE}(${FTS_TABLE}) VALUES ('rebuild')`);
503
+ let lastError;
504
+ for (let attempt = 1; attempt <= FTS_INIT_MAX_ATTEMPTS; attempt++) {
505
+ try {
506
+ db2.exec(CREATE_OBSERVATION_FTS);
507
+ const observationCount = Number(db2.prepare("SELECT COUNT(*) AS count FROM observations").get()?.count ?? 0);
508
+ const indexedCount = Number(db2.prepare(`SELECT COUNT(*) AS count FROM ${FTS_TABLE}`).get()?.count ?? 0);
509
+ if (observationCount !== indexedCount) {
510
+ db2.exec(`INSERT INTO ${FTS_TABLE}(${FTS_TABLE}) VALUES ('rebuild')`);
511
+ }
512
+ ftsAvailability.set(db2, true);
513
+ return true;
514
+ } catch (error) {
515
+ lastError = error;
516
+ if (!isTransientSqliteError(error) || attempt === FTS_INIT_MAX_ATTEMPTS) break;
436
517
  }
437
- ftsAvailability.set(db2, true);
438
- return true;
439
- } catch (error) {
440
- ftsAvailability.set(db2, false);
441
- console.warn(
442
- `[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${error instanceof Error ? error.message : String(error)}`
443
- );
444
- return false;
445
518
  }
519
+ ftsAvailability.set(db2, false);
520
+ console.warn(
521
+ `[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${lastError instanceof Error ? lastError.message : String(lastError)}`
522
+ );
523
+ return false;
446
524
  }
447
525
  function isObservationLexicalIndexEnabled(db2) {
448
526
  return ftsAvailability.get(db2) === true;
@@ -496,11 +574,12 @@ function searchObservationLexically(db2, options) {
496
574
  score: Math.max(0, Number(row.lexical_score ?? 0))
497
575
  }));
498
576
  }
499
- var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS;
577
+ var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS, FTS_INIT_MAX_ATTEMPTS;
500
578
  var init_sqlite_fts = __esm({
501
579
  "src/store/sqlite-fts.ts"() {
502
580
  "use strict";
503
581
  init_esm_shims();
582
+ init_sqlite_reliability();
504
583
  ftsAvailability = /* @__PURE__ */ new WeakMap();
505
584
  FTS_TABLE = "observations_fts";
506
585
  CREATE_OBSERVATION_FTS = `
@@ -534,6 +613,7 @@ CREATE TRIGGER IF NOT EXISTS observations_fts_au AFTER UPDATE ON observations BE
534
613
  VALUES (new.id, new.entityName, new.title, new.narrative, new.facts, new.filesModified, new.concepts, new.attachments);
535
614
  END;
536
615
  `;
616
+ FTS_INIT_MAX_ATTEMPTS = 3;
537
617
  }
538
618
  });
539
619
 
@@ -572,11 +652,21 @@ function applySchemaMigrations(db2) {
572
652
  apply();
573
653
  }
574
654
  }
655
+ function normalizeDataDir(dataDir) {
656
+ return path3.resolve(dataDir);
657
+ }
658
+ function touchDatabase(normalized, db2) {
659
+ _dbCache.delete(normalized);
660
+ _dbCache.set(normalized, db2);
661
+ }
575
662
  function getDatabase(dataDir) {
576
- const normalized = path3.resolve(dataDir);
663
+ const normalized = normalizeDataDir(dataDir);
577
664
  assertNotHomeDataDir(normalized);
578
665
  const existing = _dbCache.get(normalized);
579
- if (existing) return existing;
666
+ if (existing) {
667
+ touchDatabase(normalized, existing);
668
+ return existing;
669
+ }
580
670
  loadBetterSqlite3();
581
671
  fs.mkdirSync(dataDir, { recursive: true });
582
672
  const dbPath = path3.join(dataDir, "memorix.db");
@@ -606,6 +696,8 @@ function getDatabase(dataDir) {
606
696
  db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
607
697
  db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
608
698
  db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
699
+ db2.exec(CREATE_TASK_CONTINUITY_EVENTS_TABLE);
700
+ db2.exec(CREATE_AGENT_EFFECTS_TABLE);
609
701
  try {
610
702
  db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
611
703
  } catch {
@@ -644,7 +736,7 @@ function getDatabase(dataDir) {
644
736
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
645
737
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
646
738
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
647
- _dbCache.set(normalized, db2);
739
+ touchDatabase(normalized, db2);
648
740
  return db2;
649
741
  } catch (error) {
650
742
  try {
@@ -662,8 +754,9 @@ function closeAllDatabases() {
662
754
  }
663
755
  _dbCache.delete(key);
664
756
  }
757
+ _dbLeases.clear();
665
758
  }
666
- 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;
759
+ 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;
667
760
  var init_sqlite_db = __esm({
668
761
  "src/store/sqlite-db.ts"() {
669
762
  "use strict";
@@ -1380,6 +1473,43 @@ CREATE TABLE IF NOT EXISTS memory_feedback_events (
1380
1473
  delta REAL NOT NULL DEFAULT 0,
1381
1474
  observed_at TEXT NOT NULL
1382
1475
  );
1476
+ `;
1477
+ CREATE_TASK_CONTINUITY_EVENTS_TABLE = `
1478
+ CREATE TABLE IF NOT EXISTS task_continuity_events (
1479
+ id TEXT PRIMARY KEY,
1480
+ project_id TEXT NOT NULL,
1481
+ task_id TEXT NOT NULL,
1482
+ task TEXT NOT NULL,
1483
+ kind TEXT NOT NULL,
1484
+ content TEXT NOT NULL,
1485
+ item_status TEXT,
1486
+ source_ref TEXT,
1487
+ evidence_json TEXT NOT NULL DEFAULT '[]',
1488
+ actor TEXT,
1489
+ created_at TEXT NOT NULL,
1490
+ event_key TEXT,
1491
+ item_key TEXT,
1492
+ supersedes_id TEXT
1493
+ );
1494
+ `;
1495
+ CREATE_AGENT_EFFECTS_TABLE = `
1496
+ CREATE TABLE IF NOT EXISTS agent_effects (
1497
+ id TEXT PRIMARY KEY,
1498
+ pipeline_id TEXT NOT NULL,
1499
+ task_id TEXT NOT NULL,
1500
+ attempt INTEGER NOT NULL,
1501
+ effect_key TEXT NOT NULL,
1502
+ tool TEXT NOT NULL,
1503
+ risk_tier TEXT NOT NULL,
1504
+ replay_policy TEXT NOT NULL,
1505
+ status TEXT NOT NULL,
1506
+ call_id TEXT,
1507
+ idempotency_key TEXT NOT NULL,
1508
+ input_fingerprint TEXT,
1509
+ detail TEXT,
1510
+ started_at INTEGER NOT NULL,
1511
+ finished_at INTEGER
1512
+ );
1383
1513
  `;
1384
1514
  CREATE_MCP_BINDINGS_TABLE = `
1385
1515
  CREATE TABLE IF NOT EXISTS mcp_bindings (
@@ -1458,7 +1588,18 @@ CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(projec
1458
1588
  CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
1459
1589
  CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
1460
1590
  CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
1591
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_project_task ON task_continuity_events(project_id, task_id, created_at ASC);
1592
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_project_recent ON task_continuity_events(project_id, created_at DESC);
1593
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_item ON task_continuity_events(project_id, task_id, kind, item_key, created_at DESC);
1594
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
1595
+ ON task_continuity_events(project_id, task_id, event_key)
1596
+ WHERE event_key IS NOT NULL;
1597
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_effect_identity
1598
+ ON agent_effects(pipeline_id, task_id, attempt, effect_key);
1599
+ CREATE INDEX IF NOT EXISTS idx_agent_effect_pipeline ON agent_effects(pipeline_id, started_at ASC);
1461
1600
  CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
1601
+ CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC);
1602
+ CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at);
1462
1603
  CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1463
1604
  ON maintenance_jobs(project_id, kind, dedupe_key)
1464
1605
  WHERE status IN ('pending', 'running', 'retry');
@@ -1629,6 +1770,8 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1629
1770
  db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
1630
1771
  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)");
1631
1772
  db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
1773
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC)");
1774
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at)");
1632
1775
  }
1633
1776
  },
1634
1777
  {
@@ -1639,77 +1782,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1639
1782
  addColumnIfMissing(db2, "code_symbols", "source", "source TEXT");
1640
1783
  addColumnIfMissing(db2, "code_edges", "source", "source TEXT");
1641
1784
  }
1785
+ },
1786
+ {
1787
+ id: "1.9-continuity-v2",
1788
+ apply: (db2) => {
1789
+ addColumnIfMissing(db2, "task_continuity_events", "event_key", "event_key TEXT");
1790
+ addColumnIfMissing(db2, "task_continuity_events", "item_key", "item_key TEXT");
1791
+ addColumnIfMissing(db2, "task_continuity_events", "supersedes_id", "supersedes_id TEXT");
1792
+ 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)");
1793
+ db2.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
1794
+ ON task_continuity_events(project_id, task_id, event_key)
1795
+ WHERE event_key IS NOT NULL`);
1796
+ }
1642
1797
  }
1643
1798
  ];
1644
1799
  _dbCache = /* @__PURE__ */ new Map();
1645
- }
1646
- });
1647
-
1648
- // src/store/sqlite-reliability.ts
1649
- function isTransientSqliteError(error) {
1650
- const code = error?.code;
1651
- if (typeof code === "string") {
1652
- return /^SQLITE_BUSY(?:_|$)/i.test(code);
1653
- }
1654
- return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
1655
- }
1656
- function isSqliteUnavailableError(error) {
1657
- return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
1658
- }
1659
- function degradedReadError(storeName) {
1660
- return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
1661
- }
1662
- function degradedWriteError(storeName) {
1663
- return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
1664
- }
1665
- function formatSqliteFailure(error) {
1666
- return error instanceof Error && error.message ? error.message : String(error);
1667
- }
1668
- function delay(ms) {
1669
- return new Promise((resolve2) => setTimeout(resolve2, ms));
1670
- }
1671
- async function retrySqliteBusy(operation, label) {
1672
- for (let attempt = 0; ; attempt++) {
1673
- try {
1674
- return await operation();
1675
- } catch (error) {
1676
- if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
1677
- const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
1678
- console.error(
1679
- `[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
1680
- );
1681
- await delay(waitMs);
1682
- }
1683
- }
1684
- }
1685
- async function initializeSqliteStore(factory, dataDir, label) {
1686
- try {
1687
- loadBetterSqlite3();
1688
- } catch (error) {
1689
- throw new SqliteUnavailableError(error);
1690
- }
1691
- return retrySqliteBusy(async () => {
1692
- const store = factory();
1693
- await store.init(dataDir);
1694
- return store;
1695
- }, label);
1696
- }
1697
- var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
1698
- var init_sqlite_reliability = __esm({
1699
- "src/store/sqlite-reliability.ts"() {
1700
- "use strict";
1701
- init_esm_shims();
1702
- init_sqlite_db();
1703
- SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
1704
- SqliteUnavailableError = class extends Error {
1705
- code = "MEMORIX_SQLITE_UNAVAILABLE";
1706
- constructor(cause) {
1707
- super(
1708
- cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
1709
- );
1710
- this.name = "SqliteUnavailableError";
1711
- }
1712
- };
1800
+ _dbLeases = /* @__PURE__ */ new Map();
1713
1801
  }
1714
1802
  });
1715
1803
 
@@ -2131,9 +2219,9 @@ var init_detector = __esm({
2131
2219
  // src/config/legacy-loader.ts
2132
2220
  import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
2133
2221
  import { homedir as homedir3 } from "os";
2134
- function loadFileConfig() {
2222
+ function loadFileConfig(homeDir = homedir3()) {
2135
2223
  if (cachedConfig !== null) return cachedConfig;
2136
- const configPath = getLegacyConfigJsonPath(homedir3());
2224
+ const configPath = getLegacyConfigJsonPath(homeDir);
2137
2225
  try {
2138
2226
  if (existsSync5(configPath)) {
2139
2227
  cachedConfig = JSON.parse(readFileSync5(configPath, "utf-8"));
@@ -2163,15 +2251,15 @@ import { homedir as homedir4 } from "os";
2163
2251
  function loadTomlConfig(options = {}) {
2164
2252
  const homeDir = options.homeDir ?? homedir4();
2165
2253
  const projectRoot = options.projectRoot ?? null;
2166
- const cacheKey = `${homeDir}\0${projectRoot ?? ""}`;
2167
- const cached = configCache2.get(cacheKey);
2254
+ const cacheKey3 = `${homeDir}\0${projectRoot ?? ""}`;
2255
+ const cached = configCache2.get(cacheKey3);
2168
2256
  if (cached) return cached;
2169
2257
  const userToml = getGlobalConfigTomlPath(homeDir);
2170
2258
  const projectToml = projectRoot ? getProjectConfigTomlPath(projectRoot) : null;
2171
2259
  const userConfig = existsSync6(userToml) ? parseTomlConfig(readFileSync6(userToml, "utf8"), userToml) : {};
2172
2260
  const projectConfig = projectToml && existsSync6(projectToml) ? parseTomlConfig(readFileSync6(projectToml, "utf8"), projectToml) : {};
2173
2261
  const merged = mergeTomlConfig(userConfig, projectConfig);
2174
- configCache2.set(cacheKey, merged);
2262
+ configCache2.set(cacheKey3, merged);
2175
2263
  return merged;
2176
2264
  }
2177
2265
  function mergeTomlConfig(base, override) {
@@ -2292,8 +2380,8 @@ function getResolvedConfig(options = {}) {
2292
2380
  const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
2293
2381
  loadDotenv(projectRoot === null ? void 0 : projectRoot ?? void 0, { userHomeDir: homeDir });
2294
2382
  const toml = loadTomlConfig({ projectRoot: projectRoot ?? null, homeDir });
2295
- const yaml = loadYamlConfig(projectRoot ?? null);
2296
- const legacy = loadFileConfig();
2383
+ const yaml = loadYamlConfig(projectRoot ?? null, { homeDir });
2384
+ const legacy = loadFileConfig(homeDir);
2297
2385
  const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
2298
2386
  const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
2299
2387
  const memoryLlmProvider = first(
@@ -2315,15 +2403,17 @@ function getResolvedConfig(options = {}) {
2315
2403
  legacy.llm?.baseUrl
2316
2404
  );
2317
2405
  const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
2406
+ const isAtlasCloud = memoryLlmProvider === "atlascloud";
2318
2407
  const memoryLlmApiKey = first(
2319
2408
  process.env.MEMORIX_LLM_API_KEY,
2320
2409
  process.env.MEMORIX_API_KEY,
2321
2410
  toml.memory?.llm?.api_key,
2322
2411
  yaml.llm?.apiKey,
2323
2412
  legacy.llm?.apiKey,
2324
- process.env.OPENAI_API_KEY,
2325
- process.env.ANTHROPIC_API_KEY,
2326
- openRouterMemoryLlmApiKey
2413
+ // Never borrow another provider's credentials for the Atlas Cloud preset.
2414
+ isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
2415
+ isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
2416
+ isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
2327
2417
  );
2328
2418
  const resolved = {
2329
2419
  agent: {
@@ -2502,7 +2592,8 @@ function getEnvSourceNames() {
2502
2592
  "MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
2503
2593
  "MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
2504
2594
  "MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
2505
- "OPENROUTER_API_KEY"
2595
+ "OPENROUTER_API_KEY",
2596
+ "ATLASCLOUD_API_KEY"
2506
2597
  ].filter((name) => process.env[name]);
2507
2598
  }
2508
2599
  function isOpenRouterUrl(value) {
@@ -2721,12 +2812,45 @@ function textHash(text2) {
2721
2812
  async function loadDiskCache() {
2722
2813
  try {
2723
2814
  const raw = await readFile(CACHE_FILE, "utf-8");
2815
+ if (Buffer.byteLength(raw, "utf8") > MAX_CACHE_FILE_BYTES) {
2816
+ console.error("[memorix] FastEmbed cache exceeds the disk load limit; starting with an empty cache");
2817
+ return;
2818
+ }
2724
2819
  const entries = JSON.parse(raw);
2725
- for (const [k, v] of entries) cache.set(k, v);
2726
- console.error(`[memorix] Loaded ${entries.length} cached embeddings from disk`);
2820
+ if (!Array.isArray(entries)) return;
2821
+ for (const entry of entries) {
2822
+ if (!Array.isArray(entry) || typeof entry[0] !== "string" || !isVector(entry[1])) continue;
2823
+ cacheSet(entry[0], entry[1], false);
2824
+ }
2825
+ console.error(`[memorix] Loaded ${cache.size} cached embeddings from disk`);
2727
2826
  } catch {
2728
2827
  }
2729
2828
  }
2829
+ function isVector(value) {
2830
+ return Array.isArray(value) && value.every((entry) => typeof entry === "number");
2831
+ }
2832
+ function maxCachePayloadBytes() {
2833
+ const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
2834
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES;
2835
+ }
2836
+ function cacheSet(hash4, value, markDirty = true) {
2837
+ const incomingBytes = value.length * 8;
2838
+ if (incomingBytes > maxCachePayloadBytes()) return;
2839
+ const existing = cache.get(hash4);
2840
+ if (existing) cachePayloadBytes -= existing.length * 8;
2841
+ else {
2842
+ while (cache.size >= MAX_CACHE_SIZE || cachePayloadBytes + incomingBytes > maxCachePayloadBytes()) {
2843
+ const firstKey = cache.keys().next().value;
2844
+ if (firstKey === void 0) break;
2845
+ const old = cache.get(firstKey);
2846
+ cache.delete(firstKey);
2847
+ if (old) cachePayloadBytes -= old.length * 8;
2848
+ }
2849
+ }
2850
+ cache.set(hash4, value);
2851
+ cachePayloadBytes += incomingBytes;
2852
+ if (markDirty) diskCacheDirty = true;
2853
+ }
2730
2854
  async function saveDiskCache() {
2731
2855
  if (!diskCacheDirty) return;
2732
2856
  try {
@@ -2737,7 +2861,7 @@ async function saveDiskCache() {
2737
2861
  } catch {
2738
2862
  }
2739
2863
  }
2740
- var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, diskCacheDirty, FastEmbedProvider;
2864
+ var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, DEFAULT_CACHE_PAYLOAD_BYTES, MAX_CACHE_FILE_BYTES, cachePayloadBytes, diskCacheDirty, FastEmbedProvider;
2741
2865
  var init_fastembed_provider = __esm({
2742
2866
  "src/embedding/fastembed-provider.ts"() {
2743
2867
  "use strict";
@@ -2747,6 +2871,9 @@ var init_fastembed_provider = __esm({
2747
2871
  CACHE_FILE = join2(CACHE_DIR, ".embedding-cache.json");
2748
2872
  cache = /* @__PURE__ */ new Map();
2749
2873
  MAX_CACHE_SIZE = 5e3;
2874
+ DEFAULT_CACHE_PAYLOAD_BYTES = 64 * 1024 * 1024;
2875
+ MAX_CACHE_FILE_BYTES = 128 * 1024 * 1024;
2876
+ cachePayloadBytes = 0;
2750
2877
  diskCacheDirty = false;
2751
2878
  FastEmbedProvider = class _FastEmbedProvider {
2752
2879
  name = "fastembed-bge-small";
@@ -2788,7 +2915,7 @@ var init_fastembed_provider = __esm({
2788
2915
  if (result.length !== this.dimensions) {
2789
2916
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
2790
2917
  }
2791
- this.cacheSet(hash4, result);
2918
+ cacheSet(hash4, result);
2792
2919
  return result;
2793
2920
  }
2794
2921
  async embedBatch(texts) {
@@ -2813,7 +2940,7 @@ var init_fastembed_provider = __esm({
2813
2940
  const originalIdx = uncachedIndices[batchIdx];
2814
2941
  const plain = Array.from(vec);
2815
2942
  results[originalIdx] = plain;
2816
- this.cacheSet(textHash(uncachedTexts[batchIdx]), plain);
2943
+ cacheSet(textHash(uncachedTexts[batchIdx]), plain);
2817
2944
  batchIdx++;
2818
2945
  }
2819
2946
  }
@@ -2821,14 +2948,6 @@ var init_fastembed_provider = __esm({
2821
2948
  }
2822
2949
  return results;
2823
2950
  }
2824
- cacheSet(hash4, value) {
2825
- if (cache.size >= MAX_CACHE_SIZE) {
2826
- const firstKey = cache.keys().next().value;
2827
- if (firstKey !== void 0) cache.delete(firstKey);
2828
- }
2829
- cache.set(hash4, value);
2830
- diskCacheDirty = true;
2831
- }
2832
2951
  };
2833
2952
  }
2834
2953
  });
@@ -2838,7 +2957,15 @@ var transformers_provider_exports = {};
2838
2957
  __export(transformers_provider_exports, {
2839
2958
  TransformersProvider: () => TransformersProvider
2840
2959
  });
2841
- var cache2, MAX_CACHE_SIZE2, TransformersProvider;
2960
+ import { createHash as createHash2 } from "crypto";
2961
+ function cacheKey2(text2) {
2962
+ return createHash2("sha256").update(text2).digest("hex");
2963
+ }
2964
+ function maxCachePayloadBytes2() {
2965
+ const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
2966
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES2;
2967
+ }
2968
+ var cache2, MAX_CACHE_SIZE2, DEFAULT_CACHE_PAYLOAD_BYTES2, cachePayloadBytes2, TransformersProvider;
2842
2969
  var init_transformers_provider = __esm({
2843
2970
  "src/embedding/transformers-provider.ts"() {
2844
2971
  "use strict";
@@ -2846,6 +2973,8 @@ var init_transformers_provider = __esm({
2846
2973
  init_provider();
2847
2974
  cache2 = /* @__PURE__ */ new Map();
2848
2975
  MAX_CACHE_SIZE2 = 5e3;
2976
+ DEFAULT_CACHE_PAYLOAD_BYTES2 = 64 * 1024 * 1024;
2977
+ cachePayloadBytes2 = 0;
2849
2978
  TransformersProvider = class _TransformersProvider {
2850
2979
  name = "transformers-minilm";
2851
2980
  dimensions = 384;
@@ -2880,7 +3009,7 @@ var init_transformers_provider = __esm({
2880
3009
  return Promise.all(inputs.map((input) => this.embedInput(input, options)));
2881
3010
  }
2882
3011
  async embed(text2) {
2883
- const cached = cache2.get(text2);
3012
+ const cached = cache2.get(cacheKey2(text2));
2884
3013
  if (cached) return cached;
2885
3014
  const output = await this.extractor(text2, {
2886
3015
  pooling: "mean",
@@ -2890,7 +3019,7 @@ var init_transformers_provider = __esm({
2890
3019
  if (result.length !== this.dimensions) {
2891
3020
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
2892
3021
  }
2893
- this.cacheSet(text2, result);
3022
+ this.cacheSet(cacheKey2(text2), result);
2894
3023
  return result;
2895
3024
  }
2896
3025
  async embedBatch(texts) {
@@ -2898,7 +3027,7 @@ var init_transformers_provider = __esm({
2898
3027
  const uncachedIndices = [];
2899
3028
  const uncachedTexts = [];
2900
3029
  for (let i2 = 0; i2 < texts.length; i2++) {
2901
- const cached = cache2.get(texts[i2]);
3030
+ const cached = cache2.get(cacheKey2(texts[i2]));
2902
3031
  if (cached) {
2903
3032
  results[i2] = cached;
2904
3033
  } else {
@@ -2916,17 +3045,27 @@ var init_transformers_provider = __esm({
2916
3045
  const vec = Array.from(allVecs[i2]);
2917
3046
  const originalIdx = uncachedIndices[i2];
2918
3047
  results[originalIdx] = vec;
2919
- this.cacheSet(uncachedTexts[i2], vec);
3048
+ this.cacheSet(cacheKey2(uncachedTexts[i2]), vec);
2920
3049
  }
2921
3050
  }
2922
3051
  return results;
2923
3052
  }
2924
3053
  cacheSet(key, value) {
2925
- if (cache2.size >= MAX_CACHE_SIZE2) {
2926
- const firstKey = cache2.keys().next().value;
2927
- if (firstKey !== void 0) cache2.delete(firstKey);
3054
+ const incomingBytes = value.length * 8;
3055
+ if (incomingBytes > maxCachePayloadBytes2()) return;
3056
+ const existing = cache2.get(key);
3057
+ if (existing) cachePayloadBytes2 -= existing.length * 8;
3058
+ else {
3059
+ while (cache2.size >= MAX_CACHE_SIZE2 || cachePayloadBytes2 + incomingBytes > maxCachePayloadBytes2()) {
3060
+ const firstKey = cache2.keys().next().value;
3061
+ if (firstKey === void 0) break;
3062
+ const old = cache2.get(firstKey);
3063
+ cache2.delete(firstKey);
3064
+ if (old) cachePayloadBytes2 -= old.length * 8;
3065
+ }
2928
3066
  }
2929
3067
  cache2.set(key, value);
3068
+ cachePayloadBytes2 += incomingBytes;
2930
3069
  }
2931
3070
  };
2932
3071
  }
@@ -2948,7 +3087,7 @@ __export(api_provider_exports, {
2948
3087
  saveDiskCacheNow: () => saveDiskCacheNow,
2949
3088
  seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
2950
3089
  });
2951
- import { createHash as createHash2 } from "crypto";
3090
+ import { createHash as createHash3 } from "crypto";
2952
3091
  import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
2953
3092
  import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
2954
3093
  import { join as join3 } from "path";
@@ -2975,7 +3114,7 @@ function cacheStatFile() {
2975
3114
  function payloadBytes(vector) {
2976
3115
  return vector.length * BYTES_PER_DIM;
2977
3116
  }
2978
- function maxCachePayloadBytes() {
3117
+ function maxCachePayloadBytes3() {
2979
3118
  const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
2980
3119
  if (raw) {
2981
3120
  const parsed = Number.parseInt(raw, 10);
@@ -2985,7 +3124,7 @@ function maxCachePayloadBytes() {
2985
3124
  }
2986
3125
  function maxEntriesForDimensions(dimensions) {
2987
3126
  const dim = Math.max(1, Math.floor(dimensions));
2988
- const byBytes = Math.floor(maxCachePayloadBytes() / (dim * BYTES_PER_DIM));
3127
+ const byBytes = Math.floor(maxCachePayloadBytes3() / (dim * BYTES_PER_DIM));
2989
3128
  return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
2990
3129
  }
2991
3130
  function rememberDimensions(vector) {
@@ -2998,13 +3137,15 @@ function evictOldest() {
2998
3137
  if (firstKey === void 0) return;
2999
3138
  const old = cache3.get(firstKey);
3000
3139
  cache3.delete(firstKey);
3001
- if (old) cachePayloadBytes -= payloadBytes(old);
3140
+ if (old) cachePayloadBytes3 -= payloadBytes(old);
3002
3141
  }
3003
3142
  function evictToFit(incomingBytes, incomingDims) {
3143
+ if (incomingBytes > maxCachePayloadBytes3()) return false;
3004
3144
  const limit2 = maxEntriesForDimensions(incomingDims);
3005
- while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes + incomingBytes > maxCachePayloadBytes())) {
3145
+ while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes3 + incomingBytes > maxCachePayloadBytes3())) {
3006
3146
  evictOldest();
3007
3147
  }
3148
+ return true;
3008
3149
  }
3009
3150
  function isNumberArray(value) {
3010
3151
  return Array.isArray(value) && value.every((entry) => typeof entry === "number");
@@ -3031,12 +3172,12 @@ function cacheInsert(hash4, value, dirty) {
3031
3172
  const incoming = payloadBytes(value);
3032
3173
  const existing = cache3.get(hash4);
3033
3174
  if (existing) {
3034
- cachePayloadBytes -= payloadBytes(existing);
3175
+ cachePayloadBytes3 -= payloadBytes(existing);
3035
3176
  cache3.delete(hash4);
3036
3177
  }
3037
- evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
3178
+ if (!evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS)) return;
3038
3179
  cache3.set(hash4, value);
3039
- cachePayloadBytes += incoming;
3180
+ cachePayloadBytes3 += incoming;
3040
3181
  if (dirty) diskCacheDirty2 = true;
3041
3182
  }
3042
3183
  async function readCacheStat() {
@@ -3072,7 +3213,7 @@ function cacheNamespace(config) {
3072
3213
  ].join("|");
3073
3214
  }
3074
3215
  function textHash2(text2, namespace) {
3075
- return createHash2("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
3216
+ return createHash3("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
3076
3217
  }
3077
3218
  function inputIdentity(input, options = {}) {
3078
3219
  return JSON.stringify({
@@ -3414,7 +3555,7 @@ function getApiEmbeddingDiskCacheLoadCountForTests() {
3414
3555
  }
3415
3556
  function resetApiEmbeddingCacheForTests() {
3416
3557
  cache3.clear();
3417
- cachePayloadBytes = 0;
3558
+ cachePayloadBytes3 = 0;
3418
3559
  cacheDimensions = null;
3419
3560
  diskCacheEntryCount = 0;
3420
3561
  diskCacheLoaded = false;
@@ -3425,14 +3566,14 @@ function resetApiEmbeddingCacheForTests() {
3425
3566
  }
3426
3567
  function seedApiEmbeddingCacheForTests(entries) {
3427
3568
  cache3.clear();
3428
- cachePayloadBytes = 0;
3569
+ cachePayloadBytes3 = 0;
3429
3570
  cacheDimensions = null;
3430
3571
  for (const [key, value] of entries) cacheInsert(key, value, true);
3431
3572
  diskCacheLoaded = true;
3432
3573
  diskCacheDirty2 = true;
3433
3574
  }
3434
3575
  function getApiEmbeddingCachePayloadBytesForTests() {
3435
- return cachePayloadBytes;
3576
+ return cachePayloadBytes3;
3436
3577
  }
3437
3578
  function getApiEmbeddingJsonlLineCountCallsForTests() {
3438
3579
  return jsonlLineCountCalls;
@@ -3606,7 +3747,7 @@ function scheduleDiskSave() {
3606
3747
  diskSaveTimer = null;
3607
3748
  }, DISK_SAVE_DEBOUNCE_MS);
3608
3749
  }
3609
- function cacheSet(hash4, value) {
3750
+ function cacheSet2(hash4, value) {
3610
3751
  cacheInsert(hash4, value, true);
3611
3752
  }
3612
3753
  function resolveEnvEmbeddingApiKey() {
@@ -3726,7 +3867,7 @@ async function waitForRetry(waitMs, signal) {
3726
3867
  abortSignal.addEventListener("abort", onAbort, { once: true });
3727
3868
  });
3728
3869
  }
3729
- 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;
3870
+ 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;
3730
3871
  var init_api_provider = __esm({
3731
3872
  "src/embedding/api-provider.ts"() {
3732
3873
  "use strict";
@@ -3738,7 +3879,7 @@ var init_api_provider = __esm({
3738
3879
  BYTES_PER_DIM = 8;
3739
3880
  DEFAULT_ASSUMED_DIMENSIONS = 4096;
3740
3881
  MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
3741
- cachePayloadBytes = 0;
3882
+ cachePayloadBytes3 = 0;
3742
3883
  cacheDimensions = null;
3743
3884
  diskCacheEntryCount = 0;
3744
3885
  diskCacheDirty2 = false;
@@ -3923,7 +4064,7 @@ var init_api_provider = __esm({
3923
4064
  } else {
3924
4065
  embedding = await apiCall();
3925
4066
  }
3926
- cacheSet(hash4, embedding);
4067
+ cacheSet2(hash4, embedding);
3927
4068
  scheduleDiskSave();
3928
4069
  return embedding;
3929
4070
  }
@@ -3971,7 +4112,7 @@ var init_api_provider = __esm({
3971
4112
  for (const item of response.data) {
3972
4113
  const originalIdx = chunkIndices[item.index];
3973
4114
  results[originalIdx] = item.embedding;
3974
- cacheSet(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
4115
+ cacheSet2(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
3975
4116
  }
3976
4117
  } catch (error) {
3977
4118
  const providerLimit = parseBatchLimit(error);
@@ -4049,7 +4190,7 @@ var init_api_provider = __esm({
4049
4190
  throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d; dimension mismatch`);
4050
4191
  }
4051
4192
  this.trackUsage(response);
4052
- cacheSet(hash4, embedding);
4193
+ cacheSet2(hash4, embedding);
4053
4194
  scheduleDiskSave();
4054
4195
  return embedding;
4055
4196
  }
@@ -5432,6 +5573,7 @@ var init_provider2 = __esm({
5432
5573
  openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
5433
5574
  anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
5434
5575
  openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
5576
+ atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
5435
5577
  custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
5436
5578
  };
5437
5579
  currentConfig = null;
@@ -6195,7 +6337,7 @@ var init_obs_store = __esm({
6195
6337
  });
6196
6338
 
6197
6339
  // src/search/semantic-index.ts
6198
- import { createHash as createHash3 } from "crypto";
6340
+ import { createHash as createHash4 } from "crypto";
6199
6341
  import { createRequire as createRequire3 } from "module";
6200
6342
  import path8 from "path";
6201
6343
  function createSemanticIndexProfile(provider2) {
@@ -6209,7 +6351,7 @@ function stateKey(dataDir, profile) {
6209
6351
  return `${path8.resolve(dataDir)}::${profile.key}`;
6210
6352
  }
6211
6353
  function tableName(profile) {
6212
- const digest2 = createHash3("sha256").update(profile.key).digest("hex").slice(0, 20);
6354
+ const digest2 = createHash4("sha256").update(profile.key).digest("hex").slice(0, 20);
6213
6355
  return `${TABLE_PREFIX}${digest2}`;
6214
6356
  }
6215
6357
  function indexRoot(dataDir) {
@@ -7551,6 +7693,7 @@ async function searchObservations(options) {
7551
7693
  };
7552
7694
  let queryVector = null;
7553
7695
  let embeddingProviderForSearch = null;
7696
+ let embeddingUnavailable = false;
7554
7697
  if (quality !== "fast" && embeddingEnabled && hasQuery && tier !== "fast") {
7555
7698
  try {
7556
7699
  const provider2 = await getEmbeddingProvider();
@@ -7558,6 +7701,7 @@ async function searchObservations(options) {
7558
7701
  embeddingProviderForSearch = provider2;
7559
7702
  const activeVectorDimensions = getVectorDimensions();
7560
7703
  if (activeVectorDimensions !== null && provider2.dimensions !== activeVectorDimensions) {
7704
+ embeddingUnavailable = true;
7561
7705
  rememberSearchMode(
7562
7706
  modeKey,
7563
7707
  `fulltext (embedding dimension mismatch: provider ${provider2.dimensions}d vs index ${activeVectorDimensions}d)`
@@ -7597,8 +7741,11 @@ async function searchObservations(options) {
7597
7741
  hybridWeights: isCJKHeavy ? { text: 0.2, vector: 0.8 } : { text: 0.6, vector: 0.4 }
7598
7742
  };
7599
7743
  }
7744
+ } else {
7745
+ embeddingUnavailable = true;
7600
7746
  }
7601
7747
  } catch (error) {
7748
+ embeddingUnavailable = true;
7602
7749
  rememberSearchMode(modeKey, "fulltext (embedding unavailable)");
7603
7750
  console.error("[memorix] Embedding failed or timed out, falling back to fulltext search");
7604
7751
  }
@@ -7606,7 +7753,7 @@ async function searchObservations(options) {
7606
7753
  mark("preSearch");
7607
7754
  let results;
7608
7755
  const persistentCorpusEligible = await shouldUsePersistentSearch(projectIds, options.projectId);
7609
- const canUsePersistentLexical = persistentCorpusEligible && Boolean(hasQuery) && !queryVector && (quality === "fast" || tier === "fast" || !embeddingEnabled);
7756
+ const canUsePersistentLexical = persistentCorpusEligible && Boolean(hasQuery) && !queryVector && (quality === "fast" || tier === "fast" || !embeddingEnabled || embeddingUnavailable);
7610
7757
  let persistent = persistentCorpusEligible && queryVector && embeddingProviderForSearch ? await searchPersistentSemantically(options, projectIds, requestLimit, queryVector, embeddingProviderForSearch) : canUsePersistentLexical ? await searchPersistentLexically(options, projectIds, requestLimit) : null;
7611
7758
  const durableStore = getOptionalObservationStore();
7612
7759
  if (!persistent && queryVector && durableStore?.hasLexicalIndex?.() && count(database) === 0) {
@@ -8249,6 +8396,7 @@ var init_secret_filter = __esm({
8249
8396
  // src/runtime/maintenance-jobs.ts
8250
8397
  var maintenance_jobs_exports = {};
8251
8398
  __export(maintenance_jobs_exports, {
8399
+ DEFAULT_FAILED_HISTORY_RETENTION_MS: () => DEFAULT_FAILED_HISTORY_RETENTION_MS,
8252
8400
  MAINTENANCE_JOB_KINDS: () => MAINTENANCE_JOB_KINDS,
8253
8401
  MaintenanceJobStore: () => MaintenanceJobStore,
8254
8402
  MaintenanceJobWorker: () => MaintenanceJobWorker,
@@ -8298,7 +8446,7 @@ function normalizedKinds(kinds) {
8298
8446
  function getMaintenanceRetryDelayMs(attempts) {
8299
8447
  return Math.min(6e4, 1e3 * 2 ** Math.max(0, attempts - 1));
8300
8448
  }
8301
- var MAINTENANCE_JOB_KINDS, DEFAULT_MAX_ATTEMPTS, DEFAULT_LEASE_MS, DEFAULT_POLL_INTERVAL_MS, MAX_ERROR_LENGTH, DEFAULT_COMPLETED_HISTORY_RETENTION_MS, MaintenanceJobStore, MaintenanceJobWorker;
8449
+ 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;
8302
8450
  var init_maintenance_jobs = __esm({
8303
8451
  "src/runtime/maintenance-jobs.ts"() {
8304
8452
  "use strict";
@@ -8325,6 +8473,7 @@ var init_maintenance_jobs = __esm({
8325
8473
  DEFAULT_POLL_INTERVAL_MS = 2e3;
8326
8474
  MAX_ERROR_LENGTH = 1e3;
8327
8475
  DEFAULT_COMPLETED_HISTORY_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
8476
+ DEFAULT_FAILED_HISTORY_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
8328
8477
  MaintenanceJobStore = class {
8329
8478
  db;
8330
8479
  constructor(dataDir) {
@@ -8451,18 +8600,21 @@ var init_maintenance_jobs = __esm({
8451
8600
  }
8452
8601
  /**
8453
8602
  * Completed jobs are useful recent operator history, not permanent data.
8454
- * Failed jobs stay available for diagnosis until an operator explicitly
8455
- * resolves them or clears the database.
8603
+ * Failed diagnostics are retained longer, but are still bounded so a
8604
+ * permanently failing job kind cannot grow the database forever.
8456
8605
  */
8457
8606
  pruneCompletedHistory(options = {}) {
8458
8607
  const now3 = options.now ?? Date.now();
8459
8608
  const maxAgeMs = Number.isFinite(options.maxAgeMs) ? Math.max(0, Math.floor(options.maxAgeMs)) : DEFAULT_COMPLETED_HISTORY_RETENTION_MS;
8609
+ const failedMaxAgeMs = Number.isFinite(options.failedMaxAgeMs) ? Math.max(0, Math.floor(options.failedMaxAgeMs)) : DEFAULT_FAILED_HISTORY_RETENTION_MS;
8460
8610
  const result = this.db.prepare(`
8461
8611
  DELETE FROM maintenance_jobs
8462
- WHERE status = 'completed'
8612
+ WHERE (status = 'completed'
8463
8613
  AND completed_at IS NOT NULL
8464
- AND completed_at < ?
8465
- `).run(now3 - maxAgeMs);
8614
+ AND completed_at < ?)
8615
+ OR (status = 'failed'
8616
+ AND updated_at < ?)
8617
+ `).run(now3 - maxAgeMs, now3 - failedMaxAgeMs);
8466
8618
  return Number(result.changes ?? 0);
8467
8619
  }
8468
8620
  claimNext(options) {
@@ -8788,7 +8940,7 @@ var init_lifecycle = __esm({
8788
8940
  });
8789
8941
 
8790
8942
  // src/store/evidence-store.ts
8791
- import { createHash as createHash4, randomUUID as randomUUID3 } from "crypto";
8943
+ import { createHash as createHash5, randomUUID as randomUUID3 } from "crypto";
8792
8944
  function safeJson(value, fallback) {
8793
8945
  if (typeof value !== "string" || value.length === 0) return fallback;
8794
8946
  try {
@@ -8822,7 +8974,7 @@ function rowToCard(row) {
8822
8974
  };
8823
8975
  }
8824
8976
  function observationHash(observation) {
8825
- return createHash4("sha256").update(JSON.stringify({
8977
+ return createHash5("sha256").update(JSON.stringify({
8826
8978
  projectId: observation.projectId,
8827
8979
  id: observation.id,
8828
8980
  title: observation.title,
@@ -9252,13 +9404,13 @@ __export(workspace_exports, {
9252
9404
  loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
9253
9405
  resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
9254
9406
  });
9255
- import { createHash as createHash5 } from "crypto";
9407
+ import { createHash as createHash6 } from "crypto";
9256
9408
  import { execFile } from "child_process";
9257
9409
  import { promises as fs6 } from "fs";
9258
9410
  import path10 from "path";
9259
9411
  import { promisify } from "util";
9260
9412
  function hash(value) {
9261
- return createHash5("sha256").update(value).digest("hex");
9413
+ return createHash6("sha256").update(value).digest("hex");
9262
9414
  }
9263
9415
  function workspaceId(projectId, mode) {
9264
9416
  return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
@@ -10393,14 +10545,14 @@ var init_types2 = __esm({
10393
10545
  });
10394
10546
 
10395
10547
  // src/media/asset-store.ts
10396
- import { createHash as createHash6, randomUUID as randomUUID6 } from "crypto";
10548
+ import { createHash as createHash7, randomUUID as randomUUID6 } from "crypto";
10397
10549
  import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
10398
10550
  import path11 from "path";
10399
10551
  function mediaRoot(dataDir) {
10400
10552
  return path11.resolve(dataDir, "media");
10401
10553
  }
10402
10554
  function projectStorageKey(projectId) {
10403
- return createHash6("sha256").update(projectId).digest("hex").slice(0, 16);
10555
+ return createHash7("sha256").update(projectId).digest("hex").slice(0, 16);
10404
10556
  }
10405
10557
  function validateUnderRoot(root, candidate) {
10406
10558
  const resolved = path11.resolve(candidate);
@@ -10509,7 +10661,7 @@ async function importMediaBuffer(input) {
10509
10661
  if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
10510
10662
  if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
10511
10663
  const detected = detectMedia(input.bytes.subarray(0, 32));
10512
- const sha256 = createHash6("sha256").update(input.bytes).digest("hex");
10664
+ const sha256 = createHash7("sha256").update(input.bytes).digest("hex");
10513
10665
  return importKnownMedia({
10514
10666
  dataDir: input.dataDir,
10515
10667
  projectId: input.projectId,
@@ -10527,7 +10679,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
10527
10679
  if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
10528
10680
  const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
10529
10681
  if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
10530
- const sha256 = createHash6("sha256").update(bytes).digest("hex");
10682
+ const sha256 = createHash7("sha256").update(bytes).digest("hex");
10531
10683
  if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
10532
10684
  return bytes;
10533
10685
  }
@@ -69223,16 +69375,16 @@ var require_jwtaccess = __commonJS({
69223
69375
  * @returns A string that returns the cached key.
69224
69376
  */
69225
69377
  getCachedKey(url, scopes) {
69226
- let cacheKey = url;
69378
+ let cacheKey3 = url;
69227
69379
  if (scopes && Array.isArray(scopes) && scopes.length) {
69228
- cacheKey = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
69380
+ cacheKey3 = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
69229
69381
  } else if (typeof scopes === "string") {
69230
- cacheKey = url ? `${url}_${scopes}` : scopes;
69382
+ cacheKey3 = url ? `${url}_${scopes}` : scopes;
69231
69383
  }
69232
- if (!cacheKey) {
69384
+ if (!cacheKey3) {
69233
69385
  throw Error("Scopes or url must be provided");
69234
69386
  }
69235
- return cacheKey;
69387
+ return cacheKey3;
69236
69388
  }
69237
69389
  /**
69238
69390
  * Get a non-expired access token, after refreshing if necessary.
@@ -75778,7 +75930,7 @@ var require_websocket = __commonJS({
75778
75930
  var http3 = __require("http");
75779
75931
  var net = __require("net");
75780
75932
  var tls = __require("tls");
75781
- var { randomBytes, createHash: createHash16 } = __require("crypto");
75933
+ var { randomBytes, createHash: createHash17 } = __require("crypto");
75782
75934
  var { Duplex, Readable: Readable2 } = __require("stream");
75783
75935
  var { URL: URL2 } = __require("url");
75784
75936
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -76446,7 +76598,7 @@ var require_websocket = __commonJS({
76446
76598
  abortHandshake(websocket, socket, "Invalid Upgrade header");
76447
76599
  return;
76448
76600
  }
76449
- const digest2 = createHash16("sha1").update(key + GUID).digest("base64");
76601
+ const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
76450
76602
  if (res.headers["sec-websocket-accept"] !== digest2) {
76451
76603
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
76452
76604
  return;
@@ -76818,7 +76970,7 @@ var require_websocket_server = __commonJS({
76818
76970
  var EventEmitter = __require("events");
76819
76971
  var http3 = __require("http");
76820
76972
  var { Duplex } = __require("stream");
76821
- var { createHash: createHash16 } = __require("crypto");
76973
+ var { createHash: createHash17 } = __require("crypto");
76822
76974
  var extension3 = require_extension();
76823
76975
  var PerMessageDeflate2 = require_permessage_deflate();
76824
76976
  var subprotocol2 = require_subprotocol();
@@ -77125,7 +77277,7 @@ var require_websocket_server = __commonJS({
77125
77277
  );
77126
77278
  }
77127
77279
  if (this._state > RUNNING) return abortHandshake(socket, 503);
77128
- const digest2 = createHash16("sha1").update(key + GUID).digest("base64");
77280
+ const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
77129
77281
  const headers = [
77130
77282
  "HTTP/1.1 101 Switching Protocols",
77131
77283
  "Upgrade: websocket",
@@ -145704,9 +145856,9 @@ var init_long_term = __esm({
145704
145856
  });
145705
145857
 
145706
145858
  // src/codegraph/ids.ts
145707
- import { createHash as createHash7 } from "crypto";
145859
+ import { createHash as createHash8 } from "crypto";
145708
145860
  function digest(input) {
145709
- return createHash7("sha256").update(input).digest("hex").slice(0, 16);
145861
+ return createHash8("sha256").update(input).digest("hex").slice(0, 16);
145710
145862
  }
145711
145863
  function normalizeCodePath(path23) {
145712
145864
  return path23.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
@@ -146754,7 +146906,7 @@ var init_store = __esm({
146754
146906
 
146755
146907
  // src/codegraph/code-state.ts
146756
146908
  import { execFile as execFile2 } from "child_process";
146757
- import { createHash as createHash8 } from "crypto";
146909
+ import { createHash as createHash9 } from "crypto";
146758
146910
  import { promisify as promisify3 } from "util";
146759
146911
  async function runGit(rootPath, args) {
146760
146912
  try {
@@ -146783,7 +146935,7 @@ function changedPathCount(status) {
146783
146935
  return count2;
146784
146936
  }
146785
146937
  function fingerprint(baseRevision, status) {
146786
- return createHash8("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
146938
+ return createHash9("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
146787
146939
  }
146788
146940
  async function collectCodeStateSnapshot(input) {
146789
146941
  const [revision, status] = await Promise.all([
@@ -146877,12 +147029,12 @@ var init_exclude3 = __esm({
146877
147029
  });
146878
147030
 
146879
147031
  // src/codegraph/semantic-provider.ts
146880
- import { createHash as createHash9 } from "crypto";
147032
+ import { createHash as createHash10 } from "crypto";
146881
147033
  import "fs";
146882
147034
  import { resolve } from "path";
146883
147035
  import ts from "typescript";
146884
147036
  function hashText(value) {
146885
- return createHash9("sha256").update(value).digest("hex");
147037
+ return createHash10("sha256").update(value).digest("hex");
146886
147038
  }
146887
147039
  function canonicalPath(value) {
146888
147040
  const normalized = resolve(value).replace(/\\/g, "/");
@@ -147227,11 +147379,11 @@ __export(lite_provider_exports, {
147227
147379
  indexProjectLite: () => indexProjectLite,
147228
147380
  refreshProjectLite: () => refreshProjectLite
147229
147381
  });
147230
- import { createHash as createHash10 } from "crypto";
147382
+ import { createHash as createHash11 } from "crypto";
147231
147383
  import { existsSync as existsSync11, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
147232
147384
  import { join as join4, relative as relative2 } from "path";
147233
147385
  function hashText2(text2) {
147234
- return createHash10("sha256").update(text2).digest("hex");
147386
+ return createHash11("sha256").update(text2).digest("hex");
147235
147387
  }
147236
147388
  function extension2(path23) {
147237
147389
  const index = path23.lastIndexOf(".");
@@ -147864,7 +148016,7 @@ var claim_store_exports = {};
147864
148016
  __export(claim_store_exports, {
147865
148017
  ClaimStore: () => ClaimStore
147866
148018
  });
147867
- import { createHash as createHash11, randomUUID as randomUUID12 } from "crypto";
148019
+ import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
147868
148020
  function optionalText3(value) {
147869
148021
  return typeof value === "string" && value ? value : void 0;
147870
148022
  }
@@ -147917,7 +148069,7 @@ function rowToEvent3(row) {
147917
148069
  };
147918
148070
  }
147919
148071
  function evidenceKey(input) {
147920
- return createHash11("sha256").update(JSON.stringify([
148072
+ return createHash12("sha256").update(JSON.stringify([
147921
148073
  input.evidenceKind,
147922
148074
  input.evidenceId,
147923
148075
  input.relation,
@@ -148115,7 +148267,7 @@ __export(claims_exports, {
148115
148267
  supersedeClaim: () => supersedeClaim,
148116
148268
  writeClaim: () => writeClaim
148117
148269
  });
148118
- import { createHash as createHash12, randomUUID as randomUUID13 } from "crypto";
148270
+ import { createHash as createHash13, randomUUID as randomUUID13 } from "crypto";
148119
148271
  function compactText2(value, field) {
148120
148272
  if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
148121
148273
  const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
@@ -148127,7 +148279,7 @@ function normalizedTerm(value) {
148127
148279
  return compactText2(value, "identity").toLocaleLowerCase("en-US");
148128
148280
  }
148129
148281
  function hashIdentity(parts) {
148130
- return createHash12("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
148282
+ return createHash13("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
148131
148283
  }
148132
148284
  function buildClaimIdentity(input) {
148133
148285
  const subject = normalizedTerm(input.subject);
@@ -148368,7 +148520,7 @@ function supersedeClaim(store, input) {
148368
148520
  });
148369
148521
  }
148370
148522
  function hashObservation(observation) {
148371
- return createHash12("sha256").update(JSON.stringify([
148523
+ return createHash13("sha256").update(JSON.stringify([
148372
148524
  observation.title,
148373
148525
  observation.narrative,
148374
148526
  observation.facts,
@@ -148612,11 +148764,11 @@ var init_frontmatter = __esm({
148612
148764
  });
148613
148765
 
148614
148766
  // src/knowledge/markdown.ts
148615
- import { createHash as createHash13 } from "crypto";
148767
+ import { createHash as createHash14 } from "crypto";
148616
148768
  import { promises as fs10 } from "fs";
148617
148769
  import path18 from "path";
148618
148770
  function hashContent(content) {
148619
- return createHash13("sha256").update(content).digest("hex");
148771
+ return createHash14("sha256").update(content).digest("hex");
148620
148772
  }
148621
148773
  function stringField(data, key) {
148622
148774
  const value = data[key];
@@ -148742,11 +148894,11 @@ __export(wiki_exports, {
148742
148894
  lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
148743
148895
  readKnowledgePage: () => readKnowledgePage
148744
148896
  });
148745
- import { createHash as createHash14 } from "crypto";
148897
+ import { createHash as createHash15 } from "crypto";
148746
148898
  import { promises as fs11 } from "fs";
148747
148899
  import path19 from "path";
148748
148900
  function hash2(value) {
148749
- return createHash14("sha256").update(value).digest("hex");
148901
+ return createHash15("sha256").update(value).digest("hex");
148750
148902
  }
148751
148903
  function now() {
148752
148904
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -149603,11 +149755,11 @@ __export(workflows_exports, {
149603
149755
  syncCanonicalWorkflows: () => syncCanonicalWorkflows,
149604
149756
  writeCanonicalWorkflow: () => writeCanonicalWorkflow
149605
149757
  });
149606
- import { createHash as createHash15 } from "crypto";
149758
+ import { createHash as createHash16 } from "crypto";
149607
149759
  import { promises as fs12 } from "fs";
149608
149760
  import path20 from "path";
149609
149761
  function hash3(value) {
149610
- return createHash15("sha256").update(value).digest("hex");
149762
+ return createHash16("sha256").update(value).digest("hex");
149611
149763
  }
149612
149764
  function now2() {
149613
149765
  return (/* @__PURE__ */ new Date()).toISOString();