@kevinrabun/judges 3.66.0 → 3.68.0
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/CHANGELOG.md +17 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +112 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/config-lint.d.ts +5 -0
- package/dist/commands/config-lint.d.ts.map +1 -0
- package/dist/commands/config-lint.js +188 -0
- package/dist/commands/config-lint.js.map +1 -0
- package/dist/commands/finding-age.d.ts +5 -0
- package/dist/commands/finding-age.d.ts.map +1 -0
- package/dist/commands/finding-age.js +146 -0
- package/dist/commands/finding-age.js.map +1 -0
- package/dist/commands/finding-cluster.d.ts +5 -0
- package/dist/commands/finding-cluster.d.ts.map +1 -0
- package/dist/commands/finding-cluster.js +158 -0
- package/dist/commands/finding-cluster.js.map +1 -0
- package/dist/commands/finding-hotspot.d.ts +5 -0
- package/dist/commands/finding-hotspot.d.ts.map +1 -0
- package/dist/commands/finding-hotspot.js +116 -0
- package/dist/commands/finding-hotspot.js.map +1 -0
- package/dist/commands/finding-rank.d.ts +5 -0
- package/dist/commands/finding-rank.d.ts.map +1 -0
- package/dist/commands/finding-rank.js +139 -0
- package/dist/commands/finding-rank.js.map +1 -0
- package/dist/commands/review-ab-test.d.ts +5 -0
- package/dist/commands/review-ab-test.d.ts.map +1 -0
- package/dist/commands/review-ab-test.js +225 -0
- package/dist/commands/review-ab-test.js.map +1 -0
- package/dist/commands/review-audit-log.d.ts +5 -0
- package/dist/commands/review-audit-log.d.ts.map +1 -0
- package/dist/commands/review-audit-log.js +140 -0
- package/dist/commands/review-audit-log.js.map +1 -0
- package/dist/commands/review-badge.d.ts +5 -0
- package/dist/commands/review-badge.d.ts.map +1 -0
- package/dist/commands/review-badge.js +153 -0
- package/dist/commands/review-badge.js.map +1 -0
- package/dist/commands/review-dashboard.d.ts +5 -0
- package/dist/commands/review-dashboard.d.ts.map +1 -0
- package/dist/commands/review-dashboard.js +141 -0
- package/dist/commands/review-dashboard.js.map +1 -0
- package/dist/commands/review-diff-summary.d.ts +5 -0
- package/dist/commands/review-diff-summary.d.ts.map +1 -0
- package/dist/commands/review-diff-summary.js +155 -0
- package/dist/commands/review-diff-summary.js.map +1 -0
- package/dist/commands/review-integration.d.ts +5 -0
- package/dist/commands/review-integration.d.ts.map +1 -0
- package/dist/commands/review-integration.js +237 -0
- package/dist/commands/review-integration.js.map +1 -0
- package/dist/commands/review-notify.d.ts +5 -0
- package/dist/commands/review-notify.d.ts.map +1 -0
- package/dist/commands/review-notify.js +144 -0
- package/dist/commands/review-notify.js.map +1 -0
- package/dist/commands/review-offline.d.ts +5 -0
- package/dist/commands/review-offline.d.ts.map +1 -0
- package/dist/commands/review-offline.js +126 -0
- package/dist/commands/review-offline.js.map +1 -0
- package/dist/commands/review-quota.d.ts +5 -0
- package/dist/commands/review-quota.d.ts.map +1 -0
- package/dist/commands/review-quota.js +127 -0
- package/dist/commands/review-quota.js.map +1 -0
- package/dist/commands/review-sandbox.d.ts +5 -0
- package/dist/commands/review-sandbox.d.ts.map +1 -0
- package/dist/commands/review-sandbox.js +192 -0
- package/dist/commands/review-sandbox.js.map +1 -0
- package/dist/commands/review-streak.d.ts +5 -0
- package/dist/commands/review-streak.d.ts.map +1 -0
- package/dist/commands/review-streak.js +151 -0
- package/dist/commands/review-streak.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review-audit-log — Comprehensive local audit log for compliance tracking.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
5
|
+
import { join, dirname } from "path";
|
|
6
|
+
// ─── Storage ────────────────────────────────────────────────────────────────
|
|
7
|
+
const LOG_FILE = join(".judges", "audit-log.json");
|
|
8
|
+
function loadLog() {
|
|
9
|
+
if (!existsSync(LOG_FILE))
|
|
10
|
+
return { version: "1.0.0", entries: [] };
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(readFileSync(LOG_FILE, "utf-8"));
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return { version: "1.0.0", entries: [] };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function saveLog(log) {
|
|
19
|
+
mkdirSync(dirname(LOG_FILE), { recursive: true });
|
|
20
|
+
writeFileSync(LOG_FILE, JSON.stringify(log, null, 2), "utf-8");
|
|
21
|
+
}
|
|
22
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
23
|
+
export function runReviewAuditLog(argv) {
|
|
24
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
25
|
+
console.log(`
|
|
26
|
+
judges review-audit-log — Comprehensive local audit log
|
|
27
|
+
|
|
28
|
+
Usage:
|
|
29
|
+
judges review-audit-log show Show recent audit entries
|
|
30
|
+
judges review-audit-log show --last 20 Show last N entries
|
|
31
|
+
judges review-audit-log record --action review Record an audit entry
|
|
32
|
+
judges review-audit-log search --action suppress Search by action
|
|
33
|
+
judges review-audit-log export --output log.csv Export to CSV
|
|
34
|
+
judges review-audit-log clear Clear audit log
|
|
35
|
+
|
|
36
|
+
Subcommands:
|
|
37
|
+
show Show audit entries
|
|
38
|
+
record Record a new entry
|
|
39
|
+
search Search entries
|
|
40
|
+
export Export log
|
|
41
|
+
clear Clear all entries
|
|
42
|
+
|
|
43
|
+
Options:
|
|
44
|
+
--action <type> Action type (review, suppress, approve, fix, configure, etc.)
|
|
45
|
+
--command <cmd> Command that was run
|
|
46
|
+
--result <text> Result description
|
|
47
|
+
--last <n> Show last N entries (default: 10)
|
|
48
|
+
--output <path> Export file path
|
|
49
|
+
--format json JSON output
|
|
50
|
+
--help, -h Show this help
|
|
51
|
+
|
|
52
|
+
Tracks all review actions locally for compliance and auditability.
|
|
53
|
+
Data stored in .judges/audit-log.json.
|
|
54
|
+
`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
58
|
+
const subcommand = argv.find((a) => ["show", "record", "search", "export", "clear"].includes(a)) || "show";
|
|
59
|
+
const log = loadLog();
|
|
60
|
+
if (subcommand === "record") {
|
|
61
|
+
const action = argv.find((_a, i) => argv[i - 1] === "--action") || "unknown";
|
|
62
|
+
const command = argv.find((_a, i) => argv[i - 1] === "--command") || "";
|
|
63
|
+
const result = argv.find((_a, i) => argv[i - 1] === "--result") || "success";
|
|
64
|
+
const user = process.env.USER || process.env.USERNAME || "unknown";
|
|
65
|
+
const entry = {
|
|
66
|
+
timestamp: new Date().toISOString(),
|
|
67
|
+
action,
|
|
68
|
+
command,
|
|
69
|
+
user,
|
|
70
|
+
details: {},
|
|
71
|
+
result,
|
|
72
|
+
};
|
|
73
|
+
log.entries.push(entry);
|
|
74
|
+
saveLog(log);
|
|
75
|
+
console.log(`Audit entry recorded: ${action} by ${user}`);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (subcommand === "clear") {
|
|
79
|
+
saveLog({ version: "1.0.0", entries: [] });
|
|
80
|
+
console.log("Audit log cleared.");
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (subcommand === "search") {
|
|
84
|
+
const action = argv.find((_a, i) => argv[i - 1] === "--action");
|
|
85
|
+
const filtered = action ? log.entries.filter((e) => e.action === action) : log.entries;
|
|
86
|
+
if (format === "json") {
|
|
87
|
+
console.log(JSON.stringify(filtered, null, 2));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (filtered.length === 0) {
|
|
91
|
+
console.log(`No entries found${action ? ` for action "${action}"` : ""}.`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
console.log(`\nSearch Results (${filtered.length} entries):`);
|
|
95
|
+
console.log("─".repeat(80));
|
|
96
|
+
for (const e of filtered.slice(-20)) {
|
|
97
|
+
console.log(` ${e.timestamp} [${e.action}] ${e.command || "-"} → ${e.result} (${e.user})`);
|
|
98
|
+
}
|
|
99
|
+
console.log("─".repeat(80));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (subcommand === "export") {
|
|
103
|
+
const output = argv.find((_a, i) => argv[i - 1] === "--output");
|
|
104
|
+
if (!output) {
|
|
105
|
+
console.error("Error: --output is required for export.");
|
|
106
|
+
process.exitCode = 1;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const header = "timestamp,action,command,user,result\n";
|
|
110
|
+
const rows = log.entries
|
|
111
|
+
.map((e) => `"${e.timestamp}","${e.action}","${e.command}","${e.user}","${e.result}"`)
|
|
112
|
+
.join("\n");
|
|
113
|
+
mkdirSync(dirname(output), { recursive: true });
|
|
114
|
+
writeFileSync(output, header + rows, "utf-8");
|
|
115
|
+
console.log(`Exported ${log.entries.length} entries to ${output}`);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// show
|
|
119
|
+
const lastN = parseInt(argv.find((_a, i) => argv[i - 1] === "--last") || "10", 10);
|
|
120
|
+
const entries = log.entries.slice(-lastN);
|
|
121
|
+
if (format === "json") {
|
|
122
|
+
console.log(JSON.stringify(entries, null, 2));
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (entries.length === 0) {
|
|
126
|
+
console.log("No audit entries recorded yet.");
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
console.log(`\nAudit Log (last ${entries.length} of ${log.entries.length}):`);
|
|
130
|
+
console.log("─".repeat(80));
|
|
131
|
+
console.log(" Timestamp Action Command Result");
|
|
132
|
+
console.log("─".repeat(80));
|
|
133
|
+
for (const e of entries) {
|
|
134
|
+
const ts = e.timestamp.slice(0, 19).replace("T", " ");
|
|
135
|
+
console.log(` ${ts} ${e.action.padEnd(12)} ${(e.command || "-").padEnd(20)} ${e.result}`);
|
|
136
|
+
}
|
|
137
|
+
console.log("─".repeat(80));
|
|
138
|
+
console.log(` Total entries: ${log.entries.length}`);
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=review-audit-log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-audit-log.js","sourceRoot":"","sources":["../../src/commands/review-audit-log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-badge.d.ts","sourceRoot":"","sources":["../../src/commands/review-badge.ts"],"names":[],"mappings":"AAAA;;GAEG;AAwDH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAyGnD"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review-badge — Generate status badges for project READMEs.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
5
|
+
import { dirname } from "path";
|
|
6
|
+
// ─── Badge Generation ───────────────────────────────────────────────────────
|
|
7
|
+
function scoreToGrade(score) {
|
|
8
|
+
if (score >= 9)
|
|
9
|
+
return "A+";
|
|
10
|
+
if (score >= 8)
|
|
11
|
+
return "A";
|
|
12
|
+
if (score >= 7)
|
|
13
|
+
return "B";
|
|
14
|
+
if (score >= 6)
|
|
15
|
+
return "C";
|
|
16
|
+
if (score >= 5)
|
|
17
|
+
return "D";
|
|
18
|
+
return "F";
|
|
19
|
+
}
|
|
20
|
+
function gradeColor(grade) {
|
|
21
|
+
if (grade.startsWith("A"))
|
|
22
|
+
return "brightgreen";
|
|
23
|
+
if (grade === "B")
|
|
24
|
+
return "green";
|
|
25
|
+
if (grade === "C")
|
|
26
|
+
return "yellow";
|
|
27
|
+
if (grade === "D")
|
|
28
|
+
return "orange";
|
|
29
|
+
return "red";
|
|
30
|
+
}
|
|
31
|
+
function generateMarkdownBadge(label, value, color) {
|
|
32
|
+
const encodedLabel = encodeURIComponent(label);
|
|
33
|
+
const encodedValue = encodeURIComponent(value);
|
|
34
|
+
return ``;
|
|
35
|
+
}
|
|
36
|
+
function generateSvgBadge(label, value, color) {
|
|
37
|
+
const hexColors = {
|
|
38
|
+
brightgreen: "#4c1",
|
|
39
|
+
green: "#97CA00",
|
|
40
|
+
yellow: "#dfb317",
|
|
41
|
+
orange: "#fe7d37",
|
|
42
|
+
red: "#e05d44",
|
|
43
|
+
blue: "#007ec6",
|
|
44
|
+
lightgrey: "#9f9f9f",
|
|
45
|
+
};
|
|
46
|
+
const hex = hexColors[color] || hexColors.lightgrey;
|
|
47
|
+
const labelWidth = label.length * 7 + 10;
|
|
48
|
+
const valueWidth = value.length * 7 + 10;
|
|
49
|
+
const totalWidth = labelWidth + valueWidth;
|
|
50
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${totalWidth}" height="20">
|
|
51
|
+
<rect width="${labelWidth}" height="20" fill="#555"/>
|
|
52
|
+
<rect x="${labelWidth}" width="${valueWidth}" height="20" fill="${hex}"/>
|
|
53
|
+
<text x="${labelWidth / 2}" y="14" fill="#fff" text-anchor="middle" font-family="sans-serif" font-size="11">${label}</text>
|
|
54
|
+
<text x="${labelWidth + valueWidth / 2}" y="14" fill="#fff" text-anchor="middle" font-family="sans-serif" font-size="11">${value}</text>
|
|
55
|
+
</svg>`;
|
|
56
|
+
}
|
|
57
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
58
|
+
export function runReviewBadge(argv) {
|
|
59
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
60
|
+
console.log(`
|
|
61
|
+
judges review-badge — Generate status badges for project READMEs
|
|
62
|
+
|
|
63
|
+
Usage:
|
|
64
|
+
judges review-badge --file verdict.json Generate badge from verdict
|
|
65
|
+
judges review-badge --score 8.5 Generate badge from score
|
|
66
|
+
judges review-badge --file v.json --output badge.svg Save SVG badge
|
|
67
|
+
judges review-badge --file v.json --markdown Output markdown badge syntax
|
|
68
|
+
|
|
69
|
+
Options:
|
|
70
|
+
--file <path> Verdict JSON file
|
|
71
|
+
--score <n> Direct score (0-10)
|
|
72
|
+
--output <path> Save badge to file (SVG format)
|
|
73
|
+
--markdown Output markdown badge syntax
|
|
74
|
+
--label <text> Custom badge label (default: "Judges Score")
|
|
75
|
+
--format json JSON output
|
|
76
|
+
--help, -h Show this help
|
|
77
|
+
|
|
78
|
+
Generate badges showing review score/grade for project visibility.
|
|
79
|
+
`);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
83
|
+
const label = argv.find((_a, i) => argv[i - 1] === "--label") || "Judges Score";
|
|
84
|
+
const output = argv.find((_a, i) => argv[i - 1] === "--output");
|
|
85
|
+
const scoreArg = argv.find((_a, i) => argv[i - 1] === "--score");
|
|
86
|
+
let score;
|
|
87
|
+
let criticals = 0;
|
|
88
|
+
let findings = 0;
|
|
89
|
+
if (scoreArg) {
|
|
90
|
+
score = parseFloat(scoreArg);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const file = argv.find((_a, i) => argv[i - 1] === "--file");
|
|
94
|
+
if (!file || !existsSync(file)) {
|
|
95
|
+
console.error("Error: --file or --score is required.");
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
const verdict = JSON.parse(readFileSync(file, "utf-8"));
|
|
101
|
+
score = verdict.overallScore || 0;
|
|
102
|
+
criticals = verdict.criticalCount || 0;
|
|
103
|
+
findings = (verdict.findings || []).length;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
console.error("Error: Failed to parse verdict file.");
|
|
107
|
+
process.exitCode = 1;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const grade = scoreToGrade(score);
|
|
112
|
+
const color = gradeColor(grade);
|
|
113
|
+
const value = `${grade} (${score.toFixed(1)})`;
|
|
114
|
+
if (output) {
|
|
115
|
+
const svg = generateSvgBadge(label, value, color);
|
|
116
|
+
mkdirSync(dirname(output), { recursive: true });
|
|
117
|
+
writeFileSync(output, svg, "utf-8");
|
|
118
|
+
console.log(`Badge saved to ${output}`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (argv.includes("--markdown")) {
|
|
122
|
+
const md = generateMarkdownBadge(label, value, color);
|
|
123
|
+
console.log(md);
|
|
124
|
+
if (criticals > 0) {
|
|
125
|
+
console.log(generateMarkdownBadge("Critical Findings", String(criticals), "red"));
|
|
126
|
+
}
|
|
127
|
+
if (findings > 0) {
|
|
128
|
+
console.log(generateMarkdownBadge("Total Findings", String(findings), findings > 10 ? "orange" : "blue"));
|
|
129
|
+
}
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (format === "json") {
|
|
133
|
+
console.log(JSON.stringify({
|
|
134
|
+
label,
|
|
135
|
+
value,
|
|
136
|
+
grade,
|
|
137
|
+
score,
|
|
138
|
+
color,
|
|
139
|
+
markdown: generateMarkdownBadge(label, value, color),
|
|
140
|
+
criticals,
|
|
141
|
+
findings,
|
|
142
|
+
}, null, 2));
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
console.log(`\nBadge: ${label} — ${value}`);
|
|
146
|
+
console.log(`Grade: ${grade} Color: ${color}`);
|
|
147
|
+
console.log(`\nMarkdown:`);
|
|
148
|
+
console.log(` ${generateMarkdownBadge(label, value, color)}`);
|
|
149
|
+
if (criticals > 0)
|
|
150
|
+
console.log(` ${generateMarkdownBadge("Critical Findings", String(criticals), "red")}`);
|
|
151
|
+
console.log();
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=review-badge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-badge.js","sourceRoot":"","sources":["../../src/commands/review-badge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-dashboard.d.ts","sourceRoot":"","sources":["../../src/commands/review-dashboard.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAqJvD"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review-dashboard — Terminal-based dashboard summary of review health.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, existsSync, readdirSync } from "fs";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
7
|
+
export function runReviewDashboard(argv) {
|
|
8
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
9
|
+
console.log(`
|
|
10
|
+
judges review-dashboard — Terminal dashboard of review health
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
judges review-dashboard Show dashboard
|
|
14
|
+
judges review-dashboard --dir ./results From verdict directory
|
|
15
|
+
judges review-dashboard --file verdict.json From single file
|
|
16
|
+
judges review-dashboard --format json JSON output
|
|
17
|
+
|
|
18
|
+
Options:
|
|
19
|
+
--file <path> Single verdict file
|
|
20
|
+
--dir <directory> Directory with verdict JSON files
|
|
21
|
+
--format json JSON output
|
|
22
|
+
--help, -h Show this help
|
|
23
|
+
|
|
24
|
+
Displays a summary dashboard with key metrics: score,
|
|
25
|
+
findings by severity, trends, and actionable insights.
|
|
26
|
+
`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
30
|
+
const file = argv.find((_a, i) => argv[i - 1] === "--file");
|
|
31
|
+
const dir = argv.find((_a, i) => argv[i - 1] === "--dir");
|
|
32
|
+
const verdicts = [];
|
|
33
|
+
if (file && existsSync(file)) {
|
|
34
|
+
try {
|
|
35
|
+
verdicts.push(JSON.parse(readFileSync(file, "utf-8")));
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
/* skip */
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (dir && existsSync(dir)) {
|
|
42
|
+
try {
|
|
43
|
+
const entries = readdirSync(dir);
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
if (typeof entry === "string" && entry.endsWith(".json")) {
|
|
46
|
+
try {
|
|
47
|
+
verdicts.push(JSON.parse(readFileSync(join(dir, entry), "utf-8")));
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
/* skip */
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
/* skip */
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (verdicts.length === 0) {
|
|
60
|
+
console.log("\n No verdict data found. Use --file or --dir to provide verdict JSON files.\n");
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Compute metrics
|
|
64
|
+
const scores = verdicts.map((v) => v.overallScore || 0);
|
|
65
|
+
const avgScore = Math.round(scores.reduce((a, b) => a + b, 0) / scores.length);
|
|
66
|
+
const totalFindings = verdicts.reduce((sum, v) => sum + (v.findings || []).length, 0);
|
|
67
|
+
const severityCounts = {};
|
|
68
|
+
for (const v of verdicts) {
|
|
69
|
+
for (const f of v.findings || []) {
|
|
70
|
+
const sev = f.severity || "unknown";
|
|
71
|
+
severityCounts[sev] = (severityCounts[sev] || 0) + 1;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const criticalCount = severityCounts["critical"] || 0;
|
|
75
|
+
const highCount = severityCounts["high"] || 0;
|
|
76
|
+
const mediumCount = severityCounts["medium"] || 0;
|
|
77
|
+
const lowCount = severityCounts["low"] || 0;
|
|
78
|
+
const passCount = verdicts.filter((v) => v.overallVerdict === "pass").length;
|
|
79
|
+
const failCount = verdicts.filter((v) => v.overallVerdict === "fail").length;
|
|
80
|
+
const grade = avgScore >= 90 ? "A" : avgScore >= 80 ? "B" : avgScore >= 70 ? "C" : avgScore >= 60 ? "D" : "F";
|
|
81
|
+
if (format === "json") {
|
|
82
|
+
console.log(JSON.stringify({
|
|
83
|
+
reviewCount: verdicts.length,
|
|
84
|
+
avgScore,
|
|
85
|
+
grade,
|
|
86
|
+
totalFindings,
|
|
87
|
+
severityCounts,
|
|
88
|
+
passCount,
|
|
89
|
+
failCount,
|
|
90
|
+
}, null, 2));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const barLen = Math.round((avgScore / 100) * 20);
|
|
94
|
+
const scoreBar = "█".repeat(barLen) + "░".repeat(20 - barLen);
|
|
95
|
+
console.log(`
|
|
96
|
+
╔═══════════════════════════════════════════╗
|
|
97
|
+
║ JUDGES REVIEW DASHBOARD ║
|
|
98
|
+
╚═══════════════════════════════════════════╝
|
|
99
|
+
|
|
100
|
+
Score: ${scoreBar} ${avgScore}/100 (Grade ${grade})
|
|
101
|
+
|
|
102
|
+
┌─────────────────────────────────────────┐
|
|
103
|
+
│ Reviews: ${String(verdicts.length).padEnd(6)} Pass: ${String(passCount).padEnd(6)} Fail: ${String(failCount).padEnd(4)}│
|
|
104
|
+
│ Findings: ${String(totalFindings).padEnd(30)}│
|
|
105
|
+
└─────────────────────────────────────────┘
|
|
106
|
+
|
|
107
|
+
Severity Distribution:
|
|
108
|
+
🔴 Critical: ${"█".repeat(Math.min(criticalCount, 30))} ${criticalCount}
|
|
109
|
+
🟠 High: ${"█".repeat(Math.min(highCount, 30))} ${highCount}
|
|
110
|
+
🟡 Medium: ${"█".repeat(Math.min(mediumCount, 30))} ${mediumCount}
|
|
111
|
+
🟢 Low: ${"█".repeat(Math.min(lowCount, 30))} ${lowCount}
|
|
112
|
+
`);
|
|
113
|
+
// Top rules
|
|
114
|
+
const ruleCounts = new Map();
|
|
115
|
+
for (const v of verdicts) {
|
|
116
|
+
for (const f of v.findings || []) {
|
|
117
|
+
const rule = f.ruleId || "unknown";
|
|
118
|
+
ruleCounts.set(rule, (ruleCounts.get(rule) || 0) + 1);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const topRules = [...ruleCounts.entries()].sort(([, a], [, b]) => b - a).slice(0, 5);
|
|
122
|
+
if (topRules.length > 0) {
|
|
123
|
+
console.log(" Top Rules:");
|
|
124
|
+
for (const [rule, count] of topRules) {
|
|
125
|
+
console.log(` ${rule.padEnd(30)} ${count} occurrence(s)`);
|
|
126
|
+
}
|
|
127
|
+
console.log();
|
|
128
|
+
}
|
|
129
|
+
// Insights
|
|
130
|
+
console.log(" Insights:");
|
|
131
|
+
if (criticalCount > 0)
|
|
132
|
+
console.log(` ⚠️ ${criticalCount} critical finding(s) require immediate attention`);
|
|
133
|
+
if (failCount > passCount)
|
|
134
|
+
console.log(" ⚠️ More reviews failing than passing — consider reviewing thresholds");
|
|
135
|
+
if (avgScore >= 80)
|
|
136
|
+
console.log(" ✅ Code quality is above target");
|
|
137
|
+
if (totalFindings === 0)
|
|
138
|
+
console.log(" ✅ Clean — no findings detected");
|
|
139
|
+
console.log();
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=review-dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-dashboard.js","sourceRoot":"","sources":["../../src/commands/review-dashboard.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,+EAA+E;AAE/E,MAAM,UAAU,kBAAkB,CAAC,IAAc;IAC/C,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;CAiBf,CAAC,CAAC;QACC,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,UAAU,CAAC,IAAI,MAAM,CAAC;IAC1F,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC;IAC5E,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;IAE1E,MAAM,QAAQ,GAAsB,EAAE,CAAC;IAEvC,IAAI,IAAI,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAoB,CAAC,CAAC;QAC5E,CAAC;QAAC,MAAM,CAAC;YACP,UAAU;QACZ,CAAC;IACH,CAAC;IAED,IAAI,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAwB,CAAC;YACxD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;oBACzD,IAAI,CAAC;wBACH,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,CAAoB,CAAC,CAAC;oBACxF,CAAC;oBAAC,MAAM,CAAC;wBACP,UAAU;oBACZ,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,UAAU;QACZ,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,iFAAiF,CAAC,CAAC;QAC/F,OAAO;IACT,CAAC;IAED,kBAAkB;IAClB,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/E,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAEtF,MAAM,cAAc,GAA2B,EAAE,CAAC;IAClD,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;YACjC,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,IAAI,SAAS,CAAC;YACpC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,MAAM,aAAa,GAAG,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAE5C,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IAC7E,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IAE7E,MAAM,KAAK,GAAG,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAE9G,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CACZ;YACE,WAAW,EAAE,QAAQ,CAAC,MAAM;YAC5B,QAAQ;YACR,KAAK;YACL,aAAa;YACb,cAAc;YACd,SAAS;YACT,SAAS;SACV,EACD,IAAI,EACJ,CAAC,CACF,CACF,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC;IAE9D,OAAO,CAAC,GAAG,CAAC;;;;;WAKH,QAAQ,IAAI,QAAQ,eAAe,KAAK;;;gBAGnC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;iBAC1G,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;;;;mBAI9B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,IAAI,aAAa;mBACxD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,SAAS;mBAChD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,WAAW;mBACpD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,QAAQ;CAChE,CAAC,CAAC;IAED,YAAY;IACZ,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC7C,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,IAAI,SAAS,CAAC;YACnC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAErF,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC5B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,QAAQ,EAAE,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;IAED,WAAW;IACX,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC3B,IAAI,aAAa,GAAG,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,WAAW,aAAa,kDAAkD,CAAC,CAAC;IAC/G,IAAI,SAAS,GAAG,SAAS;QAAE,OAAO,CAAC,GAAG,CAAC,2EAA2E,CAAC,CAAC;IACpH,IAAI,QAAQ,IAAI,EAAE;QAAE,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IACtE,IAAI,aAAa,KAAK,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-diff-summary.d.ts","sourceRoot":"","sources":["../../src/commands/review-diff-summary.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAqLzD"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review-diff-summary — Concise summary of changes and findings.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, existsSync } from "fs";
|
|
5
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
6
|
+
export function runReviewDiffSummary(argv) {
|
|
7
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
8
|
+
console.log(`
|
|
9
|
+
judges review-diff-summary — Concise summary of changes + findings
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
judges review-diff-summary --file verdict.json
|
|
13
|
+
judges review-diff-summary --before before.json --after after.json
|
|
14
|
+
judges review-diff-summary --format json
|
|
15
|
+
|
|
16
|
+
Options:
|
|
17
|
+
--file <path> Single verdict to summarize
|
|
18
|
+
--before <path> Baseline verdict (before changes)
|
|
19
|
+
--after <path> Updated verdict (after changes)
|
|
20
|
+
--max-lines <n> Max summary lines (default: 20)
|
|
21
|
+
--format json JSON output
|
|
22
|
+
--help, -h Show this help
|
|
23
|
+
|
|
24
|
+
Generates a compact, PR-ready summary with key changes
|
|
25
|
+
and finding deltas. Ideal for commit messages or PR descriptions.
|
|
26
|
+
`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
30
|
+
const file = argv.find((_a, i) => argv[i - 1] === "--file");
|
|
31
|
+
const beforeFile = argv.find((_a, i) => argv[i - 1] === "--before");
|
|
32
|
+
const afterFile = argv.find((_a, i) => argv[i - 1] === "--after");
|
|
33
|
+
const maxLines = parseInt(argv.find((_a, i) => argv[i - 1] === "--max-lines") || "20", 10);
|
|
34
|
+
// Comparison mode
|
|
35
|
+
if (beforeFile && afterFile) {
|
|
36
|
+
if (!existsSync(beforeFile) || !existsSync(afterFile)) {
|
|
37
|
+
console.error("Error: Both --before and --after files must exist.");
|
|
38
|
+
process.exitCode = 1;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
let before;
|
|
42
|
+
let after;
|
|
43
|
+
try {
|
|
44
|
+
before = JSON.parse(readFileSync(beforeFile, "utf-8"));
|
|
45
|
+
after = JSON.parse(readFileSync(afterFile, "utf-8"));
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
console.error("Error: Could not parse verdict files.");
|
|
49
|
+
process.exitCode = 1;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const beforeFindings = before.findings || [];
|
|
53
|
+
const afterFindings = after.findings || [];
|
|
54
|
+
const scoreDelta = (after.overallScore || 0) - (before.overallScore || 0);
|
|
55
|
+
const findingsDelta = afterFindings.length - beforeFindings.length;
|
|
56
|
+
const beforeKeys = new Set(beforeFindings.map(fKey));
|
|
57
|
+
const afterKeys = new Set(afterFindings.map(fKey));
|
|
58
|
+
const resolved = beforeFindings.filter((f) => !afterKeys.has(fKey(f)));
|
|
59
|
+
const introduced = afterFindings.filter((f) => !beforeKeys.has(fKey(f)));
|
|
60
|
+
if (format === "json") {
|
|
61
|
+
console.log(JSON.stringify({
|
|
62
|
+
scoreBefore: before.overallScore || 0,
|
|
63
|
+
scoreAfter: after.overallScore || 0,
|
|
64
|
+
scoreDelta,
|
|
65
|
+
findingsBefore: beforeFindings.length,
|
|
66
|
+
findingsAfter: afterFindings.length,
|
|
67
|
+
findingsDelta,
|
|
68
|
+
resolved: resolved.length,
|
|
69
|
+
introduced: introduced.length,
|
|
70
|
+
}, null, 2));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
console.log(`\n Review Diff Summary\n ═════════════════════════════`);
|
|
74
|
+
console.log(` Score: ${before.overallScore || 0} → ${after.overallScore || 0} (${scoreDelta >= 0 ? "+" : ""}${scoreDelta})`);
|
|
75
|
+
console.log(` Findings: ${beforeFindings.length} → ${afterFindings.length} (${findingsDelta >= 0 ? "+" : ""}${findingsDelta})`);
|
|
76
|
+
console.log(` Resolved: ${resolved.length} ✅`);
|
|
77
|
+
console.log(` Introduced: ${introduced.length} ${introduced.length > 0 ? "🆕" : ""}`);
|
|
78
|
+
if (resolved.length > 0) {
|
|
79
|
+
console.log("\n Resolved:");
|
|
80
|
+
for (const f of resolved.slice(0, maxLines)) {
|
|
81
|
+
console.log(` ✅ [${(f.severity || "").toUpperCase()}] ${f.title || f.ruleId}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (introduced.length > 0) {
|
|
85
|
+
console.log("\n Introduced:");
|
|
86
|
+
for (const f of introduced.slice(0, maxLines)) {
|
|
87
|
+
console.log(` 🆕 [${(f.severity || "").toUpperCase()}] ${f.title || f.ruleId}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
console.log();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// Single-file mode
|
|
94
|
+
if (!file) {
|
|
95
|
+
console.error("Error: --file or both --before and --after are required.");
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (!existsSync(file)) {
|
|
100
|
+
console.error(`Error: File not found: ${file}`);
|
|
101
|
+
process.exitCode = 1;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
let verdict;
|
|
105
|
+
try {
|
|
106
|
+
verdict = JSON.parse(readFileSync(file, "utf-8"));
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
console.error(`Error: Could not parse ${file}`);
|
|
110
|
+
process.exitCode = 1;
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const findings = verdict.findings || [];
|
|
114
|
+
const severityCounts = {};
|
|
115
|
+
for (const f of findings) {
|
|
116
|
+
const sev = f.severity || "unknown";
|
|
117
|
+
severityCounts[sev] = (severityCounts[sev] || 0) + 1;
|
|
118
|
+
}
|
|
119
|
+
if (format === "json") {
|
|
120
|
+
console.log(JSON.stringify({
|
|
121
|
+
score: verdict.overallScore || 0,
|
|
122
|
+
verdict: verdict.overallVerdict || "n/a",
|
|
123
|
+
totalFindings: findings.length,
|
|
124
|
+
severityCounts,
|
|
125
|
+
summary: verdict.summary || "",
|
|
126
|
+
}, null, 2));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
console.log(`\n Review Summary\n ─────────────────────────────`);
|
|
130
|
+
console.log(` Score: ${verdict.overallScore || 0}/100 | Verdict: ${verdict.overallVerdict || "n/a"} | Findings: ${findings.length}`);
|
|
131
|
+
const sevParts = [];
|
|
132
|
+
for (const [sev, count] of Object.entries(severityCounts)) {
|
|
133
|
+
sevParts.push(`${sev}: ${count}`);
|
|
134
|
+
}
|
|
135
|
+
if (sevParts.length > 0) {
|
|
136
|
+
console.log(` ${sevParts.join(" | ")}`);
|
|
137
|
+
}
|
|
138
|
+
if (verdict.summary) {
|
|
139
|
+
console.log(`\n ${verdict.summary}`);
|
|
140
|
+
}
|
|
141
|
+
if (findings.length > 0) {
|
|
142
|
+
console.log("\n Top findings:");
|
|
143
|
+
for (const f of findings.slice(0, Math.min(maxLines, findings.length))) {
|
|
144
|
+
console.log(` [${(f.severity || "").toUpperCase()}] ${f.title || f.ruleId}`);
|
|
145
|
+
}
|
|
146
|
+
if (findings.length > maxLines) {
|
|
147
|
+
console.log(` ... and ${findings.length - maxLines} more`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
console.log();
|
|
151
|
+
}
|
|
152
|
+
function fKey(f) {
|
|
153
|
+
return [f.ruleId || "", f.title || "", String(f.severity || "")].join("|").toLowerCase();
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=review-diff-summary.js.map
|