@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.
- package/CHANGELOG.md +30 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +126 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/assign-findings.d.ts +37 -0
- package/dist/commands/assign-findings.d.ts.map +1 -0
- package/dist/commands/assign-findings.js +178 -0
- package/dist/commands/assign-findings.js.map +1 -0
- package/dist/commands/auto-triage.d.ts +32 -0
- package/dist/commands/auto-triage.d.ts.map +1 -0
- package/dist/commands/auto-triage.js +126 -0
- package/dist/commands/auto-triage.js.map +1 -0
- package/dist/commands/ci-template.d.ts +15 -0
- package/dist/commands/ci-template.d.ts.map +1 -0
- package/dist/commands/ci-template.js +212 -0
- package/dist/commands/ci-template.js.map +1 -0
- package/dist/commands/coverage-map.d.ts +23 -0
- package/dist/commands/coverage-map.d.ts.map +1 -0
- package/dist/commands/coverage-map.js +223 -0
- package/dist/commands/coverage-map.js.map +1 -0
- package/dist/commands/diff-only.d.ts +34 -0
- package/dist/commands/diff-only.d.ts.map +1 -0
- package/dist/commands/diff-only.js +152 -0
- package/dist/commands/diff-only.js.map +1 -0
- package/dist/commands/false-negatives.d.ts +35 -0
- package/dist/commands/false-negatives.d.ts.map +1 -0
- package/dist/commands/false-negatives.js +166 -0
- package/dist/commands/false-negatives.js.map +1 -0
- package/dist/commands/group-findings.d.ts +23 -0
- package/dist/commands/group-findings.d.ts.map +1 -0
- package/dist/commands/group-findings.js +155 -0
- package/dist/commands/group-findings.js.map +1 -0
- package/dist/commands/hook-install.d.ts +22 -0
- package/dist/commands/hook-install.d.ts.map +1 -0
- package/dist/commands/hook-install.js +143 -0
- package/dist/commands/hook-install.js.map +1 -0
- package/dist/commands/policy-audit.d.ts +53 -0
- package/dist/commands/policy-audit.d.ts.map +1 -0
- package/dist/commands/policy-audit.js +161 -0
- package/dist/commands/policy-audit.js.map +1 -0
- package/dist/commands/pr-summary.d.ts +26 -0
- package/dist/commands/pr-summary.d.ts.map +1 -0
- package/dist/commands/pr-summary.js +188 -0
- package/dist/commands/pr-summary.js.map +1 -0
- package/dist/commands/profile.d.ts +38 -0
- package/dist/commands/profile.d.ts.map +1 -0
- package/dist/commands/profile.js +102 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/regression-alert.d.ts +32 -0
- package/dist/commands/regression-alert.d.ts.map +1 -0
- package/dist/commands/regression-alert.js +216 -0
- package/dist/commands/regression-alert.js.map +1 -0
- package/dist/commands/remediation.d.ts +21 -0
- package/dist/commands/remediation.d.ts.map +1 -0
- package/dist/commands/remediation.js +257 -0
- package/dist/commands/remediation.js.map +1 -0
- package/dist/commands/sla-track.d.ts +57 -0
- package/dist/commands/sla-track.d.ts.map +1 -0
- package/dist/commands/sla-track.js +269 -0
- package/dist/commands/sla-track.js.map +1 -0
- package/dist/commands/smart-select.d.ts +27 -0
- package/dist/commands/smart-select.d.ts.map +1 -0
- package/dist/commands/smart-select.js +346 -0
- package/dist/commands/smart-select.js.map +1 -0
- package/dist/commands/ticket-sync.d.ts +26 -0
- package/dist/commands/ticket-sync.d.ts.map +1 -0
- package/dist/commands/ticket-sync.js +236 -0
- package/dist/commands/ticket-sync.js.map +1 -0
- package/dist/commands/upload.d.ts +14 -0
- package/dist/commands/upload.d.ts.map +1 -0
- package/dist/commands/upload.js +173 -0
- package/dist/commands/upload.js.map +1 -0
- package/dist/commands/validate-config.d.ts +17 -0
- package/dist/commands/validate-config.d.ts.map +1 -0
- package/dist/commands/validate-config.js +268 -0
- package/dist/commands/validate-config.js.map +1 -0
- package/dist/commands/warm-cache.d.ts +31 -0
- package/dist/commands/warm-cache.d.ts.map +1 -0
- package/dist/commands/warm-cache.js +166 -0
- package/dist/commands/warm-cache.js.map +1 -0
- package/package.json +1 -1
- 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"}
|