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/sdk.js CHANGED
@@ -420,9 +420,12 @@ END;
420
420
  // src/store/sqlite-db.ts
421
421
  var sqlite_db_exports = {};
422
422
  __export(sqlite_db_exports, {
423
+ acquireDatabase: () => acquireDatabase,
423
424
  closeAllDatabases: () => closeAllDatabases,
424
425
  closeDatabase: () => closeDatabase,
426
+ evictIdleDatabases: () => evictIdleDatabases,
425
427
  getDatabase: () => getDatabase,
428
+ getDatabaseStats: () => getDatabaseStats,
426
429
  isSqliteAvailable: () => isSqliteAvailable,
427
430
  loadBetterSqlite3: () => loadBetterSqlite3
428
431
  });
@@ -460,11 +463,21 @@ function applySchemaMigrations(db2) {
460
463
  apply();
461
464
  }
462
465
  }
466
+ function normalizeDataDir(dataDir) {
467
+ return path3.resolve(dataDir);
468
+ }
469
+ function touchDatabase(normalized, db2) {
470
+ _dbCache.delete(normalized);
471
+ _dbCache.set(normalized, db2);
472
+ }
463
473
  function getDatabase(dataDir) {
464
- const normalized = path3.resolve(dataDir);
474
+ const normalized = normalizeDataDir(dataDir);
465
475
  assertNotHomeDataDir(normalized);
466
476
  const existing = _dbCache.get(normalized);
467
- if (existing) return existing;
477
+ if (existing) {
478
+ touchDatabase(normalized, existing);
479
+ return existing;
480
+ }
468
481
  loadBetterSqlite3();
469
482
  fs.mkdirSync(dataDir, { recursive: true });
470
483
  const dbPath = path3.join(dataDir, "memorix.db");
@@ -494,6 +507,8 @@ function getDatabase(dataDir) {
494
507
  db2.exec(CREATE_MAINTENANCE_JOBS_TABLE);
495
508
  db2.exec(CREATE_MAINTENANCE_TARGETS_TABLE);
496
509
  db2.exec(CREATE_COMPACTION_CHECKPOINTS_TABLE);
510
+ db2.exec(CREATE_TASK_CONTINUITY_EVENTS_TABLE);
511
+ db2.exec(CREATE_AGENT_EFFECTS_TABLE);
497
512
  try {
498
513
  db2.exec(`ALTER TABLE mini_skills ADD COLUMN sourceSnapshot TEXT NOT NULL DEFAULT ''`);
499
514
  } catch {
@@ -532,7 +547,7 @@ function getDatabase(dataDir) {
532
547
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('storage_generation', '0')`).run();
533
548
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('next_id', '1')`).run();
534
549
  db2.prepare(`INSERT OR IGNORE INTO meta (key, value) VALUES ('mini_skills_generation', '0')`).run();
535
- _dbCache.set(normalized, db2);
550
+ touchDatabase(normalized, db2);
536
551
  return db2;
537
552
  } catch (error) {
538
553
  try {
@@ -542,8 +557,46 @@ function getDatabase(dataDir) {
542
557
  throw error;
543
558
  }
544
559
  }
560
+ function acquireDatabase(dataDir) {
561
+ const normalized = normalizeDataDir(dataDir);
562
+ const db2 = getDatabase(normalized);
563
+ _dbLeases.set(normalized, (_dbLeases.get(normalized) ?? 0) + 1);
564
+ let released = false;
565
+ return {
566
+ dataDir: normalized,
567
+ db: db2,
568
+ release: () => {
569
+ if (released) return;
570
+ released = true;
571
+ const count2 = (_dbLeases.get(normalized) ?? 0) - 1;
572
+ if (count2 > 0) _dbLeases.set(normalized, count2);
573
+ else _dbLeases.delete(normalized);
574
+ }
575
+ };
576
+ }
577
+ function getDatabaseStats() {
578
+ let leased = 0;
579
+ for (const count2 of _dbLeases.values()) leased += count2;
580
+ return { cached: _dbCache.size, leased, leasedDataDirs: _dbLeases.size };
581
+ }
582
+ function evictIdleDatabases(maxCached) {
583
+ const target = Math.max(0, Math.floor(maxCached));
584
+ let evicted = 0;
585
+ for (const [normalized, db2] of [..._dbCache]) {
586
+ if (_dbCache.size <= target) break;
587
+ if ((_dbLeases.get(normalized) ?? 0) > 0) continue;
588
+ try {
589
+ db2.close();
590
+ } catch {
591
+ }
592
+ _dbCache.delete(normalized);
593
+ evicted++;
594
+ }
595
+ return evicted;
596
+ }
545
597
  function closeDatabase(dataDir) {
546
- const normalized = path3.resolve(dataDir);
598
+ const normalized = normalizeDataDir(dataDir);
599
+ if ((_dbLeases.get(normalized) ?? 0) > 0) return;
547
600
  const db2 = _dbCache.get(normalized);
548
601
  if (db2) {
549
602
  try {
@@ -561,6 +614,7 @@ function closeAllDatabases() {
561
614
  }
562
615
  _dbCache.delete(key);
563
616
  }
617
+ _dbLeases.clear();
564
618
  }
565
619
  function isSqliteAvailable() {
566
620
  try {
@@ -570,7 +624,7 @@ function isSqliteAvailable() {
570
624
  return false;
571
625
  }
572
626
  }
573
- 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;
627
+ 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;
574
628
  var init_sqlite_db = __esm({
575
629
  "src/store/sqlite-db.ts"() {
576
630
  "use strict";
@@ -1287,6 +1341,43 @@ CREATE TABLE IF NOT EXISTS memory_feedback_events (
1287
1341
  delta REAL NOT NULL DEFAULT 0,
1288
1342
  observed_at TEXT NOT NULL
1289
1343
  );
1344
+ `;
1345
+ CREATE_TASK_CONTINUITY_EVENTS_TABLE = `
1346
+ CREATE TABLE IF NOT EXISTS task_continuity_events (
1347
+ id TEXT PRIMARY KEY,
1348
+ project_id TEXT NOT NULL,
1349
+ task_id TEXT NOT NULL,
1350
+ task TEXT NOT NULL,
1351
+ kind TEXT NOT NULL,
1352
+ content TEXT NOT NULL,
1353
+ item_status TEXT,
1354
+ source_ref TEXT,
1355
+ evidence_json TEXT NOT NULL DEFAULT '[]',
1356
+ actor TEXT,
1357
+ created_at TEXT NOT NULL,
1358
+ event_key TEXT,
1359
+ item_key TEXT,
1360
+ supersedes_id TEXT
1361
+ );
1362
+ `;
1363
+ CREATE_AGENT_EFFECTS_TABLE = `
1364
+ CREATE TABLE IF NOT EXISTS agent_effects (
1365
+ id TEXT PRIMARY KEY,
1366
+ pipeline_id TEXT NOT NULL,
1367
+ task_id TEXT NOT NULL,
1368
+ attempt INTEGER NOT NULL,
1369
+ effect_key TEXT NOT NULL,
1370
+ tool TEXT NOT NULL,
1371
+ risk_tier TEXT NOT NULL,
1372
+ replay_policy TEXT NOT NULL,
1373
+ status TEXT NOT NULL,
1374
+ call_id TEXT,
1375
+ idempotency_key TEXT NOT NULL,
1376
+ input_fingerprint TEXT,
1377
+ detail TEXT,
1378
+ started_at INTEGER NOT NULL,
1379
+ finished_at INTEGER
1380
+ );
1290
1381
  `;
1291
1382
  CREATE_MCP_BINDINGS_TABLE = `
1292
1383
  CREATE TABLE IF NOT EXISTS mcp_bindings (
@@ -1365,7 +1456,18 @@ CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(projec
1365
1456
  CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
1366
1457
  CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
1367
1458
  CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
1459
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_project_task ON task_continuity_events(project_id, task_id, created_at ASC);
1460
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_project_recent ON task_continuity_events(project_id, created_at DESC);
1461
+ CREATE INDEX IF NOT EXISTS idx_task_continuity_item ON task_continuity_events(project_id, task_id, kind, item_key, created_at DESC);
1462
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
1463
+ ON task_continuity_events(project_id, task_id, event_key)
1464
+ WHERE event_key IS NOT NULL;
1465
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_effect_identity
1466
+ ON agent_effects(pipeline_id, task_id, attempt, effect_key);
1467
+ CREATE INDEX IF NOT EXISTS idx_agent_effect_pipeline ON agent_effects(pipeline_id, started_at ASC);
1368
1468
  CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
1469
+ CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC);
1470
+ CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at);
1369
1471
  CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1370
1472
  ON maintenance_jobs(project_id, kind, dedupe_key)
1371
1473
  WHERE status IN ('pending', 'running', 'retry');
@@ -1536,6 +1638,8 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1536
1638
  db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
1537
1639
  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)");
1538
1640
  db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
1641
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_root ON mcp_bindings(project_root, last_used_at DESC)");
1642
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_expiry ON mcp_bindings(expires_at)");
1539
1643
  }
1540
1644
  },
1541
1645
  {
@@ -1546,9 +1650,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1546
1650
  addColumnIfMissing(db2, "code_symbols", "source", "source TEXT");
1547
1651
  addColumnIfMissing(db2, "code_edges", "source", "source TEXT");
1548
1652
  }
1653
+ },
1654
+ {
1655
+ id: "1.9-continuity-v2",
1656
+ apply: (db2) => {
1657
+ addColumnIfMissing(db2, "task_continuity_events", "event_key", "event_key TEXT");
1658
+ addColumnIfMissing(db2, "task_continuity_events", "item_key", "item_key TEXT");
1659
+ addColumnIfMissing(db2, "task_continuity_events", "supersedes_id", "supersedes_id TEXT");
1660
+ 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)");
1661
+ db2.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_task_continuity_event_key
1662
+ ON task_continuity_events(project_id, task_id, event_key)
1663
+ WHERE event_key IS NOT NULL`);
1664
+ }
1549
1665
  }
1550
1666
  ];
1551
1667
  _dbCache = /* @__PURE__ */ new Map();
1668
+ _dbLeases = /* @__PURE__ */ new Map();
1552
1669
  }
1553
1670
  });
1554
1671
 
@@ -3216,18 +3333,23 @@ __export(yaml_loader_exports, {
3216
3333
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
3217
3334
  import { homedir } from "os";
3218
3335
  import { parse as parseYamlDocument } from "yaml";
3336
+ function cacheKey(homeDir, projectRoot) {
3337
+ return `${homeDir}\0${projectRoot ?? ""}`;
3338
+ }
3219
3339
  function initProjectRoot(root) {
3220
3340
  globalProjectRoot = root;
3221
- configCache.delete(root);
3341
+ configCache.delete(cacheKey(homedir(), root));
3222
3342
  }
3223
3343
  function clearProjectRoot() {
3224
3344
  globalProjectRoot = null;
3225
3345
  }
3226
- function loadYamlConfig(projectRoot) {
3346
+ function loadYamlConfig(projectRoot, options = {}) {
3347
+ const homeDir = options.homeDir ?? homedir();
3227
3348
  const resolvedRoot = projectRoot === null ? null : projectRoot ?? globalProjectRoot ?? null;
3228
- const cached = configCache.get(resolvedRoot ?? null);
3349
+ const key = cacheKey(homeDir, resolvedRoot);
3350
+ const cached = configCache.get(key);
3229
3351
  if (cached) return cached;
3230
- const userYaml = getGlobalYamlPath(homedir());
3352
+ const userYaml = getGlobalYamlPath(homeDir);
3231
3353
  const projectYaml = resolvedRoot ? getProjectYamlPath(resolvedRoot) : null;
3232
3354
  let userConfig = {};
3233
3355
  let projectConfig = {};
@@ -3259,12 +3381,12 @@ function loadYamlConfig(projectRoot) {
3259
3381
  server: { ...userConfig.server, ...projectConfig.server },
3260
3382
  team: { ...userConfig.team, ...projectConfig.team }
3261
3383
  };
3262
- configCache.set(resolvedRoot ?? null, merged);
3384
+ configCache.set(key, merged);
3263
3385
  return merged;
3264
3386
  }
3265
- function resetYamlConfigCache(projectRoot) {
3387
+ function resetYamlConfigCache(projectRoot, homeDir = homedir()) {
3266
3388
  if (projectRoot !== void 0) {
3267
- configCache.delete(projectRoot ?? null);
3389
+ configCache.delete(cacheKey(homeDir, projectRoot ?? null));
3268
3390
  } else {
3269
3391
  configCache.clear();
3270
3392
  }
@@ -3474,9 +3596,9 @@ var init_detector = __esm({
3474
3596
  // src/config/legacy-loader.ts
3475
3597
  import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
3476
3598
  import { homedir as homedir2 } from "os";
3477
- function loadFileConfig() {
3599
+ function loadFileConfig(homeDir = homedir2()) {
3478
3600
  if (cachedConfig !== null) return cachedConfig;
3479
- const configPath = getLegacyConfigJsonPath(homedir2());
3601
+ const configPath = getLegacyConfigJsonPath(homeDir);
3480
3602
  try {
3481
3603
  if (existsSync4(configPath)) {
3482
3604
  cachedConfig = JSON.parse(readFileSync4(configPath, "utf-8"));
@@ -3506,15 +3628,15 @@ import { homedir as homedir3 } from "os";
3506
3628
  function loadTomlConfig(options = {}) {
3507
3629
  const homeDir = options.homeDir ?? homedir3();
3508
3630
  const projectRoot = options.projectRoot ?? null;
3509
- const cacheKey = `${homeDir}\0${projectRoot ?? ""}`;
3510
- const cached = configCache2.get(cacheKey);
3631
+ const cacheKey3 = `${homeDir}\0${projectRoot ?? ""}`;
3632
+ const cached = configCache2.get(cacheKey3);
3511
3633
  if (cached) return cached;
3512
3634
  const userToml = getGlobalConfigTomlPath(homeDir);
3513
3635
  const projectToml = projectRoot ? getProjectConfigTomlPath(projectRoot) : null;
3514
3636
  const userConfig = existsSync5(userToml) ? parseTomlConfig(readFileSync5(userToml, "utf8"), userToml) : {};
3515
3637
  const projectConfig = projectToml && existsSync5(projectToml) ? parseTomlConfig(readFileSync5(projectToml, "utf8"), projectToml) : {};
3516
3638
  const merged = mergeTomlConfig(userConfig, projectConfig);
3517
- configCache2.set(cacheKey, merged);
3639
+ configCache2.set(cacheKey3, merged);
3518
3640
  return merged;
3519
3641
  }
3520
3642
  function mergeTomlConfig(base, override) {
@@ -3714,8 +3836,8 @@ function getResolvedConfig(options = {}) {
3714
3836
  const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
3715
3837
  loadDotenv(projectRoot === null ? void 0 : projectRoot ?? void 0, { userHomeDir: homeDir });
3716
3838
  const toml = loadTomlConfig({ projectRoot: projectRoot ?? null, homeDir });
3717
- const yaml = loadYamlConfig(projectRoot ?? null);
3718
- const legacy = loadFileConfig();
3839
+ const yaml = loadYamlConfig(projectRoot ?? null, { homeDir });
3840
+ const legacy = loadFileConfig(homeDir);
3719
3841
  const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
3720
3842
  const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
3721
3843
  const memoryLlmProvider = first(
@@ -3737,15 +3859,17 @@ function getResolvedConfig(options = {}) {
3737
3859
  legacy.llm?.baseUrl
3738
3860
  );
3739
3861
  const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
3862
+ const isAtlasCloud = memoryLlmProvider === "atlascloud";
3740
3863
  const memoryLlmApiKey = first(
3741
3864
  process.env.MEMORIX_LLM_API_KEY,
3742
3865
  process.env.MEMORIX_API_KEY,
3743
3866
  toml.memory?.llm?.api_key,
3744
3867
  yaml.llm?.apiKey,
3745
3868
  legacy.llm?.apiKey,
3746
- process.env.OPENAI_API_KEY,
3747
- process.env.ANTHROPIC_API_KEY,
3748
- openRouterMemoryLlmApiKey
3869
+ // Never borrow another provider's credentials for the Atlas Cloud preset.
3870
+ isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : process.env.OPENAI_API_KEY,
3871
+ isAtlasCloud ? void 0 : process.env.ANTHROPIC_API_KEY,
3872
+ isAtlasCloud ? void 0 : openRouterMemoryLlmApiKey
3749
3873
  );
3750
3874
  const resolved = {
3751
3875
  agent: {
@@ -3924,7 +4048,8 @@ function getEnvSourceNames() {
3924
4048
  "MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
3925
4049
  "MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
3926
4050
  "MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
3927
- "OPENROUTER_API_KEY"
4051
+ "OPENROUTER_API_KEY",
4052
+ "ATLASCLOUD_API_KEY"
3928
4053
  ].filter((name) => process.env[name]);
3929
4054
  }
3930
4055
  function isOpenRouterUrl(value) {
@@ -4143,12 +4268,45 @@ function textHash(text3) {
4143
4268
  async function loadDiskCache() {
4144
4269
  try {
4145
4270
  const raw = await readFile(CACHE_FILE, "utf-8");
4271
+ if (Buffer.byteLength(raw, "utf8") > MAX_CACHE_FILE_BYTES) {
4272
+ console.error("[memorix] FastEmbed cache exceeds the disk load limit; starting with an empty cache");
4273
+ return;
4274
+ }
4146
4275
  const entries = JSON.parse(raw);
4147
- for (const [k, v] of entries) cache.set(k, v);
4148
- console.error(`[memorix] Loaded ${entries.length} cached embeddings from disk`);
4276
+ if (!Array.isArray(entries)) return;
4277
+ for (const entry of entries) {
4278
+ if (!Array.isArray(entry) || typeof entry[0] !== "string" || !isVector(entry[1])) continue;
4279
+ cacheSet(entry[0], entry[1], false);
4280
+ }
4281
+ console.error(`[memorix] Loaded ${cache.size} cached embeddings from disk`);
4149
4282
  } catch {
4150
4283
  }
4151
4284
  }
4285
+ function isVector(value) {
4286
+ return Array.isArray(value) && value.every((entry) => typeof entry === "number");
4287
+ }
4288
+ function maxCachePayloadBytes() {
4289
+ const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
4290
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES;
4291
+ }
4292
+ function cacheSet(hash4, value, markDirty = true) {
4293
+ const incomingBytes = value.length * 8;
4294
+ if (incomingBytes > maxCachePayloadBytes()) return;
4295
+ const existing = cache.get(hash4);
4296
+ if (existing) cachePayloadBytes -= existing.length * 8;
4297
+ else {
4298
+ while (cache.size >= MAX_CACHE_SIZE || cachePayloadBytes + incomingBytes > maxCachePayloadBytes()) {
4299
+ const firstKey = cache.keys().next().value;
4300
+ if (firstKey === void 0) break;
4301
+ const old = cache.get(firstKey);
4302
+ cache.delete(firstKey);
4303
+ if (old) cachePayloadBytes -= old.length * 8;
4304
+ }
4305
+ }
4306
+ cache.set(hash4, value);
4307
+ cachePayloadBytes += incomingBytes;
4308
+ if (markDirty) diskCacheDirty = true;
4309
+ }
4152
4310
  async function saveDiskCache() {
4153
4311
  if (!diskCacheDirty) return;
4154
4312
  try {
@@ -4159,7 +4317,7 @@ async function saveDiskCache() {
4159
4317
  } catch {
4160
4318
  }
4161
4319
  }
4162
- var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, diskCacheDirty, FastEmbedProvider;
4320
+ var CACHE_DIR, CACHE_FILE, cache, MAX_CACHE_SIZE, DEFAULT_CACHE_PAYLOAD_BYTES, MAX_CACHE_FILE_BYTES, cachePayloadBytes, diskCacheDirty, FastEmbedProvider;
4163
4321
  var init_fastembed_provider = __esm({
4164
4322
  "src/embedding/fastembed-provider.ts"() {
4165
4323
  "use strict";
@@ -4169,6 +4327,9 @@ var init_fastembed_provider = __esm({
4169
4327
  CACHE_FILE = join2(CACHE_DIR, ".embedding-cache.json");
4170
4328
  cache = /* @__PURE__ */ new Map();
4171
4329
  MAX_CACHE_SIZE = 5e3;
4330
+ DEFAULT_CACHE_PAYLOAD_BYTES = 64 * 1024 * 1024;
4331
+ MAX_CACHE_FILE_BYTES = 128 * 1024 * 1024;
4332
+ cachePayloadBytes = 0;
4172
4333
  diskCacheDirty = false;
4173
4334
  FastEmbedProvider = class _FastEmbedProvider {
4174
4335
  name = "fastembed-bge-small";
@@ -4210,7 +4371,7 @@ var init_fastembed_provider = __esm({
4210
4371
  if (result.length !== this.dimensions) {
4211
4372
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
4212
4373
  }
4213
- this.cacheSet(hash4, result);
4374
+ cacheSet(hash4, result);
4214
4375
  return result;
4215
4376
  }
4216
4377
  async embedBatch(texts) {
@@ -4235,7 +4396,7 @@ var init_fastembed_provider = __esm({
4235
4396
  const originalIdx = uncachedIndices[batchIdx];
4236
4397
  const plain = Array.from(vec);
4237
4398
  results[originalIdx] = plain;
4238
- this.cacheSet(textHash(uncachedTexts[batchIdx]), plain);
4399
+ cacheSet(textHash(uncachedTexts[batchIdx]), plain);
4239
4400
  batchIdx++;
4240
4401
  }
4241
4402
  }
@@ -4243,14 +4404,6 @@ var init_fastembed_provider = __esm({
4243
4404
  }
4244
4405
  return results;
4245
4406
  }
4246
- cacheSet(hash4, value) {
4247
- if (cache.size >= MAX_CACHE_SIZE) {
4248
- const firstKey = cache.keys().next().value;
4249
- if (firstKey !== void 0) cache.delete(firstKey);
4250
- }
4251
- cache.set(hash4, value);
4252
- diskCacheDirty = true;
4253
- }
4254
4407
  };
4255
4408
  }
4256
4409
  });
@@ -4260,7 +4413,15 @@ var transformers_provider_exports = {};
4260
4413
  __export(transformers_provider_exports, {
4261
4414
  TransformersProvider: () => TransformersProvider
4262
4415
  });
4263
- var cache2, MAX_CACHE_SIZE2, TransformersProvider;
4416
+ import { createHash as createHash2 } from "crypto";
4417
+ function cacheKey2(text3) {
4418
+ return createHash2("sha256").update(text3).digest("hex");
4419
+ }
4420
+ function maxCachePayloadBytes2() {
4421
+ const raw = Number.parseInt(process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES ?? "", 10);
4422
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CACHE_PAYLOAD_BYTES2;
4423
+ }
4424
+ var cache2, MAX_CACHE_SIZE2, DEFAULT_CACHE_PAYLOAD_BYTES2, cachePayloadBytes2, TransformersProvider;
4264
4425
  var init_transformers_provider = __esm({
4265
4426
  "src/embedding/transformers-provider.ts"() {
4266
4427
  "use strict";
@@ -4268,6 +4429,8 @@ var init_transformers_provider = __esm({
4268
4429
  init_provider();
4269
4430
  cache2 = /* @__PURE__ */ new Map();
4270
4431
  MAX_CACHE_SIZE2 = 5e3;
4432
+ DEFAULT_CACHE_PAYLOAD_BYTES2 = 64 * 1024 * 1024;
4433
+ cachePayloadBytes2 = 0;
4271
4434
  TransformersProvider = class _TransformersProvider {
4272
4435
  name = "transformers-minilm";
4273
4436
  dimensions = 384;
@@ -4302,7 +4465,7 @@ var init_transformers_provider = __esm({
4302
4465
  return Promise.all(inputs.map((input) => this.embedInput(input, options)));
4303
4466
  }
4304
4467
  async embed(text3) {
4305
- const cached = cache2.get(text3);
4468
+ const cached = cache2.get(cacheKey2(text3));
4306
4469
  if (cached) return cached;
4307
4470
  const output = await this.extractor(text3, {
4308
4471
  pooling: "mean",
@@ -4312,7 +4475,7 @@ var init_transformers_provider = __esm({
4312
4475
  if (result.length !== this.dimensions) {
4313
4476
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
4314
4477
  }
4315
- this.cacheSet(text3, result);
4478
+ this.cacheSet(cacheKey2(text3), result);
4316
4479
  return result;
4317
4480
  }
4318
4481
  async embedBatch(texts) {
@@ -4320,7 +4483,7 @@ var init_transformers_provider = __esm({
4320
4483
  const uncachedIndices = [];
4321
4484
  const uncachedTexts = [];
4322
4485
  for (let i2 = 0; i2 < texts.length; i2++) {
4323
- const cached = cache2.get(texts[i2]);
4486
+ const cached = cache2.get(cacheKey2(texts[i2]));
4324
4487
  if (cached) {
4325
4488
  results[i2] = cached;
4326
4489
  } else {
@@ -4338,17 +4501,27 @@ var init_transformers_provider = __esm({
4338
4501
  const vec = Array.from(allVecs[i2]);
4339
4502
  const originalIdx = uncachedIndices[i2];
4340
4503
  results[originalIdx] = vec;
4341
- this.cacheSet(uncachedTexts[i2], vec);
4504
+ this.cacheSet(cacheKey2(uncachedTexts[i2]), vec);
4342
4505
  }
4343
4506
  }
4344
4507
  return results;
4345
4508
  }
4346
4509
  cacheSet(key, value) {
4347
- if (cache2.size >= MAX_CACHE_SIZE2) {
4348
- const firstKey = cache2.keys().next().value;
4349
- if (firstKey !== void 0) cache2.delete(firstKey);
4510
+ const incomingBytes = value.length * 8;
4511
+ if (incomingBytes > maxCachePayloadBytes2()) return;
4512
+ const existing = cache2.get(key);
4513
+ if (existing) cachePayloadBytes2 -= existing.length * 8;
4514
+ else {
4515
+ while (cache2.size >= MAX_CACHE_SIZE2 || cachePayloadBytes2 + incomingBytes > maxCachePayloadBytes2()) {
4516
+ const firstKey = cache2.keys().next().value;
4517
+ if (firstKey === void 0) break;
4518
+ const old = cache2.get(firstKey);
4519
+ cache2.delete(firstKey);
4520
+ if (old) cachePayloadBytes2 -= old.length * 8;
4521
+ }
4350
4522
  }
4351
4523
  cache2.set(key, value);
4524
+ cachePayloadBytes2 += incomingBytes;
4352
4525
  }
4353
4526
  };
4354
4527
  }
@@ -4370,7 +4543,7 @@ __export(api_provider_exports, {
4370
4543
  saveDiskCacheNow: () => saveDiskCacheNow,
4371
4544
  seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
4372
4545
  });
4373
- import { createHash as createHash2 } from "crypto";
4546
+ import { createHash as createHash3 } from "crypto";
4374
4547
  import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
4375
4548
  import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
4376
4549
  import { join as join3 } from "path";
@@ -4397,7 +4570,7 @@ function cacheStatFile() {
4397
4570
  function payloadBytes(vector) {
4398
4571
  return vector.length * BYTES_PER_DIM;
4399
4572
  }
4400
- function maxCachePayloadBytes() {
4573
+ function maxCachePayloadBytes3() {
4401
4574
  const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
4402
4575
  if (raw) {
4403
4576
  const parsed = Number.parseInt(raw, 10);
@@ -4407,7 +4580,7 @@ function maxCachePayloadBytes() {
4407
4580
  }
4408
4581
  function maxEntriesForDimensions(dimensions) {
4409
4582
  const dim = Math.max(1, Math.floor(dimensions));
4410
- const byBytes = Math.floor(maxCachePayloadBytes() / (dim * BYTES_PER_DIM));
4583
+ const byBytes = Math.floor(maxCachePayloadBytes3() / (dim * BYTES_PER_DIM));
4411
4584
  return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
4412
4585
  }
4413
4586
  function rememberDimensions(vector) {
@@ -4420,13 +4593,15 @@ function evictOldest() {
4420
4593
  if (firstKey === void 0) return;
4421
4594
  const old = cache3.get(firstKey);
4422
4595
  cache3.delete(firstKey);
4423
- if (old) cachePayloadBytes -= payloadBytes(old);
4596
+ if (old) cachePayloadBytes3 -= payloadBytes(old);
4424
4597
  }
4425
4598
  function evictToFit(incomingBytes, incomingDims) {
4599
+ if (incomingBytes > maxCachePayloadBytes3()) return false;
4426
4600
  const limit2 = maxEntriesForDimensions(incomingDims);
4427
- while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes + incomingBytes > maxCachePayloadBytes())) {
4601
+ while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes3 + incomingBytes > maxCachePayloadBytes3())) {
4428
4602
  evictOldest();
4429
4603
  }
4604
+ return true;
4430
4605
  }
4431
4606
  function isNumberArray(value) {
4432
4607
  return Array.isArray(value) && value.every((entry) => typeof entry === "number");
@@ -4453,12 +4628,12 @@ function cacheInsert(hash4, value, dirty) {
4453
4628
  const incoming = payloadBytes(value);
4454
4629
  const existing = cache3.get(hash4);
4455
4630
  if (existing) {
4456
- cachePayloadBytes -= payloadBytes(existing);
4631
+ cachePayloadBytes3 -= payloadBytes(existing);
4457
4632
  cache3.delete(hash4);
4458
4633
  }
4459
- evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
4634
+ if (!evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS)) return;
4460
4635
  cache3.set(hash4, value);
4461
- cachePayloadBytes += incoming;
4636
+ cachePayloadBytes3 += incoming;
4462
4637
  if (dirty) diskCacheDirty2 = true;
4463
4638
  }
4464
4639
  async function readCacheStat() {
@@ -4494,7 +4669,7 @@ function cacheNamespace(config) {
4494
4669
  ].join("|");
4495
4670
  }
4496
4671
  function textHash2(text3, namespace) {
4497
- return createHash2("sha256").update(`${namespace}\0${text3}`).digest("hex").slice(0, 16);
4672
+ return createHash3("sha256").update(`${namespace}\0${text3}`).digest("hex").slice(0, 16);
4498
4673
  }
4499
4674
  function inputIdentity(input, options = {}) {
4500
4675
  return JSON.stringify({
@@ -4836,7 +5011,7 @@ function getApiEmbeddingDiskCacheLoadCountForTests() {
4836
5011
  }
4837
5012
  function resetApiEmbeddingCacheForTests() {
4838
5013
  cache3.clear();
4839
- cachePayloadBytes = 0;
5014
+ cachePayloadBytes3 = 0;
4840
5015
  cacheDimensions = null;
4841
5016
  diskCacheEntryCount = 0;
4842
5017
  diskCacheLoaded = false;
@@ -4847,14 +5022,14 @@ function resetApiEmbeddingCacheForTests() {
4847
5022
  }
4848
5023
  function seedApiEmbeddingCacheForTests(entries) {
4849
5024
  cache3.clear();
4850
- cachePayloadBytes = 0;
5025
+ cachePayloadBytes3 = 0;
4851
5026
  cacheDimensions = null;
4852
5027
  for (const [key, value] of entries) cacheInsert(key, value, true);
4853
5028
  diskCacheLoaded = true;
4854
5029
  diskCacheDirty2 = true;
4855
5030
  }
4856
5031
  function getApiEmbeddingCachePayloadBytesForTests() {
4857
- return cachePayloadBytes;
5032
+ return cachePayloadBytes3;
4858
5033
  }
4859
5034
  function getApiEmbeddingJsonlLineCountCallsForTests() {
4860
5035
  return jsonlLineCountCalls;
@@ -5028,7 +5203,7 @@ function scheduleDiskSave() {
5028
5203
  diskSaveTimer = null;
5029
5204
  }, DISK_SAVE_DEBOUNCE_MS);
5030
5205
  }
5031
- function cacheSet(hash4, value) {
5206
+ function cacheSet2(hash4, value) {
5032
5207
  cacheInsert(hash4, value, true);
5033
5208
  }
5034
5209
  function resolveEnvEmbeddingApiKey() {
@@ -5148,7 +5323,7 @@ async function waitForRetry(waitMs, signal) {
5148
5323
  abortSignal.addEventListener("abort", onAbort, { once: true });
5149
5324
  });
5150
5325
  }
5151
- 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;
5326
+ 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;
5152
5327
  var init_api_provider = __esm({
5153
5328
  "src/embedding/api-provider.ts"() {
5154
5329
  "use strict";
@@ -5160,7 +5335,7 @@ var init_api_provider = __esm({
5160
5335
  BYTES_PER_DIM = 8;
5161
5336
  DEFAULT_ASSUMED_DIMENSIONS = 4096;
5162
5337
  MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
5163
- cachePayloadBytes = 0;
5338
+ cachePayloadBytes3 = 0;
5164
5339
  cacheDimensions = null;
5165
5340
  diskCacheEntryCount = 0;
5166
5341
  diskCacheDirty2 = false;
@@ -5345,7 +5520,7 @@ var init_api_provider = __esm({
5345
5520
  } else {
5346
5521
  embedding = await apiCall();
5347
5522
  }
5348
- cacheSet(hash4, embedding);
5523
+ cacheSet2(hash4, embedding);
5349
5524
  scheduleDiskSave();
5350
5525
  return embedding;
5351
5526
  }
@@ -5393,7 +5568,7 @@ var init_api_provider = __esm({
5393
5568
  for (const item of response.data) {
5394
5569
  const originalIdx = chunkIndices[item.index];
5395
5570
  results[originalIdx] = item.embedding;
5396
- cacheSet(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
5571
+ cacheSet2(textHash2(normalizedTexts[originalIdx], this.cacheKeyNamespace), item.embedding);
5397
5572
  }
5398
5573
  } catch (error) {
5399
5574
  const providerLimit = parseBatchLimit(error);
@@ -5471,7 +5646,7 @@ var init_api_provider = __esm({
5471
5646
  throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d; dimension mismatch`);
5472
5647
  }
5473
5648
  this.trackUsage(response);
5474
- cacheSet(hash4, embedding);
5649
+ cacheSet2(hash4, embedding);
5475
5650
  scheduleDiskSave();
5476
5651
  return embedding;
5477
5652
  }
@@ -6854,6 +7029,7 @@ var init_provider2 = __esm({
6854
7029
  openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
6855
7030
  anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
6856
7031
  openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
7032
+ atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
6857
7033
  custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
6858
7034
  };
6859
7035
  currentConfig = null;
@@ -7630,7 +7806,7 @@ __export(semantic_index_exports, {
7630
7806
  upsertSemanticVector: () => upsertSemanticVector,
7631
7807
  upsertSemanticVectors: () => upsertSemanticVectors
7632
7808
  });
7633
- import { createHash as createHash3 } from "crypto";
7809
+ import { createHash as createHash4 } from "crypto";
7634
7810
  import { createRequire as createRequire3 } from "module";
7635
7811
  import path11 from "path";
7636
7812
  function createSemanticIndexProfile(provider2) {
@@ -7644,7 +7820,7 @@ function stateKey(dataDir, profile) {
7644
7820
  return `${path11.resolve(dataDir)}::${profile.key}`;
7645
7821
  }
7646
7822
  function tableName(profile) {
7647
- const digest2 = createHash3("sha256").update(profile.key).digest("hex").slice(0, 20);
7823
+ const digest2 = createHash4("sha256").update(profile.key).digest("hex").slice(0, 20);
7648
7824
  return `${TABLE_PREFIX}${digest2}`;
7649
7825
  }
7650
7826
  function indexRoot(dataDir) {
@@ -9732,6 +9908,7 @@ var init_secret_filter = __esm({
9732
9908
  // src/runtime/maintenance-jobs.ts
9733
9909
  var maintenance_jobs_exports = {};
9734
9910
  __export(maintenance_jobs_exports, {
9911
+ DEFAULT_FAILED_HISTORY_RETENTION_MS: () => DEFAULT_FAILED_HISTORY_RETENTION_MS,
9735
9912
  MAINTENANCE_JOB_KINDS: () => MAINTENANCE_JOB_KINDS,
9736
9913
  MaintenanceJobStore: () => MaintenanceJobStore,
9737
9914
  MaintenanceJobWorker: () => MaintenanceJobWorker,
@@ -9781,7 +9958,7 @@ function normalizedKinds(kinds) {
9781
9958
  function getMaintenanceRetryDelayMs(attempts) {
9782
9959
  return Math.min(6e4, 1e3 * 2 ** Math.max(0, attempts - 1));
9783
9960
  }
9784
- var MAINTENANCE_JOB_KINDS, DEFAULT_MAX_ATTEMPTS, DEFAULT_LEASE_MS, DEFAULT_POLL_INTERVAL_MS, MAX_ERROR_LENGTH, DEFAULT_COMPLETED_HISTORY_RETENTION_MS, MaintenanceJobStore, MaintenanceJobWorker;
9961
+ 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;
9785
9962
  var init_maintenance_jobs = __esm({
9786
9963
  "src/runtime/maintenance-jobs.ts"() {
9787
9964
  "use strict";
@@ -9808,6 +9985,7 @@ var init_maintenance_jobs = __esm({
9808
9985
  DEFAULT_POLL_INTERVAL_MS = 2e3;
9809
9986
  MAX_ERROR_LENGTH = 1e3;
9810
9987
  DEFAULT_COMPLETED_HISTORY_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
9988
+ DEFAULT_FAILED_HISTORY_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
9811
9989
  MaintenanceJobStore = class {
9812
9990
  db;
9813
9991
  constructor(dataDir) {
@@ -9934,18 +10112,21 @@ var init_maintenance_jobs = __esm({
9934
10112
  }
9935
10113
  /**
9936
10114
  * Completed jobs are useful recent operator history, not permanent data.
9937
- * Failed jobs stay available for diagnosis until an operator explicitly
9938
- * resolves them or clears the database.
10115
+ * Failed diagnostics are retained longer, but are still bounded so a
10116
+ * permanently failing job kind cannot grow the database forever.
9939
10117
  */
9940
10118
  pruneCompletedHistory(options = {}) {
9941
10119
  const now3 = options.now ?? Date.now();
9942
10120
  const maxAgeMs = Number.isFinite(options.maxAgeMs) ? Math.max(0, Math.floor(options.maxAgeMs)) : DEFAULT_COMPLETED_HISTORY_RETENTION_MS;
10121
+ const failedMaxAgeMs = Number.isFinite(options.failedMaxAgeMs) ? Math.max(0, Math.floor(options.failedMaxAgeMs)) : DEFAULT_FAILED_HISTORY_RETENTION_MS;
9943
10122
  const result = this.db.prepare(`
9944
10123
  DELETE FROM maintenance_jobs
9945
- WHERE status = 'completed'
10124
+ WHERE (status = 'completed'
9946
10125
  AND completed_at IS NOT NULL
9947
- AND completed_at < ?
9948
- `).run(now3 - maxAgeMs);
10126
+ AND completed_at < ?)
10127
+ OR (status = 'failed'
10128
+ AND updated_at < ?)
10129
+ `).run(now3 - maxAgeMs, now3 - failedMaxAgeMs);
9949
10130
  return Number(result.changes ?? 0);
9950
10131
  }
9951
10132
  claimNext(options) {
@@ -10299,7 +10480,7 @@ var init_lifecycle = __esm({
10299
10480
  });
10300
10481
 
10301
10482
  // src/store/evidence-store.ts
10302
- import { createHash as createHash4, randomUUID as randomUUID3 } from "crypto";
10483
+ import { createHash as createHash5, randomUUID as randomUUID3 } from "crypto";
10303
10484
  function safeJson(value, fallback) {
10304
10485
  if (typeof value !== "string" || value.length === 0) return fallback;
10305
10486
  try {
@@ -10333,7 +10514,7 @@ function rowToCard(row) {
10333
10514
  };
10334
10515
  }
10335
10516
  function observationHash(observation) {
10336
- return createHash4("sha256").update(JSON.stringify({
10517
+ return createHash5("sha256").update(JSON.stringify({
10337
10518
  projectId: observation.projectId,
10338
10519
  id: observation.id,
10339
10520
  title: observation.title,
@@ -10927,13 +11108,13 @@ __export(workspace_exports, {
10927
11108
  loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
10928
11109
  resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
10929
11110
  });
10930
- import { createHash as createHash5 } from "crypto";
11111
+ import { createHash as createHash6 } from "crypto";
10931
11112
  import { execFile } from "child_process";
10932
11113
  import { promises as fs9 } from "fs";
10933
11114
  import path14 from "path";
10934
11115
  import { promisify } from "util";
10935
11116
  function hash(value) {
10936
- return createHash5("sha256").update(value).digest("hex");
11117
+ return createHash6("sha256").update(value).digest("hex");
10937
11118
  }
10938
11119
  function workspaceId(projectId, mode) {
10939
11120
  return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
@@ -12086,14 +12267,14 @@ __export(asset_store_exports, {
12086
12267
  readMediaAsset: () => readMediaAsset,
12087
12268
  removeMediaAsset: () => removeMediaAsset
12088
12269
  });
12089
- import { createHash as createHash6, randomUUID as randomUUID6 } from "crypto";
12270
+ import { createHash as createHash7, randomUUID as randomUUID6 } from "crypto";
12090
12271
  import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
12091
12272
  import path15 from "path";
12092
12273
  function mediaRoot(dataDir) {
12093
12274
  return path15.resolve(dataDir, "media");
12094
12275
  }
12095
12276
  function projectStorageKey(projectId) {
12096
- return createHash6("sha256").update(projectId).digest("hex").slice(0, 16);
12277
+ return createHash7("sha256").update(projectId).digest("hex").slice(0, 16);
12097
12278
  }
12098
12279
  function validateUnderRoot(root, candidate) {
12099
12280
  const resolved = path15.resolve(candidate);
@@ -12153,7 +12334,7 @@ async function readHeader(filePath, bytes = 32) {
12153
12334
  }
12154
12335
  async function sha256File(filePath) {
12155
12336
  const bytes = await readFile3(filePath);
12156
- return createHash6("sha256").update(bytes).digest("hex");
12337
+ return createHash7("sha256").update(bytes).digest("hex");
12157
12338
  }
12158
12339
  function destinationFor(root, projectId, sha256, extension3) {
12159
12340
  const relative5 = path15.join("assets", projectStorageKey(projectId), sha256.slice(0, 2), `${sha256}${extension3}`);
@@ -12259,7 +12440,7 @@ async function importMediaBuffer(input) {
12259
12440
  if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
12260
12441
  if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
12261
12442
  const detected = detectMedia(input.bytes.subarray(0, 32));
12262
- const sha256 = createHash6("sha256").update(input.bytes).digest("hex");
12443
+ const sha256 = createHash7("sha256").update(input.bytes).digest("hex");
12263
12444
  return importKnownMedia({
12264
12445
  dataDir: input.dataDir,
12265
12446
  projectId: input.projectId,
@@ -12277,7 +12458,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
12277
12458
  if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
12278
12459
  const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
12279
12460
  if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
12280
- const sha256 = createHash6("sha256").update(bytes).digest("hex");
12461
+ const sha256 = createHash7("sha256").update(bytes).digest("hex");
12281
12462
  if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
12282
12463
  return bytes;
12283
12464
  }
@@ -65147,7 +65328,7 @@ var require_gaxios = __commonJS({
65147
65328
  var retry_js_1 = require_retry3();
65148
65329
  var stream_1 = __require("stream");
65149
65330
  var interceptor_js_1 = require_interceptor();
65150
- var randomUUID19 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
65331
+ var randomUUID20 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
65151
65332
  var HTTP_STATUS_NO_CONTENT = 204;
65152
65333
  var Gaxios = class {
65153
65334
  agentCache = /* @__PURE__ */ new Map();
@@ -65420,7 +65601,7 @@ var require_gaxios = __commonJS({
65420
65601
  */
65421
65602
  ["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
65422
65603
  if (opts.multipart?.length) {
65423
- const boundary = await randomUUID19();
65604
+ const boundary = await randomUUID20();
65424
65605
  preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
65425
65606
  opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
65426
65607
  } else if (shouldDirectlyPassData) {
@@ -71092,16 +71273,16 @@ var require_jwtaccess = __commonJS({
71092
71273
  * @returns A string that returns the cached key.
71093
71274
  */
71094
71275
  getCachedKey(url, scopes) {
71095
- let cacheKey = url;
71276
+ let cacheKey3 = url;
71096
71277
  if (scopes && Array.isArray(scopes) && scopes.length) {
71097
- cacheKey = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
71278
+ cacheKey3 = url ? `${url}_${scopes.join("_")}` : `${scopes.join("_")}`;
71098
71279
  } else if (typeof scopes === "string") {
71099
- cacheKey = url ? `${url}_${scopes}` : scopes;
71280
+ cacheKey3 = url ? `${url}_${scopes}` : scopes;
71100
71281
  }
71101
- if (!cacheKey) {
71282
+ if (!cacheKey3) {
71102
71283
  throw Error("Scopes or url must be provided");
71103
71284
  }
71104
- return cacheKey;
71285
+ return cacheKey3;
71105
71286
  }
71106
71287
  /**
71107
71288
  * Get a non-expired access token, after refreshing if necessary.
@@ -77647,7 +77828,7 @@ var require_websocket = __commonJS({
77647
77828
  var http3 = __require("http");
77648
77829
  var net = __require("net");
77649
77830
  var tls = __require("tls");
77650
- var { randomBytes: randomBytes2, createHash: createHash19 } = __require("crypto");
77831
+ var { randomBytes: randomBytes2, createHash: createHash20 } = __require("crypto");
77651
77832
  var { Duplex, Readable: Readable2 } = __require("stream");
77652
77833
  var { URL: URL2 } = __require("url");
77653
77834
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -78315,7 +78496,7 @@ var require_websocket = __commonJS({
78315
78496
  abortHandshake(websocket, socket, "Invalid Upgrade header");
78316
78497
  return;
78317
78498
  }
78318
- const digest2 = createHash19("sha1").update(key + GUID).digest("base64");
78499
+ const digest2 = createHash20("sha1").update(key + GUID).digest("base64");
78319
78500
  if (res.headers["sec-websocket-accept"] !== digest2) {
78320
78501
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
78321
78502
  return;
@@ -78687,7 +78868,7 @@ var require_websocket_server = __commonJS({
78687
78868
  var EventEmitter2 = __require("events");
78688
78869
  var http3 = __require("http");
78689
78870
  var { Duplex } = __require("stream");
78690
- var { createHash: createHash19 } = __require("crypto");
78871
+ var { createHash: createHash20 } = __require("crypto");
78691
78872
  var extension3 = require_extension();
78692
78873
  var PerMessageDeflate2 = require_permessage_deflate();
78693
78874
  var subprotocol2 = require_subprotocol();
@@ -78994,7 +79175,7 @@ var require_websocket_server = __commonJS({
78994
79175
  );
78995
79176
  }
78996
79177
  if (this._state > RUNNING) return abortHandshake(socket, 503);
78997
- const digest2 = createHash19("sha1").update(key + GUID).digest("base64");
79178
+ const digest2 = createHash20("sha1").update(key + GUID).digest("base64");
78998
79179
  const headers = [
78999
79180
  "HTTP/1.1 101 Switching Protocols",
79000
79181
  "Upgrade: websocket",
@@ -143053,9 +143234,9 @@ var init_union_priority_sort = __esm({
143053
143234
  // node_modules/typebox/build/value/clean/from_union.mjs
143054
143235
  function FromUnion9(context, type, value) {
143055
143236
  for (const schema of UnionPrioritySort(type.anyOf)) {
143056
- const clean = FromType19(context, schema, Clone2(value));
143057
- if (Check2(context, schema, clean))
143058
- return clean;
143237
+ const clean2 = FromType19(context, schema, Clone2(value));
143238
+ if (Check2(context, schema, clean2))
143239
+ return clean2;
143059
143240
  }
143060
143241
  return value;
143061
143242
  }
@@ -147693,9 +147874,9 @@ var init_long_term = __esm({
147693
147874
  });
147694
147875
 
147695
147876
  // src/codegraph/ids.ts
147696
- import { createHash as createHash7 } from "crypto";
147877
+ import { createHash as createHash8 } from "crypto";
147697
147878
  function digest(input) {
147698
- return createHash7("sha256").update(input).digest("hex").slice(0, 16);
147879
+ return createHash8("sha256").update(input).digest("hex").slice(0, 16);
147699
147880
  }
147700
147881
  function normalizeCodePath(path37) {
147701
147882
  return path37.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
@@ -148743,7 +148924,7 @@ var init_store = __esm({
148743
148924
 
148744
148925
  // src/codegraph/code-state.ts
148745
148926
  import { execFile as execFile2 } from "child_process";
148746
- import { createHash as createHash8 } from "crypto";
148927
+ import { createHash as createHash9 } from "crypto";
148747
148928
  import { promisify as promisify3 } from "util";
148748
148929
  async function runGit(rootPath, args) {
148749
148930
  try {
@@ -148772,7 +148953,7 @@ function changedPathCount(status) {
148772
148953
  return count2;
148773
148954
  }
148774
148955
  function fingerprint(baseRevision, status) {
148775
- return createHash8("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
148956
+ return createHash9("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
148776
148957
  }
148777
148958
  async function collectCodeStateSnapshot(input) {
148778
148959
  const [revision, status] = await Promise.all([
@@ -148866,12 +149047,12 @@ var init_exclude3 = __esm({
148866
149047
  });
148867
149048
 
148868
149049
  // src/codegraph/semantic-provider.ts
148869
- import { createHash as createHash9 } from "crypto";
149050
+ import { createHash as createHash10 } from "crypto";
148870
149051
  import "fs";
148871
149052
  import { resolve } from "path";
148872
149053
  import ts from "typescript";
148873
149054
  function hashText(value) {
148874
- return createHash9("sha256").update(value).digest("hex");
149055
+ return createHash10("sha256").update(value).digest("hex");
148875
149056
  }
148876
149057
  function canonicalPath(value) {
148877
149058
  const normalized = resolve(value).replace(/\\/g, "/");
@@ -149216,11 +149397,11 @@ __export(lite_provider_exports, {
149216
149397
  indexProjectLite: () => indexProjectLite,
149217
149398
  refreshProjectLite: () => refreshProjectLite
149218
149399
  });
149219
- import { createHash as createHash10 } from "crypto";
149400
+ import { createHash as createHash11 } from "crypto";
149220
149401
  import { existsSync as existsSync12, readdirSync as readdirSync2, readFileSync as readFileSync8, statSync as statSync3 } from "fs";
149221
149402
  import { join as join4, relative as relative2 } from "path";
149222
149403
  function hashText2(text3) {
149223
- return createHash10("sha256").update(text3).digest("hex");
149404
+ return createHash11("sha256").update(text3).digest("hex");
149224
149405
  }
149225
149406
  function extension2(path37) {
149226
149407
  const index = path37.lastIndexOf(".");
@@ -149853,7 +150034,7 @@ var claim_store_exports = {};
149853
150034
  __export(claim_store_exports, {
149854
150035
  ClaimStore: () => ClaimStore
149855
150036
  });
149856
- import { createHash as createHash11, randomUUID as randomUUID12 } from "crypto";
150037
+ import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
149857
150038
  function optionalText3(value) {
149858
150039
  return typeof value === "string" && value ? value : void 0;
149859
150040
  }
@@ -149906,7 +150087,7 @@ function rowToEvent3(row) {
149906
150087
  };
149907
150088
  }
149908
150089
  function evidenceKey(input) {
149909
- return createHash11("sha256").update(JSON.stringify([
150090
+ return createHash12("sha256").update(JSON.stringify([
149910
150091
  input.evidenceKind,
149911
150092
  input.evidenceId,
149912
150093
  input.relation,
@@ -150104,7 +150285,7 @@ __export(claims_exports, {
150104
150285
  supersedeClaim: () => supersedeClaim,
150105
150286
  writeClaim: () => writeClaim
150106
150287
  });
150107
- import { createHash as createHash12, randomUUID as randomUUID13 } from "crypto";
150288
+ import { createHash as createHash13, randomUUID as randomUUID13 } from "crypto";
150108
150289
  function compactText2(value, field) {
150109
150290
  if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
150110
150291
  const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
@@ -150116,7 +150297,7 @@ function normalizedTerm(value) {
150116
150297
  return compactText2(value, "identity").toLocaleLowerCase("en-US");
150117
150298
  }
150118
150299
  function hashIdentity(parts) {
150119
- return createHash12("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
150300
+ return createHash13("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
150120
150301
  }
150121
150302
  function buildClaimIdentity(input) {
150122
150303
  const subject = normalizedTerm(input.subject);
@@ -150357,7 +150538,7 @@ function supersedeClaim(store, input) {
150357
150538
  });
150358
150539
  }
150359
150540
  function hashObservation(observation) {
150360
- return createHash12("sha256").update(JSON.stringify([
150541
+ return createHash13("sha256").update(JSON.stringify([
150361
150542
  observation.title,
150362
150543
  observation.narrative,
150363
150544
  observation.facts,
@@ -150601,11 +150782,11 @@ var init_frontmatter = __esm({
150601
150782
  });
150602
150783
 
150603
150784
  // src/knowledge/markdown.ts
150604
- import { createHash as createHash13 } from "crypto";
150785
+ import { createHash as createHash14 } from "crypto";
150605
150786
  import { promises as fs13 } from "fs";
150606
150787
  import path22 from "path";
150607
150788
  function hashContent(content) {
150608
- return createHash13("sha256").update(content).digest("hex");
150789
+ return createHash14("sha256").update(content).digest("hex");
150609
150790
  }
150610
150791
  function stringField(data, key) {
150611
150792
  const value = data[key];
@@ -150731,11 +150912,11 @@ __export(wiki_exports, {
150731
150912
  lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
150732
150913
  readKnowledgePage: () => readKnowledgePage
150733
150914
  });
150734
- import { createHash as createHash14 } from "crypto";
150915
+ import { createHash as createHash15 } from "crypto";
150735
150916
  import { promises as fs14 } from "fs";
150736
150917
  import path23 from "path";
150737
150918
  function hash2(value) {
150738
- return createHash14("sha256").update(value).digest("hex");
150919
+ return createHash15("sha256").update(value).digest("hex");
150739
150920
  }
150740
150921
  function now() {
150741
150922
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -151954,11 +152135,11 @@ __export(workflows_exports, {
151954
152135
  syncCanonicalWorkflows: () => syncCanonicalWorkflows,
151955
152136
  writeCanonicalWorkflow: () => writeCanonicalWorkflow
151956
152137
  });
151957
- import { createHash as createHash15 } from "crypto";
152138
+ import { createHash as createHash16 } from "crypto";
151958
152139
  import { promises as fs15 } from "fs";
151959
152140
  import path24 from "path";
151960
152141
  function hash3(value) {
151961
- return createHash15("sha256").update(value).digest("hex");
152142
+ return createHash16("sha256").update(value).digest("hex");
151962
152143
  }
151963
152144
  function now2() {
151964
152145
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -155993,8 +156174,8 @@ function legacyBehavior(homeDir) {
155993
156174
  function getBehaviorConfig(options = {}) {
155994
156175
  const homeDir = options.homeDir ?? homedir22();
155995
156176
  const projectRoot = options.projectRoot === void 0 ? detectProject()?.rootPath ?? null : options.projectRoot;
155996
- const cacheKey = `${homeDir}\0${projectRoot ?? ""}`;
155997
- const cached = cache4.get(cacheKey);
156177
+ const cacheKey3 = `${homeDir}\0${projectRoot ?? ""}`;
156178
+ const cached = cache4.get(cacheKey3);
155998
156179
  if (cached) return cached;
155999
156180
  const legacy = legacyBehavior(homeDir);
156000
156181
  let resolved = {};
@@ -156008,7 +156189,7 @@ function getBehaviorConfig(options = {}) {
156008
156189
  autoCleanup: typeof resolved.autoCleanup === "boolean" ? resolved.autoCleanup : typeof legacy.autoCleanup === "boolean" ? legacy.autoCleanup : DEFAULTS.autoCleanup,
156009
156190
  formationMode: isFormationMode(resolved.formation) ? resolved.formation : isFormationMode(legacy.formationMode) ? legacy.formationMode : DEFAULTS.formationMode
156010
156191
  };
156011
- cache4.set(cacheKey, config);
156192
+ cache4.set(cacheKey3, config);
156012
156193
  return config;
156013
156194
  }
156014
156195
  function resetBehaviorConfigCache() {
@@ -156613,6 +156794,7 @@ function freshnessForMemory(status) {
156613
156794
  return "unknown";
156614
156795
  }
156615
156796
  function receiptOmissionKind(raw) {
156797
+ if (raw.includes("continuity")) return "continuity";
156616
156798
  if (raw.includes("continuation")) return "continuation";
156617
156799
  if (raw.includes("task")) return "task";
156618
156800
  if (raw.includes("fact")) return "current-fact";
@@ -156723,6 +156905,77 @@ function renderTaskWorksetPrompt(input) {
156723
156905
  trust: "source-backed"
156724
156906
  });
156725
156907
  appendLine(lines, "Task lens: " + input.lens, maxTokens, omitted, "lens");
156908
+ if (input.continuity) {
156909
+ const continuity = input.continuity;
156910
+ appendLine(lines, "", maxTokens, omitted, "continuity-heading");
156911
+ appendLine(lines, "Task continuity", maxTokens, omitted, "continuity-heading", selected, {
156912
+ kind: "continuity",
156913
+ id: "continuity:" + continuity.taskId,
156914
+ reason: "explicit task continuity ledger",
156915
+ trust: "source-backed"
156916
+ });
156917
+ appendLine(
156918
+ lines,
156919
+ "- Status: " + continuity.status + " | " + short(continuity.task, 30),
156920
+ maxTokens,
156921
+ omitted,
156922
+ "continuity-task"
156923
+ );
156924
+ appendLine(
156925
+ lines,
156926
+ "- Outcome: " + continuity.outcome.state,
156927
+ maxTokens,
156928
+ omitted,
156929
+ "continuity-outcome",
156930
+ selected,
156931
+ {
156932
+ kind: "continuity",
156933
+ id: "continuity:" + continuity.taskId,
156934
+ reason: "deterministic task outcome projection",
156935
+ trust: "derived"
156936
+ }
156937
+ );
156938
+ for (const requirement of continuity.requirements.slice(0, 3)) {
156939
+ appendLine(lines, "- Requirement: " + short(requirement, 24), maxTokens, omitted, "continuity-requirement", selected, {
156940
+ kind: "continuity",
156941
+ id: "continuity:" + continuity.taskId,
156942
+ reason: "explicit task requirement",
156943
+ trust: "source-backed"
156944
+ });
156945
+ }
156946
+ for (const decision of continuity.decisions.slice(0, 2)) {
156947
+ appendLine(lines, "- Decision: " + short(decision, 24), maxTokens, omitted, "continuity-decision", selected, {
156948
+ kind: "continuity",
156949
+ id: "continuity:" + continuity.taskId,
156950
+ reason: "explicit task decision",
156951
+ trust: "source-backed"
156952
+ });
156953
+ }
156954
+ for (const verification of continuity.verification.slice(-3)) {
156955
+ appendLine(
156956
+ lines,
156957
+ "- Verify [" + verification.status + "]: " + short(verification.content, 22),
156958
+ maxTokens,
156959
+ omitted,
156960
+ "continuity-verification",
156961
+ selected,
156962
+ {
156963
+ kind: "continuity",
156964
+ id: "continuity:" + continuity.taskId,
156965
+ reason: "task verification state",
156966
+ trust: "source-backed"
156967
+ }
156968
+ );
156969
+ }
156970
+ for (const risk of continuity.risks.slice(0, 2)) {
156971
+ appendLine(lines, "- Risk: " + short(risk, 22), maxTokens, omitted, "continuity-risk", selected, {
156972
+ kind: "continuity",
156973
+ id: "continuity:" + continuity.taskId,
156974
+ reason: "open task risk",
156975
+ trust: "source-backed"
156976
+ });
156977
+ }
156978
+ }
156726
156979
  if (input.alwaysOn) {
156727
156980
  const hasAlwaysOn = input.alwaysOn.profile.length > 0 || Boolean(input.alwaysOn.state) || input.alwaysOn.durable.length > 0;
156728
156981
  if (hasAlwaysOn) {
@@ -157246,6 +157499,7 @@ async function buildTaskWorkset(input) {
157246
157499
  version: "1.3",
157247
157500
  task,
157248
157501
  lens: input.lens,
157502
+ ...input.continuity ? { continuity: input.continuity } : {},
157249
157503
  ...input.alwaysOn && (input.alwaysOn.profile.length > 0 || input.alwaysOn.state || input.alwaysOn.durable.length > 0) ? { alwaysOn: input.alwaysOn } : {},
157250
157504
  currentFacts: input.currentFacts?.map((fact) => fact.startsWith("Historical note:") ? short(fact, 48) : short(fact, 28)).slice(0, 4) ?? [],
157251
157505
  ...continuation ? { continuation } : {},
@@ -158630,7 +158884,7 @@ var compaction_checkpoint_store_exports = {};
158630
158884
  __export(compaction_checkpoint_store_exports, {
158631
158885
  CompactionCheckpointStore: () => CompactionCheckpointStore
158632
158886
  });
158633
- import { createHash as createHash17, randomUUID as randomUUID16 } from "crypto";
158887
+ import { createHash as createHash18, randomUUID as randomUUID16 } from "crypto";
158634
158888
  function optionalText7(value) {
158635
158889
  return typeof value === "string" && value ? value : void 0;
158636
158890
  }
@@ -158672,7 +158926,7 @@ function sourceKeyFor(input, summary) {
158672
158926
  input.tokensBefore ?? "",
158673
158927
  input.firstKeptEntryId ?? ""
158674
158928
  ].join("\0");
158675
- return `derived:${createHash17("sha256").update(material).digest("hex").slice(0, 32)}`;
158929
+ return `derived:${createHash18("sha256").update(material).digest("hex").slice(0, 32)}`;
158676
158930
  }
158677
158931
  function rowToCheckpoint(row) {
158678
158932
  return {
@@ -158930,6 +159184,305 @@ var init_compaction_checkpoint_store = __esm({
158930
159184
  }
158931
159185
  });
158932
159186
 
159187
+ // src/knowledge/task-continuity.ts
159188
+ var task_continuity_exports = {};
159189
+ __export(task_continuity_exports, {
159190
+ TASK_CONTINUITY_EVENT_KINDS: () => TASK_CONTINUITY_EVENT_KINDS,
159191
+ TaskContinuityStore: () => TaskContinuityStore,
159192
+ evaluateTaskContinuity: () => evaluateTaskContinuity
159193
+ });
159194
+ import { randomUUID as randomUUID17 } from "crypto";
159195
+ function clean(value, maxLength = MAX_TEXT_LENGTH2) {
159196
+ return sanitizeCredentials(value).replace(/\s+/g, " ").trim().slice(0, maxLength);
159197
+ }
159198
+ function cleanList(values, maxLength = MAX_TEXT_LENGTH2) {
159199
+ return [...new Set((values ?? []).map((value) => clean(value, maxLength)).filter(Boolean))].slice(0, MAX_LIST_ITEMS2);
159200
+ }
159201
+ function parseRefs(value) {
159202
+ if (typeof value !== "string") return [];
159203
+ try {
159204
+ const parsed = JSON.parse(value);
159205
+ return Array.isArray(parsed) ? cleanList(parsed.filter((item) => typeof item === "string"), 500).slice(0, MAX_EVIDENCE_REFS) : [];
159206
+ } catch {
159207
+ return [];
159208
+ }
159209
+ }
159210
+ function evaluateTaskContinuity(ledger) {
159211
+ const verification = {
159212
+ passed: ledger.verification.filter((item) => item.status === "passed").length,
159213
+ failed: ledger.verification.filter((item) => item.status === "failed").length,
159214
+ pending: ledger.verification.filter((item) => item.status === "pending").length,
159215
+ skipped: ledger.verification.filter((item) => item.status === "skipped").length
159216
+ };
159217
+ const reasons = [];
159218
+ if (verification.failed > 0) reasons.push("verification-failed");
159219
+ if (verification.pending > 0) reasons.push("verification-pending");
159220
+ if (ledger.risks.length > 0) reasons.push("open-risks");
159221
+ if (ledger.status === "blocked") reasons.push("task-blocked");
159222
+ if (ledger.status === "abandoned") reasons.push("task-abandoned");
159223
+ if (ledger.status === "blocked" || ledger.status === "abandoned" || verification.failed > 0) {
159224
+ return {
159225
+ state: "at-risk",
159226
+ score: verification.passed > verification.failed ? 0.55 : 0.2,
159227
+ verification,
159228
+ reasons
159229
+ };
159230
+ }
159231
+ if (ledger.status === "completed") {
159232
+ if (verification.passed > 0 && verification.pending === 0 && verification.skipped === 0) {
159233
+ return {
159234
+ state: ledger.risks.length > 0 ? "validated-with-risks" : "validated",
159235
+ score: ledger.risks.length > 0 ? 0.8 : 1,
159236
+ verification,
159237
+ reasons: reasons.length > 0 ? reasons : ["verification-passed"]
159238
+ };
159239
+ }
159240
+ return {
159241
+ state: "unverified",
159242
+ score: 0.4,
159243
+ verification,
159244
+ reasons: reasons.length > 0 ? reasons : ["no-passing-verification"]
159245
+ };
159246
+ }
159247
+ return {
159248
+ state: "in-progress",
159249
+ score: verification.passed > 0 && verification.pending === 0 ? 0.75 : 0.5,
159250
+ verification,
159251
+ reasons: reasons.length > 0 ? reasons : ["task-open"]
159252
+ };
159253
+ }
159254
+ function rowToEvent4(row) {
159255
+ const status = row.item_status ? String(row.item_status) : void 0;
159256
+ return {
159257
+ id: String(row.id),
159258
+ projectId: String(row.project_id),
159259
+ taskId: String(row.task_id),
159260
+ task: clean(String(row.task), MAX_TASK_LENGTH),
159261
+ kind: row.kind,
159262
+ content: clean(String(row.content)),
159263
+ ...status ? { status } : {},
159264
+ ...row.source_ref ? { sourceRef: clean(String(row.source_ref), 500) } : {},
159265
+ evidenceRefs: parseRefs(row.evidence_json),
159266
+ ...row.actor ? { actor: clean(String(row.actor), 200) } : {},
159267
+ at: String(row.created_at),
159268
+ ...row.event_key ? { eventKey: clean(String(row.event_key), 200) } : {},
159269
+ ...row.item_key ? { itemKey: clean(String(row.item_key), 120) } : {},
159270
+ ...row.supersedes_id ? { supersedesId: clean(String(row.supersedes_id), 120) } : {}
159271
+ };
159272
+ }
159273
+ function aggregate(events) {
159274
+ const first2 = events.find((event) => event.kind === "task") ?? events[0];
159275
+ const latestOutcome = [...events].reverse().find((event) => event.kind === "outcome");
159276
+ const verificationByKey = /* @__PURE__ */ new Map();
159277
+ for (const event of events.filter((event2) => event2.kind === "verification")) {
159278
+ verificationByKey.set(event.itemKey ?? `event:${event.id}`, event);
159279
+ }
159280
+ const ledger = {
159281
+ taskId: first2.taskId,
159282
+ projectId: first2.projectId,
159283
+ task: first2.task,
159284
+ status: latestOutcome?.status ?? "open",
159285
+ requirements: events.filter((event) => event.kind === "requirement").map((event) => event.content),
159286
+ decisions: events.filter((event) => event.kind === "decision").map((event) => event.content),
159287
+ verification: [...verificationByKey.values()].map((event) => ({
159288
+ id: event.itemKey ?? event.id,
159289
+ content: event.content,
159290
+ status: event.status ?? "pending",
159291
+ ...event.sourceRef ? { sourceRef: event.sourceRef } : {},
159292
+ evidenceRefs: event.evidenceRefs
159293
+ })),
159294
+ risks: events.filter((event) => event.kind === "risk").map((event) => event.content),
159295
+ outcomes: events.filter((event) => event.kind === "outcome").map((event) => event.content),
159296
+ updatedAt: events[events.length - 1].at,
159297
+ events
159298
+ };
159299
+ return { ...ledger, outcome: evaluateTaskContinuity(ledger) };
159300
+ }
159301
+ var TASK_CONTINUITY_EVENT_KINDS, MAX_TEXT_LENGTH2, MAX_TASK_LENGTH, MAX_LIST_ITEMS2, MAX_EVIDENCE_REFS, MAX_EVENTS_PER_TASK, TaskContinuityStore;
159302
+ var init_task_continuity = __esm({
159303
+ "src/knowledge/task-continuity.ts"() {
159304
+ "use strict";
159305
+ init_esm_shims();
159306
+ init_secret_filter();
159307
+ init_sqlite_db();
159308
+ TASK_CONTINUITY_EVENT_KINDS = [
159309
+ "task",
159310
+ "requirement",
159311
+ "decision",
159312
+ "verification",
159313
+ "risk",
159314
+ "outcome"
159315
+ ];
159316
+ MAX_TEXT_LENGTH2 = 2e3;
159317
+ MAX_TASK_LENGTH = 1e3;
159318
+ MAX_LIST_ITEMS2 = 8;
159319
+ MAX_EVIDENCE_REFS = 8;
159320
+ MAX_EVENTS_PER_TASK = 200;
159321
+ TaskContinuityStore = class {
159322
+ db = null;
159323
+ async init(dataDir) {
159324
+ this.db = getDatabase(dataDir);
159325
+ }
159326
+ requireDb() {
159327
+ if (!this.db) throw new Error("TaskContinuityStore is not initialized.");
159328
+ return this.db;
159329
+ }
159330
+ insert(input) {
159331
+ const db2 = this.requireDb();
159332
+ const projectId = clean(input.projectId, 500);
159333
+ const taskId = clean(input.taskId, 120);
159334
+ const eventKey = input.eventKey ? clean(input.eventKey, 200) : void 0;
159335
+ if (eventKey) {
159336
+ const existing = db2.prepare(
159337
+ "SELECT * FROM task_continuity_events WHERE project_id = ? AND task_id = ? AND event_key = ?"
159338
+ ).get(projectId, taskId, eventKey);
159339
+ if (existing) return rowToEvent4(existing);
159340
+ }
159341
+ const existingCount = db2.prepare(
159342
+ "SELECT COUNT(*) AS count FROM task_continuity_events WHERE project_id = ? AND task_id = ?"
159343
+ ).get(projectId, taskId);
159344
+ if (Number(existingCount?.count ?? 0) >= MAX_EVENTS_PER_TASK) {
159345
+ throw new Error("Task continuity ledger reached its 200-event limit.");
159346
+ }
159347
+ const event = {
159348
+ id: randomUUID17(),
159349
+ projectId,
159350
+ taskId,
159351
+ task: clean(input.task, MAX_TASK_LENGTH),
159352
+ kind: input.kind,
159353
+ content: clean(input.content),
159354
+ ...input.status ? { status: input.status } : {},
159355
+ ...input.sourceRef ? { sourceRef: clean(input.sourceRef, 500) } : {},
159356
+ evidenceRefs: cleanList(input.evidenceRefs, 500).slice(0, MAX_EVIDENCE_REFS),
159357
+ ...input.actor ? { actor: clean(input.actor, 200) } : {},
159358
+ at: input.at ?? (/* @__PURE__ */ new Date()).toISOString(),
159359
+ ...eventKey ? { eventKey } : {},
159360
+ ...input.itemKey ? { itemKey: clean(input.itemKey, 120) } : {},
159361
+ ...input.supersedesId ? { supersedesId: clean(input.supersedesId, 120) } : {}
159362
+ };
159363
+ db2.prepare(`
159364
+ INSERT INTO task_continuity_events (
159365
+ id, project_id, task_id, task, kind, content, item_status,
159366
+ source_ref, evidence_json, actor, created_at, event_key, item_key, supersedes_id
159367
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
159368
+ `).run(
159369
+ event.id,
159370
+ event.projectId,
159371
+ event.taskId,
159372
+ event.task,
159373
+ event.kind,
159374
+ event.content,
159375
+ event.status ?? null,
159376
+ event.sourceRef ?? null,
159377
+ JSON.stringify(event.evidenceRefs),
159378
+ event.actor ?? null,
159379
+ event.at,
159380
+ event.eventKey ?? null,
159381
+ event.itemKey ?? null,
159382
+ event.supersedesId ?? null
159383
+ );
159384
+ return event;
159385
+ }
159386
+ start(input) {
159387
+ const task = clean(input.task, MAX_TASK_LENGTH);
159388
+ if (!task) throw new Error("A non-empty task is required.");
159389
+ const idempotencyKey = input.idempotencyKey ? clean(input.idempotencyKey, 200) : void 0;
159390
+ const taskId = clean(input.taskId ?? idempotencyKey ?? "", 120) || randomUUID17();
159391
+ const requirements = cleanList(input.requirements);
159392
+ const transaction = this.requireDb().transaction(() => {
159393
+ this.insert({
159394
+ projectId: input.projectId,
159395
+ taskId,
159396
+ task,
159397
+ kind: "task",
159398
+ content: task,
159399
+ status: "open",
159400
+ actor: input.actor,
159401
+ ...idempotencyKey ? { eventKey: `start:${idempotencyKey}` } : {}
159402
+ });
159403
+ for (const requirement of requirements) {
159404
+ this.insert({
159405
+ projectId: input.projectId,
159406
+ taskId,
159407
+ task,
159408
+ kind: "requirement",
159409
+ content: requirement,
159410
+ actor: input.actor
159411
+ });
159412
+ }
159413
+ });
159414
+ transaction.immediate();
159415
+ return { taskId, ledger: this.get(input.projectId, taskId) };
159416
+ }
159417
+ record(input) {
159418
+ const projectId = clean(input.projectId, 500);
159419
+ const taskId = clean(input.taskId, 120);
159420
+ const existing = this.get(projectId, taskId);
159421
+ if (!existing) throw new Error("Task continuity ledger not found: " + taskId);
159422
+ const transaction = this.requireDb().transaction(() => this.insert({
159423
+ projectId,
159424
+ taskId,
159425
+ task: existing.task,
159426
+ kind: input.kind,
159427
+ content: input.content,
159428
+ ...input.kind === "verification" && input.verificationStatus ? { status: input.verificationStatus } : {},
159429
+ sourceRef: input.sourceRef,
159430
+ evidenceRefs: input.evidenceRefs,
159431
+ actor: input.actor,
159432
+ at: input.at,
159433
+ ...input.idempotencyKey ? { eventKey: input.idempotencyKey } : {},
159434
+ ...input.verificationId ? { itemKey: input.verificationId } : {}
159435
+ }));
159436
+ const event = transaction.immediate();
159437
+ return { event, ledger: this.get(projectId, taskId) };
159438
+ }
159439
+ close(input) {
159440
+ const projectId = clean(input.projectId, 500);
159441
+ const taskId = clean(input.taskId, 120);
159442
+ const existing = this.get(projectId, taskId);
159443
+ if (!existing) throw new Error("Task continuity ledger not found: " + taskId);
159444
+ const transaction = this.requireDb().transaction(() => this.insert({
159445
+ projectId,
159446
+ taskId,
159447
+ task: existing.task,
159448
+ kind: "outcome",
159449
+ content: input.content,
159450
+ status: input.status,
159451
+ sourceRef: input.sourceRef,
159452
+ evidenceRefs: input.evidenceRefs,
159453
+ actor: input.actor,
159454
+ at: input.at,
159455
+ ...input.idempotencyKey ? { eventKey: input.idempotencyKey } : {}
159456
+ }));
159457
+ const event = transaction.immediate();
159458
+ return { event, ledger: this.get(projectId, taskId) };
159459
+ }
159460
+ get(projectId, taskId) {
159461
+ const normalizedProjectId = clean(projectId, 500);
159462
+ const normalizedTaskId = clean(taskId, 120);
159463
+ const rows = this.requireDb().prepare(`
159464
+ SELECT * FROM task_continuity_events
159465
+ WHERE project_id = ? AND task_id = ?
159466
+ ORDER BY created_at ASC, rowid ASC
159467
+ `).all(normalizedProjectId, normalizedTaskId);
159468
+ if (rows.length === 0) return void 0;
159469
+ return aggregate(rows.map(rowToEvent4));
159470
+ }
159471
+ list(projectId, limit2 = 20) {
159472
+ const rows = this.requireDb().prepare(`
159473
+ SELECT task_id
159474
+ FROM task_continuity_events
159475
+ WHERE project_id = ?
159476
+ GROUP BY task_id
159477
+ ORDER BY MAX(created_at) DESC
159478
+ LIMIT ?
159479
+ `).all(projectId, Math.min(100, Math.max(1, Math.floor(limit2))));
159480
+ return rows.map((row) => this.get(projectId, String(row.task_id))).filter((ledger) => Boolean(ledger));
159481
+ }
159482
+ };
159483
+ }
159484
+ });
159485
+
158933
159486
  // src/codegraph/auto-context.ts
158934
159487
  var auto_context_exports = {};
158935
159488
  __export(auto_context_exports, {
@@ -159186,6 +159739,16 @@ async function buildAutoProjectContext(input) {
159186
159739
  };
159187
159740
  }
159188
159741
  }
159742
+ let continuity = input.continuity;
159743
+ if (!continuity && input.taskId) {
159744
+ try {
159745
+ const { TaskContinuityStore: TaskContinuityStore2 } = await Promise.resolve().then(() => (init_task_continuity(), task_continuity_exports));
159746
+ const continuityStore = new TaskContinuityStore2();
159747
+ await continuityStore.init(input.dataDir);
159748
+ continuity = continuityStore.get(input.project.id, input.taskId);
159749
+ } catch {
159750
+ }
159751
+ }
159189
159752
  const alwaysOn = await buildAlwaysOnBlock({
159190
159753
  dataDir: input.dataDir,
159191
159754
  projectId: input.project.id,
@@ -159204,6 +159767,7 @@ async function buildAutoProjectContext(input) {
159204
159767
  providerQuality: providerQuality2,
159205
159768
  currentFacts: worksetFactLines(currentFacts),
159206
159769
  ...continuation ? { continuation } : {},
159770
+ ...continuity ? { continuity } : {},
159207
159771
  codeState: codeStateLine(overview),
159208
159772
  ...codeEvolution ? { codeEvolution } : {},
159209
159773
  reliableMemory: sourceSets.reliableSources.slice(0, lens.sourceLimit).map((source) => ({
@@ -159251,6 +159815,7 @@ async function buildAutoProjectContext(input) {
159251
159815
  refresh,
159252
159816
  providerQuality: providerQuality2,
159253
159817
  ...continuationRequested && workset.continuation ? { continuation: workset.continuation } : {},
159818
+ ...workset.continuity ? { continuity: workset.continuity } : {},
159254
159819
  workset
159255
159820
  };
159256
159821
  }
@@ -159552,7 +160117,14 @@ function buildBoundedContextReceipt(input) {
159552
160117
  externalState: provider2?.external.state ?? "not-detected",
159553
160118
  ...input.workset.provenance.snapshotId ? { snapshotId: input.workset.provenance.snapshotId } : {}
159554
160119
  },
159555
- ...input.workset.agentLoadout ? { loadout: input.workset.agentLoadout } : {}
160120
+ ...input.workset.agentLoadout ? { loadout: input.workset.agentLoadout } : {},
160121
+ ...input.workset.continuity ? {
160122
+ continuity: {
160123
+ taskId: input.workset.continuity.taskId,
160124
+ status: input.workset.continuity.status,
160125
+ outcome: input.workset.continuity.outcome
160126
+ }
160127
+ } : {}
159556
160128
  };
159557
160129
  }
159558
160130
  var init_context_receipt = __esm({
@@ -160184,15 +160756,21 @@ var team_store_exports = {};
160184
160756
  __export(team_store_exports, {
160185
160757
  AGENT_TYPE_ROLE_MAP: () => AGENT_TYPE_ROLE_MAP,
160186
160758
  DEFAULT_ROLES: () => DEFAULT_ROLES,
160759
+ DEFAULT_TEAM_QUERY_LIMIT: () => DEFAULT_TEAM_QUERY_LIMIT,
160760
+ MAX_TEAM_QUERY_LIMIT: () => MAX_TEAM_QUERY_LIMIT,
160187
160761
  TeamStore: () => TeamStore,
160188
160762
  getTeamStore: () => getTeamStore,
160189
160763
  initTeamStore: () => initTeamStore,
160190
160764
  isTeamStoreInitialized: () => isTeamStoreInitialized,
160191
160765
  resetTeamStore: () => resetTeamStore
160192
160766
  });
160193
- import { randomUUID as randomUUID17 } from "crypto";
160767
+ import { randomUUID as randomUUID18 } from "crypto";
160194
160768
  import path31 from "path";
160195
160769
  import fs18 from "fs";
160770
+ function clampTeamQueryLimit(limit2) {
160771
+ if (!Number.isFinite(limit2) || limit2 == null) return DEFAULT_TEAM_QUERY_LIMIT;
160772
+ return Math.min(MAX_TEAM_QUERY_LIMIT, Math.max(1, Math.floor(limit2)));
160773
+ }
160196
160774
  function getTeamStore() {
160197
160775
  if (!_teamStore) {
160198
160776
  throw new Error("[memorix] TeamStore not initialized \u2014 call initTeamStore() first");
@@ -160216,12 +160794,14 @@ function resetTeamStore() {
160216
160794
  _teamStore = null;
160217
160795
  _teamStoreDataDir = null;
160218
160796
  }
160219
- var DEFAULT_ROLES, AGENT_TYPE_ROLE_MAP, TeamStore, _teamStore, _teamStoreDataDir;
160797
+ var DEFAULT_TEAM_QUERY_LIMIT, MAX_TEAM_QUERY_LIMIT, DEFAULT_ROLES, AGENT_TYPE_ROLE_MAP, TeamStore, _teamStore, _teamStoreDataDir;
160220
160798
  var init_team_store = __esm({
160221
160799
  "src/team/team-store.ts"() {
160222
160800
  "use strict";
160223
160801
  init_esm_shims();
160224
160802
  init_sqlite_db();
160803
+ DEFAULT_TEAM_QUERY_LIMIT = 100;
160804
+ MAX_TEAM_QUERY_LIMIT = 500;
160225
160805
  DEFAULT_ROLES = [
160226
160806
  { roleId: "planner", label: "Planner", description: "Breaks down requirements, creates tasks, defines dependencies", preferredAgentTypes: ["claude-code", "cursor", "codex"], maxConcurrent: 2 },
160227
160807
  { roleId: "researcher", label: "Researcher", description: "Investigates codebase, gathers context, answers questions", preferredAgentTypes: ["claude-code", "cursor", "gemini-cli"], maxConcurrent: 2 },
@@ -160479,7 +161059,7 @@ var init_team_store = __esm({
160479
161059
  * reactivate it (preserving agent_id). Otherwise create a new one.
160480
161060
  */
160481
161061
  registerAgent(input) {
160482
- const instanceId = input.instanceId || randomUUID17();
161062
+ const instanceId = input.instanceId || randomUUID18();
160483
161063
  const now3 = Date.now();
160484
161064
  const existing = this.stmtAgentFindByInstance.get(
160485
161065
  input.projectId,
@@ -160505,7 +161085,7 @@ var init_team_store = __esm({
160505
161085
  this.eventBus?.emit("agent:joined", { agentId: row2.agent_id, projectId: input.projectId, agentType: input.agentType });
160506
161086
  return row2;
160507
161087
  }
160508
- const agentId = randomUUID17();
161088
+ const agentId = randomUUID18();
160509
161089
  this.stmtAgentUpsert.run({
160510
161090
  agent_id: agentId,
160511
161091
  project_id: input.projectId,
@@ -160531,32 +161111,37 @@ var init_team_store = __esm({
160531
161111
  return this.stmtAgentFindByInstance.get(projectId, agentType, instanceId);
160532
161112
  }
160533
161113
  listAgents(projectId, filter) {
160534
- const all = this.stmtAgentListByProject.all(projectId);
161114
+ const limit2 = clampTeamQueryLimit(filter?.limit);
160535
161115
  if (filter?.status) {
160536
- return all.filter((a) => a.status === filter.status);
161116
+ return this.db.prepare(
161117
+ `SELECT * FROM team_agents WHERE project_id = ? AND status = ? ORDER BY joined_at DESC LIMIT ?`
161118
+ ).all(projectId, filter.status, limit2);
160537
161119
  }
160538
- return all;
161120
+ return this.db.prepare(
161121
+ `SELECT * FROM team_agents WHERE project_id = ? ORDER BY joined_at DESC LIMIT ?`
161122
+ ).all(projectId, limit2);
160539
161123
  }
160540
161124
  /** List agents across all projects (for global scope) */
160541
- listAllAgents() {
161125
+ listAllAgents(limit2) {
160542
161126
  if (!this.db) return [];
160543
- return this.db.prepare("SELECT * FROM team_agents ORDER BY last_heartbeat DESC").all();
161127
+ return this.db.prepare("SELECT * FROM team_agents ORDER BY last_heartbeat DESC LIMIT ?").all(clampTeamQueryLimit(limit2));
160544
161128
  }
160545
161129
  /** List locks across all projects (for global scope) */
160546
- listAllLocks() {
161130
+ listAllLocks(limit2) {
160547
161131
  if (!this.db) return [];
160548
161132
  this.db.prepare("DELETE FROM team_locks WHERE expires_at <= ?").run(Date.now());
160549
- return this.db.prepare("SELECT * FROM team_locks WHERE expires_at > ? ORDER BY locked_at DESC").all(Date.now());
161133
+ return this.db.prepare("SELECT * FROM team_locks WHERE expires_at > ? ORDER BY locked_at DESC LIMIT ?").all(Date.now(), clampTeamQueryLimit(limit2));
160550
161134
  }
160551
161135
  /** List tasks across all projects (for global scope) */
160552
161136
  listAllTasks(filter) {
160553
161137
  if (!this.db) return [];
161138
+ const limit2 = clampTeamQueryLimit(filter?.limit);
160554
161139
  if (filter?.available) {
160555
161140
  return this.db.prepare(
160556
- `SELECT t.* FROM team_tasks t WHERE t.status = 'pending' AND t.assignee_agent_id IS NULL ORDER BY t.created_at DESC`
160557
- ).all();
161141
+ `SELECT t.* FROM team_tasks t WHERE t.status = 'pending' AND t.assignee_agent_id IS NULL ORDER BY t.created_at DESC LIMIT ?`
161142
+ ).all(limit2);
160558
161143
  }
160559
- return this.db.prepare("SELECT * FROM team_tasks ORDER BY created_at DESC").all();
161144
+ return this.db.prepare("SELECT * FROM team_tasks ORDER BY created_at DESC LIMIT ?").all(limit2);
160560
161145
  }
160561
161146
  heartbeat(agentId) {
160562
161147
  const info = this.stmtAgentUpdateHeartbeat.run(Date.now(), agentId);
@@ -160591,7 +161176,10 @@ var init_team_store = __esm({
160591
161176
  return staleIds;
160592
161177
  }
160593
161178
  getActiveCount(projectId) {
160594
- return this.listAgents(projectId, { status: "active" }).length;
161179
+ const row = this.db.prepare(
161180
+ `SELECT COUNT(*) AS count FROM team_agents WHERE project_id = ? AND status = 'active'`
161181
+ ).get(projectId);
161182
+ return Number(row?.count ?? 0);
160595
161183
  }
160596
161184
  // ═══════════════════════════════════════════════════════════════════
160597
161185
  // Message Operations
@@ -160607,7 +161195,7 @@ var init_team_store = __esm({
160607
161195
  return { error: `Recipient agent '${input.recipientAgentId}' not found \u2014 cannot send to unknown agent` };
160608
161196
  }
160609
161197
  }
160610
- const id = randomUUID17();
161198
+ const id = randomUUID18();
160611
161199
  const now3 = Date.now();
160612
161200
  const row = {
160613
161201
  id,
@@ -160626,8 +161214,14 @@ var init_team_store = __esm({
160626
161214
  this.stmtMsgInsert.run(row);
160627
161215
  return row;
160628
161216
  }
160629
- getInbox(projectId, agentId) {
160630
- return this.stmtMsgInbox.all(projectId, agentId);
161217
+ getInbox(projectId, agentId, limit2) {
161218
+ return this.db.prepare(`
161219
+ SELECT * FROM team_messages
161220
+ WHERE project_id = ?
161221
+ AND (recipient_agent_id = ? OR recipient_agent_id IS NULL)
161222
+ ORDER BY created_at ASC
161223
+ LIMIT ?
161224
+ `).all(projectId, agentId, clampTeamQueryLimit(limit2));
160631
161225
  }
160632
161226
  getUnreadCount(projectId, agentId) {
160633
161227
  const row = this.stmtMsgUnreadCount.get(projectId, agentId);
@@ -160657,7 +161251,7 @@ var init_team_store = __esm({
160657
161251
  // Task Operations (with atomic claim semantics)
160658
161252
  // ═══════════════════════════════════════════════════════════════════
160659
161253
  createTask(input) {
160660
- const taskId = randomUUID17();
161254
+ const taskId = randomUUID18();
160661
161255
  const now3 = Date.now();
160662
161256
  const row = {
160663
161257
  task_id: taskId,
@@ -160784,17 +161378,22 @@ var init_team_store = __esm({
160784
161378
  return info.changes;
160785
161379
  }
160786
161380
  listTasks(projectId, filter) {
160787
- if (filter?.available) {
160788
- return this.stmtTaskAvailable.all(projectId);
160789
- }
160790
- const all = this.stmtTaskListByProject.all(projectId);
161381
+ const clauses = ["project_id = ?"];
161382
+ const values = [projectId];
161383
+ if (filter?.available) clauses.push("status = 'pending'", "assignee_agent_id IS NULL");
160791
161384
  if (filter?.status) {
160792
- return all.filter((t2) => t2.status === filter.status);
161385
+ clauses.push("status = ?");
161386
+ values.push(filter.status);
160793
161387
  }
160794
161388
  if (filter?.assignee) {
160795
- return all.filter((t2) => t2.assignee_agent_id === filter.assignee);
161389
+ clauses.push("assignee_agent_id = ?");
161390
+ values.push(filter.assignee);
160796
161391
  }
160797
- return all;
161392
+ values.push(clampTeamQueryLimit(filter?.limit));
161393
+ const orderBy = filter?.available ? "created_at ASC, rowid ASC" : "created_at DESC, rowid DESC";
161394
+ return this.db.prepare(
161395
+ `SELECT * FROM team_tasks WHERE ${clauses.join(" AND ")} ORDER BY ${orderBy} LIMIT ?`
161396
+ ).all(...values);
160798
161397
  }
160799
161398
  /**
160800
161399
  * List available tasks for a specific agent, sorted by role affinity.
@@ -160806,7 +161405,7 @@ var init_team_store = __esm({
160806
161405
  const agent = this.stmtAgentFindById.get(agentId);
160807
161406
  if (!agent) return [];
160808
161407
  const agentRole = agent.role;
160809
- const available = this.stmtTaskAvailable.all(projectId);
161408
+ const available = this.listTasks(projectId, { available: true, limit: MAX_TEAM_QUERY_LIMIT });
160810
161409
  const eligible = available.filter((t2) => !t2.required_role || t2.required_role === agentRole);
160811
161410
  const score = (t2) => {
160812
161411
  if (t2.preferred_role === agentRole) return 0;
@@ -160860,12 +161459,16 @@ var init_team_store = __esm({
160860
161459
  const row = this.stmtLockGet.get(file, projectId);
160861
161460
  return row ?? null;
160862
161461
  }
160863
- listLocks(projectId, agentId) {
161462
+ listLocks(projectId, agentId, limit2) {
160864
161463
  this.stmtLockDeleteExpired.run(projectId, Date.now());
160865
161464
  if (agentId) {
160866
- return this.stmtLockListByAgent.all(projectId, agentId);
161465
+ return this.db.prepare(
161466
+ `SELECT * FROM team_locks WHERE project_id = ? AND locked_by = ? ORDER BY locked_at DESC LIMIT ?`
161467
+ ).all(projectId, agentId, clampTeamQueryLimit(limit2));
160867
161468
  }
160868
- return this.stmtLockListByProject.all(projectId);
161469
+ return this.db.prepare(
161470
+ `SELECT * FROM team_locks WHERE project_id = ? ORDER BY locked_at DESC LIMIT ?`
161471
+ ).all(projectId, clampTeamQueryLimit(limit2));
160869
161472
  }
160870
161473
  releaseAllLocks(agentId) {
160871
161474
  const info = this.stmtLockDeleteByAgent.run(agentId);
@@ -160929,7 +161532,7 @@ var init_team_store = __esm({
160929
161532
  for (const [agentId, msgs] of Object.entries(snap.messages.inboxes)) {
160930
161533
  for (const msg of msgs) {
160931
161534
  this.stmtMsgInsert.run({
160932
- id: msg.id ?? randomUUID17(),
161535
+ id: msg.id ?? randomUUID18(),
160933
161536
  project_id: "migrated",
160934
161537
  sender_agent_id: msg.from ?? "unknown",
160935
161538
  recipient_agent_id: msg.to === "__broadcast__" ? null : msg.to ?? agentId,
@@ -163887,7 +164490,7 @@ __export(planner_exports, {
163887
164490
  materializeTaskGraph: () => materializeTaskGraph,
163888
164491
  seedAutonomousPipeline: () => seedAutonomousPipeline
163889
164492
  });
163890
- import { randomUUID as randomUUID18 } from "crypto";
164493
+ import { randomUUID as randomUUID19 } from "crypto";
163891
164494
  function isPlannerTask(metadata) {
163892
164495
  if (!metadata) return null;
163893
164496
  try {
@@ -163945,7 +164548,7 @@ function seedAutonomousPipeline(teamStore, projectId, config, opts) {
163945
164548
  const maxIterations = config.maxIterations ?? 3;
163946
164549
  const taskBudget = config.taskBudget ?? 15;
163947
164550
  const structuredPlan = opts?.structuredPlan ?? true;
163948
- const pipelineId = randomUUID18();
164551
+ const pipelineId = randomUUID19();
163949
164552
  const meta = {
163950
164553
  plannerType: "plan",
163951
164554
  pipelineId,
@@ -164626,6 +165229,7 @@ var init_official_skills = __esm({
164626
165229
  "| Need the sequence around one memory | `memorix_timeline` | `memorix memory timeline --id <id>` |",
164627
165230
  "| Check source and freshness for a memory | `memorix_evidence` | `memorix evidence list|get|events` |",
164628
165231
  "| Record whether a memory helped, conflicted, or was corrected | `memorix_feedback` | `memorix feedback record|show|audit` |",
165232
+ "| Track task requirements, decisions, verification, and outcome | `memorix_continuity` | `memorix continuity start|record|show|close` |",
164629
165233
  "| Inspect or import controlled media | `memorix_media` | `memorix media import|attach|list|show|status` |",
164630
165234
  '| Learned reusable project knowledge | `memorix_store` | `memorix memory store --type <type> --entity <name> --title "<title>" "<text>"` |',
164631
165235
  "| Task or bug is complete/outdated | `memorix_resolve` | `memorix memory resolve --ids <ids>` |",
@@ -164649,6 +165253,7 @@ var init_official_skills = __esm({
164649
165253
  "3. Use stale or unbound memory only as a warning or search lead.",
164650
165254
  "4. Store durable decisions, fixes, and gotchas after the project state changes.",
164651
165255
  "5. Resolve completed or obsolete memories so future briefs stay small.",
165256
+ "6. For multi-step work, start a continuity ledger and pass its taskId back to memorix_project_context.",
164652
165257
  "",
164653
165258
  "## Store Rules",
164654
165259
  "",
@@ -166376,7 +166981,7 @@ init_freshness();
166376
166981
  init_obs_store();
166377
166982
  init_mini_skill_store();
166378
166983
  init_session_store();
166379
- import { createHash as createHash18 } from "crypto";
166984
+ import { createHash as createHash19 } from "crypto";
166380
166985
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
166381
166986
  import { z as z627 } from "zod";
166382
166987
 
@@ -167768,9 +168373,9 @@ init_frontmatter();
167768
168373
 
167769
168374
  // src/rules/utils.ts
167770
168375
  init_esm_shims();
167771
- import { createHash as createHash16 } from "crypto";
168376
+ import { createHash as createHash17 } from "crypto";
167772
168377
  function hashContent2(content) {
167773
- return createHash16("sha256").update(content.trim()).digest("hex").substring(0, 16);
168378
+ return createHash17("sha256").update(content.trim()).digest("hex").substring(0, 16);
167774
168379
  }
167775
168380
  function generateRuleId(source, filePath) {
167776
168381
  const sanitized = filePath.replace(/[\/\\]/g, "-").replace(/^\./, "");
@@ -169976,6 +170581,7 @@ var TOOL_PROFILES = Object.freeze({
169976
170581
  // keep the default micro profile at its nine-tool token budget.
169977
170582
  memorix_evidence: ["lite", "team", "full"],
169978
170583
  memorix_feedback: ["lite", "team", "full"],
170584
+ memorix_continuity: ["lite", "team", "full"],
169979
170585
  // ── lite: extended solo memory surface ────────────────────────────
169980
170586
  memorix_graph_context: ["lite", "team", "full"],
169981
170587
  memorix_timeline: ["lite", "team", "full"],
@@ -170198,7 +170804,7 @@ var MCP_SERVER_INFO_META_KEY = "io.modelcontextprotocol/serverInfo";
170198
170804
  function getMcpServerInfo() {
170199
170805
  return {
170200
170806
  name: "memorix",
170201
- version: true ? "1.9.5" : "1.0.1"
170807
+ version: true ? "1.9.6" : "1.0.1"
170202
170808
  };
170203
170809
  }
170204
170810
  function createMcpDiscoverResult(capabilities, serverInfo) {
@@ -170333,7 +170939,7 @@ function coerceObjectArray(val) {
170333
170939
  return [];
170334
170940
  }
170335
170941
  function createDeterministicInstanceId(projectId, agentType, agentName) {
170336
- const digest2 = createHash18("sha256").update(projectId).update("\n").update(agentType).update("\n").update(agentName ?? "").digest("hex").slice(0, 24);
170942
+ const digest2 = createHash19("sha256").update(projectId).update("\n").update(agentType).update("\n").update(agentName ?? "").digest("hex").slice(0, 24);
170337
170943
  return `auto-${digest2}`;
170338
170944
  }
170339
170945
  var BOOTSTRAP_SAFE_TOOL_NAMES = /* @__PURE__ */ new Set([
@@ -170549,6 +171155,22 @@ async function createMemorixServer(cwd, existingServer, sharedTeam, options = {}
170549
171155
  }
170550
171156
  await projectRuntimeInitPromise;
170551
171157
  };
171158
+ const activateProjectRuntime = async () => {
171159
+ if (!projectResolved) return;
171160
+ await initObservationStore(projectDir2);
171161
+ await initMiniSkillStore(projectDir2);
171162
+ await initSessionStore(projectDir2);
171163
+ await initObservations(projectDir2, { skipCorpusLoad: true });
171164
+ try {
171165
+ const { initProjectRoot: initProjectRoot2 } = await Promise.resolve().then(() => (init_yaml_loader(), yaml_loader_exports));
171166
+ const { resetDotenv: resetDotenv2, loadDotenv: loadDotenv2 } = await Promise.resolve().then(() => (init_dotenv_loader(), dotenv_loader_exports));
171167
+ initProjectRoot2(project.rootPath);
171168
+ resetDotenv2();
171169
+ loadDotenv2(project.rootPath);
171170
+ } catch {
171171
+ }
171172
+ initLLM({ projectRoot: project.rootPath });
171173
+ };
170552
171174
  let maintenanceWorker = null;
170553
171175
  const startProjectMaintenanceWorker = async (autoCleanup = false) => {
170554
171176
  maintenanceWorker?.stop();
@@ -171464,6 +172086,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
171464
172086
  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.",
171465
172087
  inputSchema: {
171466
172088
  task: z627.string().optional().describe("Current coding task or question"),
172089
+ taskId: z627.string().max(120).optional().describe("Optional task continuity ledger id to include in the brief"),
171467
172090
  refresh: z627.enum(["auto", "always", "never"]).optional().default("auto").describe(
171468
172091
  "Code Memory refresh policy. auto refreshes only when missing or stale."
171469
172092
  ),
@@ -171488,7 +172111,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
171488
172111
  limit: z627.number().optional().describe("Reserved for future source limits; current prompt stays compact by default.")
171489
172112
  }
171490
172113
  },
171491
- async ({ task, refresh, format, agent }) => {
172114
+ async ({ task, taskId, refresh, format, agent }) => {
171492
172115
  const unresolved = requireResolvedProject("build project context for the current project");
171493
172116
  if (unresolved) return unresolved;
171494
172117
  const [
@@ -171518,6 +172141,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
171518
172141
  dataDir: projectDir2,
171519
172142
  observations: observations2,
171520
172143
  task,
172144
+ taskId,
171521
172145
  agent,
171522
172146
  refresh: refresh ?? "auto",
171523
172147
  reader: getObservationReader(),
@@ -173943,6 +174567,94 @@ ${json2}
173943
174567
  }
173944
174568
  }
173945
174569
  );
174570
+ server.registerTool(
174571
+ "memorix_continuity",
174572
+ {
174573
+ title: "Task Continuity Ledger",
174574
+ 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.",
174575
+ inputSchema: {
174576
+ action: z627.enum(["start", "record", "show", "list", "close"]).describe("Continuity operation"),
174577
+ taskId: z627.string().max(120).optional().describe("Continuity task id"),
174578
+ task: z627.string().max(1e3).optional().describe("Task description for start"),
174579
+ requirements: z627.array(z627.string().max(2e3)).max(8).optional().describe("Requirements for start"),
174580
+ kind: z627.enum(["requirement", "decision", "verification", "risk"]).optional().describe("Entry kind for record"),
174581
+ content: z627.string().max(2e3).optional().describe("Requirement, decision, verification, risk, or outcome text"),
174582
+ verificationStatus: z627.enum(["pending", "passed", "failed", "skipped"]).optional(),
174583
+ verificationId: z627.string().max(120).optional().describe("Stable verification obligation id; reuse it to move pending to passed/failed"),
174584
+ idempotencyKey: z627.string().max(200).optional().describe("Stable retry key; repeating the same operation returns the original event"),
174585
+ status: z627.enum(["completed", "blocked", "abandoned"]).optional().describe("Outcome status for close"),
174586
+ sourceRef: z627.string().max(500).optional().describe("Evidence or source reference"),
174587
+ evidenceRefs: z627.array(z627.string().max(500)).max(8).optional(),
174588
+ actor: z627.string().max(200).optional(),
174589
+ limit: z627.number().int().positive().max(100).optional().default(20)
174590
+ }
174591
+ },
174592
+ async ({ action, taskId, task, requirements, kind, content, verificationStatus, verificationId, idempotencyKey, status, sourceRef, evidenceRefs: evidenceRefs2, actor, limit: limit2 }) => {
174593
+ const unresolved = requireResolvedProject("manage task continuity for the current project");
174594
+ if (unresolved) return unresolved;
174595
+ const { TaskContinuityStore: TaskContinuityStore2 } = await Promise.resolve().then(() => (init_task_continuity(), task_continuity_exports));
174596
+ const continuity = new TaskContinuityStore2();
174597
+ await continuity.init(projectDir2);
174598
+ const effectiveActor = actor ?? currentAgentId;
174599
+ try {
174600
+ if (action === "start") {
174601
+ if (!task?.trim()) return { content: [{ type: "text", text: "task is required for continuity start." }], isError: true };
174602
+ const result2 = continuity.start({
174603
+ projectId: project.id,
174604
+ task,
174605
+ ...taskId ? { taskId } : {},
174606
+ requirements,
174607
+ ...effectiveActor ? { actor: effectiveActor } : {},
174608
+ ...idempotencyKey ? { idempotencyKey } : {}
174609
+ });
174610
+ return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, ...result2 }, null, 2) }] };
174611
+ }
174612
+ if (action === "list") {
174613
+ return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, ledgers: continuity.list(project.id, limit2) }, null, 2) }] };
174614
+ }
174615
+ if (!taskId?.trim()) return { content: [{ type: "text", text: "taskId is required for this continuity action." }], isError: true };
174616
+ if (action === "show") {
174617
+ const ledger = continuity.get(project.id, taskId);
174618
+ if (!ledger) return { content: [{ type: "text", text: "Task continuity ledger not found." }], isError: true };
174619
+ return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, ledger }, null, 2) }] };
174620
+ }
174621
+ if (action === "record") {
174622
+ if (!kind || !content?.trim()) {
174623
+ return { content: [{ type: "text", text: "record requires kind and content." }], isError: true };
174624
+ }
174625
+ const result2 = continuity.record({
174626
+ projectId: project.id,
174627
+ taskId,
174628
+ kind,
174629
+ content,
174630
+ ...verificationStatus ? { verificationStatus } : {},
174631
+ ...sourceRef ? { sourceRef } : {},
174632
+ ...evidenceRefs2 ? { evidenceRefs: evidenceRefs2 } : {},
174633
+ ...effectiveActor ? { actor: effectiveActor } : {},
174634
+ ...verificationId ? { verificationId } : {},
174635
+ ...idempotencyKey ? { idempotencyKey } : {}
174636
+ });
174637
+ return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, ...result2 }, null, 2) }] };
174638
+ }
174639
+ if (!status || !content?.trim()) {
174640
+ return { content: [{ type: "text", text: "close requires status and content." }], isError: true };
174641
+ }
174642
+ const result = continuity.close({
174643
+ projectId: project.id,
174644
+ taskId,
174645
+ status,
174646
+ content,
174647
+ ...sourceRef ? { sourceRef } : {},
174648
+ ...evidenceRefs2 ? { evidenceRefs: evidenceRefs2 } : {},
174649
+ ...effectiveActor ? { actor: effectiveActor } : {},
174650
+ ...idempotencyKey ? { idempotencyKey } : {}
174651
+ });
174652
+ return { content: [{ type: "text", text: JSON.stringify({ projectId: project.id, ...result }, null, 2) }] };
174653
+ } catch (error) {
174654
+ return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true };
174655
+ }
174656
+ }
174657
+ );
173946
174658
  if (teamFeaturesEnabled) {
173947
174659
  const { initTeamStore: initTeamStore2 } = await Promise.resolve().then(() => (init_team_store(), team_store_exports));
173948
174660
  initTeamStoreForProject = initTeamStore2;
@@ -174970,7 +175682,9 @@ fi
174970
175682
  graphManager,
174971
175683
  projectId: project.id,
174972
175684
  deferredInit,
175685
+ activateProjectRuntime,
174973
175686
  switchProject,
175687
+ getProjectDataDir: () => projectDir2,
174974
175688
  isExplicitlyBound: () => projectBinding.isExplicit(),
174975
175689
  getRequestContext,
174976
175690
  handleTransportClose