agentaudit 3.13.2 → 3.13.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/cli.mjs +112 -18
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -994,11 +994,16 @@ function fmtPct(n) {
|
|
|
994
994
|
|
|
995
995
|
function dashboardBanner() {
|
|
996
996
|
const ver = getVersion();
|
|
997
|
+
const inner = 35;
|
|
998
|
+
const line1 = ` \u25C6 AgentAudit v${ver}`;
|
|
999
|
+
const line2 = ` Security Registry for AI Agents`;
|
|
1000
|
+
const pad1 = Math.max(0, inner - line1.length);
|
|
1001
|
+
const pad2 = Math.max(0, inner - line2.length);
|
|
997
1002
|
return [
|
|
998
|
-
` ${BOX.tl}${c.dim}${BOX.h.repeat(
|
|
999
|
-
` ${BOX.v}
|
|
1000
|
-
` ${BOX.v}
|
|
1001
|
-
` ${BOX.bl}${c.dim}${BOX.h.repeat(
|
|
1003
|
+
` ${BOX.tl}${c.dim}${BOX.h.repeat(inner)}${c.reset}${BOX.tr}`,
|
|
1004
|
+
` ${BOX.v}${c.bold}${c.cyan}${line1}${c.reset}${' '.repeat(pad1)}${BOX.v}`,
|
|
1005
|
+
` ${BOX.v}${c.dim}${line2}${c.reset}${' '.repeat(pad2)}${BOX.v}`,
|
|
1006
|
+
` ${BOX.bl}${c.dim}${BOX.h.repeat(inner)}${c.reset}${BOX.br}`,
|
|
1002
1007
|
];
|
|
1003
1008
|
}
|
|
1004
1009
|
|
|
@@ -3688,12 +3693,17 @@ async function auditRepo(url) {
|
|
|
3688
3693
|
if (modelNames.length === 1) {
|
|
3689
3694
|
activeLlm = resolveModel(modelNames[0]);
|
|
3690
3695
|
} else {
|
|
3691
|
-
activeLlm = resolveProvider();
|
|
3692
3696
|
// Model override: --model flag > AGENTAUDIT_MODEL env > credentials.json > provider default
|
|
3693
3697
|
const modelArgIdx2 = process.argv.indexOf('--model');
|
|
3694
3698
|
const modelFlag2 = modelArgIdx2 !== -1 ? process.argv[modelArgIdx2 + 1] : null;
|
|
3695
3699
|
const modelOverride = modelFlag2 || process.env.AGENTAUDIT_MODEL || loadLlmConfig()?.llm_model || null;
|
|
3696
|
-
if (
|
|
3700
|
+
if (modelOverride) {
|
|
3701
|
+
// Route through resolveModel() so slash-models go to OpenRouter, prefixes to native providers
|
|
3702
|
+
activeLlm = resolveModel(modelOverride);
|
|
3703
|
+
}
|
|
3704
|
+
if (!activeLlm) {
|
|
3705
|
+
activeLlm = resolveProvider();
|
|
3706
|
+
}
|
|
3697
3707
|
}
|
|
3698
3708
|
|
|
3699
3709
|
if (!activeLlm) {
|
|
@@ -4234,7 +4244,14 @@ async function fetchDashboardData() {
|
|
|
4234
4244
|
return { stats, leaderboard, benchmark, agent, creds };
|
|
4235
4245
|
}
|
|
4236
4246
|
|
|
4237
|
-
|
|
4247
|
+
const QUICK_ACTIONS = [
|
|
4248
|
+
{ key: 'a', label: 'Audit', arg: '<url>', desc: 'Deep LLM security audit', cmd: 'audit' },
|
|
4249
|
+
{ key: 'v', label: 'Audit --verify', arg: '<url>', desc: 'Audit + adversarial verification', cmd: 'audit-verify' },
|
|
4250
|
+
{ key: 'r', label: 'Remote scan', arg: '<url>', desc: 'Server-side scan (no API key)', cmd: 'remote' },
|
|
4251
|
+
{ key: 'c', label: 'Consensus', arg: '<pkg>', desc: 'Cross-model consensus view', cmd: 'consensus' },
|
|
4252
|
+
];
|
|
4253
|
+
|
|
4254
|
+
function renderOverviewTab(data, width, quickActionIdx = -1) {
|
|
4238
4255
|
const { stats, agent, leaderboard, creds } = data;
|
|
4239
4256
|
const lines = [];
|
|
4240
4257
|
const halfW = Math.min(Math.floor((width - 6) / 2), 40);
|
|
@@ -4325,14 +4342,17 @@ function renderOverviewTab(data, width) {
|
|
|
4325
4342
|
lines.push(` ${c.dim}Local:${c.reset} ${histParts.join(` ${c.dim}│${c.reset} `)}`);
|
|
4326
4343
|
}
|
|
4327
4344
|
|
|
4328
|
-
// Quick actions
|
|
4345
|
+
// Quick actions (interactive)
|
|
4329
4346
|
lines.push('');
|
|
4330
|
-
lines.push(` ${c.bold}Quick Actions${c.reset}`);
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4347
|
+
lines.push(` ${c.bold}Quick Actions${c.reset} ${c.dim}(press key or Enter to launch)${c.reset}`);
|
|
4348
|
+
for (let i = 0; i < QUICK_ACTIONS.length; i++) {
|
|
4349
|
+
const qa = QUICK_ACTIONS[i];
|
|
4350
|
+
const isSel = i === quickActionIdx;
|
|
4351
|
+
const pointer = isSel ? `${c.cyan}\u276F${c.reset}` : ' ';
|
|
4352
|
+
const keyBadge = `${c.dim}[${c.reset}${c.cyan}${qa.key}${c.reset}${c.dim}]${c.reset}`;
|
|
4353
|
+
const label = isSel ? `${c.bold}${c.cyan}${qa.label} ${qa.arg}${c.reset}` : `${qa.label} ${c.dim}${qa.arg}${c.reset}`;
|
|
4354
|
+
lines.push(` ${pointer} ${keyBadge} ${label} ${c.dim}${qa.desc}${c.reset}`);
|
|
4355
|
+
}
|
|
4336
4356
|
|
|
4337
4357
|
return lines;
|
|
4338
4358
|
}
|
|
@@ -4852,6 +4872,8 @@ async function dashboardCommand() {
|
|
|
4852
4872
|
let activeTab = 0;
|
|
4853
4873
|
let scrollOffset = 0;
|
|
4854
4874
|
let running = true;
|
|
4875
|
+
let quickActionIdx = 0; // selected quick action on overview tab
|
|
4876
|
+
let pendingAction = null; // set when user triggers a quick action
|
|
4855
4877
|
|
|
4856
4878
|
// Search tab state
|
|
4857
4879
|
let searchQuery = '';
|
|
@@ -4917,7 +4939,7 @@ async function dashboardCommand() {
|
|
|
4917
4939
|
let contentLines = [];
|
|
4918
4940
|
switch (activeTab) {
|
|
4919
4941
|
case 0:
|
|
4920
|
-
contentLines = renderOverviewTab(data, cols);
|
|
4942
|
+
contentLines = renderOverviewTab(data, cols, quickActionIdx);
|
|
4921
4943
|
break;
|
|
4922
4944
|
case 1:
|
|
4923
4945
|
contentLines = renderLeaderboardTab(data, cols);
|
|
@@ -4946,9 +4968,12 @@ async function dashboardCommand() {
|
|
|
4946
4968
|
output += '\n';
|
|
4947
4969
|
const scrollInfo = contentLines.length > availableRows ? ` ${c.dim}[${scrollOffset + 1}-${Math.min(scrollOffset + availableRows, contentLines.length)}/${contentLines.length}]${c.reset}` : '';
|
|
4948
4970
|
const isSearchTab = activeTab === 4;
|
|
4971
|
+
const isOverviewTab = activeTab === 0;
|
|
4949
4972
|
const footerHint = isSearchTab
|
|
4950
4973
|
? `${c.dim}\u2190\u2192 tab Enter=search Esc=clear q quit${c.reset}`
|
|
4951
|
-
:
|
|
4974
|
+
: isOverviewTab
|
|
4975
|
+
? `${c.dim}\u2190\u2192 tab \u2191\u2193 select Enter=launch a/v/r/c shortcut q quit${c.reset}`
|
|
4976
|
+
: `${c.dim}\u2190\u2192 tab \u2191\u2193 scroll 1-5 jump q quit${c.reset}`;
|
|
4952
4977
|
output += ` ${footerHint}${scrollInfo}\n`;
|
|
4953
4978
|
|
|
4954
4979
|
process.stdout.write(output);
|
|
@@ -5058,7 +5083,36 @@ async function dashboardCommand() {
|
|
|
5058
5083
|
return;
|
|
5059
5084
|
}
|
|
5060
5085
|
|
|
5061
|
-
//
|
|
5086
|
+
// Overview tab: quick action navigation + launch
|
|
5087
|
+
if (activeTab === 0) {
|
|
5088
|
+
// ↑↓ / j/k move quick action cursor
|
|
5089
|
+
if (key === '\x1b[A' || key === 'k') {
|
|
5090
|
+
quickActionIdx = (quickActionIdx - 1 + QUICK_ACTIONS.length) % QUICK_ACTIONS.length;
|
|
5091
|
+
render();
|
|
5092
|
+
return;
|
|
5093
|
+
}
|
|
5094
|
+
if (key === '\x1b[B' || key === 'j') {
|
|
5095
|
+
quickActionIdx = (quickActionIdx + 1) % QUICK_ACTIONS.length;
|
|
5096
|
+
render();
|
|
5097
|
+
return;
|
|
5098
|
+
}
|
|
5099
|
+
// Enter: launch selected quick action
|
|
5100
|
+
if (key === '\r' || key === '\n') {
|
|
5101
|
+
pendingAction = QUICK_ACTIONS[quickActionIdx].cmd;
|
|
5102
|
+
cleanup();
|
|
5103
|
+
return;
|
|
5104
|
+
}
|
|
5105
|
+
// Letter shortcuts: a/v/r/c
|
|
5106
|
+
const qaMatch = QUICK_ACTIONS.find(qa => qa.key === key);
|
|
5107
|
+
if (qaMatch) {
|
|
5108
|
+
pendingAction = qaMatch.cmd;
|
|
5109
|
+
cleanup();
|
|
5110
|
+
return;
|
|
5111
|
+
}
|
|
5112
|
+
return;
|
|
5113
|
+
}
|
|
5114
|
+
|
|
5115
|
+
// Other tabs: scroll
|
|
5062
5116
|
if (key === '\x1b[A' || key === 'k') { scrollOffset = Math.max(0, scrollOffset - 1); render(); return; }
|
|
5063
5117
|
if (key === '\x1b[B' || key === 'j') { scrollOffset++; render(); return; }
|
|
5064
5118
|
if (key === '\x1b[5~') { scrollOffset = Math.max(0, scrollOffset - 10); render(); return; }
|
|
@@ -5086,6 +5140,37 @@ async function dashboardCommand() {
|
|
|
5086
5140
|
if (!running) { clearInterval(check); resolve(); }
|
|
5087
5141
|
}, 100);
|
|
5088
5142
|
});
|
|
5143
|
+
|
|
5144
|
+
// Handle pending quick action after dashboard exits
|
|
5145
|
+
if (pendingAction) {
|
|
5146
|
+
const qa = QUICK_ACTIONS.find(q => q.cmd === pendingAction);
|
|
5147
|
+
const promptLabel = qa?.arg === '<pkg>' ? 'Package name' : 'URL to audit';
|
|
5148
|
+
console.log();
|
|
5149
|
+
const input = await askQuestion(` ${c.cyan}${promptLabel}:${c.reset} `);
|
|
5150
|
+
if (!input) {
|
|
5151
|
+
console.log(` ${c.dim}Cancelled.${c.reset}`);
|
|
5152
|
+
return;
|
|
5153
|
+
}
|
|
5154
|
+
console.log();
|
|
5155
|
+
// Build argv and re-enter main()
|
|
5156
|
+
const newArgs = ['node', 'cli.mjs'];
|
|
5157
|
+
switch (pendingAction) {
|
|
5158
|
+
case 'audit':
|
|
5159
|
+
newArgs.push('audit', input);
|
|
5160
|
+
break;
|
|
5161
|
+
case 'audit-verify':
|
|
5162
|
+
newArgs.push('audit', input, '--verify', 'self');
|
|
5163
|
+
break;
|
|
5164
|
+
case 'remote':
|
|
5165
|
+
newArgs.push('audit', input, '--remote');
|
|
5166
|
+
break;
|
|
5167
|
+
case 'consensus':
|
|
5168
|
+
newArgs.push('consensus', input);
|
|
5169
|
+
break;
|
|
5170
|
+
}
|
|
5171
|
+
process.argv = newArgs;
|
|
5172
|
+
await main();
|
|
5173
|
+
}
|
|
5089
5174
|
}
|
|
5090
5175
|
|
|
5091
5176
|
// ── Main ────────────────────────────────────────────────
|
|
@@ -6313,7 +6398,16 @@ async function main() {
|
|
|
6313
6398
|
}
|
|
6314
6399
|
|
|
6315
6400
|
if (command === 'audit') {
|
|
6316
|
-
|
|
6401
|
+
// Extract URLs: skip option flags and their values
|
|
6402
|
+
const optionsWithValues = new Set(['--model', '--verify', '--format', '--models']);
|
|
6403
|
+
const urls = [];
|
|
6404
|
+
for (let i = 0; i < targets.length; i++) {
|
|
6405
|
+
if (targets[i].startsWith('--')) {
|
|
6406
|
+
if (optionsWithValues.has(targets[i]) && i + 1 < targets.length) i++; // skip next (value)
|
|
6407
|
+
continue;
|
|
6408
|
+
}
|
|
6409
|
+
urls.push(targets[i]);
|
|
6410
|
+
}
|
|
6317
6411
|
if (urls.length === 0) {
|
|
6318
6412
|
console.log(` ${c.red}Error: at least one repository URL required${c.reset}`);
|
|
6319
6413
|
console.log(` ${c.dim}Usage: ${c.cyan}agentaudit audit <url>${c.dim} — e.g. agentaudit audit https://github.com/owner/repo${c.reset}`);
|