@kevinrabun/judges 3.61.0 → 3.62.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 (42) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +56 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/batch-review.d.ts +5 -0
  6. package/dist/commands/batch-review.d.ts.map +1 -0
  7. package/dist/commands/batch-review.js +181 -0
  8. package/dist/commands/batch-review.js.map +1 -0
  9. package/dist/commands/custom-rule.d.ts +5 -0
  10. package/dist/commands/custom-rule.d.ts.map +1 -0
  11. package/dist/commands/custom-rule.js +211 -0
  12. package/dist/commands/custom-rule.js.map +1 -0
  13. package/dist/commands/diff-review.d.ts +5 -0
  14. package/dist/commands/diff-review.d.ts.map +1 -0
  15. package/dist/commands/diff-review.js +191 -0
  16. package/dist/commands/diff-review.js.map +1 -0
  17. package/dist/commands/focus-area.d.ts +6 -0
  18. package/dist/commands/focus-area.d.ts.map +1 -0
  19. package/dist/commands/focus-area.js +193 -0
  20. package/dist/commands/focus-area.js.map +1 -0
  21. package/dist/commands/review-compare.d.ts +5 -0
  22. package/dist/commands/review-compare.d.ts.map +1 -0
  23. package/dist/commands/review-compare.js +201 -0
  24. package/dist/commands/review-compare.js.map +1 -0
  25. package/dist/commands/review-explain.d.ts +6 -0
  26. package/dist/commands/review-explain.d.ts.map +1 -0
  27. package/dist/commands/review-explain.js +195 -0
  28. package/dist/commands/review-explain.js.map +1 -0
  29. package/dist/commands/review-gate.d.ts +5 -0
  30. package/dist/commands/review-gate.d.ts.map +1 -0
  31. package/dist/commands/review-gate.js +213 -0
  32. package/dist/commands/review-gate.js.map +1 -0
  33. package/dist/commands/severity-tune.d.ts +5 -0
  34. package/dist/commands/severity-tune.d.ts.map +1 -0
  35. package/dist/commands/severity-tune.js +209 -0
  36. package/dist/commands/severity-tune.js.map +1 -0
  37. package/dist/commands/trend-report.d.ts +5 -0
  38. package/dist/commands/trend-report.d.ts.map +1 -0
  39. package/dist/commands/trend-report.js +149 -0
  40. package/dist/commands/trend-report.js.map +1 -0
  41. package/package.json +1 -1
  42. package/server.json +2 -2
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Focus-area — Identify high-risk areas that need the most review attention
3
+ * based on code complexity and pattern density.
4
+ */
5
+ import { readFileSync, readdirSync, statSync } from "fs";
6
+ import { join, extname, relative } from "path";
7
+ // ─── Patterns ──────────────────────────────────────────────────────────────
8
+ const RISK_PATTERNS = [
9
+ { name: "hardcoded-secret", weight: 10, regex: /(?:password|secret|api_key|token)\s*[:=]\s*["'][^"']{8,}/i },
10
+ { name: "eval-usage", weight: 10, regex: /\beval\s*\(/ },
11
+ { name: "sql-concat", weight: 10, regex: /(?:query|execute)\s*\(\s*["'`].*\+/ },
12
+ { name: "xss-risk", weight: 8, regex: /innerHTML\s*=|document\.write\s*\(/ },
13
+ { name: "command-injection", weight: 10, regex: /exec(?:Sync)?\s*\(\s*`[^`]*\$\{/ },
14
+ { name: "empty-catch", weight: 3, regex: /catch\s*\([^)]*\)\s*\{\s*\}/ },
15
+ { name: "any-type", weight: 2, regex: /:\s*any\b/ },
16
+ { name: "unsafe-regex", weight: 7, regex: /new\s+RegExp\s*\([^)]*\+/ },
17
+ { name: "nested-callback", weight: 4, regex: /\)\s*=>\s*\{[^}]*\)\s*=>\s*\{/ },
18
+ { name: "deep-nesting", weight: 5, regex: /^\s{16,}\S/ },
19
+ { name: "deprecated-api", weight: 3, regex: /new\s+Buffer\s*\(|\.substr\s*\(/ },
20
+ ];
21
+ // ─── Complexity estimation ─────────────────────────────────────────────────
22
+ function estimateComplexity(content) {
23
+ const lines = content.split("\n");
24
+ let complexity = 0;
25
+ for (const line of lines) {
26
+ // Control flow
27
+ if (/\b(?:if|else if|switch|case|while|for|catch)\b/.test(line))
28
+ complexity++;
29
+ // Logical operators
30
+ if (/&&|\|\|/.test(line))
31
+ complexity++;
32
+ // Ternary
33
+ if (/[^?][?][^?]/.test(line))
34
+ complexity += 0.5;
35
+ // Nested functions
36
+ if (/(?:function\s+\w+|=>\s*\{)/.test(line))
37
+ complexity += 0.5;
38
+ }
39
+ return Math.round(complexity);
40
+ }
41
+ // ─── Helpers ────────────────────────────────────────────────────────────────
42
+ function collectSourceFiles(dir) {
43
+ const exts = new Set([".ts", ".js", ".tsx", ".jsx", ".py", ".java", ".go", ".rs", ".cs"]);
44
+ const files = [];
45
+ const skipDirs = new Set(["node_modules", ".git", "dist", "build", "coverage"]);
46
+ function walk(d) {
47
+ let entries;
48
+ try {
49
+ entries = readdirSync(d);
50
+ }
51
+ catch {
52
+ return;
53
+ }
54
+ for (const name of entries) {
55
+ if (skipDirs.has(name))
56
+ continue;
57
+ const full = join(d, name);
58
+ try {
59
+ const st = statSync(full);
60
+ if (st.isDirectory())
61
+ walk(full);
62
+ else if (exts.has(extname(name)))
63
+ files.push(full);
64
+ }
65
+ catch {
66
+ // skip
67
+ }
68
+ }
69
+ }
70
+ walk(dir);
71
+ return files;
72
+ }
73
+ function analyzeRisk(files, baseDir) {
74
+ const fileRisks = [];
75
+ for (const filePath of files) {
76
+ let content;
77
+ try {
78
+ content = readFileSync(filePath, "utf-8");
79
+ }
80
+ catch {
81
+ continue;
82
+ }
83
+ const lines = content.split("\n");
84
+ const lineCount = lines.length;
85
+ const complexity = estimateComplexity(content);
86
+ const patternHits = new Map();
87
+ let totalWeight = 0;
88
+ for (const line of lines) {
89
+ for (const pat of RISK_PATTERNS) {
90
+ if (pat.regex.test(line)) {
91
+ totalWeight += pat.weight;
92
+ patternHits.set(pat.name, (patternHits.get(pat.name) || 0) + 1);
93
+ }
94
+ }
95
+ }
96
+ const findingCount = [...patternHits.values()].reduce((a, b) => a + b, 0);
97
+ const patternDensity = lineCount > 0 ? Math.round((findingCount / lineCount) * 1000) / 10 : 0;
98
+ // Risk score: weighted sum of complexity, pattern weight, and density
99
+ const riskScore = Math.round(complexity * 0.3 + totalWeight * 2 + patternDensity * 10);
100
+ if (riskScore > 0) {
101
+ const topPatterns = [...patternHits.entries()]
102
+ .sort((a, b) => b[1] - a[1])
103
+ .slice(0, 3)
104
+ .map(([name]) => name);
105
+ fileRisks.push({
106
+ file: relative(baseDir, filePath),
107
+ riskScore,
108
+ complexity,
109
+ patternDensity,
110
+ lineCount,
111
+ findingCount,
112
+ topPatterns,
113
+ });
114
+ }
115
+ }
116
+ fileRisks.sort((a, b) => b.riskScore - a.riskScore);
117
+ const distribution = { high: 0, medium: 0, low: 0 };
118
+ for (const fr of fileRisks) {
119
+ if (fr.riskScore >= 50)
120
+ distribution.high++;
121
+ else if (fr.riskScore >= 20)
122
+ distribution.medium++;
123
+ else
124
+ distribution.low++;
125
+ }
126
+ const summary = distribution.high > 0
127
+ ? `${distribution.high} high-risk file(s) need immediate review attention.`
128
+ : fileRisks.length > 0
129
+ ? `No critical risk areas. ${fileRisks.length} files have minor improvements available.`
130
+ : "No risk areas detected in scanned files.";
131
+ return {
132
+ filesAnalyzed: files.length,
133
+ highRiskFiles: fileRisks.slice(0, 20),
134
+ riskDistribution: distribution,
135
+ summary,
136
+ };
137
+ }
138
+ // ─── CLI ────────────────────────────────────────────────────────────────────
139
+ export function runFocusArea(argv) {
140
+ if (argv.includes("--help") || argv.includes("-h")) {
141
+ console.log(`
142
+ judges focus-area — Identify high-risk areas needing review attention
143
+
144
+ Usage:
145
+ judges focus-area [dir] Analyze risk areas
146
+ judges focus-area --top 10 Show top N files
147
+ judges focus-area --format json JSON output
148
+
149
+ Options:
150
+ [dir] Target directory (default: .)
151
+ --top <n> Number of files to show (default: 20)
152
+ --format json JSON output
153
+ --help, -h Show this help
154
+
155
+ Combines code complexity and security pattern density to rank files by
156
+ risk. Use this to prioritize review effort where it matters most.
157
+ `);
158
+ return;
159
+ }
160
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
161
+ const dir = argv.find((a) => !a.startsWith("-") &&
162
+ a !== "focus-area" &&
163
+ argv[argv.indexOf(a) - 1] !== "--format" &&
164
+ argv[argv.indexOf(a) - 1] !== "--top") || ".";
165
+ const topN = parseInt(argv.find((_a, i) => argv[i - 1] === "--top") || "20", 10);
166
+ const files = collectSourceFiles(dir);
167
+ if (files.length === 0) {
168
+ console.log("No source files found.");
169
+ return;
170
+ }
171
+ const result = analyzeRisk(files, dir);
172
+ if (format === "json") {
173
+ console.log(JSON.stringify(result, null, 2));
174
+ return;
175
+ }
176
+ console.log(`\n Focus Area Analysis\n ─────────────────────────────`);
177
+ console.log(` Files analyzed: ${result.filesAnalyzed}`);
178
+ console.log(` Risk distribution: 🔴 ${result.riskDistribution.high} high 🟡 ${result.riskDistribution.medium} medium 🟢 ${result.riskDistribution.low} low`);
179
+ console.log(`\n ${result.summary}`);
180
+ const display = result.highRiskFiles.slice(0, topN);
181
+ if (display.length > 0) {
182
+ console.log("\n Highest risk files:");
183
+ for (const fr of display) {
184
+ const icon = fr.riskScore >= 50 ? "🔴" : fr.riskScore >= 20 ? "🟡" : "🟢";
185
+ console.log(` ${icon} [${fr.riskScore}] ${fr.file} (${fr.lineCount} lines, ${fr.findingCount} findings, complexity: ${fr.complexity})`);
186
+ if (fr.topPatterns.length > 0) {
187
+ console.log(` Top patterns: ${fr.topPatterns.join(", ")}`);
188
+ }
189
+ }
190
+ }
191
+ console.log();
192
+ }
193
+ //# sourceMappingURL=focus-area.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"focus-area.js","sourceRoot":"","sources":["../../src/commands/focus-area.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Review-compare — Compare two review runs to measure improvement.
3
+ */
4
+ export declare function runReviewCompare(argv: string[]): void;
5
+ //# sourceMappingURL=review-compare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-compare.d.ts","sourceRoot":"","sources":["../../src/commands/review-compare.ts"],"names":[],"mappings":"AAAA;;GAEG;AA0FH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAuJrD"}
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Review-compare — Compare two review runs to measure improvement.
3
+ */
4
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from "fs";
5
+ import { join } from "path";
6
+ // ─── Helpers ────────────────────────────────────────────────────────────────
7
+ function getSnapshotsDir() {
8
+ return join(".", ".judges", "snapshots");
9
+ }
10
+ function loadSnapshot(id) {
11
+ const dir = getSnapshotsDir();
12
+ const filePath = join(dir, `${id}.json`);
13
+ if (!existsSync(filePath))
14
+ return null;
15
+ try {
16
+ return JSON.parse(readFileSync(filePath, "utf-8"));
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ }
22
+ function saveSnapshot(snapshot) {
23
+ const dir = getSnapshotsDir();
24
+ if (!existsSync(dir))
25
+ mkdirSync(dir, { recursive: true });
26
+ writeFileSync(join(dir, `${snapshot.id}.json`), JSON.stringify(snapshot, null, 2), "utf-8");
27
+ }
28
+ function listSnapshots() {
29
+ const dir = getSnapshotsDir();
30
+ if (!existsSync(dir))
31
+ return [];
32
+ try {
33
+ return readdirSync(dir)
34
+ .filter((f) => f.endsWith(".json"))
35
+ .map((f) => f.replace(".json", ""));
36
+ }
37
+ catch {
38
+ return [];
39
+ }
40
+ }
41
+ function compareSnapshots(before, after) {
42
+ // Build finding signatures for comparison
43
+ const beforeSigs = new Set(before.findings.map((f) => `${f.pattern}:${f.file}:${f.line}`));
44
+ const afterSigs = new Set(after.findings.map((f) => `${f.pattern}:${f.file}:${f.line}`));
45
+ const newFindings = after.findings
46
+ .filter((f) => !beforeSigs.has(`${f.pattern}:${f.file}:${f.line}`))
47
+ .map((f) => ({ pattern: f.pattern, severity: f.severity, file: f.file }));
48
+ const fixedFindings = before.findings
49
+ .filter((f) => !afterSigs.has(`${f.pattern}:${f.file}:${f.line}`))
50
+ .map((f) => ({ pattern: f.pattern, severity: f.severity, file: f.file }));
51
+ const persisting = after.counts.total - newFindings.length;
52
+ const improvement = before.counts.total - after.counts.total;
53
+ const improvementPercent = before.counts.total > 0 ? Math.round((improvement / before.counts.total) * 100) : 0;
54
+ return {
55
+ before: { id: before.id, label: before.label, total: before.counts.total },
56
+ after: { id: after.id, label: after.label, total: after.counts.total },
57
+ improvement,
58
+ improvementPercent,
59
+ newFindings,
60
+ fixedFindings,
61
+ persistingFindings: Math.max(0, persisting),
62
+ };
63
+ }
64
+ // ─── CLI ────────────────────────────────────────────────────────────────────
65
+ export function runReviewCompare(argv) {
66
+ if (argv.includes("--help") || argv.includes("-h")) {
67
+ console.log(`
68
+ judges review-compare — Compare two review runs to measure improvement
69
+
70
+ Usage:
71
+ judges review-compare save --id run1 --label "Before refactor" --findings findings.json
72
+ judges review-compare diff --before run1 --after run2
73
+ judges review-compare list List saved snapshots
74
+ judges review-compare --format json JSON output
75
+
76
+ Subcommands:
77
+ save Save a review snapshot for later comparison
78
+ diff Compare two saved snapshots
79
+ list List all saved snapshots
80
+
81
+ Save Options:
82
+ --id <name> Snapshot identifier
83
+ --label <text> Human-readable label
84
+ --findings <path> JSON file with findings array
85
+
86
+ Diff Options:
87
+ --before <id> First snapshot ID
88
+ --after <id> Second snapshot ID
89
+
90
+ Snapshots are stored locally in .judges/snapshots/.
91
+ `);
92
+ return;
93
+ }
94
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
95
+ const subcommand = argv.find((a) => !a.startsWith("-") && a !== "review-compare") || "list";
96
+ if (subcommand === "save") {
97
+ const id = argv.find((_a, i) => argv[i - 1] === "--id");
98
+ const label = argv.find((_a, i) => argv[i - 1] === "--label") || id || "unlabeled";
99
+ const findingsPath = argv.find((_a, i) => argv[i - 1] === "--findings");
100
+ if (!id) {
101
+ console.error("Error: --id is required for save.");
102
+ process.exitCode = 1;
103
+ return;
104
+ }
105
+ let findings = [];
106
+ if (findingsPath && existsSync(findingsPath)) {
107
+ try {
108
+ const raw = JSON.parse(readFileSync(findingsPath, "utf-8"));
109
+ findings = Array.isArray(raw) ? raw : Array.isArray(raw.findings) ? raw.findings : [];
110
+ }
111
+ catch {
112
+ console.error("Error: Cannot parse findings file.");
113
+ process.exitCode = 1;
114
+ return;
115
+ }
116
+ }
117
+ const counts = { critical: 0, high: 0, medium: 0, low: 0, total: findings.length };
118
+ for (const f of findings) {
119
+ if (f.severity === "critical")
120
+ counts.critical++;
121
+ else if (f.severity === "high")
122
+ counts.high++;
123
+ else if (f.severity === "medium")
124
+ counts.medium++;
125
+ else
126
+ counts.low++;
127
+ }
128
+ const snapshot = { id, timestamp: new Date().toISOString(), label, findings, counts };
129
+ saveSnapshot(snapshot);
130
+ console.log(`Saved snapshot '${id}' with ${findings.length} findings.`);
131
+ return;
132
+ }
133
+ if (subcommand === "list") {
134
+ const ids = listSnapshots();
135
+ if (ids.length === 0) {
136
+ console.log("No snapshots saved. Use 'judges review-compare save' to create one.");
137
+ return;
138
+ }
139
+ console.log(`\n Saved Snapshots:\n ─────────────────────────────`);
140
+ for (const id of ids) {
141
+ const snap = loadSnapshot(id);
142
+ if (snap) {
143
+ console.log(` ${snap.id} — ${snap.label} (${snap.counts.total} findings, ${snap.timestamp.slice(0, 10)})`);
144
+ }
145
+ }
146
+ console.log();
147
+ return;
148
+ }
149
+ if (subcommand === "diff") {
150
+ const beforeId = argv.find((_a, i) => argv[i - 1] === "--before");
151
+ const afterId = argv.find((_a, i) => argv[i - 1] === "--after");
152
+ if (!beforeId || !afterId) {
153
+ console.error("Error: Both --before and --after snapshot IDs are required.");
154
+ process.exitCode = 1;
155
+ return;
156
+ }
157
+ const before = loadSnapshot(beforeId);
158
+ const after = loadSnapshot(afterId);
159
+ if (!before) {
160
+ console.error(`Error: Snapshot '${beforeId}' not found.`);
161
+ process.exitCode = 1;
162
+ return;
163
+ }
164
+ if (!after) {
165
+ console.error(`Error: Snapshot '${afterId}' not found.`);
166
+ process.exitCode = 1;
167
+ return;
168
+ }
169
+ const result = compareSnapshots(before, after);
170
+ if (format === "json") {
171
+ console.log(JSON.stringify(result, null, 2));
172
+ return;
173
+ }
174
+ const trendIcon = result.improvement > 0 ? "📉" : result.improvement < 0 ? "📈" : "➡️";
175
+ console.log(`\n Review Comparison\n ─────────────────────────────`);
176
+ console.log(` Before: ${result.before.label} (${result.before.total} findings)`);
177
+ console.log(` After: ${result.after.label} (${result.after.total} findings)`);
178
+ console.log(` ${trendIcon} Change: ${result.improvement > 0 ? "-" : "+"}${Math.abs(result.improvement)} findings (${result.improvementPercent}%)`);
179
+ console.log(` Fixed: ${result.fixedFindings.length} New: ${result.newFindings.length} Persisting: ${result.persistingFindings}`);
180
+ if (result.fixedFindings.length > 0) {
181
+ console.log("\n Fixed findings:");
182
+ for (const f of result.fixedFindings.slice(0, 10)) {
183
+ console.log(` ✅ [${f.severity}] ${f.pattern} — ${f.file}`);
184
+ }
185
+ if (result.fixedFindings.length > 10)
186
+ console.log(` ... +${result.fixedFindings.length - 10} more`);
187
+ }
188
+ if (result.newFindings.length > 0) {
189
+ console.log("\n New findings:");
190
+ for (const f of result.newFindings.slice(0, 10)) {
191
+ console.log(` ❌ [${f.severity}] ${f.pattern} — ${f.file}`);
192
+ }
193
+ if (result.newFindings.length > 10)
194
+ console.log(` ... +${result.newFindings.length - 10} more`);
195
+ }
196
+ console.log();
197
+ return;
198
+ }
199
+ console.log("Unknown subcommand. Use --help for usage.");
200
+ }
201
+ //# sourceMappingURL=review-compare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-compare.js","sourceRoot":"","sources":["../../src/commands/review-compare.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;AACrF,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAsB5B,+EAA+E;AAE/E,SAAS,eAAe;IACtB,OAAO,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,YAAY,CAAC,EAAU;IAC9B,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAmB,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,QAAwB;IAC5C,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AAC9F,CAAC;AAED,SAAS,aAAa;IACpB,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,IAAI,CAAC;QACH,OAAQ,WAAW,CAAC,GAAG,CAAyB;aAC7C,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;aAC1C,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAsB,EAAE,KAAqB;IACrE,0CAA0C;IAC1C,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3F,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAEzF,MAAM,WAAW,GAAG,KAAK,CAAC,QAAQ;SAC/B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;SAClE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAE5E,MAAM,aAAa,GAAG,MAAM,CAAC,QAAQ;SAClC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;SACjE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAE5E,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC;IAC3D,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;IAC7D,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/G,OAAO;QACL,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;QAC1E,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE;QACtE,WAAW;QACX,kBAAkB;QAClB,WAAW;QACX,aAAa;QACb,kBAAkB,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;KAC5C,CAAC;AACJ,CAAC;AAED,+EAA+E;AAE/E,MAAM,UAAU,gBAAgB,CAAC,IAAc;IAC7C,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;CAwBf,CAAC,CAAC;QACC,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,UAAU,CAAC,IAAI,MAAM,CAAC;IAC1F,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,gBAAgB,CAAC,IAAI,MAAM,CAAC;IAE5F,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QAC1B,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;QACxE,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,SAAS,CAAC,IAAI,EAAE,IAAI,WAAW,CAAC;QACnG,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC;QAExF,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACnD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,GAAwE,EAAE,CAAC;QACvF,IAAI,YAAY,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7C,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;gBAC5D,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YACxF,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;gBACpD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;gBACrB,OAAO;YACT,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;QACnF,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,IAAI,CAAC,CAAC,QAAQ,KAAK,UAAU;gBAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;iBAC5C,IAAI,CAAC,CAAC,QAAQ,KAAK,MAAM;gBAAE,MAAM,CAAC,IAAI,EAAE,CAAC;iBACzC,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ;gBAAE,MAAM,CAAC,MAAM,EAAE,CAAC;;gBAC7C,MAAM,CAAC,GAAG,EAAE,CAAC;QACpB,CAAC;QAED,MAAM,QAAQ,GAAmB,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QACtG,YAAY,CAAC,QAAQ,CAAC,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,UAAU,QAAQ,CAAC,MAAM,YAAY,CAAC,CAAC;QACxE,OAAO;IACT,CAAC;IAED,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,qEAAqE,CAAC,CAAC;YACnF,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC;QACrE,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC;YAC9B,IAAI,IAAI,EAAE,CAAC;gBACT,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,cAAc,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;YAChH,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO;IACT,CAAC;IAED,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC;QAClF,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;QAEhF,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO,EAAE,CAAC;YAC1B,OAAO,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;YAC7E,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QACtC,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QAEpC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,oBAAoB,QAAQ,cAAc,CAAC,CAAC;YAC1D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,cAAc,CAAC,CAAC;YACzD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAE/C,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC7C,OAAO;QACT,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACvF,OAAO,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAC;QACtE,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,MAAM,CAAC,KAAK,YAAY,CAAC,CAAC;QACpF,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,CAAC,KAAK,YAAY,CAAC,CAAC;QAClF,OAAO,CAAC,GAAG,CACT,OAAO,SAAS,YAAY,MAAM,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,cAAc,MAAM,CAAC,kBAAkB,IAAI,CACzI,CAAC;QACF,OAAO,CAAC,GAAG,CACT,cAAc,MAAM,CAAC,aAAa,CAAC,MAAM,UAAU,MAAM,CAAC,WAAW,CAAC,MAAM,iBAAiB,MAAM,CAAC,kBAAkB,EAAE,CACzH,CAAC;QAEF,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;YACrC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;gBAClD,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAClE,CAAC;YACD,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,GAAG,EAAE;gBAAE,OAAO,CAAC,GAAG,CAAC,cAAc,MAAM,CAAC,aAAa,CAAC,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC;QAC3G,CAAC;QAED,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;YACnC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;gBAChD,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAClE,CAAC;YACD,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,EAAE;gBAAE,OAAO,CAAC,GAAG,CAAC,cAAc,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC;QACvG,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Review-explain — Generate plain-language explanation of review findings
3
+ * for non-technical stakeholders.
4
+ */
5
+ export declare function runReviewExplain(argv: string[]): void;
6
+ //# sourceMappingURL=review-explain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-explain.d.ts","sourceRoot":"","sources":["../../src/commands/review-explain.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA6JH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA8ErD"}
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Review-explain — Generate plain-language explanation of review findings
3
+ * for non-technical stakeholders.
4
+ */
5
+ import { readFileSync, existsSync } from "fs";
6
+ // ─── Plain-language explanations ───────────────────────────────────────────
7
+ const EXPLANATIONS = {
8
+ "hardcoded-secret": {
9
+ plain: "A password or secret key is written directly in the code, visible to anyone who can see the source.",
10
+ impact: "If code is shared or leaked, attackers can immediately access protected systems. This is a leading cause of data breaches.",
11
+ recommendation: "Move secrets to environment variables or a secrets manager. Never commit credentials to version control.",
12
+ },
13
+ "eval-usage": {
14
+ plain: "The code can execute arbitrary commands, potentially from untrusted input.",
15
+ impact: "An attacker could inject malicious code that runs with full application permissions, leading to data theft or system compromise.",
16
+ recommendation: "Replace with safer alternatives that don't allow arbitrary code execution.",
17
+ },
18
+ "sql-injection": {
19
+ plain: "User input is being inserted directly into database queries without protection.",
20
+ impact: "Attackers can manipulate queries to steal, modify, or delete data. SQL injection is consistently in the OWASP Top 10.",
21
+ recommendation: "Use parameterized queries or an ORM that handles input sanitization automatically.",
22
+ },
23
+ "sql-concat": {
24
+ plain: "Database queries are built by concatenating strings, which can allow injection attacks.",
25
+ impact: "Similar to SQL injection — attackers can manipulate queries through crafted input.",
26
+ recommendation: "Use parameterized queries instead of string concatenation.",
27
+ },
28
+ "xss-risk": {
29
+ plain: "The code inserts content directly into web pages without sanitization.",
30
+ impact: "Attackers can inject scripts that steal user credentials, redirect users, or deface the application.",
31
+ recommendation: "Always sanitize user content before displaying it. Use framework-provided escaping functions.",
32
+ },
33
+ "command-injection": {
34
+ plain: "The code runs system commands that include user-controllable data.",
35
+ impact: "An attacker could execute arbitrary commands on the server, potentially taking full control.",
36
+ recommendation: "Avoid passing user input to system commands. Use libraries with safe APIs instead.",
37
+ },
38
+ "empty-catch": {
39
+ plain: "Errors are being silently ignored — the code catches errors but does nothing with them.",
40
+ impact: "Issues go undetected in production, making debugging extremely difficult and potentially hiding security problems.",
41
+ recommendation: "Log errors appropriately and handle them based on their severity.",
42
+ },
43
+ "any-type": {
44
+ plain: "Code uses unsafe typing that bypasses compile-time safety checks.",
45
+ impact: "Bugs that would normally be caught before deployment can slip through to production.",
46
+ recommendation: "Use proper type definitions to catch errors during development rather than in production.",
47
+ },
48
+ "console-log": {
49
+ plain: "Debug logging statements are present in production code.",
50
+ impact: "Can leak sensitive information and create unnecessary noise in production logs.",
51
+ recommendation: "Use a proper logging framework with configurable levels.",
52
+ },
53
+ "deprecated-api": {
54
+ plain: "The code uses outdated functions that may be removed in future releases.",
55
+ impact: "Future updates could break the application. Deprecated APIs may also have known security vulnerabilities.",
56
+ recommendation: "Migrate to the recommended replacement APIs.",
57
+ },
58
+ "unsafe-regex": {
59
+ plain: "A pattern matching expression is built from user input, which could be exploited.",
60
+ impact: "Attackers can craft input that causes the application to hang or consume excessive resources.",
61
+ recommendation: "Validate and escape user input before using it in pattern matching.",
62
+ },
63
+ "todo-fixme": {
64
+ plain: "The code contains unfinished work markers that haven't been addressed.",
65
+ impact: "Incomplete implementations may have missing validation, error handling, or security checks.",
66
+ recommendation: "Track these in your project management tool and resolve before release.",
67
+ },
68
+ };
69
+ // ─── Analysis ──────────────────────────────────────────────────────────────
70
+ function explainFindings(findings) {
71
+ // Deduplicate by pattern
72
+ const patternSet = new Map();
73
+ for (const f of findings) {
74
+ const existing = patternSet.get(f.pattern);
75
+ if (existing) {
76
+ existing.count++;
77
+ }
78
+ else {
79
+ patternSet.set(f.pattern, { severity: f.severity, count: 1 });
80
+ }
81
+ }
82
+ const explanations = [];
83
+ for (const [pattern, data] of patternSet) {
84
+ const expl = EXPLANATIONS[pattern] || {
85
+ plain: `Found ${data.count} instance(s) of '${pattern}' pattern.`,
86
+ impact: "This finding may affect code quality or security depending on context.",
87
+ recommendation: "Review each instance and address based on your team's standards.",
88
+ };
89
+ explanations.push({
90
+ pattern,
91
+ severity: data.severity,
92
+ plainExplanation: expl.plain,
93
+ businessImpact: expl.impact,
94
+ recommendation: expl.recommendation,
95
+ });
96
+ }
97
+ // Sort by severity
98
+ const sevRank = { critical: 4, high: 3, medium: 2, low: 1 };
99
+ explanations.sort((a, b) => (sevRank[b.severity] || 0) - (sevRank[a.severity] || 0));
100
+ const criticalCount = findings.filter((f) => f.severity === "critical").length;
101
+ const highCount = findings.filter((f) => f.severity === "high").length;
102
+ let riskLevel = "Low";
103
+ if (criticalCount > 0)
104
+ riskLevel = "Critical";
105
+ else if (highCount > 0)
106
+ riskLevel = "High";
107
+ else if (findings.length > 10)
108
+ riskLevel = "Medium";
109
+ let executiveSummary;
110
+ if (findings.length === 0) {
111
+ executiveSummary = "No issues were found in this review. The code appears to meet quality and security standards.";
112
+ }
113
+ else if (criticalCount > 0) {
114
+ executiveSummary = `This review found ${criticalCount} critical security issue(s) that must be resolved before deployment. These issues could lead to data breaches or system compromise if exploited.`;
115
+ }
116
+ else if (highCount > 0) {
117
+ executiveSummary = `This review found ${highCount} high-severity issue(s) that should be addressed promptly. While not immediately exploitable, they represent significant risk.`;
118
+ }
119
+ else {
120
+ executiveSummary = `This review found ${findings.length} issue(s), none critical. These represent code quality improvements that will reduce technical debt.`;
121
+ }
122
+ return { totalFindings: findings.length, explanations, executiveSummary, riskLevel };
123
+ }
124
+ // ─── CLI ────────────────────────────────────────────────────────────────────
125
+ export function runReviewExplain(argv) {
126
+ if (argv.includes("--help") || argv.includes("-h")) {
127
+ console.log(`
128
+ judges review-explain — Plain-language explanation of review findings
129
+
130
+ Usage:
131
+ judges review-explain --file findings.json Explain findings from JSON
132
+ judges review-explain --format json JSON output
133
+
134
+ Options:
135
+ --file <path> Path to findings JSON (array or {findings: [...]})
136
+ --format json JSON output
137
+ --help, -h Show this help
138
+
139
+ Translates technical security and quality findings into plain language
140
+ that non-technical stakeholders can understand. Includes business impact
141
+ and actionable recommendations.
142
+ `);
143
+ return;
144
+ }
145
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
146
+ const findingsFile = argv.find((_a, i) => argv[i - 1] === "--file");
147
+ if (!findingsFile) {
148
+ console.error("Error: --file <path> is required. Provide a JSON file with findings.");
149
+ process.exitCode = 1;
150
+ return;
151
+ }
152
+ if (!existsSync(findingsFile)) {
153
+ console.error(`Error: File '${findingsFile}' not found.`);
154
+ process.exitCode = 1;
155
+ return;
156
+ }
157
+ let findings;
158
+ try {
159
+ const raw = JSON.parse(readFileSync(findingsFile, "utf-8"));
160
+ findings = Array.isArray(raw) ? raw : Array.isArray(raw.findings) ? raw.findings : [];
161
+ }
162
+ catch {
163
+ console.error("Error: Cannot parse findings file.");
164
+ process.exitCode = 1;
165
+ return;
166
+ }
167
+ const result = explainFindings(findings);
168
+ if (format === "json") {
169
+ console.log(JSON.stringify(result, null, 2));
170
+ return;
171
+ }
172
+ console.log(`\n Review Explanation\n ─────────────────────────────`);
173
+ console.log(` Risk Level: ${result.riskLevel}`);
174
+ console.log(` Total Findings: ${result.totalFindings}\n`);
175
+ console.log(` Executive Summary:`);
176
+ console.log(` ${result.executiveSummary}`);
177
+ if (result.explanations.length > 0) {
178
+ console.log("\n Detailed Findings:");
179
+ for (const expl of result.explanations) {
180
+ const icon = expl.severity === "critical"
181
+ ? "🔴"
182
+ : expl.severity === "high"
183
+ ? "🟠"
184
+ : expl.severity === "medium"
185
+ ? "🟡"
186
+ : "🔵";
187
+ console.log(`\n ${icon} ${expl.pattern} (${expl.severity})`);
188
+ console.log(` What: ${expl.plainExplanation}`);
189
+ console.log(` Impact: ${expl.businessImpact}`);
190
+ console.log(` Action: ${expl.recommendation}`);
191
+ }
192
+ }
193
+ console.log();
194
+ }
195
+ //# sourceMappingURL=review-explain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-explain.js","sourceRoot":"","sources":["../../src/commands/review-explain.ts"],"names":[],"mappings":"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"}