monomind 1.6.9 → 1.7.0

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.
@@ -1,14 +1,14 @@
1
1
  /**
2
2
  * Graphify MCP Tools
3
3
  *
4
- * Bridges @monomind/graph's knowledge graph into monomind's MCP tool surface.
4
+ * Bridges graphify's (Python) knowledge graph into monomind's MCP tool surface.
5
5
  * Agents can query the codebase knowledge graph without reading files —
6
6
  * god_nodes(), query_graph(), shortest_path() give structural understanding
7
7
  * in milliseconds vs. reading dozens of source files.
8
8
  *
9
- * Graph is built automatically on `monomind init` and stored at
10
- * .monomind/graph/graph.json (legacy: graphify-out/graph.json).
11
- * Rebuild manually: call graphify_build via MCP.
9
+ * Graph is built by `graphify update` (Python CLI) on `monomind init` and
10
+ * stored at .monomind/graph/graph.json (legacy: graphify-out/graph.json).
11
+ * Install: uv tool install graphifyy
12
12
  */
13
13
  import { existsSync, readFileSync } from 'fs';
14
14
  import { join, resolve } from 'path';
@@ -29,25 +29,13 @@ function graphExists(cwd) {
29
29
  }
30
30
  /**
31
31
  * Load the knowledge graph.
32
- * Tries @monomind/graph's loadGraph first; falls back to parsing raw JSON.
32
+ * Parses the graph.json produced by graphify (Python).
33
33
  */
34
34
  async function loadKnowledgeGraph(cwd) {
35
35
  const graphPath = getGraphPath(cwd);
36
- let rawNodes = [];
37
- let rawEdges = [];
38
- try {
39
- // Prefer @monomind/graph's loader which handles format normalization.
40
- const { loadGraph } = await import('@monomind/graph');
41
- const loaded = loadGraph(graphPath);
42
- rawNodes = loaded.nodes;
43
- rawEdges = loaded.edges;
44
- }
45
- catch {
46
- // Fallback: parse JSON directly
47
- const data = JSON.parse(readFileSync(graphPath, 'utf-8'));
48
- rawNodes = data.nodes || [];
49
- rawEdges = data.links || data.edges || [];
50
- }
36
+ const data = JSON.parse(readFileSync(graphPath, 'utf-8'));
37
+ const rawNodes = data.nodes || [];
38
+ const rawEdges = data.links || data.edges || [];
51
39
  // Build in-memory graph structures
52
40
  const nodes = new Map();
53
41
  for (const n of rawNodes) {
@@ -129,32 +117,46 @@ export const graphifyBuildTool = {
129
117
  const cwd = getProjectCwd();
130
118
  const targetPath = params.path || cwd;
131
119
  try {
132
- const { buildGraph } = await import('@monomind/graph');
133
- const outputDir = join(targetPath, '.monomind', 'graph');
134
- const result = await buildGraph(targetPath, {
135
- codeOnly: Boolean(params.codeOnly),
136
- outputDir,
120
+ const { execSync } = await import('child_process');
121
+ execSync(`graphify update ${targetPath}`, {
122
+ encoding: 'utf8',
123
+ cwd: targetPath,
124
+ timeout: 300000,
125
+ stdio: 'pipe',
137
126
  });
127
+ // graphify outputs to graphify-out/ by default
128
+ const graphPath = getGraphPath(targetPath);
129
+ const outputDir = join(targetPath, '.monomind', 'graph');
130
+ const statsPath = join(outputDir, 'stats.json');
131
+ let stats = { nodes: 0, edges: 0, communities: 0, files: 0 };
132
+ try {
133
+ stats = JSON.parse(readFileSync(statsPath, 'utf-8'));
134
+ }
135
+ catch {
136
+ // Stats may not exist yet — read from graph directly
137
+ try {
138
+ const g = JSON.parse(readFileSync(graphPath, 'utf-8'));
139
+ stats.nodes = g.nodes?.length || 0;
140
+ stats.edges = (g.links || g.edges)?.length || 0;
141
+ }
142
+ catch { }
143
+ }
138
144
  return {
139
145
  success: true,
140
- graphPath: result.graphPath,
141
- reportPath: result.reportPath,
142
- filesProcessed: result.filesProcessed,
143
- fromCache: result.fromCache,
144
- nodes: result.analysis.stats.nodes,
145
- edges: result.analysis.stats.edges,
146
- communities: result.analysis.stats.communities,
147
- graphQuality: result.graphQuality,
148
- experimentStatus: result.experimentStatus,
149
- corpusWarnings: result.corpusWarnings,
150
- message: `[${result.experimentStatus}] Knowledge graph built — quality=${result.graphQuality.toFixed(4)} (${result.analysis.stats.nodes}n/${result.analysis.stats.edges}e/${result.analysis.stats.communities}c)`,
146
+ graphPath,
147
+ outputDir,
148
+ nodes: stats.nodes,
149
+ edges: stats.edges,
150
+ communities: stats.communities || 0,
151
+ filesProcessed: stats.files || 0,
152
+ message: `Knowledge graph built (${stats.nodes}n/${stats.edges}e)`,
151
153
  };
152
154
  }
153
155
  catch (err) {
154
156
  return {
155
157
  error: true,
156
158
  message: String(err),
157
- hint: '@monomind/graph package not availableensure it is installed and built.',
159
+ hint: 'graphify not installedrun: uv tool install graphifyy',
158
160
  };
159
161
  }
160
162
  },
@@ -848,14 +850,20 @@ export const graphifyVisualizeTool = {
848
850
  }
849
851
  try {
850
852
  const graphPath = getGraphPath(targetPath);
851
- const { readFileSync } = await import('fs');
852
- const { join, dirname } = await import('path');
853
+ const { dirname } = await import('path');
853
854
  const outputDir = dirname(graphPath);
854
- const { exportHTML } = await import('@monomind/graph');
855
- const raw = JSON.parse(readFileSync(graphPath, 'utf-8'));
856
- const htmlPath = exportHTML(raw, outputDir);
855
+ const { execSync, spawn } = await import('child_process');
856
+ // graphify doesn't have a visualize CLI command — generate a simple HTML viewer
857
+ const graphData = readFileSync(graphPath, 'utf-8');
858
+ const htmlContent = `<!DOCTYPE html><html><head><title>Knowledge Graph</title></head><body>
859
+ <h1>Knowledge Graph Visualization</h1>
860
+ <p>Nodes: ${JSON.parse(graphData).nodes?.length || 0}, Edges: ${(JSON.parse(graphData).links || JSON.parse(graphData).edges)?.length || 0}</p>
861
+ <pre style="max-height:80vh;overflow:auto">${graphData.slice(0, 50000)}</pre>
862
+ </body></html>`;
863
+ const { writeFileSync } = await import('fs');
864
+ const htmlPath = join(outputDir, 'graph.html');
865
+ writeFileSync(htmlPath, htmlContent);
857
866
  if (params.open) {
858
- const { spawn } = await import('child_process');
859
867
  const opener = process.platform === 'darwin' ? 'open'
860
868
  : process.platform === 'win32' ? 'start' : 'xdg-open';
861
869
  spawn(opener, [htmlPath], { detached: true, stdio: 'ignore' }).unref();
@@ -868,7 +876,7 @@ export const graphifyVisualizeTool = {
868
876
  };
869
877
  }
870
878
  catch (err) {
871
- return { error: true, message: String(err) };
879
+ return { error: true, message: String(err), hint: 'graphify not installed — run: uv tool install graphifyy' };
872
880
  }
873
881
  },
874
882
  };
@@ -981,10 +989,10 @@ async function rebuild() {
981
989
  const start = Date.now();
982
990
  console.log('[graphify-watch] Change detected — rebuilding graph…');
983
991
  try {
984
- const { buildGraph } = await import('@monomind/graph');
985
- const { graph: serialized } = await buildGraph(TARGET, { outputDir: OUTPUT_DIR });
986
- const { exportHTML } = await import('@monomind/graph');
987
- exportHTML(serialized, OUTPUT_DIR);
992
+ const { execSync } = await import('child_process');
993
+ execSync('graphify update ' + TARGET, {
994
+ encoding: 'utf8', cwd: TARGET, timeout: 300000, stdio: 'pipe',
995
+ });
988
996
  console.log('[graphify-watch] Done in', Date.now() - start, 'ms');
989
997
  } catch (err) {
990
998
  console.error('[graphify-watch] Build error:', err.message ?? err);
@@ -1158,14 +1166,18 @@ export const graphifySuggestTool = {
1158
1166
  return { error: true, message: 'No graph found. Run graphify_build first.' };
1159
1167
  }
1160
1168
  try {
1161
- const { loadGraph, suggestQuestions, buildAnalysis } = await import('@monomind/graph');
1162
- const graphPath = getGraphPath(targetPath);
1163
- const outputDir = resolve(join(targetPath, '.monomind', 'graph'));
1164
- const { buildGraphologyGraph } = await import('@monomind/graph');
1165
- const raw = loadGraph(graphPath);
1166
- const graph = buildGraphologyGraph({ nodes: raw.nodes, edges: raw.edges, hyperedges: [], filesProcessed: 0, fromCache: 0, errors: [] });
1167
- const analysis = buildAnalysis(graph, outputDir);
1168
- const questions = suggestQuestions(graph, analysis.communities);
1169
+ const loaded = await loadKnowledgeGraph(targetPath);
1170
+ const godNodes = [...loaded.degree.entries()]
1171
+ .filter(([id]) => loaded.nodes.get(id)?.source_file)
1172
+ .sort((a, b) => b[1] - a[1])
1173
+ .slice(0, 10)
1174
+ .map(([id, deg]) => ({ node: id, degree: deg, file: loaded.nodes.get(id)?.source_file, question: `What role does ${id} play and why does it have ${deg} connections?` }));
1175
+ // Find isolated nodes (no connections)
1176
+ const isolated = [...loaded.degree.entries()]
1177
+ .filter(([id, d]) => d === 0 && loaded.nodes.get(id)?.source_file)
1178
+ .slice(0, 3)
1179
+ .map(([id]) => ({ node: id, degree: 0, file: loaded.nodes.get(id)?.source_file, question: `Why is ${id} isolated with no connections?` }));
1180
+ const questions = [...godNodes, ...isolated];
1169
1181
  return { success: true, questions, total: questions.length };
1170
1182
  }
1171
1183
  catch (err) {
@@ -1196,12 +1208,24 @@ export const graphifyHealthTool = {
1196
1208
  const cwd = getProjectCwd();
1197
1209
  const targetPath = params.path || cwd;
1198
1210
  try {
1199
- const { collectFiles, corpusHealth } = await import('@monomind/graph');
1200
- const files = collectFiles(targetPath);
1201
- const warnings = corpusHealth(files);
1211
+ const warnings = [];
1212
+ let totalFiles = 0;
1213
+ if (!graphExists(targetPath)) {
1214
+ warnings.push('No graph found — run graphify_build first');
1215
+ }
1216
+ else {
1217
+ const loaded = await loadKnowledgeGraph(targetPath);
1218
+ totalFiles = new Set([...loaded.nodes.values()].map(n => n.source_file).filter(Boolean)).size;
1219
+ if (loaded.nodes.size === 0)
1220
+ warnings.push('Graph is empty — rebuild with graphify_build');
1221
+ if (totalFiles < 3)
1222
+ warnings.push('Very few source files — graph analysis may not be useful');
1223
+ if (loaded.edges.length === 0)
1224
+ warnings.push('No edges found — code may lack imports/calls');
1225
+ }
1202
1226
  return {
1203
1227
  success: true,
1204
- totalFiles: files.length,
1228
+ totalFiles,
1205
1229
  warnings,
1206
1230
  healthy: warnings.length === 0,
1207
1231
  message: warnings.length === 0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monoes/monomindcli",
3
- "version": "1.6.9",
3
+ "version": "1.7.0",
4
4
  "type": "module",
5
5
  "description": "Monomind CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
6
6
  "main": "dist/src/index.js",