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
@@ -222,6 +222,74 @@ var init_launch_root = __esm({
222
222
  }
223
223
  });
224
224
 
225
+ // src/store/sqlite-reliability.ts
226
+ function isTransientSqliteError(error) {
227
+ const code = error?.code;
228
+ if (typeof code === "string") {
229
+ return /^SQLITE_BUSY(?:_|$)/i.test(code);
230
+ }
231
+ return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
232
+ }
233
+ function isSqliteUnavailableError(error) {
234
+ return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
235
+ }
236
+ function degradedReadError(storeName) {
237
+ return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
238
+ }
239
+ function degradedWriteError(storeName) {
240
+ return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
241
+ }
242
+ function formatSqliteFailure(error) {
243
+ return error instanceof Error && error.message ? error.message : String(error);
244
+ }
245
+ function delay(ms) {
246
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
247
+ }
248
+ async function retrySqliteBusy(operation, label) {
249
+ for (let attempt = 0; ; attempt++) {
250
+ try {
251
+ return await operation();
252
+ } catch (error) {
253
+ if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
254
+ const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
255
+ console.error(
256
+ `[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
257
+ );
258
+ await delay(waitMs);
259
+ }
260
+ }
261
+ }
262
+ async function initializeSqliteStore(factory, dataDir, label) {
263
+ try {
264
+ loadBetterSqlite3();
265
+ } catch (error) {
266
+ throw new SqliteUnavailableError(error);
267
+ }
268
+ return retrySqliteBusy(async () => {
269
+ const store = factory();
270
+ await store.init(dataDir);
271
+ return store;
272
+ }, label);
273
+ }
274
+ var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
275
+ var init_sqlite_reliability = __esm({
276
+ "src/store/sqlite-reliability.ts"() {
277
+ "use strict";
278
+ init_esm_shims();
279
+ init_sqlite_db();
280
+ SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
281
+ SqliteUnavailableError = class extends Error {
282
+ code = "MEMORIX_SQLITE_UNAVAILABLE";
283
+ constructor(cause) {
284
+ super(
285
+ cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
286
+ );
287
+ this.name = "SqliteUnavailableError";
288
+ }
289
+ };
290
+ }
291
+ });
292
+
225
293
  // src/store/sqlite-fts.ts
226
294
  function normalizeFtsToken(token) {
227
295
  return token.replace(/"/g, '""');
@@ -235,22 +303,27 @@ function buildFtsQuery(query) {
235
303
  function initializeObservationLexicalIndex(db2) {
236
304
  const known = ftsAvailability.get(db2);
237
305
  if (known !== void 0) return known;
238
- try {
239
- db2.exec(CREATE_OBSERVATION_FTS);
240
- const observationCount = Number(db2.prepare("SELECT COUNT(*) AS count FROM observations").get()?.count ?? 0);
241
- const indexedCount = Number(db2.prepare(`SELECT COUNT(*) AS count FROM ${FTS_TABLE}`).get()?.count ?? 0);
242
- if (observationCount !== indexedCount) {
243
- db2.exec(`INSERT INTO ${FTS_TABLE}(${FTS_TABLE}) VALUES ('rebuild')`);
306
+ let lastError;
307
+ for (let attempt = 1; attempt <= FTS_INIT_MAX_ATTEMPTS; attempt++) {
308
+ try {
309
+ db2.exec(CREATE_OBSERVATION_FTS);
310
+ const observationCount = Number(db2.prepare("SELECT COUNT(*) AS count FROM observations").get()?.count ?? 0);
311
+ const indexedCount = Number(db2.prepare(`SELECT COUNT(*) AS count FROM ${FTS_TABLE}`).get()?.count ?? 0);
312
+ if (observationCount !== indexedCount) {
313
+ db2.exec(`INSERT INTO ${FTS_TABLE}(${FTS_TABLE}) VALUES ('rebuild')`);
314
+ }
315
+ ftsAvailability.set(db2, true);
316
+ return true;
317
+ } catch (error) {
318
+ lastError = error;
319
+ if (!isTransientSqliteError(error) || attempt === FTS_INIT_MAX_ATTEMPTS) break;
244
320
  }
245
- ftsAvailability.set(db2, true);
246
- return true;
247
- } catch (error) {
248
- ftsAvailability.set(db2, false);
249
- console.warn(
250
- `[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${error instanceof Error ? error.message : String(error)}`
251
- );
252
- return false;
253
321
  }
322
+ ftsAvailability.set(db2, false);
323
+ console.warn(
324
+ `[memorix] SQLite FTS5 unavailable; using the existing search fallback: ${lastError instanceof Error ? lastError.message : String(lastError)}`
325
+ );
326
+ return false;
254
327
  }
255
328
  function isObservationLexicalIndexEnabled(db2) {
256
329
  return ftsAvailability.get(db2) === true;
@@ -304,11 +377,12 @@ function searchObservationLexically(db2, options) {
304
377
  score: Math.max(0, Number(row.lexical_score ?? 0))
305
378
  }));
306
379
  }
307
- var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS;
380
+ var ftsAvailability, FTS_TABLE, CREATE_OBSERVATION_FTS, FTS_INIT_MAX_ATTEMPTS;
308
381
  var init_sqlite_fts = __esm({
309
382
  "src/store/sqlite-fts.ts"() {
310
383
  "use strict";
311
384
  init_esm_shims();
385
+ init_sqlite_reliability();
312
386
  ftsAvailability = /* @__PURE__ */ new WeakMap();
313
387
  FTS_TABLE = "observations_fts";
314
388
  CREATE_OBSERVATION_FTS = `
@@ -342,6 +416,7 @@ CREATE TRIGGER IF NOT EXISTS observations_fts_au AFTER UPDATE ON observations BE
342
416
  VALUES (new.id, new.entityName, new.title, new.narrative, new.facts, new.filesModified, new.concepts, new.attachments);
343
417
  END;
344
418
  `;
419
+ FTS_INIT_MAX_ATTEMPTS = 3;
345
420
  }
346
421
  });
347
422
 
@@ -380,11 +455,21 @@ function applySchemaMigrations(db2) {
380
455
  apply();
381
456
  }
382
457
  }
458
+ function normalizeDataDir(dataDir) {
459
+ return path3.resolve(dataDir);
460
+ }
461
+ function touchDatabase(normalized, db2) {
462
+ _dbCache.delete(normalized);
463
+ _dbCache.set(normalized, db2);
464
+ }
383
465
  function getDatabase(dataDir) {
384
- const normalized = path3.resolve(dataDir);
466
+ const normalized = normalizeDataDir(dataDir);
385
467
  assertNotHomeDataDir(normalized);
386
468
  const existing = _dbCache.get(normalized);
387
- if (existing) return existing;
469
+ if (existing) {
470
+ touchDatabase(normalized, existing);
471
+ return existing;
472
+ }
388
473
  loadBetterSqlite3();
389
474
  fs.mkdirSync(dataDir, { recursive: true });
390
475
  const dbPath = path3.join(dataDir, "memorix.db");
@@ -414,6 +499,8 @@ function getDatabase(dataDir) {
414
499
  db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
415
500
  db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
416
501
  db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
502
+ db2.exec(CREATE_TASK_CONTINUITY_EVENTS_TABLE);
503
+ db2.exec(CREATE_AGENT_EFFECTS_TABLE);
417
504
  try {
418
505
  db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
419
506
  } catch {
@@ -452,7 +539,7 @@ function getDatabase(dataDir) {
452
539
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
453
540
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
454
541
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
455
- _dbCache.set(normalized, db2);
542
+ touchDatabase(normalized, db2);
456
543
  return db2;
457
544
  } catch (error) {
458
545
  try {
@@ -470,8 +557,9 @@ function closeAllDatabases() {
470
557
  }
471
558
  _dbCache.delete(key);
472
559
  }
560
+ _dbLeases.clear();
473
561
  }
474
- 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;
562
+ 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;
475
563
  var init_sqlite_db = __esm({
476
564
  "src/store/sqlite-db.ts"() {
477
565
  "use strict";
@@ -1188,6 +1276,43 @@ CREATE TABLE IF NOT EXISTS memory_feedback_events (
1188
1276
  delta REAL NOT NULL DEFAULT 0,
1189
1277
  observed_at TEXT NOT NULL
1190
1278
  );
1279
+ `;
1280
+ CREATE_TASK_CONTINUITY_EVENTS_TABLE = `
1281
+ CREATE TABLE IF NOT EXISTS task_continuity_events (
1282
+ id TEXT PRIMARY KEY,
1283
+ project_id TEXT NOT NULL,
1284
+ task_id TEXT NOT NULL,
1285
+ task TEXT NOT NULL,
1286
+ kind TEXT NOT NULL,
1287
+ content TEXT NOT NULL,
1288
+ item_status TEXT,
1289
+ source_ref TEXT,
1290
+ evidence_json TEXT NOT NULL DEFAULT '[]',
1291
+ actor TEXT,
1292
+ created_at TEXT NOT NULL,
1293
+ event_key TEXT,
1294
+ item_key TEXT,
1295
+ supersedes_id TEXT
1296
+ );
1297
+ `;
1298
+ CREATE_AGENT_EFFECTS_TABLE = `
1299
+ CREATE TABLE IF NOT EXISTS agent_effects (
1300
+ id TEXT PRIMARY KEY,
1301
+ pipeline_id TEXT NOT NULL,
1302
+ task_id TEXT NOT NULL,
1303
+ attempt INTEGER NOT NULL,
1304
+ effect_key TEXT NOT NULL,
1305
+ tool TEXT NOT NULL,
1306
+ risk_tier TEXT NOT NULL,
1307
+ replay_policy TEXT NOT NULL,
1308
+ status TEXT NOT NULL,
1309
+ call_id TEXT,
1310
+ idempotency_key TEXT NOT NULL,
1311
+ input_fingerprint TEXT,
1312
+ detail TEXT,
1313
+ started_at INTEGER NOT NULL,
1314
+ finished_at INTEGER
1315
+ );
1191
1316
  `;
1192
1317
  CREATE_MCP_BINDINGS_TABLE = `
1193
1318
  CREATE TABLE IF NOT EXISTS mcp_bindings (
@@ -1266,7 +1391,18 @@ CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(projec
1266
1391
  CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
1267
1392
  CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
1268
1393
  CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
1394
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_project_task ON task_continuity_events(project_id, task_id, created_at ASC);
1395
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_project_recent ON task_continuity_events(project_id, created_at DESC);
1396
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_item ON task_continuity_events(project_id, task_id, kind, item_key, created_at DESC);
1397
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
1398
+ ON task_continuity_events(project_id, task_id, event_key)
1399
+ WHERE event_key IS NOT NULL;
1400
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_effect_identity
1401
+ ON agent_effects(pipeline_id, task_id, attempt, effect_key);
1402
+ CREATE INDEX IF NOT EXISTS idx_agent_effect_pipeline ON agent_effects(pipeline_id, started_at ASC);
1269
1403
  CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
1404
+ CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC);
1405
+ CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at);
1270
1406
  CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1271
1407
  ON maintenance_jobs(project_id, kind, dedupe_key)
1272
1408
  WHERE status IN ('pending', 'running', 'retry');
@@ -1437,6 +1573,8 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1437
1573
  db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
1438
1574
  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)");
1439
1575
  db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
1576
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC)");
1577
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at)");
1440
1578
  }
1441
1579
  },
1442
1580
  {
@@ -1447,9 +1585,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1447
1585
  addColumnIfMissing(db2, "code_symbols", "source", "source TEXT");
1448
1586
  addColumnIfMissing(db2, "code_edges", "source", "source TEXT");
1449
1587
  }
1588
+ },
1589
+ {
1590
+ id: "1.9-continuity-v2",
1591
+ apply: (db2) => {
1592
+ addColumnIfMissing(db2, "task_continuity_events", "event_key", "event_key TEXT");
1593
+ addColumnIfMissing(db2, "task_continuity_events", "item_key", "item_key TEXT");
1594
+ addColumnIfMissing(db2, "task_continuity_events", "supersedes_id", "supersedes_id TEXT");
1595
+ 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)");
1596
+ db2.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
1597
+ ON task_continuity_events(project_id, task_id, event_key)
1598
+ WHERE event_key IS NOT NULL`);
1599
+ }
1450
1600
  }
1451
1601
  ];
1452
1602
  _dbCache = /* @__PURE__ */ new Map();
1603
+ _dbLeases = /* @__PURE__ */ new Map();
1453
1604
  }
1454
1605
  });
1455
1606
 
@@ -1552,15 +1703,20 @@ var init_dotenv_loader = __esm({
1552
1703
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
1553
1704
  import { homedir as homedir2 } from "os";
1554
1705
  import { parse as parseYamlDocument } from "yaml";
1706
+ function cacheKey(homeDir, projectRoot) {
1707
+ return `${homeDir}\0${projectRoot ?? ""}`;
1708
+ }
1555
1709
  function initProjectRoot(root) {
1556
1710
  globalProjectRoot = root;
1557
- configCache.delete(root);
1711
+ configCache.delete(cacheKey(homedir2(), root));
1558
1712
  }
1559
- function loadYamlConfig(projectRoot) {
1713
+ function loadYamlConfig(projectRoot, options = {}) {
1714
+ const homeDir = options.homeDir ?? homedir2();
1560
1715
  const resolvedRoot = projectRoot === null ? null : projectRoot ?? globalProjectRoot ?? null;
1561
- const cached = configCache.get(resolvedRoot ?? null);
1716
+ const key = cacheKey(homeDir, resolvedRoot);
1717
+ const cached = configCache.get(key);
1562
1718
  if (cached) return cached;
1563
- const userYaml = getGlobalYamlPath(homedir2());
1719
+ const userYaml = getGlobalYamlPath(homeDir);
1564
1720
  const projectYaml = resolvedRoot ? getProjectYamlPath(resolvedRoot) : null;
1565
1721
  let userConfig = {};
1566
1722
  let projectConfig = {};
@@ -1592,7 +1748,7 @@ function loadYamlConfig(projectRoot) {
1592
1748
  server: { ...userConfig.server, ...projectConfig.server },
1593
1749
  team: { ...userConfig.team, ...projectConfig.team }
1594
1750
  };
1595
- configCache.set(resolvedRoot ?? null, merged);
1751
+ configCache.set(key, merged);
1596
1752
  return merged;
1597
1753
  }
1598
1754
  function parseYaml(content) {
@@ -1768,9 +1924,9 @@ var init_detector = __esm({
1768
1924
  // src/config/legacy-loader.ts
1769
1925
  import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
1770
1926
  import { homedir as homedir3 } from "os";
1771
- function loadFileConfig() {
1927
+ function loadFileConfig(homeDir = homedir3()) {
1772
1928
  if (cachedConfig !== null) return cachedConfig;
1773
- const configPath = getLegacyConfigJsonPath(homedir3());
1929
+ const configPath = getLegacyConfigJsonPath(homeDir);
1774
1930
  try {
1775
1931
  if (existsSync5(configPath)) {
1776
1932
  cachedConfig = JSON.parse(readFileSync5(configPath, "utf-8"));
@@ -1800,15 +1956,15 @@ import { homedir as homedir4 } from "os";
1800
1956
  function loadTomlConfig(options = {}) {
1801
1957
  const homeDir = options.homeDir ?? homedir4();
1802
1958
  const projectRoot = options.projectRoot ?? null;
1803
- const cacheKey = `${homeDir}\0${projectRoot ?? ""}`;
1804
- const cached = configCache2.get(cacheKey);
1959
+ const cacheKey3 = `${homeDir}\0${projectRoot ?? ""}`;
1960
+ const cached = configCache2.get(cacheKey3);
1805
1961
  if (cached) return cached;
1806
1962
  const userToml = getGlobalConfigTomlPath(homeDir);
1807
1963
  const projectToml = projectRoot ? getProjectConfigTomlPath(projectRoot) : null;
1808
1964
  const userConfig = existsSync6(userToml) ? parseTomlConfig(readFileSync6(userToml, "utf8"), userToml) : {};
1809
1965
  const projectConfig = projectToml && existsSync6(projectToml) ? parseTomlConfig(readFileSync6(projectToml, "utf8"), projectToml) : {};
1810
1966
  const merged = mergeTomlConfig(userConfig, projectConfig);
1811
- configCache2.set(cacheKey, merged);
1967
+ configCache2.set(cacheKey3, merged);
1812
1968
  return merged;
1813
1969
  }
1814
1970
  function mergeTomlConfig(base, override) {
@@ -1929,8 +2085,8 @@ function getResolvedConfig(options = {}) {
1929
2085
  const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
1930
2086
  loadDotenv(projectRoot === null ? void 0 : projectRoot ?? void 0, { userHomeDir: homeDir });
1931
2087
  const toml = loadTomlConfig({ projectRoot: projectRoot ?? null, homeDir });
1932
- const yaml = loadYamlConfig(projectRoot ?? null);
1933
- const legacy = loadFileConfig();
2088
+ const yaml = loadYamlConfig(projectRoot ?? null, { homeDir });
2089
+ const legacy = loadFileConfig(homeDir);
1934
2090
  const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
1935
2091
  const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
1936
2092
  const memoryLlmProvider = first(
@@ -1952,15 +2108,17 @@ function getResolvedConfig(options = {}) {
1952
2108
  legacy.llm?.baseUrl
1953
2109
  );
1954
2110
  const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
2111
+ const isAtlasCloud = memoryLlmProvider === "atlascloud";
1955
2112
  const memoryLlmApiKey = first(
1956
2113
  process.env.MEMORIX_LLM_API_KEY,
1957
2114
  process.env.MEMORIX_API_KEY,
1958
2115
  toml.memory?.llm?.api_key,
1959
2116
  yaml.llm?.apiKey,
1960
2117
  legacy.llm?.apiKey,
1961
- process.env.OPENAI_API_KEY,
1962
- process.env.ANTHROPIC_API_KEY,
1963
- openRouterMemoryLlmApiKey
2118
+ // Never borrow another provider's credentials for the Atlas Cloud preset.
2119
+ isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
2120
+ isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
2121
+ isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
1964
2122
  );
1965
2123
  const resolved = {
1966
2124
  agent: {
@@ -2139,7 +2297,8 @@ function getEnvSourceNames() {
2139
2297
  "MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
2140
2298
  "MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
2141
2299
  "MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
2142
- "OPENROUTER_API_KEY"
2300
+ "OPENROUTER_API_KEY",
2301
+ "ATLASCLOUD_API_KEY"
2143
2302
  ].filter((name) => process.env[name]);
2144
2303
  }
2145
2304
  function isOpenRouterUrl(value) {
@@ -2970,80 +3129,13 @@ var init_provider = __esm({
2970
3129
  openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
2971
3130
  anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
2972
3131
  openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
3132
+ atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
2973
3133
  custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
2974
3134
  };
2975
3135
  currentConfig = null;
2976
3136
  }
2977
3137
  });
2978
3138
 
2979
- // src/store/sqlite-reliability.ts
2980
- function isTransientSqliteError(error) {
2981
- const code = error?.code;
2982
- if (typeof code === "string") {
2983
- return /^SQLITE_BUSY(?:_|$)/i.test(code);
2984
- }
2985
- return error instanceof Error && /\bdatabase is locked\b|\bdatabase is busy\b/i.test(error.message);
2986
- }
2987
- function isSqliteUnavailableError(error) {
2988
- return error instanceof SqliteUnavailableError || error instanceof Error && /SQLite is not available|better-sqlite3.*failed|node:sqlite.*failed|bun:sqlite.*failed/i.test(error.message);
2989
- }
2990
- function degradedReadError(storeName) {
2991
- return new Error(`[memorix] Cannot read ${storeName}: SQLite backend unavailable (memory is not loaded)`);
2992
- }
2993
- function degradedWriteError(storeName) {
2994
- return new Error(`[memorix] Cannot write ${storeName}: SQLite backend unavailable (degraded mode; read-only)`);
2995
- }
2996
- function formatSqliteFailure(error) {
2997
- return error instanceof Error && error.message ? error.message : String(error);
2998
- }
2999
- function delay(ms) {
3000
- return new Promise((resolve2) => setTimeout(resolve2, ms));
3001
- }
3002
- async function retrySqliteBusy(operation, label) {
3003
- for (let attempt = 0; ; attempt++) {
3004
- try {
3005
- return await operation();
3006
- } catch (error) {
3007
- if (!isTransientSqliteError(error) || attempt >= SQLITE_BUSY_RETRY_DELAYS_MS.length) throw error;
3008
- const waitMs = SQLITE_BUSY_RETRY_DELAYS_MS[attempt];
3009
- console.error(
3010
- `[memorix] ${label} SQLite busy (attempt ${attempt + 1}/${SQLITE_BUSY_RETRY_DELAYS_MS.length + 1}), retrying in ${waitMs}ms`
3011
- );
3012
- await delay(waitMs);
3013
- }
3014
- }
3015
- }
3016
- async function initializeSqliteStore(factory, dataDir, label) {
3017
- try {
3018
- loadBetterSqlite3();
3019
- } catch (error) {
3020
- throw new SqliteUnavailableError(error);
3021
- }
3022
- return retrySqliteBusy(async () => {
3023
- const store = factory();
3024
- await store.init(dataDir);
3025
- return store;
3026
- }, label);
3027
- }
3028
- var SQLITE_BUSY_RETRY_DELAYS_MS, SqliteUnavailableError;
3029
- var init_sqlite_reliability = __esm({
3030
- "src/store/sqlite-reliability.ts"() {
3031
- "use strict";
3032
- init_esm_shims();
3033
- init_sqlite_db();
3034
- SQLITE_BUSY_RETRY_DELAYS_MS = [50, 150, 400, 1e3, 2500];
3035
- SqliteUnavailableError = class extends Error {
3036
- code = "MEMORIX_SQLITE_UNAVAILABLE";
3037
- constructor(cause) {
3038
- super(
3039
- cause instanceof Error && cause.message ? cause.message : "[memorix] SQLite is unavailable (install a supported SQLite runtime)"
3040
- );
3041
- this.name = "SqliteUnavailableError";
3042
- }
3043
- };
3044
- }
3045
- });
3046
-
3047
3139
  // src/store/file-lock.ts
3048
3140
  import { promises as fs2 } from "fs";
3049
3141
  import { randomUUID } from "crypto";
@@ -3946,12 +4038,45 @@ function textHash(text2) {
3946
4038
  async function loadDiskCache() {
3947
4039
  try {
3948
4040
  const raw = await readFile(CACHE_FILE, "utf-8");
4041
+ if (Buffer.byteLength(raw, "utf8") > MAX_CACHE_FILE_BYTES) {
4042
+ console.error("[memorix] FastEmbed cache exceeds the disk load limit; starting with an empty cache");
4043
+ return;
4044
+ }
3949
4045
  const entries = JSON.parse(raw);
3950
- for (const [k, v] of entries) cache.set(k, v);
3951
- console.error(`[memorix] Loaded ${entries.length} cached embeddings from disk`);
4046
+ if (!Array.isArray(entries)) return;
4047
+ for (const entry of entries) {
4048
+ if (!Array.isArray(entry) || typeof entry[0] !== "string" || !isVector(entry[1])) continue;
4049
+ cacheSet(entry[0], entry[1], false);
4050
+ }
4051
+ console.error(`[memorix] Loaded ${cache.size} cached embeddings from disk`);
3952
4052
  } catch {
3953
4053
  }
3954
4054
  }
4055
+ function isVector(value) {
4056
+ return Array.isArray(value) && value.every((entry) => typeof entry === "number");
4057
+ }
4058
+ function maxCachePayloadBytes() {
4059
+ const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
4060
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES;
4061
+ }
4062
+ function cacheSet(hash4, value, markDirty = true) {
4063
+ const incomingBytes = value.length * 8;
4064
+ if (incomingBytes > maxCachePayloadBytes()) return;
4065
+ const existing = cache.get(hash4);
4066
+ if (existing) cachePayloadBytes -= existing.length * 8;
4067
+ else {
4068
+ while (cache.size >= MAX_CACHE_SIZE || cachePayloadBytes + incomingBytes > maxCachePayloadBytes()) {
4069
+ const firstKey = cache.keys().next().value;
4070
+ if (firstKey === void 0) break;
4071
+ const old = cache.get(firstKey);
4072
+ cache.delete(firstKey);
4073
+ if (old) cachePayloadBytes -= old.length * 8;
4074
+ }
4075
+ }
4076
+ cache.set(hash4, value);
4077
+ cachePayloadBytes += incomingBytes;
4078
+ if (markDirty) diskCacheDirty = true;
4079
+ }
3955
4080
  async function saveDiskCache() {
3956
4081
  if (!diskCacheDirty) return;
3957
4082
  try {
@@ -3962,7 +4087,7 @@ async function saveDiskCache() {
3962
4087
  } catch {
3963
4088
  }
3964
4089
  }
3965
- var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, diskCacheDirty, FastEmbedProvider;
4090
+ var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, DEFAULT_CACHE_PAYLOAD_BYTES, MAX_CACHE_FILE_BYTES, cachePayloadBytes, diskCacheDirty, FastEmbedProvider;
3966
4091
  var init_fastembed_provider = __esm({
3967
4092
  "src/embedding/fastembed-provider.ts"() {
3968
4093
  "use strict";
@@ -3972,6 +4097,9 @@ var init_fastembed_provider = __esm({
3972
4097
  CACHE_FILE = join2(CACHE_DIR, ".embedding-cache.json");
3973
4098
  cache = /* @__PURE__ */ new Map();
3974
4099
  MAX_CACHE_SIZE = 5e3;
4100
+ DEFAULT_CACHE_PAYLOAD_BYTES = 64 * 1024 * 1024;
4101
+ MAX_CACHE_FILE_BYTES = 128 * 1024 * 1024;
4102
+ cachePayloadBytes = 0;
3975
4103
  diskCacheDirty = false;
3976
4104
  FastEmbedProvider = class _FastEmbedProvider {
3977
4105
  name = "fastembed-bge-small";
@@ -4013,7 +4141,7 @@ var init_fastembed_provider = __esm({
4013
4141
  if (result.length !== this.dimensions) {
4014
4142
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
4015
4143
  }
4016
- this.cacheSet(hash4, result);
4144
+ cacheSet(hash4, result);
4017
4145
  return result;
4018
4146
  }
4019
4147
  async embedBatch(texts) {
@@ -4038,7 +4166,7 @@ var init_fastembed_provider = __esm({
4038
4166
  const originalIdx = uncachedIndices[batchIdx];
4039
4167
  const plain = Array.from(vec);
4040
4168
  results[originalIdx] = plain;
4041
- this.cacheSet(textHash(uncachedTexts[batchIdx]), plain);
4169
+ cacheSet(textHash(uncachedTexts[batchIdx]), plain);
4042
4170
  batchIdx++;
4043
4171
  }
4044
4172
  }
@@ -4046,14 +4174,6 @@ var init_fastembed_provider = __esm({
4046
4174
  }
4047
4175
  return results;
4048
4176
  }
4049
- cacheSet(hash4, value) {
4050
- if (cache.size >= MAX_CACHE_SIZE) {
4051
- const firstKey = cache.keys().next().value;
4052
- if (firstKey !== void 0) cache.delete(firstKey);
4053
- }
4054
- cache.set(hash4, value);
4055
- diskCacheDirty = true;
4056
- }
4057
4177
  };
4058
4178
  }
4059
4179
  });
@@ -4063,7 +4183,15 @@ var transformers_provider_exports = {};
4063
4183
  __export(transformers_provider_exports, {
4064
4184
  TransformersProvider: () => TransformersProvider
4065
4185
  });
4066
- var cache2, MAX_CACHE_SIZE2, TransformersProvider;
4186
+ import { createHash as createHash2 } from "crypto";
4187
+ function cacheKey2(text2) {
4188
+ return createHash2("sha256").update(text2).digest("hex");
4189
+ }
4190
+ function maxCachePayloadBytes2() {
4191
+ const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
4192
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES2;
4193
+ }
4194
+ var cache2, MAX_CACHE_SIZE2, DEFAULT_CACHE_PAYLOAD_BYTES2, cachePayloadBytes2, TransformersProvider;
4067
4195
  var init_transformers_provider = __esm({
4068
4196
  "src/embedding/transformers-provider.ts"() {
4069
4197
  "use strict";
@@ -4071,6 +4199,8 @@ var init_transformers_provider = __esm({
4071
4199
  init_provider2();
4072
4200
  cache2 = /* @__PURE__ */ new Map();
4073
4201
  MAX_CACHE_SIZE2 = 5e3;
4202
+ DEFAULT_CACHE_PAYLOAD_BYTES2 = 64 * 1024 * 1024;
4203
+ cachePayloadBytes2 = 0;
4074
4204
  TransformersProvider = class _TransformersProvider {
4075
4205
  name = "transformers-minilm";
4076
4206
  dimensions = 384;
@@ -4105,7 +4235,7 @@ var init_transformers_provider = __esm({
4105
4235
  return Promise.all(inputs.map((input) => this.embedInput(input, options)));
4106
4236
  }
4107
4237
  async embed(text2) {
4108
- const cached = cache2.get(text2);
4238
+ const cached = cache2.get(cacheKey2(text2));
4109
4239
  if (cached) return cached;
4110
4240
  const output = await this.extractor(text2, {
4111
4241
  pooling: "mean",
@@ -4115,7 +4245,7 @@ var init_transformers_provider = __esm({
4115
4245
  if (result.length !== this.dimensions) {
4116
4246
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
4117
4247
  }
4118
- this.cacheSet(text2, result);
4248
+ this.cacheSet(cacheKey2(text2), result);
4119
4249
  return result;
4120
4250
  }
4121
4251
  async embedBatch(texts) {
@@ -4123,7 +4253,7 @@ var init_transformers_provider = __esm({
4123
4253
  const uncachedIndices = [];
4124
4254
  const uncachedTexts = [];
4125
4255
  for (let i2 = 0; i2 < texts.length; i2++) {
4126
- const cached = cache2.get(texts[i2]);
4256
+ const cached = cache2.get(cacheKey2(texts[i2]));
4127
4257
  if (cached) {
4128
4258
  results[i2] = cached;
4129
4259
  } else {
@@ -4141,17 +4271,27 @@ var init_transformers_provider = __esm({
4141
4271
  const vec = Array.from(allVecs[i2]);
4142
4272
  const originalIdx = uncachedIndices[i2];
4143
4273
  results[originalIdx] = vec;
4144
- this.cacheSet(uncachedTexts[i2], vec);
4274
+ this.cacheSet(cacheKey2(uncachedTexts[i2]), vec);
4145
4275
  }
4146
4276
  }
4147
4277
  return results;
4148
4278
  }
4149
4279
  cacheSet(key, value) {
4150
- if (cache2.size >= MAX_CACHE_SIZE2) {
4151
- const firstKey = cache2.keys().next().value;
4152
- if (firstKey !== void 0) cache2.delete(firstKey);
4280
+ const incomingBytes = value.length * 8;
4281
+ if (incomingBytes > maxCachePayloadBytes2()) return;
4282
+ const existing = cache2.get(key);
4283
+ if (existing) cachePayloadBytes2 -= existing.length * 8;
4284
+ else {
4285
+ while (cache2.size >= MAX_CACHE_SIZE2 || cachePayloadBytes2 + incomingBytes > maxCachePayloadBytes2()) {
4286
+ const firstKey = cache2.keys().next().value;
4287
+ if (firstKey === void 0) break;
4288
+ const old = cache2.get(firstKey);
4289
+ cache2.delete(firstKey);
4290
+ if (old) cachePayloadBytes2 -= old.length * 8;
4291
+ }
4153
4292
  }
4154
4293
  cache2.set(key, value);
4294
+ cachePayloadBytes2 += incomingBytes;
4155
4295
  }
4156
4296
  };
4157
4297
  }
@@ -4173,7 +4313,7 @@ __export(api_provider_exports, {
4173
4313
  saveDiskCacheNow: () => saveDiskCacheNow,
4174
4314
  seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
4175
4315
  });
4176
- import { createHash as createHash2 } from "crypto";
4316
+ import { createHash as createHash3 } from "crypto";
4177
4317
  import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
4178
4318
  import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
4179
4319
  import { join as join3 } from "path";
@@ -4200,7 +4340,7 @@ function cacheStatFile() {
4200
4340
  function payloadBytes(vector) {
4201
4341
  return vector.length * BYTES_PER_DIM;
4202
4342
  }
4203
- function maxCachePayloadBytes() {
4343
+ function maxCachePayloadBytes3() {
4204
4344
  const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
4205
4345
  if (raw) {
4206
4346
  const parsed = Number.parseInt(raw, 10);
@@ -4210,7 +4350,7 @@ function maxCachePayloadBytes() {
4210
4350
  }
4211
4351
  function maxEntriesForDimensions(dimensions) {
4212
4352
  const dim = Math.max(1, Math.floor(dimensions));
4213
- const byBytes = Math.floor(maxCachePayloadBytes() / (dim * BYTES_PER_DIM));
4353
+ const byBytes = Math.floor(maxCachePayloadBytes3() / (dim * BYTES_PER_DIM));
4214
4354
  return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
4215
4355
  }
4216
4356
  function rememberDimensions(vector) {
@@ -4223,13 +4363,15 @@ function evictOldest() {
4223
4363
  if (firstKey === void 0) return;
4224
4364
  const old = cache3.get(firstKey);
4225
4365
  cache3.delete(firstKey);
4226
- if (old) cachePayloadBytes -= payloadBytes(old);
4366
+ if (old) cachePayloadBytes3 -= payloadBytes(old);
4227
4367
  }
4228
4368
  function evictToFit(incomingBytes, incomingDims) {
4369
+ if (incomingBytes > maxCachePayloadBytes3()) return false;
4229
4370
  const limit2 = maxEntriesForDimensions(incomingDims);
4230
- while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes + incomingBytes > maxCachePayloadBytes())) {
4371
+ while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes3 + incomingBytes > maxCachePayloadBytes3())) {
4231
4372
  evictOldest();
4232
4373
  }
4374
+ return true;
4233
4375
  }
4234
4376
  function isNumberArray(value) {
4235
4377
  return Array.isArray(value) && value.every((entry) => typeof entry === "number");
@@ -4256,12 +4398,12 @@ function cacheInsert(hash4, value, dirty) {
4256
4398
  const incoming = payloadBytes(value);
4257
4399
  const existing = cache3.get(hash4);
4258
4400
  if (existing) {
4259
- cachePayloadBytes -= payloadBytes(existing);
4401
+ cachePayloadBytes3 -= payloadBytes(existing);
4260
4402
  cache3.delete(hash4);
4261
4403
  }
4262
- evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
4404
+ if (!evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS)) return;
4263
4405
  cache3.set(hash4, value);
4264
- cachePayloadBytes += incoming;
4406
+ cachePayloadBytes3 += incoming;
4265
4407
  if (dirty) diskCacheDirty2 = true;
4266
4408
  }
4267
4409
  async function readCacheStat() {
@@ -4297,7 +4439,7 @@ function cacheNamespace(config) {
4297
4439
  ].join("|");
4298
4440
  }
4299
4441
  function textHash2(text2, namespace) {
4300
- return createHash2("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
4442
+ return createHash3("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
4301
4443
  }
4302
4444
  function inputIdentity(input, options = {}) {
4303
4445
  return JSON.stringify({
@@ -4639,7 +4781,7 @@ function getApiEmbeddingDiskCacheLoadCountForTests() {
4639
4781
  }
4640
4782
  function resetApiEmbeddingCacheForTests() {
4641
4783
  cache3.clear();
4642
- cachePayloadBytes = 0;
4784
+ cachePayloadBytes3 = 0;
4643
4785
  cacheDimensions = null;
4644
4786
  diskCacheEntryCount = 0;
4645
4787
  diskCacheLoaded = false;
@@ -4650,14 +4792,14 @@ function resetApiEmbeddingCacheForTests() {
4650
4792
  }
4651
4793
  function seedApiEmbeddingCacheForTests(entries) {
4652
4794
  cache3.clear();
4653
- cachePayloadBytes = 0;
4795
+ cachePayloadBytes3 = 0;
4654
4796
  cacheDimensions = null;
4655
4797
  for (const [key, value] of entries) cacheInsert(key, value, true);
4656
4798
  diskCacheLoaded = true;
4657
4799
  diskCacheDirty2 = true;
4658
4800
  }
4659
4801
  function getApiEmbeddingCachePayloadBytesForTests() {
4660
- return cachePayloadBytes;
4802
+ return cachePayloadBytes3;
4661
4803
  }
4662
4804
  function getApiEmbeddingJsonlLineCountCallsForTests() {
4663
4805
  return jsonlLineCountCalls;
@@ -4831,7 +4973,7 @@ function scheduleDiskSave() {
4831
4973
  diskSaveTimer = null;
4832
4974
  }, DISK_SAVE_DEBOUNCE_MS);
4833
4975
  }
4834
- function cacheSet(hash4, value) {
4976
+ function cacheSet2(hash4, value) {
4835
4977
  cacheInsert(hash4, value, true);
4836
4978
  }
4837
4979
  function resolveEnvEmbeddingApiKey() {
@@ -4951,7 +5093,7 @@ async function waitForRetry(waitMs, signal) {
4951
5093
  abortSignal.addEventListener("abort", onAbort, { once: true });
4952
5094
  });
4953
5095
  }
4954
- 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;
5096
+ 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;
4955
5097
  var init_api_provider = __esm({
4956
5098
  "src/embedding/api-provider.ts"() {
4957
5099
  "use strict";
@@ -4963,7 +5105,7 @@ var init_api_provider = __esm({
4963
5105
  BYTES_PER_DIM = 8;
4964
5106
  DEFAULT_ASSUMED_DIMENSIONS = 4096;
4965
5107
  MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
4966
- cachePayloadBytes = 0;
5108
+ cachePayloadBytes3 = 0;
4967
5109
  cacheDimensions = null;
4968
5110
  diskCacheEntryCount = 0;
4969
5111
  diskCacheDirty2 = false;
@@ -5148,7 +5290,7 @@ var init_api_provider = __esm({
5148
5290
  } else {
5149
5291
  embedding = await apiCall();
5150
5292
  }
5151
- cacheSet(hash4, embedding);
5293
+ cacheSet2(hash4, embedding);
5152
5294
  scheduleDiskSave();
5153
5295
  return embedding;
5154
5296
  }
@@ -5196,7 +5338,7 @@ var init_api_provider = __esm({
5196
5338
  for (const item of response.data) {
5197
5339
  const originalIdx = chunkIndices[item.index];
5198
5340
  results[originalIdx] = item.embedding;
5199
- cacheSet(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
5341
+ cacheSet2(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
5200
5342
  }
5201
5343
  } catch (error) {
5202
5344
  const providerLimit = parseBatchLimit(error);
@@ -5274,7 +5416,7 @@ var init_api_provider = __esm({
5274
5416
  throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d; dimension mismatch`);
5275
5417
  }
5276
5418
  this.trackUsage(response);
5277
- cacheSet(hash4, embedding);
5419
+ cacheSet2(hash4, embedding);
5278
5420
  scheduleDiskSave();
5279
5421
  return embedding;
5280
5422
  }
@@ -6195,7 +6337,7 @@ var init_timeout = __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,
@@ -9282,13 +9434,13 @@ __export(workspace_exports, {
9282
9434
  loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
9283
9435
  resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
9284
9436
  });
9285
- import { createHash as createHash5 } from "crypto";
9437
+ import { createHash as createHash6 } from "crypto";
9286
9438
  import { execFile } from "child_process";
9287
9439
  import { promises as fs6 } from "fs";
9288
9440
  import path11 from "path";
9289
9441
  import { promisify } from "util";
9290
9442
  function hash(value) {
9291
- return createHash5("sha256").update(value).digest("hex");
9443
+ return createHash6("sha256").update(value).digest("hex");
9292
9444
  }
9293
9445
  function workspaceId(projectId, mode) {
9294
9446
  return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
@@ -10423,14 +10575,14 @@ var init_types2 = __esm({
10423
10575
  });
10424
10576
 
10425
10577
  // src/media/asset-store.ts
10426
- import { createHash as createHash6, randomUUID as randomUUID6 } from "crypto";
10578
+ import { createHash as createHash7, randomUUID as randomUUID6 } from "crypto";
10427
10579
  import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
10428
10580
  import path12 from "path";
10429
10581
  function mediaRoot(dataDir) {
10430
10582
  return path12.resolve(dataDir, "media");
10431
10583
  }
10432
10584
  function projectStorageKey(projectId) {
10433
- return createHash6("sha256").update(projectId).digest("hex").slice(0, 16);
10585
+ return createHash7("sha256").update(projectId).digest("hex").slice(0, 16);
10434
10586
  }
10435
10587
  function validateUnderRoot(root, candidate) {
10436
10588
  const resolved = path12.resolve(candidate);
@@ -10539,7 +10691,7 @@ async function importMediaBuffer(input) {
10539
10691
  if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
10540
10692
  if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
10541
10693
  const detected = detectMedia(input.bytes.subarray(0, 32));
10542
- const sha256 = createHash6("sha256").update(input.bytes).digest("hex");
10694
+ const sha256 = createHash7("sha256").update(input.bytes).digest("hex");
10543
10695
  return importKnownMedia({
10544
10696
  dataDir: input.dataDir,
10545
10697
  projectId: input.projectId,
@@ -10557,7 +10709,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
10557
10709
  if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
10558
10710
  const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
10559
10711
  if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
10560
- const sha256 = createHash6("sha256").update(bytes).digest("hex");
10712
+ const sha256 = createHash7("sha256").update(bytes).digest("hex");
10561
10713
  if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
10562
10714
  return bytes;
10563
10715
  }
@@ -69253,16 +69405,16 @@ var require_jwtaccess = __commonJS({
69253
69405
  * @returns A string that returns the cached key.
69254
69406
  */
69255
69407
  getCachedKey(url, scopes) {
69256
- let cacheKey = url;
69408
+ let cacheKey3 = url;
69257
69409
  if (scopes && Array.isArray(scopes) && scopes.length) {
69258
- cacheKey = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
69410
+ cacheKey3 = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
69259
69411
  } else if (typeof scopes === "string") {
69260
- cacheKey = url ? `${url}_${scopes}` : scopes;
69412
+ cacheKey3 = url ? `${url}_${scopes}` : scopes;
69261
69413
  }
69262
- if (!cacheKey) {
69414
+ if (!cacheKey3) {
69263
69415
  throw Error("Scopes or url must be provided");
69264
69416
  }
69265
- return cacheKey;
69417
+ return cacheKey3;
69266
69418
  }
69267
69419
  /**
69268
69420
  * Get a non-expired access token, after refreshing if necessary.
@@ -75808,7 +75960,7 @@ var require_websocket = __commonJS({
75808
75960
  var http3 = __require("http");
75809
75961
  var net = __require("net");
75810
75962
  var tls = __require("tls");
75811
- var { randomBytes, createHash: createHash16 } = __require("crypto");
75963
+ var { randomBytes, createHash: createHash17 } = __require("crypto");
75812
75964
  var { Duplex, Readable: Readable2 } = __require("stream");
75813
75965
  var { URL: URL2 } = __require("url");
75814
75966
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -76476,7 +76628,7 @@ var require_websocket = __commonJS({
76476
76628
  abortHandshake(websocket, socket, "Invalid Upgrade header");
76477
76629
  return;
76478
76630
  }
76479
- const digest2 = createHash16("sha1").update(key + GUID).digest("base64");
76631
+ const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
76480
76632
  if (res.headers["sec-websocket-accept"] !== digest2) {
76481
76633
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
76482
76634
  return;
@@ -76848,7 +77000,7 @@ var require_websocket_server = __commonJS({
76848
77000
  var EventEmitter = __require("events");
76849
77001
  var http3 = __require("http");
76850
77002
  var { Duplex } = __require("stream");
76851
- var { createHash: createHash16 } = __require("crypto");
77003
+ var { createHash: createHash17 } = __require("crypto");
76852
77004
  var extension3 = require_extension();
76853
77005
  var PerMessageDeflate2 = require_permessage_deflate();
76854
77006
  var subprotocol2 = require_subprotocol();
@@ -77155,7 +77307,7 @@ var require_websocket_server = __commonJS({
77155
77307
  );
77156
77308
  }
77157
77309
  if (this._state > RUNNING) return abortHandshake(socket, 503);
77158
- const digest2 = createHash16("sha1").update(key + GUID).digest("base64");
77310
+ const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
77159
77311
  const headers = [
77160
77312
  "HTTP/1.1 101 Switching Protocols",
77161
77313
  "Upgrade: websocket",
@@ -145734,9 +145886,9 @@ var init_long_term = __esm({
145734
145886
  });
145735
145887
 
145736
145888
  // src/codegraph/ids.ts
145737
- import { createHash as createHash7 } from "crypto";
145889
+ import { createHash as createHash8 } from "crypto";
145738
145890
  function digest(input) {
145739
- return createHash7("sha256").update(input).digest("hex").slice(0, 16);
145891
+ return createHash8("sha256").update(input).digest("hex").slice(0, 16);
145740
145892
  }
145741
145893
  function normalizeCodePath(path23) {
145742
145894
  return path23.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
@@ -146784,7 +146936,7 @@ var init_store = __esm({
146784
146936
 
146785
146937
  // src/codegraph/code-state.ts
146786
146938
  import { execFile as execFile2 } from "child_process";
146787
- import { createHash as createHash8 } from "crypto";
146939
+ import { createHash as createHash9 } from "crypto";
146788
146940
  import { promisify as promisify3 } from "util";
146789
146941
  async function runGit(rootPath, args) {
146790
146942
  try {
@@ -146813,7 +146965,7 @@ function changedPathCount(status) {
146813
146965
  return count2;
146814
146966
  }
146815
146967
  function fingerprint(baseRevision, status) {
146816
- return createHash8("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
146968
+ return createHash9("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
146817
146969
  }
146818
146970
  async function collectCodeStateSnapshot(input) {
146819
146971
  const [revision, status] = await Promise.all([
@@ -146907,12 +147059,12 @@ var init_exclude3 = __esm({
146907
147059
  });
146908
147060
 
146909
147061
  // src/codegraph/semantic-provider.ts
146910
- import { createHash as createHash9 } from "crypto";
147062
+ import { createHash as createHash10 } from "crypto";
146911
147063
  import "fs";
146912
147064
  import { resolve } from "path";
146913
147065
  import ts from "typescript";
146914
147066
  function hashText(value) {
146915
- return createHash9("sha256").update(value).digest("hex");
147067
+ return createHash10("sha256").update(value).digest("hex");
146916
147068
  }
146917
147069
  function canonicalPath(value) {
146918
147070
  const normalized = resolve(value).replace(/\\/g, "/");
@@ -147257,11 +147409,11 @@ __export(lite_provider_exports, {
147257
147409
  indexProjectLite: () => indexProjectLite,
147258
147410
  refreshProjectLite: () => refreshProjectLite
147259
147411
  });
147260
- import { createHash as createHash10 } from "crypto";
147412
+ import { createHash as createHash11 } from "crypto";
147261
147413
  import { existsSync as existsSync12, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
147262
147414
  import { join as join4, relative as relative2 } from "path";
147263
147415
  function hashText2(text2) {
147264
- return createHash10("sha256").update(text2).digest("hex");
147416
+ return createHash11("sha256").update(text2).digest("hex");
147265
147417
  }
147266
147418
  function extension2(path23) {
147267
147419
  const index = path23.lastIndexOf(".");
@@ -147894,7 +148046,7 @@ var claim_store_exports = {};
147894
148046
  __export(claim_store_exports, {
147895
148047
  ClaimStore: () => ClaimStore
147896
148048
  });
147897
- import { createHash as createHash11, randomUUID as randomUUID12 } from "crypto";
148049
+ import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
147898
148050
  function optionalText3(value) {
147899
148051
  return typeof value === "string" && value ? value : void 0;
147900
148052
  }
@@ -147947,7 +148099,7 @@ function rowToEvent3(row) {
147947
148099
  };
147948
148100
  }
147949
148101
  function evidenceKey(input) {
147950
- return createHash11("sha256").update(JSON.stringify([
148102
+ return createHash12("sha256").update(JSON.stringify([
147951
148103
  input.evidenceKind,
147952
148104
  input.evidenceId,
147953
148105
  input.relation,
@@ -148145,7 +148297,7 @@ __export(claims_exports, {
148145
148297
  supersedeClaim: () => supersedeClaim,
148146
148298
  writeClaim: () => writeClaim
148147
148299
  });
148148
- import { createHash as createHash12, randomUUID as randomUUID13 } from "crypto";
148300
+ import { createHash as createHash13, randomUUID as randomUUID13 } from "crypto";
148149
148301
  function compactText2(value, field) {
148150
148302
  if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
148151
148303
  const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
@@ -148157,7 +148309,7 @@ function normalizedTerm(value) {
148157
148309
  return compactText2(value, "identity").toLocaleLowerCase("en-US");
148158
148310
  }
148159
148311
  function hashIdentity(parts) {
148160
- return createHash12("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
148312
+ return createHash13("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
148161
148313
  }
148162
148314
  function buildClaimIdentity(input) {
148163
148315
  const subject = normalizedTerm(input.subject);
@@ -148398,7 +148550,7 @@ function supersedeClaim(store, input) {
148398
148550
  });
148399
148551
  }
148400
148552
  function hashObservation(observation) {
148401
- return createHash12("sha256").update(JSON.stringify([
148553
+ return createHash13("sha256").update(JSON.stringify([
148402
148554
  observation.title,
148403
148555
  observation.narrative,
148404
148556
  observation.facts,
@@ -148642,11 +148794,11 @@ var init_frontmatter = __esm({
148642
148794
  });
148643
148795
 
148644
148796
  // src/knowledge/markdown.ts
148645
- import { createHash as createHash13 } from "crypto";
148797
+ import { createHash as createHash14 } from "crypto";
148646
148798
  import { promises as fs10 } from "fs";
148647
148799
  import path19 from "path";
148648
148800
  function hashContent(content) {
148649
- return createHash13("sha256").update(content).digest("hex");
148801
+ return createHash14("sha256").update(content).digest("hex");
148650
148802
  }
148651
148803
  function stringField(data, key) {
148652
148804
  const value = data[key];
@@ -148772,11 +148924,11 @@ __export(wiki_exports, {
148772
148924
  lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
148773
148925
  readKnowledgePage: () => readKnowledgePage
148774
148926
  });
148775
- import { createHash as createHash14 } from "crypto";
148927
+ import { createHash as createHash15 } from "crypto";
148776
148928
  import { promises as fs11 } from "fs";
148777
148929
  import path20 from "path";
148778
148930
  function hash2(value) {
148779
- return createHash14("sha256").update(value).digest("hex");
148931
+ return createHash15("sha256").update(value).digest("hex");
148780
148932
  }
148781
148933
  function now() {
148782
148934
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -149633,11 +149785,11 @@ __export(workflows_exports, {
149633
149785
  syncCanonicalWorkflows: () => syncCanonicalWorkflows,
149634
149786
  writeCanonicalWorkflow: () => writeCanonicalWorkflow
149635
149787
  });
149636
- import { createHash as createHash15 } from "crypto";
149788
+ import { createHash as createHash16 } from "crypto";
149637
149789
  import { promises as fs12 } from "fs";
149638
149790
  import path21 from "path";
149639
149791
  function hash3(value) {
149640
- return createHash15("sha256").update(value).digest("hex");
149792
+ return createHash16("sha256").update(value).digest("hex");
149641
149793
  }
149642
149794
  function now2() {
149643
149795
  return (/* @__PURE__ */ new Date()).toISOString();