@monoes/monomindcli 1.10.22 → 1.10.24

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,191 +1,139 @@
1
1
  ---
2
2
  name: monomind:understand
3
- description: "Monomind — Run semantic enrichment on the current project's monograph knowledge graph. No external plugin needed the analysis engine ships with monomind."
3
+ description: "Monomind — Run semantic enrichment on the current project's monograph knowledge graph. Uses the active Claude Code session for LLM work no API key needed."
4
4
  ---
5
5
 
6
6
  # /monomind:understand — Semantic Enrichment
7
7
 
8
- Enriches the current project's monograph knowledge graph with LLM-generated summaries,
9
- architectural layers, and semantic relationships.
8
+ Enriches the current project's monograph knowledge graph with summaries, architectural
9
+ layers, and semantic relationships.
10
10
 
11
- The analysis engine is built into monomind no external plugin installation required.
11
+ **Designed to run inside Claude Code**uses YOUR current session for LLM work via
12
+ the Task tool. No `ANTHROPIC_API_KEY` required. The script handles layer detection
13
+ and DB writes; you (Claude) handle per-file summarization.
12
14
 
13
15
  ## Parse Arguments
14
16
 
15
- Parse `$ARGUMENTS` for these optional flags:
16
-
17
- - `--dir <path>` — project directory to analyze (default: current working directory)
18
- - `--db <path>` — path to monograph.db (default: `<dir>/.monomind/monograph.db`)
19
- - `--import` import an existing graph.json only (skip analysis, run ua-import.mjs)
20
- - `--graph <path>` explicit path to a graph.json to import (implies `--import`)
21
- - `--full` force full re-analysis even if graph.json is recent
22
- - `--no-llm` — heuristic-only mode: detect layers from file paths, no API calls
23
- - `--layers-only` — skip per-file analysis, only (re-)detect architectural layers
24
- - `--incremental` — re-analyze only files changed since the last run (uses git diff)
25
- - `--onboard` — generate an ONBOARDING.md guide from the enriched graph
26
- - `--onboard-out <path>` — where to write the onboarding guide (default: `<dir>/ONBOARDING.md`)
27
- - `--batch-size <N>` — files per LLM batch (default: 5, increase for faster analysis)
17
+ Parse `$ARGUMENTS` for these flags:
18
+
19
+ - `--dir <path>` — project directory (default: cwd)
20
+ - `--db <path>` — monograph.db path (default: `<dir>/.monomind/monograph.db`)
21
+ - `--full` force full re-analysis
22
+ - `--no-llm` heuristic-only mode (no per-file summaries)
23
+ - `--layers-only` skip per-file analysis, only re-detect layers
28
24
  - `--max-files <N>` — stop after N files (0 = all)
29
- - `--dry-run` — show what would happen without writing to DB
25
+ - `--dry-run` — show what would happen, don't write
30
26
 
31
- If no flags, treat any bare path argument as `--dir`.
27
+ Bare path argument `--dir`.
32
28
 
33
29
  ---
34
30
 
35
- ## Step 1: Locate project and monograph DB
31
+ ## Step 1: Locate project, DB, and script
36
32
 
37
33
  ```bash
38
34
  DIR="${ARGUMENTS_dir:-$(pwd)}"
39
35
  DB="${ARGUMENTS_db:-$DIR/.monomind/monograph.db}"
40
- ```
41
-
42
- 1. Resolve `DIR` to an absolute path.
43
- 2. Check that `$DB` exists. If not, tell the user:
44
- > monograph.db not found at `$DB`. Build the graph first:
45
- > ```bash
46
- > npx monomind monograph build
47
- > ```
48
- > Then re-run `/monomind:understand`.
49
- And STOP.
50
-
51
- ---
52
36
 
53
- ## Step 2: Locate the built-in analysis engine
54
-
55
- The `understand-analyze.mjs` script ships with `@monomind/cli`. Find it:
56
-
57
- ```bash
58
- # Try npm root (global install / homebrew)
37
+ # Find understand-analyze.mjs (ships with monomind globally)
59
38
  GLOBAL_ROOT=$(npm root -g 2>/dev/null)
60
- SCRIPT="$GLOBAL_ROOT/@monomind/cli/scripts/understand-analyze.mjs"
61
-
62
- # If not found globally, try npx resolve
63
- if [ ! -f "$SCRIPT" ]; then
64
- SCRIPT=$(node -e "try{console.log(require.resolve('@monomind/cli/scripts/understand-analyze.mjs'))}catch{}" 2>/dev/null)
65
- fi
66
-
67
- # Fallback: walk up from the running CLI's __dirname
68
- if [ ! -f "$SCRIPT" ]; then
69
- SCRIPT=$(node -e "
70
- const {createRequire} = require('module');
71
- const r = createRequire(require.resolve('monomind'));
72
- try { console.log(r.resolve('@monomind/cli/scripts/understand-analyze.mjs')); } catch {}
73
- " 2>/dev/null)
74
- fi
39
+ SCRIPT="$GLOBAL_ROOT/monomind/packages/@monomind/cli/scripts/understand-analyze.mjs"
40
+ [ ! -f "$SCRIPT" ] && SCRIPT="$GLOBAL_ROOT/@monoes/monomindcli/scripts/understand-analyze.mjs"
75
41
  ```
76
42
 
77
- If the script is still not found:
78
- > The built-in understand engine (understand-analyze.mjs) was not found.
79
- > Update monomind: `npm install -g monomind@latest`
43
+ If `$DB` does not exist:
44
+ > monograph.db not found at `$DB`. Build it first: `npx monomind monograph build`
80
45
 
81
- And STOP.
82
-
83
- ---
46
+ If `$SCRIPT` does not exist:
47
+ > understand engine missing. Update: `npm install -g monomind@latest`
84
48
 
85
- ## Step 3: Check for existing graph.json (unless `--full`)
49
+ In either case, STOP.
86
50
 
87
- Look for (in order):
88
- - `$DIR/.understand/knowledge-graph.json`
89
- - `$DIR/.understand/graph.json`
90
- - `$DIR/.ua/graph.json`
51
+ ---
91
52
 
92
- If `--graph <path>` was supplied, use that path directly.
53
+ ## Step 2: Run the script in heuristic mode (always — fast and deterministic)
93
54
 
94
- **If a recent graph.json is found AND `--full` was NOT set:**
55
+ This step is non-negotiable. The script handles:
56
+ - File node discovery from monograph.db
57
+ - Heuristic layer detection from file paths
58
+ - DB writes (community_id + properties)
59
+ - graph.json emission to `.understand/knowledge-graph.json`
60
+ - Auto-shadowing the DB to `/tmp` when it lives on a network FS
95
61
 
96
- Report the file age and jump to **Step 5: Import**:
97
- ```
98
- Found graph.json (X hours old) — importing into monograph…
62
+ ```bash
63
+ node "$SCRIPT" --dir "$DIR" --db "$DB" --no-llm
99
64
  ```
100
65
 
101
- **If `--import` or `--graph` was set:**
102
- Jump directly to **Step 5: Import**.
103
-
104
- **Otherwise:**
105
- Proceed to **Step 4: Run analysis**.
66
+ Wait for completion. Capture stdout. Note how many file nodes were found and how
67
+ many layers were detected. Do NOT advise the user about API keys.
106
68
 
107
69
  ---
108
70
 
109
- ## Step 4: Run built-in analysis
110
-
111
- Run the built-in engine. Build the command from parsed flags:
71
+ ## Step 3: Per-file summarization (ONLY if `--no-llm` and `--layers-only` are both UNSET)
112
72
 
113
- ```bash
114
- node "$SCRIPT" \
115
- --dir "$DIR" \
116
- --db "$DB" \
117
- [--no-llm] # if --no-llm was set
118
- [--layers-only] # if --layers-only was set
119
- [--incremental] # if --incremental was set
120
- [--onboard] # if --onboard was set
121
- [--onboard-out PATH] # if --onboard-out was set
122
- [--dry-run] # if --dry-run was set
123
- [--batch-size N] # if --batch-size was set
124
- [--max-files N] # if --max-files was set
125
- ```
126
-
127
- The script will:
128
- 1. Read all file nodes from the monograph DB
129
- 2. For each file, call the Anthropic API (via `ANTHROPIC_API_KEY`) to get summaries, tags, and complexity
130
- 3. Detect architectural layers (LLM-based if API key available, heuristic fallback otherwise)
131
- 4. Write enrichment data back to `monograph.db` (community_id + properties JSON)
132
- 5. Emit a `graph.json` to `$DIR/.understand/knowledge-graph.json`
73
+ This is where YOU (the current Claude session) do the LLM work. The script left
74
+ behind a fresh `.understand/knowledge-graph.json` with placeholder summaries.
133
75
 
134
- If `ANTHROPIC_API_KEY` is not set, the script automatically falls back to `--no-llm` mode — heuristic layer detection from file paths, no per-file summaries. Tell the user this happened.
76
+ 1. Read `.understand/knowledge-graph.json`. For each node where `properties.fileSummary`
77
+ is empty or marked `[heuristic]`, do the following:
78
+ - Use the `Read` tool on `node.file_path` (relative to `$DIR`).
79
+ - Produce a JSON object: `{ id, fileSummary, tags, complexity, functionSummaries, classSummaries }`
80
+ where:
81
+ - `fileSummary`: 1-2 sentences explaining what the file does
82
+ - `tags`: array of 2-5 short tags
83
+ - `complexity`: "simple" | "moderate" | "complex"
84
+ - `functionSummaries`: top-5 functions → 1-sentence each
85
+ - `classSummaries`: classes → 1-sentence each
86
+ 2. Process files in batches of 5 for efficiency. Use `--max-files` to cap if set.
87
+ 3. Collect all analyses into an `analyses` array.
135
88
 
136
- Wait for the script to complete before proceeding.
89
+ If `$ARGUMENTS` includes `--no-llm` or `--layers-only`, SKIP this step entirely.
137
90
 
138
91
  ---
139
92
 
140
- ## Step 5: Import (only when using an existing graph.json)
93
+ ## Step 4: Write analyses back to the DB
141
94
 
142
- If jumping here from Step 3 (existing graph.json found):
95
+ Pipe the collected analyses to a small re-import:
143
96
 
144
97
  ```bash
145
- REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
146
- IMPORT_SCRIPT="$REPO_ROOT/scripts/ua-import.mjs"
147
- # fallback: alongside understand-analyze.mjs
148
- [ ! -f "$IMPORT_SCRIPT" ] && IMPORT_SCRIPT="$(dirname $SCRIPT)/../../../scripts/ua-import.mjs"
149
- node "$IMPORT_SCRIPT" "$GRAPH_JSON" "$DB"
98
+ echo "$ANALYSES_JSON" | node "$SCRIPT" --dir "$DIR" --db "$DB" --import-analyses-stdin
150
99
  ```
151
100
 
152
- If `--dry-run` was set, report what would be imported without writing to the DB.
101
+ (If your `analyses` array is empty, skip this step.)
153
102
 
154
103
  ---
155
104
 
156
- ## Step 6: Report results
157
-
158
- After the analysis or import completes, show a summary:
105
+ ## Step 5: Report
159
106
 
160
107
  ```
161
108
  ╔══════════════════════════════════════════════════╗
162
109
  ║ /monomind:understand — Enrichment Done ║
163
110
  ╠══════════════════════════════════════════════════╣
164
111
  ║ DB: .monomind/monograph.db ║
165
- Nodes enriched: <N> ║
166
- Communities: <N> (layers detected)
112
+ Files analyzed: <N> ║
113
+ LLM summaries: <N> (via active session)
114
+ ║ Layers: <N> ║
167
115
  ║ graph.json: .understand/knowledge-graph.json║
168
116
  ╚══════════════════════════════════════════════════╝
169
117
  ```
170
118
 
171
- Then tell the user:
172
- > The monograph graph is now enriched with semantic summaries and architectural layers.
173
- > Open the Monomind control panel and click **Monograph → GRAPH** to see multi-color layers.
174
- > Each color represents an architectural layer (API, Service, Data, UI, etc.).
119
+ If LLM summaries = 0 (because `--no-llm` was set), say "heuristic-only mode — no per-file summaries written".
120
+
121
+ Then:
122
+ > Open the Monomind control panel and click **Monograph GRAPH** to see layers.
123
+ > Each color = one architectural layer (API, Service, Data, UI, etc.).
175
124
  >
176
- > To re-run with full LLM analysis: `/monomind:understand --full`
177
- > To only refresh layer detection: `/monomind:understand --layers-only`
178
- > To run without API calls: `/monomind:understand --no-llm`
179
- > To re-analyze only changed files: `/monomind:understand --incremental`
180
- > To generate an onboarding guide: `/monomind:understand --onboard`
125
+ > Follow-ups:
126
+ > - `/monomind:understand --full` — re-run from scratch
127
+ > - `/monomind:understand --layers-only` — refresh only layers
128
+ > - `/monomind:understand --no-llm` — heuristic-only mode
181
129
 
182
130
  ---
183
131
 
184
132
  ## Error Handling
185
133
 
186
- - If `ANTHROPIC_API_KEY` is not set, automatically use heuristic mode report this clearly but do NOT stop.
187
- - If the script exits non-zero, show stderr and suggest `npm install -g monomind@latest`.
188
- - If monograph.db has no file nodes, tell the user to run `npx monomind monograph build` first.
189
- - All errors are non-fatal to the main session — report and return cleanly.
134
+ - Do NOT prompt the user to set `ANTHROPIC_API_KEY`. LLM work happens in this session.
135
+ - If the script exits non-zero: show stderr and suggest `npm install -g monomind@latest`.
136
+ - If monograph.db has no file nodes: tell the user to run `npx monomind monograph build` first.
137
+ - All errors are non-fatal — report and return cleanly.
190
138
 
191
- To repeat this command on a schedule, wrap it with `/monomind:repeat`.
139
+ To re-run on a schedule: wrap with `/monomind:repeat`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monoes/monomindcli",
3
- "version": "1.10.22",
3
+ "version": "1.10.24",
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",
@@ -129,58 +129,16 @@ function detectLayersHeuristic(fileNodes) {
129
129
  }
130
130
 
131
131
  // ── Anthropic API helpers ─────────────────────────────────────────────────────
132
- // Two paths:
133
- // 1. Direct API via ANTHROPIC_API_KEY (fastest, parallel-safe, requires key)
134
- // 2. `claude -p` CLI passthrough (reuses Claude Code's authno key needed)
135
- // Slower (CLI cold-start per call), but works inside any Claude Code
136
- // session without extra setup.
132
+ // LLM enrichment requires ANTHROPIC_API_KEY. When the script is invoked from
133
+ // inside a Claude Code session via /monomind:understand, the slash command
134
+ // orchestrates the LLM work inline (using the active session)the script
135
+ // itself runs in --no-llm heuristic mode in that flow. Attempting to spawn
136
+ // `claude -p` from a nested subprocess does NOT work (the nested CLI hangs
137
+ // indefinitely), so we no longer try that path.
137
138
  const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;
138
139
  const ANTHROPIC_URL = 'https://api.anthropic.com/v1/messages';
139
140
  const MODEL = 'claude-haiku-4-5-20251001'; // cheapest for bulk analysis
140
141
 
141
- // Detect `claude` CLI once at startup.
142
- let _claudeCliPath = null;
143
- function _detectClaudeCli() {
144
- if (_claudeCliPath !== null) return _claudeCliPath;
145
- try {
146
- const out = execSync('command -v claude 2>/dev/null', { encoding: 'utf-8' }).trim();
147
- _claudeCliPath = out || '';
148
- } catch { _claudeCliPath = ''; }
149
- return _claudeCliPath;
150
- }
151
-
152
- const USE_CLAUDE_CLI = !ANTHROPIC_API_KEY && !!_detectClaudeCli();
153
-
154
- async function callClaudeViaCli(systemPrompt, userPrompt, maxTokens = 1024) {
155
- return new Promise((resolveP, reject) => {
156
- const args = [
157
- '-p',
158
- '--model', 'haiku',
159
- '--output-format', 'text',
160
- '--bare', // skip hooks/skills/auto-memory — we want a fast, clean call
161
- // Combine system + user into a single prompt argument
162
- `${systemPrompt}\n\n---\n\n${userPrompt}`,
163
- ];
164
- const child = spawn(_claudeCliPath, args, {
165
- stdio: ['ignore', 'pipe', 'pipe'],
166
- env: { ...process.env },
167
- });
168
- let out = '', err = '';
169
- child.stdout.on('data', d => out += d.toString());
170
- child.stderr.on('data', d => err += d.toString());
171
- const timeout = setTimeout(() => {
172
- child.kill('SIGKILL');
173
- reject(new Error('claude -p timed out after 60s'));
174
- }, 60000);
175
- child.on('close', code => {
176
- clearTimeout(timeout);
177
- if (code !== 0) return reject(new Error(`claude -p exited ${code}: ${err.slice(0, 200)}`));
178
- resolveP(out.trim());
179
- });
180
- child.on('error', e => { clearTimeout(timeout); reject(e); });
181
- });
182
- }
183
-
184
142
  async function callClaudeViaApi(systemPrompt, userPrompt, maxTokens = 1024) {
185
143
  const body = JSON.stringify({
186
144
  model: MODEL,
@@ -223,10 +181,7 @@ async function callClaude(systemPrompt, userPrompt, maxTokens = 1024) {
223
181
  if (ANTHROPIC_API_KEY) {
224
182
  return callClaudeViaApi(systemPrompt, userPrompt, maxTokens);
225
183
  }
226
- if (USE_CLAUDE_CLI) {
227
- return callClaudeViaCli(systemPrompt, userPrompt, maxTokens);
228
- }
229
- throw new Error('No LLM path available: set ANTHROPIC_API_KEY or install `claude` CLI');
184
+ throw new Error('No LLM path available: set ANTHROPIC_API_KEY (or use the /monomind:understand slash command, which orchestrates LLM work via the active Claude Code session)');
230
185
  }
231
186
 
232
187
  function parseJson(text) {
@@ -630,10 +585,36 @@ async function main() {
630
585
  process.exit(1);
631
586
  }
632
587
 
588
+ // Detect non-local filesystems where better-sqlite3 can't acquire file locks
589
+ // (NFS, SMB, FUSE volumes — typically /Volumes/* on macOS or /mnt/* on Linux).
590
+ // When detected, copy the DB to /tmp, work there, copy back atomically at end.
591
+ let workingDbPath = dbPathArg;
592
+ let dbWasShadowed = false;
593
+ let originalDbPath = dbPathArg;
594
+ const isNetworkFs = /^\/Volumes\//.test(dbPathArg) ||
595
+ /^\/mnt\//.test(dbPathArg) ||
596
+ /^\/media\//.test(dbPathArg) ||
597
+ /^\\\\/.test(dbPathArg); // UNC paths on Windows
598
+ if (isNetworkFs && !dryRun) {
599
+ const os = await import('node:os');
600
+ const crypto = await import('node:crypto');
601
+ const tmpName = 'monograph-work-' + crypto.randomBytes(6).toString('hex') + '.db';
602
+ workingDbPath = join(os.tmpdir(), tmpName);
603
+ try {
604
+ console.log(`[understand] DB is on a non-local filesystem (${dbPathArg}). Copying to ${workingDbPath} to avoid SQLite lock issues...`);
605
+ const { copyFileSync } = await import('node:fs');
606
+ copyFileSync(originalDbPath, workingDbPath);
607
+ dbWasShadowed = true;
608
+ } catch (e) {
609
+ console.warn(`[understand] Could not copy to /tmp (${e.message}). Trying in place...`);
610
+ workingDbPath = dbPathArg;
611
+ }
612
+ }
613
+
633
614
  // Retry openDb against SQLite BUSY when monograph is building in the background
634
615
  let db;
635
616
  for (let attempt = 0; attempt < 5; attempt++) {
636
- try { db = mg.openDb(dbPathArg); break; }
617
+ try { db = mg.openDb(workingDbPath); break; }
637
618
  catch (e) {
638
619
  if (attempt === 4) throw e;
639
620
  const msg = String(e?.message || e);
@@ -697,11 +678,19 @@ async function main() {
697
678
  const batch = toAnalyze.slice(0, limit);
698
679
  console.log(`[understand] Analyzing ${batch.length} files (${toAnalyze.length - batch.length} skipped/already enriched)`);
699
680
 
700
- const llmPath = ANTHROPIC_API_KEY ? 'api' : (USE_CLAUDE_CLI ? 'claude-cli' : 'none');
681
+ // LLM path: direct Anthropic API only. The script does NOT try to spawn
682
+ // `claude -p` from within Claude Code subprocesses — that hangs because
683
+ // nested CLI sessions aren't supported. For LLM enrichment without an API
684
+ // key, use the /monomind:understand slash command which orchestrates LLM
685
+ // work via the active Claude Code session inline.
686
+ const llmPath = ANTHROPIC_API_KEY ? 'api' : 'none';
701
687
  if (llmPath === 'none' && !noLlm) {
702
- console.warn('[understand] No LLM path available (no ANTHROPIC_API_KEY and no `claude` CLI) falling back to --no-llm heuristic mode');
703
- } else if (llmPath === 'claude-cli' && !noLlm) {
704
- console.log('[understand] Using `claude -p` CLI passthrough (no API key needed; reusing Claude Code auth)');
688
+ console.log('[understand] No ANTHROPIC_API_KEY running in heuristic mode for layer detection.');
689
+ console.log('[understand] For per-file summaries: either set ANTHROPIC_API_KEY for direct API,');
690
+ console.log('[understand] or use the /monomind:understand slash command from inside Claude Code');
691
+ console.log('[understand] (the slash command does inline analysis via the active session, no key needed).');
692
+ } else if (llmPath === 'api' && !noLlm) {
693
+ console.log('[understand] LLM path: direct Anthropic API');
705
694
  }
706
695
  const useLlm = !noLlm && llmPath !== 'none';
707
696
 
@@ -850,13 +839,27 @@ async function main() {
850
839
  console.log(`║ ONBOARDING.md: ${relative(CWD, onboardOut).padEnd(31)}║`);
851
840
  }
852
841
  console.log('╚══════════════════════════════════════════════════╝');
842
+
843
+ // Copy DB back if we shadowed it on /tmp due to network FS
844
+ if (dbWasShadowed && !dryRun) {
845
+ try {
846
+ const { copyFileSync, unlinkSync } = await import('node:fs');
847
+ try { db.close(); } catch {}
848
+ console.log(`[understand] Copying enriched DB back to ${originalDbPath}...`);
849
+ copyFileSync(workingDbPath, originalDbPath);
850
+ try { unlinkSync(workingDbPath); } catch {}
851
+ } catch (e) {
852
+ console.error(`[understand] Failed to copy DB back: ${e.message}`);
853
+ console.error(`[understand] Enriched DB is at ${workingDbPath} — copy manually if needed.`);
854
+ }
855
+ }
853
856
  }
854
857
 
855
858
  // ── Detect layers and write communities to DB ────────────────────────────────
856
859
  async function detectAndWriteLayers(db, fileNodes, forceHeuristic, dryRun, dir) {
857
860
  let layers;
858
861
 
859
- if (!forceHeuristic && (ANTHROPIC_API_KEY || USE_CLAUDE_CLI)) {
862
+ if (!forceHeuristic && ANTHROPIC_API_KEY) {
860
863
  console.log('[understand] Detecting architectural layers via LLM...');
861
864
  const filePaths = fileNodes.map(n => n.file_path).filter(Boolean);
862
865
  try {