@kevinrabun/judges 3.65.0 → 3.67.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +112 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/config-lint.d.ts +5 -0
  6. package/dist/commands/config-lint.d.ts.map +1 -0
  7. package/dist/commands/config-lint.js +188 -0
  8. package/dist/commands/config-lint.js.map +1 -0
  9. package/dist/commands/finding-age.d.ts +5 -0
  10. package/dist/commands/finding-age.d.ts.map +1 -0
  11. package/dist/commands/finding-age.js +146 -0
  12. package/dist/commands/finding-age.js.map +1 -0
  13. package/dist/commands/finding-rank.d.ts +5 -0
  14. package/dist/commands/finding-rank.d.ts.map +1 -0
  15. package/dist/commands/finding-rank.js +139 -0
  16. package/dist/commands/finding-rank.js.map +1 -0
  17. package/dist/commands/finding-timeline.d.ts +5 -0
  18. package/dist/commands/finding-timeline.d.ts.map +1 -0
  19. package/dist/commands/finding-timeline.js +144 -0
  20. package/dist/commands/finding-timeline.js.map +1 -0
  21. package/dist/commands/fix-verify.d.ts +5 -0
  22. package/dist/commands/fix-verify.d.ts.map +1 -0
  23. package/dist/commands/fix-verify.js +124 -0
  24. package/dist/commands/fix-verify.js.map +1 -0
  25. package/dist/commands/review-comment.d.ts +5 -0
  26. package/dist/commands/review-comment.d.ts.map +1 -0
  27. package/dist/commands/review-comment.js +166 -0
  28. package/dist/commands/review-comment.js.map +1 -0
  29. package/dist/commands/review-dashboard.d.ts +5 -0
  30. package/dist/commands/review-dashboard.d.ts.map +1 -0
  31. package/dist/commands/review-dashboard.js +141 -0
  32. package/dist/commands/review-dashboard.js.map +1 -0
  33. package/dist/commands/review-diff-summary.d.ts +5 -0
  34. package/dist/commands/review-diff-summary.d.ts.map +1 -0
  35. package/dist/commands/review-diff-summary.js +155 -0
  36. package/dist/commands/review-diff-summary.js.map +1 -0
  37. package/dist/commands/review-export.d.ts +5 -0
  38. package/dist/commands/review-export.d.ts.map +1 -0
  39. package/dist/commands/review-export.js +180 -0
  40. package/dist/commands/review-export.js.map +1 -0
  41. package/dist/commands/review-notify.d.ts +5 -0
  42. package/dist/commands/review-notify.d.ts.map +1 -0
  43. package/dist/commands/review-notify.js +144 -0
  44. package/dist/commands/review-notify.js.map +1 -0
  45. package/dist/commands/review-offline.d.ts +5 -0
  46. package/dist/commands/review-offline.d.ts.map +1 -0
  47. package/dist/commands/review-offline.js +126 -0
  48. package/dist/commands/review-offline.js.map +1 -0
  49. package/dist/commands/review-quota.d.ts +5 -0
  50. package/dist/commands/review-quota.d.ts.map +1 -0
  51. package/dist/commands/review-quota.js +127 -0
  52. package/dist/commands/review-quota.js.map +1 -0
  53. package/dist/commands/review-schedule.d.ts +5 -0
  54. package/dist/commands/review-schedule.d.ts.map +1 -0
  55. package/dist/commands/review-schedule.js +170 -0
  56. package/dist/commands/review-schedule.js.map +1 -0
  57. package/dist/commands/review-scope.d.ts +5 -0
  58. package/dist/commands/review-scope.d.ts.map +1 -0
  59. package/dist/commands/review-scope.js +198 -0
  60. package/dist/commands/review-scope.js.map +1 -0
  61. package/dist/commands/rule-catalog.d.ts +5 -0
  62. package/dist/commands/rule-catalog.d.ts.map +1 -0
  63. package/dist/commands/rule-catalog.js +129 -0
  64. package/dist/commands/rule-catalog.js.map +1 -0
  65. package/dist/commands/setup-wizard.d.ts +5 -0
  66. package/dist/commands/setup-wizard.d.ts.map +1 -0
  67. package/dist/commands/setup-wizard.js +175 -0
  68. package/dist/commands/setup-wizard.js.map +1 -0
  69. package/package.json +1 -1
  70. package/server.json +2 -2
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Finding-timeline — Track finding trends across commits over time.
3
+ */
4
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
5
+ import { execSync } from "child_process";
6
+ import { join, dirname } from "path";
7
+ // ─── Storage ────────────────────────────────────────────────────────────────
8
+ const TIMELINE_FILE = join(".judges", "finding-timeline.json");
9
+ function loadTimeline() {
10
+ if (!existsSync(TIMELINE_FILE))
11
+ return { version: "1.0.0", entries: [] };
12
+ try {
13
+ return JSON.parse(readFileSync(TIMELINE_FILE, "utf-8"));
14
+ }
15
+ catch {
16
+ return { version: "1.0.0", entries: [] };
17
+ }
18
+ }
19
+ function saveTimeline(store) {
20
+ mkdirSync(dirname(TIMELINE_FILE), { recursive: true });
21
+ writeFileSync(TIMELINE_FILE, JSON.stringify(store, null, 2), "utf-8");
22
+ }
23
+ function countBySeverity(findings) {
24
+ const counts = {};
25
+ for (const f of findings) {
26
+ const sev = f.severity || "unknown";
27
+ counts[sev] = (counts[sev] || 0) + 1;
28
+ }
29
+ return counts;
30
+ }
31
+ // ─── CLI ────────────────────────────────────────────────────────────────────
32
+ export function runFindingTimeline(argv) {
33
+ if (argv.includes("--help") || argv.includes("-h")) {
34
+ console.log(`
35
+ judges finding-timeline — Track finding trends across commits
36
+
37
+ Usage:
38
+ judges finding-timeline record --file verdict.json --label "v1.0"
39
+ judges finding-timeline show
40
+ judges finding-timeline show --last 10
41
+ judges finding-timeline clear
42
+
43
+ Subcommands:
44
+ record Record a data point from a verdict
45
+ show Show timeline with trend visualization
46
+ clear Clear all timeline data
47
+
48
+ Options:
49
+ --file <path> Verdict JSON (for record)
50
+ --label <text> Label for this data point
51
+ --commit <hash> Git commit hash (auto-detected if omitted)
52
+ --last <n> Show only last N entries
53
+ --format json JSON output
54
+ --help, -h Show this help
55
+
56
+ Tracks findings over time to show improvement trends.
57
+ Data is stored locally in .judges/finding-timeline.json.
58
+ `);
59
+ return;
60
+ }
61
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
62
+ const subcommand = argv.find((a) => ["record", "show", "clear"].includes(a)) || "show";
63
+ const store = loadTimeline();
64
+ if (subcommand === "record") {
65
+ const file = argv.find((_a, i) => argv[i - 1] === "--file");
66
+ if (!file || !existsSync(file)) {
67
+ console.error("Error: --file with a valid verdict JSON is required.");
68
+ process.exitCode = 1;
69
+ return;
70
+ }
71
+ let verdict;
72
+ try {
73
+ verdict = JSON.parse(readFileSync(file, "utf-8"));
74
+ }
75
+ catch {
76
+ console.error(`Error: Could not parse ${file}`);
77
+ process.exitCode = 1;
78
+ return;
79
+ }
80
+ const label = argv.find((_a, i) => argv[i - 1] === "--label") || `entry-${store.entries.length + 1}`;
81
+ let commit = argv.find((_a, i) => argv[i - 1] === "--commit") || "";
82
+ if (!commit) {
83
+ try {
84
+ commit = execSync("git rev-parse --short HEAD", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
85
+ }
86
+ catch {
87
+ commit = "unknown";
88
+ }
89
+ }
90
+ const findings = verdict.findings || [];
91
+ const entry = {
92
+ id: `tl-${Date.now().toString(36)}`,
93
+ timestamp: new Date().toISOString(),
94
+ commit,
95
+ label,
96
+ totalFindings: findings.length,
97
+ bySeverity: countBySeverity(findings),
98
+ score: verdict.overallScore || 0,
99
+ };
100
+ store.entries.push(entry);
101
+ saveTimeline(store);
102
+ console.log(`Recorded timeline entry '${label}' — ${findings.length} findings, score ${entry.score}`);
103
+ return;
104
+ }
105
+ if (subcommand === "clear") {
106
+ saveTimeline({ version: "1.0.0", entries: [] });
107
+ console.log("Timeline cleared.");
108
+ return;
109
+ }
110
+ // Show
111
+ const lastN = parseInt(argv.find((_a, i) => argv[i - 1] === "--last") || "0", 10);
112
+ const entries = lastN > 0 ? store.entries.slice(-lastN) : store.entries;
113
+ if (format === "json") {
114
+ console.log(JSON.stringify({ total: store.entries.length, shown: entries.length, entries }, null, 2));
115
+ return;
116
+ }
117
+ console.log(`\n Finding Timeline (${entries.length} entries)\n ═════════════════════════════`);
118
+ if (entries.length === 0) {
119
+ console.log(" No data. Record with: judges finding-timeline record --file verdict.json");
120
+ console.log();
121
+ return;
122
+ }
123
+ // ASCII chart
124
+ const maxFindings = Math.max(...entries.map((e) => e.totalFindings), 1);
125
+ const barWidth = 30;
126
+ for (const entry of entries) {
127
+ const barLen = Math.round((entry.totalFindings / maxFindings) * barWidth);
128
+ const bar = "█".repeat(barLen) + "░".repeat(barWidth - barLen);
129
+ const date = entry.timestamp.slice(0, 10);
130
+ console.log(` ${date} ${entry.label.padEnd(15)} ${bar} ${entry.totalFindings} findings (score: ${entry.score})`);
131
+ }
132
+ // Show trend
133
+ if (entries.length >= 2) {
134
+ const first = entries[0];
135
+ const last = entries[entries.length - 1];
136
+ const delta = last.totalFindings - first.totalFindings;
137
+ const scoreDelta = last.score - first.score;
138
+ console.log();
139
+ console.log(` Trend: findings ${delta >= 0 ? "+" : ""}${delta}, score ${scoreDelta >= 0 ? "+" : ""}${scoreDelta}`);
140
+ console.log(` ${delta <= 0 && scoreDelta >= 0 ? "📈 Improving" : delta > 0 ? "📉 Declining" : "➡️ Stable"}`);
141
+ }
142
+ console.log();
143
+ }
144
+ //# sourceMappingURL=finding-timeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-timeline.js","sourceRoot":"","sources":["../../src/commands/finding-timeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Fix-verify — Re-run review on fixed code to confirm findings are resolved.
3
+ */
4
+ export declare function runFixVerify(argv: string[]): void;
5
+ //# sourceMappingURL=fix-verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix-verify.d.ts","sourceRoot":"","sources":["../../src/commands/fix-verify.ts"],"names":[],"mappings":"AAAA;;GAEG;AAwDH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAoGjD"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Fix-verify — Re-run review on fixed code to confirm findings are resolved.
3
+ */
4
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
5
+ import { dirname } from "path";
6
+ // ─── Matching ───────────────────────────────────────────────────────────────
7
+ function findingKey(f) {
8
+ return [f.ruleId || "", f.title || "", String(f.severity || "")].join("|").toLowerCase();
9
+ }
10
+ function compareVerdicts(original, updated) {
11
+ const origFindings = original.findings || [];
12
+ const updFindings = updated.findings || [];
13
+ const origKeys = new Set(origFindings.map(findingKey));
14
+ const updKeys = new Set(updFindings.map(findingKey));
15
+ const resolved = origFindings.filter((f) => !updKeys.has(findingKey(f)));
16
+ const remaining = origFindings.filter((f) => updKeys.has(findingKey(f)));
17
+ const newFindings = updFindings.filter((f) => !origKeys.has(findingKey(f)));
18
+ const resolutionRate = origFindings.length > 0 ? Math.round((resolved.length / origFindings.length) * 100) : 100;
19
+ return {
20
+ timestamp: new Date().toISOString(),
21
+ originalFile: "",
22
+ originalCount: origFindings.length,
23
+ resolvedCount: resolved.length,
24
+ remainingCount: remaining.length,
25
+ newCount: newFindings.length,
26
+ resolved,
27
+ remaining,
28
+ newFindings,
29
+ resolutionRate,
30
+ };
31
+ }
32
+ // ─── CLI ────────────────────────────────────────────────────────────────────
33
+ export function runFixVerify(argv) {
34
+ if (argv.includes("--help") || argv.includes("-h")) {
35
+ console.log(`
36
+ judges fix-verify — Verify that fixes resolved findings
37
+
38
+ Usage:
39
+ judges fix-verify --original before.json --updated after.json
40
+ judges fix-verify --original before.json --updated after.json --output report.json
41
+
42
+ Options:
43
+ --original <path> Original verdict JSON (before fixes)
44
+ --updated <path> Updated verdict JSON (after fixes)
45
+ --output <path> Write verification report to file
46
+ --format json JSON output
47
+ --help, -h Show this help
48
+
49
+ Compares two verdict files to show which findings were resolved,
50
+ which remain, and whether new findings were introduced.
51
+ `);
52
+ return;
53
+ }
54
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
55
+ const originalFile = argv.find((_a, i) => argv[i - 1] === "--original");
56
+ const updatedFile = argv.find((_a, i) => argv[i - 1] === "--updated");
57
+ const outputFile = argv.find((_a, i) => argv[i - 1] === "--output");
58
+ if (!originalFile || !updatedFile) {
59
+ console.error("Error: Both --original and --updated are required.");
60
+ process.exitCode = 1;
61
+ return;
62
+ }
63
+ if (!existsSync(originalFile)) {
64
+ console.error(`Error: File not found: ${originalFile}`);
65
+ process.exitCode = 1;
66
+ return;
67
+ }
68
+ if (!existsSync(updatedFile)) {
69
+ console.error(`Error: File not found: ${updatedFile}`);
70
+ process.exitCode = 1;
71
+ return;
72
+ }
73
+ let original;
74
+ let updated;
75
+ try {
76
+ original = JSON.parse(readFileSync(originalFile, "utf-8"));
77
+ updated = JSON.parse(readFileSync(updatedFile, "utf-8"));
78
+ }
79
+ catch {
80
+ console.error("Error: Could not parse verdict files.");
81
+ process.exitCode = 1;
82
+ return;
83
+ }
84
+ const result = compareVerdicts(original, updated);
85
+ result.originalFile = originalFile;
86
+ if (outputFile) {
87
+ mkdirSync(dirname(outputFile), { recursive: true });
88
+ writeFileSync(outputFile, JSON.stringify(result, null, 2), "utf-8");
89
+ console.log(`Verification report written to ${outputFile}`);
90
+ }
91
+ if (format === "json") {
92
+ console.log(JSON.stringify(result, null, 2));
93
+ return;
94
+ }
95
+ console.log(`\n Fix Verification Report\n ═════════════════════════════`);
96
+ console.log(` Original findings: ${result.originalCount}`);
97
+ console.log(` Resolved: ${result.resolvedCount} ✅`);
98
+ console.log(` Remaining: ${result.remainingCount} ⚠️`);
99
+ console.log(` New findings: ${result.newCount} ${result.newCount > 0 ? "🆕" : ""}`);
100
+ console.log(` Resolution rate: ${result.resolutionRate}%`);
101
+ console.log();
102
+ if (result.resolved.length > 0) {
103
+ console.log(" Resolved Findings:");
104
+ for (const f of result.resolved) {
105
+ console.log(` ✅ [${(f.severity || "").toUpperCase()}] ${f.title || f.ruleId}`);
106
+ }
107
+ console.log();
108
+ }
109
+ if (result.remaining.length > 0) {
110
+ console.log(" Remaining Findings:");
111
+ for (const f of result.remaining) {
112
+ console.log(` ⚠️ [${(f.severity || "").toUpperCase()}] ${f.title || f.ruleId}`);
113
+ }
114
+ console.log();
115
+ }
116
+ if (result.newFindings.length > 0) {
117
+ console.log(" New Findings (introduced by fixes):");
118
+ for (const f of result.newFindings) {
119
+ console.log(` 🆕 [${(f.severity || "").toUpperCase()}] ${f.title || f.ruleId}`);
120
+ }
121
+ console.log();
122
+ }
123
+ }
124
+ //# sourceMappingURL=fix-verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix-verify.js","sourceRoot":"","sources":["../../src/commands/fix-verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Review-comment — Generate inline source code comments from review findings.
3
+ */
4
+ export declare function runReviewComment(argv: string[]): void;
5
+ //# sourceMappingURL=review-comment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-comment.d.ts","sourceRoot":"","sources":["../../src/commands/review-comment.ts"],"names":[],"mappings":"AAAA;;GAEG;AA8EH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAwHrD"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Review-comment — Generate inline source code comments from review findings.
3
+ */
4
+ import { readFileSync, writeFileSync, existsSync } from "fs";
5
+ const COMMENT_STYLES = {
6
+ javascript: { line: "//", blockStart: "/*", blockEnd: "*/" },
7
+ typescript: { line: "//", blockStart: "/*", blockEnd: "*/" },
8
+ python: { line: "#", blockStart: '"""', blockEnd: '"""' },
9
+ ruby: { line: "#", blockStart: "=begin", blockEnd: "=end" },
10
+ java: { line: "//", blockStart: "/*", blockEnd: "*/" },
11
+ csharp: { line: "//", blockStart: "/*", blockEnd: "*/" },
12
+ go: { line: "//", blockStart: "/*", blockEnd: "*/" },
13
+ rust: { line: "//", blockStart: "/*", blockEnd: "*/" },
14
+ cpp: { line: "//", blockStart: "/*", blockEnd: "*/" },
15
+ c: { line: "//", blockStart: "/*", blockEnd: "*/" },
16
+ };
17
+ function getCommentStyle(lang) {
18
+ return COMMENT_STYLES[lang.toLowerCase()] || COMMENT_STYLES["javascript"];
19
+ }
20
+ function formatComment(finding, style, commentStyle) {
21
+ const severity = (finding.severity || "info").toUpperCase();
22
+ const rule = finding.ruleId || "JUDGES";
23
+ const title = finding.title || "Finding";
24
+ if (commentStyle === "line") {
25
+ const lines = [`${style.line} JUDGES [${severity}] ${rule}: ${title}`];
26
+ if (finding.recommendation) {
27
+ lines.push(`${style.line} Fix: ${finding.recommendation}`);
28
+ }
29
+ return lines.join("\n");
30
+ }
31
+ if (commentStyle === "jsdoc") {
32
+ const lines = [`/** JUDGES [${severity}] ${rule}: ${title}`];
33
+ if (finding.recommendation) {
34
+ lines.push(` * Fix: ${finding.recommendation}`);
35
+ }
36
+ lines.push(" */");
37
+ return lines.join("\n");
38
+ }
39
+ // block
40
+ const lines = [`/* JUDGES [${severity}] ${rule}: ${title}`];
41
+ if (finding.recommendation) {
42
+ lines.push(` Fix: ${finding.recommendation}`);
43
+ }
44
+ lines.push("*/");
45
+ return lines.join("\n");
46
+ }
47
+ function generateComments(findings, lang, style) {
48
+ const cs = getCommentStyle(lang);
49
+ const blocks = [];
50
+ for (const f of findings) {
51
+ const line = f.lineNumbers && f.lineNumbers.length > 0 ? f.lineNumbers[0] : 1;
52
+ blocks.push({ line, text: formatComment(f, cs, style) });
53
+ }
54
+ // Sort by line descending so insertions don't shift subsequent lines
55
+ blocks.sort((a, b) => b.line - a.line);
56
+ return blocks;
57
+ }
58
+ // ─── CLI ────────────────────────────────────────────────────────────────────
59
+ export function runReviewComment(argv) {
60
+ if (argv.includes("--help") || argv.includes("-h")) {
61
+ console.log(`
62
+ judges review-comment — Generate inline code comments from findings
63
+
64
+ Usage:
65
+ judges review-comment --verdict verdict.json --source app.ts
66
+ judges review-comment --verdict verdict.json --source app.py --lang python
67
+ judges review-comment --verdict verdict.json --preview
68
+
69
+ Options:
70
+ --verdict <path> Verdict JSON file
71
+ --source <path> Source file to annotate (optional; preview without)
72
+ --lang <language> Language (auto-detected from extension)
73
+ --style line|block|jsdoc Comment style (default: line)
74
+ --output <path> Write annotated file to path (default: modifies in-place)
75
+ --preview Show comments without modifying files
76
+ --min-severity <sev> Only include findings at this severity or above
77
+ --format json JSON output
78
+ --help, -h Show this help
79
+
80
+ Generates inline code comments from review findings. Comments include
81
+ severity, rule ID, title, and fix recommendation.
82
+ `);
83
+ return;
84
+ }
85
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
86
+ const verdictFile = argv.find((_a, i) => argv[i - 1] === "--verdict");
87
+ const sourceFile = argv.find((_a, i) => argv[i - 1] === "--source");
88
+ const lang = argv.find((_a, i) => argv[i - 1] === "--lang") || "";
89
+ const styleArg = argv.find((_a, i) => argv[i - 1] === "--style") || "line";
90
+ const outputFile = argv.find((_a, i) => argv[i - 1] === "--output");
91
+ const preview = argv.includes("--preview");
92
+ const minSev = argv.find((_a, i) => argv[i - 1] === "--min-severity");
93
+ if (!verdictFile) {
94
+ console.error("Error: --verdict is required.");
95
+ process.exitCode = 1;
96
+ return;
97
+ }
98
+ if (!existsSync(verdictFile)) {
99
+ console.error(`Error: File not found: ${verdictFile}`);
100
+ process.exitCode = 1;
101
+ return;
102
+ }
103
+ let verdict;
104
+ try {
105
+ verdict = JSON.parse(readFileSync(verdictFile, "utf-8"));
106
+ }
107
+ catch {
108
+ console.error(`Error: Could not parse ${verdictFile}`);
109
+ process.exitCode = 1;
110
+ return;
111
+ }
112
+ let findings = verdict.findings || [];
113
+ // Severity filter
114
+ if (minSev) {
115
+ const sevOrder = { critical: 4, high: 3, medium: 2, low: 1, info: 0 };
116
+ const threshold = sevOrder[minSev.toLowerCase()] ?? 0;
117
+ findings = findings.filter((f) => (sevOrder[(f.severity || "").toLowerCase()] ?? 0) >= threshold);
118
+ }
119
+ // Detect language from source file extension
120
+ const detectedLang = lang || (sourceFile ? sourceFile.split(".").pop() || "ts" : "ts");
121
+ const languageMap = {
122
+ ts: "typescript",
123
+ js: "javascript",
124
+ py: "python",
125
+ rb: "ruby",
126
+ java: "java",
127
+ cs: "csharp",
128
+ go: "go",
129
+ rs: "rust",
130
+ cpp: "cpp",
131
+ c: "c",
132
+ };
133
+ const resolvedLang = languageMap[detectedLang] || detectedLang;
134
+ const commentStyle = (["line", "block", "jsdoc"].includes(styleArg) ? styleArg : "line");
135
+ const comments = generateComments(findings, resolvedLang, commentStyle);
136
+ if (format === "json") {
137
+ console.log(JSON.stringify({ language: resolvedLang, style: commentStyle, comments }, null, 2));
138
+ return;
139
+ }
140
+ if (preview || !sourceFile) {
141
+ console.log(`\n Review Comments Preview (${resolvedLang}, ${commentStyle} style)\n ─────────────────────────────`);
142
+ for (const c of [...comments].reverse()) {
143
+ console.log(`\n Line ${c.line}:`);
144
+ for (const line of c.text.split("\n")) {
145
+ console.log(` ${line}`);
146
+ }
147
+ }
148
+ console.log(`\n Total: ${comments.length} comment(s)\n`);
149
+ return;
150
+ }
151
+ // Insert comments into source file
152
+ if (!existsSync(sourceFile)) {
153
+ console.error(`Error: Source file not found: ${sourceFile}`);
154
+ process.exitCode = 1;
155
+ return;
156
+ }
157
+ const sourceLines = readFileSync(sourceFile, "utf-8").split("\n");
158
+ for (const c of comments) {
159
+ const insertAt = Math.max(0, c.line - 1);
160
+ sourceLines.splice(insertAt, 0, c.text);
161
+ }
162
+ const dest = outputFile || sourceFile;
163
+ writeFileSync(dest, sourceLines.join("\n"), "utf-8");
164
+ console.log(`Inserted ${comments.length} comment(s) into ${dest}`);
165
+ }
166
+ //# sourceMappingURL=review-comment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-comment.js","sourceRoot":"","sources":["../../src/commands/review-comment.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Review-dashboard — Terminal-based dashboard summary of review health.
3
+ */
4
+ export declare function runReviewDashboard(argv: string[]): void;
5
+ //# sourceMappingURL=review-dashboard.d.ts.map
@@ -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