agentaudit 3.13.1 → 3.13.3
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 +89 -12
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -852,17 +852,45 @@ function padLeft(str, len) {
|
|
|
852
852
|
return diff > 0 ? ' '.repeat(diff) + str : str;
|
|
853
853
|
}
|
|
854
854
|
|
|
855
|
+
// Truncate a string with ANSI codes to maxLen visible characters
|
|
856
|
+
function truncateAnsi(str, maxLen) {
|
|
857
|
+
if (maxLen <= 0) return '';
|
|
858
|
+
let vis = 0;
|
|
859
|
+
let result = '';
|
|
860
|
+
let i = 0;
|
|
861
|
+
while (i < str.length) {
|
|
862
|
+
if (str[i] === '\x1b') {
|
|
863
|
+
const m = str.slice(i).match(/^\x1b\[[0-9;]*[a-zA-Z]/);
|
|
864
|
+
if (m) { result += m[0]; i += m[0].length; continue; }
|
|
865
|
+
}
|
|
866
|
+
if (vis >= maxLen) break;
|
|
867
|
+
result += str[i];
|
|
868
|
+
vis++;
|
|
869
|
+
i++;
|
|
870
|
+
}
|
|
871
|
+
return result + c.reset;
|
|
872
|
+
}
|
|
873
|
+
|
|
855
874
|
function drawBox(title, contentLines, width) {
|
|
856
875
|
const inner = width - 4; // 2 for "│ " + 2 for " │"
|
|
857
876
|
const totalDash = inner + 2; // total horizontal line chars between corners
|
|
858
877
|
const lines = [];
|
|
859
|
-
|
|
860
|
-
|
|
878
|
+
let titleStr = title ? ` ${title} ` : '';
|
|
879
|
+
let titleLen = visLen(titleStr);
|
|
880
|
+
// Clamp title if wider than available border space
|
|
881
|
+
if (titleLen >= totalDash - 1) {
|
|
882
|
+
const maxTitle = Math.max(1, totalDash - 4);
|
|
883
|
+
titleStr = ` ${title.slice(0, maxTitle)}… `;
|
|
884
|
+
titleLen = visLen(titleStr);
|
|
885
|
+
}
|
|
861
886
|
// Top: ╭─ Title ────────────╮ (1 dash before title + title + remaining dashes)
|
|
862
|
-
const topDash = BOX.h.repeat(Math.max(
|
|
887
|
+
const topDash = BOX.h.repeat(Math.max(0, totalDash - 1 - titleLen));
|
|
863
888
|
lines.push(` ${BOX.tl}${c.dim}${BOX.h}${c.reset}${c.bold}${titleStr}${c.reset}${c.dim}${topDash}${c.reset}${BOX.tr}`);
|
|
864
889
|
for (const line of contentLines) {
|
|
865
|
-
|
|
890
|
+
// Truncate content that exceeds box inner width
|
|
891
|
+
const vl = visLen(line);
|
|
892
|
+
const display = vl > inner ? truncateAnsi(line, inner - 1) + '…' : line;
|
|
893
|
+
lines.push(` ${BOX.v} ${padRight(display, inner + 1)}${BOX.v}`);
|
|
866
894
|
}
|
|
867
895
|
lines.push(` ${BOX.bl}${c.dim}${BOX.h.repeat(totalDash)}${c.reset}${BOX.br}`);
|
|
868
896
|
return lines;
|
|
@@ -3660,12 +3688,17 @@ async function auditRepo(url) {
|
|
|
3660
3688
|
if (modelNames.length === 1) {
|
|
3661
3689
|
activeLlm = resolveModel(modelNames[0]);
|
|
3662
3690
|
} else {
|
|
3663
|
-
activeLlm = resolveProvider();
|
|
3664
3691
|
// Model override: --model flag > AGENTAUDIT_MODEL env > credentials.json > provider default
|
|
3665
3692
|
const modelArgIdx2 = process.argv.indexOf('--model');
|
|
3666
3693
|
const modelFlag2 = modelArgIdx2 !== -1 ? process.argv[modelArgIdx2 + 1] : null;
|
|
3667
3694
|
const modelOverride = modelFlag2 || process.env.AGENTAUDIT_MODEL || loadLlmConfig()?.llm_model || null;
|
|
3668
|
-
if (
|
|
3695
|
+
if (modelOverride) {
|
|
3696
|
+
// Route through resolveModel() so slash-models go to OpenRouter, prefixes to native providers
|
|
3697
|
+
activeLlm = resolveModel(modelOverride);
|
|
3698
|
+
}
|
|
3699
|
+
if (!activeLlm) {
|
|
3700
|
+
activeLlm = resolveProvider();
|
|
3701
|
+
}
|
|
3669
3702
|
}
|
|
3670
3703
|
|
|
3671
3704
|
if (!activeLlm) {
|
|
@@ -4220,7 +4253,10 @@ function renderOverviewTab(data, width) {
|
|
|
4220
4253
|
const idx = leaderboard.findIndex(e => e.agent_name === creds.agent_name);
|
|
4221
4254
|
if (idx >= 0) rank = `#${idx + 1} of ${leaderboard.length}`;
|
|
4222
4255
|
}
|
|
4223
|
-
|
|
4256
|
+
const nameVis = visLen(creds.agent_name);
|
|
4257
|
+
const rankVis = visLen(rank);
|
|
4258
|
+
const nameGap = Math.max(1, halfW - nameVis - rankVis);
|
|
4259
|
+
profileLines.push(`${c.bold}${creds.agent_name}${c.reset}${' '.repeat(nameGap)}${c.dim}${rank}${c.reset}`);
|
|
4224
4260
|
profileLines.push(`Points ${c.bold}${fmtNum(agent.total_points)}${c.reset}`);
|
|
4225
4261
|
profileLines.push(`Audits ${c.bold}${fmtNum(agent.total_reports)}${c.reset}`);
|
|
4226
4262
|
profileLines.push(`Findings ${c.bold}${fmtNum(agent.total_findings_submitted)}${c.reset} ${c.dim}(${fmtNum(agent.total_findings_confirmed)} confirmed)${c.reset}`);
|
|
@@ -4255,6 +4291,15 @@ function renderOverviewTab(data, width) {
|
|
|
4255
4291
|
regLines.push(`${c.dim}Could not load registry stats${c.reset}`);
|
|
4256
4292
|
}
|
|
4257
4293
|
|
|
4294
|
+
// Local history stats
|
|
4295
|
+
const localHistory = loadHistory(50);
|
|
4296
|
+
const verifiedCount = localHistory.filter(h => h.verification).length;
|
|
4297
|
+
const localStats = {
|
|
4298
|
+
total: localHistory.length,
|
|
4299
|
+
verified: verifiedCount,
|
|
4300
|
+
lastAudit: localHistory[0] ? timeAgo(localHistory[0].timestamp || localHistory[0].date) : null,
|
|
4301
|
+
};
|
|
4302
|
+
|
|
4258
4303
|
const boxW = halfW + 4;
|
|
4259
4304
|
const profileBox = drawBox('Your Profile', profileLines, boxW);
|
|
4260
4305
|
const registryBox = drawBox('Registry', regLines, boxW);
|
|
@@ -4262,8 +4307,13 @@ function renderOverviewTab(data, width) {
|
|
|
4262
4307
|
// Side by side if wide enough, stacked otherwise
|
|
4263
4308
|
if (width >= boxW * 2 + 4) {
|
|
4264
4309
|
const maxLen = Math.max(profileBox.length, registryBox.length);
|
|
4265
|
-
|
|
4266
|
-
while (
|
|
4310
|
+
// Insert filler lines BEFORE the bottom border (last line), not after
|
|
4311
|
+
while (profileBox.length < maxLen) {
|
|
4312
|
+
profileBox.splice(profileBox.length - 1, 0, ` ${BOX.v} ${' '.repeat(halfW + 1)}${BOX.v}`);
|
|
4313
|
+
}
|
|
4314
|
+
while (registryBox.length < maxLen) {
|
|
4315
|
+
registryBox.splice(registryBox.length - 1, 0, ` ${BOX.v} ${' '.repeat(halfW + 1)}${BOX.v}`);
|
|
4316
|
+
}
|
|
4267
4317
|
for (let i = 0; i < maxLen; i++) {
|
|
4268
4318
|
lines.push(profileBox[i] + ' ' + registryBox[i].trimStart());
|
|
4269
4319
|
}
|
|
@@ -4271,6 +4321,24 @@ function renderOverviewTab(data, width) {
|
|
|
4271
4321
|
lines.push(...profileBox, '', ...registryBox);
|
|
4272
4322
|
}
|
|
4273
4323
|
|
|
4324
|
+
// Local history section
|
|
4325
|
+
lines.push('');
|
|
4326
|
+
if (localStats.total > 0) {
|
|
4327
|
+
const histParts = [`${c.bold}${localStats.total}${c.reset} local audits`];
|
|
4328
|
+
if (localStats.verified > 0) histParts.push(`${c.green}${localStats.verified} verified${c.reset}`);
|
|
4329
|
+
if (localStats.lastAudit) histParts.push(`${c.dim}last: ${localStats.lastAudit}${c.reset}`);
|
|
4330
|
+
lines.push(` ${c.dim}Local:${c.reset} ${histParts.join(` ${c.dim}│${c.reset} `)}`);
|
|
4331
|
+
}
|
|
4332
|
+
|
|
4333
|
+
// Quick actions
|
|
4334
|
+
lines.push('');
|
|
4335
|
+
lines.push(` ${c.bold}Quick Actions${c.reset}`);
|
|
4336
|
+
lines.push(` ${c.cyan}agentaudit audit <url>${c.reset} ${c.dim}Deep LLM security audit${c.reset}`);
|
|
4337
|
+
lines.push(` ${c.cyan}agentaudit audit <url> --verify${c.reset} ${c.dim}Audit + adversarial verification${c.reset}`);
|
|
4338
|
+
lines.push(` ${c.cyan}agentaudit audit <url> --remote${c.reset} ${c.dim}Server-side scan (no API key)${c.reset}`);
|
|
4339
|
+
lines.push(` ${c.cyan}agentaudit consensus <pkg>${c.reset} ${c.dim}Cross-model consensus view${c.reset}`);
|
|
4340
|
+
lines.push(` ${c.cyan}agentaudit search <query>${c.reset} ${c.dim}Search the registry${c.reset}`);
|
|
4341
|
+
|
|
4274
4342
|
return lines;
|
|
4275
4343
|
}
|
|
4276
4344
|
|
|
@@ -4292,7 +4360,7 @@ function renderLeaderboardTab(data, width, opts = {}) {
|
|
|
4292
4360
|
const entry = leaderboard[i];
|
|
4293
4361
|
const name = (entry.agent_name || '').slice(0, maxNameW);
|
|
4294
4362
|
const isMe = creds && entry.agent_name === creds.agent_name;
|
|
4295
|
-
const prefix = i < 3 ? `
|
|
4363
|
+
const prefix = i < 3 ? ` ${medals[i]} ` : ` ${c.dim}#${String(i + 1).padStart(2)}${c.reset} `;
|
|
4296
4364
|
const nameStr = isMe ? `${c.green}${c.bold}${name}${c.reset}` : name;
|
|
4297
4365
|
const bar = renderBar(entry.total_points || 0, maxPts, barW);
|
|
4298
4366
|
const pts = padLeft(`${fmtNum(entry.total_points || 0)} pts`, 12);
|
|
@@ -4724,7 +4792,7 @@ async function leaderboardCommand(args) {
|
|
|
4724
4792
|
const entry = data[i];
|
|
4725
4793
|
const name = (entry.agent_name || '').slice(0, 20);
|
|
4726
4794
|
const isMe = creds && entry.agent_name === creds.agent_name;
|
|
4727
|
-
const prefix = i < 3 ? `
|
|
4795
|
+
const prefix = i < 3 ? ` ${medals[i]} ` : ` ${c.dim}#${String(i + 1).padStart(2)}${c.reset} `;
|
|
4728
4796
|
const nameStr = isMe ? `${c.green}${c.bold}${name}${c.reset}` : name;
|
|
4729
4797
|
const bar = renderBar(entry.total_points || 0, maxPts, barW);
|
|
4730
4798
|
const pts = `${fmtNum(entry.total_points || 0)} pts`;
|
|
@@ -6250,7 +6318,16 @@ async function main() {
|
|
|
6250
6318
|
}
|
|
6251
6319
|
|
|
6252
6320
|
if (command === 'audit') {
|
|
6253
|
-
|
|
6321
|
+
// Extract URLs: skip option flags and their values
|
|
6322
|
+
const optionsWithValues = new Set(['--model', '--verify', '--format', '--models']);
|
|
6323
|
+
const urls = [];
|
|
6324
|
+
for (let i = 0; i < targets.length; i++) {
|
|
6325
|
+
if (targets[i].startsWith('--')) {
|
|
6326
|
+
if (optionsWithValues.has(targets[i]) && i + 1 < targets.length) i++; // skip next (value)
|
|
6327
|
+
continue;
|
|
6328
|
+
}
|
|
6329
|
+
urls.push(targets[i]);
|
|
6330
|
+
}
|
|
6254
6331
|
if (urls.length === 0) {
|
|
6255
6332
|
console.log(` ${c.red}Error: at least one repository URL required${c.reset}`);
|
|
6256
6333
|
console.log(` ${c.dim}Usage: ${c.cyan}agentaudit audit <url>${c.dim} — e.g. agentaudit audit https://github.com/owner/repo${c.reset}`);
|