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.
Files changed (2) hide show
  1. package/cli.mjs +112 -18
  2. 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(35)}${c.reset}${BOX.tr}`,
999
- ` ${BOX.v} ${c.bold}${c.cyan}◆ AgentAudit${c.reset} ${c.dim}v${ver}${c.reset}${' '.repeat(Math.max(0, 19 - ver.length))}${BOX.v}`,
1000
- ` ${BOX.v} ${c.dim}Security Registry for AI Agents${c.reset} ${BOX.v}`,
1001
- ` ${BOX.bl}${c.dim}${BOX.h.repeat(35)}${c.reset}${BOX.br}`,
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 (activeLlm && modelOverride) activeLlm.model = modelOverride;
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
- function renderOverviewTab(data, width) {
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
- lines.push(` ${c.cyan}agentaudit audit <url>${c.reset} ${c.dim}Deep LLM security audit${c.reset}`);
4332
- lines.push(` ${c.cyan}agentaudit audit <url> --verify${c.reset} ${c.dim}Audit + adversarial verification${c.reset}`);
4333
- lines.push(` ${c.cyan}agentaudit audit <url> --remote${c.reset} ${c.dim}Server-side scan (no API key)${c.reset}`);
4334
- lines.push(` ${c.cyan}agentaudit consensus <pkg>${c.reset} ${c.dim}Cross-model consensus view${c.reset}`);
4335
- lines.push(` ${c.cyan}agentaudit search <query>${c.reset} ${c.dim}Search the registry${c.reset}`);
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
- : `${c.dim}\u2190\u2192 tab \u2191\u2193 scroll 1-5 jump q quit${c.reset}`;
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
- // Scroll
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
- const urls = targets.filter(t => !t.startsWith('--'));
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}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentaudit",
3
- "version": "3.13.2",
3
+ "version": "3.13.4",
4
4
  "description": "Security scanner for AI agent packages — CLI + MCP server",
5
5
  "type": "module",
6
6
  "bin": {