monomind 1.11.0 → 1.11.2

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.11.0",
3
+ "version": "1.11.2",
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",
@@ -127,4 +127,4 @@
127
127
  "access": "public",
128
128
  "tag": "latest"
129
129
  }
130
- }
130
+ }
@@ -1424,7 +1424,16 @@ const preTaskCommand = {
1424
1424
  output.writeln(output.bold('Recommendations'));
1425
1425
  output.printList(result.recommendations);
1426
1426
  }
1427
- // Enhanced model routing module was never shipped no recommendation to add.
1427
+ // Monograph graph-first reminder always surface before the agent starts grepping
1428
+ if (description) {
1429
+ output.writeln();
1430
+ output.writeln(output.bold('[MONOGRAPH] Graph-first protocol:'));
1431
+ output.printList([
1432
+ `mcp__monomind__monograph_suggest task="${description.slice(0, 80)}" — get relevant nodes ranked by task`,
1433
+ 'mcp__monomind__monograph_query — BM25 lookup before any grep/find via Bash',
1434
+ 'mcp__monomind__monograph_impact — blast radius before editing shared code',
1435
+ ]);
1436
+ }
1428
1437
  return { success: true, data: result };
1429
1438
  }
1430
1439
  catch (error) {
@@ -17,7 +17,9 @@ function behavioralRules() {
17
17
  - NEVER save working files, text/mds, or tests to the root folder
18
18
  - Never continuously check status after spawning a swarm — wait for results
19
19
  - ALWAYS read a file before editing it
20
- - NEVER commit secrets, credentials, or .env files`;
20
+ - NEVER commit secrets, credentials, or .env files
21
+ - ALWAYS call \`mcp__monomind__monograph_query\` BEFORE running grep/rg/find via Bash for code exploration — only fall back to Bash grep if monograph returns 0 results or the DB does not exist
22
+ - When starting any task that touches 3+ files: call \`mcp__monomind__monograph_suggest\` first to get relevant nodes ranked by task relevance`;
21
23
  }
22
24
  function codingPrinciples() {
23
25
  return `## Coding Principles
@@ -365,28 +367,50 @@ MONOMIND_MEMORY_PATH=./data/memory
365
367
  \`\`\``;
366
368
  }
367
369
  function graphifySection() {
368
- return `## Knowledge Graph (Monograph)
369
-
370
- Built into monomind since v1.8.0 — no separate install needed. Pure TypeScript, no Python required.
371
-
372
- ### MCP Tools (prefix: \`mcp__monomind__\`)
373
-
374
- | Tool | Description |
375
- |------|-------------|
376
- | \`monograph_build\` | Build or refresh knowledge graph from codebase |
377
- | \`monograph_report\` | Generate GRAPH_REPORT.md with community breakdown |
378
- | \`monograph_suggest\` | Get refactoring/architecture suggestions from graph |
379
- | \`monograph_health\` | Check graph quality score and experiment status |
380
-
381
- ### How It Works
382
-
383
- 1. **AST extraction** parses TypeScript/JS/Python/Go/Rust into nodes + edges
384
- 2. **Community detection** — Louvain algorithm finds logical clusters
385
- 3. **Quality metric** \`graphQuality = avgCohesion × ln(1 + avgDegree)\`
386
- 4. **Experiment loop** — tracks BASELINE/KEEP/DISCARD in \`results.tsv\`
387
- 5. **BFD chunking** efficient Anthropic API calls via bin-packing
388
-
389
- > If monograph tools are not available, run \`npx monomind@latest init --force\` then restart Claude Code.`;
370
+ return `## Knowledge Graph — Monograph (Use Before Codebase Exploration)
371
+
372
+ Built into monomind — no separate install. Pure TypeScript, parses TS/JS/Python/Go/Rust/C/C++/Java/Ruby/Swift into a SQLite graph with BM25 full-text search.
373
+
374
+ ### MANDATORY: Graph-First, Grep-Last
375
+
376
+ **Before ANY grep/rg/find via Bash for code navigation:**
377
+ 1. Call \`mcp__monomind__monograph_query\` first — returns file path + line number
378
+ 2. Only fall back to Bash grep if monograph returns 0 results or reports DB missing
379
+
380
+ **When starting any task touching 3+ files:**
381
+ 1. \`mcp__monomind__monograph_suggest\` relevant nodes ranked by task description
382
+ 2. \`mcp__monomind__monograph_context\` — 360° view of a symbol (callers, callees, imports)
383
+ 3. \`mcp__monomind__monograph_impact\` blast radius before changing anything
384
+
385
+ **If graph is empty:** call \`mcp__monomind__monograph_build\` (runs in background; proceed with grep while it builds).
386
+
387
+ ### Available Tools (prefix: \`mcp__monomind__\`)
388
+
389
+ | Tool | Use when |
390
+ |------|----------|
391
+ | \`monograph_suggest\` | **Start every multi-file task** ranked by task relevance |
392
+ | \`monograph_query\` | **Primary code lookup** — BM25 search, returns file + line |
393
+ | \`monograph_context\` | 360° symbol view: callers, callees, imports, community |
394
+ | \`monograph_impact\` | Blast radius before a change — transitive callers + risk score |
395
+ | \`monograph_build\` | Build/rebuild the index (codeOnly:true for code-only) |
396
+ | \`monograph_god_nodes\` | High-centrality files — find the most connected internal nodes |
397
+ | \`monograph_detect_changes\` | Git diff → affected symbols since base branch |
398
+ | \`monograph_rename\` | Dry-run multi-file rename — all reference sites, never writes |
399
+ | \`monograph_route_map\` | List all HTTP routes with handler info |
400
+ | \`monograph_api_impact\` | Blast radius of an API route |
401
+ | \`monograph_cypher\` | Single-hop MATCH query over the graph |
402
+ | \`monograph_staleness\` | Git commits since last index build |
403
+ | \`monograph_stats\` | Node/edge/community counts |
404
+ | \`monograph_health\` | Index freshness vs current HEAD |
405
+ | \`monograph_shortest_path\` | Shortest dependency path between two symbols |
406
+ | \`monograph_community\` | All nodes in a community cluster |
407
+ | \`monograph_export\` | Export graph: json, svg, graphml, cypher, obsidian |
408
+ | \`monograph_augment\` | Graph-RAG context block for AI prompts |
409
+ | \`monograph_doctor\` | Platform diagnostics (Node version, DB health) |
410
+ | \`monograph_list_repos\` | Global registry of indexed repos |
411
+
412
+ ### Skip monograph for
413
+ Single-file edits, doc/config changes, quick fixes where you already know the exact file.`;
390
414
  }
391
415
  function setupAndBoundary() {
392
416
  return `## Quick Setup
@@ -198,6 +198,7 @@ export declare function getSchemaResource(db: Db): {
198
198
  export declare function getGraphResource(db: Db): {
199
199
  nodes: unknown[];
200
200
  edges: unknown[];
201
+ capturedAt: string;
201
202
  };
202
203
  export declare function getMonographCypher(db: Db, query: string): {
203
204
  rows: Record<string, unknown>[];
@@ -229,12 +229,14 @@ export function detectMonographChanges(db, opts, repoPath) {
229
229
  const affectedSymbols = [];
230
230
  const seenIds = new Set();
231
231
  for (const rel of changedFiles) {
232
- const abs = join(repoPath, rel);
233
- const nodes = getNodesForFile(db, abs);
232
+ // DB stores relative paths; try both relative and absolute to be safe
233
+ const nodes = getNodesForFile(db, rel).length > 0
234
+ ? getNodesForFile(db, rel)
235
+ : getNodesForFile(db, join(repoPath, rel));
234
236
  for (const n of nodes) {
235
237
  if (!seenIds.has(n.id)) {
236
238
  seenIds.add(n.id);
237
- affectedSymbols.push({ id: n.id, name: n.name, label: n.label, filePath: n.filePath ?? abs });
239
+ affectedSymbols.push({ id: n.id, name: n.name, label: n.label, filePath: n.filePath ?? rel });
238
240
  }
239
241
  }
240
242
  }
@@ -351,7 +353,8 @@ export async function getMonographStaleness(repoPath) {
351
353
  if (existsSync(dbPath)) {
352
354
  const db = openDb(dbPath);
353
355
  try {
354
- const meta = db.prepare("SELECT value FROM index_meta WHERE key = 'lastCommit'").get();
356
+ // monomind's indexer writes ua_last_commit; published monograph@1.1.0 writes lastCommit
357
+ const meta = db.prepare("SELECT value FROM index_meta WHERE key IN ('ua_last_commit','lastCommit') LIMIT 1").get();
355
358
  lastCommit = meta?.value ?? null;
356
359
  }
357
360
  finally {
@@ -379,7 +382,7 @@ export async function getMonographStaleness(repoPath) {
379
382
  catch { /* skip */ }
380
383
  if (commitsBehind > 0) {
381
384
  try {
382
- firstDivergingCommitTime = execSync(`git show -s --format=%cI ${lastCommit}..HEAD -- | head -1`, {
385
+ firstDivergingCommitTime = execSync(`git log -1 --format=%cI ${lastCommit}..HEAD`, {
383
386
  cwd: repoPath, encoding: 'utf-8',
384
387
  }).trim() || undefined;
385
388
  }
@@ -503,19 +506,17 @@ export function getSchemaResource(db) {
503
506
  }
504
507
  // 10d. getGraphResource
505
508
  export function getGraphResource(db) {
506
- let nodes = [];
507
- let edges = [];
508
509
  try {
509
510
  const snap = snapshotFromDb(db);
510
- // snapshotFromDb returns a graphology graph; export via raw SQL for a stable shape
511
- nodes = db.prepare('SELECT * FROM nodes LIMIT 2000').all();
512
- edges = db.prepare('SELECT * FROM edges LIMIT 10000').all();
511
+ return {
512
+ nodes: snap.nodes.slice(0, 2000),
513
+ edges: snap.edges.slice(0, 10000),
514
+ capturedAt: snap.capturedAt,
515
+ };
513
516
  }
514
517
  catch {
515
- nodes = db.prepare('SELECT * FROM nodes LIMIT 2000').all();
516
- edges = db.prepare('SELECT * FROM edges LIMIT 10000').all();
518
+ return { nodes: [], edges: [], capturedAt: new Date().toISOString() };
517
519
  }
518
- return { nodes, edges };
519
520
  }
520
521
  // ─── Tier 2: Best-effort / correctly-shaped degradation ───────────────────────
521
522
  // 11. getMonographCypher — minimal single-hop MATCH evaluator
@@ -694,7 +695,25 @@ export async function injectAiContext(opts) {
694
695
  const { repoPath, targets = ['claude', 'agents-md'] } = opts;
695
696
  const SENTINEL_START = '<!-- monograph:start -->';
696
697
  const SENTINEL_END = '<!-- monograph:end -->';
697
- const block = `${SENTINEL_START}\n## Monograph Knowledge Graph\n\nMonograph provides code intelligence via graph-based search.\nTools: monograph_query, monograph_context, monograph_impact, monograph_route_map, monograph_cypher.\n${SENTINEL_END}`;
698
+ const block = `${SENTINEL_START}
699
+ ## Knowledge Graph — Monograph (Use Before Codebase Exploration)
700
+
701
+ **MANDATORY: Graph-First, Grep-Last.**
702
+ Before ANY grep/rg/find via Bash for code navigation, call \`mcp__monomind__monograph_query\` first.
703
+ Only fall back to Bash grep if monograph returns 0 results or the DB is missing.
704
+
705
+ When starting any task touching 3+ files:
706
+ 1. \`mcp__monomind__monograph_suggest\` — relevant nodes ranked by task description
707
+ 2. \`mcp__monomind__monograph_context\` — 360° view of a symbol (callers, callees, imports)
708
+ 3. \`mcp__monomind__monograph_impact\` — blast radius before changing anything
709
+
710
+ Key tools: monograph_query (BM25 search, file+line), monograph_context (symbol 360°),
711
+ monograph_impact (blast radius), monograph_detect_changes (git diff → symbols),
712
+ monograph_rename (dry-run multi-file rename), monograph_route_map (HTTP routes),
713
+ monograph_cypher (single-hop graph query), monograph_augment (graph-RAG context).
714
+
715
+ If graph is empty: call monograph_build (codeOnly:true) and proceed with grep while it builds.
716
+ ${SENTINEL_END}`;
698
717
  const updated = [];
699
718
  const fileMaps = {
700
719
  'claude': join(repoPath, 'CLAUDE.md'),
@@ -901,7 +920,7 @@ export async function getGroupList(configPath) {
901
920
  try {
902
921
  const db = openDb(dbPath);
903
922
  nodeCount = countNodes(db);
904
- const meta = db.prepare("SELECT value FROM index_meta WHERE key = 'indexedAt'").get();
923
+ const meta = db.prepare("SELECT value FROM index_meta WHERE key IN ('ua_analyzed_at','indexedAt') LIMIT 1").get();
905
924
  indexedAt = meta?.value ?? null;
906
925
  closeDb(db);
907
926
  }
@@ -1028,12 +1047,12 @@ export async function getGroupStatus(configPath) {
1028
1047
  const db = openDb(dbPath);
1029
1048
  const nc = countNodes(db);
1030
1049
  const contracts = db.prepare("SELECT COUNT(*) as n FROM nodes WHERE label = 'Route'").get();
1031
- const meta = db.prepare("SELECT value FROM index_meta WHERE key = 'lastCommit'").get();
1050
+ const meta = db.prepare("SELECT value FROM index_meta WHERE key IN ('ua_last_commit','lastCommit') LIMIT 1").get();
1032
1051
  closeDb(db);
1033
1052
  groups.push({
1034
1053
  name,
1035
1054
  indexed: nc > 0,
1036
- stale: false, // we'd need git to detect; default false
1055
+ stale: false, // git-based staleness check requires repoPath; default false
1037
1056
  contractCount: contracts?.n ?? 0,
1038
1057
  ...(meta?.value ? { lastSync: meta.value } : {}),
1039
1058
  });
@@ -1055,9 +1074,9 @@ export async function serveMonograph(opts) {
1055
1074
  if (_httpServer) {
1056
1075
  return { status: 'already_running', url: _serverUrl ?? `http://localhost:${port}` };
1057
1076
  }
1058
- const nodes = opts.db.prepare('SELECT * FROM nodes LIMIT 500').all();
1059
- const edges = opts.db.prepare('SELECT * FROM edges LIMIT 3000').all();
1060
- const html = toHtml(nodes, edges);
1077
+ // snapshotFromDb returns camelCase nodes/edges as toHtml expects (filePath, communityId, sourceId, targetId)
1078
+ const snap = snapshotFromDb(opts.db);
1079
+ const html = toHtml(snap.nodes.slice(0, 500), snap.edges.slice(0, 3000));
1061
1080
  _httpServer = createServer((req, res) => {
1062
1081
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
1063
1082
  res.end(html);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monoes/monomindcli",
3
- "version": "1.11.0",
3
+ "version": "1.11.2",
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",
@@ -113,4 +113,4 @@
113
113
  "access": "public",
114
114
  "tag": "latest"
115
115
  }
116
- }
116
+ }