@kevinrabun/judges 3.63.0 → 3.64.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 (38) 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/auto-approve.d.ts +5 -0
  6. package/dist/commands/auto-approve.d.ts.map +1 -0
  7. package/dist/commands/auto-approve.js +189 -0
  8. package/dist/commands/auto-approve.js.map +1 -0
  9. package/dist/commands/diff-explain.d.ts +5 -0
  10. package/dist/commands/diff-explain.d.ts.map +1 -0
  11. package/dist/commands/diff-explain.js +143 -0
  12. package/dist/commands/diff-explain.js.map +1 -0
  13. package/dist/commands/fix-suggest.d.ts +5 -0
  14. package/dist/commands/fix-suggest.d.ts.map +1 -0
  15. package/dist/commands/fix-suggest.js +172 -0
  16. package/dist/commands/fix-suggest.js.map +1 -0
  17. package/dist/commands/multi-lang-review.d.ts +5 -0
  18. package/dist/commands/multi-lang-review.d.ts.map +1 -0
  19. package/dist/commands/multi-lang-review.js +231 -0
  20. package/dist/commands/multi-lang-review.js.map +1 -0
  21. package/dist/commands/review-priority.d.ts +5 -0
  22. package/dist/commands/review-priority.d.ts.map +1 -0
  23. package/dist/commands/review-priority.js +158 -0
  24. package/dist/commands/review-priority.js.map +1 -0
  25. package/dist/commands/review-profile.d.ts +5 -0
  26. package/dist/commands/review-profile.d.ts.map +1 -0
  27. package/dist/commands/review-profile.js +169 -0
  28. package/dist/commands/review-profile.js.map +1 -0
  29. package/dist/commands/review-stats.d.ts +5 -0
  30. package/dist/commands/review-stats.d.ts.map +1 -0
  31. package/dist/commands/review-stats.js +176 -0
  32. package/dist/commands/review-stats.js.map +1 -0
  33. package/dist/commands/review-template.d.ts +5 -0
  34. package/dist/commands/review-template.d.ts.map +1 -0
  35. package/dist/commands/review-template.js +213 -0
  36. package/dist/commands/review-template.js.map +1 -0
  37. package/package.json +1 -1
  38. package/server.json +2 -2
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Auto-approve — Auto-approve findings below a configurable threshold.
3
+ */
4
+ import { readFileSync } from "fs";
5
+ // ─── Default policy ────────────────────────────────────────────────────────
6
+ function defaultPolicy() {
7
+ return {
8
+ maxLowFindings: 10,
9
+ maxMediumFindings: 3,
10
+ allowedRules: [],
11
+ requireMinScore: 70,
12
+ blockOnSecurity: true,
13
+ autoApproveClean: true,
14
+ };
15
+ }
16
+ // ─── Severity classification ────────────────────────────────────────────────
17
+ const SEVERITY_ORDER = { critical: 0, high: 1, medium: 2, low: 3 };
18
+ function isSecurity(finding) {
19
+ const rid = (finding.ruleId || "").toLowerCase();
20
+ return /sql|inject|xss|csrf|traversal|auth|secret|crypt|ssrf|deserial/i.test(rid);
21
+ }
22
+ // ─── Approval engine ───────────────────────────────────────────────────────
23
+ function evaluateApproval(verdict, policy) {
24
+ const findings = verdict.findings || [];
25
+ const violations = [];
26
+ const approved = [];
27
+ const flagged = [];
28
+ // Check score threshold
29
+ if ((verdict.overallScore ?? 0) < policy.requireMinScore) {
30
+ violations.push(`Score ${verdict.overallScore} is below minimum ${policy.requireMinScore}`);
31
+ }
32
+ // Classify findings
33
+ const severityCounts = { critical: 0, high: 0, medium: 0, low: 0 };
34
+ for (const f of findings) {
35
+ const sev = f.severity || "low";
36
+ severityCounts[sev] = (severityCounts[sev] || 0) + 1;
37
+ const sevLevel = SEVERITY_ORDER[sev] ?? 3;
38
+ // Critical and high are always flagged
39
+ if (sevLevel <= 1) {
40
+ flagged.push(f);
41
+ continue;
42
+ }
43
+ // Security findings blocked if policy says so
44
+ if (policy.blockOnSecurity && isSecurity(f)) {
45
+ flagged.push(f);
46
+ continue;
47
+ }
48
+ // Low findings auto-approved
49
+ if (sev === "low") {
50
+ approved.push(f);
51
+ continue;
52
+ }
53
+ // Medium finding — check against allowed rules
54
+ if (policy.allowedRules.length > 0 && policy.allowedRules.includes(f.ruleId)) {
55
+ approved.push(f);
56
+ }
57
+ else {
58
+ flagged.push(f);
59
+ }
60
+ }
61
+ // Check threshold violations
62
+ if (severityCounts["critical"] > 0) {
63
+ violations.push(`${severityCounts["critical"]} critical finding(s) detected`);
64
+ }
65
+ if (severityCounts["high"] > 0) {
66
+ violations.push(`${severityCounts["high"]} high finding(s) detected`);
67
+ }
68
+ if (severityCounts["medium"] > policy.maxMediumFindings) {
69
+ violations.push(`${severityCounts["medium"]} medium findings exceed max of ${policy.maxMediumFindings}`);
70
+ }
71
+ if (severityCounts["low"] > policy.maxLowFindings) {
72
+ violations.push(`${severityCounts["low"]} low findings exceed max of ${policy.maxLowFindings}`);
73
+ }
74
+ const isApproved = violations.length === 0 || (findings.length === 0 && policy.autoApproveClean);
75
+ let reason;
76
+ if (isApproved && findings.length === 0) {
77
+ reason = "Clean review — no findings";
78
+ }
79
+ else if (isApproved) {
80
+ reason = "All findings within policy thresholds";
81
+ }
82
+ else {
83
+ reason = violations.join("; ");
84
+ }
85
+ return {
86
+ approved: isApproved,
87
+ reason,
88
+ autoApproved: approved.length,
89
+ manualRequired: flagged.length,
90
+ policyViolations: violations,
91
+ findings: { approved, flagged },
92
+ };
93
+ }
94
+ // ─── CLI ────────────────────────────────────────────────────────────────────
95
+ export function runAutoApprove(argv) {
96
+ if (argv.includes("--help") || argv.includes("-h")) {
97
+ console.log(`
98
+ judges auto-approve — Auto-approve findings below threshold
99
+
100
+ Usage:
101
+ judges auto-approve --input verdict.json
102
+ judges auto-approve --input verdict.json --policy policy.json
103
+ judges auto-approve --input verdict.json --format json
104
+
105
+ Options:
106
+ --input <file> TribunalVerdict JSON file (required)
107
+ --policy <file> Approval policy JSON file (optional, uses defaults)
108
+ --min-score <n> Minimum score for approval (default: 70)
109
+ --format json JSON output
110
+ --help, -h Show this help
111
+
112
+ Policy defaults:
113
+ maxLowFindings: 10, maxMediumFindings: 3, requireMinScore: 70,
114
+ blockOnSecurity: true, autoApproveClean: true
115
+
116
+ Auto-approves low-severity findings and flags critical/high findings
117
+ for manual review. Reduces noise while maintaining safety.
118
+ `);
119
+ return;
120
+ }
121
+ const inputPath = argv.find((_a, i) => argv[i - 1] === "--input");
122
+ const policyPath = argv.find((_a, i) => argv[i - 1] === "--policy");
123
+ const minScoreStr = argv.find((_a, i) => argv[i - 1] === "--min-score");
124
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
125
+ if (!inputPath) {
126
+ console.error("Error: --input is required. Provide a verdict JSON file.");
127
+ process.exitCode = 1;
128
+ return;
129
+ }
130
+ let verdict;
131
+ try {
132
+ verdict = JSON.parse(readFileSync(inputPath, "utf-8"));
133
+ }
134
+ catch {
135
+ console.error(`Error: Cannot read or parse ${inputPath}`);
136
+ process.exitCode = 1;
137
+ return;
138
+ }
139
+ let policy = defaultPolicy();
140
+ if (policyPath) {
141
+ try {
142
+ const custom = JSON.parse(readFileSync(policyPath, "utf-8"));
143
+ policy = { ...policy, ...custom };
144
+ }
145
+ catch {
146
+ console.error(`Error: Cannot read policy file ${policyPath}`);
147
+ process.exitCode = 1;
148
+ return;
149
+ }
150
+ }
151
+ if (minScoreStr) {
152
+ policy.requireMinScore = parseInt(minScoreStr, 10);
153
+ }
154
+ const result = evaluateApproval(verdict, policy);
155
+ if (format === "json") {
156
+ console.log(JSON.stringify({
157
+ ...result,
158
+ findings: { autoApproved: result.findings.approved.length, flagged: result.findings.flagged.length },
159
+ }, null, 2));
160
+ if (!result.approved)
161
+ process.exitCode = 1;
162
+ return;
163
+ }
164
+ const icon = result.approved ? "✅" : "❌";
165
+ console.log(`\n Auto-Approval Result: ${icon} ${result.approved ? "APPROVED" : "REQUIRES REVIEW"}\n ─────────────────────────────`);
166
+ console.log(` Reason: ${result.reason}`);
167
+ console.log(` Score: ${verdict.overallScore ?? 0}/100`);
168
+ console.log(` Auto-approved: ${result.autoApproved} finding(s)`);
169
+ console.log(` Manual review: ${result.manualRequired} finding(s)`);
170
+ if (result.policyViolations.length > 0) {
171
+ console.log(`\n Policy Violations:`);
172
+ for (const v of result.policyViolations) {
173
+ console.log(` ❌ ${v}`);
174
+ }
175
+ }
176
+ if (result.findings.flagged.length > 0) {
177
+ console.log(`\n Flagged Findings:`);
178
+ for (const f of result.findings.flagged.slice(0, 10)) {
179
+ console.log(` 🔴 [${f.severity}] ${f.ruleId}: ${f.title}`);
180
+ }
181
+ if (result.findings.flagged.length > 10) {
182
+ console.log(` ... and ${result.findings.flagged.length - 10} more`);
183
+ }
184
+ }
185
+ console.log();
186
+ if (!result.approved)
187
+ process.exitCode = 1;
188
+ }
189
+ //# sourceMappingURL=auto-approve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-approve.js","sourceRoot":"","sources":["../../src/commands/auto-approve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Diff-explain — Explain why specific diff changes were flagged.
3
+ */
4
+ export declare function runDiffExplain(argv: string[]): void;
5
+ //# sourceMappingURL=diff-explain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-explain.d.ts","sourceRoot":"","sources":["../../src/commands/diff-explain.ts"],"names":[],"mappings":"AAAA;;GAEG;AAyFH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAoFnD"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Diff-explain — Explain why specific diff changes were flagged.
3
+ */
4
+ import { readFileSync } from "fs";
5
+ // ─── Knowledge base for common rules ────────────────────────────────────────
6
+ const RULE_EXPLANATIONS = {
7
+ "sql-injection": {
8
+ risk: "Attacker can manipulate database queries to extract, modify, or delete data",
9
+ whyFlagged: "User input is concatenated into SQL queries without parameterization",
10
+ action: "Use parameterized queries or prepared statements instead of string concatenation",
11
+ },
12
+ "xss-vulnerability": {
13
+ risk: "Attacker can inject malicious scripts that execute in other users' browsers",
14
+ whyFlagged: "User-supplied data is rendered in HTML without proper escaping",
15
+ action: "Sanitize and escape all user input before rendering in HTML context",
16
+ },
17
+ "hardcoded-secret": {
18
+ risk: "Credentials exposed in source code can be harvested from version control",
19
+ whyFlagged: "String patterns matching API keys, passwords, or tokens detected in code",
20
+ action: "Move secrets to environment variables or a secrets manager",
21
+ },
22
+ "path-traversal": {
23
+ risk: "Attacker can access files outside intended directories",
24
+ whyFlagged: "File paths constructed from user input without validation",
25
+ action: "Validate and normalize file paths, restrict to allowed directories",
26
+ },
27
+ "insecure-random": {
28
+ risk: "Predictable random values weaken security mechanisms",
29
+ whyFlagged: "Math.random() or similar used for security-sensitive operations",
30
+ action: "Use crypto.getRandomValues() or crypto.randomBytes() for security",
31
+ },
32
+ "error-info-leak": {
33
+ risk: "Internal error details can reveal system architecture to attackers",
34
+ whyFlagged: "Error messages expose stack traces, file paths, or internal details",
35
+ action: "Return generic error messages to users, log details server-side",
36
+ },
37
+ "missing-auth": {
38
+ risk: "Unauthorized access to protected resources or operations",
39
+ whyFlagged: "Endpoint or function lacks authentication/authorization checks",
40
+ action: "Add authentication middleware and verify user permissions",
41
+ },
42
+ "unsafe-deserialization": {
43
+ risk: "Attacker can execute arbitrary code via crafted serialized data",
44
+ whyFlagged: "Deserialization of untrusted data detected",
45
+ action: "Validate and whitelist types before deserialization, use safe formats like JSON",
46
+ },
47
+ };
48
+ // ─── Explanation engine ─────────────────────────────────────────────────────
49
+ function explainFinding(finding) {
50
+ const ruleId = finding.ruleId || "unknown";
51
+ const known = RULE_EXPLANATIONS[ruleId];
52
+ const explanation = known
53
+ ? known.whyFlagged
54
+ : `This code was flagged by the '${ruleId}' rule. ${finding.description || "Review the identified pattern for potential issues."}`;
55
+ const risk = known
56
+ ? known.risk
57
+ : `Potential ${finding.severity || "medium"}-severity issue that may affect code quality or security.`;
58
+ const action = known
59
+ ? known.action
60
+ : finding.recommendation || "Review and address the finding according to best practices.";
61
+ return {
62
+ finding: { ruleId, severity: finding.severity || "medium", title: finding.title },
63
+ context: finding.description || "",
64
+ explanation,
65
+ risk,
66
+ suggestedAction: action,
67
+ };
68
+ }
69
+ // ─── CLI ────────────────────────────────────────────────────────────────────
70
+ export function runDiffExplain(argv) {
71
+ if (argv.includes("--help") || argv.includes("-h")) {
72
+ console.log(`
73
+ judges diff-explain — Explain why changes were flagged
74
+
75
+ Usage:
76
+ judges diff-explain --input verdict.json
77
+ judges diff-explain --input verdict.json --rule sql-injection
78
+ judges diff-explain --input verdict.json --severity critical
79
+ judges diff-explain --format json
80
+
81
+ Options:
82
+ --input <file> TribunalVerdict JSON file (required)
83
+ --rule <id> Explain only findings for a specific rule
84
+ --severity <level> Filter by severity: critical, high, medium, low
85
+ --limit <n> Maximum findings to explain (default: 20)
86
+ --format json JSON output
87
+ --help, -h Show this help
88
+
89
+ Provides plain-language explanations of why code was flagged,
90
+ what the risk is, and what action to take. Useful for developers
91
+ unfamiliar with specific security or quality patterns.
92
+ `);
93
+ return;
94
+ }
95
+ const inputPath = argv.find((_a, i) => argv[i - 1] === "--input");
96
+ const ruleFilter = argv.find((_a, i) => argv[i - 1] === "--rule");
97
+ const sevFilter = argv.find((_a, i) => argv[i - 1] === "--severity");
98
+ const limitStr = argv.find((_a, i) => argv[i - 1] === "--limit");
99
+ const limit = limitStr ? parseInt(limitStr, 10) : 20;
100
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
101
+ if (!inputPath) {
102
+ console.error("Error: --input is required. Provide a verdict JSON file.");
103
+ process.exitCode = 1;
104
+ return;
105
+ }
106
+ let verdict;
107
+ try {
108
+ verdict = JSON.parse(readFileSync(inputPath, "utf-8"));
109
+ }
110
+ catch {
111
+ console.error(`Error: Cannot read or parse ${inputPath}`);
112
+ process.exitCode = 1;
113
+ return;
114
+ }
115
+ let findings = verdict.findings || [];
116
+ if (ruleFilter) {
117
+ findings = findings.filter((f) => f.ruleId === ruleFilter);
118
+ }
119
+ if (sevFilter) {
120
+ findings = findings.filter((f) => f.severity === sevFilter);
121
+ }
122
+ findings = findings.slice(0, limit);
123
+ if (findings.length === 0) {
124
+ console.log("No findings to explain.");
125
+ return;
126
+ }
127
+ const explanations = findings.map(explainFinding);
128
+ if (format === "json") {
129
+ console.log(JSON.stringify({ count: explanations.length, explanations }, null, 2));
130
+ return;
131
+ }
132
+ console.log(`\n Diff Explanations (${explanations.length} finding(s))\n ─────────────────────────────`);
133
+ for (const exp of explanations) {
134
+ const sevIcon = { critical: "🔴", high: "🟠", medium: "🟡", low: "🔵" };
135
+ const icon = sevIcon[exp.finding.severity] || "⬜";
136
+ console.log(`\n ${icon} [${exp.finding.severity}] ${exp.finding.ruleId}: ${exp.finding.title}`);
137
+ console.log(` Why flagged: ${exp.explanation}`);
138
+ console.log(` Risk: ${exp.risk}`);
139
+ console.log(` Action: ${exp.suggestedAction}`);
140
+ }
141
+ console.log();
142
+ }
143
+ //# sourceMappingURL=diff-explain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-explain.js","sourceRoot":"","sources":["../../src/commands/diff-explain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Fix-suggest — Generate concrete code fix suggestions for findings.
3
+ */
4
+ export declare function runFixSuggest(argv: string[]): void;
5
+ //# sourceMappingURL=fix-suggest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix-suggest.d.ts","sourceRoot":"","sources":["../../src/commands/fix-suggest.ts"],"names":[],"mappings":"AAAA;;GAEG;AAuHH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAoFlD"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Fix-suggest — Generate concrete code fix suggestions for findings.
3
+ */
4
+ import { readFileSync } from "fs";
5
+ // ─── Fix patterns database ──────────────────────────────────────────────────
6
+ const FIX_PATTERNS = {
7
+ "sql-injection": {
8
+ problem: "User input concatenated directly into SQL query string",
9
+ fixDesc: "Use parameterized queries with placeholders",
10
+ before: "db.query(`SELECT * FROM users WHERE id = ${userId}`)",
11
+ after: 'db.query("SELECT * FROM users WHERE id = ?", [userId])',
12
+ refs: ["https://cheatsheetseries.owasp.org/cheatsheets/Query_Parameterization_Cheat_Sheet.html"],
13
+ },
14
+ "xss-vulnerability": {
15
+ problem: "User-supplied data rendered without escaping",
16
+ fixDesc: "Sanitize output using context-appropriate encoding",
17
+ before: "element.innerHTML = userInput;",
18
+ after: "element.textContent = userInput;",
19
+ refs: ["https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html"],
20
+ },
21
+ "hardcoded-secret": {
22
+ problem: "Secret value hardcoded in source file",
23
+ fixDesc: "Move secret to environment variable or secrets manager",
24
+ before: 'const API_KEY = "sk-abc123...";',
25
+ after: "const API_KEY = process.env.API_KEY;",
26
+ refs: ["https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html"],
27
+ },
28
+ "path-traversal": {
29
+ problem: "File path constructed from user input without validation",
30
+ fixDesc: "Normalize path and validate it stays within allowed directory",
31
+ before: "const file = path.join(uploadDir, req.params.filename);",
32
+ after: "const file = path.join(uploadDir, path.basename(req.params.filename));",
33
+ refs: ["https://owasp.org/www-community/attacks/Path_Traversal"],
34
+ },
35
+ "insecure-random": {
36
+ problem: "Math.random() used for security-sensitive value",
37
+ fixDesc: "Use cryptographically secure random number generator",
38
+ before: "const token = Math.random().toString(36);",
39
+ after: 'const token = crypto.randomBytes(32).toString("hex");',
40
+ refs: ["CWE-338: Use of Cryptographically Weak PRNG"],
41
+ },
42
+ "missing-auth": {
43
+ problem: "Endpoint lacks authentication check",
44
+ fixDesc: "Add authentication middleware before handler",
45
+ before: "app.get('/api/data', handler);",
46
+ after: "app.get('/api/data', authMiddleware, handler);",
47
+ refs: ["https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html"],
48
+ },
49
+ "error-info-leak": {
50
+ problem: "Detailed error information sent to client",
51
+ fixDesc: "Return generic error response, log details server-side",
52
+ before: "res.status(500).json({ error: err.stack });",
53
+ after: 'res.status(500).json({ error: "Internal server error" });',
54
+ refs: ["https://cheatsheetseries.owasp.org/cheatsheets/Error_Handling_Cheat_Sheet.html"],
55
+ },
56
+ "unsafe-deserialization": {
57
+ problem: "Deserialization of untrusted data",
58
+ fixDesc: "Validate input format and use safe deserialization",
59
+ before: "const obj = eval('(' + input + ')');",
60
+ after: "const obj = JSON.parse(input);",
61
+ refs: ["https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html"],
62
+ },
63
+ };
64
+ // ─── Suggestion engine ─────────────────────────────────────────────────────
65
+ function suggestFix(finding) {
66
+ const ruleId = finding.ruleId || "unknown";
67
+ const known = FIX_PATTERNS[ruleId];
68
+ if (known) {
69
+ return {
70
+ ruleId,
71
+ severity: finding.severity || "medium",
72
+ title: finding.title,
73
+ problem: known.problem,
74
+ fixDescription: known.fixDesc,
75
+ beforePattern: known.before,
76
+ afterPattern: known.after,
77
+ confidence: "high",
78
+ references: known.refs,
79
+ };
80
+ }
81
+ // Generate generic suggestion from finding data
82
+ return {
83
+ ruleId,
84
+ severity: finding.severity || "medium",
85
+ title: finding.title,
86
+ problem: finding.description || "Code pattern flagged for review",
87
+ fixDescription: finding.recommendation || "Apply the recommended fix pattern",
88
+ beforePattern: "",
89
+ afterPattern: "",
90
+ confidence: "medium",
91
+ references: [],
92
+ };
93
+ }
94
+ // ─── CLI ────────────────────────────────────────────────────────────────────
95
+ export function runFixSuggest(argv) {
96
+ if (argv.includes("--help") || argv.includes("-h")) {
97
+ console.log(`
98
+ judges fix-suggest — Generate concrete fix suggestions
99
+
100
+ Usage:
101
+ judges fix-suggest --input verdict.json
102
+ judges fix-suggest --input verdict.json --rule sql-injection
103
+ judges fix-suggest --input verdict.json --severity critical
104
+ judges fix-suggest --format json
105
+
106
+ Options:
107
+ --input <file> TribunalVerdict JSON file (required)
108
+ --rule <id> Suggest fixes only for a specific rule
109
+ --severity <level> Filter by severity
110
+ --limit <n> Maximum suggestions (default: 20)
111
+ --format json JSON output
112
+ --help, -h Show this help
113
+
114
+ Generates concrete before/after code patterns for each finding,
115
+ with links to OWASP/CWE references where applicable.
116
+ `);
117
+ return;
118
+ }
119
+ const inputPath = argv.find((_a, i) => argv[i - 1] === "--input");
120
+ const ruleFilter = argv.find((_a, i) => argv[i - 1] === "--rule");
121
+ const sevFilter = argv.find((_a, i) => argv[i - 1] === "--severity");
122
+ const limitStr = argv.find((_a, i) => argv[i - 1] === "--limit");
123
+ const limit = limitStr ? parseInt(limitStr, 10) : 20;
124
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
125
+ if (!inputPath) {
126
+ console.error("Error: --input is required. Provide a verdict JSON file.");
127
+ process.exitCode = 1;
128
+ return;
129
+ }
130
+ let verdict;
131
+ try {
132
+ verdict = JSON.parse(readFileSync(inputPath, "utf-8"));
133
+ }
134
+ catch {
135
+ console.error(`Error: Cannot read or parse ${inputPath}`);
136
+ process.exitCode = 1;
137
+ return;
138
+ }
139
+ let findings = verdict.findings || [];
140
+ if (ruleFilter)
141
+ findings = findings.filter((f) => f.ruleId === ruleFilter);
142
+ if (sevFilter)
143
+ findings = findings.filter((f) => f.severity === sevFilter);
144
+ findings = findings.slice(0, limit);
145
+ if (findings.length === 0) {
146
+ console.log("No findings to suggest fixes for.");
147
+ return;
148
+ }
149
+ const suggestions = findings.map(suggestFix);
150
+ if (format === "json") {
151
+ console.log(JSON.stringify({ count: suggestions.length, suggestions }, null, 2));
152
+ return;
153
+ }
154
+ console.log(`\n Fix Suggestions (${suggestions.length})\n ─────────────────────────────`);
155
+ for (const s of suggestions) {
156
+ const sevIcon = { critical: "🔴", high: "🟠", medium: "🟡", low: "🔵" };
157
+ const icon = sevIcon[s.severity] || "⬜";
158
+ console.log(`\n ${icon} [${s.severity}] ${s.ruleId}: ${s.title}`);
159
+ console.log(` Problem: ${s.problem}`);
160
+ console.log(` Fix: ${s.fixDescription}`);
161
+ if (s.beforePattern) {
162
+ console.log(` Before: ${s.beforePattern}`);
163
+ console.log(` After: ${s.afterPattern}`);
164
+ }
165
+ console.log(` Confidence: ${s.confidence}`);
166
+ if (s.references.length > 0) {
167
+ console.log(` References: ${s.references.join(", ")}`);
168
+ }
169
+ }
170
+ console.log();
171
+ }
172
+ //# sourceMappingURL=fix-suggest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix-suggest.js","sourceRoot":"","sources":["../../src/commands/fix-suggest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Multi-lang-review — Cross-language consistency checking.
3
+ */
4
+ export declare function runMultiLangReview(argv: string[]): void;
5
+ //# sourceMappingURL=multi-lang-review.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-lang-review.d.ts","sourceRoot":"","sources":["../../src/commands/multi-lang-review.ts"],"names":[],"mappings":"AAAA;;GAEG;AAsMH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAsFvD"}