@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 +1 -1
- package/scripts/understand-analyze.mjs +77 -28
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monoes/monomindcli",
|
|
3
|
-
"version": "1.10.
|
|
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
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
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
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
-
|
|
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 {}
|