@kevinrabun/judges 3.41.0 → 3.42.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 (46) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +70 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/auto-triage.d.ts +32 -0
  6. package/dist/commands/auto-triage.d.ts.map +1 -0
  7. package/dist/commands/auto-triage.js +126 -0
  8. package/dist/commands/auto-triage.js.map +1 -0
  9. package/dist/commands/coverage-map.d.ts +23 -0
  10. package/dist/commands/coverage-map.d.ts.map +1 -0
  11. package/dist/commands/coverage-map.js +223 -0
  12. package/dist/commands/coverage-map.js.map +1 -0
  13. package/dist/commands/diff-only.d.ts +34 -0
  14. package/dist/commands/diff-only.d.ts.map +1 -0
  15. package/dist/commands/diff-only.js +152 -0
  16. package/dist/commands/diff-only.js.map +1 -0
  17. package/dist/commands/group-findings.d.ts +23 -0
  18. package/dist/commands/group-findings.d.ts.map +1 -0
  19. package/dist/commands/group-findings.js +155 -0
  20. package/dist/commands/group-findings.js.map +1 -0
  21. package/dist/commands/pr-summary.d.ts +26 -0
  22. package/dist/commands/pr-summary.d.ts.map +1 -0
  23. package/dist/commands/pr-summary.js +188 -0
  24. package/dist/commands/pr-summary.js.map +1 -0
  25. package/dist/commands/profile.d.ts +38 -0
  26. package/dist/commands/profile.d.ts.map +1 -0
  27. package/dist/commands/profile.js +102 -0
  28. package/dist/commands/profile.js.map +1 -0
  29. package/dist/commands/smart-select.d.ts +27 -0
  30. package/dist/commands/smart-select.d.ts.map +1 -0
  31. package/dist/commands/smart-select.js +346 -0
  32. package/dist/commands/smart-select.js.map +1 -0
  33. package/dist/commands/upload.d.ts +14 -0
  34. package/dist/commands/upload.d.ts.map +1 -0
  35. package/dist/commands/upload.js +173 -0
  36. package/dist/commands/upload.js.map +1 -0
  37. package/dist/commands/validate-config.d.ts +17 -0
  38. package/dist/commands/validate-config.d.ts.map +1 -0
  39. package/dist/commands/validate-config.js +268 -0
  40. package/dist/commands/validate-config.js.map +1 -0
  41. package/dist/commands/warm-cache.d.ts +31 -0
  42. package/dist/commands/warm-cache.d.ts.map +1 -0
  43. package/dist/commands/warm-cache.js +166 -0
  44. package/dist/commands/warm-cache.js.map +1 -0
  45. package/package.json +1 -1
  46. package/server.json +2 -2
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Rule coverage map — show which rules apply to which languages,
3
+ * helping teams understand their coverage and identify gaps.
4
+ */
5
+ // ─── Rules-to-Language Mapping ──────────────────────────────────────────────
6
+ /**
7
+ * Universal rules applicable to all programming languages.
8
+ */
9
+ const UNIVERSAL_RULES = [
10
+ { pattern: "SEC-", judge: "cybersecurity", severity: "high" },
11
+ { pattern: "ERR-", judge: "error-handling", severity: "medium" },
12
+ { pattern: "MAINT-", judge: "maintainability", severity: "low" },
13
+ { pattern: "DOC-", judge: "documentation", severity: "low" },
14
+ { pattern: "STRUCT-", judge: "code-structure", severity: "medium" },
15
+ { pattern: "TEST-", judge: "testing", severity: "medium" },
16
+ { pattern: "LOG-", judge: "logging-privacy", severity: "medium" },
17
+ { pattern: "AI-", judge: "ai-code-safety", severity: "high" },
18
+ ];
19
+ /**
20
+ * Language-specific rules with limited applicability.
21
+ */
22
+ const LANGUAGE_RULES = [
23
+ {
24
+ pattern: "INJECT-SQL",
25
+ judge: "cybersecurity",
26
+ severity: "critical",
27
+ languages: ["typescript", "javascript", "python", "java", "csharp", "php", "ruby", "go"],
28
+ },
29
+ {
30
+ pattern: "INJECT-CMD",
31
+ judge: "cybersecurity",
32
+ severity: "critical",
33
+ languages: ["typescript", "javascript", "python", "java", "csharp", "php", "ruby", "go", "rust"],
34
+ },
35
+ {
36
+ pattern: "XSS-",
37
+ judge: "cybersecurity",
38
+ severity: "high",
39
+ languages: ["typescript", "javascript", "python", "java", "csharp", "php", "ruby"],
40
+ },
41
+ {
42
+ pattern: "SSRF-",
43
+ judge: "cybersecurity",
44
+ severity: "high",
45
+ languages: ["typescript", "javascript", "python", "java", "csharp", "go", "ruby"],
46
+ },
47
+ {
48
+ pattern: "CRYPTO-",
49
+ judge: "cybersecurity",
50
+ severity: "high",
51
+ languages: ["typescript", "javascript", "python", "java", "csharp", "go", "rust", "c", "cpp"],
52
+ },
53
+ {
54
+ pattern: "AUTH-",
55
+ judge: "authentication",
56
+ severity: "high",
57
+ languages: ["typescript", "javascript", "python", "java", "csharp", "go", "ruby", "php"],
58
+ },
59
+ {
60
+ pattern: "PERF-",
61
+ judge: "performance",
62
+ severity: "medium",
63
+ languages: ["typescript", "javascript", "python", "java", "csharp", "go", "rust", "c", "cpp"],
64
+ },
65
+ {
66
+ pattern: "DB-",
67
+ judge: "database",
68
+ severity: "medium",
69
+ languages: ["typescript", "javascript", "python", "java", "csharp", "go", "ruby", "sql"],
70
+ },
71
+ { pattern: "IAC-", judge: "iac-security", severity: "high", languages: ["terraform", "bicep", "yaml", "dockerfile"] },
72
+ { pattern: "CICD-", judge: "ci-cd", severity: "high", languages: ["yaml", "dockerfile", "bash", "powershell"] },
73
+ {
74
+ pattern: "CONCUR-",
75
+ judge: "concurrency",
76
+ severity: "high",
77
+ languages: ["go", "rust", "java", "csharp", "python", "c", "cpp"],
78
+ },
79
+ { pattern: "A11Y-", judge: "accessibility", severity: "medium", languages: ["typescript", "javascript", "html"] },
80
+ {
81
+ pattern: "I18N-",
82
+ judge: "internationalization",
83
+ severity: "low",
84
+ languages: ["typescript", "javascript", "python", "java", "csharp"],
85
+ },
86
+ { pattern: "FW-REACT", judge: "framework-safety", severity: "high", languages: ["typescript", "javascript"] },
87
+ { pattern: "FW-EXPRESS", judge: "framework-safety", severity: "high", languages: ["typescript", "javascript"] },
88
+ { pattern: "FW-DJANGO", judge: "framework-safety", severity: "high", languages: ["python"] },
89
+ { pattern: "FW-FLASK", judge: "framework-safety", severity: "high", languages: ["python"] },
90
+ { pattern: "FW-SPRING", judge: "framework-safety", severity: "high", languages: ["java", "kotlin"] },
91
+ { pattern: "FW-RAILS", judge: "framework-safety", severity: "high", languages: ["ruby"] },
92
+ { pattern: "FW-NEXT", judge: "framework-safety", severity: "high", languages: ["typescript", "javascript"] },
93
+ { pattern: "FW-FASTAPI", judge: "framework-safety", severity: "high", languages: ["python"] },
94
+ ];
95
+ const ALL_LANGUAGES = [
96
+ "typescript",
97
+ "javascript",
98
+ "python",
99
+ "java",
100
+ "csharp",
101
+ "go",
102
+ "rust",
103
+ "ruby",
104
+ "php",
105
+ "c",
106
+ "cpp",
107
+ "kotlin",
108
+ "scala",
109
+ "swift",
110
+ "dart",
111
+ "bash",
112
+ "powershell",
113
+ "sql",
114
+ "terraform",
115
+ "bicep",
116
+ "yaml",
117
+ "dockerfile",
118
+ "html",
119
+ ];
120
+ // ─── Coverage Computation ───────────────────────────────────────────────────
121
+ export function buildCoverageMap(languages) {
122
+ const langs = languages || ALL_LANGUAGES;
123
+ const rules = [];
124
+ const matrix = {};
125
+ // Universal rules
126
+ for (const r of UNIVERSAL_RULES) {
127
+ const coverage = {
128
+ ruleId: r.pattern.replace(/-$/, ""),
129
+ languages: [...langs],
130
+ severity: r.severity,
131
+ judge: r.judge,
132
+ };
133
+ rules.push(coverage);
134
+ matrix[coverage.ruleId] = {};
135
+ for (const l of langs)
136
+ matrix[coverage.ruleId][l] = true;
137
+ }
138
+ // Language-specific rules
139
+ for (const r of LANGUAGE_RULES) {
140
+ const applicableLangs = r.languages.filter((l) => langs.includes(l));
141
+ const coverage = {
142
+ ruleId: r.pattern.replace(/-$/, ""),
143
+ languages: applicableLangs,
144
+ severity: r.severity,
145
+ judge: r.judge,
146
+ };
147
+ rules.push(coverage);
148
+ matrix[coverage.ruleId] = {};
149
+ for (const l of langs)
150
+ matrix[coverage.ruleId][l] = applicableLangs.includes(l);
151
+ }
152
+ // Statistics
153
+ const byLanguage = {};
154
+ const byJudge = {};
155
+ for (const r of rules) {
156
+ byJudge[r.judge] = (byJudge[r.judge] || 0) + 1;
157
+ for (const l of r.languages) {
158
+ byLanguage[l] = (byLanguage[l] || 0) + 1;
159
+ }
160
+ }
161
+ return {
162
+ languages: langs,
163
+ rules,
164
+ matrix,
165
+ stats: { totalRules: rules.length, byLanguage, byJudge },
166
+ };
167
+ }
168
+ // ─── CLI ────────────────────────────────────────────────────────────────────
169
+ export function runCoverageMap(argv) {
170
+ if (argv.includes("--help") || argv.includes("-h")) {
171
+ console.log(`
172
+ judges coverage-map — Show which rules apply to which languages
173
+
174
+ Usage:
175
+ judges coverage-map Full coverage matrix
176
+ judges coverage-map --languages typescript,python Focus on specific languages
177
+ judges coverage-map --judge cybersecurity Filter by judge
178
+
179
+ Options:
180
+ --languages <list> Comma-separated languages to show
181
+ --judge <id> Filter rules by judge
182
+ --format json JSON output
183
+ --help, -h Show this help
184
+ `);
185
+ return;
186
+ }
187
+ const langsArg = argv.find((_a, i) => argv[i - 1] === "--languages");
188
+ const judgeFilter = argv.find((_a, i) => argv[i - 1] === "--judge");
189
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
190
+ const languages = langsArg ? langsArg.split(",").map((s) => s.trim()) : undefined;
191
+ const map = buildCoverageMap(languages);
192
+ let rules = map.rules;
193
+ if (judgeFilter) {
194
+ rules = rules.filter((r) => r.judge === judgeFilter);
195
+ }
196
+ if (format === "json") {
197
+ console.log(JSON.stringify({ ...map, rules }, null, 2));
198
+ return;
199
+ }
200
+ console.log(`\n Rule Coverage Map\n`);
201
+ console.log(` Total rules: ${rules.length} | Languages: ${map.languages.length}\n`);
202
+ // Show compact matrix
203
+ const displayLangs = map.languages.slice(0, 12); // limit width
204
+ const header = " " + "Rule".padEnd(20) + displayLangs.map((l) => l.slice(0, 4).padEnd(5)).join("");
205
+ console.log(header);
206
+ console.log(" " + "─".repeat(header.length - 2));
207
+ for (const r of rules) {
208
+ const row = displayLangs.map((l) => (r.languages.includes(l) ? " ✓ " : " · ")).join("");
209
+ console.log(` ${r.ruleId.padEnd(20)}${row}`);
210
+ }
211
+ console.log(`\n Coverage by language:`);
212
+ const sorted = Object.entries(map.stats.byLanguage).sort((a, b) => b[1] - a[1]);
213
+ for (const [lang, count] of sorted) {
214
+ const pct = ((count / rules.length) * 100).toFixed(0);
215
+ console.log(` ${lang.padEnd(15)} ${String(count).padStart(3)} rules (${pct}%)`);
216
+ }
217
+ console.log(`\n Coverage by judge:`);
218
+ for (const [judge, count] of Object.entries(map.stats.byJudge).sort((a, b) => b[1] - a[1])) {
219
+ console.log(` ${judge.padEnd(25)} ${count} rules`);
220
+ }
221
+ console.log("");
222
+ }
223
+ //# sourceMappingURL=coverage-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage-map.js","sourceRoot":"","sources":["../../src/commands/coverage-map.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Diff-only evaluation — evaluate only changed lines in a PR or git diff.
3
+ *
4
+ * Parses unified diff output to identify changed line ranges,
5
+ * then filters evaluation findings to only those touching changed code.
6
+ * This drastically reduces noise in CI review comments.
7
+ */
8
+ import type { Finding } from "../types.js";
9
+ export interface DiffHunk {
10
+ file: string;
11
+ startLine: number;
12
+ lineCount: number;
13
+ }
14
+ export interface DiffFilterResult {
15
+ original: number;
16
+ filtered: number;
17
+ removed: number;
18
+ findings: Finding[];
19
+ }
20
+ /**
21
+ * Parse a unified diff to extract changed file/line ranges.
22
+ * Handles both `git diff` and `git diff --cached` output.
23
+ */
24
+ export declare function parseDiff(diff: string): DiffHunk[];
25
+ /**
26
+ * Filter findings to only those touching changed lines.
27
+ */
28
+ export declare function filterByDiff(findings: Finding[], diff: string): DiffFilterResult;
29
+ /**
30
+ * Get the list of changed files from a diff.
31
+ */
32
+ export declare function getChangedFiles(diff: string): string[];
33
+ export declare function runDiffOnly(argv: string[]): Promise<void>;
34
+ //# sourceMappingURL=diff-only.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-only.d.ts","sourceRoot":"","sources":["../../src/commands/diff-only.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAID;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAwBlD;AAcD;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAUhF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAOtD;AAID,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAwF/D"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Diff-only evaluation — evaluate only changed lines in a PR or git diff.
3
+ *
4
+ * Parses unified diff output to identify changed line ranges,
5
+ * then filters evaluation findings to only those touching changed code.
6
+ * This drastically reduces noise in CI review comments.
7
+ */
8
+ // ─── Diff Parsing ───────────────────────────────────────────────────────────
9
+ /**
10
+ * Parse a unified diff to extract changed file/line ranges.
11
+ * Handles both `git diff` and `git diff --cached` output.
12
+ */
13
+ export function parseDiff(diff) {
14
+ const hunks = [];
15
+ let currentFile = "";
16
+ for (const line of diff.split("\n")) {
17
+ // Match +++ b/path/to/file
18
+ const fileMatch = line.match(/^\+\+\+ b\/(.+)$/);
19
+ if (fileMatch) {
20
+ currentFile = fileMatch[1];
21
+ continue;
22
+ }
23
+ // Match @@ -old,count +new,count @@
24
+ const hunkMatch = line.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/);
25
+ if (hunkMatch && currentFile) {
26
+ hunks.push({
27
+ file: currentFile,
28
+ startLine: parseInt(hunkMatch[1], 10),
29
+ lineCount: parseInt(hunkMatch[2] || "1", 10),
30
+ });
31
+ }
32
+ }
33
+ return hunks;
34
+ }
35
+ /**
36
+ * Check whether a finding overlaps with any changed hunk.
37
+ */
38
+ function isInDiff(finding, hunks) {
39
+ const findingLine = finding.lineNumbers?.[0];
40
+ if (!findingLine)
41
+ return false;
42
+ return hunks.some((h) => {
43
+ return findingLine >= h.startLine && findingLine <= h.startLine + h.lineCount - 1;
44
+ });
45
+ }
46
+ /**
47
+ * Filter findings to only those touching changed lines.
48
+ */
49
+ export function filterByDiff(findings, diff) {
50
+ const hunks = parseDiff(diff);
51
+ const filtered = findings.filter((f) => isInDiff(f, hunks));
52
+ return {
53
+ original: findings.length,
54
+ filtered: filtered.length,
55
+ removed: findings.length - filtered.length,
56
+ findings: filtered,
57
+ };
58
+ }
59
+ /**
60
+ * Get the list of changed files from a diff.
61
+ */
62
+ export function getChangedFiles(diff) {
63
+ const files = new Set();
64
+ for (const line of diff.split("\n")) {
65
+ const match = line.match(/^\+\+\+ b\/(.+)$/);
66
+ if (match)
67
+ files.add(match[1]);
68
+ }
69
+ return [...files];
70
+ }
71
+ // ─── CLI ────────────────────────────────────────────────────────────────────
72
+ export async function runDiffOnly(argv) {
73
+ if (argv.includes("--help") || argv.includes("-h")) {
74
+ console.log(`
75
+ judges diff-only — Evaluate only changed lines in a PR or diff
76
+
77
+ Usage:
78
+ judges diff-only --base main Diff against main branch
79
+ judges diff-only --base HEAD~1 Diff against previous commit
80
+ judges diff-only --diff-file changes.patch Use a pre-generated diff
81
+
82
+ Options:
83
+ --base <ref> Git ref to diff against (default: main)
84
+ --diff-file <path> Pre-generated diff file
85
+ --input <path> JSON results to filter (default: run fresh eval)
86
+ --format json JSON output
87
+ --help, -h Show this help
88
+
89
+ The command diffs against the base ref, identifies changed lines,
90
+ and filters findings to only those touching changed code. This is
91
+ ideal for CI pipelines reviewing PRs.
92
+ `);
93
+ return;
94
+ }
95
+ const { readFileSync, existsSync } = await import("fs");
96
+ const { execSync } = await import("child_process");
97
+ let diff;
98
+ const diffFile = argv.find((_a, i) => argv[i - 1] === "--diff-file");
99
+ if (diffFile && existsSync(diffFile)) {
100
+ diff = readFileSync(diffFile, "utf-8");
101
+ }
102
+ else {
103
+ const base = argv.find((_a, i) => argv[i - 1] === "--base") || "main";
104
+ try {
105
+ diff = execSync(`git diff ${base}`, { encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 });
106
+ }
107
+ catch {
108
+ console.error(`Error: could not run git diff ${base}`);
109
+ process.exit(1);
110
+ }
111
+ }
112
+ const changedFiles = getChangedFiles(diff);
113
+ const hunks = parseDiff(diff);
114
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
115
+ const inputPath = argv.find((_a, i) => argv[i - 1] === "--input");
116
+ if (inputPath && existsSync(inputPath)) {
117
+ const data = JSON.parse(readFileSync(inputPath, "utf-8"));
118
+ const findings = data.evaluations
119
+ ? data.evaluations.flatMap((e) => e.findings || [])
120
+ : data.findings || data;
121
+ const result = filterByDiff(findings, diff);
122
+ if (format === "json") {
123
+ console.log(JSON.stringify(result, null, 2));
124
+ return;
125
+ }
126
+ console.log(`\n Diff-Only Filter Results\n`);
127
+ console.log(` Changed files: ${changedFiles.length}`);
128
+ console.log(` Changed hunks: ${hunks.length}`);
129
+ console.log(` Original findings: ${result.original}`);
130
+ console.log(` In diff: ${result.filtered}`);
131
+ console.log(` Filtered out: ${result.removed}\n`);
132
+ for (const f of result.findings) {
133
+ const loc = f.lineNumbers?.length ? `:${f.lineNumbers[0]}` : "";
134
+ console.log(` ${f.severity.padEnd(8)} ${f.ruleId}: ${f.title.slice(0, 80)}${loc}`);
135
+ }
136
+ console.log("");
137
+ return;
138
+ }
139
+ // Just show diff info without filtering
140
+ if (format === "json") {
141
+ console.log(JSON.stringify({ changedFiles, hunks, totalHunks: hunks.length }, null, 2));
142
+ return;
143
+ }
144
+ console.log(`\n Changed Files (${changedFiles.length}):\n`);
145
+ for (const f of changedFiles) {
146
+ const fileHunks = hunks.filter((h) => h.file === f);
147
+ const totalLines = fileHunks.reduce((s, h) => s + h.lineCount, 0);
148
+ console.log(` ${f} (${fileHunks.length} hunks, ${totalLines} lines)`);
149
+ }
150
+ console.log(`\n Run with --input <results.json> to filter findings.\n`);
151
+ }
152
+ //# sourceMappingURL=diff-only.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-only.js","sourceRoot":"","sources":["../../src/commands/diff-only.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Finding grouping — group related findings by category, file, or rule
3
+ * for better review UX and digest-style reporting.
4
+ */
5
+ import type { Finding } from "../types.js";
6
+ export type GroupByKey = "category" | "severity" | "file" | "rule" | "judge";
7
+ export interface FindingGroup {
8
+ key: string;
9
+ label: string;
10
+ findings: Finding[];
11
+ count: number;
12
+ criticalCount: number;
13
+ highCount: number;
14
+ }
15
+ export interface GroupedReport {
16
+ groupBy: GroupByKey;
17
+ groups: FindingGroup[];
18
+ totalFindings: number;
19
+ totalGroups: number;
20
+ }
21
+ export declare function groupFindings(findings: Finding[], groupBy: GroupByKey): GroupedReport;
22
+ export declare function runGroupFindings(argv: string[]): void;
23
+ //# sourceMappingURL=group-findings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-findings.d.ts","sourceRoot":"","sources":["../../src/commands/group-findings.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE7E,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AA4ED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,UAAU,GAAG,aAAa,CA2BrF;AAID,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAmErD"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Finding grouping — group related findings by category, file, or rule
3
+ * for better review UX and digest-style reporting.
4
+ */
5
+ // ─── Category Classification ────────────────────────────────────────────────
6
+ const RULE_CATEGORIES = {
7
+ // Security
8
+ "SEC-": "Security",
9
+ "AUTH-": "Authentication",
10
+ "CRYPTO-": "Cryptography",
11
+ "INJECT-": "Injection",
12
+ "XSS-": "Cross-Site Scripting",
13
+ "SSRF-": "Server-Side Request Forgery",
14
+ "IDOR-": "Broken Access Control",
15
+ // Quality
16
+ "PERF-": "Performance",
17
+ "ERR-": "Error Handling",
18
+ "LOG-": "Logging",
19
+ "TEST-": "Testing",
20
+ "DOC-": "Documentation",
21
+ "MAINT-": "Maintainability",
22
+ "STRUCT-": "Code Structure",
23
+ // Reliability
24
+ "CONCUR-": "Concurrency",
25
+ "RACE-": "Race Conditions",
26
+ "SCALE-": "Scalability",
27
+ "CACHE-": "Caching",
28
+ "RATE-": "Rate Limiting",
29
+ // Compliance
30
+ "COMPLY-": "Compliance",
31
+ "DATA-": "Data Protection",
32
+ "PII-": "Privacy",
33
+ // AI
34
+ "AI-": "AI Safety",
35
+ "HALLUC-": "Hallucination",
36
+ "FW-": "Framework Safety",
37
+ // Infrastructure
38
+ "IAC-": "Infrastructure as Code",
39
+ "CICD-": "CI/CD",
40
+ "CLOUD-": "Cloud Readiness",
41
+ "DB-": "Database",
42
+ // Accessibility / UX
43
+ "A11Y-": "Accessibility",
44
+ "I18N-": "Internationalization",
45
+ "UX-": "User Experience",
46
+ };
47
+ function classifyRule(ruleId) {
48
+ for (const [prefix, category] of Object.entries(RULE_CATEGORIES)) {
49
+ if (ruleId.toUpperCase().startsWith(prefix))
50
+ return category;
51
+ }
52
+ return "Other";
53
+ }
54
+ // ─── Grouping Logic ─────────────────────────────────────────────────────────
55
+ function getGroupKey(finding, groupBy) {
56
+ switch (groupBy) {
57
+ case "category":
58
+ return classifyRule(finding.ruleId);
59
+ case "severity":
60
+ return finding.severity;
61
+ case "file":
62
+ return "(grouped)";
63
+ case "rule":
64
+ return finding.ruleId;
65
+ case "judge":
66
+ return finding.judgeId || "(unknown)";
67
+ }
68
+ }
69
+ export function groupFindings(findings, groupBy) {
70
+ const groups = new Map();
71
+ for (const f of findings) {
72
+ const key = getGroupKey(f, groupBy);
73
+ const arr = groups.get(key) || [];
74
+ arr.push(f);
75
+ groups.set(key, arr);
76
+ }
77
+ const sortedGroups = [...groups.entries()]
78
+ .map(([key, items]) => ({
79
+ key,
80
+ label: key,
81
+ findings: items,
82
+ count: items.length,
83
+ criticalCount: items.filter((f) => f.severity === "critical").length,
84
+ highCount: items.filter((f) => f.severity === "high").length,
85
+ }))
86
+ .sort((a, b) => b.criticalCount - a.criticalCount || b.highCount - a.highCount || b.count - a.count);
87
+ return {
88
+ groupBy,
89
+ groups: sortedGroups,
90
+ totalFindings: findings.length,
91
+ totalGroups: sortedGroups.length,
92
+ };
93
+ }
94
+ // ─── CLI ────────────────────────────────────────────────────────────────────
95
+ export function runGroupFindings(argv) {
96
+ if (argv.includes("--help") || argv.includes("-h")) {
97
+ console.log(`
98
+ judges group — Group findings by category, severity, file, rule, or judge
99
+
100
+ Usage:
101
+ judges group --input results.json Group by category (default)
102
+ judges group --input results.json --by severity Group by severity
103
+ judges group --input results.json --by file Group by file
104
+
105
+ Options:
106
+ --input <path> Path to JSON results file (required)
107
+ --by <key> Group by: category, severity, file, rule, judge (default: category)
108
+ --format json JSON output
109
+ --help, -h Show this help
110
+ `);
111
+ return;
112
+ }
113
+ const { readFileSync, existsSync } = require("fs");
114
+ const inputPath = argv.find((_a, i) => argv[i - 1] === "--input");
115
+ if (!inputPath || !existsSync(inputPath)) {
116
+ console.error("Error: --input <path> required (JSON results file)");
117
+ process.exit(1);
118
+ }
119
+ const byArg = argv.find((_a, i) => argv[i - 1] === "--by") || "category";
120
+ const validKeys = new Set(["category", "severity", "file", "rule", "judge"]);
121
+ if (!validKeys.has(byArg)) {
122
+ console.error(`Error: --by must be one of: ${[...validKeys].join(", ")}`);
123
+ process.exit(1);
124
+ }
125
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
126
+ const data = JSON.parse(readFileSync(inputPath, "utf-8"));
127
+ const findings = data.evaluations
128
+ ? data.evaluations.flatMap((e) => e.findings || [])
129
+ : data.findings || data;
130
+ const report = groupFindings(findings, byArg);
131
+ if (format === "json") {
132
+ console.log(JSON.stringify(report, null, 2));
133
+ return;
134
+ }
135
+ console.log(`\n Findings Grouped by ${report.groupBy}\n`);
136
+ console.log(` Total: ${report.totalFindings} findings in ${report.totalGroups} groups\n`);
137
+ for (const g of report.groups) {
138
+ const badges = [];
139
+ if (g.criticalCount > 0)
140
+ badges.push(`🔴 ${g.criticalCount} critical`);
141
+ if (g.highCount > 0)
142
+ badges.push(`🟠 ${g.highCount} high`);
143
+ const badge = badges.length > 0 ? ` (${badges.join(", ")})` : "";
144
+ console.log(` 📁 ${g.label} — ${g.count} findings${badge}`);
145
+ for (const f of g.findings.slice(0, 5)) {
146
+ const loc = f.lineNumbers?.length ? `:${f.lineNumbers[0]}` : "";
147
+ console.log(` ${f.severity.padEnd(8)} ${f.ruleId}: ${f.title.slice(0, 80)}${loc}`);
148
+ }
149
+ if (g.findings.length > 5) {
150
+ console.log(` ... and ${g.findings.length - 5} more`);
151
+ }
152
+ console.log("");
153
+ }
154
+ }
155
+ //# sourceMappingURL=group-findings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-findings.js","sourceRoot":"","sources":["../../src/commands/group-findings.ts"],"names":[],"mappings":"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"}