monomind 2.0.3 → 2.1.3

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 (113) hide show
  1. package/README.md +74 -92
  2. package/package.json +11 -7
  3. package/packages/@monomind/cli/.claude/helpers/control-start.cjs +13 -20
  4. package/packages/@monomind/cli/.claude/helpers/event-logger.cjs +109 -6
  5. package/packages/@monomind/cli/.claude/helpers/graphify-freshen.cjs +19 -17
  6. package/packages/@monomind/cli/.claude/helpers/handlers/agent-start-handler.cjs +60 -28
  7. package/packages/@monomind/cli/.claude/helpers/handlers/capture-handler.cjs +99 -28
  8. package/packages/@monomind/cli/.claude/helpers/handlers/edit-handler.cjs +27 -9
  9. package/packages/@monomind/cli/.claude/helpers/handlers/gates-handler.cjs +18 -9
  10. package/packages/@monomind/cli/.claude/helpers/handlers/loops-status-handler.cjs +1 -1
  11. package/packages/@monomind/cli/.claude/helpers/handlers/route-handler.cjs +33 -4
  12. package/packages/@monomind/cli/.claude/helpers/handlers/session-handler.cjs +75 -45
  13. package/packages/@monomind/cli/.claude/helpers/handlers/session-restore-handler.cjs +0 -12
  14. package/packages/@monomind/cli/.claude/helpers/handlers/task-handler.cjs +53 -22
  15. package/packages/@monomind/cli/.claude/helpers/hook-handler.cjs +75 -4
  16. package/packages/@monomind/cli/.claude/helpers/intelligence.cjs +94 -15
  17. package/packages/@monomind/cli/.claude/helpers/session.cjs +6 -1
  18. package/packages/@monomind/cli/.claude/helpers/statusline.cjs +10 -10
  19. package/packages/@monomind/cli/.claude/helpers/token-tracker.cjs +3 -3
  20. package/packages/@monomind/cli/.claude/helpers/utils/agent-registrations.cjs +41 -0
  21. package/packages/@monomind/cli/.claude/helpers/utils/fs-helpers.cjs +183 -0
  22. package/packages/@monomind/cli/.claude/helpers/utils/micro-agents.cjs +10 -6
  23. package/packages/@monomind/cli/.claude/helpers/utils/monograph.cjs +73 -2
  24. package/packages/@monomind/cli/.claude/helpers/utils/telemetry.cjs +35 -19
  25. package/packages/@monomind/cli/README.md +74 -92
  26. package/packages/@monomind/cli/bin/cli.js +10 -1
  27. package/packages/@monomind/cli/dist/src/browser/workflow/store.d.ts +2 -2
  28. package/packages/@monomind/cli/dist/src/commands/agent-ops.js +9 -15
  29. package/packages/@monomind/cli/dist/src/commands/browse.d.ts +1 -1
  30. package/packages/@monomind/cli/dist/src/commands/cleanup.js +20 -4
  31. package/packages/@monomind/cli/dist/src/commands/completions.js +66 -261
  32. package/packages/@monomind/cli/dist/src/commands/doctor-env-checks.js +5 -0
  33. package/packages/@monomind/cli/dist/src/commands/doctor.js +7 -2
  34. package/packages/@monomind/cli/dist/src/commands/hooks-workers.js +7 -0
  35. package/packages/@monomind/cli/dist/src/commands/index.js +3 -0
  36. package/packages/@monomind/cli/dist/src/commands/mcp.js +11 -6
  37. package/packages/@monomind/cli/dist/src/commands/memory-admin.js +12 -6
  38. package/packages/@monomind/cli/dist/src/commands/memory-transfer.js +6 -13
  39. package/packages/@monomind/cli/dist/src/commands/monograph.js +3 -3
  40. package/packages/@monomind/cli/dist/src/commands/org.d.ts +3 -1
  41. package/packages/@monomind/cli/dist/src/commands/org.js +321 -127
  42. package/packages/@monomind/cli/dist/src/commands/platforms.d.ts +1 -1
  43. package/packages/@monomind/cli/dist/src/commands/start.js +142 -37
  44. package/packages/@monomind/cli/dist/src/commands/tokens.js +21 -3
  45. package/packages/@monomind/cli/dist/src/config-adapter.js +37 -17
  46. package/packages/@monomind/cli/dist/src/index.js +64 -28
  47. package/packages/@monomind/cli/dist/src/init/claudemd-generator.js +44 -11
  48. package/packages/@monomind/cli/dist/src/init/executor.js +93 -55
  49. package/packages/@monomind/cli/dist/src/mcp-client.d.ts +8 -3
  50. package/packages/@monomind/cli/dist/src/mcp-client.js +37 -3
  51. package/packages/@monomind/cli/dist/src/mcp-server.js +8 -2
  52. package/packages/@monomind/cli/dist/src/mcp-tools/agent-tools.d.ts +20 -0
  53. package/packages/@monomind/cli/dist/src/mcp-tools/agent-tools.js +10 -5
  54. package/packages/@monomind/cli/dist/src/mcp-tools/auto-install.d.ts +8 -8
  55. package/packages/@monomind/cli/dist/src/mcp-tools/coherence/types.d.ts +31 -31
  56. package/packages/@monomind/cli/dist/src/mcp-tools/github-tools.js +30 -8
  57. package/packages/@monomind/cli/dist/src/mcp-tools/graphify-tools.js +11 -2
  58. package/packages/@monomind/cli/dist/src/mcp-tools/hive-mind-tools.js +56 -35
  59. package/packages/@monomind/cli/dist/src/mcp-tools/knowledge-tools.js +9 -1
  60. package/packages/@monomind/cli/dist/src/mcp-tools/monograph-compat.js +56 -14
  61. package/packages/@monomind/cli/dist/src/mcp-tools/monograph-tools.js +88 -41
  62. package/packages/@monomind/cli/dist/src/mcp-tools/quality/coverage-analysis/prioritize-gaps.d.ts +36 -36
  63. package/packages/@monomind/cli/dist/src/mcp-tools/quality/security-compliance/detect-secrets.d.ts +4 -4
  64. package/packages/@monomind/cli/dist/src/mcp-tools/swarm-tools.js +6 -4
  65. package/packages/@monomind/cli/dist/src/mcp-tools/system-tools.js +4 -4
  66. package/packages/@monomind/cli/dist/src/mcp-tools/types.d.ts +20 -0
  67. package/packages/@monomind/cli/dist/src/mcp-tools/types.js +36 -1
  68. package/packages/@monomind/cli/dist/src/memory/ewc-consolidation.d.ts +12 -0
  69. package/packages/@monomind/cli/dist/src/memory/hnsw-operations.d.ts +13 -1
  70. package/packages/@monomind/cli/dist/src/memory/hnsw-operations.js +66 -14
  71. package/packages/@monomind/cli/dist/src/memory/intelligence.js +99 -3
  72. package/packages/@monomind/cli/dist/src/memory/memory-bridge.d.ts +7 -0
  73. package/packages/@monomind/cli/dist/src/memory/memory-bridge.js +20 -0
  74. package/packages/@monomind/cli/dist/src/memory/sona-optimizer.d.ts +12 -0
  75. package/packages/@monomind/cli/dist/src/orgrt/broker.d.ts +26 -0
  76. package/packages/@monomind/cli/dist/src/orgrt/broker.js +73 -0
  77. package/packages/@monomind/cli/dist/src/orgrt/bus.d.ts +5 -1
  78. package/packages/@monomind/cli/dist/src/orgrt/bus.js +5 -1
  79. package/packages/@monomind/cli/dist/src/orgrt/daemon.d.ts +46 -0
  80. package/packages/@monomind/cli/dist/src/orgrt/daemon.js +201 -18
  81. package/packages/@monomind/cli/dist/src/orgrt/forwarder.d.ts +10 -5
  82. package/packages/@monomind/cli/dist/src/orgrt/forwarder.js +138 -8
  83. package/packages/@monomind/cli/dist/src/orgrt/inbox.d.ts +11 -0
  84. package/packages/@monomind/cli/dist/src/orgrt/inbox.js +56 -0
  85. package/packages/@monomind/cli/dist/src/orgrt/policy.d.ts +5 -1
  86. package/packages/@monomind/cli/dist/src/orgrt/policy.js +58 -5
  87. package/packages/@monomind/cli/dist/src/orgrt/provider.js +1 -0
  88. package/packages/@monomind/cli/dist/src/orgrt/scheduler.d.ts +13 -0
  89. package/packages/@monomind/cli/dist/src/orgrt/scheduler.js +48 -0
  90. package/packages/@monomind/cli/dist/src/orgrt/server.d.ts +9 -0
  91. package/packages/@monomind/cli/dist/src/orgrt/server.js +39 -0
  92. package/packages/@monomind/cli/dist/src/orgrt/session.d.ts +10 -1
  93. package/packages/@monomind/cli/dist/src/orgrt/session.js +24 -1
  94. package/packages/@monomind/cli/dist/src/orgrt/test-loop.d.ts +12 -0
  95. package/packages/@monomind/cli/dist/src/orgrt/test-loop.js +108 -0
  96. package/packages/@monomind/cli/dist/src/orgrt/types.d.ts +52 -52
  97. package/packages/@monomind/cli/dist/src/output.d.ts +29 -29
  98. package/packages/@monomind/cli/dist/src/output.js +22 -7
  99. package/packages/@monomind/cli/dist/src/parser.d.ts +32 -0
  100. package/packages/@monomind/cli/dist/src/parser.js +130 -5
  101. package/packages/@monomind/cli/dist/src/routing/embed-worker.js +13 -1
  102. package/packages/@monomind/cli/dist/src/routing/route-layer-factory.js +31 -0
  103. package/packages/@monomind/cli/dist/src/services/config-file-manager.d.ts +21 -0
  104. package/packages/@monomind/cli/dist/src/services/config-file-manager.js +60 -7
  105. package/packages/@monomind/cli/dist/src/services/crash-reporter.js +2 -1
  106. package/packages/@monomind/cli/dist/src/types.d.ts +2 -2
  107. package/packages/@monomind/cli/dist/src/ui/dashboard.html +243 -49
  108. package/packages/@monomind/cli/dist/src/ui/orgs-files.js +192 -0
  109. package/packages/@monomind/cli/dist/src/ui/orgs.html +79 -11
  110. package/packages/@monomind/cli/dist/src/ui/server.mjs +346 -139
  111. package/packages/@monomind/cli/dist/src/utils/input-guards.d.ts +9 -0
  112. package/packages/@monomind/cli/dist/src/utils/input-guards.js +39 -5
  113. package/packages/@monomind/cli/package.json +15 -15
@@ -19,23 +19,36 @@ function _isValidDb(p) {
19
19
  return false;
20
20
  }
21
21
  }
22
- function getDbPath() {
23
- const cwd = getProjectCwd();
22
+ /**
23
+ * Resolve the monograph DB path for a given repo root (defaults to project cwd).
24
+ * Falls back to searching up to the git root when the DB isn't directly under
25
+ * `<cwd>/.monomind` — e.g. when called from a subdirectory of the repo. Only
26
+ * the no-arg (project cwd) form is cached; explicit `repoPath` overrides are
27
+ * cheap one-off lookups (staleness checks with a user-supplied path) so caching
28
+ * them isn't worth the invalidation complexity.
29
+ */
30
+ function getDbPath(repoPathOverride) {
31
+ const cwd = repoPathOverride ?? getProjectCwd();
32
+ const useCache = repoPathOverride === undefined;
24
33
  // Invalidate cache when project root changes (e.g. MONOMIND_CWD set after initialize)
25
- if (_cachedDbPath && _cachedCwd === cwd)
34
+ if (useCache && _cachedDbPath && _cachedCwd === cwd)
26
35
  return _cachedDbPath;
27
- _cachedCwd = cwd;
28
- _cachedDbPath = undefined;
36
+ if (useCache) {
37
+ _cachedCwd = cwd;
38
+ _cachedDbPath = undefined;
39
+ }
29
40
  const direct = join(cwd, '.monomind', 'monograph.db');
30
41
  if (_isValidDb(direct)) {
31
- _cachedDbPath = direct;
42
+ if (useCache)
43
+ _cachedDbPath = direct;
32
44
  return direct;
33
45
  }
34
46
  try {
35
47
  const root = execSync('git rev-parse --show-toplevel', { cwd, encoding: 'utf8' }).trim();
36
48
  const candidate = join(root, '.monomind', 'monograph.db');
37
49
  if (_isValidDb(candidate)) {
38
- _cachedDbPath = candidate;
50
+ if (useCache)
51
+ _cachedDbPath = candidate;
39
52
  return candidate;
40
53
  }
41
54
  }
@@ -46,13 +59,6 @@ function getDbPath() {
46
59
  function text(t) {
47
60
  return { content: [{ type: 'text', text: t }] };
48
61
  }
49
- function ensureDbExists() {
50
- const p = getDbPath();
51
- if (!_isValidDb(p)) {
52
- throw new Error(`Monograph index not built yet. Run monograph_build first (path: ${p}).`);
53
- }
54
- return p;
55
- }
56
62
  // ── Active watcher registry ──────────────────────────────────────────────────
57
63
  const _activeWatchers = new Map();
58
64
  function applyPprRerank(db, seedNodes, damping, maxResults) {
@@ -577,9 +583,13 @@ function taskRelevance(task, nodeText) {
577
583
  return taskTerms.filter(t => txt.includes(t)).length / taskTerms.length;
578
584
  }
579
585
  // ── monograph_visualize ───────────────────────────────────────────────────────
586
+ // Columns needed to render/export the graph — deliberately excludes `embedding`,
587
+ // which can be several KB per node (384D vectors) and would otherwise bloat
588
+ // tool-result payloads and written files by many MB.
589
+ const NODE_RENDER_COLUMNS = 'id, label, name, norm_label, file_path, start_line, end_line, community_id, is_exported, language, properties';
580
590
  const monographVisualizeTool = {
581
591
  name: 'monograph_visualize',
582
- description: 'Render the knowledge graph as HTML (default), SVG, or JSON.',
592
+ description: 'Render the knowledge graph as HTML (default), SVG, or JSON. Writes output to a file under .monomind/visualize/ and returns the file path (output can be multi-MB at the max node count, too large to return inline).',
583
593
  inputSchema: {
584
594
  type: 'object',
585
595
  properties: {
@@ -589,6 +599,7 @@ const monographVisualizeTool = {
589
599
  },
590
600
  handler: async (input) => {
591
601
  const { openDb, closeDb, toJson, toHtml, toSvg } = await import('@monoes/monograph');
602
+ const { writeFileSync, mkdirSync } = await import('fs');
592
603
  const db = openDb(getDbPath());
593
604
  try {
594
605
  // Cap maxNodes: passed to SQL LIMIT clause for both nodes (n) and edges
@@ -598,7 +609,7 @@ const monographVisualizeTool = {
598
609
  const limit = Number.isFinite(rawMaxNodes) && rawMaxNodes > 0
599
610
  ? Math.min(Math.floor(rawMaxNodes), MAX_EXPORT_NODES)
600
611
  : 500;
601
- const nodes = db.prepare('SELECT * FROM nodes LIMIT ?').all(limit);
612
+ const nodes = db.prepare(`SELECT ${NODE_RENDER_COLUMNS} FROM nodes LIMIT ?`).all(limit);
602
613
  // Only include edges where both endpoints are in the visible node set
603
614
  const edges = db.prepare(`
604
615
  SELECT e.* FROM edges e
@@ -607,11 +618,15 @@ const monographVisualizeTool = {
607
618
  LIMIT ?
608
619
  `).all(limit, limit, limit * 3);
609
620
  const fmt = input.format ?? 'html';
610
- if (fmt === 'json')
611
- return text(toJson(nodes, edges));
612
- if (fmt === 'svg')
613
- return text(toSvg(nodes, edges));
614
- return text(toHtml(nodes, edges));
621
+ const rendered = fmt === 'json' ? toJson(nodes, edges)
622
+ : fmt === 'svg' ? toSvg(nodes, edges)
623
+ : toHtml(nodes, edges);
624
+ const ext = fmt === 'json' ? 'json' : fmt === 'svg' ? 'svg' : 'html';
625
+ const outDir = resolve(join(getProjectCwd(), '.monomind', 'visualize'));
626
+ mkdirSync(outDir, { recursive: true });
627
+ const outPath = join(outDir, `graph-${Date.now()}.${ext}`);
628
+ writeFileSync(outPath, rendered);
629
+ return text(`Visualization written to ${outPath} (${nodes.length} nodes, ${edges.length} edges)${ext === 'html' ? '\nNote: HTML uses the vis-network CDN script and requires network access to render.' : ''}`);
615
630
  }
616
631
  finally {
617
632
  closeDb(db);
@@ -700,7 +715,8 @@ const monographReportTool = {
700
715
  return `${i + 1}. **${n.name}** (${n.label}) — degree ${n.degree}${loc ? ` \`${loc}\`` : ''}`;
701
716
  }),
702
717
  ].join('\n');
703
- const outPath = resolve(input.path ?? join(getProjectCwd(), '.monomind', 'GRAPH_REPORT.md'));
718
+ const rawOutPath = input.path ?? join(getProjectCwd(), '.monomind', 'GRAPH_REPORT.md');
719
+ const outPath = resolve(getProjectCwd(), rawOutPath);
704
720
  const allowedRoot = resolve(getProjectCwd());
705
721
  if (outPath !== allowedRoot && !outPath.startsWith(allowedRoot + sep)) {
706
722
  return text(`Error: path must be within the project directory (${allowedRoot})`);
@@ -725,7 +741,13 @@ let _buildInProgress = false;
725
741
  async function computeCommitsBehind(repoPath) {
726
742
  const { openDb, closeDb } = await import('@monoes/monograph');
727
743
  const { execSync } = await import('child_process');
728
- const db = openDb(join(repoPath, '.monomind', 'monograph.db'));
744
+ const dbPath = getDbPath(repoPath);
745
+ if (!_isValidDb(dbPath))
746
+ return null;
747
+ // openDb's fileMustExist option isn't in the currently-published
748
+ // @monoes/monograph release this CLI depends on — _isValidDb above is the
749
+ // real guard against openDb silently creating an empty DB at a missing path.
750
+ const db = openDb(dbPath);
729
751
  try {
730
752
  const meta = db.prepare("SELECT value FROM index_meta WHERE key = 'last_commit_hash'").get() ?? db.prepare("SELECT value FROM index_meta WHERE key = 'lastCommit'").get();
731
753
  const lastCommit = meta?.value ?? null;
@@ -929,11 +951,13 @@ const monographExportTool = {
929
951
  const { writeFileSync, mkdirSync } = await import('fs');
930
952
  const db = openDb(getDbPath());
931
953
  try {
932
- const nodes = db.prepare('SELECT * FROM nodes').all();
954
+ // Exclude `embedding` a several-KB-per-node vector column that would
955
+ // otherwise bloat exported files by many MB for no rendering benefit.
956
+ const nodes = db.prepare(`SELECT ${NODE_RENDER_COLUMNS} FROM nodes`).all();
933
957
  const edges = db.prepare('SELECT * FROM edges').all();
934
958
  const fmt = input.format;
935
959
  const requestedOut = input.outputPath ?? join(getProjectCwd(), '.monomind', 'export');
936
- const outDir = resolve(requestedOut);
960
+ const outDir = resolve(getProjectCwd(), requestedOut);
937
961
  const allowedRoot = resolve(getProjectCwd());
938
962
  if (outDir !== allowedRoot && !outDir.startsWith(allowedRoot + sep)) {
939
963
  return text(`Error: outputPath must be within the project directory (${allowedRoot})`);
@@ -1072,8 +1096,10 @@ const monographImpactTool = {
1072
1096
  const impactPath = typeof rawImpactPath === 'string' && rawImpactPath.length > MAX_IMPACT_PATH_LEN
1073
1097
  ? rawImpactPath.slice(0, MAX_IMPACT_PATH_LEN) : rawImpactPath;
1074
1098
  const rawDepth = input.depth;
1075
- const depth = typeof rawDepth === 'number' && Number.isFinite(rawDepth) && rawDepth > 0
1076
- ? Math.min(Math.floor(rawDepth), 6) : rawDepth;
1099
+ const depth = rawDepth === undefined
1100
+ ? undefined
1101
+ : (typeof rawDepth === 'number' && Number.isFinite(rawDepth) && rawDepth > 0
1102
+ ? Math.min(Math.floor(rawDepth), 6) : 3);
1077
1103
  const result = getMonographImpact(db, {
1078
1104
  name: impactName,
1079
1105
  filePath: impactPath,
@@ -1737,7 +1763,13 @@ const monographInstallSkillsTool = {
1737
1763
  return text(`Invalid platform "${platform}". Must be one of: ${validPlatforms.join(', ')}`);
1738
1764
  }
1739
1765
  // Load community data from graph
1740
- const dbPath = join(repoPath, '.monomind', 'monograph.db');
1766
+ const dbPath = getDbPath(repoPath);
1767
+ // openDb's fileMustExist option isn't in the currently-published
1768
+ // @monoes/monograph release this CLI depends on — check validity
1769
+ // ourselves so a missing DB doesn't get silently auto-created empty.
1770
+ if (!_isValidDb(dbPath)) {
1771
+ return text('Graph not built yet. Run monograph_build first.');
1772
+ }
1741
1773
  let db;
1742
1774
  try {
1743
1775
  db = openDb(dbPath);
@@ -1846,21 +1878,19 @@ const monographListReposTool = {
1846
1878
  // ── monograph_group_contracts ─────────────────────────────────────────────────
1847
1879
  const monographGroupContractsTool = {
1848
1880
  name: 'monograph_group_contracts',
1849
- description: 'List public API contracts (exported symbols, interfaces, and types) for all groups defined in .monograph/groups.json.',
1881
+ description: 'List public API contracts (exported symbols, interfaces, and types) for all groups defined in group.yaml.',
1850
1882
  inputSchema: {
1851
1883
  type: 'object',
1852
1884
  properties: {
1853
- repoPath: { type: 'string', description: 'Absolute path to the repository (defaults to cwd).' },
1885
+ configPath: { type: 'string', description: 'Path to group.yaml (defaults to group.yaml in project cwd)' },
1854
1886
  },
1855
1887
  },
1856
1888
  handler: async (input) => {
1857
1889
  const { getGroupContracts } = await import('./monograph-compat.js');
1858
- const { join } = await import('path');
1859
- const repoPath = input.repoPath ?? getProjectCwd();
1860
- const configPath = join(repoPath, '.monograph', 'groups.json');
1890
+ const configPath = input.configPath ?? join(getProjectCwd(), 'group.yaml');
1861
1891
  const contracts = await getGroupContracts(configPath);
1862
1892
  if (contracts.length === 0)
1863
- return text('No contracts found. Ensure groups are defined in .monograph/groups.json.');
1893
+ return text(`No contracts found. Ensure groups are defined in ${configPath}.`);
1864
1894
  const lines = contracts.map(c => `[${c.groupName}] ${c.symbol} — ${c.filePath}:${c.line}`);
1865
1895
  return text(lines.join('\n'));
1866
1896
  },
@@ -1872,14 +1902,12 @@ const monographGroupStatusTool = {
1872
1902
  inputSchema: {
1873
1903
  type: 'object',
1874
1904
  properties: {
1875
- repoPath: { type: 'string', description: 'Absolute path to the repository (defaults to cwd).' },
1905
+ configPath: { type: 'string', description: 'Path to group.yaml (defaults to group.yaml in project cwd)' },
1876
1906
  },
1877
1907
  },
1878
1908
  handler: async (input) => {
1879
1909
  const { getGroupStatus } = await import('./monograph-compat.js');
1880
- const { join } = await import('path');
1881
- const repoPath = input.repoPath ?? getProjectCwd();
1882
- const configPath = join(repoPath, '.monograph', 'groups.json');
1910
+ const configPath = input.configPath ?? join(getProjectCwd(), 'group.yaml');
1883
1911
  const status = await getGroupStatus(configPath);
1884
1912
  const lines = [`Groups: ${status.totalGroups} (${status.indexedGroups} indexed, ${status.stalledGroups} stalled)`];
1885
1913
  for (const g of status.groups) {
@@ -1954,10 +1982,26 @@ const monographDeadCodeTool = {
1954
1982
  const repoPath = input.path ?? getProjectCwd();
1955
1983
  const cats = input.categories ?? ['dead-functions', 'orphan-files', 'stale-dist'];
1956
1984
  const result = {};
1957
- const dbPath = join(repoPath, '.monomind', 'monograph.db');
1985
+ const dbPath = getDbPath(repoPath);
1986
+ // openDb's fileMustExist option isn't in the currently-published
1987
+ // @monoes/monograph release this CLI depends on — check validity
1988
+ // ourselves so a missing DB doesn't get silently auto-created empty.
1989
+ if (!_isValidDb(dbPath)) {
1990
+ return text(JSON.stringify({ error: 'No monograph index found. Run monograph_build first.' }));
1991
+ }
1958
1992
  let db = null;
1959
1993
  try {
1960
1994
  db = openDb(dbPath);
1995
+ // _isValidDb's size check can't distinguish a real index from an
1996
+ // empty-but-schema-migrated DB (better-sqlite3 auto-creates + migrates
1997
+ // on open, and other unguarded openDb() call sites in this file can
1998
+ // create exactly that as a side effect of an unrelated tool call before
1999
+ // monograph_build ever runs). Verify actual content post-open so this
2000
+ // reports "never built" instead of a misleading "0 dead functions found".
2001
+ const { count } = db.prepare('SELECT COUNT(*) as count FROM nodes').get();
2002
+ if (count === 0) {
2003
+ return text(JSON.stringify({ error: 'No monograph index found. Run monograph_build first.' }));
2004
+ }
1961
2005
  }
1962
2006
  catch {
1963
2007
  return text(JSON.stringify({ error: 'No monograph index found. Run monograph_build first.' }));
@@ -1997,9 +2041,12 @@ const monographDeadCodeTool = {
1997
2041
  FROM nodes n
1998
2042
  WHERE n.label = 'File'
1999
2043
  AND (SELECT COUNT(*) FROM edges e WHERE e.target_id = n.id AND e.relation = 'IMPORTS') = 0
2000
- AND n.file_path NOT LIKE '%test%'
2044
+ AND n.file_path NOT LIKE '%/test/%'
2045
+ AND n.file_path NOT LIKE '%/tests/%'
2046
+ AND n.file_path NOT LIKE '%.test.%'
2001
2047
  AND n.file_path NOT LIKE '%__tests__%'
2002
- AND n.file_path NOT LIKE '%spec%'
2048
+ AND n.file_path NOT LIKE '%/spec/%'
2049
+ AND n.file_path NOT LIKE '%.spec.%'
2003
2050
  AND n.file_path NOT LIKE '%/index.%'
2004
2051
  AND n.file_path NOT LIKE 'bin/%'
2005
2052
  AND n.file_path NOT LIKE 'scripts/%'
@@ -13,14 +13,14 @@ export declare const PrioritizeGapsInputSchema: z.ZodObject<{
13
13
  startLine: z.ZodNumber;
14
14
  endLine: z.ZodNumber;
15
15
  }, "strip", z.ZodTypeAny, {
16
- type: "function" | "line" | "branch";
17
16
  id: string;
17
+ type: "branch" | "function" | "line";
18
18
  file: string;
19
19
  startLine: number;
20
20
  endLine: number;
21
21
  }, {
22
- type: "function" | "line" | "branch";
23
22
  id: string;
23
+ type: "branch" | "function" | "line";
24
24
  file: string;
25
25
  startLine: number;
26
26
  endLine: number;
@@ -52,9 +52,15 @@ export declare const PrioritizeGapsInputSchema: z.ZodObject<{
52
52
  limit: z.ZodDefault<z.ZodNumber>;
53
53
  groupBy: z.ZodDefault<z.ZodEnum<["risk", "file", "type", "none"]>>;
54
54
  }, "strip", z.ZodTypeAny, {
55
- limit: number;
56
- factors: ("complexity" | "change-frequency" | "defect-history" | "business-critical" | "dependency-count" | "test-difficulty")[];
57
- groupBy: "type" | "none" | "file" | "risk";
55
+ gaps?: {
56
+ id: string;
57
+ type: "branch" | "function" | "line";
58
+ file: string;
59
+ startLine: number;
60
+ endLine: number;
61
+ }[] | undefined;
62
+ targetPath?: string | undefined;
63
+ factors: ("business-critical" | "change-frequency" | "complexity" | "defect-history" | "dependency-count" | "test-difficulty")[];
58
64
  weights?: {
59
65
  complexity: number;
60
66
  changeFrequency: number;
@@ -63,16 +69,18 @@ export declare const PrioritizeGapsInputSchema: z.ZodObject<{
63
69
  dependencyCount: number;
64
70
  testDifficulty: number;
65
71
  } | undefined;
72
+ limit: number;
73
+ groupBy: "file" | "none" | "risk" | "type";
74
+ }, {
66
75
  gaps?: {
67
- type: "function" | "line" | "branch";
68
76
  id: string;
77
+ type: "branch" | "function" | "line";
69
78
  file: string;
70
79
  startLine: number;
71
80
  endLine: number;
72
81
  }[] | undefined;
73
82
  targetPath?: string | undefined;
74
- }, {
75
- limit?: number | undefined;
83
+ factors?: ("business-critical" | "change-frequency" | "complexity" | "defect-history" | "dependency-count" | "test-difficulty")[] | undefined;
76
84
  weights?: {
77
85
  complexity?: number | undefined;
78
86
  changeFrequency?: number | undefined;
@@ -81,16 +89,8 @@ export declare const PrioritizeGapsInputSchema: z.ZodObject<{
81
89
  dependencyCount?: number | undefined;
82
90
  testDifficulty?: number | undefined;
83
91
  } | undefined;
84
- gaps?: {
85
- type: "function" | "line" | "branch";
86
- id: string;
87
- file: string;
88
- startLine: number;
89
- endLine: number;
90
- }[] | undefined;
91
- targetPath?: string | undefined;
92
- factors?: ("complexity" | "change-frequency" | "defect-history" | "business-critical" | "dependency-count" | "test-difficulty")[] | undefined;
93
- groupBy?: "type" | "none" | "file" | "risk" | undefined;
92
+ limit?: number | undefined;
93
+ groupBy?: "file" | "none" | "risk" | "type" | undefined;
94
94
  }>;
95
95
  export type PrioritizeGapsInput = z.infer<typeof PrioritizeGapsInputSchema>;
96
96
  export interface PrioritizeGapsOutput {
@@ -176,14 +176,14 @@ export declare const toolDefinition: {
176
176
  startLine: z.ZodNumber;
177
177
  endLine: z.ZodNumber;
178
178
  }, "strip", z.ZodTypeAny, {
179
- type: "function" | "line" | "branch";
180
179
  id: string;
180
+ type: "branch" | "function" | "line";
181
181
  file: string;
182
182
  startLine: number;
183
183
  endLine: number;
184
184
  }, {
185
- type: "function" | "line" | "branch";
186
185
  id: string;
186
+ type: "branch" | "function" | "line";
187
187
  file: string;
188
188
  startLine: number;
189
189
  endLine: number;
@@ -215,9 +215,15 @@ export declare const toolDefinition: {
215
215
  limit: z.ZodDefault<z.ZodNumber>;
216
216
  groupBy: z.ZodDefault<z.ZodEnum<["risk", "file", "type", "none"]>>;
217
217
  }, "strip", z.ZodTypeAny, {
218
- limit: number;
219
- factors: ("complexity" | "change-frequency" | "defect-history" | "business-critical" | "dependency-count" | "test-difficulty")[];
220
- groupBy: "type" | "none" | "file" | "risk";
218
+ gaps?: {
219
+ id: string;
220
+ type: "branch" | "function" | "line";
221
+ file: string;
222
+ startLine: number;
223
+ endLine: number;
224
+ }[] | undefined;
225
+ targetPath?: string | undefined;
226
+ factors: ("business-critical" | "change-frequency" | "complexity" | "defect-history" | "dependency-count" | "test-difficulty")[];
221
227
  weights?: {
222
228
  complexity: number;
223
229
  changeFrequency: number;
@@ -226,16 +232,18 @@ export declare const toolDefinition: {
226
232
  dependencyCount: number;
227
233
  testDifficulty: number;
228
234
  } | undefined;
235
+ limit: number;
236
+ groupBy: "file" | "none" | "risk" | "type";
237
+ }, {
229
238
  gaps?: {
230
- type: "function" | "line" | "branch";
231
239
  id: string;
240
+ type: "branch" | "function" | "line";
232
241
  file: string;
233
242
  startLine: number;
234
243
  endLine: number;
235
244
  }[] | undefined;
236
245
  targetPath?: string | undefined;
237
- }, {
238
- limit?: number | undefined;
246
+ factors?: ("business-critical" | "change-frequency" | "complexity" | "defect-history" | "dependency-count" | "test-difficulty")[] | undefined;
239
247
  weights?: {
240
248
  complexity?: number | undefined;
241
249
  changeFrequency?: number | undefined;
@@ -244,16 +252,8 @@ export declare const toolDefinition: {
244
252
  dependencyCount?: number | undefined;
245
253
  testDifficulty?: number | undefined;
246
254
  } | undefined;
247
- gaps?: {
248
- type: "function" | "line" | "branch";
249
- id: string;
250
- file: string;
251
- startLine: number;
252
- endLine: number;
253
- }[] | undefined;
254
- targetPath?: string | undefined;
255
- factors?: ("complexity" | "change-frequency" | "defect-history" | "business-critical" | "dependency-count" | "test-difficulty")[] | undefined;
256
- groupBy?: "type" | "none" | "file" | "risk" | undefined;
255
+ limit?: number | undefined;
256
+ groupBy?: "file" | "none" | "risk" | "type" | undefined;
257
257
  }>;
258
258
  handler: typeof handler;
259
259
  };
@@ -15,16 +15,16 @@ export declare const DetectSecretsInputSchema: z.ZodObject<{
15
15
  scanHistory: z.ZodDefault<z.ZodBoolean>;
16
16
  }, "strip", z.ZodTypeAny, {
17
17
  targetPath: string;
18
+ secretTypes: ("api-key" | "aws-key" | "aws-secret" | "azure-key" | "certificate" | "connection-string" | "gcp-key" | "generic" | "password" | "private-key" | "token")[];
18
19
  excludePatterns: string[];
19
- secretTypes: ("password" | "token" | "api-key" | "private-key" | "connection-string" | "certificate" | "aws-key" | "aws-secret" | "gcp-key" | "azure-key" | "generic")[];
20
20
  includeEntropy: boolean;
21
21
  entropyThreshold: number;
22
22
  verifySecrets: boolean;
23
23
  scanHistory: boolean;
24
24
  }, {
25
25
  targetPath: string;
26
+ secretTypes?: ("api-key" | "aws-key" | "aws-secret" | "azure-key" | "certificate" | "connection-string" | "gcp-key" | "generic" | "password" | "private-key" | "token")[] | undefined;
26
27
  excludePatterns?: string[] | undefined;
27
- secretTypes?: ("password" | "token" | "api-key" | "private-key" | "connection-string" | "certificate" | "aws-key" | "aws-secret" | "gcp-key" | "azure-key" | "generic")[] | undefined;
28
28
  includeEntropy?: boolean | undefined;
29
29
  entropyThreshold?: number | undefined;
30
30
  verifySecrets?: boolean | undefined;
@@ -116,16 +116,16 @@ export declare const toolDefinition: {
116
116
  scanHistory: z.ZodDefault<z.ZodBoolean>;
117
117
  }, "strip", z.ZodTypeAny, {
118
118
  targetPath: string;
119
+ secretTypes: ("api-key" | "aws-key" | "aws-secret" | "azure-key" | "certificate" | "connection-string" | "gcp-key" | "generic" | "password" | "private-key" | "token")[];
119
120
  excludePatterns: string[];
120
- secretTypes: ("password" | "token" | "api-key" | "private-key" | "connection-string" | "certificate" | "aws-key" | "aws-secret" | "gcp-key" | "azure-key" | "generic")[];
121
121
  includeEntropy: boolean;
122
122
  entropyThreshold: number;
123
123
  verifySecrets: boolean;
124
124
  scanHistory: boolean;
125
125
  }, {
126
126
  targetPath: string;
127
+ secretTypes?: ("api-key" | "aws-key" | "aws-secret" | "azure-key" | "certificate" | "connection-string" | "gcp-key" | "generic" | "password" | "private-key" | "token")[] | undefined;
127
128
  excludePatterns?: string[] | undefined;
128
- secretTypes?: ("password" | "token" | "api-key" | "private-key" | "connection-string" | "certificate" | "aws-key" | "aws-secret" | "gcp-key" | "azure-key" | "generic")[] | undefined;
129
129
  includeEntropy?: boolean | undefined;
130
130
  entropyThreshold?: number | undefined;
131
131
  verifySecrets?: boolean | undefined;
@@ -7,13 +7,14 @@
7
7
  import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, statSync } from 'node:fs';
8
8
  import { join } from 'node:path';
9
9
  import { randomBytes } from 'node:crypto';
10
- import { getProjectCwd } from './types.js';
10
+ import { getMonomindDataRoot, migrateLegacyStoreFile } from './types.js';
11
11
  import { agentTools } from './agent-tools.js';
12
- // Swarm state persistence
13
- const SWARM_DIR = '.monomind/swarm';
12
+ // Swarm state persistence — relative to the git-safe data root (see
13
+ // getMonomindDataRoot()), matching agent/task/hive-mind stores.
14
+ const SWARM_DIR = 'swarm';
14
15
  const SWARM_STATE_FILE = 'swarm-state.json';
15
16
  function getSwarmDir() {
16
- return join(getProjectCwd(), SWARM_DIR);
17
+ return join(getMonomindDataRoot(), SWARM_DIR);
17
18
  }
18
19
  function getSwarmStatePath() {
19
20
  return join(getSwarmDir(), SWARM_STATE_FILE);
@@ -28,6 +29,7 @@ const MAX_SWARM_STORE_BYTES = 10 * 1024 * 1024;
28
29
  function loadSwarmStore() {
29
30
  try {
30
31
  const path = getSwarmStatePath();
32
+ migrateLegacyStoreFile(path, join(SWARM_DIR, SWARM_STATE_FILE));
31
33
  if (existsSync(path)) {
32
34
  if (statSync(path).size > MAX_SWARM_STORE_BYTES)
33
35
  return { swarms: {}, version: '3.0.0' };
@@ -8,7 +8,7 @@
8
8
  * - process.cpuUsage() for real CPU stats
9
9
  * - os module for system information
10
10
  */
11
- import { getProjectCwd } from './types.js';
11
+ import { getProjectCwd, getMonomindDataRoot } from './types.js';
12
12
  import { existsSync, readFileSync, statSync, writeFileSync, renameSync, mkdirSync } from 'node:fs';
13
13
  import { join, dirname } from 'node:path';
14
14
  import { fileURLToPath } from 'node:url';
@@ -184,7 +184,7 @@ export const systemTools = [
184
184
  // Fallback: JSON store files (backward compatibility)
185
185
  if (_metricsSource === 'none') {
186
186
  try {
187
- const agentStorePath = join(getProjectCwd(), STORAGE_DIR, 'agents', 'store.json');
187
+ const agentStorePath = join(getMonomindDataRoot(), 'agents', 'store.json');
188
188
  if (existsSync(agentStorePath) && statSync(agentStorePath).size <= MAX_SYSTEM_STORE_BYTES) {
189
189
  const agentStore = JSON.parse(readFileSync(agentStorePath, 'utf-8'));
190
190
  const agents = Object.values(agentStore.agents || {});
@@ -197,7 +197,7 @@ export const systemTools = [
197
197
  }
198
198
  catch { /* agent store not available */ }
199
199
  try {
200
- const taskStorePath = join(getProjectCwd(), STORAGE_DIR, 'tasks', 'store.json');
200
+ const taskStorePath = join(getMonomindDataRoot(), 'tasks', 'store.json');
201
201
  if (existsSync(taskStorePath) && statSync(taskStorePath).size <= MAX_SYSTEM_STORE_BYTES) {
202
202
  const taskStore = JSON.parse(readFileSync(taskStorePath, 'utf-8'));
203
203
  const tasks = Object.values(taskStore.tasks || {});
@@ -534,7 +534,7 @@ export const systemTools = [
534
534
  },
535
535
  handler: async () => {
536
536
  // Read from the task store file
537
- const storePath = join(getProjectCwd(), '.monomind', 'tasks', 'store.json');
537
+ const storePath = join(getMonomindDataRoot(), 'tasks', 'store.json');
538
538
  let tasks = [];
539
539
  try {
540
540
  if (existsSync(storePath) && statSync(storePath).size <= MAX_SYSTEM_STORE_BYTES) {
@@ -24,6 +24,26 @@ export interface MCPToolResult {
24
24
  */
25
25
  export declare function getProjectCwd(): string;
26
26
  export declare function getMonomindDataRoot(cwd?: string): string;
27
+ /**
28
+ * One-time migration for the agent/task/hive/swarm stores that historically lived
29
+ * under `<projectCwd>/.monomind/<subpath>` (via getProjectCwd()) before being
30
+ * consolidated onto the canonical getMonomindDataRoot() location (typically
31
+ * `<repo>/.git/monomind/<subpath>`). Several MCP tool files (agent-tools.ts,
32
+ * hive-mind-tools.ts, swarm-tools.ts, system-tools.ts) used to read/write the
33
+ * legacy path directly, causing the same logical store to physically split from
34
+ * task-tools.ts/session-tools.ts, which always used getMonomindDataRoot().
35
+ *
36
+ * If the canonical file is missing but the legacy file exists, copy (never move,
37
+ * for safety) the legacy file into place so pre-existing data isn't silently
38
+ * orphaned. Best-effort and idempotent — never throws, and it's a no-op once the
39
+ * canonical file exists or when the two paths already coincide (e.g. no .git).
40
+ *
41
+ * @param canonicalPath Absolute path under getMonomindDataRoot() the tool now reads from.
42
+ * @param legacySubpath Path relative to `.monomind/` that the tool used to read from
43
+ * (e.g. `join('agents', 'store.json')`).
44
+ * @param cwd Optional project cwd override (defaults to getProjectCwd()).
45
+ */
46
+ export declare function migrateLegacyStoreFile(canonicalPath: string, legacySubpath: string, cwd?: string): void;
27
47
  export interface MCPTool {
28
48
  name: string;
29
49
  description: string;
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Local type definitions to avoid external imports outside package boundary.
5
5
  */
6
- import { statSync, readFileSync } from 'node:fs';
6
+ import { statSync, readFileSync, existsSync, mkdirSync, copyFileSync } from 'node:fs';
7
7
  import { join, dirname, resolve } from 'node:path';
8
8
  /**
9
9
  * Returns the effective project working directory.
@@ -60,4 +60,39 @@ export function getMonomindDataRoot(cwd) {
60
60
  _dataRootCache.set(workDir, result);
61
61
  return result;
62
62
  }
63
+ /**
64
+ * One-time migration for the agent/task/hive/swarm stores that historically lived
65
+ * under `<projectCwd>/.monomind/<subpath>` (via getProjectCwd()) before being
66
+ * consolidated onto the canonical getMonomindDataRoot() location (typically
67
+ * `<repo>/.git/monomind/<subpath>`). Several MCP tool files (agent-tools.ts,
68
+ * hive-mind-tools.ts, swarm-tools.ts, system-tools.ts) used to read/write the
69
+ * legacy path directly, causing the same logical store to physically split from
70
+ * task-tools.ts/session-tools.ts, which always used getMonomindDataRoot().
71
+ *
72
+ * If the canonical file is missing but the legacy file exists, copy (never move,
73
+ * for safety) the legacy file into place so pre-existing data isn't silently
74
+ * orphaned. Best-effort and idempotent — never throws, and it's a no-op once the
75
+ * canonical file exists or when the two paths already coincide (e.g. no .git).
76
+ *
77
+ * @param canonicalPath Absolute path under getMonomindDataRoot() the tool now reads from.
78
+ * @param legacySubpath Path relative to `.monomind/` that the tool used to read from
79
+ * (e.g. `join('agents', 'store.json')`).
80
+ * @param cwd Optional project cwd override (defaults to getProjectCwd()).
81
+ */
82
+ export function migrateLegacyStoreFile(canonicalPath, legacySubpath, cwd) {
83
+ try {
84
+ if (existsSync(canonicalPath))
85
+ return;
86
+ const legacyPath = join(cwd || getProjectCwd(), '.monomind', legacySubpath);
87
+ if (legacyPath === canonicalPath)
88
+ return;
89
+ if (!existsSync(legacyPath))
90
+ return;
91
+ mkdirSync(dirname(canonicalPath), { recursive: true });
92
+ copyFileSync(legacyPath, canonicalPath);
93
+ }
94
+ catch {
95
+ // Best-effort; leave both stores as-is on any failure.
96
+ }
97
+ }
63
98
  //# sourceMappingURL=types.js.map
@@ -127,6 +127,12 @@ export declare class EWCConsolidator {
127
127
  private globalFisher;
128
128
  private consolidationHistory;
129
129
  private initialized;
130
+ /** Dirty flag: true when in-memory state diverges from disk */
131
+ private dirty;
132
+ /** Pending debounced write timer */
133
+ private saveTimer;
134
+ /** Debounce window for disk writes (ms) */
135
+ private static readonly SAVE_DEBOUNCE_MS;
130
136
  constructor(config?: Partial<EWCConfig>);
131
137
  /**
132
138
  * Initialize the consolidator by loading persisted state
@@ -237,6 +243,12 @@ export declare class EWCConsolidator {
237
243
  * Prune old, low-importance patterns to stay within limit
238
244
  */
239
245
  private pruneOldPatterns;
246
+ /**
247
+ * Schedule a debounced disk flush.
248
+ * Multiple calls within SAVE_DEBOUNCE_MS coalesce into one write,
249
+ * preventing blocking I/O on every consolidation or gradient event.
250
+ */
251
+ private scheduleSave;
240
252
  /**
241
253
  * Save state to disk
242
254
  */
@@ -10,8 +10,20 @@ interface HNSWEntry {
10
10
  namespace: string;
11
11
  content: string;
12
12
  }
13
+ /** Minimal shape of the real @monoes/memory HNSWIndex class relied on here. */
14
+ interface RealHNSWIndex {
15
+ addPoint(id: string, vector: Float32Array): Promise<void>;
16
+ search(query: Float32Array, k: number, ef?: number): Promise<Array<{
17
+ id: string;
18
+ distance: number;
19
+ }>>;
20
+ rebuild(entries: Array<{
21
+ id: string;
22
+ vector: Float32Array;
23
+ }>): Promise<void>;
24
+ }
13
25
  interface HNSWIndex {
14
- db: any;
26
+ instance: RealHNSWIndex;
15
27
  entries: Map<string, HNSWEntry>;
16
28
  dimensions: number;
17
29
  initialized: boolean;