monomind 1.18.0 → 1.18.1

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "monomind",
3
- "version": "1.18.0",
3
+ "version": "1.18.1",
4
4
  "description": "Monomind - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -1981,41 +1981,64 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
1981
1981
  const d = path.resolve(dir || process.cwd());
1982
1982
  const dbPath = path.join(d, '.monomind', 'monograph.db');
1983
1983
 
1984
- // Generate HTML on-the-fly from SQLite DB using the improved toHtml export
1984
+ // Generate HTML on-the-fly from SQLite DB
1985
1985
  if (fs.existsSync(dbPath)) {
1986
- const { openDb, closeDb } = await import(new URL('../../../../monograph/dist/src/storage/db.js', import.meta.url).href);
1987
- const { toHtml } = await import(new URL('../../../../monograph/dist/src/export/html.js', import.meta.url).href);
1988
- const db = openDb(dbPath);
1989
1986
  let html;
1990
1987
  try {
1991
- const rawNodes = db.prepare('SELECT * FROM nodes LIMIT 5000').all();
1992
- const rawEdges = db.prepare('SELECT * FROM edges').all();
1993
- // Remap snake_case DB columns to camelCase MonographNode/MonographEdge interfaces
1994
- const parsedNodes = rawNodes.map(n => ({
1995
- id: n.id,
1996
- label: n.label,
1997
- name: n.name,
1998
- normLabel: n.norm_label,
1999
- filePath: n.file_path,
2000
- startLine: n.start_line,
2001
- endLine: n.end_line,
2002
- communityId: n.community_id,
2003
- isExported: !!n.is_exported,
2004
- language: n.language,
2005
- properties: n.properties ? JSON.parse(n.properties) : {},
2006
- }));
2007
- const parsedEdges = rawEdges.map(e => ({
2008
- id: e.id,
2009
- sourceId: e.source_id,
2010
- targetId: e.target_id,
2011
- relation: e.relation,
2012
- confidence: e.confidence,
2013
- confidenceScore: e.confidence_score,
2014
- weight: e.weight,
1988
+ // Try better-sqlite3 first (fast, in-process)
1989
+ const { openDb, closeDb } = await import(new URL('../../../../monograph/dist/src/storage/db.js', import.meta.url).href);
1990
+ const { toHtml } = await import(new URL('../../../../monograph/dist/src/export/html.js', import.meta.url).href);
1991
+ const db = openDb(dbPath);
1992
+ try {
1993
+ const rawNodes = db.prepare('SELECT * FROM nodes LIMIT 5000').all();
1994
+ const rawEdges = db.prepare('SELECT * FROM edges').all();
1995
+ const parsedNodes = rawNodes.map(n => ({
1996
+ id: n.id, label: n.label, name: n.name, normLabel: n.norm_label,
1997
+ filePath: n.file_path, startLine: n.start_line, endLine: n.end_line,
1998
+ communityId: n.community_id, isExported: !!n.is_exported,
1999
+ language: n.language, properties: n.properties ? JSON.parse(n.properties) : {},
2000
+ }));
2001
+ const parsedEdges = rawEdges.map(e => ({
2002
+ id: e.id, sourceId: e.source_id, targetId: e.target_id,
2003
+ relation: e.relation, confidence: e.confidence,
2004
+ confidenceScore: e.confidence_score, weight: e.weight,
2005
+ }));
2006
+ html = toHtml(parsedNodes, parsedEdges);
2007
+ } finally { closeDb(db); }
2008
+ } catch {
2009
+ // Fallback: sqlite3 CLI + inline Sigma.js graph
2010
+ const { execSync } = await import('child_process');
2011
+ const runSql = (sql) => {
2012
+ try { return JSON.parse(execSync(`sqlite3 -json "${dbPath}"`, { encoding: 'utf-8', timeout: 15000, maxBuffer: 50*1024*1024, input: sql + ';' }) || '[]'); } catch { return []; }
2013
+ };
2014
+ const rawNodes = runSql('SELECT id, name, label, file_path, community_id FROM nodes LIMIT 2000');
2015
+ const rawEdges = runSql('SELECT source_id, target_id, relation FROM edges');
2016
+ const degree = new Map();
2017
+ for (const n of rawNodes) degree.set(n.id, 0);
2018
+ for (const e of rawEdges) {
2019
+ if (degree.has(e.source_id)) degree.set(e.source_id, (degree.get(e.source_id)||0)+1);
2020
+ if (degree.has(e.target_id)) degree.set(e.target_id, (degree.get(e.target_id)||0)+1);
2021
+ }
2022
+ const topNodes = [...rawNodes].sort((a,b) => (degree.get(b.id)||0)-(degree.get(a.id)||0)).slice(0,500);
2023
+ const topIds = new Set(topNodes.map(n => n.id));
2024
+ const filteredEdges = rawEdges.filter(e => topIds.has(e.source_id) && topIds.has(e.target_id)).slice(0,2000);
2025
+ const colors = ['#4E79A7','#F28E2B','#E15759','#76B7B2','#59A14F','#EDC948','#B07AA1','#FF9DA7','#9C755F','#BAB0AC'];
2026
+ const nodesJson = JSON.stringify(topNodes.map((n,i) => {
2027
+ const d = degree.get(n.id)||1;
2028
+ const c = n.community_id != null ? colors[n.community_id % colors.length] : colors[i % colors.length];
2029
+ return { id: n.id, label: n.name||n.id, x: Math.cos(i*0.618*Math.PI*2)*300+Math.random()*50, y: Math.sin(i*0.618*Math.PI*2)*300+Math.random()*50, size: Math.min(3+Math.sqrt(d)*2,20), color: c };
2015
2030
  }));
2016
- html = toHtml(parsedNodes, parsedEdges);
2017
- } finally {
2018
- closeDb(db);
2031
+ const edgesJson = JSON.stringify(filteredEdges.map((e,i) => ({ id:'e'+i, source:e.source_id, target:e.target_id })));
2032
+ html = `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Monograph</title>
2033
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/sigma.js/2.4.0/sigma.min.js"><\/script>
2034
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/graphology/0.25.4/graphology.umd.min.js"><\/script>
2035
+ <style>*{margin:0;padding:0}body{background:#0f0f1a;overflow:hidden}#g{width:100vw;height:100vh}</style></head>
2036
+ <body><div id="g"></div><script>
2037
+ const g=new graphology.Graph();
2038
+ ${nodesJson}.forEach(n=>g.addNode(n.id,{label:n.label,x:n.x,y:n.y,size:n.size,color:n.color}));
2039
+ ${edgesJson}.forEach(e=>{try{g.addEdge(e.source,e.target,{size:0.5,color:'#333'})}catch{}});
2040
+ new Sigma(g,document.getElementById('g'),{renderEdgeLabels:false,labelColor:{color:'#ccc'},labelSize:10});
2041
+ <\/script></body></html>`;
2019
2042
  }
2020
2043
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Access-Control-Allow-Origin': '*', 'Cache-Control': 'no-cache' });
2021
2044
  res.end(html);
@@ -2087,31 +2110,31 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
2087
2110
  const dbPath = path.join(d, '.monomind', 'monograph.db');
2088
2111
  let nodes = [], edges = [];
2089
2112
  if (fs.existsSync(dbPath)) {
2090
- const { openDb, closeDb } = await import(new URL('../../../../monograph/dist/src/storage/db.js', import.meta.url).href);
2091
- const db = openDb(dbPath);
2092
- try {
2093
- const nodeLimit = Math.min(parseInt(qs.get('limit') || '500', 10), 5000);
2094
- // ?labels=Section,Concept → fetch only those label types (no degree cutoff)
2095
- const labelFilter = qs.get('labels') ? new Set(qs.get('labels').split(',').map(s => s.trim())) : null;
2096
- const rawNodes = labelFilter
2097
- ? db.prepare(`SELECT id, name, label, file_path, community_id FROM nodes WHERE label IN (${[...labelFilter].map(() => '?').join(',')}) LIMIT 5000`).all(...labelFilter)
2098
- : db.prepare('SELECT id, name, label, file_path, community_id FROM nodes LIMIT 5000').all();
2099
- const rawEdges = db.prepare('SELECT source_id, target_id, relation FROM edges').all();
2100
- // Compute degree
2101
- const degree = new Map();
2102
- for (const n of rawNodes) degree.set(n.id, 0);
2103
- for (const e of rawEdges) {
2104
- if (degree.has(e.source_id)) degree.set(e.source_id, (degree.get(e.source_id) || 0) + 1);
2105
- if (degree.has(e.target_id)) degree.set(e.target_id, (degree.get(e.target_id) || 0) + 1);
2106
- }
2107
- // When filtering by labels, return all matching nodes (skip degree sort+slice)
2108
- const topNodes = labelFilter
2109
- ? rawNodes
2110
- : [...rawNodes].sort((a, b) => (degree.get(b.id) || 0) - (degree.get(a.id) || 0)).slice(0, nodeLimit);
2111
- const topIds = new Set(topNodes.map(n => n.id));
2112
- nodes = topNodes.map(n => ({ id: n.id, label: n.name || n.id, type: n.label || 'unknown', degree: degree.get(n.id) || 0 }));
2113
- edges = rawEdges.filter(e => topIds.has(e.source_id) && topIds.has(e.target_id)).slice(0, 2000).map(e => ({ source: e.source_id, target: e.target_id, relation: e.relation || 'REF' }));
2114
- } finally { closeDb(db); }
2113
+ const { execSync } = await import('child_process');
2114
+ const runSql = (sql, timeout = 10000) => {
2115
+ try {
2116
+ return JSON.parse(execSync(`sqlite3 -json "${dbPath}"`,
2117
+ { encoding: 'utf-8', timeout, maxBuffer: 50 * 1024 * 1024, input: sql + ';' }) || '[]');
2118
+ } catch { return []; }
2119
+ };
2120
+ const nodeLimit = Math.min(parseInt(qs.get('limit') || '500', 10), 5000);
2121
+ const labelFilter = qs.get('labels') ? qs.get('labels').split(',').map(s => s.trim()) : null;
2122
+ const rawNodes = labelFilter
2123
+ ? runSql(`SELECT id, name, label, file_path, community_id FROM nodes WHERE label IN (${labelFilter.map(l => "'" + l.replace(/'/g, "''") + "'").join(',')}) LIMIT 5000`)
2124
+ : runSql(`SELECT id, name, label, file_path, community_id FROM nodes LIMIT 5000`);
2125
+ const rawEdges = runSql('SELECT source_id, target_id, relation FROM edges');
2126
+ const degree = new Map();
2127
+ for (const n of rawNodes) degree.set(n.id, 0);
2128
+ for (const e of rawEdges) {
2129
+ if (degree.has(e.source_id)) degree.set(e.source_id, (degree.get(e.source_id) || 0) + 1);
2130
+ if (degree.has(e.target_id)) degree.set(e.target_id, (degree.get(e.target_id) || 0) + 1);
2131
+ }
2132
+ const topNodes = labelFilter
2133
+ ? rawNodes
2134
+ : [...rawNodes].sort((a, b) => (degree.get(b.id) || 0) - (degree.get(a.id) || 0)).slice(0, nodeLimit);
2135
+ const topIds = new Set(topNodes.map(n => n.id));
2136
+ nodes = topNodes.map(n => ({ id: n.id, label: n.name || n.id, type: n.label || 'unknown', degree: degree.get(n.id) || 0 }));
2137
+ edges = rawEdges.filter(e => topIds.has(e.source_id) && topIds.has(e.target_id)).slice(0, 2000).map(e => ({ source: e.source_id, target: e.target_id, relation: e.relation || 'REF' }));
2115
2138
  }
2116
2139
  res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Cache-Control': 'no-cache' });
2117
2140
  res.end(JSON.stringify({ nodes, edges }));
@@ -3648,11 +3671,11 @@ export async function startServer({ port = 4242, projectDir, openBrowser = true
3648
3671
  godNodes: gods,
3649
3672
  typeDistribution: types,
3650
3673
  relationDistribution: relations,
3651
- updatedAt: fs.statSync(dbPath).mtime,
3674
+ updatedAt: (() => { try { return fs.statSync(dbPath).mtime; } catch { return null; } })(),
3652
3675
  }));
3653
3676
  } catch (err) {
3654
- res.writeHead(500, { 'Content-Type': 'application/json' });
3655
- res.end(JSON.stringify({ error: String(err) }));
3677
+ res.writeHead(200, { 'Content-Type': 'application/json' });
3678
+ res.end(JSON.stringify({ exists: true, nodes: 0, edges: 0, godNodes: [], typeDistribution: [], relationDistribution: [], error: String(err) }));
3656
3679
  }
3657
3680
  return;
3658
3681
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monoes/monomindcli",
3
- "version": "1.18.0",
3
+ "version": "1.18.1",
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",