@monoes/monomindcli 1.10.3 → 1.10.4

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": "@monoes/monomindcli",
3
- "version": "1.10.3",
3
+ "version": "1.10.4",
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",
@@ -134,26 +134,42 @@ const ANTHROPIC_URL = 'https://api.anthropic.com/v1/messages';
134
134
  const MODEL = 'claude-haiku-4-5-20251001'; // cheapest for bulk analysis
135
135
 
136
136
  async function callClaude(systemPrompt, userPrompt, maxTokens = 1024) {
137
- const resp = await fetch(ANTHROPIC_URL, {
138
- method: 'POST',
139
- headers: {
140
- 'Content-Type': 'application/json',
141
- 'x-api-key': ANTHROPIC_API_KEY,
142
- 'anthropic-version': '2023-06-01',
143
- },
144
- body: JSON.stringify({
145
- model: MODEL,
146
- max_tokens: maxTokens,
147
- system: systemPrompt,
148
- messages: [{ role: 'user', content: userPrompt }],
149
- }),
137
+ const body = JSON.stringify({
138
+ model: MODEL,
139
+ max_tokens: maxTokens,
140
+ system: systemPrompt,
141
+ messages: [{ role: 'user', content: userPrompt }],
150
142
  });
151
- if (!resp.ok) {
152
- const text = await resp.text();
153
- throw new Error(`Anthropic API ${resp.status}: ${text.slice(0, 200)}`);
143
+ const headers = {
144
+ 'Content-Type': 'application/json',
145
+ 'x-api-key': ANTHROPIC_API_KEY,
146
+ 'anthropic-version': '2023-06-01',
147
+ };
148
+ let lastError;
149
+ for (let attempt = 0; attempt < 3; attempt++) {
150
+ try {
151
+ const resp = await fetch(ANTHROPIC_URL, { method: 'POST', headers, body });
152
+ if (resp.ok) {
153
+ const data = await resp.json();
154
+ return data.content?.[0]?.text ?? '';
155
+ }
156
+ // Retry on 429 (rate limit) and 5xx; fail fast on 4xx
157
+ if (resp.status === 429 || resp.status >= 500) {
158
+ const retryAfter = parseInt(resp.headers.get('retry-after') || '0', 10);
159
+ const backoff = retryAfter > 0 ? retryAfter * 1000 : Math.min(2 ** attempt * 1000, 8000);
160
+ await new Promise(r => setTimeout(r, backoff));
161
+ lastError = new Error(`Anthropic API ${resp.status} (attempt ${attempt + 1}/3)`);
162
+ continue;
163
+ }
164
+ const text = await resp.text();
165
+ throw new Error(`Anthropic API ${resp.status}: ${text.slice(0, 200)}`);
166
+ } catch (e) {
167
+ lastError = e;
168
+ if (attempt === 2) break;
169
+ await new Promise(r => setTimeout(r, Math.min(2 ** attempt * 1000, 4000)));
170
+ }
154
171
  }
155
- const data = await resp.json();
156
- return data.content?.[0]?.text ?? '';
172
+ throw lastError || new Error('Anthropic API failed after 3 attempts');
157
173
  }
158
174
 
159
175
  function parseJson(text) {
@@ -285,14 +301,25 @@ const isIgnoredByUser = makeIgnoreMatcher(_ignorePatterns);
285
301
 
286
302
  // ── Incremental mode helpers (ported from staleness.ts) ──────────────────────
287
303
  function getChangedFiles(dir, lastHash) {
288
- try {
289
- const out = execFileSync('git', ['diff', `${lastHash}..HEAD`, '--name-only'], {
290
- cwd: dir, encoding: 'utf-8',
291
- });
292
- return out.split('\n').map(l => l.trim()).filter(l => l.length > 0);
293
- } catch {
294
- return [];
304
+ const files = new Set();
305
+ function runGit(args) {
306
+ try {
307
+ const out = execFileSync('git', args, { cwd: dir, encoding: 'utf-8' });
308
+ for (const line of out.split('\n')) {
309
+ const trimmed = line.trim();
310
+ if (!trimmed) continue;
311
+ // `git status --porcelain` lines look like " M path/to/file" or "?? path"
312
+ // Strip the leading status code if present
313
+ const path = trimmed.length > 3 && trimmed[2] === ' ' ? trimmed.slice(3) : trimmed;
314
+ files.add(path);
315
+ }
316
+ } catch { /* git not available or no diff */ }
295
317
  }
318
+ // Committed changes since last run
319
+ runGit(['diff', `${lastHash}..HEAD`, '--name-only']);
320
+ // Uncommitted working tree changes (staged + unstaged + untracked)
321
+ runGit(['status', '--porcelain']);
322
+ return [...files];
296
323
  }
297
324
 
298
325
  function getCurrentCommitHash(dir) {
@@ -463,13 +490,20 @@ function buildOnboardingGuide(graphJson) {
463
490
  }
464
491
  }
465
492
 
493
+ const FILE_MAP_LIMIT = 50;
494
+ const HOTSPOT_LIMIT = 20;
495
+
466
496
  const fileNodes = nodes.filter(n => n.type === 'file' && n.filePath && n.summary);
467
497
  if (fileNodes.length > 0) {
468
498
  lines.push('## File Map');
469
499
  lines.push('');
500
+ if (fileNodes.length > FILE_MAP_LIMIT) {
501
+ lines.push(`Showing ${FILE_MAP_LIMIT} of ${fileNodes.length} analyzed files. See \`.understand/knowledge-graph.json\` for the full list.`);
502
+ lines.push('');
503
+ }
470
504
  lines.push('| File | Purpose | Complexity |');
471
505
  lines.push('|------|---------|------------|');
472
- for (const node of fileNodes) {
506
+ for (const node of fileNodes.slice(0, FILE_MAP_LIMIT)) {
473
507
  const summary = (node.summary || '').replace(/\|/g, '\\|');
474
508
  lines.push(`| \`${node.filePath}\` | ${summary} | ${node.complexity || 'moderate'} |`);
475
509
  }
@@ -481,8 +515,12 @@ function buildOnboardingGuide(graphJson) {
481
515
  lines.push('## Complexity Hotspots');
482
516
  lines.push('');
483
517
  lines.push('These components are the most complex and deserve extra attention:');
518
+ if (complexNodes.length > HOTSPOT_LIMIT) {
519
+ lines.push('');
520
+ lines.push(`Showing top ${HOTSPOT_LIMIT} of ${complexNodes.length} complex components.`);
521
+ }
484
522
  lines.push('');
485
- for (const node of complexNodes) {
523
+ for (const node of complexNodes.slice(0, HOTSPOT_LIMIT)) {
486
524
  lines.push(`- **${node.name}** (${node.type}): ${node.summary || ''}`);
487
525
  }
488
526
  lines.push('');
@@ -535,7 +573,18 @@ async function main() {
535
573
  process.exit(1);
536
574
  }
537
575
 
538
- const db = mg.openDb(dbPathArg);
576
+ // Retry openDb against SQLite BUSY when monograph is building in the background
577
+ let db;
578
+ for (let attempt = 0; attempt < 5; attempt++) {
579
+ try { db = mg.openDb(dbPathArg); break; }
580
+ catch (e) {
581
+ if (attempt === 4) throw e;
582
+ const msg = String(e?.message || e);
583
+ if (!/busy|locked/i.test(msg)) throw e;
584
+ console.log(`[understand] monograph.db busy, retrying in ${(attempt + 1) * 2}s...`);
585
+ await new Promise(r => setTimeout(r, (attempt + 1) * 2000));
586
+ }
587
+ }
539
588
 
540
589
  // Ensure properties column exists
541
590
  try { db.prepare(`ALTER TABLE nodes ADD COLUMN properties TEXT`).run(); } catch {}