@kevinrabun/judges 3.80.0 → 3.82.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 (78) hide show
  1. package/CHANGELOG.md +26 -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/finding-age-tracker.d.ts +8 -0
  6. package/dist/commands/finding-age-tracker.d.ts.map +1 -0
  7. package/dist/commands/finding-age-tracker.js +153 -0
  8. package/dist/commands/finding-age-tracker.js.map +1 -0
  9. package/dist/commands/finding-cwe-map.d.ts +5 -0
  10. package/dist/commands/finding-cwe-map.d.ts.map +1 -0
  11. package/dist/commands/finding-cwe-map.js +134 -0
  12. package/dist/commands/finding-cwe-map.js.map +1 -0
  13. package/dist/commands/finding-duplicate-rule.d.ts +5 -0
  14. package/dist/commands/finding-duplicate-rule.d.ts.map +1 -0
  15. package/dist/commands/finding-duplicate-rule.js +104 -0
  16. package/dist/commands/finding-duplicate-rule.js.map +1 -0
  17. package/dist/commands/finding-false-neg-check.d.ts +9 -0
  18. package/dist/commands/finding-false-neg-check.d.ts.map +1 -0
  19. package/dist/commands/finding-false-neg-check.js +140 -0
  20. package/dist/commands/finding-false-neg-check.js.map +1 -0
  21. package/dist/commands/finding-line-blame.d.ts +8 -0
  22. package/dist/commands/finding-line-blame.d.ts.map +1 -0
  23. package/dist/commands/finding-line-blame.js +133 -0
  24. package/dist/commands/finding-line-blame.js.map +1 -0
  25. package/dist/commands/finding-pattern-match.d.ts +5 -0
  26. package/dist/commands/finding-pattern-match.d.ts.map +1 -0
  27. package/dist/commands/finding-pattern-match.js +166 -0
  28. package/dist/commands/finding-pattern-match.js.map +1 -0
  29. package/dist/commands/finding-risk-matrix.d.ts +5 -0
  30. package/dist/commands/finding-risk-matrix.d.ts.map +1 -0
  31. package/dist/commands/finding-risk-matrix.js +127 -0
  32. package/dist/commands/finding-risk-matrix.js.map +1 -0
  33. package/dist/commands/finding-summary-digest.d.ts +8 -0
  34. package/dist/commands/finding-summary-digest.d.ts.map +1 -0
  35. package/dist/commands/finding-summary-digest.js +146 -0
  36. package/dist/commands/finding-summary-digest.js.map +1 -0
  37. package/dist/commands/review-code-owner.d.ts +8 -0
  38. package/dist/commands/review-code-owner.d.ts.map +1 -0
  39. package/dist/commands/review-code-owner.js +165 -0
  40. package/dist/commands/review-code-owner.js.map +1 -0
  41. package/dist/commands/review-dependency-graph.d.ts +5 -0
  42. package/dist/commands/review-dependency-graph.d.ts.map +1 -0
  43. package/dist/commands/review-dependency-graph.js +95 -0
  44. package/dist/commands/review-dependency-graph.js.map +1 -0
  45. package/dist/commands/review-diff-stats.d.ts +5 -0
  46. package/dist/commands/review-diff-stats.d.ts.map +1 -0
  47. package/dist/commands/review-diff-stats.js +91 -0
  48. package/dist/commands/review-diff-stats.js.map +1 -0
  49. package/dist/commands/review-exclude-vendor.d.ts +5 -0
  50. package/dist/commands/review-exclude-vendor.d.ts.map +1 -0
  51. package/dist/commands/review-exclude-vendor.js +159 -0
  52. package/dist/commands/review-exclude-vendor.js.map +1 -0
  53. package/dist/commands/review-export-pdf.d.ts +8 -0
  54. package/dist/commands/review-export-pdf.d.ts.map +1 -0
  55. package/dist/commands/review-export-pdf.js +132 -0
  56. package/dist/commands/review-export-pdf.js.map +1 -0
  57. package/dist/commands/review-file-stats.d.ts +5 -0
  58. package/dist/commands/review-file-stats.d.ts.map +1 -0
  59. package/dist/commands/review-file-stats.js +131 -0
  60. package/dist/commands/review-file-stats.js.map +1 -0
  61. package/dist/commands/review-parallel-files.d.ts +8 -0
  62. package/dist/commands/review-parallel-files.d.ts.map +1 -0
  63. package/dist/commands/review-parallel-files.js +135 -0
  64. package/dist/commands/review-parallel-files.js.map +1 -0
  65. package/dist/commands/review-rule-filter.d.ts +5 -0
  66. package/dist/commands/review-rule-filter.d.ts.map +1 -0
  67. package/dist/commands/review-rule-filter.js +117 -0
  68. package/dist/commands/review-rule-filter.js.map +1 -0
  69. package/dist/commands/review-scope-lock.d.ts +8 -0
  70. package/dist/commands/review-scope-lock.d.ts.map +1 -0
  71. package/dist/commands/review-scope-lock.js +139 -0
  72. package/dist/commands/review-scope-lock.js.map +1 -0
  73. package/dist/commands/review-watch-mode.d.ts +8 -0
  74. package/dist/commands/review-watch-mode.d.ts.map +1 -0
  75. package/dist/commands/review-watch-mode.js +133 -0
  76. package/dist/commands/review-watch-mode.js.map +1 -0
  77. package/package.json +1 -1
  78. package/server.json +2 -2
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Finding-line-blame — Map findings to git blame information.
3
+ *
4
+ * Shows who last modified lines associated with findings,
5
+ * helping attribute findings to specific changes/authors.
6
+ */
7
+ import { readFileSync, existsSync } from "fs";
8
+ import { execSync } from "child_process";
9
+ // ─── Helpers ────────────────────────────────────────────────────────────────
10
+ function getBlameForLines(file, lines) {
11
+ const results = [];
12
+ for (const line of lines) {
13
+ try {
14
+ const output = execSync(`git blame -L ${line},${line} --porcelain "${file}"`, {
15
+ encoding: "utf-8",
16
+ stdio: ["pipe", "pipe", "pipe"],
17
+ });
18
+ let author = "unknown";
19
+ let date = "";
20
+ let commit = "";
21
+ for (const blameLine of output.split("\n")) {
22
+ if (blameLine.startsWith("author "))
23
+ author = blameLine.slice(7);
24
+ else if (blameLine.startsWith("author-time ")) {
25
+ const ts = parseInt(blameLine.slice(12), 10);
26
+ date = new Date(ts * 1000).toISOString().split("T")[0];
27
+ }
28
+ else if (/^[0-9a-f]{40}/.test(blameLine)) {
29
+ commit = blameLine.split(" ")[0].slice(0, 8);
30
+ }
31
+ }
32
+ results.push({ line, author, date, commit });
33
+ }
34
+ catch {
35
+ /* skip lines that can't be blamed */
36
+ }
37
+ }
38
+ return results;
39
+ }
40
+ // ─── CLI ────────────────────────────────────────────────────────────────────
41
+ export function runFindingLineBlame(argv) {
42
+ const verdictIdx = argv.indexOf("--verdict");
43
+ const fileIdx = argv.indexOf("--file");
44
+ const formatIdx = argv.indexOf("--format");
45
+ const verdictPath = verdictIdx >= 0 ? argv[verdictIdx + 1] : undefined;
46
+ const sourceFile = fileIdx >= 0 ? argv[fileIdx + 1] : undefined;
47
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
48
+ if (argv.includes("--help") || argv.includes("-h")) {
49
+ console.log(`
50
+ judges finding-line-blame — Map findings to git blame
51
+
52
+ Usage:
53
+ judges finding-line-blame --verdict <verdict.json> --file <source>
54
+ [--format table|json]
55
+
56
+ Options:
57
+ --verdict <path> Path to verdict JSON file (required)
58
+ --file <path> Source file to blame (required)
59
+ --format <fmt> Output format: table (default), json
60
+ --help, -h Show this help
61
+ `);
62
+ return;
63
+ }
64
+ if (!verdictPath || !sourceFile) {
65
+ console.error("Error: --verdict and --file required");
66
+ process.exitCode = 1;
67
+ return;
68
+ }
69
+ if (!existsSync(verdictPath)) {
70
+ console.error(`Error: verdict not found: ${verdictPath}`);
71
+ process.exitCode = 1;
72
+ return;
73
+ }
74
+ if (!existsSync(sourceFile)) {
75
+ console.error(`Error: file not found: ${sourceFile}`);
76
+ process.exitCode = 1;
77
+ return;
78
+ }
79
+ let verdict;
80
+ try {
81
+ verdict = JSON.parse(readFileSync(verdictPath, "utf-8"));
82
+ }
83
+ catch {
84
+ console.error("Error: invalid verdict JSON");
85
+ process.exitCode = 1;
86
+ return;
87
+ }
88
+ const results = [];
89
+ for (const f of verdict.findings) {
90
+ if (!f.lineNumbers || f.lineNumbers.length === 0)
91
+ continue;
92
+ const blameLines = getBlameForLines(sourceFile, f.lineNumbers);
93
+ if (blameLines.length > 0) {
94
+ results.push({
95
+ ruleId: f.ruleId,
96
+ title: f.title,
97
+ severity: f.severity || "medium",
98
+ blameLines,
99
+ });
100
+ }
101
+ }
102
+ if (format === "json") {
103
+ console.log(JSON.stringify(results, null, 2));
104
+ return;
105
+ }
106
+ if (results.length === 0) {
107
+ console.log("No blame data available for findings.");
108
+ return;
109
+ }
110
+ console.log(`\nFinding Line Blame — ${sourceFile}`);
111
+ console.log("═".repeat(70));
112
+ for (const r of results) {
113
+ console.log(`\n [${r.severity.toUpperCase()}] ${r.title}`);
114
+ console.log(` Rule: ${r.ruleId}`);
115
+ for (const b of r.blameLines) {
116
+ console.log(` L${b.line}: ${b.author} (${b.date}) ${b.commit}`);
117
+ }
118
+ }
119
+ // Author summary
120
+ const authorCounts = new Map();
121
+ for (const r of results) {
122
+ for (const b of r.blameLines) {
123
+ authorCounts.set(b.author, (authorCounts.get(b.author) || 0) + 1);
124
+ }
125
+ }
126
+ console.log("\n" + "─".repeat(70));
127
+ console.log("Author Summary:");
128
+ for (const [author, count] of [...authorCounts.entries()].sort((a, b) => b[1] - a[1])) {
129
+ console.log(` ${author}: ${count} finding line(s)`);
130
+ }
131
+ console.log("═".repeat(70));
132
+ }
133
+ //# sourceMappingURL=finding-line-blame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-line-blame.js","sourceRoot":"","sources":["../../src/commands/finding-line-blame.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Finding-pattern-match — Match findings against custom patterns.
3
+ */
4
+ export declare function runFindingPatternMatch(argv: string[]): void;
5
+ //# sourceMappingURL=finding-pattern-match.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-pattern-match.d.ts","sourceRoot":"","sources":["../../src/commands/finding-pattern-match.ts"],"names":[],"mappings":"AAAA;;GAEG;AAgDH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAiI3D"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Finding-pattern-match — Match findings against custom patterns.
3
+ */
4
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
5
+ import { dirname, join } from "path";
6
+ // ─── Helpers ────────────────────────────────────────────────────────────────
7
+ function patternsFile() {
8
+ return join(process.cwd(), ".judges", "match-patterns.json");
9
+ }
10
+ function loadPatterns() {
11
+ const f = patternsFile();
12
+ if (!existsSync(f))
13
+ return [];
14
+ try {
15
+ return JSON.parse(readFileSync(f, "utf-8"));
16
+ }
17
+ catch {
18
+ return [];
19
+ }
20
+ }
21
+ function savePatterns(patterns) {
22
+ const f = patternsFile();
23
+ const d = dirname(f);
24
+ if (!existsSync(d))
25
+ mkdirSync(d, { recursive: true });
26
+ writeFileSync(f, JSON.stringify(patterns, null, 2));
27
+ }
28
+ function matchFinding(finding, pattern) {
29
+ if (pattern.rulePattern && !finding.ruleId.includes(pattern.rulePattern))
30
+ return false;
31
+ if (pattern.titlePattern && !finding.title.toLowerCase().includes(pattern.titlePattern.toLowerCase()))
32
+ return false;
33
+ if (pattern.severities.length > 0 && !pattern.severities.includes(finding.severity))
34
+ return false;
35
+ return true;
36
+ }
37
+ // ─── CLI ────────────────────────────────────────────────────────────────────
38
+ export function runFindingPatternMatch(argv) {
39
+ const sub = argv[0];
40
+ if (!sub || sub === "--help" || sub === "-h") {
41
+ console.log(`
42
+ judges finding-pattern-match — Match findings against custom patterns
43
+
44
+ Usage:
45
+ judges finding-pattern-match apply --file <results.json> [--format json]
46
+ judges finding-pattern-match add --name <name> [--rule <pattern>] [--title <pattern>] [--severity <list>] [--action <act>]
47
+ judges finding-pattern-match list
48
+ judges finding-pattern-match remove --name <name>
49
+ judges finding-pattern-match clear
50
+
51
+ Options:
52
+ --name <name> Pattern name
53
+ --rule <pattern> Substring to match in ruleId
54
+ --title <pattern> Substring to match in title
55
+ --severity <list> Comma-separated severities
56
+ --action <act> Action: flag, suppress, escalate (default: flag)
57
+ --format json JSON output
58
+ --help, -h Show this help
59
+ `);
60
+ return;
61
+ }
62
+ const args = argv.slice(1);
63
+ const patterns = loadPatterns();
64
+ if (sub === "apply") {
65
+ const file = args.find((_a, i) => args[i - 1] === "--file");
66
+ const format = args.find((_a, i) => args[i - 1] === "--format") || "text";
67
+ if (!file) {
68
+ console.error("Error: --file required");
69
+ process.exitCode = 1;
70
+ return;
71
+ }
72
+ if (!existsSync(file)) {
73
+ console.error(`Error: file not found: ${file}`);
74
+ process.exitCode = 1;
75
+ return;
76
+ }
77
+ let verdict;
78
+ try {
79
+ verdict = JSON.parse(readFileSync(file, "utf-8"));
80
+ }
81
+ catch {
82
+ console.error("Error: could not parse file");
83
+ process.exitCode = 1;
84
+ return;
85
+ }
86
+ const findings = verdict.findings || [];
87
+ const matches = findings.map((f) => {
88
+ const matched = patterns.filter((p) => matchFinding(f, p));
89
+ return { ...f, matchedPatterns: matched.map((p) => p.name), actions: matched.map((p) => p.action) };
90
+ });
91
+ const withMatches = matches.filter((m) => m.matchedPatterns.length > 0);
92
+ if (format === "json") {
93
+ console.log(JSON.stringify({ total: findings.length, matched: withMatches.length, findings: matches }, null, 2));
94
+ return;
95
+ }
96
+ console.log(`\nPattern Match Results:`);
97
+ console.log("═".repeat(65));
98
+ console.log(` ${withMatches.length} of ${findings.length} findings matched ${patterns.length} patterns`);
99
+ console.log("─".repeat(65));
100
+ for (const m of withMatches.slice(0, 20)) {
101
+ const acts = [...new Set(m.actions)].join(", ");
102
+ console.log(` ${m.ruleId.padEnd(22)} [${acts}] patterns: ${m.matchedPatterns.join(", ")}`);
103
+ }
104
+ if (withMatches.length > 20)
105
+ console.log(` ... and ${withMatches.length - 20} more`);
106
+ console.log("═".repeat(65));
107
+ }
108
+ else if (sub === "add") {
109
+ const name = args.find((_a, i) => args[i - 1] === "--name");
110
+ if (!name) {
111
+ console.error("Error: --name required");
112
+ process.exitCode = 1;
113
+ return;
114
+ }
115
+ const ruleP = args.find((_a, i) => args[i - 1] === "--rule") || "";
116
+ const titleP = args.find((_a, i) => args[i - 1] === "--title") || "";
117
+ const sevStr = args.find((_a, i) => args[i - 1] === "--severity") || "";
118
+ const action = args.find((_a, i) => args[i - 1] === "--action") || "flag";
119
+ patterns.push({
120
+ name,
121
+ rulePattern: ruleP,
122
+ titlePattern: titleP,
123
+ severities: sevStr ? sevStr.split(",") : [],
124
+ action,
125
+ });
126
+ savePatterns(patterns);
127
+ console.log(`Added pattern: ${name}`);
128
+ }
129
+ else if (sub === "list") {
130
+ if (patterns.length === 0) {
131
+ console.log("No patterns defined.");
132
+ return;
133
+ }
134
+ console.log(`\nMatch Patterns (${patterns.length}):`);
135
+ console.log("═".repeat(55));
136
+ for (const p of patterns) {
137
+ console.log(` ${p.name.padEnd(18)} [${p.action}] rule:${p.rulePattern || "*"} title:${p.titlePattern || "*"}`);
138
+ }
139
+ console.log("═".repeat(55));
140
+ }
141
+ else if (sub === "remove") {
142
+ const name = args.find((_a, i) => args[i - 1] === "--name");
143
+ if (!name) {
144
+ console.error("Error: --name required");
145
+ process.exitCode = 1;
146
+ return;
147
+ }
148
+ const filtered = patterns.filter((p) => p.name !== name);
149
+ if (filtered.length === patterns.length) {
150
+ console.error(`Pattern "${name}" not found.`);
151
+ process.exitCode = 1;
152
+ return;
153
+ }
154
+ savePatterns(filtered);
155
+ console.log(`Removed pattern: ${name}`);
156
+ }
157
+ else if (sub === "clear") {
158
+ savePatterns([]);
159
+ console.log("All patterns cleared.");
160
+ }
161
+ else {
162
+ console.error(`Unknown subcommand: ${sub}. Use --help for usage.`);
163
+ process.exitCode = 1;
164
+ }
165
+ }
166
+ //# sourceMappingURL=finding-pattern-match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-pattern-match.js","sourceRoot":"","sources":["../../src/commands/finding-pattern-match.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Finding-risk-matrix — Generate risk matrices from findings.
3
+ */
4
+ export declare function runFindingRiskMatrix(argv: string[]): void;
5
+ //# sourceMappingURL=finding-risk-matrix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-risk-matrix.d.ts","sourceRoot":"","sources":["../../src/commands/finding-risk-matrix.ts"],"names":[],"mappings":"AAAA;;GAEG;AAwEH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA2EzD"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Finding-risk-matrix — Generate risk matrices from findings.
3
+ */
4
+ import { readFileSync, existsSync } from "fs";
5
+ // ─── Constants ──────────────────────────────────────────────────────────────
6
+ const SEVERITY_LEVELS = ["critical", "high", "medium", "low", "info"];
7
+ const CONFIDENCE_LEVELS = ["high", "medium", "low"];
8
+ // ─── Helpers ────────────────────────────────────────────────────────────────
9
+ function loadVerdict(filePath) {
10
+ if (!existsSync(filePath))
11
+ return null;
12
+ try {
13
+ return JSON.parse(readFileSync(filePath, "utf-8"));
14
+ }
15
+ catch {
16
+ return null;
17
+ }
18
+ }
19
+ function buildMatrix(verdict) {
20
+ const cells = [];
21
+ for (const sev of SEVERITY_LEVELS) {
22
+ for (const conf of CONFIDENCE_LEVELS) {
23
+ const matching = verdict.findings.filter((f) => {
24
+ const fSev = (f.severity || "medium").toLowerCase();
25
+ const fConf = f.confidence !== undefined && f.confidence !== null
26
+ ? f.confidence >= 0.8
27
+ ? "high"
28
+ : f.confidence >= 0.5
29
+ ? "medium"
30
+ : "low"
31
+ : "medium";
32
+ return fSev === sev && fConf === conf;
33
+ });
34
+ if (matching.length > 0) {
35
+ cells.push({
36
+ severity: sev,
37
+ confidence: conf,
38
+ count: matching.length,
39
+ findings: matching.map((f) => f.title),
40
+ });
41
+ }
42
+ }
43
+ }
44
+ return cells;
45
+ }
46
+ function riskScore(severity, confidence) {
47
+ const sevWeight = { critical: 5, high: 4, medium: 3, low: 2, info: 1 };
48
+ const confWeight = { high: 3, medium: 2, low: 1 };
49
+ const score = (sevWeight[severity] || 1) * (confWeight[confidence] || 1);
50
+ if (score >= 12)
51
+ return "CRITICAL";
52
+ if (score >= 8)
53
+ return "HIGH";
54
+ if (score >= 4)
55
+ return "MEDIUM";
56
+ return "LOW";
57
+ }
58
+ // ─── CLI ────────────────────────────────────────────────────────────────────
59
+ export function runFindingRiskMatrix(argv) {
60
+ const fileIdx = argv.indexOf("--file");
61
+ const formatIdx = argv.indexOf("--format");
62
+ const filePath = fileIdx >= 0 ? argv[fileIdx + 1] : undefined;
63
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
64
+ if (argv.includes("--help") || argv.includes("-h")) {
65
+ console.log(`
66
+ judges finding-risk-matrix — Generate risk matrix from findings
67
+
68
+ Usage:
69
+ judges finding-risk-matrix --file <verdict.json> [--format table|json|markdown]
70
+
71
+ Options:
72
+ --file <path> Path to verdict JSON file (required)
73
+ --format <fmt> Output format: table (default), json, markdown
74
+ --help, -h Show this help
75
+ `);
76
+ return;
77
+ }
78
+ if (!filePath) {
79
+ console.error("Error: --file required");
80
+ process.exitCode = 1;
81
+ return;
82
+ }
83
+ const verdict = loadVerdict(filePath);
84
+ if (!verdict) {
85
+ console.error(`Error: cannot load ${filePath}`);
86
+ process.exitCode = 1;
87
+ return;
88
+ }
89
+ const cells = buildMatrix(verdict);
90
+ if (format === "json") {
91
+ console.log(JSON.stringify(cells, null, 2));
92
+ return;
93
+ }
94
+ if (format === "markdown") {
95
+ console.log("| Severity | Confidence | Count | Risk Level |");
96
+ console.log("|----------|------------|-------|------------|");
97
+ for (const c of cells) {
98
+ console.log(`| ${c.severity} | ${c.confidence} | ${c.count} | ${riskScore(c.severity, c.confidence)} |`);
99
+ }
100
+ return;
101
+ }
102
+ // Table format
103
+ console.log("\nRisk Matrix");
104
+ console.log("═".repeat(60));
105
+ console.log(`${"Severity".padEnd(12)} ${"Confidence".padEnd(12)} ${"Count".padEnd(8)} Risk Level`);
106
+ console.log("─".repeat(60));
107
+ const sorted = [...cells].sort((a, b) => {
108
+ const sevOrder = SEVERITY_LEVELS.indexOf(a.severity) - SEVERITY_LEVELS.indexOf(b.severity);
109
+ if (sevOrder !== 0)
110
+ return sevOrder;
111
+ return CONFIDENCE_LEVELS.indexOf(a.confidence) - CONFIDENCE_LEVELS.indexOf(b.confidence);
112
+ });
113
+ for (const c of sorted) {
114
+ const risk = riskScore(c.severity, c.confidence);
115
+ console.log(`${c.severity.padEnd(12)} ${c.confidence.padEnd(12)} ${String(c.count).padEnd(8)} ${risk}`);
116
+ for (const t of c.findings.slice(0, 3)) {
117
+ console.log(` → ${t}`);
118
+ }
119
+ if (c.findings.length > 3)
120
+ console.log(` … and ${c.findings.length - 3} more`);
121
+ }
122
+ console.log("─".repeat(60));
123
+ const total = cells.reduce((s, c) => s + c.count, 0);
124
+ console.log(`Total findings: ${total}`);
125
+ console.log("═".repeat(60));
126
+ }
127
+ //# sourceMappingURL=finding-risk-matrix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-risk-matrix.js","sourceRoot":"","sources":["../../src/commands/finding-risk-matrix.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Finding-summary-digest — Generate concise digests of finding summaries.
3
+ *
4
+ * Creates executive-style summaries of review results suitable for
5
+ * stakeholder communication and quick decision-making.
6
+ */
7
+ export declare function runFindingSummaryDigest(argv: string[]): void;
8
+ //# sourceMappingURL=finding-summary-digest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-summary-digest.d.ts","sourceRoot":"","sources":["../../src/commands/finding-summary-digest.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgGH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAmE5D"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Finding-summary-digest — Generate concise digests of finding summaries.
3
+ *
4
+ * Creates executive-style summaries of review results suitable for
5
+ * stakeholder communication and quick decision-making.
6
+ */
7
+ import { readFileSync, existsSync } from "fs";
8
+ // ─── Helpers ────────────────────────────────────────────────────────────────
9
+ function severityEmoji(severity) {
10
+ switch (severity.toLowerCase()) {
11
+ case "critical":
12
+ return "[CRIT]";
13
+ case "high":
14
+ return "[HIGH]";
15
+ case "medium":
16
+ return "[MED]";
17
+ case "low":
18
+ return "[LOW]";
19
+ default:
20
+ return "[INFO]";
21
+ }
22
+ }
23
+ function generateDigest(verdict) {
24
+ const lines = [];
25
+ const total = verdict.findings.length;
26
+ // Header
27
+ lines.push("REVIEW DIGEST");
28
+ lines.push("=".repeat(50));
29
+ // Status
30
+ const status = verdict.overallVerdict === "pass" ? "PASS" : "FAIL";
31
+ lines.push(`Status: ${status} | Score: ${verdict.overallScore} | Findings: ${total}`);
32
+ lines.push("");
33
+ // Severity distribution
34
+ const sevCounts = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
35
+ for (const f of verdict.findings) {
36
+ const sev = (f.severity || "medium").toLowerCase();
37
+ sevCounts[sev] = (sevCounts[sev] || 0) + 1;
38
+ }
39
+ lines.push("Severity Distribution:");
40
+ for (const [sev, count] of Object.entries(sevCounts)) {
41
+ if (count > 0) {
42
+ const bar = "█".repeat(Math.min(count, 20));
43
+ lines.push(` ${sev.padEnd(10)} ${bar} ${count}`);
44
+ }
45
+ }
46
+ lines.push("");
47
+ // Top findings by severity
48
+ const criticalAndHigh = verdict.findings
49
+ .filter((f) => ["critical", "high"].includes((f.severity || "medium").toLowerCase()))
50
+ .slice(0, 5);
51
+ if (criticalAndHigh.length > 0) {
52
+ lines.push("Priority Findings:");
53
+ for (const f of criticalAndHigh) {
54
+ lines.push(` ${severityEmoji(f.severity || "medium")} ${f.title}`);
55
+ if (f.recommendation) {
56
+ const rec = f.recommendation.length > 60 ? f.recommendation.slice(0, 60) + "…" : f.recommendation;
57
+ lines.push(` Fix: ${rec}`);
58
+ }
59
+ }
60
+ lines.push("");
61
+ }
62
+ // Rule coverage
63
+ const rules = new Set(verdict.findings.map((f) => f.ruleId));
64
+ lines.push(`Rules triggered: ${rules.size}`);
65
+ // Judge participation
66
+ if (verdict.evaluations && verdict.evaluations.length > 0) {
67
+ const passing = verdict.evaluations.filter((e) => e.verdict === "pass").length;
68
+ lines.push(`Judges: ${passing}/${verdict.evaluations.length} passing`);
69
+ }
70
+ lines.push("");
71
+ lines.push("=".repeat(50));
72
+ // Action items
73
+ if (sevCounts["critical"] > 0) {
74
+ lines.push(`ACTION REQUIRED: ${sevCounts["critical"]} critical finding(s) must be addressed before merge.`);
75
+ }
76
+ else if (sevCounts["high"] > 0) {
77
+ lines.push(`RECOMMENDED: Address ${sevCounts["high"]} high-severity finding(s) before merge.`);
78
+ }
79
+ else if (total > 0) {
80
+ lines.push(`ADVISORY: ${total} finding(s) for review. No blockers detected.`);
81
+ }
82
+ else {
83
+ lines.push("CLEAN: No findings detected.");
84
+ }
85
+ return lines.join("\n");
86
+ }
87
+ // ─── CLI ────────────────────────────────────────────────────────────────────
88
+ export function runFindingSummaryDigest(argv) {
89
+ const fileIdx = argv.indexOf("--file");
90
+ const formatIdx = argv.indexOf("--format");
91
+ const filePath = fileIdx >= 0 ? argv[fileIdx + 1] : undefined;
92
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "text";
93
+ if (argv.includes("--help") || argv.includes("-h")) {
94
+ console.log(`
95
+ judges finding-summary-digest — Generate concise finding digests
96
+
97
+ Usage:
98
+ judges finding-summary-digest --file <verdict.json> [--format text|json]
99
+
100
+ Options:
101
+ --file <path> Path to verdict JSON file (required)
102
+ --format <fmt> Output format: text (default), json
103
+ --help, -h Show this help
104
+ `);
105
+ return;
106
+ }
107
+ if (!filePath) {
108
+ console.error("Error: --file required");
109
+ process.exitCode = 1;
110
+ return;
111
+ }
112
+ if (!existsSync(filePath)) {
113
+ console.error(`Error: file not found: ${filePath}`);
114
+ process.exitCode = 1;
115
+ return;
116
+ }
117
+ let verdict;
118
+ try {
119
+ verdict = JSON.parse(readFileSync(filePath, "utf-8"));
120
+ }
121
+ catch {
122
+ console.error("Error: invalid JSON");
123
+ process.exitCode = 1;
124
+ return;
125
+ }
126
+ if (format === "json") {
127
+ const sevCounts = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
128
+ for (const f of verdict.findings) {
129
+ const sev = (f.severity || "medium").toLowerCase();
130
+ sevCounts[sev] = (sevCounts[sev] || 0) + 1;
131
+ }
132
+ console.log(JSON.stringify({
133
+ status: verdict.overallVerdict,
134
+ score: verdict.overallScore,
135
+ totalFindings: verdict.findings.length,
136
+ severityCounts: sevCounts,
137
+ rulesTriggered: new Set(verdict.findings.map((f) => f.ruleId)).size,
138
+ topFindings: verdict.findings
139
+ .slice(0, 5)
140
+ .map((f) => ({ title: f.title, severity: f.severity, ruleId: f.ruleId })),
141
+ }, null, 2));
142
+ return;
143
+ }
144
+ console.log(generateDigest(verdict));
145
+ }
146
+ //# sourceMappingURL=finding-summary-digest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-summary-digest.js","sourceRoot":"","sources":["../../src/commands/finding-summary-digest.ts"],"names":[],"mappings":"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"}