agentaudit 3.9.20 → 3.9.22
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 +153 -15
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -58,6 +58,7 @@ function resolveProvider(flagOverride, keys) {
|
|
|
58
58
|
// ── Global flags (set in main before command routing) ────
|
|
59
59
|
let jsonMode = false;
|
|
60
60
|
let quietMode = false;
|
|
61
|
+
let modelOverride = null; // --model flag or AGENTAUDIT_MODEL env or config
|
|
61
62
|
|
|
62
63
|
// ── ANSI Colors (respects NO_COLOR and --no-color) ───────
|
|
63
64
|
|
|
@@ -1486,7 +1487,7 @@ async function auditRepo(url) {
|
|
|
1486
1487
|
'content-type': 'application/json',
|
|
1487
1488
|
},
|
|
1488
1489
|
body: JSON.stringify({
|
|
1489
|
-
model: 'claude-sonnet-4-20250514',
|
|
1490
|
+
model: modelOverride || 'claude-sonnet-4-20250514',
|
|
1490
1491
|
max_tokens: 8192,
|
|
1491
1492
|
system: systemPrompt,
|
|
1492
1493
|
messages: [{ role: 'user', content: userMessage }],
|
|
@@ -1509,22 +1510,22 @@ async function auditRepo(url) {
|
|
|
1509
1510
|
switch (resolvedProvider.id) {
|
|
1510
1511
|
case 'openrouter':
|
|
1511
1512
|
apiUrl = 'https://openrouter.ai/api/v1/chat/completions';
|
|
1512
|
-
modelName = process.env.OPENROUTER_MODEL || 'anthropic/claude-sonnet-4';
|
|
1513
|
+
modelName = modelOverride || process.env.OPENROUTER_MODEL || 'anthropic/claude-sonnet-4';
|
|
1513
1514
|
authHeaders = { 'Authorization': `Bearer ${resolvedProvider.key}`, 'HTTP-Referer': 'https://agentaudit.dev', 'X-Title': 'AgentAudit' };
|
|
1514
1515
|
break;
|
|
1515
1516
|
case 'ollama':
|
|
1516
1517
|
apiUrl = `${resolvedProvider.host}/v1/chat/completions`;
|
|
1517
|
-
modelName = resolvedProvider.model;
|
|
1518
|
+
modelName = modelOverride || resolvedProvider.model;
|
|
1518
1519
|
authHeaders = {};
|
|
1519
1520
|
break;
|
|
1520
1521
|
case 'custom':
|
|
1521
1522
|
apiUrl = resolvedProvider.url.endsWith('/chat/completions') ? resolvedProvider.url : `${resolvedProvider.url.replace(/\/$/, '')}/chat/completions`;
|
|
1522
|
-
modelName = resolvedProvider.model;
|
|
1523
|
+
modelName = modelOverride || resolvedProvider.model;
|
|
1523
1524
|
authHeaders = resolvedProvider.key ? { 'Authorization': `Bearer ${resolvedProvider.key}` } : {};
|
|
1524
1525
|
break;
|
|
1525
1526
|
default: // openai
|
|
1526
1527
|
apiUrl = 'https://api.openai.com/v1/chat/completions';
|
|
1527
|
-
modelName = 'gpt-4o';
|
|
1528
|
+
modelName = modelOverride || 'gpt-4o';
|
|
1528
1529
|
authHeaders = { 'Authorization': `Bearer ${resolvedProvider.key}` };
|
|
1529
1530
|
}
|
|
1530
1531
|
|
|
@@ -1630,7 +1631,7 @@ async function auditRepo(url) {
|
|
|
1630
1631
|
|
|
1631
1632
|
// ── Check command ───────────────────────────────────────
|
|
1632
1633
|
|
|
1633
|
-
async function checkPackage(name) {
|
|
1634
|
+
async function checkPackage(name, { autoAudit = false } = {}) {
|
|
1634
1635
|
if (!jsonMode) {
|
|
1635
1636
|
console.log(`${icons.info} Looking up ${c.bold}${name}${c.reset} in registry...`);
|
|
1636
1637
|
console.log();
|
|
@@ -1639,8 +1640,8 @@ async function checkPackage(name) {
|
|
|
1639
1640
|
const data = await checkRegistry(name);
|
|
1640
1641
|
if (!data) {
|
|
1641
1642
|
if (!jsonMode) {
|
|
1642
|
-
//
|
|
1643
|
-
if (name.includes('github.com') || name.includes('://')) {
|
|
1643
|
+
// Auto-audit: only when called from 'check' command AND input looks like a URL
|
|
1644
|
+
if (autoAudit && (name.includes('github.com') || name.includes('://'))) {
|
|
1644
1645
|
console.log(` ${c.yellow}Not found in registry.${c.reset}`);
|
|
1645
1646
|
console.log(` ${c.dim}Starting audit for ${name}...${c.reset}`);
|
|
1646
1647
|
console.log();
|
|
@@ -1649,7 +1650,8 @@ async function checkPackage(name) {
|
|
|
1649
1650
|
console.log(` ${c.yellow}✖ Not found${c.reset} — "${name}" hasn't been audited yet.`);
|
|
1650
1651
|
console.log();
|
|
1651
1652
|
console.log(` ${c.dim}Next steps:${c.reset}`);
|
|
1652
|
-
console.log(` ${c.cyan}agentaudit
|
|
1653
|
+
console.log(` ${c.cyan}agentaudit check <repo-url>${c.reset} ${c.dim}Auto-lookup + audit if not found${c.reset}`);
|
|
1654
|
+
console.log(` ${c.cyan}agentaudit audit <repo-url>${c.reset} ${c.dim}Deep LLM audit${c.reset}`);
|
|
1653
1655
|
console.log(` ${c.cyan}agentaudit scan <repo-url>${c.reset} ${c.dim}Quick static check (no API key)${c.reset}`);
|
|
1654
1656
|
}
|
|
1655
1657
|
return null;
|
|
@@ -1731,9 +1733,25 @@ async function main() {
|
|
|
1731
1733
|
quietMode = rawArgs.includes('--quiet') || rawArgs.includes('-q');
|
|
1732
1734
|
// --no-color already handled at top level for `c` object
|
|
1733
1735
|
|
|
1736
|
+
// --model flag: --model=<name> or --model <name>
|
|
1737
|
+
const modelFlagIdx = rawArgs.findIndex(a => a === '--model');
|
|
1738
|
+
const modelFlagEq = rawArgs.find(a => a.startsWith('--model='));
|
|
1739
|
+
modelOverride = modelFlagEq?.split('=')[1]
|
|
1740
|
+
|| (modelFlagIdx >= 0 ? rawArgs[modelFlagIdx + 1] : null)
|
|
1741
|
+
|| process.env.AGENTAUDIT_MODEL
|
|
1742
|
+
|| loadConfig()?.preferred_model
|
|
1743
|
+
|| null;
|
|
1744
|
+
|
|
1734
1745
|
// Strip global flags from args
|
|
1735
1746
|
const globalFlags = new Set(['--json', '--quiet', '-q', '--no-color']);
|
|
1736
|
-
|
|
1747
|
+
let args = rawArgs.filter(a => !globalFlags.has(a));
|
|
1748
|
+
// Strip --model and its value
|
|
1749
|
+
args = args.filter((a, i, arr) => {
|
|
1750
|
+
if (a.startsWith('--model=')) return false;
|
|
1751
|
+
if (a === '--model') { arr[i + 1] = '__skip__'; return false; }
|
|
1752
|
+
if (a === '__skip__') return false;
|
|
1753
|
+
return true;
|
|
1754
|
+
});
|
|
1737
1755
|
|
|
1738
1756
|
if (args[0] === '-v' || args[0] === '--version') {
|
|
1739
1757
|
console.log(`agentaudit ${getVersion()}`);
|
|
@@ -1757,6 +1775,7 @@ async function main() {
|
|
|
1757
1775
|
console.log(` ${c.bold}SETUP${c.reset}`);
|
|
1758
1776
|
console.log(` ${c.cyan}status${c.reset} Check providers & API keys`);
|
|
1759
1777
|
console.log(` ${c.cyan}setup${c.reset} Register & configure`);
|
|
1778
|
+
console.log(` ${c.cyan}models${c.reset} List available LLM models`);
|
|
1760
1779
|
console.log(` ${c.cyan}config set${c.reset} <key> <value> Set default provider/options`);
|
|
1761
1780
|
console.log();
|
|
1762
1781
|
console.log(` ${c.bold}OPTIONS${c.reset}`);
|
|
@@ -1764,6 +1783,7 @@ async function main() {
|
|
|
1764
1783
|
console.log(` ${c.dim}--quiet Suppress banner${c.reset}`);
|
|
1765
1784
|
console.log(` ${c.dim}--no-color Disable colors ${c.reset}${c.dim}(also: NO_COLOR=1)${c.reset}`);
|
|
1766
1785
|
console.log(` ${c.dim}--provider <p> Force provider ${c.reset}${c.dim}(anthropic|openai|openrouter|ollama|custom)${c.reset}`);
|
|
1786
|
+
console.log(` ${c.dim}--model <m> Override model ${c.reset}${c.dim}(e.g. gpt-4o-mini, claude-3.5-sonnet)${c.reset}`);
|
|
1767
1787
|
console.log(` ${c.dim}--export Export audit payload to markdown${c.reset}`);
|
|
1768
1788
|
console.log(` ${c.dim}--debug Show raw LLM response on errors${c.reset}`);
|
|
1769
1789
|
console.log();
|
|
@@ -1775,7 +1795,9 @@ async function main() {
|
|
|
1775
1795
|
console.log();
|
|
1776
1796
|
console.log(` ${c.bold}PROVIDERS${c.reset} ${c.dim}(set any one for deep audits)${c.reset}`);
|
|
1777
1797
|
console.log(` ${c.dim}ANTHROPIC_API_KEY · OPENAI_API_KEY · OPENROUTER_API_KEY · OLLAMA_MODEL · LLM_API_URL${c.reset}`);
|
|
1778
|
-
console.log(` ${c.dim}Set default: AGENTAUDIT_PROVIDER=openai
|
|
1798
|
+
console.log(` ${c.dim}Set default: AGENTAUDIT_PROVIDER=openai AGENTAUDIT_MODEL=gpt-4o-mini${c.reset}`);
|
|
1799
|
+
console.log(` ${c.dim}Or persist: agentaudit config set provider openai${c.reset}`);
|
|
1800
|
+
console.log(` ${c.dim} agentaudit config set model gpt-4o-mini${c.reset}`);
|
|
1779
1801
|
console.log(` ${c.dim}Run ${c.cyan}agentaudit status${c.dim} to check configuration.${c.reset}`);
|
|
1780
1802
|
console.log();
|
|
1781
1803
|
process.exitCode = 0; return;
|
|
@@ -1858,9 +1880,11 @@ async function main() {
|
|
|
1858
1880
|
const resolved = resolveProvider(null, keys);
|
|
1859
1881
|
console.log();
|
|
1860
1882
|
if (resolved) {
|
|
1861
|
-
|
|
1862
|
-
console.log(` ${c.
|
|
1883
|
+
const activeModel = modelOverride || process.env.AGENTAUDIT_MODEL || loadConfig()?.preferred_model;
|
|
1884
|
+
console.log(` ${c.bold}Active:${c.reset} ${c.green}${resolved.label}${c.reset}${activeModel ? ` ${c.dim}model: ${activeModel}${c.reset}` : ''}`);
|
|
1885
|
+
console.log(` ${c.dim}Override: --provider=<name> --model=<name>${c.reset}`);
|
|
1863
1886
|
console.log(` ${c.dim}Set default: agentaudit config set provider <name>${c.reset}`);
|
|
1887
|
+
console.log(` ${c.dim} agentaudit config set model <name>${c.reset}`);
|
|
1864
1888
|
} else {
|
|
1865
1889
|
console.log(` ${c.yellow}⚠ No working LLM provider.${c.reset} Deep audits require one.`);
|
|
1866
1890
|
console.log(` ${c.dim}Set a key: export ANTHROPIC_API_KEY=sk-ant-...${c.reset}`);
|
|
@@ -1888,6 +1912,113 @@ async function main() {
|
|
|
1888
1912
|
return;
|
|
1889
1913
|
}
|
|
1890
1914
|
|
|
1915
|
+
if (command === 'models') {
|
|
1916
|
+
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
1917
|
+
const openaiKey = process.env.OPENAI_API_KEY;
|
|
1918
|
+
const openrouterKey = process.env.OPENROUTER_API_KEY;
|
|
1919
|
+
|
|
1920
|
+
console.log(` ${c.bold}Available models by provider:${c.reset}`);
|
|
1921
|
+
console.log();
|
|
1922
|
+
|
|
1923
|
+
// Static lists for Anthropic (no list API)
|
|
1924
|
+
console.log(` ${c.bold}Anthropic${c.reset}${anthropicKey ? ` ${c.green}(configured)${c.reset}` : ` ${c.dim}(not configured)${c.reset}`}`);
|
|
1925
|
+
console.log(` ${c.dim}claude-sonnet-4-20250514${c.reset} ${c.dim}(default)${c.reset}`);
|
|
1926
|
+
console.log(` ${c.dim}claude-opus-4-20250514${c.reset}`);
|
|
1927
|
+
console.log(` ${c.dim}claude-haiku-3-20250514${c.reset}`);
|
|
1928
|
+
console.log();
|
|
1929
|
+
|
|
1930
|
+
// Static list for OpenAI
|
|
1931
|
+
console.log(` ${c.bold}OpenAI${c.reset}${openaiKey ? ` ${c.green}(configured)${c.reset}` : ` ${c.dim}(not configured)${c.reset}`}`);
|
|
1932
|
+
console.log(` ${c.dim}gpt-4o${c.reset} ${c.dim}(default)${c.reset}`);
|
|
1933
|
+
console.log(` ${c.dim}gpt-4o-mini${c.reset}`);
|
|
1934
|
+
console.log(` ${c.dim}gpt-4.1${c.reset}`);
|
|
1935
|
+
console.log(` ${c.dim}gpt-4.1-mini${c.reset}`);
|
|
1936
|
+
console.log(` ${c.dim}o3${c.reset}`);
|
|
1937
|
+
console.log(` ${c.dim}o4-mini${c.reset}`);
|
|
1938
|
+
console.log();
|
|
1939
|
+
|
|
1940
|
+
// OpenRouter — fetch from API
|
|
1941
|
+
console.log(` ${c.bold}OpenRouter${c.reset}${openrouterKey ? ` ${c.green}(configured)${c.reset}` : ` ${c.dim}(not configured)${c.reset}`}`);
|
|
1942
|
+
if (openrouterKey || targets.includes('--all')) {
|
|
1943
|
+
process.stdout.write(` ${c.dim}Fetching models...${c.reset}`);
|
|
1944
|
+
try {
|
|
1945
|
+
const res = await fetch('https://openrouter.ai/api/v1/models', {
|
|
1946
|
+
headers: openrouterKey ? { 'Authorization': `Bearer ${openrouterKey}` } : {},
|
|
1947
|
+
signal: AbortSignal.timeout(10_000),
|
|
1948
|
+
});
|
|
1949
|
+
const data = await res.json();
|
|
1950
|
+
const models = (data.data || [])
|
|
1951
|
+
.filter(m => m.id && !m.id.includes(':free') && !m.id.includes('/extended'))
|
|
1952
|
+
.sort((a, b) => (a.id || '').localeCompare(b.id || ''));
|
|
1953
|
+
|
|
1954
|
+
// Group by provider prefix
|
|
1955
|
+
const groups = {};
|
|
1956
|
+
for (const m of models) {
|
|
1957
|
+
const [prefix] = m.id.split('/');
|
|
1958
|
+
if (!groups[prefix]) groups[prefix] = [];
|
|
1959
|
+
groups[prefix].push(m);
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
// Show popular ones first
|
|
1963
|
+
const popular = ['anthropic', 'openai', 'google', 'meta-llama', 'mistralai', 'deepseek'];
|
|
1964
|
+
const shown = new Set();
|
|
1965
|
+
process.stdout.write(`\r ${c.green}${models.length} models available${c.reset} \n`);
|
|
1966
|
+
console.log();
|
|
1967
|
+
|
|
1968
|
+
for (const prefix of popular) {
|
|
1969
|
+
if (!groups[prefix]) continue;
|
|
1970
|
+
shown.add(prefix);
|
|
1971
|
+
console.log(` ${c.bold}${prefix}${c.reset}`);
|
|
1972
|
+
for (const m of groups[prefix].slice(0, 5)) {
|
|
1973
|
+
console.log(` ${c.dim}${m.id}${c.reset}`);
|
|
1974
|
+
}
|
|
1975
|
+
if (groups[prefix].length > 5) {
|
|
1976
|
+
console.log(` ${c.dim}... and ${groups[prefix].length - 5} more${c.reset}`);
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1980
|
+
const otherCount = Object.keys(groups).filter(k => !shown.has(k)).length;
|
|
1981
|
+
if (otherCount > 0) {
|
|
1982
|
+
console.log();
|
|
1983
|
+
console.log(` ${c.dim}+ ${otherCount} more providers. Use --model=<provider/model>${c.reset}`);
|
|
1984
|
+
console.log(` ${c.dim}Full list: https://openrouter.ai/models${c.reset}`);
|
|
1985
|
+
}
|
|
1986
|
+
} catch (e) {
|
|
1987
|
+
process.stdout.write(`\r ${c.red}Failed to fetch: ${e.message}${c.reset} \n`);
|
|
1988
|
+
}
|
|
1989
|
+
} else {
|
|
1990
|
+
console.log(` ${c.dim}anthropic/claude-sonnet-4${c.reset} ${c.dim}(default)${c.reset}`);
|
|
1991
|
+
console.log(` ${c.dim}Set OPENROUTER_API_KEY to see all ${c.bold}200+${c.reset}${c.dim} models${c.reset}`);
|
|
1992
|
+
console.log(` ${c.dim}Or browse: https://openrouter.ai/models${c.reset}`);
|
|
1993
|
+
}
|
|
1994
|
+
console.log();
|
|
1995
|
+
|
|
1996
|
+
// Ollama
|
|
1997
|
+
const ollamaModel = process.env.OLLAMA_MODEL;
|
|
1998
|
+
const ollamaHost = process.env.OLLAMA_HOST || 'http://localhost:11434';
|
|
1999
|
+
console.log(` ${c.bold}Ollama${c.reset}${ollamaModel ? ` ${c.green}(configured: ${ollamaModel})${c.reset}` : ` ${c.dim}(not configured)${c.reset}`}`);
|
|
2000
|
+
if (ollamaModel || process.env.OLLAMA_HOST) {
|
|
2001
|
+
try {
|
|
2002
|
+
const res = await fetch(`${ollamaHost}/api/tags`, { signal: AbortSignal.timeout(5_000) });
|
|
2003
|
+
const data = await res.json();
|
|
2004
|
+
for (const m of (data.models || []).slice(0, 10)) {
|
|
2005
|
+
console.log(` ${c.dim}${m.name}${c.reset}`);
|
|
2006
|
+
}
|
|
2007
|
+
} catch {
|
|
2008
|
+
console.log(` ${c.dim}(Ollama not running at ${ollamaHost})${c.reset}`);
|
|
2009
|
+
}
|
|
2010
|
+
} else {
|
|
2011
|
+
console.log(` ${c.dim}Set OLLAMA_MODEL to use local models${c.reset}`);
|
|
2012
|
+
}
|
|
2013
|
+
console.log();
|
|
2014
|
+
|
|
2015
|
+
console.log(` ${c.bold}Set model:${c.reset}`);
|
|
2016
|
+
console.log(` ${c.cyan}agentaudit config set model <name>${c.reset}`);
|
|
2017
|
+
console.log(` ${c.cyan}agentaudit audit <url> --model <name>${c.reset}`);
|
|
2018
|
+
console.log(` ${c.dim}Or env: AGENTAUDIT_MODEL=<name>${c.reset}`);
|
|
2019
|
+
return;
|
|
2020
|
+
}
|
|
2021
|
+
|
|
1891
2022
|
if (command === 'config') {
|
|
1892
2023
|
const subCmd = targets[0];
|
|
1893
2024
|
if (subCmd === 'set' && targets[1] === 'provider' && targets[2]) {
|
|
@@ -1902,6 +2033,12 @@ async function main() {
|
|
|
1902
2033
|
console.log(` ${c.green}✔${c.reset} Default provider set to: ${c.bold}${val}${c.reset}`);
|
|
1903
2034
|
console.log(` ${c.dim}Override per-command: --provider=<name>${c.reset}`);
|
|
1904
2035
|
console.log(` ${c.dim}Or env: AGENTAUDIT_PROVIDER=<name>${c.reset}`);
|
|
2036
|
+
} else if (subCmd === 'set' && targets[1] === 'model' && targets[2]) {
|
|
2037
|
+
const val = targets[2];
|
|
2038
|
+
saveConfig({ preferred_model: val });
|
|
2039
|
+
console.log(` ${c.green}✔${c.reset} Default model set to: ${c.bold}${val}${c.reset}`);
|
|
2040
|
+
console.log(` ${c.dim}Override per-command: --model=<name>${c.reset}`);
|
|
2041
|
+
console.log(` ${c.dim}Or env: AGENTAUDIT_MODEL=<name>${c.reset}`);
|
|
1905
2042
|
} else if (subCmd === 'get' || !subCmd) {
|
|
1906
2043
|
const cfg = loadConfig();
|
|
1907
2044
|
console.log(` ${c.bold}Config:${c.reset} ${USER_CONFIG_FILE}`);
|
|
@@ -1933,8 +2070,9 @@ async function main() {
|
|
|
1933
2070
|
return;
|
|
1934
2071
|
}
|
|
1935
2072
|
const results = [];
|
|
2073
|
+
const allowAutoAudit = command === 'check'; // only 'check' auto-audits, 'lookup' never does
|
|
1936
2074
|
for (const t of names) {
|
|
1937
|
-
const data = await checkPackage(t);
|
|
2075
|
+
const data = await checkPackage(t, { autoAudit: allowAutoAudit });
|
|
1938
2076
|
results.push(data);
|
|
1939
2077
|
}
|
|
1940
2078
|
if (jsonMode) {
|
|
@@ -2005,7 +2143,7 @@ async function main() {
|
|
|
2005
2143
|
}
|
|
2006
2144
|
|
|
2007
2145
|
// Typo correction via Levenshtein distance
|
|
2008
|
-
const knownCommands = ['discover', 'scan', 'audit', 'check', 'lookup', 'status', 'setup', 'config'];
|
|
2146
|
+
const knownCommands = ['discover', 'scan', 'audit', 'check', 'lookup', 'status', 'setup', 'config', 'models'];
|
|
2009
2147
|
const suggestion = knownCommands
|
|
2010
2148
|
.map(cmd => ({ cmd, dist: levenshtein(command, cmd) }))
|
|
2011
2149
|
.filter(x => x.dist <= 3)
|