memorix 1.9.5 → 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 (62) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +6 -1
  3. package/README.zh-CN.md +6 -1
  4. package/dist/cli/index.js +1647 -264
  5. package/dist/index.d.ts +12 -7
  6. package/dist/index.js +952 -182
  7. package/dist/maintenance-runner.js +243 -103
  8. package/dist/media-audio-runner.js +243 -103
  9. package/dist/media-video-runner.js +243 -103
  10. package/dist/memcode-runtime/CHANGELOG.md +42 -0
  11. package/dist/sdk.js +871 -157
  12. package/dist/vector-backfill-runner.js +243 -103
  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/sqlite-db.ts +144 -4
  62. package/src/team/team-store.ts +62 -27
@@ -380,11 +380,21 @@ function applySchemaMigrations(db2) {
380
380
  apply();
381
381
  }
382
382
  }
383
+ function normalizeDataDir(dataDir) {
384
+ return path3.resolve(dataDir);
385
+ }
386
+ function touchDatabase(normalized, db2) {
387
+ _dbCache.delete(normalized);
388
+ _dbCache.set(normalized, db2);
389
+ }
383
390
  function getDatabase(dataDir) {
384
- const normalized = path3.resolve(dataDir);
391
+ const normalized = normalizeDataDir(dataDir);
385
392
  assertNotHomeDataDir(normalized);
386
393
  const existing = _dbCache.get(normalized);
387
- if (existing) return existing;
394
+ if (existing) {
395
+ touchDatabase(normalized, existing);
396
+ return existing;
397
+ }
388
398
  loadBetterSqlite3();
389
399
  fs.mkdirSync(dataDir, { recursive: true });
390
400
  const dbPath = path3.join(dataDir, "memorix.db");
@@ -414,6 +424,8 @@ function getDatabase(dataDir) {
414
424
  db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
415
425
  db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
416
426
  db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
427
+ db2.exec(CREATE_TASK_CONTINUITY_EVENTS_TABLE);
428
+ db2.exec(CREATE_AGENT_EFFECTS_TABLE);
417
429
  try {
418
430
  db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
419
431
  } catch {
@@ -452,7 +464,7 @@ function getDatabase(dataDir) {
452
464
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
453
465
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
454
466
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
455
- _dbCache.set(normalized, db2);
467
+ touchDatabase(normalized, db2);
456
468
  return db2;
457
469
  } catch (error) {
458
470
  try {
@@ -470,8 +482,9 @@ function closeAllDatabases() {
470
482
  }
471
483
  _dbCache.delete(key);
472
484
  }
485
+ _dbLeases.clear();
473
486
  }
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;
487
+ 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
488
  var init_sqlite_db = __esm({
476
489
  "src/store/sqlite-db.ts"() {
477
490
  "use strict";
@@ -1188,6 +1201,43 @@ CREATE TABLE IF NOT EXISTS memory_feedback_events (
1188
1201
  delta REAL NOT NULL DEFAULT 0,
1189
1202
  observed_at TEXT NOT NULL
1190
1203
  );
1204
+ `;
1205
+ CREATE_TASK_CONTINUITY_EVENTS_TABLE = `
1206
+ CREATE TABLE IF NOT EXISTS task_continuity_events (
1207
+ id TEXT PRIMARY KEY,
1208
+ project_id TEXT NOT NULL,
1209
+ task_id TEXT NOT NULL,
1210
+ task TEXT NOT NULL,
1211
+ kind TEXT NOT NULL,
1212
+ content TEXT NOT NULL,
1213
+ item_status TEXT,
1214
+ source_ref TEXT,
1215
+ evidence_json TEXT NOT NULL DEFAULT '[]',
1216
+ actor TEXT,
1217
+ created_at TEXT NOT NULL,
1218
+ event_key TEXT,
1219
+ item_key TEXT,
1220
+ supersedes_id TEXT
1221
+ );
1222
+ `;
1223
+ CREATE_AGENT_EFFECTS_TABLE = `
1224
+ CREATE TABLE IF NOT EXISTS agent_effects (
1225
+ id TEXT PRIMARY KEY,
1226
+ pipeline_id TEXT NOT NULL,
1227
+ task_id TEXT NOT NULL,
1228
+ attempt INTEGER NOT NULL,
1229
+ effect_key TEXT NOT NULL,
1230
+ tool TEXT NOT NULL,
1231
+ risk_tier TEXT NOT NULL,
1232
+ replay_policy TEXT NOT NULL,
1233
+ status TEXT NOT NULL,
1234
+ call_id TEXT,
1235
+ idempotency_key TEXT NOT NULL,
1236
+ input_fingerprint TEXT,
1237
+ detail TEXT,
1238
+ started_at INTEGER NOT NULL,
1239
+ finished_at INTEGER
1240
+ );
1191
1241
  `;
1192
1242
  CREATE_MCP_BINDINGS_TABLE = `
1193
1243
  CREATE TABLE IF NOT EXISTS mcp_bindings (
@@ -1266,7 +1316,18 @@ CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(projec
1266
1316
  CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
1267
1317
  CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
1268
1318
  CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
1319
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_project_task ON task_continuity_events(project_id, task_id, created_at ASC);
1320
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_project_recent ON task_continuity_events(project_id, created_at DESC);
1321
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_item ON task_continuity_events(project_id, task_id, kind, item_key, created_at DESC);
1322
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
1323
+ ON task_continuity_events(project_id, task_id, event_key)
1324
+ WHERE event_key IS NOT NULL;
1325
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_effect_identity
1326
+ ON agent_effects(pipeline_id, task_id, attempt, effect_key);
1327
+ CREATE INDEX IF NOT EXISTS idx_agent_effect_pipeline ON agent_effects(pipeline_id, started_at ASC);
1269
1328
  CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
1329
+ CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC);
1330
+ CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at);
1270
1331
  CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1271
1332
  ON maintenance_jobs(project_id, kind, dedupe_key)
1272
1333
  WHERE status IN ('pending', 'running', 'retry');
@@ -1437,6 +1498,8 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1437
1498
  db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
1438
1499
  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
1500
  db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
1501
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC)");
1502
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at)");
1440
1503
  }
1441
1504
  },
1442
1505
  {
@@ -1447,9 +1510,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1447
1510
  addColumnIfMissing(db2, "code_symbols", "source", "source TEXT");
1448
1511
  addColumnIfMissing(db2, "code_edges", "source", "source TEXT");
1449
1512
  }
1513
+ },
1514
+ {
1515
+ id: "1.9-continuity-v2",
1516
+ apply: (db2) => {
1517
+ addColumnIfMissing(db2, "task_continuity_events", "event_key", "event_key TEXT");
1518
+ addColumnIfMissing(db2, "task_continuity_events", "item_key", "item_key TEXT");
1519
+ addColumnIfMissing(db2, "task_continuity_events", "supersedes_id", "supersedes_id TEXT");
1520
+ 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)");
1521
+ db2.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
1522
+ ON task_continuity_events(project_id, task_id, event_key)
1523
+ WHERE event_key IS NOT NULL`);
1524
+ }
1450
1525
  }
1451
1526
  ];
1452
1527
  _dbCache = /* @__PURE__ */ new Map();
1528
+ _dbLeases = /* @__PURE__ */ new Map();
1453
1529
  }
1454
1530
  });
1455
1531
 
@@ -1552,15 +1628,20 @@ var init_dotenv_loader = __esm({
1552
1628
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
1553
1629
  import { homedir as homedir2 } from "os";
1554
1630
  import { parse as parseYamlDocument } from "yaml";
1631
+ function cacheKey(homeDir, projectRoot) {
1632
+ return `${homeDir}\0${projectRoot ?? ""}`;
1633
+ }
1555
1634
  function initProjectRoot(root) {
1556
1635
  globalProjectRoot = root;
1557
- configCache.delete(root);
1636
+ configCache.delete(cacheKey(homedir2(), root));
1558
1637
  }
1559
- function loadYamlConfig(projectRoot) {
1638
+ function loadYamlConfig(projectRoot, options = {}) {
1639
+ const homeDir = options.homeDir ?? homedir2();
1560
1640
  const resolvedRoot = projectRoot === null ? null : projectRoot ?? globalProjectRoot ?? null;
1561
- const cached = configCache.get(resolvedRoot ?? null);
1641
+ const key = cacheKey(homeDir, resolvedRoot);
1642
+ const cached = configCache.get(key);
1562
1643
  if (cached) return cached;
1563
- const userYaml = getGlobalYamlPath(homedir2());
1644
+ const userYaml = getGlobalYamlPath(homeDir);
1564
1645
  const projectYaml = resolvedRoot ? getProjectYamlPath(resolvedRoot) : null;
1565
1646
  let userConfig = {};
1566
1647
  let projectConfig = {};
@@ -1592,7 +1673,7 @@ function loadYamlConfig(projectRoot) {
1592
1673
  server: { ...userConfig.server, ...projectConfig.server },
1593
1674
  team: { ...userConfig.team, ...projectConfig.team }
1594
1675
  };
1595
- configCache.set(resolvedRoot ?? null, merged);
1676
+ configCache.set(key, merged);
1596
1677
  return merged;
1597
1678
  }
1598
1679
  function parseYaml(content) {
@@ -1768,9 +1849,9 @@ var init_detector = __esm({
1768
1849
  // src/config/legacy-loader.ts
1769
1850
  import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
1770
1851
  import { homedir as homedir3 } from "os";
1771
- function loadFileConfig() {
1852
+ function loadFileConfig(homeDir = homedir3()) {
1772
1853
  if (cachedConfig !== null) return cachedConfig;
1773
- const configPath = getLegacyConfigJsonPath(homedir3());
1854
+ const configPath = getLegacyConfigJsonPath(homeDir);
1774
1855
  try {
1775
1856
  if (existsSync5(configPath)) {
1776
1857
  cachedConfig = JSON.parse(readFileSync5(configPath, "utf-8"));
@@ -1800,15 +1881,15 @@ import { homedir as homedir4 } from "os";
1800
1881
  function loadTomlConfig(options = {}) {
1801
1882
  const homeDir = options.homeDir ?? homedir4();
1802
1883
  const projectRoot = options.projectRoot ?? null;
1803
- const cacheKey = `${homeDir}\0${projectRoot ?? ""}`;
1804
- const cached = configCache2.get(cacheKey);
1884
+ const cacheKey3 = `${homeDir}\0${projectRoot ?? ""}`;
1885
+ const cached = configCache2.get(cacheKey3);
1805
1886
  if (cached) return cached;
1806
1887
  const userToml = getGlobalConfigTomlPath(homeDir);
1807
1888
  const projectToml = projectRoot ? getProjectConfigTomlPath(projectRoot) : null;
1808
1889
  const userConfig = existsSync6(userToml) ? parseTomlConfig(readFileSync6(userToml, "utf8"), userToml) : {};
1809
1890
  const projectConfig = projectToml && existsSync6(projectToml) ? parseTomlConfig(readFileSync6(projectToml, "utf8"), projectToml) : {};
1810
1891
  const merged = mergeTomlConfig(userConfig, projectConfig);
1811
- configCache2.set(cacheKey, merged);
1892
+ configCache2.set(cacheKey3, merged);
1812
1893
  return merged;
1813
1894
  }
1814
1895
  function mergeTomlConfig(base, override) {
@@ -1929,8 +2010,8 @@ function getResolvedConfig(options = {}) {
1929
2010
  const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
1930
2011
  loadDotenv(projectRoot === null ? void 0 : projectRoot ?? void 0, { userHomeDir: homeDir });
1931
2012
  const toml = loadTomlConfig({ projectRoot: projectRoot ?? null, homeDir });
1932
- const yaml = loadYamlConfig(projectRoot ?? null);
1933
- const legacy = loadFileConfig();
2013
+ const yaml = loadYamlConfig(projectRoot ?? null, { homeDir });
2014
+ const legacy = loadFileConfig(homeDir);
1934
2015
  const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
1935
2016
  const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
1936
2017
  const memoryLlmProvider = first(
@@ -1952,15 +2033,17 @@ function getResolvedConfig(options = {}) {
1952
2033
  legacy.llm?.baseUrl
1953
2034
  );
1954
2035
  const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
2036
+ const isAtlasCloud = memoryLlmProvider === "atlascloud";
1955
2037
  const memoryLlmApiKey = first(
1956
2038
  process.env.MEMORIX_LLM_API_KEY,
1957
2039
  process.env.MEMORIX_API_KEY,
1958
2040
  toml.memory?.llm?.api_key,
1959
2041
  yaml.llm?.apiKey,
1960
2042
  legacy.llm?.apiKey,
1961
- process.env.OPENAI_API_KEY,
1962
- process.env.ANTHROPIC_API_KEY,
1963
- openRouterMemoryLlmApiKey
2043
+ // Never borrow another provider's credentials for the Atlas Cloud preset.
2044
+ isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
2045
+ isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
2046
+ isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
1964
2047
  );
1965
2048
  const resolved = {
1966
2049
  agent: {
@@ -2139,7 +2222,8 @@ function getEnvSourceNames() {
2139
2222
  "MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
2140
2223
  "MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
2141
2224
  "MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
2142
- "OPENROUTER_API_KEY"
2225
+ "OPENROUTER_API_KEY",
2226
+ "ATLASCLOUD_API_KEY"
2143
2227
  ].filter((name) => process.env[name]);
2144
2228
  }
2145
2229
  function isOpenRouterUrl(value) {
@@ -2970,6 +3054,7 @@ var init_provider = __esm({
2970
3054
  openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
2971
3055
  anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
2972
3056
  openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
3057
+ atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
2973
3058
  custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
2974
3059
  };
2975
3060
  currentConfig = null;
@@ -3946,12 +4031,45 @@ function textHash(text2) {
3946
4031
  async function loadDiskCache() {
3947
4032
  try {
3948
4033
  const raw = await readFile(CACHE_FILE, "utf-8");
4034
+ if (Buffer.byteLength(raw, "utf8") > MAX_CACHE_FILE_BYTES) {
4035
+ console.error("[memorix] FastEmbed cache exceeds the disk load limit; starting with an empty cache");
4036
+ return;
4037
+ }
3949
4038
  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`);
4039
+ if (!Array.isArray(entries)) return;
4040
+ for (const entry of entries) {
4041
+ if (!Array.isArray(entry) || typeof entry[0] !== "string" || !isVector(entry[1])) continue;
4042
+ cacheSet(entry[0], entry[1], false);
4043
+ }
4044
+ console.error(`[memorix] Loaded ${cache.size} cached embeddings from disk`);
3952
4045
  } catch {
3953
4046
  }
3954
4047
  }
4048
+ function isVector(value) {
4049
+ return Array.isArray(value) && value.every((entry) => typeof entry === "number");
4050
+ }
4051
+ function maxCachePayloadBytes() {
4052
+ const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
4053
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES;
4054
+ }
4055
+ function cacheSet(hash4, value, markDirty = true) {
4056
+ const incomingBytes = value.length * 8;
4057
+ if (incomingBytes > maxCachePayloadBytes()) return;
4058
+ const existing = cache.get(hash4);
4059
+ if (existing) cachePayloadBytes -= existing.length * 8;
4060
+ else {
4061
+ while (cache.size >= MAX_CACHE_SIZE || cachePayloadBytes + incomingBytes > maxCachePayloadBytes()) {
4062
+ const firstKey = cache.keys().next().value;
4063
+ if (firstKey === void 0) break;
4064
+ const old = cache.get(firstKey);
4065
+ cache.delete(firstKey);
4066
+ if (old) cachePayloadBytes -= old.length * 8;
4067
+ }
4068
+ }
4069
+ cache.set(hash4, value);
4070
+ cachePayloadBytes += incomingBytes;
4071
+ if (markDirty) diskCacheDirty = true;
4072
+ }
3955
4073
  async function saveDiskCache() {
3956
4074
  if (!diskCacheDirty) return;
3957
4075
  try {
@@ -3962,7 +4080,7 @@ async function saveDiskCache() {
3962
4080
  } catch {
3963
4081
  }
3964
4082
  }
3965
- var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, diskCacheDirty, FastEmbedProvider;
4083
+ var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, DEFAULT_CACHE_PAYLOAD_BYTES, MAX_CACHE_FILE_BYTES, cachePayloadBytes, diskCacheDirty, FastEmbedProvider;
3966
4084
  var init_fastembed_provider = __esm({
3967
4085
  "src/embedding/fastembed-provider.ts"() {
3968
4086
  "use strict";
@@ -3972,6 +4090,9 @@ var init_fastembed_provider = __esm({
3972
4090
  CACHE_FILE = join2(CACHE_DIR, ".embedding-cache.json");
3973
4091
  cache = /* @__PURE__ */ new Map();
3974
4092
  MAX_CACHE_SIZE = 5e3;
4093
+ DEFAULT_CACHE_PAYLOAD_BYTES = 64 * 1024 * 1024;
4094
+ MAX_CACHE_FILE_BYTES = 128 * 1024 * 1024;
4095
+ cachePayloadBytes = 0;
3975
4096
  diskCacheDirty = false;
3976
4097
  FastEmbedProvider = class _FastEmbedProvider {
3977
4098
  name = "fastembed-bge-small";
@@ -4013,7 +4134,7 @@ var init_fastembed_provider = __esm({
4013
4134
  if (result.length !== this.dimensions) {
4014
4135
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
4015
4136
  }
4016
- this.cacheSet(hash4, result);
4137
+ cacheSet(hash4, result);
4017
4138
  return result;
4018
4139
  }
4019
4140
  async embedBatch(texts) {
@@ -4038,7 +4159,7 @@ var init_fastembed_provider = __esm({
4038
4159
  const originalIdx = uncachedIndices[batchIdx];
4039
4160
  const plain = Array.from(vec);
4040
4161
  results[originalIdx] = plain;
4041
- this.cacheSet(textHash(uncachedTexts[batchIdx]), plain);
4162
+ cacheSet(textHash(uncachedTexts[batchIdx]), plain);
4042
4163
  batchIdx++;
4043
4164
  }
4044
4165
  }
@@ -4046,14 +4167,6 @@ var init_fastembed_provider = __esm({
4046
4167
  }
4047
4168
  return results;
4048
4169
  }
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
4170
  };
4058
4171
  }
4059
4172
  });
@@ -4063,7 +4176,15 @@ var transformers_provider_exports = {};
4063
4176
  __export(transformers_provider_exports, {
4064
4177
  TransformersProvider: () => TransformersProvider
4065
4178
  });
4066
- var cache2, MAX_CACHE_SIZE2, TransformersProvider;
4179
+ import { createHash as createHash2 } from "crypto";
4180
+ function cacheKey2(text2) {
4181
+ return createHash2("sha256").update(text2).digest("hex");
4182
+ }
4183
+ function maxCachePayloadBytes2() {
4184
+ const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
4185
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES2;
4186
+ }
4187
+ var cache2, MAX_CACHE_SIZE2, DEFAULT_CACHE_PAYLOAD_BYTES2, cachePayloadBytes2, TransformersProvider;
4067
4188
  var init_transformers_provider = __esm({
4068
4189
  "src/embedding/transformers-provider.ts"() {
4069
4190
  "use strict";
@@ -4071,6 +4192,8 @@ var init_transformers_provider = __esm({
4071
4192
  init_provider2();
4072
4193
  cache2 = /* @__PURE__ */ new Map();
4073
4194
  MAX_CACHE_SIZE2 = 5e3;
4195
+ DEFAULT_CACHE_PAYLOAD_BYTES2 = 64 * 1024 * 1024;
4196
+ cachePayloadBytes2 = 0;
4074
4197
  TransformersProvider = class _TransformersProvider {
4075
4198
  name = "transformers-minilm";
4076
4199
  dimensions = 384;
@@ -4105,7 +4228,7 @@ var init_transformers_provider = __esm({
4105
4228
  return Promise.all(inputs.map((input) => this.embedInput(input, options)));
4106
4229
  }
4107
4230
  async embed(text2) {
4108
- const cached = cache2.get(text2);
4231
+ const cached = cache2.get(cacheKey2(text2));
4109
4232
  if (cached) return cached;
4110
4233
  const output = await this.extractor(text2, {
4111
4234
  pooling: "mean",
@@ -4115,7 +4238,7 @@ var init_transformers_provider = __esm({
4115
4238
  if (result.length !== this.dimensions) {
4116
4239
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
4117
4240
  }
4118
- this.cacheSet(text2, result);
4241
+ this.cacheSet(cacheKey2(text2), result);
4119
4242
  return result;
4120
4243
  }
4121
4244
  async embedBatch(texts) {
@@ -4123,7 +4246,7 @@ var init_transformers_provider = __esm({
4123
4246
  const uncachedIndices = [];
4124
4247
  const uncachedTexts = [];
4125
4248
  for (let i2 = 0; i2 < texts.length; i2++) {
4126
- const cached = cache2.get(texts[i2]);
4249
+ const cached = cache2.get(cacheKey2(texts[i2]));
4127
4250
  if (cached) {
4128
4251
  results[i2] = cached;
4129
4252
  } else {
@@ -4141,17 +4264,27 @@ var init_transformers_provider = __esm({
4141
4264
  const vec = Array.from(allVecs[i2]);
4142
4265
  const originalIdx = uncachedIndices[i2];
4143
4266
  results[originalIdx] = vec;
4144
- this.cacheSet(uncachedTexts[i2], vec);
4267
+ this.cacheSet(cacheKey2(uncachedTexts[i2]), vec);
4145
4268
  }
4146
4269
  }
4147
4270
  return results;
4148
4271
  }
4149
4272
  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);
4273
+ const incomingBytes = value.length * 8;
4274
+ if (incomingBytes > maxCachePayloadBytes2()) return;
4275
+ const existing = cache2.get(key);
4276
+ if (existing) cachePayloadBytes2 -= existing.length * 8;
4277
+ else {
4278
+ while (cache2.size >= MAX_CACHE_SIZE2 || cachePayloadBytes2 + incomingBytes > maxCachePayloadBytes2()) {
4279
+ const firstKey = cache2.keys().next().value;
4280
+ if (firstKey === void 0) break;
4281
+ const old = cache2.get(firstKey);
4282
+ cache2.delete(firstKey);
4283
+ if (old) cachePayloadBytes2 -= old.length * 8;
4284
+ }
4153
4285
  }
4154
4286
  cache2.set(key, value);
4287
+ cachePayloadBytes2 += incomingBytes;
4155
4288
  }
4156
4289
  };
4157
4290
  }
@@ -4173,7 +4306,7 @@ __export(api_provider_exports, {
4173
4306
  saveDiskCacheNow: () => saveDiskCacheNow,
4174
4307
  seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
4175
4308
  });
4176
- import { createHash as createHash2 } from "crypto";
4309
+ import { createHash as createHash3 } from "crypto";
4177
4310
  import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
4178
4311
  import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
4179
4312
  import { join as join3 } from "path";
@@ -4200,7 +4333,7 @@ function cacheStatFile() {
4200
4333
  function payloadBytes(vector) {
4201
4334
  return vector.length * BYTES_PER_DIM;
4202
4335
  }
4203
- function maxCachePayloadBytes() {
4336
+ function maxCachePayloadBytes3() {
4204
4337
  const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
4205
4338
  if (raw) {
4206
4339
  const parsed = Number.parseInt(raw, 10);
@@ -4210,7 +4343,7 @@ function maxCachePayloadBytes() {
4210
4343
  }
4211
4344
  function maxEntriesForDimensions(dimensions) {
4212
4345
  const dim = Math.max(1, Math.floor(dimensions));
4213
- const byBytes = Math.floor(maxCachePayloadBytes() / (dim * BYTES_PER_DIM));
4346
+ const byBytes = Math.floor(maxCachePayloadBytes3() / (dim * BYTES_PER_DIM));
4214
4347
  return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
4215
4348
  }
4216
4349
  function rememberDimensions(vector) {
@@ -4223,13 +4356,15 @@ function evictOldest() {
4223
4356
  if (firstKey === void 0) return;
4224
4357
  const old = cache3.get(firstKey);
4225
4358
  cache3.delete(firstKey);
4226
- if (old) cachePayloadBytes -= payloadBytes(old);
4359
+ if (old) cachePayloadBytes3 -= payloadBytes(old);
4227
4360
  }
4228
4361
  function evictToFit(incomingBytes, incomingDims) {
4362
+ if (incomingBytes > maxCachePayloadBytes3()) return false;
4229
4363
  const limit2 = maxEntriesForDimensions(incomingDims);
4230
- while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes + incomingBytes > maxCachePayloadBytes())) {
4364
+ while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes3 + incomingBytes > maxCachePayloadBytes3())) {
4231
4365
  evictOldest();
4232
4366
  }
4367
+ return true;
4233
4368
  }
4234
4369
  function isNumberArray(value) {
4235
4370
  return Array.isArray(value) && value.every((entry) => typeof entry === "number");
@@ -4256,12 +4391,12 @@ function cacheInsert(hash4, value, dirty) {
4256
4391
  const incoming = payloadBytes(value);
4257
4392
  const existing = cache3.get(hash4);
4258
4393
  if (existing) {
4259
- cachePayloadBytes -= payloadBytes(existing);
4394
+ cachePayloadBytes3 -= payloadBytes(existing);
4260
4395
  cache3.delete(hash4);
4261
4396
  }
4262
- evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
4397
+ if (!evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS)) return;
4263
4398
  cache3.set(hash4, value);
4264
- cachePayloadBytes += incoming;
4399
+ cachePayloadBytes3 += incoming;
4265
4400
  if (dirty) diskCacheDirty2 = true;
4266
4401
  }
4267
4402
  async function readCacheStat() {
@@ -4297,7 +4432,7 @@ function cacheNamespace(config) {
4297
4432
  ].join("|");
4298
4433
  }
4299
4434
  function textHash2(text2, namespace) {
4300
- return createHash2("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
4435
+ return createHash3("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
4301
4436
  }
4302
4437
  function inputIdentity(input, options = {}) {
4303
4438
  return JSON.stringify({
@@ -4639,7 +4774,7 @@ function getApiEmbeddingDiskCacheLoadCountForTests() {
4639
4774
  }
4640
4775
  function resetApiEmbeddingCacheForTests() {
4641
4776
  cache3.clear();
4642
- cachePayloadBytes = 0;
4777
+ cachePayloadBytes3 = 0;
4643
4778
  cacheDimensions = null;
4644
4779
  diskCacheEntryCount = 0;
4645
4780
  diskCacheLoaded = false;
@@ -4650,14 +4785,14 @@ function resetApiEmbeddingCacheForTests() {
4650
4785
  }
4651
4786
  function seedApiEmbeddingCacheForTests(entries) {
4652
4787
  cache3.clear();
4653
- cachePayloadBytes = 0;
4788
+ cachePayloadBytes3 = 0;
4654
4789
  cacheDimensions = null;
4655
4790
  for (const [key, value] of entries) cacheInsert(key, value, true);
4656
4791
  diskCacheLoaded = true;
4657
4792
  diskCacheDirty2 = true;
4658
4793
  }
4659
4794
  function getApiEmbeddingCachePayloadBytesForTests() {
4660
- return cachePayloadBytes;
4795
+ return cachePayloadBytes3;
4661
4796
  }
4662
4797
  function getApiEmbeddingJsonlLineCountCallsForTests() {
4663
4798
  return jsonlLineCountCalls;
@@ -4831,7 +4966,7 @@ function scheduleDiskSave() {
4831
4966
  diskSaveTimer = null;
4832
4967
  }, DISK_SAVE_DEBOUNCE_MS);
4833
4968
  }
4834
- function cacheSet(hash4, value) {
4969
+ function cacheSet2(hash4, value) {
4835
4970
  cacheInsert(hash4, value, true);
4836
4971
  }
4837
4972
  function resolveEnvEmbeddingApiKey() {
@@ -4951,7 +5086,7 @@ async function waitForRetry(waitMs, signal) {
4951
5086
  abortSignal.addEventListener("abort", onAbort, { once: true });
4952
5087
  });
4953
5088
  }
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;
5089
+ 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
5090
  var init_api_provider = __esm({
4956
5091
  "src/embedding/api-provider.ts"() {
4957
5092
  "use strict";
@@ -4963,7 +5098,7 @@ var init_api_provider = __esm({
4963
5098
  BYTES_PER_DIM = 8;
4964
5099
  DEFAULT_ASSUMED_DIMENSIONS = 4096;
4965
5100
  MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
4966
- cachePayloadBytes = 0;
5101
+ cachePayloadBytes3 = 0;
4967
5102
  cacheDimensions = null;
4968
5103
  diskCacheEntryCount = 0;
4969
5104
  diskCacheDirty2 = false;
@@ -5148,7 +5283,7 @@ var init_api_provider = __esm({
5148
5283
  } else {
5149
5284
  embedding = await apiCall();
5150
5285
  }
5151
- cacheSet(hash4, embedding);
5286
+ cacheSet2(hash4, embedding);
5152
5287
  scheduleDiskSave();
5153
5288
  return embedding;
5154
5289
  }
@@ -5196,7 +5331,7 @@ var init_api_provider = __esm({
5196
5331
  for (const item of response.data) {
5197
5332
  const originalIdx = chunkIndices[item.index];
5198
5333
  results[originalIdx] = item.embedding;
5199
- cacheSet(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
5334
+ cacheSet2(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
5200
5335
  }
5201
5336
  } catch (error) {
5202
5337
  const providerLimit = parseBatchLimit(error);
@@ -5274,7 +5409,7 @@ var init_api_provider = __esm({
5274
5409
  throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d; dimension mismatch`);
5275
5410
  }
5276
5411
  this.trackUsage(response);
5277
- cacheSet(hash4, embedding);
5412
+ cacheSet2(hash4, embedding);
5278
5413
  scheduleDiskSave();
5279
5414
  return embedding;
5280
5415
  }
@@ -6195,7 +6330,7 @@ var init_timeout = __esm({
6195
6330
  });
6196
6331
 
6197
6332
  // src/search/semantic-index.ts
6198
- import { createHash as createHash3 } from "crypto";
6333
+ import { createHash as createHash4 } from "crypto";
6199
6334
  import { createRequire as createRequire3 } from "module";
6200
6335
  import path8 from "path";
6201
6336
  function createSemanticIndexProfile(provider2) {
@@ -6209,7 +6344,7 @@ function stateKey(dataDir, profile) {
6209
6344
  return `${path8.resolve(dataDir)}::${profile.key}`;
6210
6345
  }
6211
6346
  function tableName(profile) {
6212
- const digest2 = createHash3("sha256").update(profile.key).digest("hex").slice(0, 20);
6347
+ const digest2 = createHash4("sha256").update(profile.key).digest("hex").slice(0, 20);
6213
6348
  return `${TABLE_PREFIX}${digest2}`;
6214
6349
  }
6215
6350
  function indexRoot(dataDir) {
@@ -8249,6 +8384,7 @@ var init_secret_filter = __esm({
8249
8384
  // src/runtime/maintenance-jobs.ts
8250
8385
  var maintenance_jobs_exports = {};
8251
8386
  __export(maintenance_jobs_exports, {
8387
+ DEFAULT_FAILED_HISTORY_RETENTION_MS: () => DEFAULT_FAILED_HISTORY_RETENTION_MS,
8252
8388
  MAINTENANCE_JOB_KINDS: () => MAINTENANCE_JOB_KINDS,
8253
8389
  MaintenanceJobStore: () => MaintenanceJobStore,
8254
8390
  MaintenanceJobWorker: () => MaintenanceJobWorker,
@@ -8298,7 +8434,7 @@ function normalizedKinds(kinds) {
8298
8434
  function getMaintenanceRetryDelayMs(attempts) {
8299
8435
  return Math.min(6e4, 1e3 * 2 ** Math.max(0, attempts - 1));
8300
8436
  }
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;
8437
+ 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
8438
  var init_maintenance_jobs = __esm({
8303
8439
  "src/runtime/maintenance-jobs.ts"() {
8304
8440
  "use strict";
@@ -8325,6 +8461,7 @@ var init_maintenance_jobs = __esm({
8325
8461
  DEFAULT_POLL_INTERVAL_MS = 2e3;
8326
8462
  MAX_ERROR_LENGTH = 1e3;
8327
8463
  DEFAULT_COMPLETED_HISTORY_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
8464
+ DEFAULT_FAILED_HISTORY_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
8328
8465
  MaintenanceJobStore = class {
8329
8466
  db;
8330
8467
  constructor(dataDir) {
@@ -8451,18 +8588,21 @@ var init_maintenance_jobs = __esm({
8451
8588
  }
8452
8589
  /**
8453
8590
  * 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.
8591
+ * Failed diagnostics are retained longer, but are still bounded so a
8592
+ * permanently failing job kind cannot grow the database forever.
8456
8593
  */
8457
8594
  pruneCompletedHistory(options = {}) {
8458
8595
  const now3 = options.now ?? Date.now();
8459
8596
  const maxAgeMs = Number.isFinite(options.maxAgeMs) ? Math.max(0, Math.floor(options.maxAgeMs)) : DEFAULT_COMPLETED_HISTORY_RETENTION_MS;
8597
+ const failedMaxAgeMs = Number.isFinite(options.failedMaxAgeMs) ? Math.max(0, Math.floor(options.failedMaxAgeMs)) : DEFAULT_FAILED_HISTORY_RETENTION_MS;
8460
8598
  const result = this.db.prepare(`
8461
8599
  DELETE FROM maintenance_jobs
8462
- WHERE status = 'completed'
8600
+ WHERE (status = 'completed'
8463
8601
  AND completed_at IS NOT NULL
8464
- AND completed_at < ?
8465
- `).run(now3 - maxAgeMs);
8602
+ AND completed_at < ?)
8603
+ OR (status = 'failed'
8604
+ AND updated_at < ?)
8605
+ `).run(now3 - maxAgeMs, now3 - failedMaxAgeMs);
8466
8606
  return Number(result.changes ?? 0);
8467
8607
  }
8468
8608
  claimNext(options) {
@@ -8788,7 +8928,7 @@ var init_lifecycle = __esm({
8788
8928
  });
8789
8929
 
8790
8930
  // src/store/evidence-store.ts
8791
- import { createHash as createHash4, randomUUID as randomUUID3 } from "crypto";
8931
+ import { createHash as createHash5, randomUUID as randomUUID3 } from "crypto";
8792
8932
  function safeJson(value, fallback) {
8793
8933
  if (typeof value !== "string" || value.length === 0) return fallback;
8794
8934
  try {
@@ -8822,7 +8962,7 @@ function rowToCard(row) {
8822
8962
  };
8823
8963
  }
8824
8964
  function observationHash(observation) {
8825
- return createHash4("sha256").update(JSON.stringify({
8965
+ return createHash5("sha256").update(JSON.stringify({
8826
8966
  projectId: observation.projectId,
8827
8967
  id: observation.id,
8828
8968
  title: observation.title,
@@ -9282,13 +9422,13 @@ __export(workspace_exports, {
9282
9422
  loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
9283
9423
  resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
9284
9424
  });
9285
- import { createHash as createHash5 } from "crypto";
9425
+ import { createHash as createHash6 } from "crypto";
9286
9426
  import { execFile } from "child_process";
9287
9427
  import { promises as fs6 } from "fs";
9288
9428
  import path11 from "path";
9289
9429
  import { promisify } from "util";
9290
9430
  function hash(value) {
9291
- return createHash5("sha256").update(value).digest("hex");
9431
+ return createHash6("sha256").update(value).digest("hex");
9292
9432
  }
9293
9433
  function workspaceId(projectId, mode) {
9294
9434
  return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
@@ -10423,14 +10563,14 @@ var init_types2 = __esm({
10423
10563
  });
10424
10564
 
10425
10565
  // src/media/asset-store.ts
10426
- import { createHash as createHash6, randomUUID as randomUUID6 } from "crypto";
10566
+ import { createHash as createHash7, randomUUID as randomUUID6 } from "crypto";
10427
10567
  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
10568
  import path12 from "path";
10429
10569
  function mediaRoot(dataDir) {
10430
10570
  return path12.resolve(dataDir, "media");
10431
10571
  }
10432
10572
  function projectStorageKey(projectId) {
10433
- return createHash6("sha256").update(projectId).digest("hex").slice(0, 16);
10573
+ return createHash7("sha256").update(projectId).digest("hex").slice(0, 16);
10434
10574
  }
10435
10575
  function validateUnderRoot(root, candidate) {
10436
10576
  const resolved = path12.resolve(candidate);
@@ -10539,7 +10679,7 @@ async function importMediaBuffer(input) {
10539
10679
  if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
10540
10680
  if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
10541
10681
  const detected = detectMedia(input.bytes.subarray(0, 32));
10542
- const sha256 = createHash6("sha256").update(input.bytes).digest("hex");
10682
+ const sha256 = createHash7("sha256").update(input.bytes).digest("hex");
10543
10683
  return importKnownMedia({
10544
10684
  dataDir: input.dataDir,
10545
10685
  projectId: input.projectId,
@@ -10557,7 +10697,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
10557
10697
  if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
10558
10698
  const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
10559
10699
  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");
10700
+ const sha256 = createHash7("sha256").update(bytes).digest("hex");
10561
10701
  if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
10562
10702
  return bytes;
10563
10703
  }
@@ -69253,16 +69393,16 @@ var require_jwtaccess = __commonJS({
69253
69393
  * @returns A string that returns the cached key.
69254
69394
  */
69255
69395
  getCachedKey(url, scopes) {
69256
- let cacheKey = url;
69396
+ let cacheKey3 = url;
69257
69397
  if (scopes && Array.isArray(scopes) && scopes.length) {
69258
- cacheKey = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
69398
+ cacheKey3 = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
69259
69399
  } else if (typeof scopes === "string") {
69260
- cacheKey = url ? `${url}_${scopes}` : scopes;
69400
+ cacheKey3 = url ? `${url}_${scopes}` : scopes;
69261
69401
  }
69262
- if (!cacheKey) {
69402
+ if (!cacheKey3) {
69263
69403
  throw Error("Scopes or url must be provided");
69264
69404
  }
69265
- return cacheKey;
69405
+ return cacheKey3;
69266
69406
  }
69267
69407
  /**
69268
69408
  * Get a non-expired access token, after refreshing if necessary.
@@ -75808,7 +75948,7 @@ var require_websocket = __commonJS({
75808
75948
  var http3 = __require("http");
75809
75949
  var net = __require("net");
75810
75950
  var tls = __require("tls");
75811
- var { randomBytes, createHash: createHash16 } = __require("crypto");
75951
+ var { randomBytes, createHash: createHash17 } = __require("crypto");
75812
75952
  var { Duplex, Readable: Readable2 } = __require("stream");
75813
75953
  var { URL: URL2 } = __require("url");
75814
75954
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -76476,7 +76616,7 @@ var require_websocket = __commonJS({
76476
76616
  abortHandshake(websocket, socket, "Invalid Upgrade header");
76477
76617
  return;
76478
76618
  }
76479
- const digest2 = createHash16("sha1").update(key + GUID).digest("base64");
76619
+ const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
76480
76620
  if (res.headers["sec-websocket-accept"] !== digest2) {
76481
76621
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
76482
76622
  return;
@@ -76848,7 +76988,7 @@ var require_websocket_server = __commonJS({
76848
76988
  var EventEmitter = __require("events");
76849
76989
  var http3 = __require("http");
76850
76990
  var { Duplex } = __require("stream");
76851
- var { createHash: createHash16 } = __require("crypto");
76991
+ var { createHash: createHash17 } = __require("crypto");
76852
76992
  var extension3 = require_extension();
76853
76993
  var PerMessageDeflate2 = require_permessage_deflate();
76854
76994
  var subprotocol2 = require_subprotocol();
@@ -77155,7 +77295,7 @@ var require_websocket_server = __commonJS({
77155
77295
  );
77156
77296
  }
77157
77297
  if (this._state > RUNNING) return abortHandshake(socket, 503);
77158
- const digest2 = createHash16("sha1").update(key + GUID).digest("base64");
77298
+ const digest2 = createHash17("sha1").update(key + GUID).digest("base64");
77159
77299
  const headers = [
77160
77300
  "HTTP/1.1 101 Switching Protocols",
77161
77301
  "Upgrade: websocket",
@@ -145734,9 +145874,9 @@ var init_long_term = __esm({
145734
145874
  });
145735
145875
 
145736
145876
  // src/codegraph/ids.ts
145737
- import { createHash as createHash7 } from "crypto";
145877
+ import { createHash as createHash8 } from "crypto";
145738
145878
  function digest(input) {
145739
- return createHash7("sha256").update(input).digest("hex").slice(0, 16);
145879
+ return createHash8("sha256").update(input).digest("hex").slice(0, 16);
145740
145880
  }
145741
145881
  function normalizeCodePath(path23) {
145742
145882
  return path23.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
@@ -146784,7 +146924,7 @@ var init_store = __esm({
146784
146924
 
146785
146925
  // src/codegraph/code-state.ts
146786
146926
  import { execFile as execFile2 } from "child_process";
146787
- import { createHash as createHash8 } from "crypto";
146927
+ import { createHash as createHash9 } from "crypto";
146788
146928
  import { promisify as promisify3 } from "util";
146789
146929
  async function runGit(rootPath, args) {
146790
146930
  try {
@@ -146813,7 +146953,7 @@ function changedPathCount(status) {
146813
146953
  return count2;
146814
146954
  }
146815
146955
  function fingerprint(baseRevision, status) {
146816
- return createHash8("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
146956
+ return createHash9("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
146817
146957
  }
146818
146958
  async function collectCodeStateSnapshot(input) {
146819
146959
  const [revision, status] = await Promise.all([
@@ -146907,12 +147047,12 @@ var init_exclude3 = __esm({
146907
147047
  });
146908
147048
 
146909
147049
  // src/codegraph/semantic-provider.ts
146910
- import { createHash as createHash9 } from "crypto";
147050
+ import { createHash as createHash10 } from "crypto";
146911
147051
  import "fs";
146912
147052
  import { resolve } from "path";
146913
147053
  import ts from "typescript";
146914
147054
  function hashText(value) {
146915
- return createHash9("sha256").update(value).digest("hex");
147055
+ return createHash10("sha256").update(value).digest("hex");
146916
147056
  }
146917
147057
  function canonicalPath(value) {
146918
147058
  const normalized = resolve(value).replace(/\\/g, "/");
@@ -147257,11 +147397,11 @@ __export(lite_provider_exports, {
147257
147397
  indexProjectLite: () => indexProjectLite,
147258
147398
  refreshProjectLite: () => refreshProjectLite
147259
147399
  });
147260
- import { createHash as createHash10 } from "crypto";
147400
+ import { createHash as createHash11 } from "crypto";
147261
147401
  import { existsSync as existsSync12, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
147262
147402
  import { join as join4, relative as relative2 } from "path";
147263
147403
  function hashText2(text2) {
147264
- return createHash10("sha256").update(text2).digest("hex");
147404
+ return createHash11("sha256").update(text2).digest("hex");
147265
147405
  }
147266
147406
  function extension2(path23) {
147267
147407
  const index = path23.lastIndexOf(".");
@@ -147894,7 +148034,7 @@ var claim_store_exports = {};
147894
148034
  __export(claim_store_exports, {
147895
148035
  ClaimStore: () => ClaimStore
147896
148036
  });
147897
- import { createHash as createHash11, randomUUID as randomUUID12 } from "crypto";
148037
+ import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
147898
148038
  function optionalText3(value) {
147899
148039
  return typeof value === "string" && value ? value : void 0;
147900
148040
  }
@@ -147947,7 +148087,7 @@ function rowToEvent3(row) {
147947
148087
  };
147948
148088
  }
147949
148089
  function evidenceKey(input) {
147950
- return createHash11("sha256").update(JSON.stringify([
148090
+ return createHash12("sha256").update(JSON.stringify([
147951
148091
  input.evidenceKind,
147952
148092
  input.evidenceId,
147953
148093
  input.relation,
@@ -148145,7 +148285,7 @@ __export(claims_exports, {
148145
148285
  supersedeClaim: () => supersedeClaim,
148146
148286
  writeClaim: () => writeClaim
148147
148287
  });
148148
- import { createHash as createHash12, randomUUID as randomUUID13 } from "crypto";
148288
+ import { createHash as createHash13, randomUUID as randomUUID13 } from "crypto";
148149
148289
  function compactText2(value, field) {
148150
148290
  if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
148151
148291
  const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
@@ -148157,7 +148297,7 @@ function normalizedTerm(value) {
148157
148297
  return compactText2(value, "identity").toLocaleLowerCase("en-US");
148158
148298
  }
148159
148299
  function hashIdentity(parts) {
148160
- return createHash12("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
148300
+ return createHash13("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
148161
148301
  }
148162
148302
  function buildClaimIdentity(input) {
148163
148303
  const subject = normalizedTerm(input.subject);
@@ -148398,7 +148538,7 @@ function supersedeClaim(store, input) {
148398
148538
  });
148399
148539
  }
148400
148540
  function hashObservation(observation) {
148401
- return createHash12("sha256").update(JSON.stringify([
148541
+ return createHash13("sha256").update(JSON.stringify([
148402
148542
  observation.title,
148403
148543
  observation.narrative,
148404
148544
  observation.facts,
@@ -148642,11 +148782,11 @@ var init_frontmatter = __esm({
148642
148782
  });
148643
148783
 
148644
148784
  // src/knowledge/markdown.ts
148645
- import { createHash as createHash13 } from "crypto";
148785
+ import { createHash as createHash14 } from "crypto";
148646
148786
  import { promises as fs10 } from "fs";
148647
148787
  import path19 from "path";
148648
148788
  function hashContent(content) {
148649
- return createHash13("sha256").update(content).digest("hex");
148789
+ return createHash14("sha256").update(content).digest("hex");
148650
148790
  }
148651
148791
  function stringField(data, key) {
148652
148792
  const value = data[key];
@@ -148772,11 +148912,11 @@ __export(wiki_exports, {
148772
148912
  lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
148773
148913
  readKnowledgePage: () => readKnowledgePage
148774
148914
  });
148775
- import { createHash as createHash14 } from "crypto";
148915
+ import { createHash as createHash15 } from "crypto";
148776
148916
  import { promises as fs11 } from "fs";
148777
148917
  import path20 from "path";
148778
148918
  function hash2(value) {
148779
- return createHash14("sha256").update(value).digest("hex");
148919
+ return createHash15("sha256").update(value).digest("hex");
148780
148920
  }
148781
148921
  function now() {
148782
148922
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -149633,11 +149773,11 @@ __export(workflows_exports, {
149633
149773
  syncCanonicalWorkflows: () => syncCanonicalWorkflows,
149634
149774
  writeCanonicalWorkflow: () => writeCanonicalWorkflow
149635
149775
  });
149636
- import { createHash as createHash15 } from "crypto";
149776
+ import { createHash as createHash16 } from "crypto";
149637
149777
  import { promises as fs12 } from "fs";
149638
149778
  import path21 from "path";
149639
149779
  function hash3(value) {
149640
- return createHash15("sha256").update(value).digest("hex");
149780
+ return createHash16("sha256").update(value).digest("hex");
149641
149781
  }
149642
149782
  function now2() {
149643
149783
  return (/* @__PURE__ */ new Date()).toISOString();