agentaudit 3.9.17 → 3.9.19
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/README.md +32 -4
- package/cli.mjs +152 -32
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -208,6 +208,7 @@ Then ask your agent: *"Check which MCP servers I have installed and audit any un
|
|
|
208
208
|
| `agentaudit audit <url>` | Deep LLM-powered 3-pass audit (~30s) | `agentaudit audit https://github.com/owner/repo` |
|
|
209
209
|
| `agentaudit lookup <name>` | Look up package in trust registry | `agentaudit lookup fastmcp` |
|
|
210
210
|
| `agentaudit check <name\|url>` | Lookup + auto-audit if not found | `agentaudit check https://github.com/owner/repo` |
|
|
211
|
+
| `agentaudit status` | Check API keys + active LLM provider | `agentaudit status` |
|
|
211
212
|
| `agentaudit setup` | Register agent + configure API key | `agentaudit setup` |
|
|
212
213
|
|
|
213
214
|
### Global Flags
|
|
@@ -217,6 +218,7 @@ Then ask your agent: *"Check which MCP servers I have installed and audit any un
|
|
|
217
218
|
| `--json` | Output machine-readable JSON to stdout |
|
|
218
219
|
| `--quiet` / `-q` | Suppress banner and decorative output (show findings only) |
|
|
219
220
|
| `--no-color` | Disable ANSI colors (also respects `NO_COLOR` env var) |
|
|
221
|
+
| `--provider <name>` | Force LLM provider (`anthropic`, `openai`, `openrouter`, `ollama`, `custom`) |
|
|
220
222
|
| `--help` / `-h` | Show help text |
|
|
221
223
|
| `-v` / `--version` | Show version |
|
|
222
224
|
|
|
@@ -433,12 +435,19 @@ export AGENTAUDIT_API_KEY=asf_your_key_here
|
|
|
433
435
|
| Variable | Description |
|
|
434
436
|
|----------|-------------|
|
|
435
437
|
| `AGENTAUDIT_API_KEY` | API key for registry access |
|
|
436
|
-
| `ANTHROPIC_API_KEY` | Anthropic API key for deep audits (Claude) |
|
|
438
|
+
| `ANTHROPIC_API_KEY` | Anthropic API key for deep audits (Claude) -- recommended |
|
|
437
439
|
| `OPENAI_API_KEY` | OpenAI API key for deep audits (GPT-4o) |
|
|
438
440
|
| `OPENROUTER_API_KEY` | OpenRouter API key (access 200+ models) |
|
|
439
441
|
| `OPENROUTER_MODEL` | Model to use via OpenRouter (default: `anthropic/claude-sonnet-4`) |
|
|
442
|
+
| `OLLAMA_MODEL` | Ollama model name for local audits (e.g. `llama3.1`, `qwen2.5-coder`) |
|
|
443
|
+
| `OLLAMA_HOST` | Ollama server URL (default: `http://localhost:11434`) |
|
|
444
|
+
| `LLM_API_URL` | Any OpenAI-compatible API endpoint (e.g. LM Studio, vLLM, Together, Groq) |
|
|
445
|
+
| `LLM_API_KEY` | API key for custom endpoint (optional if no auth needed) |
|
|
446
|
+
| `LLM_MODEL` | Model name for custom endpoint |
|
|
440
447
|
| `NO_COLOR` | Disable ANSI colors ([no-color.org](https://no-color.org)) |
|
|
441
448
|
|
|
449
|
+
> **Provider priority:** Anthropic > OpenAI > OpenRouter > Custom > Ollama. Override with `--provider=ollama` etc.
|
|
450
|
+
|
|
442
451
|
---
|
|
443
452
|
|
|
444
453
|
## 📦 Requirements
|
|
@@ -468,7 +477,7 @@ Or use without installing: `npx agentaudit`
|
|
|
468
477
|
|
|
469
478
|
### Setting up your LLM key for deep audits
|
|
470
479
|
|
|
471
|
-
The `audit` command supports **
|
|
480
|
+
The `audit` command supports **any LLM provider**. Set one of these environment variables:
|
|
472
481
|
|
|
473
482
|
```bash
|
|
474
483
|
# Linux / macOS
|
|
@@ -487,13 +496,32 @@ set OPENAI_API_KEY=sk-...
|
|
|
487
496
|
set OPENROUTER_API_KEY=sk-or-...
|
|
488
497
|
```
|
|
489
498
|
|
|
490
|
-
**Provider priority:** Anthropic > OpenAI > OpenRouter
|
|
499
|
+
**Provider priority:** Anthropic > OpenAI > OpenRouter > Custom > Ollama. Override with `--provider=<name>`.
|
|
491
500
|
|
|
492
|
-
**OpenRouter model selection:** By default
|
|
501
|
+
**OpenRouter model selection:** By default uses `anthropic/claude-sonnet-4`. Override with:
|
|
493
502
|
```bash
|
|
494
503
|
export OPENROUTER_MODEL=google/gemini-2.5-pro # or any model on openrouter.ai
|
|
495
504
|
```
|
|
496
505
|
|
|
506
|
+
**Local with Ollama (free, no API key):**
|
|
507
|
+
```bash
|
|
508
|
+
export OLLAMA_MODEL=llama3.1 # or qwen2.5-coder, deepseek-r1, etc.
|
|
509
|
+
agentaudit audit https://github.com/owner/repo
|
|
510
|
+
```
|
|
511
|
+
> Note: Local models produce lower quality audits than Claude/GPT-4o. Use for quick checks, not production security audits.
|
|
512
|
+
|
|
513
|
+
**Any OpenAI-compatible API:**
|
|
514
|
+
```bash
|
|
515
|
+
export LLM_API_URL=http://localhost:1234/v1 # LM Studio, vLLM, etc.
|
|
516
|
+
export LLM_MODEL=my-model
|
|
517
|
+
agentaudit audit https://github.com/owner/repo
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
**Check your setup:**
|
|
521
|
+
```bash
|
|
522
|
+
agentaudit status # validates all configured API keys
|
|
523
|
+
```
|
|
524
|
+
|
|
497
525
|
**Troubleshooting:** If you see `API error: Incorrect API key`, double-check your key is valid and has credits. Use `--debug` to see the full API response.
|
|
498
526
|
|
|
499
527
|
### What data is sent externally?
|
package/cli.mjs
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* agentaudit audit <repo-url> Deep LLM-powered security audit
|
|
10
10
|
* agentaudit lookup <name> Look up package in registry
|
|
11
11
|
* agentaudit check <name|url> Lookup + auto-audit if not found
|
|
12
|
+
* agentaudit status Check configured API keys + providers
|
|
12
13
|
* agentaudit setup Register + configure API key
|
|
13
14
|
*
|
|
14
15
|
* Global flags: --json, --quiet, --no-color
|
|
@@ -25,6 +26,35 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
25
26
|
const SKILL_DIR = path.resolve(__dirname);
|
|
26
27
|
const REGISTRY_URL = 'https://agentaudit.dev';
|
|
27
28
|
|
|
29
|
+
// ── Provider resolution ────
|
|
30
|
+
function resolveProvider(preferred, keys) {
|
|
31
|
+
const orModel = process.env.OPENROUTER_MODEL || 'anthropic/claude-sonnet-4';
|
|
32
|
+
const ollamaModel = process.env.OLLAMA_MODEL || 'llama3.1';
|
|
33
|
+
const ollamaHost = process.env.OLLAMA_HOST || 'http://localhost:11434';
|
|
34
|
+
const customUrl = process.env.LLM_API_URL;
|
|
35
|
+
const customKey = process.env.LLM_API_KEY;
|
|
36
|
+
const customModel = process.env.LLM_MODEL || 'default';
|
|
37
|
+
|
|
38
|
+
const providers = {
|
|
39
|
+
anthropic: keys.anthropicKey ? { id: 'anthropic', label: 'Anthropic (Claude)', key: keys.anthropicKey } : null,
|
|
40
|
+
openai: keys.openaiKey ? { id: 'openai', label: 'OpenAI (GPT-4o)', key: keys.openaiKey } : null,
|
|
41
|
+
openrouter: keys.openrouterKey ? { id: 'openrouter', label: `OpenRouter (${orModel})`, key: keys.openrouterKey } : null,
|
|
42
|
+
ollama: process.env.OLLAMA_MODEL || process.env.OLLAMA_HOST ? { id: 'ollama', label: `Ollama (${ollamaModel})`, key: null, host: ollamaHost, model: ollamaModel } : null,
|
|
43
|
+
custom: customUrl ? { id: 'custom', label: `Custom (${customModel})`, key: customKey, url: customUrl, model: customModel } : null,
|
|
44
|
+
};
|
|
45
|
+
// Aliases
|
|
46
|
+
const aliases = { claude: 'anthropic', gpt: 'openai', 'gpt-4o': 'openai', 'gpt4': 'openai', or: 'openrouter', local: 'ollama' };
|
|
47
|
+
|
|
48
|
+
if (preferred) {
|
|
49
|
+
const resolved = aliases[preferred] || preferred;
|
|
50
|
+
const p = providers[resolved];
|
|
51
|
+
if (!p) return null;
|
|
52
|
+
return p;
|
|
53
|
+
}
|
|
54
|
+
// Auto-detect priority: Anthropic > OpenAI > OpenRouter > Custom > Ollama (local last — usually weaker)
|
|
55
|
+
return providers.anthropic || providers.openai || providers.openrouter || providers.custom || providers.ollama || null;
|
|
56
|
+
}
|
|
57
|
+
|
|
28
58
|
// ── Global flags (set in main before command routing) ────
|
|
29
59
|
let jsonMode = false;
|
|
30
60
|
let quietMode = false;
|
|
@@ -1312,15 +1342,25 @@ async function auditRepo(url) {
|
|
|
1312
1342
|
const openaiKey = process.env.OPENAI_API_KEY;
|
|
1313
1343
|
const openrouterKey = process.env.OPENROUTER_API_KEY;
|
|
1314
1344
|
const openrouterModel = process.env.OPENROUTER_MODEL || 'anthropic/claude-sonnet-4';
|
|
1315
|
-
|
|
1345
|
+
|
|
1346
|
+
// --provider flag overrides auto-detection
|
|
1347
|
+
const providerFlag = process.argv.find(a => a.startsWith('--provider='))?.split('=')[1]?.toLowerCase()
|
|
1348
|
+
|| (process.argv.includes('--provider') ? process.argv[process.argv.indexOf('--provider') + 1]?.toLowerCase() : null);
|
|
1349
|
+
|
|
1350
|
+
const resolvedProvider = resolveProvider(providerFlag, { anthropicKey, openaiKey, openrouterKey });
|
|
1351
|
+
const activeProvider = resolvedProvider?.label || null;
|
|
1316
1352
|
|
|
1317
|
-
if (!
|
|
1353
|
+
if (!resolvedProvider) {
|
|
1318
1354
|
// No LLM API key — clear explanation
|
|
1319
1355
|
console.log();
|
|
1320
|
-
console.log(` ${c.yellow}No LLM
|
|
1356
|
+
console.log(` ${c.yellow}No LLM provider configured.${c.reset} The ${c.bold}audit${c.reset} command needs an LLM to analyze code.`);
|
|
1321
1357
|
console.log();
|
|
1322
|
-
console.log(` ${c.bold}Option 1: Set an API key${c.reset}`);
|
|
1323
|
-
console.log(`
|
|
1358
|
+
console.log(` ${c.bold}Option 1: Set an API key${c.reset} ${c.dim}(any one of these)${c.reset}`);
|
|
1359
|
+
console.log(` ${c.cyan}ANTHROPIC_API_KEY${c.reset} Anthropic Claude ${c.dim}(recommended)${c.reset}`);
|
|
1360
|
+
console.log(` ${c.cyan}OPENAI_API_KEY${c.reset} OpenAI GPT-4o`);
|
|
1361
|
+
console.log(` ${c.cyan}OPENROUTER_API_KEY${c.reset} OpenRouter ${c.dim}(200+ models)${c.reset}`);
|
|
1362
|
+
console.log(` ${c.cyan}OLLAMA_MODEL${c.reset} Ollama ${c.dim}(local, free, set model name)${c.reset}`);
|
|
1363
|
+
console.log(` ${c.cyan}LLM_API_URL${c.reset} Any OpenAI-compatible API ${c.dim}(+ LLM_API_KEY, LLM_MODEL)${c.reset}`);
|
|
1324
1364
|
console.log();
|
|
1325
1365
|
console.log(` ${c.dim}# Linux / macOS:${c.reset}`);
|
|
1326
1366
|
console.log(` ${c.dim}export ANTHROPIC_API_KEY=sk-ant-...${c.reset}`);
|
|
@@ -1397,11 +1437,11 @@ async function auditRepo(url) {
|
|
|
1397
1437
|
let _lastLlmText = '';
|
|
1398
1438
|
|
|
1399
1439
|
try {
|
|
1400
|
-
if (
|
|
1440
|
+
if (resolvedProvider.id === 'anthropic') {
|
|
1401
1441
|
const res = await fetch('https://api.anthropic.com/v1/messages', {
|
|
1402
1442
|
method: 'POST',
|
|
1403
1443
|
headers: {
|
|
1404
|
-
'x-api-key':
|
|
1444
|
+
'x-api-key': resolvedProvider.key,
|
|
1405
1445
|
'anthropic-version': '2023-06-01',
|
|
1406
1446
|
'content-type': 'application/json',
|
|
1407
1447
|
},
|
|
@@ -1423,20 +1463,34 @@ async function auditRepo(url) {
|
|
|
1423
1463
|
const text = data.content?.[0]?.text || '';
|
|
1424
1464
|
_lastLlmText = text;
|
|
1425
1465
|
report = extractJSON(text);
|
|
1426
|
-
} else
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1466
|
+
} else {
|
|
1467
|
+
// OpenAI, OpenRouter, Ollama, or Custom (all use OpenAI-compatible chat completions API)
|
|
1468
|
+
let apiUrl, modelName, authHeaders;
|
|
1469
|
+
switch (resolvedProvider.id) {
|
|
1470
|
+
case 'openrouter':
|
|
1471
|
+
apiUrl = 'https://openrouter.ai/api/v1/chat/completions';
|
|
1472
|
+
modelName = process.env.OPENROUTER_MODEL || 'anthropic/claude-sonnet-4';
|
|
1473
|
+
authHeaders = { 'Authorization': `Bearer ${resolvedProvider.key}`, 'HTTP-Referer': 'https://agentaudit.dev', 'X-Title': 'AgentAudit' };
|
|
1474
|
+
break;
|
|
1475
|
+
case 'ollama':
|
|
1476
|
+
apiUrl = `${resolvedProvider.host}/v1/chat/completions`;
|
|
1477
|
+
modelName = resolvedProvider.model;
|
|
1478
|
+
authHeaders = {};
|
|
1479
|
+
break;
|
|
1480
|
+
case 'custom':
|
|
1481
|
+
apiUrl = resolvedProvider.url.endsWith('/chat/completions') ? resolvedProvider.url : `${resolvedProvider.url.replace(/\/$/, '')}/chat/completions`;
|
|
1482
|
+
modelName = resolvedProvider.model;
|
|
1483
|
+
authHeaders = resolvedProvider.key ? { 'Authorization': `Bearer ${resolvedProvider.key}` } : {};
|
|
1484
|
+
break;
|
|
1485
|
+
default: // openai
|
|
1486
|
+
apiUrl = 'https://api.openai.com/v1/chat/completions';
|
|
1487
|
+
modelName = 'gpt-4o';
|
|
1488
|
+
authHeaders = { 'Authorization': `Bearer ${resolvedProvider.key}` };
|
|
1489
|
+
}
|
|
1432
1490
|
|
|
1433
1491
|
const res = await fetch(apiUrl, {
|
|
1434
1492
|
method: 'POST',
|
|
1435
|
-
headers: {
|
|
1436
|
-
'Authorization': `Bearer ${apiToken}`,
|
|
1437
|
-
'Content-Type': 'application/json',
|
|
1438
|
-
...extraHeaders,
|
|
1439
|
-
},
|
|
1493
|
+
headers: { 'Content-Type': 'application/json', ...authHeaders },
|
|
1440
1494
|
body: JSON.stringify({
|
|
1441
1495
|
model: modelName,
|
|
1442
1496
|
max_tokens: 8192,
|
|
@@ -1445,7 +1499,7 @@ async function auditRepo(url) {
|
|
|
1445
1499
|
{ role: 'user', content: userMessage },
|
|
1446
1500
|
],
|
|
1447
1501
|
}),
|
|
1448
|
-
signal: AbortSignal.timeout(120_000),
|
|
1502
|
+
signal: AbortSignal.timeout(resolvedProvider.id === 'ollama' ? 300_000 : 120_000), // Ollama: 5min (local can be slow)
|
|
1449
1503
|
});
|
|
1450
1504
|
const data = await res.json();
|
|
1451
1505
|
if (data.error) {
|
|
@@ -1656,12 +1710,14 @@ async function main() {
|
|
|
1656
1710
|
console.log(` ${c.cyan}agentaudit audit${c.reset} <url> [url...] Deep LLM-powered security audit`);
|
|
1657
1711
|
console.log(` ${c.cyan}agentaudit lookup${c.reset} <name> Look up package in registry`);
|
|
1658
1712
|
console.log(` ${c.cyan}agentaudit check${c.reset} <name|url> Lookup + auto-audit if not found`);
|
|
1713
|
+
console.log(` ${c.cyan}agentaudit status${c.reset} Check API keys + active provider`);
|
|
1659
1714
|
console.log(` ${c.cyan}agentaudit setup${c.reset} Register + configure API key`);
|
|
1660
1715
|
console.log();
|
|
1661
1716
|
console.log(` ${c.bold}Global flags:${c.reset}`);
|
|
1662
1717
|
console.log(` ${c.dim}--json Output JSON to stdout (machine-readable)${c.reset}`);
|
|
1663
1718
|
console.log(` ${c.dim}--quiet Suppress banner and tree visualization${c.reset}`);
|
|
1664
1719
|
console.log(` ${c.dim}--no-color Disable ANSI colors (also: NO_COLOR env)${c.reset}`);
|
|
1720
|
+
console.log(` ${c.dim}--provider Force LLM provider (anthropic, openai, openrouter)${c.reset}`);
|
|
1665
1721
|
console.log();
|
|
1666
1722
|
console.log(` ${c.bold}Quick Scan${c.reset} vs ${c.bold}Deep Audit${c.reset}:`);
|
|
1667
1723
|
console.log(` ${c.dim}scan = fast regex-based static analysis (~2s)${c.reset}`);
|
|
@@ -1677,19 +1733,14 @@ async function main() {
|
|
|
1677
1733
|
console.log(` agentaudit audit https://github.com/owner/repo`);
|
|
1678
1734
|
console.log(` agentaudit lookup fastmcp --json`);
|
|
1679
1735
|
console.log();
|
|
1680
|
-
console.log(` ${c.bold}For deep audits,${c.reset} set an LLM
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
} else {
|
|
1689
|
-
console.log(` ${c.dim}export ANTHROPIC_API_KEY=sk-ant-...${c.reset}`);
|
|
1690
|
-
console.log(` ${c.dim}export OPENAI_API_KEY=sk-...${c.reset}`);
|
|
1691
|
-
console.log(` ${c.dim}export OPENROUTER_API_KEY=sk-or-...${c.reset} ${c.dim}(200+ models, set OPENROUTER_MODEL to pick)${c.reset}`);
|
|
1692
|
-
}
|
|
1736
|
+
console.log(` ${c.bold}For deep audits,${c.reset} set an LLM provider (any one):`);
|
|
1737
|
+
console.log(` ${c.dim}ANTHROPIC_API_KEY Anthropic Claude (recommended)${c.reset}`);
|
|
1738
|
+
console.log(` ${c.dim}OPENAI_API_KEY OpenAI GPT-4o${c.reset}`);
|
|
1739
|
+
console.log(` ${c.dim}OPENROUTER_API_KEY 200+ models (+ OPENROUTER_MODEL)${c.reset}`);
|
|
1740
|
+
console.log(` ${c.dim}OLLAMA_MODEL Local Ollama (+ OLLAMA_HOST)${c.reset}`);
|
|
1741
|
+
console.log(` ${c.dim}LLM_API_URL Any OpenAI-compatible API (+ LLM_API_KEY, LLM_MODEL)${c.reset}`);
|
|
1742
|
+
console.log();
|
|
1743
|
+
console.log(` ${c.dim}Run ${c.cyan}agentaudit status${c.dim} to check your configured providers.${c.reset}`);
|
|
1693
1744
|
console.log();
|
|
1694
1745
|
console.log(` ${c.bold}Or use as MCP server${c.reset} in Cursor/Claude ${c.dim}(no extra API key needed):${c.reset}`);
|
|
1695
1746
|
console.log(` ${c.dim}Add to your MCP config:${c.reset}`);
|
|
@@ -1709,6 +1760,75 @@ async function main() {
|
|
|
1709
1760
|
return;
|
|
1710
1761
|
}
|
|
1711
1762
|
|
|
1763
|
+
if (command === 'status') {
|
|
1764
|
+
console.log(` ${c.bold}LLM Providers:${c.reset}`);
|
|
1765
|
+
console.log();
|
|
1766
|
+
const keys = {
|
|
1767
|
+
anthropicKey: process.env.ANTHROPIC_API_KEY,
|
|
1768
|
+
openaiKey: process.env.OPENAI_API_KEY,
|
|
1769
|
+
openrouterKey: process.env.OPENROUTER_API_KEY,
|
|
1770
|
+
};
|
|
1771
|
+
const ollamaHost = process.env.OLLAMA_HOST || 'http://localhost:11434';
|
|
1772
|
+
const ollamaModel = process.env.OLLAMA_MODEL;
|
|
1773
|
+
const customUrl = process.env.LLM_API_URL;
|
|
1774
|
+
|
|
1775
|
+
const checks = [
|
|
1776
|
+
{ name: 'Anthropic', env: 'ANTHROPIC_API_KEY', key: keys.anthropicKey, testUrl: 'https://api.anthropic.com/v1/messages', testHeaders: (k) => ({ 'x-api-key': k, 'anthropic-version': '2023-06-01', 'content-type': 'application/json' }), testBody: JSON.stringify({ model: 'claude-sonnet-4-20250514', max_tokens: 1, messages: [{ role: 'user', content: 'hi' }] }) },
|
|
1777
|
+
{ name: 'OpenAI', env: 'OPENAI_API_KEY', key: keys.openaiKey, testUrl: 'https://api.openai.com/v1/models', testHeaders: (k) => ({ 'Authorization': `Bearer ${k}` }), testBody: null },
|
|
1778
|
+
{ name: 'OpenRouter', env: 'OPENROUTER_API_KEY', key: keys.openrouterKey, testUrl: 'https://openrouter.ai/api/v1/models', testHeaders: (k) => ({ 'Authorization': `Bearer ${k}` }), testBody: null },
|
|
1779
|
+
{ name: 'Ollama', env: 'OLLAMA_MODEL', key: ollamaModel, testUrl: `${ollamaHost}/api/tags`, testHeaders: () => ({}), testBody: null },
|
|
1780
|
+
{ name: 'Custom', env: 'LLM_API_URL', key: customUrl, testUrl: customUrl ? `${customUrl.replace(/\/$/, '')}/models` : null, testHeaders: (k) => process.env.LLM_API_KEY ? ({ 'Authorization': `Bearer ${process.env.LLM_API_KEY}` }) : {}, testBody: null },
|
|
1781
|
+
];
|
|
1782
|
+
|
|
1783
|
+
for (const p of checks) {
|
|
1784
|
+
if (!p.key) {
|
|
1785
|
+
console.log(` ${c.dim}○${c.reset} ${p.name.padEnd(12)} ${c.dim}not set${c.reset} ${c.dim}(${p.env})${c.reset}`);
|
|
1786
|
+
continue;
|
|
1787
|
+
}
|
|
1788
|
+
const masked = p.key.substring(0, 8) + '...' + p.key.substring(p.key.length - 4);
|
|
1789
|
+
process.stdout.write(` ${c.yellow}●${c.reset} ${p.name.padEnd(12)} ${c.dim}${masked}${c.reset} checking...`);
|
|
1790
|
+
try {
|
|
1791
|
+
const res = await fetch(p.testUrl, {
|
|
1792
|
+
method: p.testBody ? 'POST' : 'GET',
|
|
1793
|
+
headers: p.testHeaders(p.key),
|
|
1794
|
+
...(p.testBody ? { body: p.testBody } : {}),
|
|
1795
|
+
signal: AbortSignal.timeout(10_000),
|
|
1796
|
+
});
|
|
1797
|
+
if (res.ok || res.status === 200 || res.status === 201) {
|
|
1798
|
+
process.stdout.write(`\r ${c.green}●${c.reset} ${p.name.padEnd(12)} ${c.dim}${masked}${c.reset} ${c.green}valid ✓${c.reset} \n`);
|
|
1799
|
+
} else {
|
|
1800
|
+
const body = await res.json().catch(() => ({}));
|
|
1801
|
+
const errMsg = body?.error?.message || `HTTP ${res.status}`;
|
|
1802
|
+
process.stdout.write(`\r ${c.red}●${c.reset} ${p.name.padEnd(12)} ${c.dim}${masked}${c.reset} ${c.red}invalid ✗${c.reset} ${c.dim}(${errMsg})${c.reset} \n`);
|
|
1803
|
+
}
|
|
1804
|
+
} catch (e) {
|
|
1805
|
+
process.stdout.write(`\r ${c.red}●${c.reset} ${p.name.padEnd(12)} ${c.dim}${masked}${c.reset} ${c.red}error ✗${c.reset} ${c.dim}(${e.message})${c.reset} \n`);
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
const resolved = resolveProvider(null, keys);
|
|
1810
|
+
console.log();
|
|
1811
|
+
if (resolved) {
|
|
1812
|
+
console.log(` ${c.bold}Active provider:${c.reset} ${resolved.label}`);
|
|
1813
|
+
console.log(` ${c.dim}Override with: --provider=openai | --provider=openrouter | --provider=anthropic${c.reset}`);
|
|
1814
|
+
} else {
|
|
1815
|
+
console.log(` ${c.yellow}No LLM provider configured.${c.reset} Set one of the API keys above for deep audits.`);
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
// AgentAudit registry key
|
|
1819
|
+
console.log();
|
|
1820
|
+
console.log(` ${c.bold}Registry:${c.reset}`);
|
|
1821
|
+
const creds = loadCredentials();
|
|
1822
|
+
if (creds?.api_key) {
|
|
1823
|
+
const masked = creds.api_key.substring(0, 8) + '...' + creds.api_key.substring(creds.api_key.length - 4);
|
|
1824
|
+
console.log(` ${c.green}●${c.reset} AgentAudit ${c.dim}${masked}${c.reset} ${c.dim}(${creds.agent_name || 'unknown'})${c.reset}`);
|
|
1825
|
+
} else {
|
|
1826
|
+
console.log(` ${c.dim}○${c.reset} AgentAudit ${c.dim}not set${c.reset} ${c.dim}(run: agentaudit setup)${c.reset}`);
|
|
1827
|
+
}
|
|
1828
|
+
console.log();
|
|
1829
|
+
return;
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1712
1832
|
if (command === 'discover') {
|
|
1713
1833
|
const scanFlag = targets.includes('--quick') || targets.includes('--scan') || targets.includes('-s');
|
|
1714
1834
|
const auditFlag = targets.includes('--deep') || targets.includes('--audit') || targets.includes('-a');
|