@monoes/monomindcli 1.10.23 → 1.10.25

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,197 +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`
80
-
81
- And STOP.
43
+ If `$DB` does not exist:
44
+ > monograph.db not found at `$DB`. Build it first: `npx monomind monograph build`
82
45
 
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
71
+ ## Step 3: Per-file summarization (ONLY if `--no-llm` and `--layers-only` are both UNSET)
110
72
 
111
- Run the built-in engine. Build the command from parsed flags:
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.
112
75
 
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
- ```
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.
126
88
 
127
- The script will:
128
- 1. Read all file nodes from the monograph DB
129
- 2. Pick the best available LLM path automatically (no env vars to set):
130
- - `claude -p` CLI passthrough — reuses the active Claude Code authentication
131
- - direct Anthropic API — if `ANTHROPIC_API_KEY` happens to be set (faster for bulk runs)
132
- - heuristic-only fallback — if neither is reachable
133
- 3. For each file, generate summaries, tags, and complexity
134
- 4. Detect architectural layers
135
- 5. Write enrichment data back to `monograph.db` (community_id + properties JSON)
136
- 6. Emit a `graph.json` to `$DIR/.understand/knowledge-graph.json`
137
-
138
- Wait for the script to complete before proceeding. Do NOT pre-check or advise about
139
- `ANTHROPIC_API_KEY` — the script picks its path silently and prints the chosen mode
140
- on stdout. Report only what the script actually reports.
89
+ If `$ARGUMENTS` includes `--no-llm` or `--layers-only`, SKIP this step entirely.
141
90
 
142
91
  ---
143
92
 
144
- ## Step 5: Import (only when using an existing graph.json)
93
+ ## Step 4: Write analyses back to the DB
145
94
 
146
- If jumping here from Step 3 (existing graph.json found):
95
+ Pipe the collected analyses to a small re-import:
147
96
 
148
97
  ```bash
149
- REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
150
- IMPORT_SCRIPT="$REPO_ROOT/scripts/ua-import.mjs"
151
- # fallback: alongside understand-analyze.mjs
152
- [ ! -f "$IMPORT_SCRIPT" ] && IMPORT_SCRIPT="$(dirname $SCRIPT)/../../../scripts/ua-import.mjs"
153
- node "$IMPORT_SCRIPT" "$GRAPH_JSON" "$DB"
98
+ echo "$ANALYSES_JSON" | node "$SCRIPT" --dir "$DIR" --db "$DB" --import-analyses-stdin
154
99
  ```
155
100
 
156
- 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.)
157
102
 
158
103
  ---
159
104
 
160
- ## Step 6: Report results
161
-
162
- After the analysis or import completes, show a summary:
105
+ ## Step 5: Report
163
106
 
164
107
  ```
165
108
  ╔══════════════════════════════════════════════════╗
166
109
  ║ /monomind:understand — Enrichment Done ║
167
110
  ╠══════════════════════════════════════════════════╣
168
111
  ║ DB: .monomind/monograph.db ║
169
- Nodes enriched: <N> ║
170
- Communities: <N> (layers detected)
112
+ Files analyzed: <N> ║
113
+ LLM summaries: <N> (via active session)
114
+ ║ Layers: <N> ║
171
115
  ║ graph.json: .understand/knowledge-graph.json║
172
116
  ╚══════════════════════════════════════════════════╝
173
117
  ```
174
118
 
175
- Then tell the user:
176
- > The monograph graph is now enriched with semantic summaries and architectural layers.
177
- > Open the Monomind control panel and click **Monograph → GRAPH** to see multi-color layers.
178
- > 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.).
179
124
  >
180
- > Common follow-ups:
181
- > - `/monomind:understand --full` — full re-analysis from scratch
182
- > - `/monomind:understand --layers-only` — refresh only layer detection
183
- > - `/monomind:understand --incremental` — re-analyze only changed files
184
- > - `/monomind:understand --onboard` — generate an onboarding guide
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
185
129
 
186
130
  ---
187
131
 
188
132
  ## Error Handling
189
133
 
190
- - The script auto-selects an LLM path (`claude -p` CLI API key heuristic). Do not
191
- prompt the user to set `ANTHROPIC_API_KEY`. Monomind is designed to run inside an
192
- authenticated Claude Code session the CLI passthrough is the default path.
193
- - If the script exits non-zero, show stderr and suggest `npm install -g monomind@latest`.
194
- - If monograph.db has no file nodes, tell the user to run `npx monomind monograph build` first.
195
- - 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.
196
138
 
197
- 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.23",
3
+ "version": "1.10.25",
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",
@@ -22,8 +22,9 @@
22
22
  * --no-llm Heuristic-only mode (layers + tags from paths, no API calls)
23
23
  * --layers-only Skip per-file analysis, only (re-)detect layers
24
24
  *
25
- * Env:
26
- * ANTHROPIC_API_KEY Required unless --no-llm is set
25
+ * Designed to be invoked by the /monomind:understand slash command. The
26
+ * slash command runs the script in --no-llm mode and orchestrates the
27
+ * per-file summarization through the active Claude Code session.
27
28
  */
28
29
 
29
30
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
@@ -129,60 +130,16 @@ function detectLayersHeuristic(fileNodes) {
129
130
  }
130
131
 
131
132
  // ── 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.
133
+ // LLM enrichment requires ANTHROPIC_API_KEY. When the script is invoked from
134
+ // inside a Claude Code session via /monomind:understand, the slash command
135
+ // orchestrates the LLM work inline (using the active session)the script
136
+ // itself runs in --no-llm heuristic mode in that flow. Attempting to spawn
137
+ // `claude -p` from a nested subprocess does NOT work (the nested CLI hangs
138
+ // indefinitely), so we no longer try that path.
137
139
  const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;
138
140
  const ANTHROPIC_URL = 'https://api.anthropic.com/v1/messages';
139
141
  const MODEL = 'claude-haiku-4-5-20251001'; // cheapest for bulk analysis
140
142
 
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
- // NOTE: do NOT pass --bare here. --bare disables OAuth/keychain reads
157
- // and forces ANTHROPIC_API_KEY — which is exactly what we're avoiding.
158
- // We want the CLI to use the user's logged-in Claude Code session.
159
- const args = [
160
- '-p',
161
- '--model', 'haiku',
162
- '--output-format', 'text',
163
- '--disable-slash-commands', // skip skill auto-resolution overhead
164
- `${systemPrompt}\n\n---\n\n${userPrompt}`,
165
- ];
166
- const child = spawn(_claudeCliPath, args, {
167
- stdio: ['ignore', 'pipe', 'pipe'],
168
- env: { ...process.env },
169
- });
170
- let out = '', err = '';
171
- child.stdout.on('data', d => out += d.toString());
172
- child.stderr.on('data', d => err += d.toString());
173
- const timeout = setTimeout(() => {
174
- child.kill('SIGKILL');
175
- reject(new Error('claude -p timed out after 120s'));
176
- }, 120000);
177
- child.on('close', code => {
178
- clearTimeout(timeout);
179
- if (code !== 0) return reject(new Error(`claude -p exited ${code}: ${err.slice(0, 200)}`));
180
- resolveP(out.trim());
181
- });
182
- child.on('error', e => { clearTimeout(timeout); reject(e); });
183
- });
184
- }
185
-
186
143
  async function callClaudeViaApi(systemPrompt, userPrompt, maxTokens = 1024) {
187
144
  const body = JSON.stringify({
188
145
  model: MODEL,
@@ -225,10 +182,7 @@ async function callClaude(systemPrompt, userPrompt, maxTokens = 1024) {
225
182
  if (ANTHROPIC_API_KEY) {
226
183
  return callClaudeViaApi(systemPrompt, userPrompt, maxTokens);
227
184
  }
228
- if (USE_CLAUDE_CLI) {
229
- return callClaudeViaCli(systemPrompt, userPrompt, maxTokens);
230
- }
231
- throw new Error('No LLM path available: set ANTHROPIC_API_KEY or install `claude` CLI');
185
+ throw new Error('No LLM path available. Use /monomind:understand from inside Claude Code — the slash command orchestrates LLM work through the active session.');
232
186
  }
233
187
 
234
188
  function parseJson(text) {
@@ -632,10 +586,36 @@ async function main() {
632
586
  process.exit(1);
633
587
  }
634
588
 
589
+ // Detect non-local filesystems where better-sqlite3 can't acquire file locks
590
+ // (NFS, SMB, FUSE volumes — typically /Volumes/* on macOS or /mnt/* on Linux).
591
+ // When detected, copy the DB to /tmp, work there, copy back atomically at end.
592
+ let workingDbPath = dbPathArg;
593
+ let dbWasShadowed = false;
594
+ let originalDbPath = dbPathArg;
595
+ const isNetworkFs = /^\/Volumes\//.test(dbPathArg) ||
596
+ /^\/mnt\//.test(dbPathArg) ||
597
+ /^\/media\//.test(dbPathArg) ||
598
+ /^\\\\/.test(dbPathArg); // UNC paths on Windows
599
+ if (isNetworkFs && !dryRun) {
600
+ const os = await import('node:os');
601
+ const crypto = await import('node:crypto');
602
+ const tmpName = 'monograph-work-' + crypto.randomBytes(6).toString('hex') + '.db';
603
+ workingDbPath = join(os.tmpdir(), tmpName);
604
+ try {
605
+ console.log(`[understand] DB is on a non-local filesystem (${dbPathArg}). Copying to ${workingDbPath} to avoid SQLite lock issues...`);
606
+ const { copyFileSync } = await import('node:fs');
607
+ copyFileSync(originalDbPath, workingDbPath);
608
+ dbWasShadowed = true;
609
+ } catch (e) {
610
+ console.warn(`[understand] Could not copy to /tmp (${e.message}). Trying in place...`);
611
+ workingDbPath = dbPathArg;
612
+ }
613
+ }
614
+
635
615
  // Retry openDb against SQLite BUSY when monograph is building in the background
636
616
  let db;
637
617
  for (let attempt = 0; attempt < 5; attempt++) {
638
- try { db = mg.openDb(dbPathArg); break; }
618
+ try { db = mg.openDb(workingDbPath); break; }
639
619
  catch (e) {
640
620
  if (attempt === 4) throw e;
641
621
  const msg = String(e?.message || e);
@@ -699,22 +679,13 @@ async function main() {
699
679
  const batch = toAnalyze.slice(0, limit);
700
680
  console.log(`[understand] Analyzing ${batch.length} files (${toAnalyze.length - batch.length} skipped/already enriched)`);
701
681
 
702
- // Prefer the CLI passthrough when available monomind is designed to run
703
- // inside an authenticated Claude Code session and the CLI reuses that auth
704
- // without prompting for an API key. Direct API only takes precedence when
705
- // explicitly opted into (MONOMIND_PREFER_API=1).
706
- const preferApi = process.env.MONOMIND_PREFER_API === '1';
707
- const llmPath = (preferApi && ANTHROPIC_API_KEY) ? 'api'
708
- : USE_CLAUDE_CLI ? 'claude-cli'
709
- : ANTHROPIC_API_KEY ? 'api'
710
- : 'none';
682
+ // LLM path determined automatically. The script does NOT advise on
683
+ // credentials orchestration is the slash command's job.
684
+ const llmPath = ANTHROPIC_API_KEY ? 'api' : 'none';
711
685
  if (llmPath === 'none' && !noLlm) {
712
- console.warn('[understand] No LLM path available — `claude` CLI not found on PATH and ANTHROPIC_API_KEY not set. Running in heuristic mode.');
713
- console.warn('[understand] Tip: install Claude Code or set ANTHROPIC_API_KEY to enable per-file summaries.');
714
- } else if (llmPath === 'claude-cli' && !noLlm) {
715
- console.log('[understand] LLM path: `claude -p` CLI passthrough (reusing Claude Code session, no key needed)');
716
- } else if (llmPath === 'api' && !noLlm) {
717
- console.log('[understand] LLM path: direct Anthropic API (ANTHROPIC_API_KEY set)');
686
+ console.log('[understand] Running in heuristic mode. For per-file summaries,');
687
+ console.log('[understand] use /monomind:understand from inside Claude Code the slash');
688
+ console.log('[understand] command orchestrates summarization through the active session.');
718
689
  }
719
690
  const useLlm = !noLlm && llmPath !== 'none';
720
691
 
@@ -863,13 +834,27 @@ async function main() {
863
834
  console.log(`║ ONBOARDING.md: ${relative(CWD, onboardOut).padEnd(31)}║`);
864
835
  }
865
836
  console.log('╚══════════════════════════════════════════════════╝');
837
+
838
+ // Copy DB back if we shadowed it on /tmp due to network FS
839
+ if (dbWasShadowed && !dryRun) {
840
+ try {
841
+ const { copyFileSync, unlinkSync } = await import('node:fs');
842
+ try { db.close(); } catch {}
843
+ console.log(`[understand] Copying enriched DB back to ${originalDbPath}...`);
844
+ copyFileSync(workingDbPath, originalDbPath);
845
+ try { unlinkSync(workingDbPath); } catch {}
846
+ } catch (e) {
847
+ console.error(`[understand] Failed to copy DB back: ${e.message}`);
848
+ console.error(`[understand] Enriched DB is at ${workingDbPath} — copy manually if needed.`);
849
+ }
850
+ }
866
851
  }
867
852
 
868
853
  // ── Detect layers and write communities to DB ────────────────────────────────
869
854
  async function detectAndWriteLayers(db, fileNodes, forceHeuristic, dryRun, dir) {
870
855
  let layers;
871
856
 
872
- if (!forceHeuristic && (ANTHROPIC_API_KEY || USE_CLAUDE_CLI)) {
857
+ if (!forceHeuristic && ANTHROPIC_API_KEY) {
873
858
  console.log('[understand] Detecting architectural layers via LLM...');
874
859
  const filePaths = fileNodes.map(n => n.file_path).filter(Boolean);
875
860
  try {