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
package/dist/index.js CHANGED
@@ -444,11 +444,21 @@ function applySchemaMigrations(db2) {
444
444
  apply();
445
445
  }
446
446
  }
447
+ function normalizeDataDir(dataDir) {
448
+ return path3.resolve(dataDir);
449
+ }
450
+ function touchDatabase(normalized, db2) {
451
+ _dbCache.delete(normalized);
452
+ _dbCache.set(normalized, db2);
453
+ }
447
454
  function getDatabase(dataDir) {
448
- const normalized = path3.resolve(dataDir);
455
+ const normalized = normalizeDataDir(dataDir);
449
456
  assertNotHomeDataDir(normalized);
450
457
  const existing = _dbCache.get(normalized);
451
- if (existing) return existing;
458
+ if (existing) {
459
+ touchDatabase(normalized, existing);
460
+ return existing;
461
+ }
452
462
  loadBetterSqlite3();
453
463
  fs.mkdirSync(dataDir, { recursive: true });
454
464
  const dbPath = path3.join(dataDir, "memorix.db");
@@ -478,6 +488,8 @@ function getDatabase(dataDir) {
478
488
  db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
479
489
  db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
480
490
  db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
491
+ db2.exec(CREATE_TASK_CONTINUITY_EVENTS_TABLE);
492
+ db2.exec(CREATE_AGENT_EFFECTS_TABLE);
481
493
  try {
482
494
  db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
483
495
  } catch {
@@ -516,7 +528,7 @@ function getDatabase(dataDir) {
516
528
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
517
529
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
518
530
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
519
- _dbCache.set(normalized, db2);
531
+ touchDatabase(normalized, db2);
520
532
  return db2;
521
533
  } catch (error) {
522
534
  try {
@@ -534,8 +546,9 @@ function closeAllDatabases() {
534
546
  }
535
547
  _dbCache.delete(key);
536
548
  }
549
+ _dbLeases.clear();
537
550
  }
538
- 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;
551
+ 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;
539
552
  var init_sqlite_db = __esm({
540
553
  "src/store/sqlite-db.ts"() {
541
554
  "use strict";
@@ -1252,6 +1265,43 @@ CREATE TABLE IF NOT EXISTS memory_feedback_events (
1252
1265
  delta REAL NOT NULL DEFAULT 0,
1253
1266
  observed_at TEXT NOT NULL
1254
1267
  );
1268
+ `;
1269
+ CREATE_TASK_CONTINUITY_EVENTS_TABLE = `
1270
+ CREATE TABLE IF NOT EXISTS task_continuity_events (
1271
+ id TEXT PRIMARY KEY,
1272
+ project_id TEXT NOT NULL,
1273
+ task_id TEXT NOT NULL,
1274
+ task TEXT NOT NULL,
1275
+ kind TEXT NOT NULL,
1276
+ content TEXT NOT NULL,
1277
+ item_status TEXT,
1278
+ source_ref TEXT,
1279
+ evidence_json TEXT NOT NULL DEFAULT '[]',
1280
+ actor TEXT,
1281
+ created_at TEXT NOT NULL,
1282
+ event_key TEXT,
1283
+ item_key TEXT,
1284
+ supersedes_id TEXT
1285
+ );
1286
+ `;
1287
+ CREATE_AGENT_EFFECTS_TABLE = `
1288
+ CREATE TABLE IF NOT EXISTS agent_effects (
1289
+ id TEXT PRIMARY KEY,
1290
+ pipeline_id TEXT NOT NULL,
1291
+ task_id TEXT NOT NULL,
1292
+ attempt INTEGER NOT NULL,
1293
+ effect_key TEXT NOT NULL,
1294
+ tool TEXT NOT NULL,
1295
+ risk_tier TEXT NOT NULL,
1296
+ replay_policy TEXT NOT NULL,
1297
+ status TEXT NOT NULL,
1298
+ call_id TEXT,
1299
+ idempotency_key TEXT NOT NULL,
1300
+ input_fingerprint TEXT,
1301
+ detail TEXT,
1302
+ started_at INTEGER NOT NULL,
1303
+ finished_at INTEGER
1304
+ );
1255
1305
  `;
1256
1306
  CREATE_MCP_BINDINGS_TABLE = `
1257
1307
  CREATE TABLE IF NOT EXISTS mcp_bindings (
@@ -1330,7 +1380,18 @@ CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(projec
1330
1380
  CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
1331
1381
  CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
1332
1382
  CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
1383
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_project_task ON task_continuity_events(project_id, task_id, created_at ASC);
1384
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_project_recent ON task_continuity_events(project_id, created_at DESC);
1385
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_item ON task_continuity_events(project_id, task_id, kind, item_key, created_at DESC);
1386
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
1387
+ ON task_continuity_events(project_id, task_id, event_key)
1388
+ WHERE event_key IS NOT NULL;
1389
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_effect_identity
1390
+ ON agent_effects(pipeline_id, task_id, attempt, effect_key);
1391
+ CREATE INDEX IF NOT EXISTS idx_agent_effect_pipeline ON agent_effects(pipeline_id, started_at ASC);
1333
1392
  CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
1393
+ CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC);
1394
+ CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at);
1334
1395
  CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1335
1396
  ON maintenance_jobs(project_id, kind, dedupe_key)
1336
1397
  WHERE status IN ('pending', 'running', 'retry');
@@ -1501,6 +1562,8 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1501
1562
  db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
1502
1563
  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)");
1503
1564
  db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
1565
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC)");
1566
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at)");
1504
1567
  }
1505
1568
  },
1506
1569
  {
@@ -1511,9 +1574,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1511
1574
  addColumnIfMissing(db2, "code_symbols", "source", "source TEXT");
1512
1575
  addColumnIfMissing(db2, "code_edges", "source", "source TEXT");
1513
1576
  }
1577
+ },
1578
+ {
1579
+ id: "1.9-continuity-v2",
1580
+ apply: (db2) => {
1581
+ addColumnIfMissing(db2, "task_continuity_events", "event_key", "event_key TEXT");
1582
+ addColumnIfMissing(db2, "task_continuity_events", "item_key", "item_key TEXT");
1583
+ addColumnIfMissing(db2, "task_continuity_events", "supersedes_id", "supersedes_id TEXT");
1584
+ 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)");
1585
+ db2.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
1586
+ ON task_continuity_events(project_id, task_id, event_key)
1587
+ WHERE event_key IS NOT NULL`);
1588
+ }
1514
1589
  }
1515
1590
  ];
1516
1591
  _dbCache = /* @__PURE__ */ new Map();
1592
+ _dbLeases = /* @__PURE__ */ new Map();
1517
1593
  }
1518
1594
  });
1519
1595
 
@@ -3228,18 +3304,23 @@ __export(yaml_loader_exports, {
3228
3304
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
3229
3305
  import { homedir } from "os";
3230
3306
  import { parse as parseYamlDocument } from "yaml";
3307
+ function cacheKey(homeDir, projectRoot) {
3308
+ return `${homeDir}\0${projectRoot ?? ""}`;
3309
+ }
3231
3310
  function initProjectRoot(root) {
3232
3311
  globalProjectRoot = root;
3233
- configCache.delete(root);
3312
+ configCache.delete(cacheKey(homedir(), root));
3234
3313
  }
3235
3314
  function clearProjectRoot() {
3236
3315
  globalProjectRoot = null;
3237
3316
  }
3238
- function loadYamlConfig(projectRoot) {
3317
+ function loadYamlConfig(projectRoot, options = {}) {
3318
+ const homeDir = options.homeDir ?? homedir();
3239
3319
  const resolvedRoot = projectRoot === null ? null : projectRoot ?? globalProjectRoot ?? null;
3240
- const cached = configCache.get(resolvedRoot ?? null);
3320
+ const key = cacheKey(homeDir, resolvedRoot);
3321
+ const cached = configCache.get(key);
3241
3322
  if (cached) return cached;
3242
- const userYaml = getGlobalYamlPath(homedir());
3323
+ const userYaml = getGlobalYamlPath(homeDir);
3243
3324
  const projectYaml = resolvedRoot ? getProjectYamlPath(resolvedRoot) : null;
3244
3325
  let userConfig = {};
3245
3326
  let projectConfig = {};
@@ -3271,12 +3352,12 @@ function loadYamlConfig(projectRoot) {
3271
3352
  server: { ...userConfig.server, ...projectConfig.server },
3272
3353
  team: { ...userConfig.team, ...projectConfig.team }
3273
3354
  };
3274
- configCache.set(resolvedRoot ?? null, merged);
3355
+ configCache.set(key, merged);
3275
3356
  return merged;
3276
3357
  }
3277
- function resetYamlConfigCache(projectRoot) {
3358
+ function resetYamlConfigCache(projectRoot, homeDir = homedir()) {
3278
3359
  if (projectRoot !== void 0) {
3279
- configCache.delete(projectRoot ?? null);
3360
+ configCache.delete(cacheKey(homeDir, projectRoot ?? null));
3280
3361
  } else {
3281
3362
  configCache.clear();
3282
3363
  }
@@ -3486,9 +3567,9 @@ var init_detector = __esm({
3486
3567
  // src/config/legacy-loader.ts
3487
3568
  import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
3488
3569
  import { homedir as homedir2 } from "os";
3489
- function loadFileConfig() {
3570
+ function loadFileConfig(homeDir = homedir2()) {
3490
3571
  if (cachedConfig !== null) return cachedConfig;
3491
- const configPath = getLegacyConfigJsonPath(homedir2());
3572
+ const configPath = getLegacyConfigJsonPath(homeDir);
3492
3573
  try {
3493
3574
  if (existsSync4(configPath)) {
3494
3575
  cachedConfig = JSON.parse(readFileSync4(configPath, "utf-8"));
@@ -3518,15 +3599,15 @@ import { homedir as homedir3 } from "os";
3518
3599
  function loadTomlConfig(options = {}) {
3519
3600
  const homeDir = options.homeDir ?? homedir3();
3520
3601
  const projectRoot = options.projectRoot ?? null;
3521
- const cacheKey = `${homeDir}\0${projectRoot ?? ""}`;
3522
- const cached = configCache2.get(cacheKey);
3602
+ const cacheKey3 = `${homeDir}\0${projectRoot ?? ""}`;
3603
+ const cached = configCache2.get(cacheKey3);
3523
3604
  if (cached) return cached;
3524
3605
  const userToml = getGlobalConfigTomlPath(homeDir);
3525
3606
  const projectToml = projectRoot ? getProjectConfigTomlPath(projectRoot) : null;
3526
3607
  const userConfig = existsSync5(userToml) ? parseTomlConfig(readFileSync5(userToml, "utf8"), userToml) : {};
3527
3608
  const projectConfig = projectToml && existsSync5(projectToml) ? parseTomlConfig(readFileSync5(projectToml, "utf8"), projectToml) : {};
3528
3609
  const merged = mergeTomlConfig(userConfig, projectConfig);
3529
- configCache2.set(cacheKey, merged);
3610
+ configCache2.set(cacheKey3, merged);
3530
3611
  return merged;
3531
3612
  }
3532
3613
  function mergeTomlConfig(base, override) {
@@ -3726,8 +3807,8 @@ function getResolvedConfig(options = {}) {
3726
3807
  const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
3727
3808
  loadDotenv(projectRoot === null ? void 0 : projectRoot ?? void 0, { userHomeDir: homeDir });
3728
3809
  const toml = loadTomlConfig({ projectRoot: projectRoot ?? null, homeDir });
3729
- const yaml = loadYamlConfig(projectRoot ?? null);
3730
- const legacy = loadFileConfig();
3810
+ const yaml = loadYamlConfig(projectRoot ?? null, { homeDir });
3811
+ const legacy = loadFileConfig(homeDir);
3731
3812
  const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
3732
3813
  const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
3733
3814
  const memoryLlmProvider = first(
@@ -3749,15 +3830,17 @@ function getResolvedConfig(options = {}) {
3749
3830
  legacy.llm?.baseUrl
3750
3831
  );
3751
3832
  const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
3833
+ const isAtlasCloud = memoryLlmProvider === "atlascloud";
3752
3834
  const memoryLlmApiKey = first(
3753
3835
  process.env.MEMORIX_LLM_API_KEY,
3754
3836
  process.env.MEMORIX_API_KEY,
3755
3837
  toml.memory?.llm?.api_key,
3756
3838
  yaml.llm?.apiKey,
3757
3839
  legacy.llm?.apiKey,
3758
- process.env.OPENAI_API_KEY,
3759
- process.env.ANTHROPIC_API_KEY,
3760
- openRouterMemoryLlmApiKey
3840
+ // Never borrow another provider's credentials for the Atlas Cloud preset.
3841
+ isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
3842
+ isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
3843
+ isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
3761
3844
  );
3762
3845
  const resolved = {
3763
3846
  agent: {
@@ -3936,7 +4019,8 @@ function getEnvSourceNames() {
3936
4019
  "MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
3937
4020
  "MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
3938
4021
  "MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
3939
- "OPENROUTER_API_KEY"
4022
+ "OPENROUTER_API_KEY",
4023
+ "ATLASCLOUD_API_KEY"
3940
4024
  ].filter((name) => process.env[name]);
3941
4025
  }
3942
4026
  function isOpenRouterUrl(value) {
@@ -4155,12 +4239,45 @@ function textHash(text3) {
4155
4239
  async function loadDiskCache() {
4156
4240
  try {
4157
4241
  const raw = await readFile(CACHE_FILE, "utf-8");
4242
+ if (Buffer.byteLength(raw, "utf8") > MAX_CACHE_FILE_BYTES) {
4243
+ console.error("[memorix] FastEmbed cache exceeds the disk load limit; starting with an empty cache");
4244
+ return;
4245
+ }
4158
4246
  const entries = JSON.parse(raw);
4159
- for (const [k, v] of entries) cache.set(k, v);
4160
- console.error(`[memorix] Loaded ${entries.length} cached embeddings from disk`);
4247
+ if (!Array.isArray(entries)) return;
4248
+ for (const entry of entries) {
4249
+ if (!Array.isArray(entry) || typeof entry[0] !== "string" || !isVector(entry[1])) continue;
4250
+ cacheSet(entry[0], entry[1], false);
4251
+ }
4252
+ console.error(`[memorix] Loaded ${cache.size} cached embeddings from disk`);
4161
4253
  } catch {
4162
4254
  }
4163
4255
  }
4256
+ function isVector(value) {
4257
+ return Array.isArray(value) && value.every((entry) => typeof entry === "number");
4258
+ }
4259
+ function maxCachePayloadBytes() {
4260
+ const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
4261
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES;
4262
+ }
4263
+ function cacheSet(hash4, value, markDirty = true) {
4264
+ const incomingBytes = value.length * 8;
4265
+ if (incomingBytes > maxCachePayloadBytes()) return;
4266
+ const existing = cache.get(hash4);
4267
+ if (existing) cachePayloadBytes -= existing.length * 8;
4268
+ else {
4269
+ while (cache.size >= MAX_CACHE_SIZE || cachePayloadBytes + incomingBytes > maxCachePayloadBytes()) {
4270
+ const firstKey = cache.keys().next().value;
4271
+ if (firstKey === void 0) break;
4272
+ const old = cache.get(firstKey);
4273
+ cache.delete(firstKey);
4274
+ if (old) cachePayloadBytes -= old.length * 8;
4275
+ }
4276
+ }
4277
+ cache.set(hash4, value);
4278
+ cachePayloadBytes += incomingBytes;
4279
+ if (markDirty) diskCacheDirty = true;
4280
+ }
4164
4281
  async function saveDiskCache() {
4165
4282
  if (!diskCacheDirty) return;
4166
4283
  try {
@@ -4171,7 +4288,7 @@ async function saveDiskCache() {
4171
4288
  } catch {
4172
4289
  }
4173
4290
  }
4174
- var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, diskCacheDirty, FastEmbedProvider;
4291
+ var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, DEFAULT_CACHE_PAYLOAD_BYTES, MAX_CACHE_FILE_BYTES, cachePayloadBytes, diskCacheDirty, FastEmbedProvider;
4175
4292
  var init_fastembed_provider = __esm({
4176
4293
  "src/embedding/fastembed-provider.ts"() {
4177
4294
  "use strict";
@@ -4181,6 +4298,9 @@ var init_fastembed_provider = __esm({
4181
4298
  CACHE_FILE = join2(CACHE_DIR, ".embedding-cache.json");
4182
4299
  cache = /* @__PURE__ */ new Map();
4183
4300
  MAX_CACHE_SIZE = 5e3;
4301
+ DEFAULT_CACHE_PAYLOAD_BYTES = 64 * 1024 * 1024;
4302
+ MAX_CACHE_FILE_BYTES = 128 * 1024 * 1024;
4303
+ cachePayloadBytes = 0;
4184
4304
  diskCacheDirty = false;
4185
4305
  FastEmbedProvider = class _FastEmbedProvider {
4186
4306
  name = "fastembed-bge-small";
@@ -4222,7 +4342,7 @@ var init_fastembed_provider = __esm({
4222
4342
  if (result.length !== this.dimensions) {
4223
4343
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
4224
4344
  }
4225
- this.cacheSet(hash4, result);
4345
+ cacheSet(hash4, result);
4226
4346
  return result;
4227
4347
  }
4228
4348
  async embedBatch(texts) {
@@ -4247,7 +4367,7 @@ var init_fastembed_provider = __esm({
4247
4367
  const originalIdx = uncachedIndices[batchIdx];
4248
4368
  const plain = Array.from(vec);
4249
4369
  results[originalIdx] = plain;
4250
- this.cacheSet(textHash(uncachedTexts[batchIdx]), plain);
4370
+ cacheSet(textHash(uncachedTexts[batchIdx]), plain);
4251
4371
  batchIdx++;
4252
4372
  }
4253
4373
  }
@@ -4255,14 +4375,6 @@ var init_fastembed_provider = __esm({
4255
4375
  }
4256
4376
  return results;
4257
4377
  }
4258
- cacheSet(hash4, value) {
4259
- if (cache.size >= MAX_CACHE_SIZE) {
4260
- const firstKey = cache.keys().next().value;
4261
- if (firstKey !== void 0) cache.delete(firstKey);
4262
- }
4263
- cache.set(hash4, value);
4264
- diskCacheDirty = true;
4265
- }
4266
4378
  };
4267
4379
  }
4268
4380
  });
@@ -4272,7 +4384,15 @@ var transformers_provider_exports = {};
4272
4384
  __export(transformers_provider_exports, {
4273
4385
  TransformersProvider: () => TransformersProvider
4274
4386
  });
4275
- var cache2, MAX_CACHE_SIZE2, TransformersProvider;
4387
+ import { createHash as createHash2 } from "crypto";
4388
+ function cacheKey2(text3) {
4389
+ return createHash2("sha256").update(text3).digest("hex");
4390
+ }
4391
+ function maxCachePayloadBytes2() {
4392
+ const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
4393
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES2;
4394
+ }
4395
+ var cache2, MAX_CACHE_SIZE2, DEFAULT_CACHE_PAYLOAD_BYTES2, cachePayloadBytes2, TransformersProvider;
4276
4396
  var init_transformers_provider = __esm({
4277
4397
  "src/embedding/transformers-provider.ts"() {
4278
4398
  "use strict";
@@ -4280,6 +4400,8 @@ var init_transformers_provider = __esm({
4280
4400
  init_provider();
4281
4401
  cache2 = /* @__PURE__ */ new Map();
4282
4402
  MAX_CACHE_SIZE2 = 5e3;
4403
+ DEFAULT_CACHE_PAYLOAD_BYTES2 = 64 * 1024 * 1024;
4404
+ cachePayloadBytes2 = 0;
4283
4405
  TransformersProvider = class _TransformersProvider {
4284
4406
  name = "transformers-minilm";
4285
4407
  dimensions = 384;
@@ -4314,7 +4436,7 @@ var init_transformers_provider = __esm({
4314
4436
  return Promise.all(inputs.map((input) => this.embedInput(input, options)));
4315
4437
  }
4316
4438
  async embed(text3) {
4317
- const cached = cache2.get(text3);
4439
+ const cached = cache2.get(cacheKey2(text3));
4318
4440
  if (cached) return cached;
4319
4441
  const output = await this.extractor(text3, {
4320
4442
  pooling: "mean",
@@ -4324,7 +4446,7 @@ var init_transformers_provider = __esm({
4324
4446
  if (result.length !== this.dimensions) {
4325
4447
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
4326
4448
  }
4327
- this.cacheSet(text3, result);
4449
+ this.cacheSet(cacheKey2(text3), result);
4328
4450
  return result;
4329
4451
  }
4330
4452
  async embedBatch(texts) {
@@ -4332,7 +4454,7 @@ var init_transformers_provider = __esm({
4332
4454
  const uncachedIndices = [];
4333
4455
  const uncachedTexts = [];
4334
4456
  for (let i2 = 0; i2 < texts.length; i2++) {
4335
- const cached = cache2.get(texts[i2]);
4457
+ const cached = cache2.get(cacheKey2(texts[i2]));
4336
4458
  if (cached) {
4337
4459
  results[i2] = cached;
4338
4460
  } else {
@@ -4350,17 +4472,27 @@ var init_transformers_provider = __esm({
4350
4472
  const vec = Array.from(allVecs[i2]);
4351
4473
  const originalIdx = uncachedIndices[i2];
4352
4474
  results[originalIdx] = vec;
4353
- this.cacheSet(uncachedTexts[i2], vec);
4475
+ this.cacheSet(cacheKey2(uncachedTexts[i2]), vec);
4354
4476
  }
4355
4477
  }
4356
4478
  return results;
4357
4479
  }
4358
4480
  cacheSet(key, value) {
4359
- if (cache2.size >= MAX_CACHE_SIZE2) {
4360
- const firstKey = cache2.keys().next().value;
4361
- if (firstKey !== void 0) cache2.delete(firstKey);
4481
+ const incomingBytes = value.length * 8;
4482
+ if (incomingBytes > maxCachePayloadBytes2()) return;
4483
+ const existing = cache2.get(key);
4484
+ if (existing) cachePayloadBytes2 -= existing.length * 8;
4485
+ else {
4486
+ while (cache2.size >= MAX_CACHE_SIZE2 || cachePayloadBytes2 + incomingBytes > maxCachePayloadBytes2()) {
4487
+ const firstKey = cache2.keys().next().value;
4488
+ if (firstKey === void 0) break;
4489
+ const old = cache2.get(firstKey);
4490
+ cache2.delete(firstKey);
4491
+ if (old) cachePayloadBytes2 -= old.length * 8;
4492
+ }
4362
4493
  }
4363
4494
  cache2.set(key, value);
4495
+ cachePayloadBytes2 += incomingBytes;
4364
4496
  }
4365
4497
  };
4366
4498
  }
@@ -4382,7 +4514,7 @@ __export(api_provider_exports, {
4382
4514
  saveDiskCacheNow: () => saveDiskCacheNow,
4383
4515
  seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
4384
4516
  });
4385
- import { createHash as createHash2 } from "crypto";
4517
+ import { createHash as createHash3 } from "crypto";
4386
4518
  import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
4387
4519
  import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
4388
4520
  import { join as join3 } from "path";
@@ -4409,7 +4541,7 @@ function cacheStatFile() {
4409
4541
  function payloadBytes(vector) {
4410
4542
  return vector.length * BYTES_PER_DIM;
4411
4543
  }
4412
- function maxCachePayloadBytes() {
4544
+ function maxCachePayloadBytes3() {
4413
4545
  const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
4414
4546
  if (raw) {
4415
4547
  const parsed = Number.parseInt(raw, 10);
@@ -4419,7 +4551,7 @@ function maxCachePayloadBytes() {
4419
4551
  }
4420
4552
  function maxEntriesForDimensions(dimensions) {
4421
4553
  const dim = Math.max(1, Math.floor(dimensions));
4422
- const byBytes = Math.floor(maxCachePayloadBytes() / (dim * BYTES_PER_DIM));
4554
+ const byBytes = Math.floor(maxCachePayloadBytes3() / (dim * BYTES_PER_DIM));
4423
4555
  return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
4424
4556
  }
4425
4557
  function rememberDimensions(vector) {
@@ -4432,13 +4564,15 @@ function evictOldest() {
4432
4564
  if (firstKey === void 0) return;
4433
4565
  const old = cache3.get(firstKey);
4434
4566
  cache3.delete(firstKey);
4435
- if (old) cachePayloadBytes -= payloadBytes(old);
4567
+ if (old) cachePayloadBytes3 -= payloadBytes(old);
4436
4568
  }
4437
4569
  function evictToFit(incomingBytes, incomingDims) {
4570
+ if (incomingBytes > maxCachePayloadBytes3()) return false;
4438
4571
  const limit2 = maxEntriesForDimensions(incomingDims);
4439
- while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes + incomingBytes > maxCachePayloadBytes())) {
4572
+ while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes3 + incomingBytes > maxCachePayloadBytes3())) {
4440
4573
  evictOldest();
4441
4574
  }
4575
+ return true;
4442
4576
  }
4443
4577
  function isNumberArray(value) {
4444
4578
  return Array.isArray(value) && value.every((entry) => typeof entry === "number");
@@ -4465,12 +4599,12 @@ function cacheInsert(hash4, value, dirty) {
4465
4599
  const incoming = payloadBytes(value);
4466
4600
  const existing = cache3.get(hash4);
4467
4601
  if (existing) {
4468
- cachePayloadBytes -= payloadBytes(existing);
4602
+ cachePayloadBytes3 -= payloadBytes(existing);
4469
4603
  cache3.delete(hash4);
4470
4604
  }
4471
- evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
4605
+ if (!evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS)) return;
4472
4606
  cache3.set(hash4, value);
4473
- cachePayloadBytes += incoming;
4607
+ cachePayloadBytes3 += incoming;
4474
4608
  if (dirty) diskCacheDirty2 = true;
4475
4609
  }
4476
4610
  async function readCacheStat() {
@@ -4506,7 +4640,7 @@ function cacheNamespace(config) {
4506
4640
  ].join("|");
4507
4641
  }
4508
4642
  function textHash2(text3, namespace) {
4509
- return createHash2("sha256").update(`${namespace}\0${text3}`).digest("hex").slice(0, 16);
4643
+ return createHash3("sha256").update(`${namespace}\0${text3}`).digest("hex").slice(0, 16);
4510
4644
  }
4511
4645
  function inputIdentity(input, options = {}) {
4512
4646
  return JSON.stringify({
@@ -4848,7 +4982,7 @@ function getApiEmbeddingDiskCacheLoadCountForTests() {
4848
4982
  }
4849
4983
  function resetApiEmbeddingCacheForTests() {
4850
4984
  cache3.clear();
4851
- cachePayloadBytes = 0;
4985
+ cachePayloadBytes3 = 0;
4852
4986
  cacheDimensions = null;
4853
4987
  diskCacheEntryCount = 0;
4854
4988
  diskCacheLoaded = false;
@@ -4859,14 +4993,14 @@ function resetApiEmbeddingCacheForTests() {
4859
4993
  }
4860
4994
  function seedApiEmbeddingCacheForTests(entries) {
4861
4995
  cache3.clear();
4862
- cachePayloadBytes = 0;
4996
+ cachePayloadBytes3 = 0;
4863
4997
  cacheDimensions = null;
4864
4998
  for (const [key, value] of entries) cacheInsert(key, value, true);
4865
4999
  diskCacheLoaded = true;
4866
5000
  diskCacheDirty2 = true;
4867
5001
  }
4868
5002
  function getApiEmbeddingCachePayloadBytesForTests() {
4869
- return cachePayloadBytes;
5003
+ return cachePayloadBytes3;
4870
5004
  }
4871
5005
  function getApiEmbeddingJsonlLineCountCallsForTests() {
4872
5006
  return jsonlLineCountCalls;
@@ -5040,7 +5174,7 @@ function scheduleDiskSave() {
5040
5174
  diskSaveTimer = null;
5041
5175
  }, DISK_SAVE_DEBOUNCE_MS);
5042
5176
  }
5043
- function cacheSet(hash4, value) {
5177
+ function cacheSet2(hash4, value) {
5044
5178
  cacheInsert(hash4, value, true);
5045
5179
  }
5046
5180
  function resolveEnvEmbeddingApiKey() {
@@ -5160,7 +5294,7 @@ async function waitForRetry(waitMs, signal) {
5160
5294
  abortSignal.addEventListener("abort", onAbort, { once: true });
5161
5295
  });
5162
5296
  }
5163
- 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;
5297
+ 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;
5164
5298
  var init_api_provider = __esm({
5165
5299
  "src/embedding/api-provider.ts"() {
5166
5300
  "use strict";
@@ -5172,7 +5306,7 @@ var init_api_provider = __esm({
5172
5306
  BYTES_PER_DIM = 8;
5173
5307
  DEFAULT_ASSUMED_DIMENSIONS = 4096;
5174
5308
  MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
5175
- cachePayloadBytes = 0;
5309
+ cachePayloadBytes3 = 0;
5176
5310
  cacheDimensions = null;
5177
5311
  diskCacheEntryCount = 0;
5178
5312
  diskCacheDirty2 = false;
@@ -5357,7 +5491,7 @@ var init_api_provider = __esm({
5357
5491
  } else {
5358
5492
  embedding = await apiCall();
5359
5493
  }
5360
- cacheSet(hash4, embedding);
5494
+ cacheSet2(hash4, embedding);
5361
5495
  scheduleDiskSave();
5362
5496
  return embedding;
5363
5497
  }
@@ -5405,7 +5539,7 @@ var init_api_provider = __esm({
5405
5539
  for (const item of response.data) {
5406
5540
  const originalIdx = chunkIndices[item.index];
5407
5541
  results[originalIdx] = item.embedding;
5408
- cacheSet(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
5542
+ cacheSet2(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
5409
5543
  }
5410
5544
  } catch (error) {
5411
5545
  const providerLimit = parseBatchLimit(error);
@@ -5483,7 +5617,7 @@ var init_api_provider = __esm({
5483
5617
  throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d; dimension mismatch`);
5484
5618
  }
5485
5619
  this.trackUsage(response);
5486
- cacheSet(hash4, embedding);
5620
+ cacheSet2(hash4, embedding);
5487
5621
  scheduleDiskSave();
5488
5622
  return embedding;
5489
5623
  }
@@ -6866,6 +7000,7 @@ var init_provider2 = __esm({
6866
7000
  openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
6867
7001
  anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
6868
7002
  openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
7003
+ atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
6869
7004
  custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
6870
7005
  };
6871
7006
  currentConfig = null;
@@ -7629,7 +7764,7 @@ var init_obs_store = __esm({
7629
7764
  });
7630
7765
 
7631
7766
  // src/search/semantic-index.ts
7632
- import { createHash as createHash3 } from "crypto";
7767
+ import { createHash as createHash4 } from "crypto";
7633
7768
  import { createRequire as createRequire3 } from "module";
7634
7769
  import path11 from "path";
7635
7770
  function createSemanticIndexProfile(provider2) {
@@ -7643,7 +7778,7 @@ function stateKey(dataDir, profile) {
7643
7778
  return `${path11.resolve(dataDir)}::${profile.key}`;
7644
7779
  }
7645
7780
  function tableName(profile) {
7646
- const digest2 = createHash3("sha256").update(profile.key).digest("hex").slice(0, 20);
7781
+ const digest2 = createHash4("sha256").update(profile.key).digest("hex").slice(0, 20);
7647
7782
  return `${TABLE_PREFIX}${digest2}`;
7648
7783
  }
7649
7784
  function indexRoot(dataDir) {
@@ -9686,6 +9821,7 @@ var init_secret_filter = __esm({
9686
9821
  // src/runtime/maintenance-jobs.ts
9687
9822
  var maintenance_jobs_exports = {};
9688
9823
  __export(maintenance_jobs_exports, {
9824
+ DEFAULT_FAILED_HISTORY_RETENTION_MS: () => DEFAULT_FAILED_HISTORY_RETENTION_MS,
9689
9825
  MAINTENANCE_JOB_KINDS: () => MAINTENANCE_JOB_KINDS,
9690
9826
  MaintenanceJobStore: () => MaintenanceJobStore,
9691
9827
  MaintenanceJobWorker: () => MaintenanceJobWorker,
@@ -9735,7 +9871,7 @@ function normalizedKinds(kinds) {
9735
9871
  function getMaintenanceRetryDelayMs(attempts) {
9736
9872
  return Math.min(6e4, 1e3 * 2 ** Math.max(0, attempts - 1));
9737
9873
  }
9738
- var MAINTENANCE_JOB_KINDS, DEFAULT_MAX_ATTEMPTS, DEFAULT_LEASE_MS, DEFAULT_POLL_INTERVAL_MS, MAX_ERROR_LENGTH, DEFAULT_COMPLETED_HISTORY_RETENTION_MS, MaintenanceJobStore, MaintenanceJobWorker;
9874
+ 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;
9739
9875
  var init_maintenance_jobs = __esm({
9740
9876
  "src/runtime/maintenance-jobs.ts"() {
9741
9877
  "use strict";
@@ -9762,6 +9898,7 @@ var init_maintenance_jobs = __esm({
9762
9898
  DEFAULT_POLL_INTERVAL_MS = 2e3;
9763
9899
  MAX_ERROR_LENGTH = 1e3;
9764
9900
  DEFAULT_COMPLETED_HISTORY_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
9901
+ DEFAULT_FAILED_HISTORY_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
9765
9902
  MaintenanceJobStore = class {
9766
9903
  db;
9767
9904
  constructor(dataDir) {
@@ -9888,18 +10025,21 @@ var init_maintenance_jobs = __esm({
9888
10025
  }
9889
10026
  /**
9890
10027
  * Completed jobs are useful recent operator history, not permanent data.
9891
- * Failed jobs stay available for diagnosis until an operator explicitly
9892
- * resolves them or clears the database.
10028
+ * Failed diagnostics are retained longer, but are still bounded so a
10029
+ * permanently failing job kind cannot grow the database forever.
9893
10030
  */
9894
10031
  pruneCompletedHistory(options = {}) {
9895
10032
  const now3 = options.now ?? Date.now();
9896
10033
  const maxAgeMs = Number.isFinite(options.maxAgeMs) ? Math.max(0, Math.floor(options.maxAgeMs)) : DEFAULT_COMPLETED_HISTORY_RETENTION_MS;
10034
+ const failedMaxAgeMs = Number.isFinite(options.failedMaxAgeMs) ? Math.max(0, Math.floor(options.failedMaxAgeMs)) : DEFAULT_FAILED_HISTORY_RETENTION_MS;
9897
10035
  const result = this.db.prepare(`
9898
10036
  DELETE FROM maintenance_jobs
9899
- WHERE status = 'completed'
10037
+ WHERE (status = 'completed'
9900
10038
  AND completed_at IS NOT NULL
9901
- AND completed_at < ?
9902
- `).run(now3 - maxAgeMs);
10039
+ AND completed_at < ?)
10040
+ OR (status = 'failed'
10041
+ AND updated_at < ?)
10042
+ `).run(now3 - maxAgeMs, now3 - failedMaxAgeMs);
9903
10043
  return Number(result.changes ?? 0);
9904
10044
  }
9905
10045
  claimNext(options) {
@@ -10253,7 +10393,7 @@ var init_lifecycle = __esm({
10253
10393
  });
10254
10394
 
10255
10395
  // src/store/evidence-store.ts
10256
- import { createHash as createHash4, randomUUID as randomUUID3 } from "crypto";
10396
+ import { createHash as createHash5, randomUUID as randomUUID3 } from "crypto";
10257
10397
  function safeJson(value, fallback) {
10258
10398
  if (typeof value !== "string" || value.length === 0) return fallback;
10259
10399
  try {
@@ -10287,7 +10427,7 @@ function rowToCard(row) {
10287
10427
  };
10288
10428
  }
10289
10429
  function observationHash(observation) {
10290
- return createHash4("sha256").update(JSON.stringify({
10430
+ return createHash5("sha256").update(JSON.stringify({
10291
10431
  projectId: observation.projectId,
10292
10432
  id: observation.id,
10293
10433
  title: observation.title,
@@ -10881,13 +11021,13 @@ __export(workspace_exports, {
10881
11021
  loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
10882
11022
  resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
10883
11023
  });
10884
- import { createHash as createHash5 } from "crypto";
11024
+ import { createHash as createHash6 } from "crypto";
10885
11025
  import { execFile } from "child_process";
10886
11026
  import { promises as fs9 } from "fs";
10887
11027
  import path14 from "path";
10888
11028
  import { promisify } from "util";
10889
11029
  function hash(value) {
10890
- return createHash5("sha256").update(value).digest("hex");
11030
+ return createHash6("sha256").update(value).digest("hex");
10891
11031
  }
10892
11032
  function workspaceId(projectId, mode) {
10893
11033
  return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
@@ -12040,14 +12180,14 @@ __export(asset_store_exports, {
12040
12180
  readMediaAsset: () => readMediaAsset,
12041
12181
  removeMediaAsset: () => removeMediaAsset
12042
12182
  });
12043
- import { createHash as createHash6, randomUUID as randomUUID6 } from "crypto";
12183
+ import { createHash as createHash7, randomUUID as randomUUID6 } from "crypto";
12044
12184
  import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
12045
12185
  import path15 from "path";
12046
12186
  function mediaRoot(dataDir) {
12047
12187
  return path15.resolve(dataDir, "media");
12048
12188
  }
12049
12189
  function projectStorageKey(projectId) {
12050
- return createHash6("sha256").update(projectId).digest("hex").slice(0, 16);
12190
+ return createHash7("sha256").update(projectId).digest("hex").slice(0, 16);
12051
12191
  }
12052
12192
  function validateUnderRoot(root, candidate) {
12053
12193
  const resolved = path15.resolve(candidate);
@@ -12107,7 +12247,7 @@ async function readHeader(filePath, bytes = 32) {
12107
12247
  }
12108
12248
  async function sha256File(filePath) {
12109
12249
  const bytes = await readFile3(filePath);
12110
- return createHash6("sha256").update(bytes).digest("hex");
12250
+ return createHash7("sha256").update(bytes).digest("hex");
12111
12251
  }
12112
12252
  function destinationFor(root, projectId, sha256, extension3) {
12113
12253
  const relative5 = path15.join("assets", projectStorageKey(projectId), sha256.slice(0, 2), `${sha256}${extension3}`);
@@ -12213,7 +12353,7 @@ async function importMediaBuffer(input) {
12213
12353
  if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
12214
12354
  if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
12215
12355
  const detected = detectMedia(input.bytes.subarray(0, 32));
12216
- const sha256 = createHash6("sha256").update(input.bytes).digest("hex");
12356
+ const sha256 = createHash7("sha256").update(input.bytes).digest("hex");
12217
12357
  return importKnownMedia({
12218
12358
  dataDir: input.dataDir,
12219
12359
  projectId: input.projectId,
@@ -12231,7 +12371,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
12231
12371
  if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
12232
12372
  const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
12233
12373
  if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
12234
- const sha256 = createHash6("sha256").update(bytes).digest("hex");
12374
+ const sha256 = createHash7("sha256").update(bytes).digest("hex");
12235
12375
  if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
12236
12376
  return bytes;
12237
12377
  }
@@ -65101,7 +65241,7 @@ var require_gaxios = __commonJS({
65101
65241
  var retry_js_1 = require_retry3();
65102
65242
  var stream_1 = __require("stream");
65103
65243
  var interceptor_js_1 = require_interceptor();
65104
- var randomUUID19 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
65244
+ var randomUUID20 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
65105
65245
  var HTTP_STATUS_NO_CONTENT = 204;
65106
65246
  var Gaxios = class {
65107
65247
  agentCache = /* @__PURE__ */ new Map();
@@ -65374,7 +65514,7 @@ var require_gaxios = __commonJS({
65374
65514
  */
65375
65515
  ["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
65376
65516
  if (opts.multipart?.length) {
65377
- const boundary = await randomUUID19();
65517
+ const boundary = await randomUUID20();
65378
65518
  preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
65379
65519
  opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
65380
65520
  } else if (shouldDirectlyPassData) {
@@ -71046,16 +71186,16 @@ var require_jwtaccess = __commonJS({
71046
71186
  * @returns A string that returns the cached key.
71047
71187
  */
71048
71188
  getCachedKey(url, scopes) {
71049
- let cacheKey = url;
71189
+ let cacheKey3 = url;
71050
71190
  if (scopes && Array.isArray(scopes) && scopes.length) {
71051
- cacheKey = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
71191
+ cacheKey3 = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
71052
71192
  } else if (typeof scopes === "string") {
71053
- cacheKey = url ? `${url}_${scopes}` : scopes;
71193
+ cacheKey3 = url ? `${url}_${scopes}` : scopes;
71054
71194
  }
71055
- if (!cacheKey) {
71195
+ if (!cacheKey3) {
71056
71196
  throw Error("Scopes or url must be provided");
71057
71197
  }
71058
- return cacheKey;
71198
+ return cacheKey3;
71059
71199
  }
71060
71200
  /**
71061
71201
  * Get a non-expired access token, after refreshing if necessary.
@@ -77601,7 +77741,7 @@ var require_websocket = __commonJS({
77601
77741
  var http3 = __require("http");
77602
77742
  var net = __require("net");
77603
77743
  var tls = __require("tls");
77604
- var { randomBytes: randomBytes2, createHash: createHash19 } = __require("crypto");
77744
+ var { randomBytes: randomBytes2, createHash: createHash20 } = __require("crypto");
77605
77745
  var { Duplex, Readable: Readable2 } = __require("stream");
77606
77746
  var { URL: URL2 } = __require("url");
77607
77747
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -78269,7 +78409,7 @@ var require_websocket = __commonJS({
78269
78409
  abortHandshake(websocket, socket, "Invalid Upgrade header");
78270
78410
  return;
78271
78411
  }
78272
- const digest2 = createHash19("sha1").update(key + GUID).digest("base64");
78412
+ const digest2 = createHash20("sha1").update(key + GUID).digest("base64");
78273
78413
  if (res.headers["sec-websocket-accept"] !== digest2) {
78274
78414
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
78275
78415
  return;
@@ -78641,7 +78781,7 @@ var require_websocket_server = __commonJS({
78641
78781
  var EventEmitter2 = __require("events");
78642
78782
  var http3 = __require("http");
78643
78783
  var { Duplex } = __require("stream");
78644
- var { createHash: createHash19 } = __require("crypto");
78784
+ var { createHash: createHash20 } = __require("crypto");
78645
78785
  var extension3 = require_extension();
78646
78786
  var PerMessageDeflate2 = require_permessage_deflate();
78647
78787
  var subprotocol2 = require_subprotocol();
@@ -78948,7 +79088,7 @@ var require_websocket_server = __commonJS({
78948
79088
  );
78949
79089
  }
78950
79090
  if (this._state > RUNNING) return abortHandshake(socket, 503);
78951
- const digest2 = createHash19("sha1").update(key + GUID).digest("base64");
79091
+ const digest2 = createHash20("sha1").update(key + GUID).digest("base64");
78952
79092
  const headers = [
78953
79093
  "HTTP/1.1 101 Switching Protocols",
78954
79094
  "Upgrade: websocket",
@@ -143007,9 +143147,9 @@ var init_union_priority_sort = __esm({
143007
143147
  // node_modules/typebox/build/value/clean/from_union.mjs
143008
143148
  function FromUnion9(context, type, value) {
143009
143149
  for (const schema of UnionPrioritySort(type.anyOf)) {
143010
- const clean = FromType19(context, schema, Clone2(value));
143011
- if (Check2(context, schema, clean))
143012
- return clean;
143150
+ const clean2 = FromType19(context, schema, Clone2(value));
143151
+ if (Check2(context, schema, clean2))
143152
+ return clean2;
143013
143153
  }
143014
143154
  return value;
143015
143155
  }
@@ -147647,9 +147787,9 @@ var init_long_term = __esm({
147647
147787
  });
147648
147788
 
147649
147789
  // src/codegraph/ids.ts
147650
- import { createHash as createHash7 } from "crypto";
147790
+ import { createHash as createHash8 } from "crypto";
147651
147791
  function digest(input) {
147652
- return createHash7("sha256").update(input).digest("hex").slice(0, 16);
147792
+ return createHash8("sha256").update(input).digest("hex").slice(0, 16);
147653
147793
  }
147654
147794
  function normalizeCodePath(path38) {
147655
147795
  return path38.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
@@ -148697,7 +148837,7 @@ var init_store = __esm({
148697
148837
 
148698
148838
  // src/codegraph/code-state.ts
148699
148839
  import { execFile as execFile2 } from "child_process";
148700
- import { createHash as createHash8 } from "crypto";
148840
+ import { createHash as createHash9 } from "crypto";
148701
148841
  import { promisify as promisify3 } from "util";
148702
148842
  async function runGit(rootPath, args) {
148703
148843
  try {
@@ -148726,7 +148866,7 @@ function changedPathCount(status) {
148726
148866
  return count2;
148727
148867
  }
148728
148868
  function fingerprint(baseRevision, status) {
148729
- return createHash8("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
148869
+ return createHash9("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
148730
148870
  }
148731
148871
  async function collectCodeStateSnapshot(input) {
148732
148872
  const [revision, status] = await Promise.all([
@@ -148820,12 +148960,12 @@ var init_exclude3 = __esm({
148820
148960
  });
148821
148961
 
148822
148962
  // src/codegraph/semantic-provider.ts
148823
- import { createHash as createHash9 } from "crypto";
148963
+ import { createHash as createHash10 } from "crypto";
148824
148964
  import "fs";
148825
148965
  import { resolve } from "path";
148826
148966
  import ts from "typescript";
148827
148967
  function hashText(value) {
148828
- return createHash9("sha256").update(value).digest("hex");
148968
+ return createHash10("sha256").update(value).digest("hex");
148829
148969
  }
148830
148970
  function canonicalPath(value) {
148831
148971
  const normalized = resolve(value).replace(/\\/g, "/");
@@ -149170,11 +149310,11 @@ __export(lite_provider_exports, {
149170
149310
  indexProjectLite: () => indexProjectLite,
149171
149311
  refreshProjectLite: () => refreshProjectLite
149172
149312
  });
149173
- import { createHash as createHash10 } from "crypto";
149313
+ import { createHash as createHash11 } from "crypto";
149174
149314
  import { existsSync as existsSync12, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
149175
149315
  import { join as join4, relative as relative2 } from "path";
149176
149316
  function hashText2(text3) {
149177
- return createHash10("sha256").update(text3).digest("hex");
149317
+ return createHash11("sha256").update(text3).digest("hex");
149178
149318
  }
149179
149319
  function extension2(path38) {
149180
149320
  const index = path38.lastIndexOf(".");
@@ -149807,7 +149947,7 @@ var claim_store_exports = {};
149807
149947
  __export(claim_store_exports, {
149808
149948
  ClaimStore: () => ClaimStore
149809
149949
  });
149810
- import { createHash as createHash11, randomUUID as randomUUID12 } from "crypto";
149950
+ import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
149811
149951
  function optionalText3(value) {
149812
149952
  return typeof value === "string" && value ? value : void 0;
149813
149953
  }
@@ -149860,7 +150000,7 @@ function rowToEvent3(row) {
149860
150000
  };
149861
150001
  }
149862
150002
  function evidenceKey(input) {
149863
- return createHash11("sha256").update(JSON.stringify([
150003
+ return createHash12("sha256").update(JSON.stringify([
149864
150004
  input.evidenceKind,
149865
150005
  input.evidenceId,
149866
150006
  input.relation,
@@ -150058,7 +150198,7 @@ __export(claims_exports, {
150058
150198
  supersedeClaim: () => supersedeClaim,
150059
150199
  writeClaim: () => writeClaim
150060
150200
  });
150061
- import { createHash as createHash12, randomUUID as randomUUID13 } from "crypto";
150201
+ import { createHash as createHash13, randomUUID as randomUUID13 } from "crypto";
150062
150202
  function compactText2(value, field) {
150063
150203
  if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
150064
150204
  const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
@@ -150070,7 +150210,7 @@ function normalizedTerm(value) {
150070
150210
  return compactText2(value, "identity").toLocaleLowerCase("en-US");
150071
150211
  }
150072
150212
  function hashIdentity(parts) {
150073
- return createHash12("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
150213
+ return createHash13("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
150074
150214
  }
150075
150215
  function buildClaimIdentity(input) {
150076
150216
  const subject = normalizedTerm(input.subject);
@@ -150311,7 +150451,7 @@ function supersedeClaim(store, input) {
150311
150451
  });
150312
150452
  }
150313
150453
  function hashObservation(observation) {
150314
- return createHash12("sha256").update(JSON.stringify([
150454
+ return createHash13("sha256").update(JSON.stringify([
150315
150455
  observation.title,
150316
150456
  observation.narrative,
150317
150457
  observation.facts,
@@ -150555,11 +150695,11 @@ var init_frontmatter = __esm({
150555
150695
  });
150556
150696
 
150557
150697
  // src/knowledge/markdown.ts
150558
- import { createHash as createHash13 } from "crypto";
150698
+ import { createHash as createHash14 } from "crypto";
150559
150699
  import { promises as fs13 } from "fs";
150560
150700
  import path22 from "path";
150561
150701
  function hashContent(content) {
150562
- return createHash13("sha256").update(content).digest("hex");
150702
+ return createHash14("sha256").update(content).digest("hex");
150563
150703
  }
150564
150704
  function stringField(data, key) {
150565
150705
  const value = data[key];
@@ -150685,11 +150825,11 @@ __export(wiki_exports, {
150685
150825
  lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
150686
150826
  readKnowledgePage: () => readKnowledgePage
150687
150827
  });
150688
- import { createHash as createHash14 } from "crypto";
150828
+ import { createHash as createHash15 } from "crypto";
150689
150829
  import { promises as fs14 } from "fs";
150690
150830
  import path23 from "path";
150691
150831
  function hash2(value) {
150692
- return createHash14("sha256").update(value).digest("hex");
150832
+ return createHash15("sha256").update(value).digest("hex");
150693
150833
  }
150694
150834
  function now() {
150695
150835
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -151908,11 +152048,11 @@ __export(workflows_exports, {
151908
152048
  syncCanonicalWorkflows: () => syncCanonicalWorkflows,
151909
152049
  writeCanonicalWorkflow: () => writeCanonicalWorkflow
151910
152050
  });
151911
- import { createHash as createHash15 } from "crypto";
152051
+ import { createHash as createHash16 } from "crypto";
151912
152052
  import { promises as fs15 } from "fs";
151913
152053
  import path24 from "path";
151914
152054
  function hash3(value) {
151915
- return createHash15("sha256").update(value).digest("hex");
152055
+ return createHash16("sha256").update(value).digest("hex");
151916
152056
  }
151917
152057
  function now2() {
151918
152058
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -156273,9 +156413,9 @@ var init_graph_context = __esm({
156273
156413
  });
156274
156414
 
156275
156415
  // src/rules/utils.ts
156276
- import { createHash as createHash16 } from "crypto";
156416
+ import { createHash as createHash17 } from "crypto";
156277
156417
  function hashContent2(content) {
156278
- return createHash16("sha256").update(content.trim()).digest("hex").substring(0, 16);
156418
+ return createHash17("sha256").update(content.trim()).digest("hex").substring(0, 16);
156279
156419
  }
156280
156420
  function generateRuleId(source, filePath) {
156281
156421
  const sanitized = filePath.replace(/[\/\\]/g, "-").replace(/^\./, "");
@@ -158718,6 +158858,7 @@ var init_tool_profile = __esm({
158718
158858
  // keep the default micro profile at its nine-tool token budget.
158719
158859
  memorix_evidence: ["lite", "team", "full"],
158720
158860
  memorix_feedback: ["lite", "team", "full"],
158861
+ memorix_continuity: ["lite", "team", "full"],
158721
158862
  // ── lite: extended solo memory surface ────────────────────────────
158722
158863
  memorix_graph_context: ["lite", "team", "full"],
158723
158864
  memorix_timeline: ["lite", "team", "full"],
@@ -159951,7 +160092,7 @@ var init_request_context = __esm({
159951
160092
  function getMcpServerInfo() {
159952
160093
  return {
159953
160094
  name: "memorix",
159954
- version: true ? "1.9.5" : "1.0.1"
160095
+ version: true ? "1.9.6" : "1.0.1"
159955
160096
  };
159956
160097
  }
159957
160098
  function createMcpDiscoverResult(capabilities, serverInfo) {
@@ -160040,8 +160181,8 @@ function legacyBehavior(homeDir) {
160040
160181
  function getBehaviorConfig(options = {}) {
160041
160182
  const homeDir = options.homeDir ?? homedir22();
160042
160183
  const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
160043
- const cacheKey = `${homeDir}\0${projectRoot ?? ""}`;
160044
- const cached = cache4.get(cacheKey);
160184
+ const cacheKey3 = `${homeDir}\0${projectRoot ?? ""}`;
160185
+ const cached = cache4.get(cacheKey3);
160045
160186
  if (cached) return cached;
160046
160187
  const legacy = legacyBehavior(homeDir);
160047
160188
  let resolved = {};
@@ -160055,7 +160196,7 @@ function getBehaviorConfig(options = {}) {
160055
160196
  autoCleanup: typeof resolved.autoCleanup === "boolean" ? resolved.autoCleanup : typeof legacy.autoCleanup === "boolean" ? legacy.autoCleanup : DEFAULTS.autoCleanup,
160056
160197
  formationMode: isFormationMode(resolved.formation) ? resolved.formation : isFormationMode(legacy.formationMode) ? legacy.formationMode : DEFAULTS.formationMode
160057
160198
  };
160058
- cache4.set(cacheKey, config);
160199
+ cache4.set(cacheKey3, config);
160059
160200
  return config;
160060
160201
  }
160061
160202
  function resetBehaviorConfigCache() {
@@ -160660,6 +160801,7 @@ function freshnessForMemory(status) {
160660
160801
  return "unknown";
160661
160802
  }
160662
160803
  function receiptOmissionKind(raw) {
160804
+ if (raw.includes("continuity")) return "continuity";
160663
160805
  if (raw.includes("continuation")) return "continuation";
160664
160806
  if (raw.includes("task")) return "task";
160665
160807
  if (raw.includes("fact")) return "current-fact";
@@ -160770,6 +160912,77 @@ function renderTaskWorksetPrompt(input) {
160770
160912
  trust: "source-backed"
160771
160913
  });
160772
160914
  appendLine(lines, "Task lens: " + input.lens, maxTokens, omitted, "lens");
160915
+ if (input.continuity) {
160916
+ const continuity = input.continuity;
160917
+ appendLine(lines, "", maxTokens, omitted, "continuity-heading");
160918
+ appendLine(lines, "Task continuity", maxTokens, omitted, "continuity-heading", selected, {
160919
+ kind: "continuity",
160920
+ id: "continuity:" + continuity.taskId,
160921
+ reason: "explicit task continuity ledger",
160922
+ trust: "source-backed"
160923
+ });
160924
+ appendLine(
160925
+ lines,
160926
+ "- Status: " + continuity.status + " | " + short(continuity.task, 30),
160927
+ maxTokens,
160928
+ omitted,
160929
+ "continuity-task"
160930
+ );
160931
+ appendLine(
160932
+ lines,
160933
+ "- Outcome: " + continuity.outcome.state,
160934
+ maxTokens,
160935
+ omitted,
160936
+ "continuity-outcome",
160937
+ selected,
160938
+ {
160939
+ kind: "continuity",
160940
+ id: "continuity:" + continuity.taskId,
160941
+ reason: "deterministic task outcome projection",
160942
+ trust: "derived"
160943
+ }
160944
+ );
160945
+ for (const requirement of continuity.requirements.slice(0, 3)) {
160946
+ appendLine(lines, "- Requirement: " + short(requirement, 24), maxTokens, omitted, "continuity-requirement", selected, {
160947
+ kind: "continuity",
160948
+ id: "continuity:" + continuity.taskId,
160949
+ reason: "explicit task requirement",
160950
+ trust: "source-backed"
160951
+ });
160952
+ }
160953
+ for (const decision of continuity.decisions.slice(0, 2)) {
160954
+ appendLine(lines, "- Decision: " + short(decision, 24), maxTokens, omitted, "continuity-decision", selected, {
160955
+ kind: "continuity",
160956
+ id: "continuity:" + continuity.taskId,
160957
+ reason: "explicit task decision",
160958
+ trust: "source-backed"
160959
+ });
160960
+ }
160961
+ for (const verification of continuity.verification.slice(-3)) {
160962
+ appendLine(
160963
+ lines,
160964
+ "- Verify [" + verification.status + "]: " + short(verification.content, 22),
160965
+ maxTokens,
160966
+ omitted,
160967
+ "continuity-verification",
160968
+ selected,
160969
+ {
160970
+ kind: "continuity",
160971
+ id: "continuity:" + continuity.taskId,
160972
+ reason: "task verification state",
160973
+ trust: "source-backed"
160974
+ }
160975
+ );
160976
+ }
160977
+ for (const risk of continuity.risks.slice(0, 2)) {
160978
+ appendLine(lines, "- Risk: " + short(risk, 22), maxTokens, omitted, "continuity-risk", selected, {
160979
+ kind: "continuity",
160980
+ id: "continuity:" + continuity.taskId,
160981
+ reason: "open task risk",
160982
+ trust: "source-backed"
160983
+ });
160984
+ }
160985
+ }
160773
160986
  if (input.alwaysOn) {
160774
160987
  const hasAlwaysOn = input.alwaysOn.profile.length > 0 || Boolean(input.alwaysOn.state) || input.alwaysOn.durable.length > 0;
160775
160988
  if (hasAlwaysOn) {
@@ -161293,6 +161506,7 @@ async function buildTaskWorkset(input) {
161293
161506
  version: "1.3",
161294
161507
  task,
161295
161508
  lens: input.lens,
161509
+ ...input.continuity ? { continuity: input.continuity } : {},
161296
161510
  ...input.alwaysOn && (input.alwaysOn.profile.length > 0 || input.alwaysOn.state || input.alwaysOn.durable.length > 0) ? { alwaysOn: input.alwaysOn } : {},
161297
161511
  currentFacts: input.currentFacts?.map((fact) => fact.startsWith("Historical note:") ? short(fact, 48) : short(fact, 28)).slice(0, 4) ?? [],
161298
161512
  ...continuation ? { continuation } : {},
@@ -162677,7 +162891,7 @@ var compaction_checkpoint_store_exports = {};
162677
162891
  __export(compaction_checkpoint_store_exports, {
162678
162892
  CompactionCheckpointStore: () => CompactionCheckpointStore
162679
162893
  });
162680
- import { createHash as createHash17, randomUUID as randomUUID16 } from "crypto";
162894
+ import { createHash as createHash18, randomUUID as randomUUID16 } from "crypto";
162681
162895
  function optionalText7(value) {
162682
162896
  return typeof value === "string" && value ? value : void 0;
162683
162897
  }
@@ -162719,7 +162933,7 @@ function sourceKeyFor(input, summary) {
162719
162933
  input.tokensBefore ?? "",
162720
162934
  input.firstKeptEntryId ?? ""
162721
162935
  ].join("\0");
162722
- return `derived:${createHash17("sha256").update(material).digest("hex").slice(0, 32)}`;
162936
+ return `derived:${createHash18("sha256").update(material).digest("hex").slice(0, 32)}`;
162723
162937
  }
162724
162938
  function rowToCheckpoint(row) {
162725
162939
  return {
@@ -162977,6 +163191,305 @@ var init_compaction_checkpoint_store = __esm({
162977
163191
  }
162978
163192
  });
162979
163193
 
163194
+ // src/knowledge/task-continuity.ts
163195
+ var task_continuity_exports = {};
163196
+ __export(task_continuity_exports, {
163197
+ TASK_CONTINUITY_EVENT_KINDS: () => TASK_CONTINUITY_EVENT_KINDS,
163198
+ TaskContinuityStore: () => TaskContinuityStore,
163199
+ evaluateTaskContinuity: () => evaluateTaskContinuity
163200
+ });
163201
+ import { randomUUID as randomUUID17 } from "crypto";
163202
+ function clean(value, maxLength = MAX_TEXT_LENGTH2) {
163203
+ return sanitizeCredentials(value).replace(/\s+/g, " ").trim().slice(0, maxLength);
163204
+ }
163205
+ function cleanList(values, maxLength = MAX_TEXT_LENGTH2) {
163206
+ return [...new Set((values ?? []).map((value) => clean(value, maxLength)).filter(Boolean))].slice(0, MAX_LIST_ITEMS2);
163207
+ }
163208
+ function parseRefs(value) {
163209
+ if (typeof value !== "string") return [];
163210
+ try {
163211
+ const parsed = JSON.parse(value);
163212
+ return Array.isArray(parsed) ? cleanList(parsed.filter((item) => typeof item === "string"), 500).slice(0, MAX_EVIDENCE_REFS) : [];
163213
+ } catch {
163214
+ return [];
163215
+ }
163216
+ }
163217
+ function evaluateTaskContinuity(ledger) {
163218
+ const verification = {
163219
+ passed: ledger.verification.filter((item) => item.status === "passed").length,
163220
+ failed: ledger.verification.filter((item) => item.status === "failed").length,
163221
+ pending: ledger.verification.filter((item) => item.status === "pending").length,
163222
+ skipped: ledger.verification.filter((item) => item.status === "skipped").length
163223
+ };
163224
+ const reasons = [];
163225
+ if (verification.failed > 0) reasons.push("verification-failed");
163226
+ if (verification.pending > 0) reasons.push("verification-pending");
163227
+ if (ledger.risks.length > 0) reasons.push("open-risks");
163228
+ if (ledger.status === "blocked") reasons.push("task-blocked");
163229
+ if (ledger.status === "abandoned") reasons.push("task-abandoned");
163230
+ if (ledger.status === "blocked" || ledger.status === "abandoned" || verification.failed > 0) {
163231
+ return {
163232
+ state: "at-risk",
163233
+ score: verification.passed > verification.failed ? 0.55 : 0.2,
163234
+ verification,
163235
+ reasons
163236
+ };
163237
+ }
163238
+ if (ledger.status === "completed") {
163239
+ if (verification.passed > 0 && verification.pending === 0 && verification.skipped === 0) {
163240
+ return {
163241
+ state: ledger.risks.length > 0 ? "validated-with-risks" : "validated",
163242
+ score: ledger.risks.length > 0 ? 0.8 : 1,
163243
+ verification,
163244
+ reasons: reasons.length > 0 ? reasons : ["verification-passed"]
163245
+ };
163246
+ }
163247
+ return {
163248
+ state: "unverified",
163249
+ score: 0.4,
163250
+ verification,
163251
+ reasons: reasons.length > 0 ? reasons : ["no-passing-verification"]
163252
+ };
163253
+ }
163254
+ return {
163255
+ state: "in-progress",
163256
+ score: verification.passed > 0 && verification.pending === 0 ? 0.75 : 0.5,
163257
+ verification,
163258
+ reasons: reasons.length > 0 ? reasons : ["task-open"]
163259
+ };
163260
+ }
163261
+ function rowToEvent4(row) {
163262
+ const status = row.item_status ? String(row.item_status) : void 0;
163263
+ return {
163264
+ id: String(row.id),
163265
+ projectId: String(row.project_id),
163266
+ taskId: String(row.task_id),
163267
+ task: clean(String(row.task), MAX_TASK_LENGTH),
163268
+ kind: row.kind,
163269
+ content: clean(String(row.content)),
163270
+ ...status ? { status } : {},
163271
+ ...row.source_ref ? { sourceRef: clean(String(row.source_ref), 500) } : {},
163272
+ evidenceRefs: parseRefs(row.evidence_json),
163273
+ ...row.actor ? { actor: clean(String(row.actor), 200) } : {},
163274
+ at: String(row.created_at),
163275
+ ...row.event_key ? { eventKey: clean(String(row.event_key), 200) } : {},
163276
+ ...row.item_key ? { itemKey: clean(String(row.item_key), 120) } : {},
163277
+ ...row.supersedes_id ? { supersedesId: clean(String(row.supersedes_id), 120) } : {}
163278
+ };
163279
+ }
163280
+ function aggregate(events) {
163281
+ const first2 = events.find((event) => event.kind === "task") ?? events[0];
163282
+ const latestOutcome = [...events].reverse().find((event) => event.kind === "outcome");
163283
+ const verificationByKey = /* @__PURE__ */ new Map();
163284
+ for (const event of events.filter((event2) => event2.kind === "verification")) {
163285
+ verificationByKey.set(event.itemKey ?? `event:${event.id}`, event);
163286
+ }
163287
+ const ledger = {
163288
+ taskId: first2.taskId,
163289
+ projectId: first2.projectId,
163290
+ task: first2.task,
163291
+ status: latestOutcome?.status ?? "open",
163292
+ requirements: events.filter((event) => event.kind === "requirement").map((event) => event.content),
163293
+ decisions: events.filter((event) => event.kind === "decision").map((event) => event.content),
163294
+ verification: [...verificationByKey.values()].map((event) => ({
163295
+ id: event.itemKey ?? event.id,
163296
+ content: event.content,
163297
+ status: event.status ?? "pending",
163298
+ ...event.sourceRef ? { sourceRef: event.sourceRef } : {},
163299
+ evidenceRefs: event.evidenceRefs
163300
+ })),
163301
+ risks: events.filter((event) => event.kind === "risk").map((event) => event.content),
163302
+ outcomes: events.filter((event) => event.kind === "outcome").map((event) => event.content),
163303
+ updatedAt: events[events.length - 1].at,
163304
+ events
163305
+ };
163306
+ return { ...ledger, outcome: evaluateTaskContinuity(ledger) };
163307
+ }
163308
+ var TASK_CONTINUITY_EVENT_KINDS, MAX_TEXT_LENGTH2, MAX_TASK_LENGTH, MAX_LIST_ITEMS2, MAX_EVIDENCE_REFS, MAX_EVENTS_PER_TASK, TaskContinuityStore;
163309
+ var init_task_continuity = __esm({
163310
+ "src/knowledge/task-continuity.ts"() {
163311
+ "use strict";
163312
+ init_esm_shims();
163313
+ init_secret_filter();
163314
+ init_sqlite_db();
163315
+ TASK_CONTINUITY_EVENT_KINDS = [
163316
+ "task",
163317
+ "requirement",
163318
+ "decision",
163319
+ "verification",
163320
+ "risk",
163321
+ "outcome"
163322
+ ];
163323
+ MAX_TEXT_LENGTH2 = 2e3;
163324
+ MAX_TASK_LENGTH = 1e3;
163325
+ MAX_LIST_ITEMS2 = 8;
163326
+ MAX_EVIDENCE_REFS = 8;
163327
+ MAX_EVENTS_PER_TASK = 200;
163328
+ TaskContinuityStore = class {
163329
+ db = null;
163330
+ async init(dataDir) {
163331
+ this.db = getDatabase(dataDir);
163332
+ }
163333
+ requireDb() {
163334
+ if (!this.db) throw new Error("TaskContinuityStore is not initialized.");
163335
+ return this.db;
163336
+ }
163337
+ insert(input) {
163338
+ const db2 = this.requireDb();
163339
+ const projectId = clean(input.projectId, 500);
163340
+ const taskId = clean(input.taskId, 120);
163341
+ const eventKey = input.eventKey ? clean(input.eventKey, 200) : void 0;
163342
+ if (eventKey) {
163343
+ const existing = db2.prepare(
163344
+ "SELECT * FROM task_continuity_events WHERE project_id = ? AND task_id = ? AND event_key = ?"
163345
+ ).get(projectId, taskId, eventKey);
163346
+ if (existing) return rowToEvent4(existing);
163347
+ }
163348
+ const existingCount = db2.prepare(
163349
+ "SELECT COUNT(*) AS count FROM task_continuity_events WHERE project_id = ? AND task_id = ?"
163350
+ ).get(projectId, taskId);
163351
+ if (Number(existingCount?.count ?? 0) >= MAX_EVENTS_PER_TASK) {
163352
+ throw new Error("Task continuity ledger reached its 200-event limit.");
163353
+ }
163354
+ const event = {
163355
+ id: randomUUID17(),
163356
+ projectId,
163357
+ taskId,
163358
+ task: clean(input.task, MAX_TASK_LENGTH),
163359
+ kind: input.kind,
163360
+ content: clean(input.content),
163361
+ ...input.status ? { status: input.status } : {},
163362
+ ...input.sourceRef ? { sourceRef: clean(input.sourceRef, 500) } : {},
163363
+ evidenceRefs: cleanList(input.evidenceRefs, 500).slice(0, MAX_EVIDENCE_REFS),
163364
+ ...input.actor ? { actor: clean(input.actor, 200) } : {},
163365
+ at: input.at ?? (/* @__PURE__ */ new Date()).toISOString(),
163366
+ ...eventKey ? { eventKey } : {},
163367
+ ...input.itemKey ? { itemKey: clean(input.itemKey, 120) } : {},
163368
+ ...input.supersedesId ? { supersedesId: clean(input.supersedesId, 120) } : {}
163369
+ };
163370
+ db2.prepare(`
163371
+ INSERT INTO task_continuity_events (
163372
+ id, project_id, task_id, task, kind, content, item_status,
163373
+ source_ref, evidence_json, actor, created_at, event_key, item_key, supersedes_id
163374
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
163375
+ `).run(
163376
+ event.id,
163377
+ event.projectId,
163378
+ event.taskId,
163379
+ event.task,
163380
+ event.kind,
163381
+ event.content,
163382
+ event.status ?? null,
163383
+ event.sourceRef ?? null,
163384
+ JSON.stringify(event.evidenceRefs),
163385
+ event.actor ?? null,
163386
+ event.at,
163387
+ event.eventKey ?? null,
163388
+ event.itemKey ?? null,
163389
+ event.supersedesId ?? null
163390
+ );
163391
+ return event;
163392
+ }
163393
+ start(input) {
163394
+ const task = clean(input.task, MAX_TASK_LENGTH);
163395
+ if (!task) throw new Error("A non-empty task is required.");
163396
+ const idempotencyKey = input.idempotencyKey ? clean(input.idempotencyKey, 200) : void 0;
163397
+ const taskId = clean(input.taskId ?? idempotencyKey ?? "", 120) || randomUUID17();
163398
+ const requirements = cleanList(input.requirements);
163399
+ const transaction = this.requireDb().transaction(() => {
163400
+ this.insert({
163401
+ projectId: input.projectId,
163402
+ taskId,
163403
+ task,
163404
+ kind: "task",
163405
+ content: task,
163406
+ status: "open",
163407
+ actor: input.actor,
163408
+ ...idempotencyKey ? { eventKey: `start:${idempotencyKey}` } : {}
163409
+ });
163410
+ for (const requirement of requirements) {
163411
+ this.insert({
163412
+ projectId: input.projectId,
163413
+ taskId,
163414
+ task,
163415
+ kind: "requirement",
163416
+ content: requirement,
163417
+ actor: input.actor
163418
+ });
163419
+ }
163420
+ });
163421
+ transaction.immediate();
163422
+ return { taskId, ledger: this.get(input.projectId, taskId) };
163423
+ }
163424
+ record(input) {
163425
+ const projectId = clean(input.projectId, 500);
163426
+ const taskId = clean(input.taskId, 120);
163427
+ const existing = this.get(projectId, taskId);
163428
+ if (!existing) throw new Error("Task continuity ledger not found: " + taskId);
163429
+ const transaction = this.requireDb().transaction(() => this.insert({
163430
+ projectId,
163431
+ taskId,
163432
+ task: existing.task,
163433
+ kind: input.kind,
163434
+ content: input.content,
163435
+ ...input.kind === "verification" && input.verificationStatus ? { status: input.verificationStatus } : {},
163436
+ sourceRef: input.sourceRef,
163437
+ evidenceRefs: input.evidenceRefs,
163438
+ actor: input.actor,
163439
+ at: input.at,
163440
+ ...input.idempotencyKey ? { eventKey: input.idempotencyKey } : {},
163441
+ ...input.verificationId ? { itemKey: input.verificationId } : {}
163442
+ }));
163443
+ const event = transaction.immediate();
163444
+ return { event, ledger: this.get(projectId, taskId) };
163445
+ }
163446
+ close(input) {
163447
+ const projectId = clean(input.projectId, 500);
163448
+ const taskId = clean(input.taskId, 120);
163449
+ const existing = this.get(projectId, taskId);
163450
+ if (!existing) throw new Error("Task continuity ledger not found: " + taskId);
163451
+ const transaction = this.requireDb().transaction(() => this.insert({
163452
+ projectId,
163453
+ taskId,
163454
+ task: existing.task,
163455
+ kind: "outcome",
163456
+ content: input.content,
163457
+ status: input.status,
163458
+ sourceRef: input.sourceRef,
163459
+ evidenceRefs: input.evidenceRefs,
163460
+ actor: input.actor,
163461
+ at: input.at,
163462
+ ...input.idempotencyKey ? { eventKey: input.idempotencyKey } : {}
163463
+ }));
163464
+ const event = transaction.immediate();
163465
+ return { event, ledger: this.get(projectId, taskId) };
163466
+ }
163467
+ get(projectId, taskId) {
163468
+ const normalizedProjectId = clean(projectId, 500);
163469
+ const normalizedTaskId = clean(taskId, 120);
163470
+ const rows = this.requireDb().prepare(`
163471
+ SELECT * FROM task_continuity_events
163472
+ WHERE project_id = ? AND task_id = ?
163473
+ ORDER BY created_at ASC, rowid ASC
163474
+ `).all(normalizedProjectId, normalizedTaskId);
163475
+ if (rows.length === 0) return void 0;
163476
+ return aggregate(rows.map(rowToEvent4));
163477
+ }
163478
+ list(projectId, limit2 = 20) {
163479
+ const rows = this.requireDb().prepare(`
163480
+ SELECT task_id
163481
+ FROM task_continuity_events
163482
+ WHERE project_id = ?
163483
+ GROUP BY task_id
163484
+ ORDER BY MAX(created_at) DESC
163485
+ LIMIT ?
163486
+ `).all(projectId, Math.min(100, Math.max(1, Math.floor(limit2))));
163487
+ return rows.map((row) => this.get(projectId, String(row.task_id))).filter((ledger) => Boolean(ledger));
163488
+ }
163489
+ };
163490
+ }
163491
+ });
163492
+
162980
163493
  // src/codegraph/auto-context.ts
162981
163494
  var auto_context_exports = {};
162982
163495
  __export(auto_context_exports, {
@@ -163233,6 +163746,16 @@ async function buildAutoProjectContext(input) {
163233
163746
  };
163234
163747
  }
163235
163748
  }
163749
+ let continuity = input.continuity;
163750
+ if (!continuity && input.taskId) {
163751
+ try {
163752
+ const { TaskContinuityStore: TaskContinuityStore2 } = await Promise.resolve().then(() => (init_task_continuity(), task_continuity_exports));
163753
+ const continuityStore = new TaskContinuityStore2();
163754
+ await continuityStore.init(input.dataDir);
163755
+ continuity = continuityStore.get(input.project.id, input.taskId);
163756
+ } catch {
163757
+ }
163758
+ }
163236
163759
  const alwaysOn = await buildAlwaysOnBlock({
163237
163760
  dataDir: input.dataDir,
163238
163761
  projectId: input.project.id,
@@ -163251,6 +163774,7 @@ async function buildAutoProjectContext(input) {
163251
163774
  providerQuality: providerQuality2,
163252
163775
  currentFacts: worksetFactLines(currentFacts),
163253
163776
  ...continuation ? { continuation } : {},
163777
+ ...continuity ? { continuity } : {},
163254
163778
  codeState: codeStateLine(overview),
163255
163779
  ...codeEvolution ? { codeEvolution } : {},
163256
163780
  reliableMemory: sourceSets.reliableSources.slice(0, lens.sourceLimit).map((source) => ({
@@ -163298,6 +163822,7 @@ async function buildAutoProjectContext(input) {
163298
163822
  refresh,
163299
163823
  providerQuality: providerQuality2,
163300
163824
  ...continuationRequested && workset.continuation ? { continuation: workset.continuation } : {},
163825
+ ...workset.continuity ? { continuity: workset.continuity } : {},
163301
163826
  workset
163302
163827
  };
163303
163828
  }
@@ -163599,7 +164124,14 @@ function buildBoundedContextReceipt(input) {
163599
164124
  externalState: provider2?.external.state ?? "not-detected",
163600
164125
  ...input.workset.provenance.snapshotId ? { snapshotId: input.workset.provenance.snapshotId } : {}
163601
164126
  },
163602
- ...input.workset.agentLoadout ? { loadout: input.workset.agentLoadout } : {}
164127
+ ...input.workset.agentLoadout ? { loadout: input.workset.agentLoadout } : {},
164128
+ ...input.workset.continuity ? {
164129
+ continuity: {
164130
+ taskId: input.workset.continuity.taskId,
164131
+ status: input.workset.continuity.status,
164132
+ outcome: input.workset.continuity.outcome
164133
+ }
164134
+ } : {}
163603
164135
  };
163604
164136
  }
163605
164137
  var init_context_receipt = __esm({
@@ -164231,15 +164763,21 @@ var team_store_exports = {};
164231
164763
  __export(team_store_exports, {
164232
164764
  AGENT_TYPE_ROLE_MAP: () => AGENT_TYPE_ROLE_MAP,
164233
164765
  DEFAULT_ROLES: () => DEFAULT_ROLES,
164766
+ DEFAULT_TEAM_QUERY_LIMIT: () => DEFAULT_TEAM_QUERY_LIMIT,
164767
+ MAX_TEAM_QUERY_LIMIT: () => MAX_TEAM_QUERY_LIMIT,
164234
164768
  TeamStore: () => TeamStore,
164235
164769
  getTeamStore: () => getTeamStore,
164236
164770
  initTeamStore: () => initTeamStore,
164237
164771
  isTeamStoreInitialized: () => isTeamStoreInitialized,
164238
164772
  resetTeamStore: () => resetTeamStore
164239
164773
  });
164240
- import { randomUUID as randomUUID17 } from "crypto";
164774
+ import { randomUUID as randomUUID18 } from "crypto";
164241
164775
  import path31 from "path";
164242
164776
  import fs18 from "fs";
164777
+ function clampTeamQueryLimit(limit2) {
164778
+ if (!Number.isFinite(limit2) || limit2 == null) return DEFAULT_TEAM_QUERY_LIMIT;
164779
+ return Math.min(MAX_TEAM_QUERY_LIMIT, Math.max(1, Math.floor(limit2)));
164780
+ }
164243
164781
  function getTeamStore() {
164244
164782
  if (!_teamStore) {
164245
164783
  throw new Error("[memorix] TeamStore not initialized \u2014 call initTeamStore() first");
@@ -164263,12 +164801,14 @@ function resetTeamStore() {
164263
164801
  _teamStore = null;
164264
164802
  _teamStoreDataDir = null;
164265
164803
  }
164266
- var DEFAULT_ROLES, AGENT_TYPE_ROLE_MAP, TeamStore, _teamStore, _teamStoreDataDir;
164804
+ var DEFAULT_TEAM_QUERY_LIMIT, MAX_TEAM_QUERY_LIMIT, DEFAULT_ROLES, AGENT_TYPE_ROLE_MAP, TeamStore, _teamStore, _teamStoreDataDir;
164267
164805
  var init_team_store = __esm({
164268
164806
  "src/team/team-store.ts"() {
164269
164807
  "use strict";
164270
164808
  init_esm_shims();
164271
164809
  init_sqlite_db();
164810
+ DEFAULT_TEAM_QUERY_LIMIT = 100;
164811
+ MAX_TEAM_QUERY_LIMIT = 500;
164272
164812
  DEFAULT_ROLES = [
164273
164813
  { roleId: "planner", label: "Planner", description: "Breaks down requirements, creates tasks, defines dependencies", preferredAgentTypes: ["claude-code", "cursor", "codex"], maxConcurrent: 2 },
164274
164814
  { roleId: "researcher", label: "Researcher", description: "Investigates codebase, gathers context, answers questions", preferredAgentTypes: ["claude-code", "cursor", "gemini-cli"], maxConcurrent: 2 },
@@ -164526,7 +165066,7 @@ var init_team_store = __esm({
164526
165066
  * reactivate it (preserving agent_id). Otherwise create a new one.
164527
165067
  */
164528
165068
  registerAgent(input) {
164529
- const instanceId = input.instanceId || randomUUID17();
165069
+ const instanceId = input.instanceId || randomUUID18();
164530
165070
  const now3 = Date.now();
164531
165071
  const existing = this.stmtAgentFindByInstance.get(
164532
165072
  input.projectId,
@@ -164552,7 +165092,7 @@ var init_team_store = __esm({
164552
165092
  this.eventBus?.emit("agent:joined", { agentId: row2.agent_id, projectId: input.projectId, agentType: input.agentType });
164553
165093
  return row2;
164554
165094
  }
164555
- const agentId = randomUUID17();
165095
+ const agentId = randomUUID18();
164556
165096
  this.stmtAgentUpsert.run({
164557
165097
  agent_id: agentId,
164558
165098
  project_id: input.projectId,
@@ -164578,32 +165118,37 @@ var init_team_store = __esm({
164578
165118
  return this.stmtAgentFindByInstance.get(projectId, agentType, instanceId);
164579
165119
  }
164580
165120
  listAgents(projectId, filter) {
164581
- const all = this.stmtAgentListByProject.all(projectId);
165121
+ const limit2 = clampTeamQueryLimit(filter?.limit);
164582
165122
  if (filter?.status) {
164583
- return all.filter((a) => a.status === filter.status);
165123
+ return this.db.prepare(
165124
+ `SELECT * FROM team_agents WHERE project_id = ? AND status = ? ORDER BY joined_at DESC LIMIT ?`
165125
+ ).all(projectId, filter.status, limit2);
164584
165126
  }
164585
- return all;
165127
+ return this.db.prepare(
165128
+ `SELECT * FROM team_agents WHERE project_id = ? ORDER BY joined_at DESC LIMIT ?`
165129
+ ).all(projectId, limit2);
164586
165130
  }
164587
165131
  /** List agents across all projects (for global scope) */
164588
- listAllAgents() {
165132
+ listAllAgents(limit2) {
164589
165133
  if (!this.db) return [];
164590
- return this.db.prepare("SELECT * FROM team_agents ORDER BY last_heartbeat DESC").all();
165134
+ return this.db.prepare("SELECT * FROM team_agents ORDER BY last_heartbeat DESC LIMIT ?").all(clampTeamQueryLimit(limit2));
164591
165135
  }
164592
165136
  /** List locks across all projects (for global scope) */
164593
- listAllLocks() {
165137
+ listAllLocks(limit2) {
164594
165138
  if (!this.db) return [];
164595
165139
  this.db.prepare("DELETE FROM team_locks WHERE expires_at <= ?").run(Date.now());
164596
- return this.db.prepare("SELECT * FROM team_locks WHERE expires_at > ? ORDER BY locked_at DESC").all(Date.now());
165140
+ return this.db.prepare("SELECT * FROM team_locks WHERE expires_at > ? ORDER BY locked_at DESC LIMIT ?").all(Date.now(), clampTeamQueryLimit(limit2));
164597
165141
  }
164598
165142
  /** List tasks across all projects (for global scope) */
164599
165143
  listAllTasks(filter) {
164600
165144
  if (!this.db) return [];
165145
+ const limit2 = clampTeamQueryLimit(filter?.limit);
164601
165146
  if (filter?.available) {
164602
165147
  return this.db.prepare(
164603
- `SELECT t.* FROM team_tasks t WHERE t.status = 'pending' AND t.assignee_agent_id IS NULL ORDER BY t.created_at DESC`
164604
- ).all();
165148
+ `SELECT t.* FROM team_tasks t WHERE t.status = 'pending' AND t.assignee_agent_id IS NULL ORDER BY t.created_at DESC LIMIT ?`
165149
+ ).all(limit2);
164605
165150
  }
164606
- return this.db.prepare("SELECT * FROM team_tasks ORDER BY created_at DESC").all();
165151
+ return this.db.prepare("SELECT * FROM team_tasks ORDER BY created_at DESC LIMIT ?").all(limit2);
164607
165152
  }
164608
165153
  heartbeat(agentId) {
164609
165154
  const info = this.stmtAgentUpdateHeartbeat.run(Date.now(), agentId);
@@ -164638,7 +165183,10 @@ var init_team_store = __esm({
164638
165183
  return staleIds;
164639
165184
  }
164640
165185
  getActiveCount(projectId) {
164641
- return this.listAgents(projectId, { status: "active" }).length;
165186
+ const row = this.db.prepare(
165187
+ `SELECT COUNT(*) AS count FROM team_agents WHERE project_id = ? AND status = 'active'`
165188
+ ).get(projectId);
165189
+ return Number(row?.count ?? 0);
164642
165190
  }
164643
165191
  // ═══════════════════════════════════════════════════════════════════
164644
165192
  // Message Operations
@@ -164654,7 +165202,7 @@ var init_team_store = __esm({
164654
165202
  return { error: `Recipient agent '${input.recipientAgentId}' not found \u2014 cannot send to unknown agent` };
164655
165203
  }
164656
165204
  }
164657
- const id = randomUUID17();
165205
+ const id = randomUUID18();
164658
165206
  const now3 = Date.now();
164659
165207
  const row = {
164660
165208
  id,
@@ -164673,8 +165221,14 @@ var init_team_store = __esm({
164673
165221
  this.stmtMsgInsert.run(row);
164674
165222
  return row;
164675
165223
  }
164676
- getInbox(projectId, agentId) {
164677
- return this.stmtMsgInbox.all(projectId, agentId);
165224
+ getInbox(projectId, agentId, limit2) {
165225
+ return this.db.prepare(`
165226
+ SELECT * FROM team_messages
165227
+ WHERE project_id = ?
165228
+ AND (recipient_agent_id = ? OR recipient_agent_id IS NULL)
165229
+ ORDER BY created_at ASC
165230
+ LIMIT ?
165231
+ `).all(projectId, agentId, clampTeamQueryLimit(limit2));
164678
165232
  }
164679
165233
  getUnreadCount(projectId, agentId) {
164680
165234
  const row = this.stmtMsgUnreadCount.get(projectId, agentId);
@@ -164704,7 +165258,7 @@ var init_team_store = __esm({
164704
165258
  // Task Operations (with atomic claim semantics)
164705
165259
  // ═══════════════════════════════════════════════════════════════════
164706
165260
  createTask(input) {
164707
- const taskId = randomUUID17();
165261
+ const taskId = randomUUID18();
164708
165262
  const now3 = Date.now();
164709
165263
  const row = {
164710
165264
  task_id: taskId,
@@ -164831,17 +165385,22 @@ var init_team_store = __esm({
164831
165385
  return info.changes;
164832
165386
  }
164833
165387
  listTasks(projectId, filter) {
164834
- if (filter?.available) {
164835
- return this.stmtTaskAvailable.all(projectId);
164836
- }
164837
- const all = this.stmtTaskListByProject.all(projectId);
165388
+ const clauses = ["project_id = ?"];
165389
+ const values = [projectId];
165390
+ if (filter?.available) clauses.push("status = 'pending'", "assignee_agent_id IS NULL");
164838
165391
  if (filter?.status) {
164839
- return all.filter((t2) => t2.status === filter.status);
165392
+ clauses.push("status = ?");
165393
+ values.push(filter.status);
164840
165394
  }
164841
165395
  if (filter?.assignee) {
164842
- return all.filter((t2) => t2.assignee_agent_id === filter.assignee);
165396
+ clauses.push("assignee_agent_id = ?");
165397
+ values.push(filter.assignee);
164843
165398
  }
164844
- return all;
165399
+ values.push(clampTeamQueryLimit(filter?.limit));
165400
+ const orderBy = filter?.available ? "created_at ASC, rowid ASC" : "created_at DESC, rowid DESC";
165401
+ return this.db.prepare(
165402
+ `SELECT * FROM team_tasks WHERE ${clauses.join(" AND ")} ORDER BY ${orderBy} LIMIT ?`
165403
+ ).all(...values);
164845
165404
  }
164846
165405
  /**
164847
165406
  * List available tasks for a specific agent, sorted by role affinity.
@@ -164853,7 +165412,7 @@ var init_team_store = __esm({
164853
165412
  const agent = this.stmtAgentFindById.get(agentId);
164854
165413
  if (!agent) return [];
164855
165414
  const agentRole = agent.role;
164856
- const available = this.stmtTaskAvailable.all(projectId);
165415
+ const available = this.listTasks(projectId, { available: true, limit: MAX_TEAM_QUERY_LIMIT });
164857
165416
  const eligible = available.filter((t2) => !t2.required_role || t2.required_role === agentRole);
164858
165417
  const score = (t2) => {
164859
165418
  if (t2.preferred_role === agentRole) return 0;
@@ -164907,12 +165466,16 @@ var init_team_store = __esm({
164907
165466
  const row = this.stmtLockGet.get(file, projectId);
164908
165467
  return row ?? null;
164909
165468
  }
164910
- listLocks(projectId, agentId) {
165469
+ listLocks(projectId, agentId, limit2) {
164911
165470
  this.stmtLockDeleteExpired.run(projectId, Date.now());
164912
165471
  if (agentId) {
164913
- return this.stmtLockListByAgent.all(projectId, agentId);
165472
+ return this.db.prepare(
165473
+ `SELECT * FROM team_locks WHERE project_id = ? AND locked_by = ? ORDER BY locked_at DESC LIMIT ?`
165474
+ ).all(projectId, agentId, clampTeamQueryLimit(limit2));
164914
165475
  }
164915
- return this.stmtLockListByProject.all(projectId);
165476
+ return this.db.prepare(
165477
+ `SELECT * FROM team_locks WHERE project_id = ? ORDER BY locked_at DESC LIMIT ?`
165478
+ ).all(projectId, clampTeamQueryLimit(limit2));
164916
165479
  }
164917
165480
  releaseAllLocks(agentId) {
164918
165481
  const info = this.stmtLockDeleteByAgent.run(agentId);
@@ -164976,7 +165539,7 @@ var init_team_store = __esm({
164976
165539
  for (const [agentId, msgs] of Object.entries(snap.messages.inboxes)) {
164977
165540
  for (const msg of msgs) {
164978
165541
  this.stmtMsgInsert.run({
164979
- id: msg.id ?? randomUUID17(),
165542
+ id: msg.id ?? randomUUID18(),
164980
165543
  project_id: "migrated",
164981
165544
  sender_agent_id: msg.from ?? "unknown",
164982
165545
  recipient_agent_id: msg.to === "__broadcast__" ? null : msg.to ?? agentId,
@@ -167934,7 +168497,7 @@ __export(planner_exports, {
167934
168497
  materializeTaskGraph: () => materializeTaskGraph,
167935
168498
  seedAutonomousPipeline: () => seedAutonomousPipeline
167936
168499
  });
167937
- import { randomUUID as randomUUID18 } from "crypto";
168500
+ import { randomUUID as randomUUID19 } from "crypto";
167938
168501
  function isPlannerTask(metadata) {
167939
168502
  if (!metadata) return null;
167940
168503
  try {
@@ -167992,7 +168555,7 @@ function seedAutonomousPipeline(teamStore, projectId, config, opts) {
167992
168555
  const maxIterations = config.maxIterations ?? 3;
167993
168556
  const taskBudget = config.taskBudget ?? 15;
167994
168557
  const structuredPlan = opts?.structuredPlan ?? true;
167995
- const pipelineId = randomUUID18();
168558
+ const pipelineId = randomUUID19();
167996
168559
  const meta = {
167997
168560
  plannerType: "plan",
167998
168561
  pipelineId,
@@ -168673,6 +169236,7 @@ var init_official_skills = __esm({
168673
169236
  "| Need the sequence around one memory | `memorix_timeline` | `memorix memory timeline --id <id>` |",
168674
169237
  "| Check source and freshness for a memory | `memorix_evidence` | `memorix evidence list|get|events` |",
168675
169238
  "| Record whether a memory helped, conflicted, or was corrected | `memorix_feedback` | `memorix feedback record|show|audit` |",
169239
+ "| Track task requirements, decisions, verification, and outcome | `memorix_continuity` | `memorix continuity start|record|show|close` |",
168676
169240
  "| Inspect or import controlled media | `memorix_media` | `memorix media import|attach|list|show|status` |",
168677
169241
  '| Learned reusable project knowledge | `memorix_store` | `memorix memory store --type <type> --entity <name> --title "<title>" "<text>"` |',
168678
169242
  "| Task or bug is complete/outdated | `memorix_resolve` | `memorix memory resolve --ids <ids>` |",
@@ -168696,6 +169260,7 @@ var init_official_skills = __esm({
168696
169260
  "3. Use stale or unbound memory only as a warning or search lead.",
168697
169261
  "4. Store durable decisions, fixes, and gotchas after the project state changes.",
168698
169262
  "5. Resolve completed or obsolete memories so future briefs stay small.",
169263
+ "6. For multi-step work, start a continuity ledger and pass its taskId back to memorix_project_context.",
168699
169264
  "",
168700
169265
  "## Store Rules",
168701
169266
  "",
@@ -170417,7 +170982,7 @@ __export(server_exports2, {
170417
170982
  createMemorixServer: () => createMemorixServer,
170418
170983
  shouldAwaitProjectRuntime: () => shouldAwaitProjectRuntime
170419
170984
  });
170420
- import { createHash as createHash18 } from "crypto";
170985
+ import { createHash as createHash19 } from "crypto";
170421
170986
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
170422
170987
  import { z as z627 } from "zod";
170423
170988
  function formatFormationStageDurations(stageDurationsMs) {
@@ -170501,7 +171066,7 @@ function coerceObjectArray(val) {
170501
171066
  return [];
170502
171067
  }
170503
171068
  function createDeterministicInstanceId(projectId, agentType, agentName) {
170504
- const digest2 = createHash18("sha256").update(projectId).update("\n").update(agentType).update("\n").update(agentName ?? "").digest("hex").slice(0, 24);
171069
+ const digest2 = createHash19("sha256").update(projectId).update("\n").update(agentType).update("\n").update(agentName ?? "").digest("hex").slice(0, 24);
170505
171070
  return `auto-${digest2}`;
170506
171071
  }
170507
171072
  function shouldAwaitProjectRuntime(toolName) {
@@ -170708,6 +171273,22 @@ async function createMemorixServer(cwd, existingServer, sharedTeam, options = {}
170708
171273
  }
170709
171274
  await projectRuntimeInitPromise;
170710
171275
  };
171276
+ const activateProjectRuntime = async () => {
171277
+ if (!projectResolved) return;
171278
+ await initObservationStore(projectDir2);
171279
+ await initMiniSkillStore(projectDir2);
171280
+ await initSessionStore(projectDir2);
171281
+ await initObservations(projectDir2, { skipCorpusLoad: true });
171282
+ try {
171283
+ const { initProjectRoot: initProjectRoot2 } = await Promise.resolve().then(() => (init_yaml_loader(), yaml_loader_exports));
171284
+ const { resetDotenv: resetDotenv2, loadDotenv: loadDotenv2 } = await Promise.resolve().then(() => (init_dotenv_loader(), dotenv_loader_exports));
171285
+ initProjectRoot2(project.rootPath);
171286
+ resetDotenv2();
171287
+ loadDotenv2(project.rootPath);
171288
+ } catch {
171289
+ }
171290
+ initLLM({ projectRoot: project.rootPath });
171291
+ };
170711
171292
  let maintenanceWorker = null;
170712
171293
  const startProjectMaintenanceWorker = async (autoCleanup = false) => {
170713
171294
  maintenanceWorker?.stop();
@@ -171623,6 +172204,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
171623
172204
  description: "Build a compact Memory Autopilot brief for the current coding task. Schedules Code Memory refresh when needed, includes Start here files, reliable code-bound memories, stale/suspect cautions, and verification hints. Use this at the start of a new coding turn or after switching tasks.",
171624
172205
  inputSchema: {
171625
172206
  task: z627.string().optional().describe("Current coding task or question"),
172207
+ taskId: z627.string().max(120).optional().describe("Optional task continuity ledger id to include in the brief"),
171626
172208
  refresh: z627.enum(["auto", "always", "never"]).optional().default("auto").describe(
171627
172209
  "Code Memory refresh policy. auto refreshes only when missing or stale."
171628
172210
  ),
@@ -171647,7 +172229,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
171647
172229
  limit: z627.number().optional().describe("Reserved for future source limits; current prompt stays compact by default.")
171648
172230
  }
171649
172231
  },
171650
- async ({ task, refresh, format, agent }) => {
172232
+ async ({ task, taskId, refresh, format, agent }) => {
171651
172233
  const unresolved = requireResolvedProject("build project context for the current project");
171652
172234
  if (unresolved) return unresolved;
171653
172235
  const [
@@ -171677,6 +172259,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
171677
172259
  dataDir: projectDir2,
171678
172260
  observations: observations2,
171679
172261
  task,
172262
+ taskId,
171680
172263
  agent,
171681
172264
  refresh: refresh ?? "auto",
171682
172265
  reader: getObservationReader(),
@@ -174102,6 +174685,94 @@ ${json2}
174102
174685
  }
174103
174686
  }
174104
174687
  );
174688
+ server.registerTool(
174689
+ "memorix_continuity",
174690
+ {
174691
+ title: "Task Continuity Ledger",
174692
+ description: "Maintain a bounded, append-only continuity ledger for a coding task. Use start for requirements, record for decisions/verification/risks, show or list to inspect, and close for the final outcome. Pass the returned taskId to memorix_project_context so the current brief includes this ledger.",
174693
+ inputSchema: {
174694
+ action: z627.enum(["start", "record", "show", "list", "close"]).describe("Continuity operation"),
174695
+ taskId: z627.string().max(120).optional().describe("Continuity task id"),
174696
+ task: z627.string().max(1e3).optional().describe("Task description for start"),
174697
+ requirements: z627.array(z627.string().max(2e3)).max(8).optional().describe("Requirements for start"),
174698
+ kind: z627.enum(["requirement", "decision", "verification", "risk"]).optional().describe("Entry kind for record"),
174699
+ content: z627.string().max(2e3).optional().describe("Requirement, decision, verification, risk, or outcome text"),
174700
+ verificationStatus: z627.enum(["pending", "passed", "failed", "skipped"]).optional(),
174701
+ verificationId: z627.string().max(120).optional().describe("Stable verification obligation id; reuse it to move pending to passed/failed"),
174702
+ idempotencyKey: z627.string().max(200).optional().describe("Stable retry key; repeating the same operation returns the original event"),
174703
+ status: z627.enum(["completed", "blocked", "abandoned"]).optional().describe("Outcome status for close"),
174704
+ sourceRef: z627.string().max(500).optional().describe("Evidence or source reference"),
174705
+ evidenceRefs: z627.array(z627.string().max(500)).max(8).optional(),
174706
+ actor: z627.string().max(200).optional(),
174707
+ limit: z627.number().int().positive().max(100).optional().default(20)
174708
+ }
174709
+ },
174710
+ async ({ action, taskId, task, requirements, kind, content, verificationStatus, verificationId, idempotencyKey, status, sourceRef, evidenceRefs: evidenceRefs2, actor, limit: limit2 }) => {
174711
+ const unresolved = requireResolvedProject("manage task continuity for the current project");
174712
+ if (unresolved) return unresolved;
174713
+ const { TaskContinuityStore: TaskContinuityStore2 } = await Promise.resolve().then(() => (init_task_continuity(), task_continuity_exports));
174714
+ const continuity = new TaskContinuityStore2();
174715
+ await continuity.init(projectDir2);
174716
+ const effectiveActor = actor ?? currentAgentId;
174717
+ try {
174718
+ if (action === "start") {
174719
+ if (!task?.trim()) return { content: [{ type: "text", text: "task is required for continuity start." }], isError: true };
174720
+ const result2 = continuity.start({
174721
+ projectId: project.id,
174722
+ task,
174723
+ ...taskId ? { taskId } : {},
174724
+ requirements,
174725
+ ...effectiveActor ? { actor: effectiveActor } : {},
174726
+ ...idempotencyKey ? { idempotencyKey } : {}
174727
+ });
174728
+ return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, ...result2 }, null, 2) }] };
174729
+ }
174730
+ if (action === "list") {
174731
+ return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, ledgers: continuity.list(project.id, limit2) }, null, 2) }] };
174732
+ }
174733
+ if (!taskId?.trim()) return { content: [{ type: "text", text: "taskId is required for this continuity action." }], isError: true };
174734
+ if (action === "show") {
174735
+ const ledger = continuity.get(project.id, taskId);
174736
+ if (!ledger) return { content: [{ type: "text", text: "Task continuity ledger not found." }], isError: true };
174737
+ return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, ledger }, null, 2) }] };
174738
+ }
174739
+ if (action === "record") {
174740
+ if (!kind || !content?.trim()) {
174741
+ return { content: [{ type: "text", text: "record requires kind and content." }], isError: true };
174742
+ }
174743
+ const result2 = continuity.record({
174744
+ projectId: project.id,
174745
+ taskId,
174746
+ kind,
174747
+ content,
174748
+ ...verificationStatus ? { verificationStatus } : {},
174749
+ ...sourceRef ? { sourceRef } : {},
174750
+ ...evidenceRefs2 ? { evidenceRefs: evidenceRefs2 } : {},
174751
+ ...effectiveActor ? { actor: effectiveActor } : {},
174752
+ ...verificationId ? { verificationId } : {},
174753
+ ...idempotencyKey ? { idempotencyKey } : {}
174754
+ });
174755
+ return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, ...result2 }, null, 2) }] };
174756
+ }
174757
+ if (!status || !content?.trim()) {
174758
+ return { content: [{ type: "text", text: "close requires status and content." }], isError: true };
174759
+ }
174760
+ const result = continuity.close({
174761
+ projectId: project.id,
174762
+ taskId,
174763
+ status,
174764
+ content,
174765
+ ...sourceRef ? { sourceRef } : {},
174766
+ ...evidenceRefs2 ? { evidenceRefs: evidenceRefs2 } : {},
174767
+ ...effectiveActor ? { actor: effectiveActor } : {},
174768
+ ...idempotencyKey ? { idempotencyKey } : {}
174769
+ });
174770
+ return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, ...result }, null, 2) }] };
174771
+ } catch (error) {
174772
+ return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true };
174773
+ }
174774
+ }
174775
+ );
174105
174776
  if (teamFeaturesEnabled) {
174106
174777
  const { initTeamStore: initTeamStore2 } = await Promise.resolve().then(() => (init_team_store(), team_store_exports));
174107
174778
  initTeamStoreForProject = initTeamStore2;
@@ -175129,7 +175800,9 @@ fi
175129
175800
  graphManager,
175130
175801
  projectId: project.id,
175131
175802
  deferredInit,
175803
+ activateProjectRuntime,
175132
175804
  switchProject,
175805
+ getProjectDataDir: () => projectDir2,
175133
175806
  isExplicitlyBound: () => projectBinding.isExplicit(),
175134
175807
  getRequestContext,
175135
175808
  handleTransportClose
@@ -175480,7 +176153,10 @@ var init_mcp_root_path = __esm({
175480
176153
  // src/server/modern-mcp-bridge.ts
175481
176154
  var modern_mcp_bridge_exports = {};
175482
176155
  __export(modern_mcp_bridge_exports, {
175483
- createModernMcpBridge: () => createModernMcpBridge
176156
+ ModernMcpRuntimePool: () => ModernMcpRuntimePool,
176157
+ createModernMcpBridge: () => createModernMcpBridge,
176158
+ createModernMcpRuntime: () => createModernMcpRuntime,
176159
+ withBusinessRuntimeQueue: () => withBusinessRuntimeQueue
175484
176160
  });
175485
176161
  import {
175486
176162
  fromJsonSchema,
@@ -175488,7 +176164,12 @@ import {
175488
176164
  } from "@modelcontextprotocol/server";
175489
176165
  import { Client as LegacyClient } from "@modelcontextprotocol/sdk/client/index.js";
175490
176166
  import { InMemoryTransport as LegacyInMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
175491
- async function createModernMcpBridge(options) {
176167
+ function withBusinessRuntimeQueue(work) {
176168
+ const result = businessRuntimeQueue.then(work);
176169
+ businessRuntimeQueue = result.catch(() => void 0);
176170
+ return result;
176171
+ }
176172
+ async function createModernMcpRuntime(options) {
175492
176173
  const { createMemorixServer: createMemorixServer2 } = await Promise.resolve().then(() => (init_server2(), server_exports2));
175493
176174
  const legacy = await createMemorixServer2(
175494
176175
  options.projectRoot,
@@ -175509,46 +176190,135 @@ async function createModernMcpBridge(options) {
175509
176190
  await legacy.server.connect(serverTransport);
175510
176191
  await legacyClient.connect(clientTransport);
175511
176192
  const listed = await legacyClient.listTools();
175512
- const modern = new ModernMcpServer(getMcpServerInfo());
175513
- for (const tool of listed.tools) {
175514
- modern.registerTool(
175515
- tool.name,
175516
- {
175517
- ...tool.title ? { title: tool.title } : {},
175518
- ...tool.description ? { description: tool.description } : {},
175519
- inputSchema: fromJsonSchema(tool.inputSchema)
175520
- },
175521
- async (args) => await legacyClient.callTool({
175522
- name: tool.name,
175523
- arguments: args
175524
- })
175525
- );
175526
- }
175527
- const bridge = modern;
175528
- bridge.memorix = {
176193
+ const callTool = (name, args) => withBusinessRuntimeQueue(async () => {
176194
+ await legacy.activateProjectRuntime();
176195
+ return await legacyClient.callTool({ name, arguments: args });
176196
+ });
176197
+ const lifecycle = {
175529
176198
  projectId: legacy.projectId,
175530
176199
  deferredInit: legacy.deferredInit,
176200
+ activateProjectRuntime: legacy.activateProjectRuntime,
175531
176201
  switchProject: legacy.switchProject,
176202
+ getProjectDataDir: legacy.getProjectDataDir,
175532
176203
  isExplicitlyBound: legacy.isExplicitlyBound,
175533
176204
  handleTransportClose: legacy.handleTransportClose
175534
176205
  };
175535
176206
  let closed = false;
175536
- const modernClose = modern.close.bind(modern);
175537
- modern.close = async () => {
176207
+ return {
176208
+ projectId: legacy.projectId,
176209
+ getProjectDataDir: legacy.getProjectDataDir,
176210
+ createBridge: () => {
176211
+ const requestServer = new ModernMcpServer(getMcpServerInfo());
176212
+ for (const tool of listed.tools) {
176213
+ requestServer.registerTool(
176214
+ tool.name,
176215
+ {
176216
+ ...tool.title ? { title: tool.title } : {},
176217
+ ...tool.description ? { description: tool.description } : {},
176218
+ inputSchema: fromJsonSchema(tool.inputSchema)
176219
+ },
176220
+ async (args) => await callTool(tool.name, args)
176221
+ );
176222
+ }
176223
+ requestServer.memorix = lifecycle;
176224
+ return requestServer;
176225
+ },
176226
+ close: async () => {
176227
+ if (closed) return;
176228
+ closed = true;
176229
+ await legacyClient.close().catch(() => void 0);
176230
+ await legacy.server.close().catch(() => void 0);
176231
+ legacy.handleTransportClose();
176232
+ }
176233
+ };
176234
+ }
176235
+ async function createModernMcpBridge(options) {
176236
+ const runtime = await createModernMcpRuntime(options);
176237
+ const bridge = runtime.createBridge();
176238
+ const close = bridge.close.bind(bridge);
176239
+ let closed = false;
176240
+ bridge.close = async () => {
175538
176241
  if (closed) return;
175539
176242
  closed = true;
175540
- await modernClose();
175541
- await legacyClient.close().catch(() => void 0);
175542
- await legacy.server.close().catch(() => void 0);
175543
- legacy.handleTransportClose();
176243
+ await close();
176244
+ await runtime.close();
175544
176245
  };
175545
176246
  return bridge;
175546
176247
  }
176248
+ var businessRuntimeQueue, ModernMcpRuntimePool;
175547
176249
  var init_modern_mcp_bridge = __esm({
175548
176250
  "src/server/modern-mcp-bridge.ts"() {
175549
176251
  "use strict";
175550
176252
  init_esm_shims();
175551
176253
  init_mcp_discovery();
176254
+ businessRuntimeQueue = Promise.resolve();
176255
+ ModernMcpRuntimePool = class {
176256
+ constructor(maxEntries = 32) {
176257
+ this.maxEntries = maxEntries;
176258
+ }
176259
+ maxEntries;
176260
+ entries = /* @__PURE__ */ new Map();
176261
+ pending = /* @__PURE__ */ new Map();
176262
+ async createBridge(key, create2) {
176263
+ let entry = this.entries.get(key);
176264
+ if (!entry) {
176265
+ let pending = this.pending.get(key);
176266
+ if (!pending) {
176267
+ pending = create2().then((runtime) => {
176268
+ const created = { runtime, refs: 0, lastUsedAt: Date.now() };
176269
+ this.entries.set(key, created);
176270
+ return created;
176271
+ });
176272
+ this.pending.set(key, pending);
176273
+ }
176274
+ try {
176275
+ entry = await pending;
176276
+ } finally {
176277
+ this.pending.delete(key);
176278
+ }
176279
+ }
176280
+ entry.refs++;
176281
+ entry.lastUsedAt = Date.now();
176282
+ const bridge = entry.runtime.createBridge();
176283
+ const close = bridge.close.bind(bridge);
176284
+ let released = false;
176285
+ bridge.close = async () => {
176286
+ try {
176287
+ await close();
176288
+ } finally {
176289
+ if (!released) {
176290
+ released = true;
176291
+ entry.refs = Math.max(0, entry.refs - 1);
176292
+ entry.lastUsedAt = Date.now();
176293
+ }
176294
+ }
176295
+ };
176296
+ return bridge;
176297
+ }
176298
+ async evictIdle() {
176299
+ let closed = 0;
176300
+ const idle = [...this.entries.entries()].filter(([, entry]) => entry.refs === 0).sort(([, left], [, right]) => left.lastUsedAt - right.lastUsedAt);
176301
+ for (const [key, entry] of idle) {
176302
+ if (this.entries.size <= this.maxEntries || entry.refs > 0) continue;
176303
+ this.entries.delete(key);
176304
+ await entry.runtime.close();
176305
+ closed++;
176306
+ }
176307
+ return closed;
176308
+ }
176309
+ async close() {
176310
+ const entries = [...this.entries.values()];
176311
+ this.entries.clear();
176312
+ await Promise.all(entries.map((entry) => entry.runtime.close().catch(() => void 0)));
176313
+ }
176314
+ stats() {
176315
+ return {
176316
+ entries: this.entries.size,
176317
+ activeRefs: [...this.entries.values()].reduce((sum, entry) => sum + entry.refs, 0),
176318
+ pending: this.pending.size
176319
+ };
176320
+ }
176321
+ };
175552
176322
  }
175553
176323
  });
175554
176324
 
@@ -175660,7 +176430,7 @@ var init_serve_shared = __esm({
175660
176430
 
175661
176431
  // src/cli/version.ts
175662
176432
  function getCliVersion() {
175663
- return true ? "1.9.5" : pkg.version;
176433
+ return true ? "1.9.6" : pkg.version;
175664
176434
  }
175665
176435
  var init_version3 = __esm({
175666
176436
  "src/cli/version.ts"() {