@kevinrabun/judges 3.42.0 → 3.44.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 (74) hide show
  1. package/CHANGELOG.md +25 -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/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/burndown.d.ts +27 -0
  10. package/dist/commands/burndown.d.ts.map +1 -0
  11. package/dist/commands/burndown.js +180 -0
  12. package/dist/commands/burndown.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/false-negatives.d.ts +35 -0
  18. package/dist/commands/false-negatives.d.ts.map +1 -0
  19. package/dist/commands/false-negatives.js +166 -0
  20. package/dist/commands/false-negatives.js.map +1 -0
  21. package/dist/commands/hook-install.d.ts +22 -0
  22. package/dist/commands/hook-install.d.ts.map +1 -0
  23. package/dist/commands/hook-install.js +143 -0
  24. package/dist/commands/hook-install.js.map +1 -0
  25. package/dist/commands/kb.d.ts +41 -0
  26. package/dist/commands/kb.d.ts.map +1 -0
  27. package/dist/commands/kb.js +231 -0
  28. package/dist/commands/kb.js.map +1 -0
  29. package/dist/commands/noise-advisor.d.ts +30 -0
  30. package/dist/commands/noise-advisor.d.ts.map +1 -0
  31. package/dist/commands/noise-advisor.js +171 -0
  32. package/dist/commands/noise-advisor.js.map +1 -0
  33. package/dist/commands/policy-audit.d.ts +53 -0
  34. package/dist/commands/policy-audit.d.ts.map +1 -0
  35. package/dist/commands/policy-audit.js +161 -0
  36. package/dist/commands/policy-audit.js.map +1 -0
  37. package/dist/commands/recommend.d.ts +21 -0
  38. package/dist/commands/recommend.d.ts.map +1 -0
  39. package/dist/commands/recommend.js +283 -0
  40. package/dist/commands/recommend.js.map +1 -0
  41. package/dist/commands/regression-alert.d.ts +32 -0
  42. package/dist/commands/regression-alert.d.ts.map +1 -0
  43. package/dist/commands/regression-alert.js +216 -0
  44. package/dist/commands/regression-alert.js.map +1 -0
  45. package/dist/commands/remediation.d.ts +21 -0
  46. package/dist/commands/remediation.d.ts.map +1 -0
  47. package/dist/commands/remediation.js +257 -0
  48. package/dist/commands/remediation.js.map +1 -0
  49. package/dist/commands/report-template.d.ts +17 -0
  50. package/dist/commands/report-template.d.ts.map +1 -0
  51. package/dist/commands/report-template.js +291 -0
  52. package/dist/commands/report-template.js.map +1 -0
  53. package/dist/commands/review-queue.d.ts +34 -0
  54. package/dist/commands/review-queue.d.ts.map +1 -0
  55. package/dist/commands/review-queue.js +226 -0
  56. package/dist/commands/review-queue.js.map +1 -0
  57. package/dist/commands/rule-owner.d.ts +31 -0
  58. package/dist/commands/rule-owner.d.ts.map +1 -0
  59. package/dist/commands/rule-owner.js +182 -0
  60. package/dist/commands/rule-owner.js.map +1 -0
  61. package/dist/commands/sla-track.d.ts +57 -0
  62. package/dist/commands/sla-track.d.ts.map +1 -0
  63. package/dist/commands/sla-track.js +269 -0
  64. package/dist/commands/sla-track.js.map +1 -0
  65. package/dist/commands/suppress.d.ts +40 -0
  66. package/dist/commands/suppress.d.ts.map +1 -0
  67. package/dist/commands/suppress.js +209 -0
  68. package/dist/commands/suppress.js.map +1 -0
  69. package/dist/commands/ticket-sync.d.ts +26 -0
  70. package/dist/commands/ticket-sync.d.ts.map +1 -0
  71. package/dist/commands/ticket-sync.js +236 -0
  72. package/dist/commands/ticket-sync.js.map +1 -0
  73. package/package.json +1 -1
  74. package/server.json +2 -2
@@ -0,0 +1,291 @@
1
+ /**
2
+ * Report templates — generate reports from different predefined
3
+ * templates targeting different audiences (exec, dev, compliance).
4
+ *
5
+ * Pure local generation — no external services.
6
+ */
7
+ import { readFileSync, writeFileSync, existsSync } from "fs";
8
+ // ─── Templates ──────────────────────────────────────────────────────────────
9
+ const TEMPLATES = [
10
+ {
11
+ id: "exec-summary",
12
+ name: "Executive Summary",
13
+ audience: "Leadership",
14
+ description: "One-page overview with verdict, risk score, and trend",
15
+ },
16
+ {
17
+ id: "dev-detail",
18
+ name: "Developer Detail",
19
+ audience: "Developers",
20
+ description: "Full findings with code locations, fixes, and references",
21
+ },
22
+ {
23
+ id: "compliance",
24
+ name: "Compliance Report",
25
+ audience: "Auditors",
26
+ description: "SOC2/ISO-aligned report with policy hash and evidence",
27
+ },
28
+ {
29
+ id: "pr-review",
30
+ name: "PR Review",
31
+ audience: "Code Reviewers",
32
+ description: "Focused diff-aware summary for PR review",
33
+ },
34
+ {
35
+ id: "trend",
36
+ name: "Trend Report",
37
+ audience: "Management",
38
+ description: "Historical comparison showing improvement trajectory",
39
+ },
40
+ {
41
+ id: "onboarding",
42
+ name: "Onboarding Report",
43
+ audience: "New Team Members",
44
+ description: "Gentle introduction to codebase health with learning resources",
45
+ },
46
+ ];
47
+ // ─── Report Generators ─────────────────────────────────────────────────────
48
+ function renderExecSummary(verdict) {
49
+ const critical = verdict.criticalCount || 0;
50
+ const high = verdict.highCount || 0;
51
+ const lines = [
52
+ "# Executive Summary — Code Review Report",
53
+ "",
54
+ `**Date:** ${new Date().toISOString().split("T")[0]}`,
55
+ `**Verdict:** ${verdict.overallVerdict.toUpperCase()}`,
56
+ `**Score:** ${verdict.overallScore}/100`,
57
+ "",
58
+ "## Risk Overview",
59
+ "",
60
+ `| Metric | Value |`,
61
+ `|--------|-------|`,
62
+ `| Critical findings | ${critical} |`,
63
+ `| High findings | ${high} |`,
64
+ `| Total findings | ${verdict.findings.length} |`,
65
+ `| Judges evaluated | ${verdict.evaluations.length} |`,
66
+ "",
67
+ "## Summary",
68
+ "",
69
+ verdict.summary,
70
+ "",
71
+ "## Action Required",
72
+ "",
73
+ ];
74
+ if (critical > 0) {
75
+ lines.push("**IMMEDIATE ACTION:** Critical findings require attention within 24 hours.");
76
+ }
77
+ else if (high > 0) {
78
+ lines.push("**ACTION NEEDED:** High-severity findings should be addressed this sprint.");
79
+ }
80
+ else {
81
+ lines.push("**STATUS:** No critical issues. Continue monitoring.");
82
+ }
83
+ lines.push("", "---", "_Generated by Judges_");
84
+ return lines.join("\n");
85
+ }
86
+ function renderDevDetail(verdict) {
87
+ const lines = [
88
+ "# Developer Report — Detailed Findings",
89
+ "",
90
+ `**Verdict:** ${verdict.overallVerdict} (${verdict.overallScore}/100)`,
91
+ `**Findings:** ${verdict.findings.length}`,
92
+ "",
93
+ ];
94
+ const bySeverity = {};
95
+ for (const f of verdict.findings) {
96
+ (bySeverity[f.severity] ??= []).push(f);
97
+ }
98
+ for (const sev of ["critical", "high", "medium", "low", "info"]) {
99
+ const findings = bySeverity[sev];
100
+ if (!findings?.length)
101
+ continue;
102
+ lines.push(`## ${sev.toUpperCase()} (${findings.length})`, "");
103
+ for (const f of findings) {
104
+ lines.push(`### ${f.ruleId}: ${f.title}`);
105
+ if (f.lineNumbers?.length)
106
+ lines.push(`**Lines:** ${f.lineNumbers.join(", ")}`);
107
+ lines.push("", f.description, "");
108
+ lines.push("**Fix:**", f.recommendation, "");
109
+ if (f.reference)
110
+ lines.push(`**Reference:** ${f.reference}`, "");
111
+ lines.push("---", "");
112
+ }
113
+ }
114
+ return lines.join("\n");
115
+ }
116
+ function renderComplianceReport(verdict) {
117
+ const lines = [
118
+ "# Compliance Report",
119
+ "",
120
+ `**Generated:** ${new Date().toISOString()}`,
121
+ `**Verdict:** ${verdict.overallVerdict}`,
122
+ `**Score:** ${verdict.overallScore}/100`,
123
+ "",
124
+ "## Evaluation Summary",
125
+ "",
126
+ `| Judge | Verdict | Score | Findings |`,
127
+ `|-------|---------|-------|----------|`,
128
+ ];
129
+ for (const e of verdict.evaluations) {
130
+ lines.push(`| ${e.judgeId} | ${e.verdict} | ${e.score} | ${e.findings.length} |`);
131
+ }
132
+ lines.push("", "## Finding Categories", "", "| Severity | Count |", "|----------|-------|");
133
+ const bySev = {};
134
+ for (const f of verdict.findings) {
135
+ bySev[f.severity] = (bySev[f.severity] || 0) + 1;
136
+ }
137
+ for (const [s, c] of Object.entries(bySev)) {
138
+ lines.push(`| ${s} | ${c} |`);
139
+ }
140
+ lines.push("", "## Evidence", "", `- Total judges evaluated: ${verdict.evaluations.length}`, `- Total findings: ${verdict.findings.length}`, `- Critical count: ${verdict.criticalCount || 0}`, `- High count: ${verdict.highCount || 0}`, "", "---", "_Audit report generated by Judges_");
141
+ return lines.join("\n");
142
+ }
143
+ function renderTrendReport(verdict) {
144
+ const lines = [
145
+ "# Trend Report",
146
+ "",
147
+ `**Current Score:** ${verdict.overallScore}/100`,
148
+ `**Current Findings:** ${verdict.findings.length}`,
149
+ "",
150
+ "## Current Snapshot",
151
+ "",
152
+ ];
153
+ const bySev = {};
154
+ for (const f of verdict.findings) {
155
+ bySev[f.severity] = (bySev[f.severity] || 0) + 1;
156
+ }
157
+ lines.push("| Severity | Count |", "|----------|-------|");
158
+ for (const [s, c] of Object.entries(bySev)) {
159
+ lines.push(`| ${s} | ${c} |`);
160
+ }
161
+ lines.push("", "## Top Rules", "", "| Rule | Count |", "|------|-------|");
162
+ const byRule = {};
163
+ for (const f of verdict.findings) {
164
+ byRule[f.ruleId] = (byRule[f.ruleId] || 0) + 1;
165
+ }
166
+ const sorted = Object.entries(byRule)
167
+ .sort((a, b) => b[1] - a[1])
168
+ .slice(0, 10);
169
+ for (const [r, c] of sorted) {
170
+ lines.push(`| ${r} | ${c} |`);
171
+ }
172
+ lines.push("", "> Compare with `judges regression-alert --check` for baseline comparison.", "", "---", "_Generated by Judges_");
173
+ return lines.join("\n");
174
+ }
175
+ function renderOnboarding(verdict) {
176
+ const lines = [
177
+ "# Welcome to Your Codebase Health Report",
178
+ "",
179
+ "This report helps new team members understand the current code quality state.",
180
+ "",
181
+ `**Overall Score:** ${verdict.overallScore}/100 (${verdict.overallVerdict})`,
182
+ `**Total Findings:** ${verdict.findings.length}`,
183
+ "",
184
+ "## What Do These Findings Mean?",
185
+ "",
186
+ "Findings are categorized by severity:",
187
+ "- **Critical/High:** Security issues that must be fixed",
188
+ "- **Medium:** Best practice violations worth addressing",
189
+ "- **Low/Info:** Suggestions for improvement",
190
+ "",
191
+ "## Key Areas to Learn",
192
+ "",
193
+ ];
194
+ const categories = new Set(verdict.findings.map((f) => f.ruleId.split("-")[0]));
195
+ const catDescriptions = {
196
+ SEC: "Security vulnerabilities (injections, XSS, etc.)",
197
+ AUTH: "Authentication and authorization issues",
198
+ CRYPTO: "Cryptography best practices",
199
+ PERF: "Performance optimization opportunities",
200
+ ERR: "Error handling patterns",
201
+ IAC: "Infrastructure as Code security",
202
+ SSRF: "Server-side request forgery prevention",
203
+ CONCUR: "Concurrency and race condition safety",
204
+ };
205
+ for (const cat of categories) {
206
+ lines.push(`- **${cat}:** ${catDescriptions[cat] || "Code quality rules"}`);
207
+ }
208
+ lines.push("", "## Getting Started", "", "1. Run `judges remediation <rule-id>` for fix guides", "2. Run `judges explain <rule-id>` for rule details", "3. Ask your team lead about suppression policies", "", "---", "_Generated by Judges_");
209
+ return lines.join("\n");
210
+ }
211
+ // ─── Public API ─────────────────────────────────────────────────────────────
212
+ export function listTemplates() {
213
+ return TEMPLATES;
214
+ }
215
+ export function generateReport(templateId, verdict) {
216
+ switch (templateId) {
217
+ case "exec-summary":
218
+ return renderExecSummary(verdict);
219
+ case "dev-detail":
220
+ return renderDevDetail(verdict);
221
+ case "compliance":
222
+ return renderComplianceReport(verdict);
223
+ case "trend":
224
+ return renderTrendReport(verdict);
225
+ case "onboarding":
226
+ return renderOnboarding(verdict);
227
+ case "pr-review":
228
+ return renderDevDetail(verdict); // reuse dev detail for PR
229
+ default:
230
+ throw new Error(`Unknown template: ${templateId}. Use --list to see options.`);
231
+ }
232
+ }
233
+ // ─── CLI ────────────────────────────────────────────────────────────────────
234
+ export function runReportTemplate(argv) {
235
+ if (argv.includes("--help") || argv.includes("-h")) {
236
+ console.log(`
237
+ judges report-template — Generate reports from predefined templates
238
+
239
+ Usage:
240
+ judges report-template --list List available templates
241
+ judges report-template --template exec-summary --input results.json
242
+ judges report-template --template dev-detail --input results.json --output report.md
243
+
244
+ Options:
245
+ --template <id> Template to use (required)
246
+ --input <path> Results JSON file (required)
247
+ --output <path> Write report to file (default: stdout)
248
+ --list List available templates
249
+ --help, -h Show this help
250
+
251
+ Templates:
252
+ exec-summary One-page leadership overview
253
+ dev-detail Full findings with fixes
254
+ compliance SOC2/ISO-aligned evidence report
255
+ pr-review Diff-aware PR summary
256
+ trend Historical comparison
257
+ onboarding New team member introduction
258
+ `);
259
+ return;
260
+ }
261
+ if (argv.includes("--list")) {
262
+ console.log("\n Report Templates\n ────────────────");
263
+ for (const t of TEMPLATES) {
264
+ console.log(` ${t.id.padEnd(16)} ${t.name} (${t.audience})`);
265
+ console.log(` ${t.description}`);
266
+ }
267
+ console.log("");
268
+ return;
269
+ }
270
+ const templateId = argv.find((_a, i) => argv[i - 1] === "--template");
271
+ const inputPath = argv.find((_a, i) => argv[i - 1] === "--input");
272
+ const outputPath = argv.find((_a, i) => argv[i - 1] === "--output");
273
+ if (!templateId || !inputPath) {
274
+ console.error("Error: --template and --input required");
275
+ process.exit(1);
276
+ }
277
+ if (!existsSync(inputPath)) {
278
+ console.error(`Error: file not found: ${inputPath}`);
279
+ process.exit(1);
280
+ }
281
+ const verdict = JSON.parse(readFileSync(inputPath, "utf-8"));
282
+ const report = generateReport(templateId, verdict);
283
+ if (outputPath) {
284
+ writeFileSync(outputPath, report);
285
+ console.log(` Report written to ${outputPath}`);
286
+ }
287
+ else {
288
+ console.log(report);
289
+ }
290
+ }
291
+ //# sourceMappingURL=report-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report-template.js","sourceRoot":"","sources":["../../src/commands/report-template.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Review queue — surface findings needing human judgment and route
3
+ * them to appropriate experts based on rule ownership.
4
+ *
5
+ * Uses local data from findings, rule-owners, and feedback.
6
+ */
7
+ import type { Finding } from "../types.js";
8
+ export interface ReviewItem {
9
+ id: string;
10
+ ruleId: string;
11
+ severity: string;
12
+ title: string;
13
+ description: string;
14
+ confidence: number;
15
+ recommendedReviewer?: string;
16
+ status: "pending" | "approved" | "dismissed" | "escalated";
17
+ verdict?: string;
18
+ reviewedBy?: string;
19
+ reviewedIso?: string;
20
+ addedIso: string;
21
+ }
22
+ export declare function addToReviewQueue(findings: Finding[], confidenceThreshold?: number): ReviewItem[];
23
+ export declare function reviewItem(id: string, verdict: "approved" | "dismissed" | "escalated", reviewer: string): void;
24
+ export declare function getQueueStats(): {
25
+ total: number;
26
+ pending: number;
27
+ approved: number;
28
+ dismissed: number;
29
+ escalated: number;
30
+ byReviewer: Record<string, number>;
31
+ avgConfidence: number;
32
+ };
33
+ export declare function runReviewQueue(argv: string[]): Promise<void>;
34
+ //# sourceMappingURL=review-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-queue.d.ts","sourceRoot":"","sources":["../../src/commands/review-queue.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,WAAW,CAAC;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AA6CD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,mBAAmB,SAAM,GAAG,UAAU,EAAE,CA+B7F;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,WAAW,GAAG,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAS9G;AAED,wBAAgB,aAAa,IAAI;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,aAAa,EAAE,MAAM,CAAC;CACvB,CAuBA;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA0HlE"}
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Review queue — surface findings needing human judgment and route
3
+ * them to appropriate experts based on rule ownership.
4
+ *
5
+ * Uses local data from findings, rule-owners, and feedback.
6
+ */
7
+ import { readFileSync, writeFileSync, existsSync } from "fs";
8
+ const REVIEW_FILE = ".judges-review-queue.json";
9
+ // ─── Core ───────────────────────────────────────────────────────────────────
10
+ function loadDb(file = REVIEW_FILE) {
11
+ if (!existsSync(file))
12
+ return { items: [] };
13
+ return JSON.parse(readFileSync(file, "utf-8"));
14
+ }
15
+ function saveDb(db, file = REVIEW_FILE) {
16
+ writeFileSync(file, JSON.stringify(db, null, 2));
17
+ }
18
+ function itemId(f) {
19
+ return `${f.ruleId}:${f.title}`.slice(0, 80);
20
+ }
21
+ function resolveReviewer(ruleId) {
22
+ try {
23
+ const ownerFile = ".judges-owners.json";
24
+ if (!existsSync(ownerFile))
25
+ return undefined;
26
+ const db = JSON.parse(readFileSync(ownerFile, "utf-8"));
27
+ if (!db.owners)
28
+ return undefined;
29
+ // Exact match first
30
+ const exact = db.owners.find((o) => o.pattern === ruleId);
31
+ if (exact)
32
+ return exact.owner;
33
+ // Prefix match
34
+ let best;
35
+ for (const o of db.owners) {
36
+ if (ruleId.startsWith(o.pattern) && (!best || o.pattern.length > best.pattern.length)) {
37
+ best = o;
38
+ }
39
+ }
40
+ return best?.owner;
41
+ }
42
+ catch {
43
+ return undefined;
44
+ }
45
+ }
46
+ export function addToReviewQueue(findings, confidenceThreshold = 0.6) {
47
+ const db = loadDb();
48
+ const existing = new Set(db.items.map((i) => i.id));
49
+ const added = [];
50
+ const now = new Date().toISOString();
51
+ for (const f of findings) {
52
+ const conf = f.confidence ?? 0.5;
53
+ if (conf >= confidenceThreshold)
54
+ continue; // High-confidence: auto-approved
55
+ const id = itemId(f);
56
+ if (existing.has(id))
57
+ continue;
58
+ const item = {
59
+ id,
60
+ ruleId: f.ruleId,
61
+ severity: f.severity,
62
+ title: f.title,
63
+ description: f.description,
64
+ confidence: conf,
65
+ recommendedReviewer: resolveReviewer(f.ruleId),
66
+ status: "pending",
67
+ addedIso: now,
68
+ };
69
+ db.items.push(item);
70
+ added.push(item);
71
+ existing.add(id);
72
+ }
73
+ saveDb(db);
74
+ return added;
75
+ }
76
+ export function reviewItem(id, verdict, reviewer) {
77
+ const db = loadDb();
78
+ const item = db.items.find((i) => i.id === id);
79
+ if (!item)
80
+ throw new Error(`Review item not found: ${id}`);
81
+ item.status = verdict;
82
+ item.verdict = verdict;
83
+ item.reviewedBy = reviewer;
84
+ item.reviewedIso = new Date().toISOString();
85
+ saveDb(db);
86
+ }
87
+ export function getQueueStats() {
88
+ const db = loadDb();
89
+ const stats = {
90
+ total: db.items.length,
91
+ pending: db.items.filter((i) => i.status === "pending").length,
92
+ approved: db.items.filter((i) => i.status === "approved").length,
93
+ dismissed: db.items.filter((i) => i.status === "dismissed").length,
94
+ escalated: db.items.filter((i) => i.status === "escalated").length,
95
+ byReviewer: {},
96
+ avgConfidence: 0,
97
+ };
98
+ for (const i of db.items) {
99
+ const reviewer = i.recommendedReviewer || "unassigned";
100
+ stats.byReviewer[reviewer] = (stats.byReviewer[reviewer] || 0) + 1;
101
+ }
102
+ const pending = db.items.filter((i) => i.status === "pending");
103
+ if (pending.length > 0) {
104
+ stats.avgConfidence = Math.round((pending.reduce((s, i) => s + i.confidence, 0) / pending.length) * 100) / 100;
105
+ }
106
+ return stats;
107
+ }
108
+ // ─── CLI ────────────────────────────────────────────────────────────────────
109
+ export async function runReviewQueue(argv) {
110
+ if (argv.includes("--help") || argv.includes("-h")) {
111
+ console.log(`
112
+ judges review-queue — Human review queue for low-confidence findings
113
+
114
+ Usage:
115
+ judges review-queue --input results.json Add low-confidence findings to queue
116
+ judges review-queue --list Show pending review items
117
+ judges review-queue --approve <id> --reviewer "Alice"
118
+ judges review-queue --dismiss <id> --reviewer "Bob"
119
+ judges review-queue --escalate <id> --reviewer "Carol"
120
+ judges review-queue --stats Show queue statistics
121
+
122
+ Options:
123
+ --input <path> Results JSON with findings
124
+ --threshold <n> Confidence threshold (default: 0.6, below → queue)
125
+ --list Show pending items
126
+ --approve <id> Approve a finding as valid
127
+ --dismiss <id> Dismiss a finding as FP
128
+ --escalate <id> Escalate for deeper review
129
+ --reviewer <name> Reviewer name (required for verdicts)
130
+ --stats Queue statistics
131
+ --format json JSON output
132
+ --help, -h Show this help
133
+ `);
134
+ return;
135
+ }
136
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
137
+ // Add findings from input
138
+ const inputPath = argv.find((_a, i) => argv[i - 1] === "--input");
139
+ if (inputPath) {
140
+ if (!existsSync(inputPath)) {
141
+ console.error(`Error: file not found: ${inputPath}`);
142
+ process.exit(1);
143
+ }
144
+ const data = JSON.parse(readFileSync(inputPath, "utf-8"));
145
+ const findings = data.evaluations
146
+ ? data.evaluations.flatMap((e) => e.findings || [])
147
+ : data.findings || data;
148
+ const thresholdStr = argv.find((_a, i) => argv[i - 1] === "--threshold");
149
+ const threshold = thresholdStr ? parseFloat(thresholdStr) : 0.6;
150
+ const added = addToReviewQueue(findings, threshold);
151
+ if (format === "json") {
152
+ console.log(JSON.stringify(added, null, 2));
153
+ }
154
+ else {
155
+ console.log(`\n Added ${added.length} finding(s) to review queue (threshold: ${threshold})\n`);
156
+ for (const item of added.slice(0, 10)) {
157
+ console.log(` ${item.severity.padEnd(8)} ${item.ruleId.padEnd(12)} conf: ${item.confidence} → ${item.recommendedReviewer || "unassigned"}`);
158
+ }
159
+ if (added.length > 10)
160
+ console.log(` ... and ${added.length - 10} more`);
161
+ console.log("");
162
+ }
163
+ return;
164
+ }
165
+ // Verdicts
166
+ const reviewer = argv.find((_a, i) => argv[i - 1] === "--reviewer");
167
+ for (const action of ["approve", "dismiss", "escalate"]) {
168
+ const target = argv.find((_a, i) => argv[i - 1] === `--${action}`);
169
+ if (target) {
170
+ if (!reviewer) {
171
+ console.error("Error: --reviewer required");
172
+ process.exit(1);
173
+ }
174
+ const verdict = action === "approve" ? "approved" : action === "dismiss" ? "dismissed" : "escalated";
175
+ reviewItem(target, verdict, reviewer);
176
+ console.log(` ${verdict}: ${target} by ${reviewer}`);
177
+ return;
178
+ }
179
+ }
180
+ // List pending
181
+ if (argv.includes("--list")) {
182
+ const db = loadDb();
183
+ const pending = db.items.filter((i) => i.status === "pending");
184
+ if (format === "json") {
185
+ console.log(JSON.stringify(pending, null, 2));
186
+ }
187
+ else if (pending.length === 0) {
188
+ console.log("\n Review queue is empty.\n");
189
+ }
190
+ else {
191
+ console.log(`\n Pending Reviews (${pending.length})\n ──────────────────`);
192
+ for (const item of pending) {
193
+ console.log(` ${item.severity.padEnd(8)} ${item.ruleId.padEnd(12)} conf: ${item.confidence} → ${item.recommendedReviewer || "unassigned"}`);
194
+ console.log(` ${item.title}`);
195
+ console.log(` ID: ${item.id}`);
196
+ }
197
+ console.log("");
198
+ }
199
+ return;
200
+ }
201
+ // Stats (default)
202
+ const s = getQueueStats();
203
+ if (format === "json") {
204
+ console.log(JSON.stringify(s, null, 2));
205
+ }
206
+ else {
207
+ console.log(`
208
+ Review Queue
209
+ ────────────
210
+ Total: ${s.total}
211
+ Pending: ${s.pending}
212
+ Approved: ${s.approved}
213
+ Dismissed: ${s.dismissed}
214
+ Escalated: ${s.escalated}
215
+ Avg conf: ${s.avgConfidence}
216
+ `);
217
+ if (Object.keys(s.byReviewer).length > 0) {
218
+ console.log(" By reviewer:");
219
+ for (const [name, count] of Object.entries(s.byReviewer)) {
220
+ console.log(` ${name.padEnd(20)} ${count}`);
221
+ }
222
+ console.log("");
223
+ }
224
+ }
225
+ }
226
+ //# sourceMappingURL=review-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-queue.js","sourceRoot":"","sources":["../../src/commands/review-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Rule ownership — map rules/categories to team owners for
3
+ * accountability, escalation, and expertise routing.
4
+ *
5
+ * Stored locally in .judges-owners.json.
6
+ */
7
+ export interface RuleOwner {
8
+ /** Rule ID or prefix (e.g., "SEC-001" or "SEC") */
9
+ pattern: string;
10
+ /** Owner name or team */
11
+ owner: string;
12
+ /** Contact (email/Slack handle) */
13
+ contact?: string;
14
+ /** Expertise level */
15
+ expertise: "expert" | "familiar" | "learning";
16
+ /** When assigned */
17
+ assignedIso: string;
18
+ }
19
+ export declare function assignOwner(pattern: string, owner: string, opts?: {
20
+ contact?: string;
21
+ expertise?: RuleOwner["expertise"];
22
+ }): RuleOwner;
23
+ export declare function removeOwner(pattern: string): boolean;
24
+ export declare function findOwner(ruleId: string): RuleOwner | undefined;
25
+ export declare function getOwnerStats(): {
26
+ totalPatterns: number;
27
+ byOwner: Record<string, number>;
28
+ byExpertise: Record<string, number>;
29
+ };
30
+ export declare function runRuleOwner(argv: string[]): void;
31
+ //# sourceMappingURL=rule-owner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-owner.d.ts","sourceRoot":"","sources":["../../src/commands/rule-owner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,SAAS;IACxB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sBAAsB;IACtB,SAAS,EAAE,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC;IAC9C,oBAAoB;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAmBD,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,CAAC,WAAW,CAAC,CAAA;CAAE,GAC9D,SAAS,CAiBX;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAOpD;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAa/D;AAED,wBAAgB,aAAa,IAAI;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC,CASA;AAID,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAgHjD"}