@kevinrabun/judges 3.41.0 → 3.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +126 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/assign-findings.d.ts +37 -0
  6. package/dist/commands/assign-findings.d.ts.map +1 -0
  7. package/dist/commands/assign-findings.js +178 -0
  8. package/dist/commands/assign-findings.js.map +1 -0
  9. package/dist/commands/auto-triage.d.ts +32 -0
  10. package/dist/commands/auto-triage.d.ts.map +1 -0
  11. package/dist/commands/auto-triage.js +126 -0
  12. package/dist/commands/auto-triage.js.map +1 -0
  13. package/dist/commands/ci-template.d.ts +15 -0
  14. package/dist/commands/ci-template.d.ts.map +1 -0
  15. package/dist/commands/ci-template.js +212 -0
  16. package/dist/commands/ci-template.js.map +1 -0
  17. package/dist/commands/coverage-map.d.ts +23 -0
  18. package/dist/commands/coverage-map.d.ts.map +1 -0
  19. package/dist/commands/coverage-map.js +223 -0
  20. package/dist/commands/coverage-map.js.map +1 -0
  21. package/dist/commands/diff-only.d.ts +34 -0
  22. package/dist/commands/diff-only.d.ts.map +1 -0
  23. package/dist/commands/diff-only.js +152 -0
  24. package/dist/commands/diff-only.js.map +1 -0
  25. package/dist/commands/false-negatives.d.ts +35 -0
  26. package/dist/commands/false-negatives.d.ts.map +1 -0
  27. package/dist/commands/false-negatives.js +166 -0
  28. package/dist/commands/false-negatives.js.map +1 -0
  29. package/dist/commands/group-findings.d.ts +23 -0
  30. package/dist/commands/group-findings.d.ts.map +1 -0
  31. package/dist/commands/group-findings.js +155 -0
  32. package/dist/commands/group-findings.js.map +1 -0
  33. package/dist/commands/hook-install.d.ts +22 -0
  34. package/dist/commands/hook-install.d.ts.map +1 -0
  35. package/dist/commands/hook-install.js +143 -0
  36. package/dist/commands/hook-install.js.map +1 -0
  37. package/dist/commands/policy-audit.d.ts +53 -0
  38. package/dist/commands/policy-audit.d.ts.map +1 -0
  39. package/dist/commands/policy-audit.js +161 -0
  40. package/dist/commands/policy-audit.js.map +1 -0
  41. package/dist/commands/pr-summary.d.ts +26 -0
  42. package/dist/commands/pr-summary.d.ts.map +1 -0
  43. package/dist/commands/pr-summary.js +188 -0
  44. package/dist/commands/pr-summary.js.map +1 -0
  45. package/dist/commands/profile.d.ts +38 -0
  46. package/dist/commands/profile.d.ts.map +1 -0
  47. package/dist/commands/profile.js +102 -0
  48. package/dist/commands/profile.js.map +1 -0
  49. package/dist/commands/regression-alert.d.ts +32 -0
  50. package/dist/commands/regression-alert.d.ts.map +1 -0
  51. package/dist/commands/regression-alert.js +216 -0
  52. package/dist/commands/regression-alert.js.map +1 -0
  53. package/dist/commands/remediation.d.ts +21 -0
  54. package/dist/commands/remediation.d.ts.map +1 -0
  55. package/dist/commands/remediation.js +257 -0
  56. package/dist/commands/remediation.js.map +1 -0
  57. package/dist/commands/sla-track.d.ts +57 -0
  58. package/dist/commands/sla-track.d.ts.map +1 -0
  59. package/dist/commands/sla-track.js +269 -0
  60. package/dist/commands/sla-track.js.map +1 -0
  61. package/dist/commands/smart-select.d.ts +27 -0
  62. package/dist/commands/smart-select.d.ts.map +1 -0
  63. package/dist/commands/smart-select.js +346 -0
  64. package/dist/commands/smart-select.js.map +1 -0
  65. package/dist/commands/ticket-sync.d.ts +26 -0
  66. package/dist/commands/ticket-sync.d.ts.map +1 -0
  67. package/dist/commands/ticket-sync.js +236 -0
  68. package/dist/commands/ticket-sync.js.map +1 -0
  69. package/dist/commands/upload.d.ts +14 -0
  70. package/dist/commands/upload.d.ts.map +1 -0
  71. package/dist/commands/upload.js +173 -0
  72. package/dist/commands/upload.js.map +1 -0
  73. package/dist/commands/validate-config.d.ts +17 -0
  74. package/dist/commands/validate-config.d.ts.map +1 -0
  75. package/dist/commands/validate-config.js +268 -0
  76. package/dist/commands/validate-config.js.map +1 -0
  77. package/dist/commands/warm-cache.d.ts +31 -0
  78. package/dist/commands/warm-cache.d.ts.map +1 -0
  79. package/dist/commands/warm-cache.js +166 -0
  80. package/dist/commands/warm-cache.js.map +1 -0
  81. package/package.json +1 -1
  82. package/server.json +2 -2
@@ -0,0 +1,188 @@
1
+ /**
2
+ * PR summary comment — post a top-level comment on a GitHub PR
3
+ * with the overall Judges verdict, score, and finding counts.
4
+ *
5
+ * Uses the GitHub API to create or update a comment with a distinctive
6
+ * marker so subsequent runs update in-place rather than spamming.
7
+ */
8
+ // ─── Marker ─────────────────────────────────────────────────────────────────
9
+ const COMMENT_MARKER = "<!-- judges-pr-summary -->";
10
+ // ─── Formatting ─────────────────────────────────────────────────────────────
11
+ function verdictEmoji(verdict) {
12
+ if (verdict === "pass")
13
+ return "✅";
14
+ if (verdict === "fail")
15
+ return "❌";
16
+ return "⚠️";
17
+ }
18
+ function severityBadge(severity) {
19
+ const map = { critical: "🔴", high: "🟠", medium: "🟡", low: "🔵", info: "⚪" };
20
+ return map[severity] || "⚪";
21
+ }
22
+ export function formatPrSummary(verdict) {
23
+ const emoji = verdictEmoji(verdict.overallVerdict);
24
+ const lines = [
25
+ COMMENT_MARKER,
26
+ `## ${emoji} Judges Code Review — ${verdict.overallVerdict.toUpperCase()}`,
27
+ "",
28
+ `| Metric | Value |`,
29
+ `|--------|-------|`,
30
+ `| **Verdict** | ${verdict.overallVerdict} |`,
31
+ `| **Score** | ${verdict.overallScore}/100 |`,
32
+ `| **Critical** | ${verdict.criticalCount} |`,
33
+ `| **High** | ${verdict.highCount} |`,
34
+ `| **Judges Run** | ${verdict.evaluations.length} |`,
35
+ "",
36
+ ];
37
+ // Per-judge breakdown
38
+ if (verdict.evaluations.length > 0) {
39
+ lines.push("### Judge Breakdown", "");
40
+ lines.push("| Judge | Verdict | Score | Findings |");
41
+ lines.push("|-------|---------|-------|----------|");
42
+ for (const evaluation of verdict.evaluations) {
43
+ const jEmoji = verdictEmoji(evaluation.verdict);
44
+ const findingCount = evaluation.findings?.length ?? 0;
45
+ lines.push(`| ${evaluation.judgeId} | ${jEmoji} ${evaluation.verdict} | ${evaluation.score}/100 | ${findingCount} |`);
46
+ }
47
+ lines.push("");
48
+ }
49
+ // Top findings
50
+ const allFindings = verdict.evaluations.flatMap((e) => e.findings || []);
51
+ const topFindings = allFindings.filter((f) => f.severity === "critical" || f.severity === "high").slice(0, 10);
52
+ if (topFindings.length > 0) {
53
+ lines.push("### Top Findings", "");
54
+ for (const f of topFindings) {
55
+ const badge = severityBadge(f.severity);
56
+ const loc = f.lineNumbers?.length ? ` (line ${f.lineNumbers[0]})` : "";
57
+ lines.push(`- ${badge} **${f.severity.toUpperCase()}** — ${f.ruleId}: ${f.title}${loc}`);
58
+ }
59
+ lines.push("");
60
+ }
61
+ lines.push("---", `<sub>Generated by [Judges](https://github.com/KevinRabun/judges) at ${new Date().toISOString()}</sub>`);
62
+ return lines.join("\n");
63
+ }
64
+ // ─── GitHub API ─────────────────────────────────────────────────────────────
65
+ async function findExistingComment(owner, repo, prNumber, token, baseUrl) {
66
+ const url = `${baseUrl}/repos/${owner}/${repo}/issues/${prNumber}/comments?per_page=100`;
67
+ const res = await fetch(url, {
68
+ headers: { Authorization: `Bearer ${token}`, Accept: "application/vnd.github+json" },
69
+ });
70
+ if (!res.ok)
71
+ return null;
72
+ const comments = (await res.json());
73
+ const existing = comments.find((c) => c.body.includes(COMMENT_MARKER));
74
+ return existing ? { id: existing.id, url: existing.html_url } : null;
75
+ }
76
+ export async function postPrSummary(options) {
77
+ const baseUrl = options.baseUrl || "https://api.github.com";
78
+ const body = formatPrSummary(options.verdict);
79
+ const headers = {
80
+ Authorization: `Bearer ${options.token}`,
81
+ Accept: "application/vnd.github+json",
82
+ "Content-Type": "application/json",
83
+ };
84
+ // Check for existing comment to update
85
+ const existing = await findExistingComment(options.owner, options.repo, options.prNumber, options.token, baseUrl);
86
+ if (existing) {
87
+ const url = `${baseUrl}/repos/${options.owner}/${options.repo}/issues/comments/${existing.id}`;
88
+ const res = await fetch(url, {
89
+ method: "PATCH",
90
+ headers,
91
+ body: JSON.stringify({ body }),
92
+ });
93
+ if (!res.ok)
94
+ throw new Error(`Failed to update comment: ${res.status} ${res.statusText}`);
95
+ return { commentId: existing.id, updated: true, url: existing.url };
96
+ }
97
+ const url = `${baseUrl}/repos/${options.owner}/${options.repo}/issues/${options.prNumber}/comments`;
98
+ const res = await fetch(url, {
99
+ method: "POST",
100
+ headers,
101
+ body: JSON.stringify({ body }),
102
+ });
103
+ if (!res.ok)
104
+ throw new Error(`Failed to create comment: ${res.status} ${res.statusText}`);
105
+ const data = (await res.json());
106
+ return { commentId: data.id, updated: false, url: data.html_url };
107
+ }
108
+ // ─── CLI ────────────────────────────────────────────────────────────────────
109
+ export async function runPrSummary(argv) {
110
+ if (argv.includes("--help") || argv.includes("-h")) {
111
+ console.log(`
112
+ judges pr-summary — Post a PR summary comment with Judges results
113
+
114
+ Usage:
115
+ judges eval --file src/app.ts --format json | judges pr-summary --pr 42 --repo owner/repo
116
+
117
+ Options:
118
+ --pr <number> PR number (required)
119
+ --repo <owner/repo> GitHub repo (auto-detected from git)
120
+ --token <token> GitHub token (default: GITHUB_TOKEN env)
121
+ --sarif <path> Read results from SARIF file instead of stdin
122
+ --help, -h Show this help
123
+ `);
124
+ return;
125
+ }
126
+ const { readFileSync, existsSync } = await import("fs");
127
+ const { execSync } = await import("child_process");
128
+ const prArg = argv.find((_a, i) => argv[i - 1] === "--pr");
129
+ if (!prArg) {
130
+ console.error("Error: --pr <number> is required");
131
+ process.exit(1);
132
+ }
133
+ const prNumber = parseInt(prArg, 10);
134
+ let repoArg = argv.find((_a, i) => argv[i - 1] === "--repo");
135
+ if (!repoArg) {
136
+ try {
137
+ const remote = execSync("git remote get-url origin", { encoding: "utf-8" }).trim();
138
+ const match = remote.match(/github\.com[:/](.+?)(?:\.git)?$/);
139
+ if (match)
140
+ repoArg = match[1];
141
+ }
142
+ catch {
143
+ /* ignore */
144
+ }
145
+ }
146
+ if (!repoArg) {
147
+ console.error("Error: --repo <owner/repo> required (could not auto-detect)");
148
+ process.exit(1);
149
+ }
150
+ const [owner, repo] = repoArg.split("/");
151
+ const token = argv.find((_a, i) => argv[i - 1] === "--token") || process.env.GITHUB_TOKEN || "";
152
+ if (!token) {
153
+ console.error("Error: --token or GITHUB_TOKEN env required");
154
+ process.exit(1);
155
+ }
156
+ // Load verdict
157
+ const sarifPath = argv.find((_a, i) => argv[i - 1] === "--sarif");
158
+ let verdict;
159
+ if (sarifPath && existsSync(sarifPath)) {
160
+ // Parse SARIF and synthesize a verdict
161
+ const sarif = JSON.parse(readFileSync(sarifPath, "utf-8"));
162
+ const findings = sarif.runs?.[0]?.results || [];
163
+ verdict = {
164
+ overallVerdict: findings.some((f) => f.level === "error") ? "fail" : "pass",
165
+ overallScore: Math.max(0, 100 - findings.length * 5),
166
+ summary: `SARIF upload with ${findings.length} findings`,
167
+ evaluations: [],
168
+ findings: [],
169
+ criticalCount: findings.filter((f) => f.level === "error").length,
170
+ highCount: findings.filter((f) => f.level === "warning").length,
171
+ timestamp: new Date().toISOString(),
172
+ };
173
+ }
174
+ else {
175
+ // Try reading JSON verdict from stdin arg or file
176
+ const jsonArg = argv.find((_a, i) => argv[i - 1] === "--json");
177
+ if (jsonArg && existsSync(jsonArg)) {
178
+ verdict = JSON.parse(readFileSync(jsonArg, "utf-8"));
179
+ }
180
+ else {
181
+ console.error("Error: provide --sarif <path> or --json <path>");
182
+ process.exit(1);
183
+ }
184
+ }
185
+ const result = await postPrSummary({ owner, repo, prNumber, token, verdict });
186
+ console.log(`${result.updated ? "Updated" : "Created"} PR summary comment: ${result.url}`);
187
+ }
188
+ //# sourceMappingURL=pr-summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pr-summary.js","sourceRoot":"","sources":["../../src/commands/pr-summary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Performance profiling — track evaluation time per judge/evaluator.
3
+ *
4
+ * Wraps tribunal evaluation and reports timing data for each judge,
5
+ * helping identify bottlenecks and optimize CI pipeline duration.
6
+ */
7
+ export interface JudgeTiming {
8
+ judgeId: string;
9
+ durationMs: number;
10
+ findingCount: number;
11
+ }
12
+ export interface ProfilingReport {
13
+ totalMs: number;
14
+ judges: JudgeTiming[];
15
+ slowest: string;
16
+ fastest: string;
17
+ avgMs: number;
18
+ }
19
+ /**
20
+ * Create a profiling wrapper around a function.
21
+ */
22
+ export declare function profileFn<T>(fn: () => T): {
23
+ result: T;
24
+ durationMs: number;
25
+ };
26
+ /**
27
+ * Create a profiling wrapper around an async function.
28
+ */
29
+ export declare function profileAsync<T>(fn: () => Promise<T>): Promise<{
30
+ result: T;
31
+ durationMs: number;
32
+ }>;
33
+ /**
34
+ * Build a profiling report from timing data collected during evaluation.
35
+ */
36
+ export declare function buildProfilingReport(timings: JudgeTiming[]): ProfilingReport;
37
+ export declare function runProfile(argv: string[]): void;
38
+ //# sourceMappingURL=profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../src/commands/profile.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAID;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG;IAAE,MAAM,EAAE,CAAC,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAI3E;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,CAAC,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAItG;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,eAAe,CAe5E;AAID,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAgD/C"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Performance profiling — track evaluation time per judge/evaluator.
3
+ *
4
+ * Wraps tribunal evaluation and reports timing data for each judge,
5
+ * helping identify bottlenecks and optimize CI pipeline duration.
6
+ */
7
+ // ─── Profiling ──────────────────────────────────────────────────────────────
8
+ /**
9
+ * Create a profiling wrapper around a function.
10
+ */
11
+ export function profileFn(fn) {
12
+ const start = performance.now();
13
+ const result = fn();
14
+ return { result, durationMs: Math.round(performance.now() - start) };
15
+ }
16
+ /**
17
+ * Create a profiling wrapper around an async function.
18
+ */
19
+ export async function profileAsync(fn) {
20
+ const start = performance.now();
21
+ const result = await fn();
22
+ return { result, durationMs: Math.round(performance.now() - start) };
23
+ }
24
+ /**
25
+ * Build a profiling report from timing data collected during evaluation.
26
+ */
27
+ export function buildProfilingReport(timings) {
28
+ if (timings.length === 0) {
29
+ return { totalMs: 0, judges: [], slowest: "N/A", fastest: "N/A", avgMs: 0 };
30
+ }
31
+ const sorted = [...timings].sort((a, b) => b.durationMs - a.durationMs);
32
+ const totalMs = sorted.reduce((sum, t) => sum + t.durationMs, 0);
33
+ return {
34
+ totalMs,
35
+ judges: sorted,
36
+ slowest: sorted[0].judgeId,
37
+ fastest: sorted[sorted.length - 1].judgeId,
38
+ avgMs: Math.round(totalMs / sorted.length),
39
+ };
40
+ }
41
+ // ─── CLI ────────────────────────────────────────────────────────────────────
42
+ export function runProfile(argv) {
43
+ if (argv.includes("--help") || argv.includes("-h")) {
44
+ console.log(`
45
+ judges profile — Performance profiling for judge evaluations
46
+
47
+ Usage:
48
+ judges profile <file> Profile evaluation of a file
49
+ judges profile --report <path> Display a saved profiling report
50
+
51
+ Options:
52
+ --format json JSON output
53
+ --threshold <ms> Highlight judges slower than threshold (default: 500)
54
+ --help, -h Show this help
55
+
56
+ Note: This command wraps the normal evaluation pipeline with timing
57
+ instrumentation. Each judge's execution time is measured individually.
58
+ `);
59
+ return;
60
+ }
61
+ const { readFileSync, existsSync } = require("fs");
62
+ const reportPath = argv.find((_a, i) => argv[i - 1] === "--report");
63
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
64
+ const thresholdStr = argv.find((_a, i) => argv[i - 1] === "--threshold");
65
+ const threshold = thresholdStr ? parseInt(thresholdStr, 10) : 500;
66
+ if (reportPath && existsSync(reportPath)) {
67
+ const report = JSON.parse(readFileSync(reportPath, "utf-8"));
68
+ printReport(report, format, threshold);
69
+ return;
70
+ }
71
+ // Without a saved report, show instructions
72
+ console.log(`
73
+ Profiling requires running an evaluation first.
74
+
75
+ Run with JUDGES_PROFILE=1 to enable profiling during eval:
76
+
77
+ JUDGES_PROFILE=1 judges eval --file src/app.ts --format json > results.json
78
+
79
+ Then view the profiling data:
80
+
81
+ judges profile --report .judges-profile.json
82
+
83
+ The profiling data is saved to .judges-profile.json automatically
84
+ when JUDGES_PROFILE=1 is set.
85
+ `);
86
+ }
87
+ function printReport(report, format, threshold) {
88
+ if (format === "json") {
89
+ console.log(JSON.stringify(report, null, 2));
90
+ return;
91
+ }
92
+ console.log(`\n ⏱️ Judges Evaluation Profile\n`);
93
+ console.log(` Total: ${report.totalMs}ms | Avg: ${report.avgMs}ms | Judges: ${report.judges.length}\n`);
94
+ const maxLen = Math.max(...report.judges.map((j) => j.judgeId.length));
95
+ for (const j of report.judges) {
96
+ const bar = "█".repeat(Math.max(1, Math.round((j.durationMs / report.totalMs) * 40)));
97
+ const warn = j.durationMs > threshold ? " ⚠️ SLOW" : "";
98
+ console.log(` ${j.judgeId.padEnd(maxLen)} ${String(j.durationMs).padStart(6)}ms ${bar} (${j.findingCount} findings)${warn}`);
99
+ }
100
+ console.log(`\n Slowest: ${report.slowest} | Fastest: ${report.fastest}\n`);
101
+ }
102
+ //# sourceMappingURL=profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.js","sourceRoot":"","sources":["../../src/commands/profile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Regression alerting — compare current scan results against a saved
3
+ * baseline snapshot to detect quality regressions.
4
+ *
5
+ * Snapshots are stored locally in .judges-baseline.json.
6
+ */
7
+ import type { Finding } from "../types.js";
8
+ export interface BaselineSnapshot {
9
+ timestamp: string;
10
+ gitCommit?: string;
11
+ gitBranch?: string;
12
+ totalFindings: number;
13
+ bySeverity: Record<string, number>;
14
+ byRule: Record<string, number>;
15
+ findingIds: string[];
16
+ }
17
+ export interface RegressionReport {
18
+ status: "improved" | "stable" | "regressed";
19
+ newFindings: string[];
20
+ fixedFindings: string[];
21
+ delta: number;
22
+ severityDelta: Record<string, number>;
23
+ ruleDelta: Record<string, number>;
24
+ baseline: BaselineSnapshot;
25
+ current: BaselineSnapshot;
26
+ }
27
+ export declare function buildSnapshot(findings: Finding[]): BaselineSnapshot;
28
+ export declare function saveBaseline(snapshot: BaselineSnapshot, file?: string): void;
29
+ export declare function loadBaseline(file?: string): BaselineSnapshot | null;
30
+ export declare function compareSnapshots(baseline: BaselineSnapshot, current: BaselineSnapshot): RegressionReport;
31
+ export declare function runRegressionAlert(argv: string[]): Promise<void>;
32
+ //# sourceMappingURL=regression-alert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regression-alert.d.ts","sourceRoot":"","sources":["../../src/commands/regression-alert.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC5C,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,EAAE,gBAAgB,CAAC;CAC3B;AAqBD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAqBnE;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,gBAAgB,EAAE,IAAI,SAAgB,GAAG,IAAI,CAEnF;AAED,wBAAgB,YAAY,CAAC,IAAI,SAAgB,GAAG,gBAAgB,GAAG,IAAI,CAG1E;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,gBAAgB,GAAG,gBAAgB,CAmCxG;AAID,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6ItE"}
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Regression alerting — compare current scan results against a saved
3
+ * baseline snapshot to detect quality regressions.
4
+ *
5
+ * Snapshots are stored locally in .judges-baseline.json.
6
+ */
7
+ import { readFileSync, writeFileSync, existsSync } from "fs";
8
+ const BASELINE_FILE = ".judges-baseline.json";
9
+ // ─── Helpers ────────────────────────────────────────────────────────────────
10
+ function makeFindingId(f) {
11
+ return `${f.ruleId}::${f.title}`;
12
+ }
13
+ function getGitInfo() {
14
+ try {
15
+ const { execSync } = require("child_process");
16
+ const commit = execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim();
17
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf-8" }).trim();
18
+ return { commit, branch };
19
+ }
20
+ catch {
21
+ return {};
22
+ }
23
+ }
24
+ export function buildSnapshot(findings) {
25
+ const git = getGitInfo();
26
+ const bySeverity = {};
27
+ const byRule = {};
28
+ const findingIds = [];
29
+ for (const f of findings) {
30
+ bySeverity[f.severity] = (bySeverity[f.severity] || 0) + 1;
31
+ byRule[f.ruleId] = (byRule[f.ruleId] || 0) + 1;
32
+ findingIds.push(makeFindingId(f));
33
+ }
34
+ return {
35
+ timestamp: new Date().toISOString(),
36
+ gitCommit: git.commit,
37
+ gitBranch: git.branch,
38
+ totalFindings: findings.length,
39
+ bySeverity,
40
+ byRule,
41
+ findingIds,
42
+ };
43
+ }
44
+ export function saveBaseline(snapshot, file = BASELINE_FILE) {
45
+ writeFileSync(file, JSON.stringify(snapshot, null, 2));
46
+ }
47
+ export function loadBaseline(file = BASELINE_FILE) {
48
+ if (!existsSync(file))
49
+ return null;
50
+ return JSON.parse(readFileSync(file, "utf-8"));
51
+ }
52
+ export function compareSnapshots(baseline, current) {
53
+ const baseSet = new Set(baseline.findingIds);
54
+ const currSet = new Set(current.findingIds);
55
+ const newFindings = current.findingIds.filter((id) => !baseSet.has(id));
56
+ const fixedFindings = baseline.findingIds.filter((id) => !currSet.has(id));
57
+ const delta = current.totalFindings - baseline.totalFindings;
58
+ const severityDelta = {};
59
+ const allSeverities = new Set([...Object.keys(baseline.bySeverity), ...Object.keys(current.bySeverity)]);
60
+ for (const sev of allSeverities) {
61
+ severityDelta[sev] = (current.bySeverity[sev] || 0) - (baseline.bySeverity[sev] || 0);
62
+ }
63
+ const ruleDelta = {};
64
+ const allRules = new Set([...Object.keys(baseline.byRule), ...Object.keys(current.byRule)]);
65
+ for (const rule of allRules) {
66
+ const d = (current.byRule[rule] || 0) - (baseline.byRule[rule] || 0);
67
+ if (d !== 0)
68
+ ruleDelta[rule] = d;
69
+ }
70
+ let status = "stable";
71
+ if (delta > 0 || newFindings.length > 0)
72
+ status = "regressed";
73
+ else if (delta < 0 || fixedFindings.length > 0)
74
+ status = "improved";
75
+ return {
76
+ status,
77
+ newFindings,
78
+ fixedFindings,
79
+ delta,
80
+ severityDelta,
81
+ ruleDelta,
82
+ baseline,
83
+ current,
84
+ };
85
+ }
86
+ // ─── CLI ────────────────────────────────────────────────────────────────────
87
+ export async function runRegressionAlert(argv) {
88
+ if (argv.includes("--help") || argv.includes("-h")) {
89
+ console.log(`
90
+ judges regression-alert — Detect quality regressions between scans
91
+
92
+ Usage:
93
+ judges regression-alert --save --input results.json Save current results as baseline
94
+ judges regression-alert --check --input results.json Compare current results against baseline
95
+ judges regression-alert --show Show current baseline
96
+
97
+ Options:
98
+ --save Save current results as the baseline
99
+ --check Compare against saved baseline
100
+ --show Display stored baseline info
101
+ --input <path> Results JSON file
102
+ --fail-on-regression Exit with code 1 if regressions detected (CI mode)
103
+ --threshold <n> Only alert if >= n new findings (default: 1)
104
+ --format json JSON output
105
+ --help, -h Show this help
106
+ `);
107
+ return;
108
+ }
109
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
110
+ const inputPath = argv.find((_a, i) => argv[i - 1] === "--input");
111
+ const failOnRegression = argv.includes("--fail-on-regression");
112
+ const thresholdStr = argv.find((_a, i) => argv[i - 1] === "--threshold");
113
+ const threshold = thresholdStr ? parseInt(thresholdStr, 10) : 1;
114
+ // Show baseline
115
+ if (argv.includes("--show")) {
116
+ const baseline = loadBaseline();
117
+ if (!baseline) {
118
+ console.log("\n No baseline saved. Run with --save first.\n");
119
+ return;
120
+ }
121
+ if (format === "json") {
122
+ console.log(JSON.stringify(baseline, null, 2));
123
+ }
124
+ else {
125
+ console.log(`
126
+ Baseline Snapshot
127
+ ─────────────────
128
+ Saved: ${baseline.timestamp}
129
+ Commit: ${baseline.gitCommit || "unknown"}
130
+ Branch: ${baseline.gitBranch || "unknown"}
131
+ Findings: ${baseline.totalFindings}
132
+ `);
133
+ for (const [sev, count] of Object.entries(baseline.bySeverity)) {
134
+ console.log(` ${sev.padEnd(10)} ${count}`);
135
+ }
136
+ console.log("");
137
+ }
138
+ return;
139
+ }
140
+ // Both --save and --check need input
141
+ if (!inputPath) {
142
+ console.error("Error: --input <path> required");
143
+ process.exit(1);
144
+ }
145
+ if (!existsSync(inputPath)) {
146
+ console.error(`Error: file not found: ${inputPath}`);
147
+ process.exit(1);
148
+ }
149
+ const data = JSON.parse(readFileSync(inputPath, "utf-8"));
150
+ const findings = data.evaluations
151
+ ? data.evaluations.flatMap((e) => e.findings || [])
152
+ : data.findings || data;
153
+ const snapshot = buildSnapshot(findings);
154
+ // Save baseline
155
+ if (argv.includes("--save")) {
156
+ saveBaseline(snapshot);
157
+ if (format === "json") {
158
+ console.log(JSON.stringify(snapshot, null, 2));
159
+ }
160
+ else {
161
+ console.log(`\n Baseline saved: ${snapshot.totalFindings} findings (${snapshot.gitCommit || "no git"})\n`);
162
+ }
163
+ return;
164
+ }
165
+ // Check against baseline
166
+ if (argv.includes("--check")) {
167
+ const baseline = loadBaseline();
168
+ if (!baseline) {
169
+ console.error("Error: No baseline saved. Run with --save first.");
170
+ process.exit(1);
171
+ }
172
+ const report = compareSnapshots(baseline, snapshot);
173
+ if (format === "json") {
174
+ console.log(JSON.stringify(report, null, 2));
175
+ }
176
+ else {
177
+ const icon = report.status === "improved" ? "✅" : report.status === "regressed" ? "🚨" : "➖";
178
+ console.log(`\n ${icon} Status: ${report.status.toUpperCase()} (delta: ${report.delta >= 0 ? "+" : ""}${report.delta})`);
179
+ console.log(` Baseline: ${baseline.totalFindings} findings (${baseline.gitCommit || "?"})`);
180
+ console.log(` Current: ${snapshot.totalFindings} findings (${snapshot.gitCommit || "?"})\n`);
181
+ if (report.newFindings.length > 0) {
182
+ console.log(` New findings (${report.newFindings.length}):`);
183
+ for (const id of report.newFindings.slice(0, 20)) {
184
+ console.log(` + ${id}`);
185
+ }
186
+ if (report.newFindings.length > 20) {
187
+ console.log(` ... and ${report.newFindings.length - 20} more`);
188
+ }
189
+ }
190
+ if (report.fixedFindings.length > 0) {
191
+ console.log(`\n Fixed findings (${report.fixedFindings.length}):`);
192
+ for (const id of report.fixedFindings.slice(0, 20)) {
193
+ console.log(` - ${id}`);
194
+ }
195
+ if (report.fixedFindings.length > 20) {
196
+ console.log(` ... and ${report.fixedFindings.length - 20} more`);
197
+ }
198
+ }
199
+ if (Object.keys(report.severityDelta).length > 0) {
200
+ console.log("\n By severity:");
201
+ for (const [sev, d] of Object.entries(report.severityDelta)) {
202
+ if (d !== 0)
203
+ console.log(` ${sev.padEnd(10)} ${d >= 0 ? "+" : ""}${d}`);
204
+ }
205
+ }
206
+ console.log("");
207
+ }
208
+ if (failOnRegression && report.newFindings.length >= threshold) {
209
+ console.error(` ❌ Regression detected: ${report.newFindings.length} new finding(s) (threshold: ${threshold})`);
210
+ process.exit(1);
211
+ }
212
+ return;
213
+ }
214
+ console.log("Use --save, --check, or --show. See --help for details.");
215
+ }
216
+ //# sourceMappingURL=regression-alert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regression-alert.js","sourceRoot":"","sources":["../../src/commands/regression-alert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Remediation guides — provide step-by-step fix guidance for common
3
+ * finding categories, linked from finding output.
4
+ *
5
+ * Each guide includes: description, risk level, fix steps,
6
+ * code examples (before/after), and references.
7
+ */
8
+ export interface RemediationGuide {
9
+ rulePrefix: string;
10
+ title: string;
11
+ category: string;
12
+ risk: string;
13
+ steps: string[];
14
+ beforeCode?: string;
15
+ afterCode?: string;
16
+ references: string[];
17
+ }
18
+ export declare function findGuide(ruleId: string): RemediationGuide | undefined;
19
+ export declare function listGuides(): RemediationGuide[];
20
+ export declare function runRemediationGuide(argv: string[]): void;
21
+ //# sourceMappingURL=remediation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remediation.d.ts","sourceRoot":"","sources":["../../src/commands/remediation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AA6KD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAGtE;AAED,wBAAgB,UAAU,IAAI,gBAAgB,EAAE,CAE/C;AAID,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAmFxD"}