agentaudit 3.9.10 → 3.9.12
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/cli.mjs +39 -29
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -343,38 +343,47 @@ function extractJSON(text) {
|
|
|
343
343
|
// 1. Try parsing the entire text as JSON directly
|
|
344
344
|
try { return JSON.parse(text.trim()); } catch {}
|
|
345
345
|
|
|
346
|
-
// 2. Strip markdown code fences (
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
try {
|
|
346
|
+
// 2. Strip markdown code fences — try last fence first (report is usually at the end)
|
|
347
|
+
const fenceMatches = [...text.matchAll(/```(?:json)?\s*\n?([\s\S]*?)\n?\s*```/g)];
|
|
348
|
+
for (let i = fenceMatches.length - 1; i >= 0; i--) {
|
|
349
|
+
try {
|
|
350
|
+
const parsed = JSON.parse(fenceMatches[i][1].trim());
|
|
351
|
+
if (parsed && typeof parsed === 'object' && ('risk_score' in parsed || 'findings' in parsed || 'result' in parsed)) return parsed;
|
|
352
|
+
} catch {}
|
|
353
|
+
}
|
|
354
|
+
// Try any fence even without report keys
|
|
355
|
+
for (let i = fenceMatches.length - 1; i >= 0; i--) {
|
|
356
|
+
try { return JSON.parse(fenceMatches[i][1].trim()); } catch {}
|
|
350
357
|
}
|
|
351
358
|
|
|
352
|
-
// 3. Find
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
depth
|
|
367
|
-
if (depth === 0) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
359
|
+
// 3. Find ALL balanced top-level { ... } blocks, try each (prefer largest valid one)
|
|
360
|
+
const blocks = [];
|
|
361
|
+
let searchFrom = 0;
|
|
362
|
+
while (searchFrom < text.length) {
|
|
363
|
+
const start = text.indexOf('{', searchFrom);
|
|
364
|
+
if (start === -1) break;
|
|
365
|
+
let depth = 0, inStr = false, esc = false;
|
|
366
|
+
let end = -1;
|
|
367
|
+
for (let i = start; i < text.length; i++) {
|
|
368
|
+
const ch = text[i];
|
|
369
|
+
if (esc) { esc = false; continue; }
|
|
370
|
+
if (ch === '\\' && inStr) { esc = true; continue; }
|
|
371
|
+
if (ch === '"') { inStr = !inStr; continue; }
|
|
372
|
+
if (inStr) continue;
|
|
373
|
+
if (ch === '{') depth++;
|
|
374
|
+
else if (ch === '}') { depth--; if (depth === 0) { end = i; break; } }
|
|
375
|
+
}
|
|
376
|
+
if (end > start) {
|
|
377
|
+
blocks.push(text.slice(start, end + 1));
|
|
378
|
+
searchFrom = end + 1;
|
|
379
|
+
} else {
|
|
380
|
+
searchFrom = start + 1;
|
|
371
381
|
}
|
|
372
382
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
const
|
|
376
|
-
|
|
377
|
-
try { return JSON.parse(greedy[0]); } catch {}
|
|
383
|
+
// Try largest block first (the report JSON is usually the biggest)
|
|
384
|
+
blocks.sort((a, b) => b.length - a.length);
|
|
385
|
+
for (const block of blocks) {
|
|
386
|
+
try { return JSON.parse(block); } catch {}
|
|
378
387
|
}
|
|
379
388
|
|
|
380
389
|
return null;
|
|
@@ -1300,6 +1309,7 @@ async function auditRepo(url) {
|
|
|
1300
1309
|
// Check for API keys to determine which LLM to use
|
|
1301
1310
|
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
1302
1311
|
const openaiKey = process.env.OPENAI_API_KEY;
|
|
1312
|
+
const activeProvider = anthropicKey ? 'Anthropic (Claude)' : openaiKey ? 'OpenAI (GPT-4o)' : null;
|
|
1303
1313
|
|
|
1304
1314
|
if (!anthropicKey && !openaiKey) {
|
|
1305
1315
|
// No LLM API key — clear explanation
|
|
@@ -1364,7 +1374,7 @@ async function auditRepo(url) {
|
|
|
1364
1374
|
}
|
|
1365
1375
|
|
|
1366
1376
|
// We have an API key — run LLM audit
|
|
1367
|
-
process.stdout.write(` ${c.dim}[4/4]${c.reset} Running LLM analysis...`);
|
|
1377
|
+
process.stdout.write(` ${c.dim}[4/4]${c.reset} Running LLM analysis ${c.dim}(${activeProvider})${c.reset}...`);
|
|
1368
1378
|
|
|
1369
1379
|
const systemPrompt = auditPrompt || 'You are a security auditor. Analyze the code and report findings as JSON.';
|
|
1370
1380
|
const userMessage = [
|