memorix 1.9.4 → 1.9.6

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 (90) hide show
  1. package/CHANGELOG.md +75 -1
  2. package/README.md +12 -6
  3. package/README.zh-CN.md +12 -6
  4. package/dist/cli/index.js +2533 -585
  5. package/dist/index.d.ts +15 -8
  6. package/dist/index.js +1201 -284
  7. package/dist/maintenance-runner.js +387 -216
  8. package/dist/media-audio-runner.js +300 -129
  9. package/dist/media-video-runner.js +300 -129
  10. package/dist/memcode-runtime/CHANGELOG.md +75 -1
  11. package/dist/sdk.d.ts +1 -0
  12. package/dist/sdk.js +1882 -998
  13. package/dist/types.d.ts +1 -1
  14. package/dist/vector-backfill-runner.js +300 -129
  15. package/docs/AGENT_OPERATOR_PLAYBOOK.md +47 -3
  16. package/docs/API_REFERENCE.md +39 -1
  17. package/docs/CONFIGURATION.md +58 -1
  18. package/docs/DEVELOPMENT.md +1 -1
  19. package/docs/DOCKER.md +23 -3
  20. package/docs/INTEGRATIONS.md +1 -1
  21. package/docs/KNOWN_ISSUES_AND_ROADMAP.md +61 -1
  22. package/docs/MULTI-DEVICE-SYNC-RESEARCH.md +4 -0
  23. package/docs/PERFORMANCE.md +46 -2
  24. package/docs/README.md +2 -1
  25. package/docs/SETUP.md +56 -1
  26. package/package.json +3 -2
  27. package/plugins/antigravity/memorix/plugin.json +1 -1
  28. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  29. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  30. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  31. package/plugins/copilot/memorix/plugin.json +1 -1
  32. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  33. package/plugins/hermes/memorix/plugin.yaml +1 -1
  34. package/plugins/omp/memorix/package.json +1 -1
  35. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  36. package/plugins/pi/memorix/package.json +1 -1
  37. package/server.json +2 -2
  38. package/src/cli/capability-map.ts +1 -0
  39. package/src/cli/command-guide.ts +15 -3
  40. package/src/cli/commands/agent-integrations.ts +57 -0
  41. package/src/cli/commands/background.ts +11 -2
  42. package/src/cli/commands/context.ts +2 -0
  43. package/src/cli/commands/continuity.ts +155 -0
  44. package/src/cli/commands/init.ts +5 -2
  45. package/src/cli/commands/serve-http.ts +435 -84
  46. package/src/cli/commands/setup.ts +77 -10
  47. package/src/cli/commands/sync-store.ts +47 -12
  48. package/src/cli/commands/sync.ts +26 -0
  49. package/src/cli/index.ts +3 -1
  50. package/src/cli/tui/ConfigureView.tsx +2 -0
  51. package/src/codegraph/auto-context.ts +17 -0
  52. package/src/config/legacy-loader.ts +2 -2
  53. package/src/config/resolved-config.ts +8 -5
  54. package/src/config/yaml-loader.ts +20 -10
  55. package/src/dashboard/server.ts +10 -12
  56. package/src/embedding/api-provider.ts +4 -2
  57. package/src/embedding/fastembed-provider.ts +47 -14
  58. package/src/embedding/transformers-provider.ts +29 -7
  59. package/src/evaluation/memory-quality-gate.ts +90 -0
  60. package/src/hooks/official-skills.ts +2 -0
  61. package/src/integrations/registry.ts +1 -1
  62. package/src/knowledge/context-assembly.ts +1 -0
  63. package/src/knowledge/context-receipt.ts +15 -0
  64. package/src/knowledge/task-continuity.ts +413 -0
  65. package/src/knowledge/workset.ts +77 -0
  66. package/src/llm/provider.ts +2 -1
  67. package/src/memory/graph.ts +10 -8
  68. package/src/memory/session.ts +1 -1
  69. package/src/orchestrate/coordinator.ts +60 -0
  70. package/src/orchestrate/effect-ledger.ts +160 -0
  71. package/src/orchestrate/pipeline-trace.ts +40 -6
  72. package/src/runtime/maintenance-jobs.ts +12 -6
  73. package/src/sdk.ts +24 -0
  74. package/src/server/mcp-binding-store.ts +14 -3
  75. package/src/server/modern-mcp-bridge.ts +153 -27
  76. package/src/server/tool-profile.ts +3 -2
  77. package/src/server.ts +131 -7
  78. package/src/store/file-lock.ts +28 -3
  79. package/src/store/graph-store.ts +178 -46
  80. package/src/store/persistence.ts +14 -9
  81. package/src/store/sqlite-db.ts +150 -7
  82. package/src/store/sqlite-store.ts +32 -27
  83. package/src/sync/engine.ts +9 -7
  84. package/src/sync/namespace.ts +23 -0
  85. package/src/sync/policy.ts +19 -4
  86. package/src/sync/store-port.ts +43 -13
  87. package/src/sync/types.ts +2 -0
  88. package/src/team/team-store.ts +62 -27
  89. package/src/types.ts +1 -1
  90. package/src/workspace/mcp-adapters/grok.ts +32 -0
@@ -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) {
@@ -542,11 +547,21 @@ function applySchemaMigrations(db2) {
542
547
  apply();
543
548
  }
544
549
  }
550
+ function normalizeDataDir(dataDir) {
551
+ return path3.resolve(dataDir);
552
+ }
553
+ function touchDatabase(normalized, db2) {
554
+ _dbCache.delete(normalized);
555
+ _dbCache.set(normalized, db2);
556
+ }
545
557
  function getDatabase(dataDir) {
546
- const normalized = path3.resolve(dataDir);
558
+ const normalized = normalizeDataDir(dataDir);
547
559
  assertNotHomeDataDir(normalized);
548
560
  const existing = _dbCache.get(normalized);
549
- if (existing) return existing;
561
+ if (existing) {
562
+ touchDatabase(normalized, existing);
563
+ return existing;
564
+ }
550
565
  loadBetterSqlite3();
551
566
  fs.mkdirSync(dataDir, { recursive: true });
552
567
  const dbPath = path3.join(dataDir, "memorix.db");
@@ -576,6 +591,8 @@ function getDatabase(dataDir) {
576
591
  db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
577
592
  db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
578
593
  db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
594
+ db2.exec(CREATE_TASK_CONTINUITY_EVENTS_TABLE);
595
+ db2.exec(CREATE_AGENT_EFFECTS_TABLE);
579
596
  try {
580
597
  db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
581
598
  } catch {
@@ -614,7 +631,7 @@ function getDatabase(dataDir) {
614
631
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
615
632
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
616
633
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
617
- _dbCache.set(normalized, db2);
634
+ touchDatabase(normalized, db2);
618
635
  return db2;
619
636
  } catch (error) {
620
637
  try {
@@ -632,8 +649,9 @@ function closeAllDatabases() {
632
649
  }
633
650
  _dbCache.delete(key);
634
651
  }
652
+ _dbLeases.clear();
635
653
  }
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;
654
+ 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
655
  var init_sqlite_db = __esm({
638
656
  "src/store/sqlite-db.ts"() {
639
657
  "use strict";
@@ -805,18 +823,21 @@ CREATE TABLE IF NOT EXISTS chat_transcript (
805
823
  `;
806
824
  CREATE_GRAPH_ENTITIES_TABLE = `
807
825
  CREATE TABLE IF NOT EXISTS graph_entities (
808
- name TEXT PRIMARY KEY,
826
+ projectId TEXT NOT NULL,
827
+ name TEXT NOT NULL,
809
828
  entityType TEXT NOT NULL DEFAULT '',
810
- observations TEXT NOT NULL DEFAULT '[]'
829
+ observations TEXT NOT NULL DEFAULT '[]',
830
+ PRIMARY KEY (projectId, name)
811
831
  );
812
832
  `;
813
833
  CREATE_GRAPH_RELATIONS_TABLE = `
814
834
  CREATE TABLE IF NOT EXISTS graph_relations (
815
835
  id INTEGER PRIMARY KEY AUTOINCREMENT,
836
+ projectId TEXT NOT NULL,
816
837
  from_entity TEXT NOT NULL,
817
838
  to_entity TEXT NOT NULL,
818
839
  relationType TEXT NOT NULL DEFAULT '',
819
- UNIQUE(from_entity, to_entity, relationType)
840
+ UNIQUE(projectId, from_entity, to_entity, relationType)
820
841
  );
821
842
  `;
822
843
  CREATE_CODE_FILES_TABLE = `
@@ -1347,6 +1368,43 @@ CREATE TABLE IF NOT EXISTS memory_feedback_events (
1347
1368
  delta REAL NOT NULL DEFAULT 0,
1348
1369
  observed_at TEXT NOT NULL
1349
1370
  );
1371
+ `;
1372
+ CREATE_TASK_CONTINUITY_EVENTS_TABLE = `
1373
+ CREATE TABLE IF NOT EXISTS task_continuity_events (
1374
+ id TEXT PRIMARY KEY,
1375
+ project_id TEXT NOT NULL,
1376
+ task_id TEXT NOT NULL,
1377
+ task TEXT NOT NULL,
1378
+ kind TEXT NOT NULL,
1379
+ content TEXT NOT NULL,
1380
+ item_status TEXT,
1381
+ source_ref TEXT,
1382
+ evidence_json TEXT NOT NULL DEFAULT '[]',
1383
+ actor TEXT,
1384
+ created_at TEXT NOT NULL,
1385
+ event_key TEXT,
1386
+ item_key TEXT,
1387
+ supersedes_id TEXT
1388
+ );
1389
+ `;
1390
+ CREATE_AGENT_EFFECTS_TABLE = `
1391
+ CREATE TABLE IF NOT EXISTS agent_effects (
1392
+ id TEXT PRIMARY KEY,
1393
+ pipeline_id TEXT NOT NULL,
1394
+ task_id TEXT NOT NULL,
1395
+ attempt INTEGER NOT NULL,
1396
+ effect_key TEXT NOT NULL,
1397
+ tool TEXT NOT NULL,
1398
+ risk_tier TEXT NOT NULL,
1399
+ replay_policy TEXT NOT NULL,
1400
+ status TEXT NOT NULL,
1401
+ call_id TEXT,
1402
+ idempotency_key TEXT NOT NULL,
1403
+ input_fingerprint TEXT,
1404
+ detail TEXT,
1405
+ started_at INTEGER NOT NULL,
1406
+ finished_at INTEGER
1407
+ );
1350
1408
  `;
1351
1409
  CREATE_MCP_BINDINGS_TABLE = `
1352
1410
  CREATE TABLE IF NOT EXISTS mcp_bindings (
@@ -1425,7 +1483,18 @@ CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(projec
1425
1483
  CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
1426
1484
  CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
1427
1485
  CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
1486
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_project_task ON task_continuity_events(project_id, task_id, created_at ASC);
1487
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_project_recent ON task_continuity_events(project_id, created_at DESC);
1488
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_item ON task_continuity_events(project_id, task_id, kind, item_key, created_at DESC);
1489
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
1490
+ ON task_continuity_events(project_id, task_id, event_key)
1491
+ WHERE event_key IS NOT NULL;
1492
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_effect_identity
1493
+ ON agent_effects(pipeline_id, task_id, attempt, effect_key);
1494
+ CREATE INDEX IF NOT EXISTS idx_agent_effect_pipeline ON agent_effects(pipeline_id, started_at ASC);
1428
1495
  CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
1496
+ CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC);
1497
+ CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at);
1429
1498
  CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1430
1499
  ON maintenance_jobs(project_id, kind, dedupe_key)
1431
1500
  WHERE status IN ('pending', 'running', 'retry');
@@ -1596,6 +1665,8 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1596
1665
  db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
1597
1666
  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)");
1598
1667
  db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
1668
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC)");
1669
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at)");
1599
1670
  }
1600
1671
  },
1601
1672
  {
@@ -1606,9 +1677,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1606
1677
  addColumnIfMissing(db2, "code_symbols", "source", "source TEXT");
1607
1678
  addColumnIfMissing(db2, "code_edges", "source", "source TEXT");
1608
1679
  }
1680
+ },
1681
+ {
1682
+ id: "1.9-continuity-v2",
1683
+ apply: (db2) => {
1684
+ addColumnIfMissing(db2, "task_continuity_events", "event_key", "event_key TEXT");
1685
+ addColumnIfMissing(db2, "task_continuity_events", "item_key", "item_key TEXT");
1686
+ addColumnIfMissing(db2, "task_continuity_events", "supersedes_id", "supersedes_id TEXT");
1687
+ 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)");
1688
+ db2.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
1689
+ ON task_continuity_events(project_id, task_id, event_key)
1690
+ WHERE event_key IS NOT NULL`);
1691
+ }
1609
1692
  }
1610
1693
  ];
1611
1694
  _dbCache = /* @__PURE__ */ new Map();
1695
+ _dbLeases = /* @__PURE__ */ new Map();
1612
1696
  }
1613
1697
  });
1614
1698
 
@@ -2124,6 +2208,7 @@ var init_media_store = __esm({
2124
2208
  // src/runtime/maintenance-jobs.ts
2125
2209
  var maintenance_jobs_exports = {};
2126
2210
  __export(maintenance_jobs_exports, {
2211
+ DEFAULT_FAILED_HISTORY_RETENTION_MS: () => DEFAULT_FAILED_HISTORY_RETENTION_MS,
2127
2212
  MAINTENANCE_JOB_KINDS: () => MAINTENANCE_JOB_KINDS,
2128
2213
  MaintenanceJobStore: () => MaintenanceJobStore,
2129
2214
  MaintenanceJobWorker: () => MaintenanceJobWorker,
@@ -2173,7 +2258,7 @@ function normalizedKinds(kinds) {
2173
2258
  function getMaintenanceRetryDelayMs(attempts) {
2174
2259
  return Math.min(6e4, 1e3 * 2 ** Math.max(0, attempts - 1));
2175
2260
  }
2176
- var MAINTENANCE_JOB_KINDS, DEFAULT_MAX_ATTEMPTS, DEFAULT_LEASE_MS, DEFAULT_POLL_INTERVAL_MS, MAX_ERROR_LENGTH, DEFAULT_COMPLETED_HISTORY_RETENTION_MS, MaintenanceJobStore, MaintenanceJobWorker;
2261
+ 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;
2177
2262
  var init_maintenance_jobs = __esm({
2178
2263
  "src/runtime/maintenance-jobs.ts"() {
2179
2264
  "use strict";
@@ -2200,6 +2285,7 @@ var init_maintenance_jobs = __esm({
2200
2285
  DEFAULT_POLL_INTERVAL_MS = 2e3;
2201
2286
  MAX_ERROR_LENGTH = 1e3;
2202
2287
  DEFAULT_COMPLETED_HISTORY_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
2288
+ DEFAULT_FAILED_HISTORY_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
2203
2289
  MaintenanceJobStore = class {
2204
2290
  db;
2205
2291
  constructor(dataDir) {
@@ -2326,18 +2412,21 @@ var init_maintenance_jobs = __esm({
2326
2412
  }
2327
2413
  /**
2328
2414
  * Completed jobs are useful recent operator history, not permanent data.
2329
- * Failed jobs stay available for diagnosis until an operator explicitly
2330
- * resolves them or clears the database.
2415
+ * Failed diagnostics are retained longer, but are still bounded so a
2416
+ * permanently failing job kind cannot grow the database forever.
2331
2417
  */
2332
2418
  pruneCompletedHistory(options = {}) {
2333
2419
  const now3 = options.now ?? Date.now();
2334
2420
  const maxAgeMs = Number.isFinite(options.maxAgeMs) ? Math.max(0, Math.floor(options.maxAgeMs)) : DEFAULT_COMPLETED_HISTORY_RETENTION_MS;
2421
+ const failedMaxAgeMs = Number.isFinite(options.failedMaxAgeMs) ? Math.max(0, Math.floor(options.failedMaxAgeMs)) : DEFAULT_FAILED_HISTORY_RETENTION_MS;
2335
2422
  const result = this.db.prepare(`
2336
2423
  DELETE FROM maintenance_jobs
2337
- WHERE status = 'completed'
2424
+ WHERE (status = 'completed'
2338
2425
  AND completed_at IS NOT NULL
2339
- AND completed_at < ?
2340
- `).run(now3 - maxAgeMs);
2426
+ AND completed_at < ?)
2427
+ OR (status = 'failed'
2428
+ AND updated_at < ?)
2429
+ `).run(now3 - maxAgeMs, now3 - failedMaxAgeMs);
2341
2430
  return Number(result.changes ?? 0);
2342
2431
  }
2343
2432
  claimNext(options) {
@@ -2697,6 +2786,21 @@ var init_sqlite_reliability = __esm({
2697
2786
  import { promises as fs2 } from "fs";
2698
2787
  import { randomUUID as randomUUID3 } from "crypto";
2699
2788
  import path4 from "path";
2789
+ function canReclaimStaleLock(raw) {
2790
+ try {
2791
+ const parsed = JSON.parse(raw);
2792
+ const pid = Number(parsed.pid);
2793
+ if (!Number.isSafeInteger(pid) || pid < 1) return true;
2794
+ try {
2795
+ process.kill(pid, 0);
2796
+ return false;
2797
+ } catch (error) {
2798
+ return error.code !== "EPERM";
2799
+ }
2800
+ } catch {
2801
+ return true;
2802
+ }
2803
+ }
2700
2804
  async function acquireLock(lockPath) {
2701
2805
  for (let i2 = 0; i2 < MAX_RETRIES; i2++) {
2702
2806
  try {
@@ -2710,9 +2814,12 @@ async function acquireLock(lockPath) {
2710
2814
  try {
2711
2815
  const stat5 = await fs2.stat(lockPath);
2712
2816
  if (Date.now() - stat5.mtimeMs > LOCK_STALE_MS) {
2713
- await fs2.unlink(lockPath).catch(() => {
2714
- });
2715
- continue;
2817
+ const raw2 = await fs2.readFile(lockPath, "utf8").catch(() => "");
2818
+ if (canReclaimStaleLock(raw2)) {
2819
+ await fs2.unlink(lockPath).catch(() => {
2820
+ });
2821
+ continue;
2822
+ }
2716
2823
  }
2717
2824
  } catch {
2718
2825
  continue;
@@ -2723,6 +2830,10 @@ async function acquireLock(lockPath) {
2723
2830
  }
2724
2831
  }
2725
2832
  }
2833
+ const raw = await fs2.readFile(lockPath, "utf8").catch(() => "");
2834
+ if (!canReclaimStaleLock(raw)) {
2835
+ throw new Error(`Failed to acquire lock: ${lockPath} (owner is still running)`);
2836
+ }
2726
2837
  await fs2.unlink(lockPath).catch(() => {
2727
2838
  });
2728
2839
  try {
@@ -3089,9 +3200,9 @@ var init_detector = __esm({
3089
3200
  // src/config/legacy-loader.ts
3090
3201
  import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
3091
3202
  import { homedir as homedir3 } from "os";
3092
- function loadFileConfig() {
3203
+ function loadFileConfig(homeDir = homedir3()) {
3093
3204
  if (cachedConfig !== null) return cachedConfig;
3094
- const configPath = getLegacyConfigJsonPath(homedir3());
3205
+ const configPath = getLegacyConfigJsonPath(homeDir);
3095
3206
  try {
3096
3207
  if (existsSync5(configPath)) {
3097
3208
  cachedConfig = JSON.parse(readFileSync5(configPath, "utf-8"));
@@ -3121,15 +3232,15 @@ import { homedir as homedir4 } from "os";
3121
3232
  function loadTomlConfig(options = {}) {
3122
3233
  const homeDir = options.homeDir ?? homedir4();
3123
3234
  const projectRoot = options.projectRoot ?? null;
3124
- const cacheKey = `${homeDir}\0${projectRoot ?? ""}`;
3125
- const cached = configCache2.get(cacheKey);
3235
+ const cacheKey3 = `${homeDir}\0${projectRoot ?? ""}`;
3236
+ const cached = configCache2.get(cacheKey3);
3126
3237
  if (cached) return cached;
3127
3238
  const userToml = getGlobalConfigTomlPath(homeDir);
3128
3239
  const projectToml = projectRoot ? getProjectConfigTomlPath(projectRoot) : null;
3129
3240
  const userConfig = existsSync6(userToml) ? parseTomlConfig(readFileSync6(userToml, "utf8"), userToml) : {};
3130
3241
  const projectConfig = projectToml && existsSync6(projectToml) ? parseTomlConfig(readFileSync6(projectToml, "utf8"), projectToml) : {};
3131
3242
  const merged = mergeTomlConfig(userConfig, projectConfig);
3132
- configCache2.set(cacheKey, merged);
3243
+ configCache2.set(cacheKey3, merged);
3133
3244
  return merged;
3134
3245
  }
3135
3246
  function mergeTomlConfig(base, override) {
@@ -3250,8 +3361,8 @@ function getResolvedConfig(options = {}) {
3250
3361
  const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
3251
3362
  loadDotenv(projectRoot === null ? void 0 : projectRoot ?? void 0, { userHomeDir: homeDir });
3252
3363
  const toml = loadTomlConfig({ projectRoot: projectRoot ?? null, homeDir });
3253
- const yaml = loadYamlConfig(projectRoot ?? null);
3254
- const legacy = loadFileConfig();
3364
+ const yaml = loadYamlConfig(projectRoot ?? null, { homeDir });
3365
+ const legacy = loadFileConfig(homeDir);
3255
3366
  const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
3256
3367
  const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
3257
3368
  const memoryLlmProvider = first(
@@ -3273,15 +3384,17 @@ function getResolvedConfig(options = {}) {
3273
3384
  legacy.llm?.baseUrl
3274
3385
  );
3275
3386
  const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
3387
+ const isAtlasCloud = memoryLlmProvider === "atlascloud";
3276
3388
  const memoryLlmApiKey = first(
3277
3389
  process.env.MEMORIX_LLM_API_KEY,
3278
3390
  process.env.MEMORIX_API_KEY,
3279
3391
  toml.memory?.llm?.api_key,
3280
3392
  yaml.llm?.apiKey,
3281
3393
  legacy.llm?.apiKey,
3282
- process.env.OPENAI_API_KEY,
3283
- process.env.ANTHROPIC_API_KEY,
3284
- openRouterMemoryLlmApiKey
3394
+ // Never borrow another provider's credentials for the Atlas Cloud preset.
3395
+ isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
3396
+ isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
3397
+ isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
3285
3398
  );
3286
3399
  const resolved = {
3287
3400
  agent: {
@@ -3460,7 +3573,8 @@ function getEnvSourceNames() {
3460
3573
  "MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
3461
3574
  "MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
3462
3575
  "MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
3463
- "OPENROUTER_API_KEY"
3576
+ "OPENROUTER_API_KEY",
3577
+ "ATLASCLOUD_API_KEY"
3464
3578
  ].filter((name) => process.env[name]);
3465
3579
  }
3466
3580
  function isOpenRouterUrl(value) {
@@ -3679,12 +3793,45 @@ function textHash(text2) {
3679
3793
  async function loadDiskCache() {
3680
3794
  try {
3681
3795
  const raw = await readFile(CACHE_FILE, "utf-8");
3796
+ if (Buffer.byteLength(raw, "utf8") > MAX_CACHE_FILE_BYTES) {
3797
+ console.error("[memorix] FastEmbed cache exceeds the disk load limit; starting with an empty cache");
3798
+ return;
3799
+ }
3682
3800
  const entries = JSON.parse(raw);
3683
- for (const [k, v] of entries) cache.set(k, v);
3684
- console.error(`[memorix] Loaded ${entries.length} cached embeddings from disk`);
3801
+ if (!Array.isArray(entries)) return;
3802
+ for (const entry of entries) {
3803
+ if (!Array.isArray(entry) || typeof entry[0] !== "string" || !isVector(entry[1])) continue;
3804
+ cacheSet(entry[0], entry[1], false);
3805
+ }
3806
+ console.error(`[memorix] Loaded ${cache.size} cached embeddings from disk`);
3685
3807
  } catch {
3686
3808
  }
3687
3809
  }
3810
+ function isVector(value) {
3811
+ return Array.isArray(value) && value.every((entry) => typeof entry === "number");
3812
+ }
3813
+ function maxCachePayloadBytes() {
3814
+ const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
3815
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES;
3816
+ }
3817
+ function cacheSet(hash4, value, markDirty = true) {
3818
+ const incomingBytes = value.length * 8;
3819
+ if (incomingBytes > maxCachePayloadBytes()) return;
3820
+ const existing = cache.get(hash4);
3821
+ if (existing) cachePayloadBytes -= existing.length * 8;
3822
+ else {
3823
+ while (cache.size >= MAX_CACHE_SIZE || cachePayloadBytes + incomingBytes > maxCachePayloadBytes()) {
3824
+ const firstKey = cache.keys().next().value;
3825
+ if (firstKey === void 0) break;
3826
+ const old = cache.get(firstKey);
3827
+ cache.delete(firstKey);
3828
+ if (old) cachePayloadBytes -= old.length * 8;
3829
+ }
3830
+ }
3831
+ cache.set(hash4, value);
3832
+ cachePayloadBytes += incomingBytes;
3833
+ if (markDirty) diskCacheDirty = true;
3834
+ }
3688
3835
  async function saveDiskCache() {
3689
3836
  if (!diskCacheDirty) return;
3690
3837
  try {
@@ -3695,7 +3842,7 @@ async function saveDiskCache() {
3695
3842
  } catch {
3696
3843
  }
3697
3844
  }
3698
- var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, diskCacheDirty, FastEmbedProvider;
3845
+ var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, DEFAULT_CACHE_PAYLOAD_BYTES, MAX_CACHE_FILE_BYTES, cachePayloadBytes, diskCacheDirty, FastEmbedProvider;
3699
3846
  var init_fastembed_provider = __esm({
3700
3847
  "src/embedding/fastembed-provider.ts"() {
3701
3848
  "use strict";
@@ -3705,6 +3852,9 @@ var init_fastembed_provider = __esm({
3705
3852
  CACHE_FILE = join2(CACHE_DIR, ".embedding-cache.json");
3706
3853
  cache = /* @__PURE__ */ new Map();
3707
3854
  MAX_CACHE_SIZE = 5e3;
3855
+ DEFAULT_CACHE_PAYLOAD_BYTES = 64 * 1024 * 1024;
3856
+ MAX_CACHE_FILE_BYTES = 128 * 1024 * 1024;
3857
+ cachePayloadBytes = 0;
3708
3858
  diskCacheDirty = false;
3709
3859
  FastEmbedProvider = class _FastEmbedProvider {
3710
3860
  name = "fastembed-bge-small";
@@ -3746,7 +3896,7 @@ var init_fastembed_provider = __esm({
3746
3896
  if (result.length !== this.dimensions) {
3747
3897
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
3748
3898
  }
3749
- this.cacheSet(hash4, result);
3899
+ cacheSet(hash4, result);
3750
3900
  return result;
3751
3901
  }
3752
3902
  async embedBatch(texts) {
@@ -3771,7 +3921,7 @@ var init_fastembed_provider = __esm({
3771
3921
  const originalIdx = uncachedIndices[batchIdx];
3772
3922
  const plain = Array.from(vec);
3773
3923
  results[originalIdx] = plain;
3774
- this.cacheSet(textHash(uncachedTexts[batchIdx]), plain);
3924
+ cacheSet(textHash(uncachedTexts[batchIdx]), plain);
3775
3925
  batchIdx++;
3776
3926
  }
3777
3927
  }
@@ -3779,14 +3929,6 @@ var init_fastembed_provider = __esm({
3779
3929
  }
3780
3930
  return results;
3781
3931
  }
3782
- cacheSet(hash4, value) {
3783
- if (cache.size >= MAX_CACHE_SIZE) {
3784
- const firstKey = cache.keys().next().value;
3785
- if (firstKey !== void 0) cache.delete(firstKey);
3786
- }
3787
- cache.set(hash4, value);
3788
- diskCacheDirty = true;
3789
- }
3790
3932
  };
3791
3933
  }
3792
3934
  });
@@ -3796,7 +3938,15 @@ var transformers_provider_exports = {};
3796
3938
  __export(transformers_provider_exports, {
3797
3939
  TransformersProvider: () => TransformersProvider
3798
3940
  });
3799
- var cache2, MAX_CACHE_SIZE2, TransformersProvider;
3941
+ import { createHash as createHash2 } from "crypto";
3942
+ function cacheKey2(text2) {
3943
+ return createHash2("sha256").update(text2).digest("hex");
3944
+ }
3945
+ function maxCachePayloadBytes2() {
3946
+ const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
3947
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES2;
3948
+ }
3949
+ var cache2, MAX_CACHE_SIZE2, DEFAULT_CACHE_PAYLOAD_BYTES2, cachePayloadBytes2, TransformersProvider;
3800
3950
  var init_transformers_provider = __esm({
3801
3951
  "src/embedding/transformers-provider.ts"() {
3802
3952
  "use strict";
@@ -3804,6 +3954,8 @@ var init_transformers_provider = __esm({
3804
3954
  init_provider();
3805
3955
  cache2 = /* @__PURE__ */ new Map();
3806
3956
  MAX_CACHE_SIZE2 = 5e3;
3957
+ DEFAULT_CACHE_PAYLOAD_BYTES2 = 64 * 1024 * 1024;
3958
+ cachePayloadBytes2 = 0;
3807
3959
  TransformersProvider = class _TransformersProvider {
3808
3960
  name = "transformers-minilm";
3809
3961
  dimensions = 384;
@@ -3838,7 +3990,7 @@ var init_transformers_provider = __esm({
3838
3990
  return Promise.all(inputs.map((input) => this.embedInput(input, options)));
3839
3991
  }
3840
3992
  async embed(text2) {
3841
- const cached = cache2.get(text2);
3993
+ const cached = cache2.get(cacheKey2(text2));
3842
3994
  if (cached) return cached;
3843
3995
  const output = await this.extractor(text2, {
3844
3996
  pooling: "mean",
@@ -3848,7 +4000,7 @@ var init_transformers_provider = __esm({
3848
4000
  if (result.length !== this.dimensions) {
3849
4001
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
3850
4002
  }
3851
- this.cacheSet(text2, result);
4003
+ this.cacheSet(cacheKey2(text2), result);
3852
4004
  return result;
3853
4005
  }
3854
4006
  async embedBatch(texts) {
@@ -3856,7 +4008,7 @@ var init_transformers_provider = __esm({
3856
4008
  const uncachedIndices = [];
3857
4009
  const uncachedTexts = [];
3858
4010
  for (let i2 = 0; i2 < texts.length; i2++) {
3859
- const cached = cache2.get(texts[i2]);
4011
+ const cached = cache2.get(cacheKey2(texts[i2]));
3860
4012
  if (cached) {
3861
4013
  results[i2] = cached;
3862
4014
  } else {
@@ -3874,17 +4026,27 @@ var init_transformers_provider = __esm({
3874
4026
  const vec = Array.from(allVecs[i2]);
3875
4027
  const originalIdx = uncachedIndices[i2];
3876
4028
  results[originalIdx] = vec;
3877
- this.cacheSet(uncachedTexts[i2], vec);
4029
+ this.cacheSet(cacheKey2(uncachedTexts[i2]), vec);
3878
4030
  }
3879
4031
  }
3880
4032
  return results;
3881
4033
  }
3882
4034
  cacheSet(key, value) {
3883
- if (cache2.size >= MAX_CACHE_SIZE2) {
3884
- const firstKey = cache2.keys().next().value;
3885
- if (firstKey !== void 0) cache2.delete(firstKey);
4035
+ const incomingBytes = value.length * 8;
4036
+ if (incomingBytes > maxCachePayloadBytes2()) return;
4037
+ const existing = cache2.get(key);
4038
+ if (existing) cachePayloadBytes2 -= existing.length * 8;
4039
+ else {
4040
+ while (cache2.size >= MAX_CACHE_SIZE2 || cachePayloadBytes2 + incomingBytes > maxCachePayloadBytes2()) {
4041
+ const firstKey = cache2.keys().next().value;
4042
+ if (firstKey === void 0) break;
4043
+ const old = cache2.get(firstKey);
4044
+ cache2.delete(firstKey);
4045
+ if (old) cachePayloadBytes2 -= old.length * 8;
4046
+ }
3886
4047
  }
3887
4048
  cache2.set(key, value);
4049
+ cachePayloadBytes2 += incomingBytes;
3888
4050
  }
3889
4051
  };
3890
4052
  }
@@ -3906,7 +4068,7 @@ __export(api_provider_exports, {
3906
4068
  saveDiskCacheNow: () => saveDiskCacheNow,
3907
4069
  seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
3908
4070
  });
3909
- import { createHash as createHash2 } from "crypto";
4071
+ import { createHash as createHash3 } from "crypto";
3910
4072
  import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
3911
4073
  import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
3912
4074
  import { join as join3 } from "path";
@@ -3933,7 +4095,7 @@ function cacheStatFile() {
3933
4095
  function payloadBytes(vector) {
3934
4096
  return vector.length * BYTES_PER_DIM;
3935
4097
  }
3936
- function maxCachePayloadBytes() {
4098
+ function maxCachePayloadBytes3() {
3937
4099
  const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
3938
4100
  if (raw) {
3939
4101
  const parsed = Number.parseInt(raw, 10);
@@ -3943,7 +4105,7 @@ function maxCachePayloadBytes() {
3943
4105
  }
3944
4106
  function maxEntriesForDimensions(dimensions) {
3945
4107
  const dim = Math.max(1, Math.floor(dimensions));
3946
- const byBytes = Math.floor(maxCachePayloadBytes() / (dim * BYTES_PER_DIM));
4108
+ const byBytes = Math.floor(maxCachePayloadBytes3() / (dim * BYTES_PER_DIM));
3947
4109
  return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
3948
4110
  }
3949
4111
  function rememberDimensions(vector) {
@@ -3956,13 +4118,15 @@ function evictOldest() {
3956
4118
  if (firstKey === void 0) return;
3957
4119
  const old = cache3.get(firstKey);
3958
4120
  cache3.delete(firstKey);
3959
- if (old) cachePayloadBytes -= payloadBytes(old);
4121
+ if (old) cachePayloadBytes3 -= payloadBytes(old);
3960
4122
  }
3961
4123
  function evictToFit(incomingBytes, incomingDims) {
4124
+ if (incomingBytes > maxCachePayloadBytes3()) return false;
3962
4125
  const limit2 = maxEntriesForDimensions(incomingDims);
3963
- while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes + incomingBytes > maxCachePayloadBytes())) {
4126
+ while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes3 + incomingBytes > maxCachePayloadBytes3())) {
3964
4127
  evictOldest();
3965
4128
  }
4129
+ return true;
3966
4130
  }
3967
4131
  function isNumberArray(value) {
3968
4132
  return Array.isArray(value) && value.every((entry) => typeof entry === "number");
@@ -3989,12 +4153,12 @@ function cacheInsert(hash4, value, dirty) {
3989
4153
  const incoming = payloadBytes(value);
3990
4154
  const existing = cache3.get(hash4);
3991
4155
  if (existing) {
3992
- cachePayloadBytes -= payloadBytes(existing);
4156
+ cachePayloadBytes3 -= payloadBytes(existing);
3993
4157
  cache3.delete(hash4);
3994
4158
  }
3995
- evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
4159
+ if (!evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS)) return;
3996
4160
  cache3.set(hash4, value);
3997
- cachePayloadBytes += incoming;
4161
+ cachePayloadBytes3 += incoming;
3998
4162
  if (dirty) diskCacheDirty2 = true;
3999
4163
  }
4000
4164
  async function readCacheStat() {
@@ -4030,7 +4194,7 @@ function cacheNamespace(config) {
4030
4194
  ].join("|");
4031
4195
  }
4032
4196
  function textHash2(text2, namespace) {
4033
- return createHash2("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
4197
+ return createHash3("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
4034
4198
  }
4035
4199
  function inputIdentity(input, options = {}) {
4036
4200
  return JSON.stringify({
@@ -4372,7 +4536,7 @@ function getApiEmbeddingDiskCacheLoadCountForTests() {
4372
4536
  }
4373
4537
  function resetApiEmbeddingCacheForTests() {
4374
4538
  cache3.clear();
4375
- cachePayloadBytes = 0;
4539
+ cachePayloadBytes3 = 0;
4376
4540
  cacheDimensions = null;
4377
4541
  diskCacheEntryCount = 0;
4378
4542
  diskCacheLoaded = false;
@@ -4383,14 +4547,14 @@ function resetApiEmbeddingCacheForTests() {
4383
4547
  }
4384
4548
  function seedApiEmbeddingCacheForTests(entries) {
4385
4549
  cache3.clear();
4386
- cachePayloadBytes = 0;
4550
+ cachePayloadBytes3 = 0;
4387
4551
  cacheDimensions = null;
4388
4552
  for (const [key, value] of entries) cacheInsert(key, value, true);
4389
4553
  diskCacheLoaded = true;
4390
4554
  diskCacheDirty2 = true;
4391
4555
  }
4392
4556
  function getApiEmbeddingCachePayloadBytesForTests() {
4393
- return cachePayloadBytes;
4557
+ return cachePayloadBytes3;
4394
4558
  }
4395
4559
  function getApiEmbeddingJsonlLineCountCallsForTests() {
4396
4560
  return jsonlLineCountCalls;
@@ -4564,7 +4728,7 @@ function scheduleDiskSave() {
4564
4728
  diskSaveTimer = null;
4565
4729
  }, DISK_SAVE_DEBOUNCE_MS);
4566
4730
  }
4567
- function cacheSet(hash4, value) {
4731
+ function cacheSet2(hash4, value) {
4568
4732
  cacheInsert(hash4, value, true);
4569
4733
  }
4570
4734
  function resolveEnvEmbeddingApiKey() {
@@ -4684,7 +4848,7 @@ async function waitForRetry(waitMs, signal) {
4684
4848
  abortSignal.addEventListener("abort", onAbort, { once: true });
4685
4849
  });
4686
4850
  }
4687
- 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;
4851
+ 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;
4688
4852
  var init_api_provider = __esm({
4689
4853
  "src/embedding/api-provider.ts"() {
4690
4854
  "use strict";
@@ -4696,7 +4860,7 @@ var init_api_provider = __esm({
4696
4860
  BYTES_PER_DIM = 8;
4697
4861
  DEFAULT_ASSUMED_DIMENSIONS = 4096;
4698
4862
  MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
4699
- cachePayloadBytes = 0;
4863
+ cachePayloadBytes3 = 0;
4700
4864
  cacheDimensions = null;
4701
4865
  diskCacheEntryCount = 0;
4702
4866
  diskCacheDirty2 = false;
@@ -4881,7 +5045,7 @@ var init_api_provider = __esm({
4881
5045
  } else {
4882
5046
  embedding = await apiCall();
4883
5047
  }
4884
- cacheSet(hash4, embedding);
5048
+ cacheSet2(hash4, embedding);
4885
5049
  scheduleDiskSave();
4886
5050
  return embedding;
4887
5051
  }
@@ -4929,7 +5093,7 @@ var init_api_provider = __esm({
4929
5093
  for (const item of response.data) {
4930
5094
  const originalIdx = chunkIndices[item.index];
4931
5095
  results[originalIdx] = item.embedding;
4932
- cacheSet(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
5096
+ cacheSet2(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
4933
5097
  }
4934
5098
  } catch (error) {
4935
5099
  const providerLimit = parseBatchLimit(error);
@@ -5007,7 +5171,7 @@ var init_api_provider = __esm({
5007
5171
  throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d; dimension mismatch`);
5008
5172
  }
5009
5173
  this.trackUsage(response);
5010
- cacheSet(hash4, embedding);
5174
+ cacheSet2(hash4, embedding);
5011
5175
  scheduleDiskSave();
5012
5176
  return embedding;
5013
5177
  }
@@ -6390,6 +6554,7 @@ var init_provider2 = __esm({
6390
6554
  openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
6391
6555
  anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
6392
6556
  openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
6557
+ atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
6393
6558
  custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
6394
6559
  };
6395
6560
  currentConfig = null;
@@ -6653,6 +6818,7 @@ var init_sqlite_store = __esm({
6653
6818
  init_sqlite_db();
6654
6819
  init_sqlite_reliability();
6655
6820
  init_sqlite_fts();
6821
+ init_file_lock();
6656
6822
  SqliteBackend = class {
6657
6823
  db = null;
6658
6824
  dataDir = "";
@@ -6816,38 +6982,43 @@ var init_sqlite_store = __esm({
6816
6982
  }
6817
6983
  // ── Migration ────────────────────────────────────────────────────
6818
6984
  async migrateFromJsonIfNeeded() {
6819
- const count2 = this.db.prepare(`SELECT COUNT(*) AS cnt FROM observations`).get();
6820
- if (count2.cnt > 0) return;
6821
6985
  const jsonPath = path7.join(this.dataDir, "observations.json");
6822
6986
  if (!fs4.existsSync(jsonPath)) return;
6823
- try {
6987
+ await withFileLock(this.dataDir, async () => {
6988
+ const count2 = this.db.prepare(`SELECT COUNT(*) AS cnt FROM observations`).get();
6989
+ if (count2.cnt > 0) return;
6824
6990
  const raw = fs4.readFileSync(jsonPath, "utf-8");
6825
- const observations2 = JSON.parse(raw);
6991
+ const parsed = JSON.parse(raw);
6992
+ if (!Array.isArray(parsed)) {
6993
+ throw new Error("[memorix] observations.json migration refused: expected a JSON array");
6994
+ }
6995
+ const observations2 = parsed;
6826
6996
  if (observations2.length === 0) return;
6997
+ if (observations2.some((obs) => !obs || !Number.isSafeInteger(obs.id) || obs.id < 1 || typeof obs.projectId !== "string")) {
6998
+ throw new Error("[memorix] observations.json migration refused: invalid observation record");
6999
+ }
6827
7000
  console.error(`[memorix] Migrating ${observations2.length} observations from JSON to SQLite...`);
6828
7001
  const insertMany = this.db.transaction((obsList) => {
6829
7002
  for (const obs of obsList) {
6830
7003
  this.stmtInsert.run(obsToRow(obs));
6831
7004
  }
6832
- });
6833
- insertMany(observations2);
6834
- const counterPath = path7.join(this.dataDir, "counter.json");
6835
- if (fs4.existsSync(counterPath)) {
6836
- try {
7005
+ const counterPath = path7.join(this.dataDir, "counter.json");
7006
+ let counterNextId;
7007
+ if (fs4.existsSync(counterPath)) {
6837
7008
  const counterData = JSON.parse(fs4.readFileSync(counterPath, "utf-8"));
6838
- const nextId2 = counterData.nextId ?? counterData.next_id ?? Math.max(...observations2.map((o) => o.id)) + 1;
6839
- this.rawSaveIdCounter(nextId2);
6840
- } catch {
6841
- this.rawSaveIdCounter(Math.max(...observations2.map((o) => o.id)) + 1);
7009
+ const candidate = counterData.nextId ?? counterData.next_id;
7010
+ if (candidate !== void 0 && (!Number.isSafeInteger(candidate) || Number(candidate) < 1)) {
7011
+ throw new Error("[memorix] counter.json migration refused: nextId must be a positive integer");
7012
+ }
7013
+ counterNextId = candidate === void 0 ? void 0 : Number(candidate);
6842
7014
  }
6843
- } else {
6844
- this.rawSaveIdCounter(Math.max(...observations2.map((o) => o.id)) + 1);
6845
- }
6846
- this.bumpGeneration();
7015
+ const maxId = Math.max(...obsList.map((obs) => obs.id));
7016
+ this.rawSaveIdCounter(Math.max(counterNextId ?? 1, maxId + 1));
7017
+ this.bumpGeneration();
7018
+ });
7019
+ insertMany(observations2);
6847
7020
  console.error(`[memorix] Migration complete. ${observations2.length} observations now in SQLite.`);
6848
- } catch (err) {
6849
- console.error(`[memorix] JSON\u2192SQLite migration failed (non-fatal, data preserved in JSON): ${err}`);
6850
- }
7021
+ });
6851
7022
  }
6852
7023
  // ── Public read ──────────────────────────────────────────────────
6853
7024
  async loadAll() {
@@ -7147,7 +7318,7 @@ var init_obs_store = __esm({
7147
7318
  });
7148
7319
 
7149
7320
  // src/search/semantic-index.ts
7150
- import { createHash as createHash3 } from "crypto";
7321
+ import { createHash as createHash4 } from "crypto";
7151
7322
  import { createRequire as createRequire3 } from "module";
7152
7323
  import path8 from "path";
7153
7324
  function createSemanticIndexProfile(provider2) {
@@ -7161,7 +7332,7 @@ function stateKey(dataDir, profile) {
7161
7332
  return `${path8.resolve(dataDir)}::${profile.key}`;
7162
7333
  }
7163
7334
  function tableName(profile) {
7164
- const digest2 = createHash3("sha256").update(profile.key).digest("hex").slice(0, 20);
7335
+ const digest2 = createHash4("sha256").update(profile.key).digest("hex").slice(0, 20);
7165
7336
  return `${TABLE_PREFIX}${digest2}`;
7166
7337
  }
7167
7338
  function indexRoot(dataDir) {
@@ -9239,7 +9410,7 @@ var init_lifecycle = __esm({
9239
9410
  });
9240
9411
 
9241
9412
  // src/store/evidence-store.ts
9242
- import { createHash as createHash4, randomUUID as randomUUID4 } from "crypto";
9413
+ import { createHash as createHash5, randomUUID as randomUUID4 } from "crypto";
9243
9414
  function safeJson(value, fallback) {
9244
9415
  if (typeof value !== "string" || value.length === 0) return fallback;
9245
9416
  try {
@@ -9273,7 +9444,7 @@ function rowToCard(row) {
9273
9444
  };
9274
9445
  }
9275
9446
  function observationHash(observation) {
9276
- return createHash4("sha256").update(JSON.stringify({
9447
+ return createHash5("sha256").update(JSON.stringify({
9277
9448
  projectId: observation.projectId,
9278
9449
  id: observation.id,
9279
9450
  title: observation.title,
@@ -9703,13 +9874,13 @@ __export(workspace_exports, {
9703
9874
  loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
9704
9875
  resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
9705
9876
  });
9706
- import { createHash as createHash5 } from "crypto";
9877
+ import { createHash as createHash6 } from "crypto";
9707
9878
  import { execFile } from "child_process";
9708
9879
  import { promises as fs6 } from "fs";
9709
9880
  import path10 from "path";
9710
9881
  import { promisify } from "util";
9711
9882
  function hash(value) {
9712
- return createHash5("sha256").update(value).digest("hex");
9883
+ return createHash6("sha256").update(value).digest("hex");
9713
9884
  }
9714
9885
  function workspaceId(projectId, mode) {
9715
9886
  return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
@@ -10317,14 +10488,14 @@ var init_types2 = __esm({
10317
10488
  });
10318
10489
 
10319
10490
  // src/media/asset-store.ts
10320
- import { createHash as createHash6, randomUUID as randomUUID6 } from "crypto";
10491
+ import { createHash as createHash7, randomUUID as randomUUID6 } from "crypto";
10321
10492
  import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
10322
10493
  import path11 from "path";
10323
10494
  function mediaRoot(dataDir) {
10324
10495
  return path11.resolve(dataDir, "media");
10325
10496
  }
10326
10497
  function projectStorageKey(projectId) {
10327
- return createHash6("sha256").update(projectId).digest("hex").slice(0, 16);
10498
+ return createHash7("sha256").update(projectId).digest("hex").slice(0, 16);
10328
10499
  }
10329
10500
  function validateUnderRoot(root, candidate) {
10330
10501
  const resolved = path11.resolve(candidate);
@@ -10433,7 +10604,7 @@ async function importMediaBuffer(input) {
10433
10604
  if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
10434
10605
  if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
10435
10606
  const detected = detectMedia(input.bytes.subarray(0, 32));
10436
- const sha256 = createHash6("sha256").update(input.bytes).digest("hex");
10607
+ const sha256 = createHash7("sha256").update(input.bytes).digest("hex");
10437
10608
  return importKnownMedia({
10438
10609
  dataDir: input.dataDir,
10439
10610
  projectId: input.projectId,
@@ -10451,7 +10622,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
10451
10622
  if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
10452
10623
  const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
10453
10624
  if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
10454
- const sha256 = createHash6("sha256").update(bytes).digest("hex");
10625
+ const sha256 = createHash7("sha256").update(bytes).digest("hex");
10455
10626
  if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
10456
10627
  return bytes;
10457
10628
  }
@@ -69147,16 +69318,16 @@ var require_jwtaccess = __commonJS({
69147
69318
  * @returns A string that returns the cached key.
69148
69319
  */
69149
69320
  getCachedKey(url, scopes) {
69150
- let cacheKey = url;
69321
+ let cacheKey3 = url;
69151
69322
  if (scopes && Array.isArray(scopes) && scopes.length) {
69152
- cacheKey = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
69323
+ cacheKey3 = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
69153
69324
  } else if (typeof scopes === "string") {
69154
- cacheKey = url ? `${url}_${scopes}` : scopes;
69325
+ cacheKey3 = url ? `${url}_${scopes}` : scopes;
69155
69326
  }
69156
- if (!cacheKey) {
69327
+ if (!cacheKey3) {
69157
69328
  throw Error("Scopes or url must be provided");
69158
69329
  }
69159
- return cacheKey;
69330
+ return cacheKey3;
69160
69331
  }
69161
69332
  /**
69162
69333
  * Get a non-expired access token, after refreshing if necessary.
@@ -75702,7 +75873,7 @@ var require_websocket = __commonJS({
75702
75873
  var http3 = __require("http");
75703
75874
  var net = __require("net");
75704
75875
  var tls = __require("tls");
75705
- var { randomBytes, createHash: createHash16 } = __require("crypto");
75876
+ var { randomBytes, createHash: createHash17 } = __require("crypto");
75706
75877
  var { Duplex, Readable: Readable2 } = __require("stream");
75707
75878
  var { URL: URL2 } = __require("url");
75708
75879
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -76370,7 +76541,7 @@ var require_websocket = __commonJS({
76370
76541
  abortHandshake(websocket, socket, "Invalid Upgrade header");
76371
76542
  return;
76372
76543
  }
76373
- const digest2 = createHash16("sha1").update(key + GUID).digest("base64");
76544
+ const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
76374
76545
  if (res.headers["sec-websocket-accept"] !== digest2) {
76375
76546
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
76376
76547
  return;
@@ -76742,7 +76913,7 @@ var require_websocket_server = __commonJS({
76742
76913
  var EventEmitter = __require("events");
76743
76914
  var http3 = __require("http");
76744
76915
  var { Duplex } = __require("stream");
76745
- var { createHash: createHash16 } = __require("crypto");
76916
+ var { createHash: createHash17 } = __require("crypto");
76746
76917
  var extension3 = require_extension();
76747
76918
  var PerMessageDeflate2 = require_permessage_deflate();
76748
76919
  var subprotocol2 = require_subprotocol();
@@ -77049,7 +77220,7 @@ var require_websocket_server = __commonJS({
77049
77220
  );
77050
77221
  }
77051
77222
  if (this._state > RUNNING) return abortHandshake(socket, 503);
77052
- const digest2 = createHash16("sha1").update(key + GUID).digest("base64");
77223
+ const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
77053
77224
  const headers = [
77054
77225
  "HTTP/1.1 101 Switching Protocols",
77055
77226
  "Upgrade: websocket",
@@ -145334,9 +145505,9 @@ var init_long_term = __esm({
145334
145505
  });
145335
145506
 
145336
145507
  // src/codegraph/ids.ts
145337
- import { createHash as createHash7 } from "crypto";
145508
+ import { createHash as createHash8 } from "crypto";
145338
145509
  function digest(input) {
145339
- return createHash7("sha256").update(input).digest("hex").slice(0, 16);
145510
+ return createHash8("sha256").update(input).digest("hex").slice(0, 16);
145340
145511
  }
145341
145512
  function normalizeCodePath(path23) {
145342
145513
  return path23.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
@@ -146384,7 +146555,7 @@ var init_store = __esm({
146384
146555
 
146385
146556
  // src/codegraph/code-state.ts
146386
146557
  import { execFile as execFile2 } from "child_process";
146387
- import { createHash as createHash8 } from "crypto";
146558
+ import { createHash as createHash9 } from "crypto";
146388
146559
  import { promisify as promisify3 } from "util";
146389
146560
  async function runGit(rootPath, args) {
146390
146561
  try {
@@ -146413,7 +146584,7 @@ function changedPathCount(status) {
146413
146584
  return count2;
146414
146585
  }
146415
146586
  function fingerprint(baseRevision, status) {
146416
- return createHash8("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
146587
+ return createHash9("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
146417
146588
  }
146418
146589
  async function collectCodeStateSnapshot(input) {
146419
146590
  const [revision, status] = await Promise.all([
@@ -146507,12 +146678,12 @@ var init_exclude3 = __esm({
146507
146678
  });
146508
146679
 
146509
146680
  // src/codegraph/semantic-provider.ts
146510
- import { createHash as createHash9 } from "crypto";
146681
+ import { createHash as createHash10 } from "crypto";
146511
146682
  import "fs";
146512
146683
  import { resolve } from "path";
146513
146684
  import ts from "typescript";
146514
146685
  function hashText(value) {
146515
- return createHash9("sha256").update(value).digest("hex");
146686
+ return createHash10("sha256").update(value).digest("hex");
146516
146687
  }
146517
146688
  function canonicalPath(value) {
146518
146689
  const normalized = resolve(value).replace(/\\/g, "/");
@@ -146857,11 +147028,11 @@ __export(lite_provider_exports, {
146857
147028
  indexProjectLite: () => indexProjectLite,
146858
147029
  refreshProjectLite: () => refreshProjectLite
146859
147030
  });
146860
- import { createHash as createHash10 } from "crypto";
147031
+ import { createHash as createHash11 } from "crypto";
146861
147032
  import { existsSync as existsSync10, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
146862
147033
  import { join as join4, relative as relative2 } from "path";
146863
147034
  function hashText2(text2) {
146864
- return createHash10("sha256").update(text2).digest("hex");
147035
+ return createHash11("sha256").update(text2).digest("hex");
146865
147036
  }
146866
147037
  function extension2(path23) {
146867
147038
  const index = path23.lastIndexOf(".");
@@ -147494,7 +147665,7 @@ var claim_store_exports = {};
147494
147665
  __export(claim_store_exports, {
147495
147666
  ClaimStore: () => ClaimStore
147496
147667
  });
147497
- import { createHash as createHash11, randomUUID as randomUUID12 } from "crypto";
147668
+ import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
147498
147669
  function optionalText3(value) {
147499
147670
  return typeof value === "string" && value ? value : void 0;
147500
147671
  }
@@ -147547,7 +147718,7 @@ function rowToEvent3(row) {
147547
147718
  };
147548
147719
  }
147549
147720
  function evidenceKey(input) {
147550
- return createHash11("sha256").update(JSON.stringify([
147721
+ return createHash12("sha256").update(JSON.stringify([
147551
147722
  input.evidenceKind,
147552
147723
  input.evidenceId,
147553
147724
  input.relation,
@@ -147745,7 +147916,7 @@ __export(claims_exports, {
147745
147916
  supersedeClaim: () => supersedeClaim,
147746
147917
  writeClaim: () => writeClaim
147747
147918
  });
147748
- import { createHash as createHash12, randomUUID as randomUUID13 } from "crypto";
147919
+ import { createHash as createHash13, randomUUID as randomUUID13 } from "crypto";
147749
147920
  function compactText2(value, field) {
147750
147921
  if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
147751
147922
  const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
@@ -147757,7 +147928,7 @@ function normalizedTerm(value) {
147757
147928
  return compactText2(value, "identity").toLocaleLowerCase("en-US");
147758
147929
  }
147759
147930
  function hashIdentity(parts) {
147760
- return createHash12("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
147931
+ return createHash13("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
147761
147932
  }
147762
147933
  function buildClaimIdentity(input) {
147763
147934
  const subject = normalizedTerm(input.subject);
@@ -147998,7 +148169,7 @@ function supersedeClaim(store, input) {
147998
148169
  });
147999
148170
  }
148000
148171
  function hashObservation(observation) {
148001
- return createHash12("sha256").update(JSON.stringify([
148172
+ return createHash13("sha256").update(JSON.stringify([
148002
148173
  observation.title,
148003
148174
  observation.narrative,
148004
148175
  observation.facts,
@@ -148242,11 +148413,11 @@ var init_frontmatter = __esm({
148242
148413
  });
148243
148414
 
148244
148415
  // src/knowledge/markdown.ts
148245
- import { createHash as createHash13 } from "crypto";
148416
+ import { createHash as createHash14 } from "crypto";
148246
148417
  import { promises as fs10 } from "fs";
148247
148418
  import path17 from "path";
148248
148419
  function hashContent(content) {
148249
- return createHash13("sha256").update(content).digest("hex");
148420
+ return createHash14("sha256").update(content).digest("hex");
148250
148421
  }
148251
148422
  function stringField(data, key) {
148252
148423
  const value = data[key];
@@ -148372,11 +148543,11 @@ __export(wiki_exports, {
148372
148543
  lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
148373
148544
  readKnowledgePage: () => readKnowledgePage
148374
148545
  });
148375
- import { createHash as createHash14 } from "crypto";
148546
+ import { createHash as createHash15 } from "crypto";
148376
148547
  import { promises as fs11 } from "fs";
148377
148548
  import path18 from "path";
148378
148549
  function hash2(value) {
148379
- return createHash14("sha256").update(value).digest("hex");
148550
+ return createHash15("sha256").update(value).digest("hex");
148380
148551
  }
148381
148552
  function now() {
148382
148553
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -149233,11 +149404,11 @@ __export(workflows_exports, {
149233
149404
  syncCanonicalWorkflows: () => syncCanonicalWorkflows,
149234
149405
  writeCanonicalWorkflow: () => writeCanonicalWorkflow
149235
149406
  });
149236
- import { createHash as createHash15 } from "crypto";
149407
+ import { createHash as createHash16 } from "crypto";
149237
149408
  import { promises as fs12 } from "fs";
149238
149409
  import path19 from "path";
149239
149410
  function hash3(value) {
149240
- return createHash15("sha256").update(value).digest("hex");
149411
+ return createHash16("sha256").update(value).digest("hex");
149241
149412
  }
149242
149413
  function now2() {
149243
149414
  return (/* @__PURE__ */ new Date()).toISOString();