@kevinrabun/judges 3.41.0 → 3.43.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 (82) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +126 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/assign-findings.d.ts +37 -0
  6. package/dist/commands/assign-findings.d.ts.map +1 -0
  7. package/dist/commands/assign-findings.js +178 -0
  8. package/dist/commands/assign-findings.js.map +1 -0
  9. package/dist/commands/auto-triage.d.ts +32 -0
  10. package/dist/commands/auto-triage.d.ts.map +1 -0
  11. package/dist/commands/auto-triage.js +126 -0
  12. package/dist/commands/auto-triage.js.map +1 -0
  13. package/dist/commands/ci-template.d.ts +15 -0
  14. package/dist/commands/ci-template.d.ts.map +1 -0
  15. package/dist/commands/ci-template.js +212 -0
  16. package/dist/commands/ci-template.js.map +1 -0
  17. package/dist/commands/coverage-map.d.ts +23 -0
  18. package/dist/commands/coverage-map.d.ts.map +1 -0
  19. package/dist/commands/coverage-map.js +223 -0
  20. package/dist/commands/coverage-map.js.map +1 -0
  21. package/dist/commands/diff-only.d.ts +34 -0
  22. package/dist/commands/diff-only.d.ts.map +1 -0
  23. package/dist/commands/diff-only.js +152 -0
  24. package/dist/commands/diff-only.js.map +1 -0
  25. package/dist/commands/false-negatives.d.ts +35 -0
  26. package/dist/commands/false-negatives.d.ts.map +1 -0
  27. package/dist/commands/false-negatives.js +166 -0
  28. package/dist/commands/false-negatives.js.map +1 -0
  29. package/dist/commands/group-findings.d.ts +23 -0
  30. package/dist/commands/group-findings.d.ts.map +1 -0
  31. package/dist/commands/group-findings.js +155 -0
  32. package/dist/commands/group-findings.js.map +1 -0
  33. package/dist/commands/hook-install.d.ts +22 -0
  34. package/dist/commands/hook-install.d.ts.map +1 -0
  35. package/dist/commands/hook-install.js +143 -0
  36. package/dist/commands/hook-install.js.map +1 -0
  37. package/dist/commands/policy-audit.d.ts +53 -0
  38. package/dist/commands/policy-audit.d.ts.map +1 -0
  39. package/dist/commands/policy-audit.js +161 -0
  40. package/dist/commands/policy-audit.js.map +1 -0
  41. package/dist/commands/pr-summary.d.ts +26 -0
  42. package/dist/commands/pr-summary.d.ts.map +1 -0
  43. package/dist/commands/pr-summary.js +188 -0
  44. package/dist/commands/pr-summary.js.map +1 -0
  45. package/dist/commands/profile.d.ts +38 -0
  46. package/dist/commands/profile.d.ts.map +1 -0
  47. package/dist/commands/profile.js +102 -0
  48. package/dist/commands/profile.js.map +1 -0
  49. package/dist/commands/regression-alert.d.ts +32 -0
  50. package/dist/commands/regression-alert.d.ts.map +1 -0
  51. package/dist/commands/regression-alert.js +216 -0
  52. package/dist/commands/regression-alert.js.map +1 -0
  53. package/dist/commands/remediation.d.ts +21 -0
  54. package/dist/commands/remediation.d.ts.map +1 -0
  55. package/dist/commands/remediation.js +257 -0
  56. package/dist/commands/remediation.js.map +1 -0
  57. package/dist/commands/sla-track.d.ts +57 -0
  58. package/dist/commands/sla-track.d.ts.map +1 -0
  59. package/dist/commands/sla-track.js +269 -0
  60. package/dist/commands/sla-track.js.map +1 -0
  61. package/dist/commands/smart-select.d.ts +27 -0
  62. package/dist/commands/smart-select.d.ts.map +1 -0
  63. package/dist/commands/smart-select.js +346 -0
  64. package/dist/commands/smart-select.js.map +1 -0
  65. package/dist/commands/ticket-sync.d.ts +26 -0
  66. package/dist/commands/ticket-sync.d.ts.map +1 -0
  67. package/dist/commands/ticket-sync.js +236 -0
  68. package/dist/commands/ticket-sync.js.map +1 -0
  69. package/dist/commands/upload.d.ts +14 -0
  70. package/dist/commands/upload.d.ts.map +1 -0
  71. package/dist/commands/upload.js +173 -0
  72. package/dist/commands/upload.js.map +1 -0
  73. package/dist/commands/validate-config.d.ts +17 -0
  74. package/dist/commands/validate-config.d.ts.map +1 -0
  75. package/dist/commands/validate-config.js +268 -0
  76. package/dist/commands/validate-config.js.map +1 -0
  77. package/dist/commands/warm-cache.d.ts +31 -0
  78. package/dist/commands/warm-cache.d.ts.map +1 -0
  79. package/dist/commands/warm-cache.js +166 -0
  80. package/dist/commands/warm-cache.js.map +1 -0
  81. package/package.json +1 -1
  82. 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,35 @@
1
+ /**
2
+ * False-negative report — collect and analyze cases where Judges
3
+ * missed a real vulnerability or bug that was later found manually.
4
+ *
5
+ * Builds a local feedback database (.judges-false-negatives.json)
6
+ * that helps teams understand blind spots and request new rules.
7
+ */
8
+ export interface FalseNegativeEntry {
9
+ id: string;
10
+ timestamp: string;
11
+ file: string;
12
+ line?: number;
13
+ category: string;
14
+ description: string;
15
+ severity: string;
16
+ expectedRule?: string;
17
+ language: string;
18
+ codeSnippet?: string;
19
+ reportedBy?: string;
20
+ status: "open" | "rule-added" | "wont-fix" | "duplicate";
21
+ }
22
+ export interface FalseNegativeDb {
23
+ entries: FalseNegativeEntry[];
24
+ version: string;
25
+ }
26
+ export declare function addFalseNegative(entry: Omit<FalseNegativeEntry, "id" | "timestamp" | "status">): FalseNegativeEntry;
27
+ export declare function getFalseNegativeStats(db: FalseNegativeDb): {
28
+ total: number;
29
+ open: number;
30
+ byCategory: Record<string, number>;
31
+ bySeverity: Record<string, number>;
32
+ byLanguage: Record<string, number>;
33
+ };
34
+ export declare function runFalseNegativeReport(argv: string[]): void;
35
+ //# sourceMappingURL=false-negatives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"false-negatives.d.ts","sourceRoot":"","sources":["../../src/commands/false-negatives.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,CAAC;CAC1D;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAuBD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,GAAG,WAAW,GAAG,QAAQ,CAAC,GAAG,kBAAkB,CAcnH;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,eAAe,GAAG;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,CAaA;AAID,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA2G3D"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * False-negative report — collect and analyze cases where Judges
3
+ * missed a real vulnerability or bug that was later found manually.
4
+ *
5
+ * Builds a local feedback database (.judges-false-negatives.json)
6
+ * that helps teams understand blind spots and request new rules.
7
+ */
8
+ import { createHash } from "crypto";
9
+ // ─── Database ───────────────────────────────────────────────────────────────
10
+ const DB_FILE = ".judges-false-negatives.json";
11
+ function loadDb() {
12
+ const { readFileSync, existsSync } = require("fs");
13
+ if (existsSync(DB_FILE)) {
14
+ try {
15
+ return JSON.parse(readFileSync(DB_FILE, "utf-8"));
16
+ }
17
+ catch {
18
+ /* corrupt */
19
+ }
20
+ }
21
+ return { entries: [], version: "1.0" };
22
+ }
23
+ function saveDb(db) {
24
+ const { writeFileSync } = require("fs");
25
+ writeFileSync(DB_FILE, JSON.stringify(db, null, 2), "utf-8");
26
+ }
27
+ export function addFalseNegative(entry) {
28
+ const db = loadDb();
29
+ const fn = {
30
+ ...entry,
31
+ id: createHash("sha256")
32
+ .update(Date.now().toString() + entry.file + entry.description)
33
+ .digest("hex")
34
+ .slice(0, 10),
35
+ timestamp: new Date().toISOString(),
36
+ status: "open",
37
+ };
38
+ db.entries.push(fn);
39
+ saveDb(db);
40
+ return fn;
41
+ }
42
+ export function getFalseNegativeStats(db) {
43
+ const open = db.entries.filter((e) => e.status === "open").length;
44
+ const byCategory = {};
45
+ const bySeverity = {};
46
+ const byLanguage = {};
47
+ for (const e of db.entries) {
48
+ byCategory[e.category] = (byCategory[e.category] || 0) + 1;
49
+ bySeverity[e.severity] = (bySeverity[e.severity] || 0) + 1;
50
+ byLanguage[e.language] = (byLanguage[e.language] || 0) + 1;
51
+ }
52
+ return { total: db.entries.length, open, byCategory, bySeverity, byLanguage };
53
+ }
54
+ // ─── CLI ────────────────────────────────────────────────────────────────────
55
+ export function runFalseNegativeReport(argv) {
56
+ if (argv.includes("--help") || argv.includes("-h")) {
57
+ console.log(`
58
+ judges false-negatives — Report and track missed vulnerabilities
59
+
60
+ Usage:
61
+ judges false-negatives Show report
62
+ judges false-negatives --add --file src/app.ts \\
63
+ --line 42 --category injection --severity high \\
64
+ --description "SQL injection via user input" Add a missed finding
65
+ judges false-negatives --resolve <id> Mark as resolved
66
+
67
+ Options:
68
+ --add Add a new false-negative report
69
+ --file <path> File where the issue was found
70
+ --line <n> Line number
71
+ --category <cat> Category (injection, auth, crypto, xss, etc.)
72
+ --severity <level> Severity (critical, high, medium, low)
73
+ --description <text> Description of what was missed
74
+ --language <lang> Language (auto-detected from file)
75
+ --resolve <id> Mark entry as resolved
76
+ --format json JSON output
77
+ --help, -h Show this help
78
+
79
+ This builds a local feedback database that helps identify blind spots
80
+ in the current rule set, informing future rule development.
81
+ `);
82
+ return;
83
+ }
84
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
85
+ if (argv.includes("--add")) {
86
+ const file = argv.find((_a, i) => argv[i - 1] === "--file") || "";
87
+ const lineStr = argv.find((_a, i) => argv[i - 1] === "--line");
88
+ const category = argv.find((_a, i) => argv[i - 1] === "--category") || "unknown";
89
+ const severity = argv.find((_a, i) => argv[i - 1] === "--severity") || "medium";
90
+ const description = argv.find((_a, i) => argv[i - 1] === "--description") || "";
91
+ const language = argv.find((_a, i) => argv[i - 1] === "--language") || detectLanguage(file);
92
+ if (!file || !description) {
93
+ console.error("Error: --file and --description required");
94
+ process.exit(1);
95
+ }
96
+ const entry = addFalseNegative({
97
+ file,
98
+ line: lineStr ? parseInt(lineStr, 10) : undefined,
99
+ category,
100
+ severity,
101
+ description,
102
+ language,
103
+ });
104
+ console.log(` ✅ Added false-negative report: ${entry.id}`);
105
+ return;
106
+ }
107
+ const resolveId = argv.find((_a, i) => argv[i - 1] === "--resolve");
108
+ if (resolveId) {
109
+ const db = loadDb();
110
+ const entry = db.entries.find((e) => e.id === resolveId);
111
+ if (!entry) {
112
+ console.error(`Error: entry ${resolveId} not found`);
113
+ process.exit(1);
114
+ }
115
+ entry.status = "rule-added";
116
+ saveDb(db);
117
+ console.log(` ✅ Resolved: ${resolveId}`);
118
+ return;
119
+ }
120
+ // Show report
121
+ const db = loadDb();
122
+ if (db.entries.length === 0) {
123
+ console.log("\n No false-negative reports. Use --add to report a missed finding.\n");
124
+ return;
125
+ }
126
+ const stats = getFalseNegativeStats(db);
127
+ if (format === "json") {
128
+ console.log(JSON.stringify({ stats, entries: db.entries }, null, 2));
129
+ return;
130
+ }
131
+ console.log(`\n False-Negative Analysis\n`);
132
+ console.log(` Total: ${stats.total} | Open: ${stats.open}\n`);
133
+ console.log(" By Category:");
134
+ for (const [cat, count] of Object.entries(stats.byCategory).sort((a, b) => b[1] - a[1])) {
135
+ console.log(` ${cat.padEnd(20)} ${count}`);
136
+ }
137
+ console.log("\n By Severity:");
138
+ for (const [sev, count] of Object.entries(stats.bySeverity).sort((a, b) => b[1] - a[1])) {
139
+ console.log(` ${sev.padEnd(20)} ${count}`);
140
+ }
141
+ console.log("\n Recent entries:");
142
+ for (const e of db.entries.slice(-10)) {
143
+ const status = e.status === "open" ? "🔴" : "✅";
144
+ console.log(` ${status} ${e.id} ${e.severity.padEnd(8)} ${e.category.padEnd(15)} ${e.description.slice(0, 50)}`);
145
+ }
146
+ console.log("");
147
+ }
148
+ function detectLanguage(file) {
149
+ const { extname } = require("path");
150
+ const ext = extname(file).toLowerCase();
151
+ const map = {
152
+ ".ts": "typescript",
153
+ ".tsx": "typescript",
154
+ ".js": "javascript",
155
+ ".jsx": "javascript",
156
+ ".py": "python",
157
+ ".go": "go",
158
+ ".rs": "rust",
159
+ ".java": "java",
160
+ ".cs": "csharp",
161
+ ".rb": "ruby",
162
+ ".php": "php",
163
+ };
164
+ return map[ext] || "unknown";
165
+ }
166
+ //# sourceMappingURL=false-negatives.js.map