@kevinrabun/judges 3.43.0 → 3.45.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 (70) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +112 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/burndown.d.ts +27 -0
  6. package/dist/commands/burndown.d.ts.map +1 -0
  7. package/dist/commands/burndown.js +180 -0
  8. package/dist/commands/burndown.js.map +1 -0
  9. package/dist/commands/compare-runs.d.ts +38 -0
  10. package/dist/commands/compare-runs.d.ts.map +1 -0
  11. package/dist/commands/compare-runs.js +229 -0
  12. package/dist/commands/compare-runs.js.map +1 -0
  13. package/dist/commands/correlate.d.ts +28 -0
  14. package/dist/commands/correlate.d.ts.map +1 -0
  15. package/dist/commands/correlate.js +242 -0
  16. package/dist/commands/correlate.js.map +1 -0
  17. package/dist/commands/digest.d.ts +20 -0
  18. package/dist/commands/digest.d.ts.map +1 -0
  19. package/dist/commands/digest.js +222 -0
  20. package/dist/commands/digest.js.map +1 -0
  21. package/dist/commands/explain-finding.d.ts +8 -0
  22. package/dist/commands/explain-finding.d.ts.map +1 -0
  23. package/dist/commands/explain-finding.js +279 -0
  24. package/dist/commands/explain-finding.js.map +1 -0
  25. package/dist/commands/judge-reputation.d.ts +29 -0
  26. package/dist/commands/judge-reputation.d.ts.map +1 -0
  27. package/dist/commands/judge-reputation.js +199 -0
  28. package/dist/commands/judge-reputation.js.map +1 -0
  29. package/dist/commands/kb.d.ts +41 -0
  30. package/dist/commands/kb.d.ts.map +1 -0
  31. package/dist/commands/kb.js +231 -0
  32. package/dist/commands/kb.js.map +1 -0
  33. package/dist/commands/noise-advisor.d.ts +30 -0
  34. package/dist/commands/noise-advisor.d.ts.map +1 -0
  35. package/dist/commands/noise-advisor.js +171 -0
  36. package/dist/commands/noise-advisor.js.map +1 -0
  37. package/dist/commands/query.d.ts +20 -0
  38. package/dist/commands/query.d.ts.map +1 -0
  39. package/dist/commands/query.js +230 -0
  40. package/dist/commands/query.js.map +1 -0
  41. package/dist/commands/recommend.d.ts +21 -0
  42. package/dist/commands/recommend.d.ts.map +1 -0
  43. package/dist/commands/recommend.js +283 -0
  44. package/dist/commands/recommend.js.map +1 -0
  45. package/dist/commands/report-template.d.ts +17 -0
  46. package/dist/commands/report-template.d.ts.map +1 -0
  47. package/dist/commands/report-template.js +291 -0
  48. package/dist/commands/report-template.js.map +1 -0
  49. package/dist/commands/review-queue.d.ts +34 -0
  50. package/dist/commands/review-queue.d.ts.map +1 -0
  51. package/dist/commands/review-queue.js +226 -0
  52. package/dist/commands/review-queue.js.map +1 -0
  53. package/dist/commands/rule-owner.d.ts +31 -0
  54. package/dist/commands/rule-owner.d.ts.map +1 -0
  55. package/dist/commands/rule-owner.js +182 -0
  56. package/dist/commands/rule-owner.js.map +1 -0
  57. package/dist/commands/rule-share.d.ts +35 -0
  58. package/dist/commands/rule-share.d.ts.map +1 -0
  59. package/dist/commands/rule-share.js +203 -0
  60. package/dist/commands/rule-share.js.map +1 -0
  61. package/dist/commands/suppress.d.ts +40 -0
  62. package/dist/commands/suppress.d.ts.map +1 -0
  63. package/dist/commands/suppress.js +209 -0
  64. package/dist/commands/suppress.js.map +1 -0
  65. package/dist/commands/vote.d.ts +32 -0
  66. package/dist/commands/vote.d.ts.map +1 -0
  67. package/dist/commands/vote.js +201 -0
  68. package/dist/commands/vote.js.map +1 -0
  69. package/package.json +1 -1
  70. package/server.json +2 -2
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Burndown — track finding resolution progress over time and
3
+ * visualize whether the team is on track to meet targets.
4
+ *
5
+ * Data stored locally in .judges-burndown.json.
6
+ */
7
+ import { readFileSync, writeFileSync, existsSync } from "fs";
8
+ const BURNDOWN_FILE = ".judges-burndown.json";
9
+ // ─── Core ───────────────────────────────────────────────────────────────────
10
+ function loadDb(file = BURNDOWN_FILE) {
11
+ if (!existsSync(file))
12
+ return { entries: [] };
13
+ return JSON.parse(readFileSync(file, "utf-8"));
14
+ }
15
+ function saveDb(db, file = BURNDOWN_FILE) {
16
+ writeFileSync(file, JSON.stringify(db, null, 2));
17
+ }
18
+ function getGitCommit() {
19
+ try {
20
+ const { execSync } = require("child_process");
21
+ return execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim();
22
+ }
23
+ catch {
24
+ return undefined;
25
+ }
26
+ }
27
+ export function recordSnapshot(findings) {
28
+ const db = loadDb();
29
+ const now = new Date();
30
+ const bySeverity = {};
31
+ for (const f of findings) {
32
+ bySeverity[f.severity] = (bySeverity[f.severity] || 0) + 1;
33
+ }
34
+ const entry = {
35
+ timestamp: now.toISOString(),
36
+ date: now.toISOString().split("T")[0],
37
+ totalFindings: findings.length,
38
+ bySeverity,
39
+ gitCommit: getGitCommit(),
40
+ };
41
+ db.entries.push(entry);
42
+ // Keep last 365 entries max
43
+ if (db.entries.length > 365) {
44
+ db.entries = db.entries.slice(-365);
45
+ }
46
+ saveDb(db);
47
+ return entry;
48
+ }
49
+ export function setTarget(count, deadline) {
50
+ const db = loadDb();
51
+ db.target = { count, deadline };
52
+ saveDb(db);
53
+ }
54
+ export function getBurndownData() {
55
+ return loadDb();
56
+ }
57
+ function renderChart(db) {
58
+ if (db.entries.length === 0)
59
+ return " No data points. Run evaluations to populate.";
60
+ const lines = [];
61
+ const maxFindings = Math.max(...db.entries.map((e) => e.totalFindings), 1);
62
+ const chartWidth = 50;
63
+ const recent = db.entries.slice(-20); // Last 20 entries
64
+ for (const entry of recent) {
65
+ const barLen = Math.round((entry.totalFindings / maxFindings) * chartWidth);
66
+ const bar = "█".repeat(barLen) + "░".repeat(chartWidth - barLen);
67
+ lines.push(` ${entry.date} ${bar} ${entry.totalFindings}`);
68
+ }
69
+ return lines.join("\n");
70
+ }
71
+ function calculateTrajectory(db) {
72
+ if (db.entries.length < 2)
73
+ return " Need at least 2 data points for trajectory.";
74
+ const first = db.entries[0];
75
+ const last = db.entries[db.entries.length - 1];
76
+ const daysBetween = (new Date(last.timestamp).getTime() - new Date(first.timestamp).getTime()) / 86_400_000;
77
+ const delta = last.totalFindings - first.totalFindings;
78
+ const ratePerDay = daysBetween > 0 ? Math.round((delta / daysBetween) * 10) / 10 : 0;
79
+ const parts = [
80
+ ` Start: ${first.totalFindings} findings (${first.date})`,
81
+ ` Now: ${last.totalFindings} findings (${last.date})`,
82
+ ` Rate: ${ratePerDay >= 0 ? "+" : ""}${ratePerDay}/day`,
83
+ ];
84
+ if (db.target) {
85
+ const remaining = last.totalFindings - db.target.count;
86
+ if (remaining <= 0) {
87
+ parts.push(` Target: ${db.target.count} by ${db.target.deadline} — ✅ ACHIEVED`);
88
+ }
89
+ else if (ratePerDay >= 0) {
90
+ parts.push(` Target: ${db.target.count} by ${db.target.deadline} — ⚠️ Findings increasing`);
91
+ }
92
+ else {
93
+ const daysNeeded = Math.abs(Math.ceil(remaining / ratePerDay));
94
+ const eta = new Date();
95
+ eta.setDate(eta.getDate() + daysNeeded);
96
+ const onTrack = eta.getTime() <= new Date(db.target.deadline).getTime();
97
+ parts.push(` Target: ${db.target.count} by ${db.target.deadline} — ${onTrack ? "✅ On track" : "⚠️ Behind schedule"}`, ` ETA: ${eta.toISOString().split("T")[0]} (${daysNeeded} days at current rate)`);
98
+ }
99
+ }
100
+ return parts.join("\n");
101
+ }
102
+ // ─── CLI ────────────────────────────────────────────────────────────────────
103
+ export async function runBurndown(argv) {
104
+ if (argv.includes("--help") || argv.includes("-h")) {
105
+ console.log(`
106
+ judges burndown — Track finding resolution progress
107
+
108
+ Usage:
109
+ judges burndown --record --input results.json Record a data point
110
+ judges burndown --show Show burndown chart
111
+ judges burndown --set-target 50 --deadline 2025-06-01
112
+ judges burndown --trajectory Show trajectory analysis
113
+
114
+ Options:
115
+ --record Record current findings as data point
116
+ --input <path> Results JSON file
117
+ --show Display burndown chart
118
+ --set-target <n> Set target finding count
119
+ --deadline <date> Target deadline (YYYY-MM-DD)
120
+ --trajectory Show rate and ETA analysis
121
+ --format json JSON output
122
+ --help, -h Show this help
123
+ `);
124
+ return;
125
+ }
126
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
127
+ // Record snapshot
128
+ const inputPath = argv.find((_a, i) => argv[i - 1] === "--input");
129
+ if (argv.includes("--record") && inputPath) {
130
+ if (!existsSync(inputPath)) {
131
+ console.error(`Error: file not found: ${inputPath}`);
132
+ process.exit(1);
133
+ }
134
+ const data = JSON.parse(readFileSync(inputPath, "utf-8"));
135
+ const findings = data.evaluations
136
+ ? data.evaluations.flatMap((e) => e.findings || [])
137
+ : data.findings || data;
138
+ const entry = recordSnapshot(findings);
139
+ if (format === "json") {
140
+ console.log(JSON.stringify(entry, null, 2));
141
+ }
142
+ else {
143
+ console.log(` Recorded: ${entry.totalFindings} findings on ${entry.date}`);
144
+ }
145
+ return;
146
+ }
147
+ // Set target
148
+ const targetStr = argv.find((_a, i) => argv[i - 1] === "--set-target");
149
+ const deadline = argv.find((_a, i) => argv[i - 1] === "--deadline");
150
+ if (targetStr && deadline) {
151
+ setTarget(parseInt(targetStr, 10), deadline);
152
+ console.log(` Target set: ${targetStr} findings by ${deadline}`);
153
+ return;
154
+ }
155
+ const db = getBurndownData();
156
+ // Trajectory
157
+ if (argv.includes("--trajectory")) {
158
+ if (format === "json") {
159
+ console.log(JSON.stringify(db, null, 2));
160
+ }
161
+ else {
162
+ console.log("\n Trajectory Analysis\n ───────────────────");
163
+ console.log(calculateTrajectory(db));
164
+ console.log("");
165
+ }
166
+ return;
167
+ }
168
+ // Show chart (default)
169
+ if (format === "json") {
170
+ console.log(JSON.stringify(db, null, 2));
171
+ }
172
+ else {
173
+ console.log("\n Finding Burndown\n ────────────────");
174
+ console.log(renderChart(db));
175
+ console.log("");
176
+ console.log(calculateTrajectory(db));
177
+ console.log("");
178
+ }
179
+ }
180
+ //# sourceMappingURL=burndown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"burndown.js","sourceRoot":"","sources":["../../src/commands/burndown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Compare evaluation runs — side-by-side comparison of two evaluation
3
+ * snapshots to show what changed.
4
+ *
5
+ * Uses local .judges-runs/ directory.
6
+ */
7
+ import type { Finding } from "../types.js";
8
+ interface RunSnapshot {
9
+ id: string;
10
+ label?: string;
11
+ timestamp: string;
12
+ findings: Finding[];
13
+ summary: {
14
+ total: number;
15
+ critical: number;
16
+ high: number;
17
+ medium: number;
18
+ low: number;
19
+ };
20
+ }
21
+ interface RunComparison {
22
+ runA: string;
23
+ runB: string;
24
+ added: Finding[];
25
+ removed: Finding[];
26
+ unchanged: number;
27
+ severityDelta: Record<string, number>;
28
+ ruleChanges: Record<string, {
29
+ added: number;
30
+ removed: number;
31
+ }>;
32
+ }
33
+ export declare function saveRun(findings: Finding[], label?: string): RunSnapshot;
34
+ export declare function listRuns(): RunSnapshot[];
35
+ export declare function compareRuns(runAId: string, runBId: string): RunComparison;
36
+ export declare function runCompareRuns(argv: string[]): void;
37
+ export {};
38
+ //# sourceMappingURL=compare-runs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare-runs.d.ts","sourceRoot":"","sources":["../../src/commands/compare-runs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;CACH;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjE;AAcD,wBAAgB,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,CAkBxE;AAED,wBAAgB,QAAQ,IAAI,WAAW,EAAE,CAMxC;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CA6CzE;AAID,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA6GnD"}
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Compare evaluation runs — side-by-side comparison of two evaluation
3
+ * snapshots to show what changed.
4
+ *
5
+ * Uses local .judges-runs/ directory.
6
+ */
7
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from "fs";
8
+ import { join } from "path";
9
+ const RUNS_DIR = ".judges-runs";
10
+ // ─── Core ───────────────────────────────────────────────────────────────────
11
+ function ensureDir() {
12
+ if (!existsSync(RUNS_DIR))
13
+ mkdirSync(RUNS_DIR, { recursive: true });
14
+ }
15
+ function findingKey(f) {
16
+ return `${f.ruleId}:${f.title}:${(f.lineNumbers || []).join(",")}`;
17
+ }
18
+ export function saveRun(findings, label) {
19
+ ensureDir();
20
+ const id = `run-${Date.now()}`;
21
+ const snapshot = {
22
+ id,
23
+ label,
24
+ timestamp: new Date().toISOString(),
25
+ findings,
26
+ summary: {
27
+ total: findings.length,
28
+ critical: findings.filter((f) => f.severity === "critical").length,
29
+ high: findings.filter((f) => f.severity === "high").length,
30
+ medium: findings.filter((f) => f.severity === "medium").length,
31
+ low: findings.filter((f) => f.severity === "low").length,
32
+ },
33
+ };
34
+ writeFileSync(join(RUNS_DIR, `${id}.json`), JSON.stringify(snapshot, null, 2));
35
+ return snapshot;
36
+ }
37
+ export function listRuns() {
38
+ ensureDir();
39
+ const files = readdirSync(RUNS_DIR)
40
+ .filter((f) => f.endsWith(".json"))
41
+ .sort();
42
+ return files.map((f) => JSON.parse(readFileSync(join(RUNS_DIR, f), "utf-8")));
43
+ }
44
+ export function compareRuns(runAId, runBId) {
45
+ const runA = JSON.parse(readFileSync(join(RUNS_DIR, `${runAId}.json`), "utf-8"));
46
+ const runB = JSON.parse(readFileSync(join(RUNS_DIR, `${runBId}.json`), "utf-8"));
47
+ const keysA = new Set(runA.findings.map(findingKey));
48
+ const keysB = new Set(runB.findings.map(findingKey));
49
+ const findingsMapA = new Map(runA.findings.map((f) => [findingKey(f), f]));
50
+ const findingsMapB = new Map(runB.findings.map((f) => [findingKey(f), f]));
51
+ const added = [];
52
+ const removed = [];
53
+ let unchanged = 0;
54
+ for (const key of keysB) {
55
+ if (!keysA.has(key)) {
56
+ added.push(findingsMapB.get(key));
57
+ }
58
+ else {
59
+ unchanged++;
60
+ }
61
+ }
62
+ for (const key of keysA) {
63
+ if (!keysB.has(key)) {
64
+ removed.push(findingsMapA.get(key));
65
+ }
66
+ }
67
+ const severityDelta = {
68
+ critical: runB.summary.critical - runA.summary.critical,
69
+ high: runB.summary.high - runA.summary.high,
70
+ medium: runB.summary.medium - runA.summary.medium,
71
+ low: runB.summary.low - runA.summary.low,
72
+ };
73
+ // Rule-level changes
74
+ const ruleChanges = {};
75
+ for (const f of added) {
76
+ if (!ruleChanges[f.ruleId])
77
+ ruleChanges[f.ruleId] = { added: 0, removed: 0 };
78
+ ruleChanges[f.ruleId].added++;
79
+ }
80
+ for (const f of removed) {
81
+ if (!ruleChanges[f.ruleId])
82
+ ruleChanges[f.ruleId] = { added: 0, removed: 0 };
83
+ ruleChanges[f.ruleId].removed++;
84
+ }
85
+ return { runA: runAId, runB: runBId, added, removed, unchanged, severityDelta, ruleChanges };
86
+ }
87
+ // ─── CLI ────────────────────────────────────────────────────────────────────
88
+ export function runCompareRuns(argv) {
89
+ if (argv.includes("--help") || argv.includes("-h")) {
90
+ console.log(`
91
+ judges compare-runs — Compare evaluation runs side by side
92
+
93
+ Usage:
94
+ judges compare-runs --save Save current results as a run
95
+ judges compare-runs --save --label "baseline" Save with label
96
+ judges compare-runs --list List saved runs
97
+ judges compare-runs --compare <runA> <runB> Compare two runs
98
+ judges compare-runs --latest Compare last two runs
99
+
100
+ Options:
101
+ --save Save .judges-results.json as a run snapshot
102
+ --label <text> Label for the snapshot
103
+ --list List all saved runs
104
+ --compare <A> <B> Compare two run IDs
105
+ --latest Compare the two most recent runs
106
+ --format json JSON output
107
+ --help, -h Show this help
108
+ `);
109
+ return;
110
+ }
111
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
112
+ // Save run
113
+ if (argv.includes("--save")) {
114
+ const resultsFile = ".judges-results.json";
115
+ if (!existsSync(resultsFile)) {
116
+ console.error(" ❌ No .judges-results.json found. Run an evaluation first.");
117
+ return;
118
+ }
119
+ const data = JSON.parse(readFileSync(resultsFile, "utf-8"));
120
+ const findings = Array.isArray(data) ? data : data.findings || [];
121
+ const label = argv.find((_a, i) => argv[i - 1] === "--label");
122
+ const run = saveRun(findings, label);
123
+ if (format === "json") {
124
+ console.log(JSON.stringify(run, null, 2));
125
+ }
126
+ else {
127
+ console.log(` ✅ Run saved: ${run.id}${label ? ` (${label})` : ""} — ${run.summary.total} findings`);
128
+ }
129
+ return;
130
+ }
131
+ // List runs
132
+ if (argv.includes("--list")) {
133
+ const runs = listRuns();
134
+ if (runs.length === 0) {
135
+ console.log("\n No runs saved. Use --save to capture a snapshot.\n");
136
+ return;
137
+ }
138
+ if (format === "json") {
139
+ console.log(JSON.stringify(runs.map((r) => ({ id: r.id, label: r.label, timestamp: r.timestamp, total: r.summary.total })), null, 2));
140
+ }
141
+ else {
142
+ console.log(`\n Saved Runs (${runs.length})\n ──────────────`);
143
+ for (const r of runs) {
144
+ const lbl = r.label ? ` (${r.label})` : "";
145
+ console.log(` ${r.id}${lbl} ${r.timestamp.split("T")[0]} ${r.summary.total} findings`);
146
+ }
147
+ console.log("");
148
+ }
149
+ return;
150
+ }
151
+ // Compare latest
152
+ if (argv.includes("--latest")) {
153
+ const runs = listRuns();
154
+ if (runs.length < 2) {
155
+ console.error(" ❌ Need at least 2 saved runs. Use --save to capture more.");
156
+ return;
157
+ }
158
+ const comparison = compareRuns(runs[runs.length - 2].id, runs[runs.length - 1].id);
159
+ printComparison(comparison, format);
160
+ return;
161
+ }
162
+ // Compare specific runs
163
+ const compareIdx = argv.indexOf("--compare");
164
+ if (compareIdx >= 0 && argv[compareIdx + 1] && argv[compareIdx + 2]) {
165
+ const runAId = argv[compareIdx + 1];
166
+ const runBId = argv[compareIdx + 2];
167
+ try {
168
+ const comparison = compareRuns(runAId, runBId);
169
+ printComparison(comparison, format);
170
+ }
171
+ catch {
172
+ console.error(` ❌ Could not load runs. Check IDs with --list.`);
173
+ }
174
+ return;
175
+ }
176
+ // Default: show latest
177
+ const runs = listRuns();
178
+ if (runs.length === 0) {
179
+ console.log("\n No runs saved. Use --save to start tracking.\n");
180
+ }
181
+ else {
182
+ const latest = runs[runs.length - 1];
183
+ console.log(`\n Latest Run: ${latest.id}${latest.label ? ` (${latest.label})` : ""}`);
184
+ console.log(` Date: ${latest.timestamp}`);
185
+ console.log(` Findings: ${latest.summary.total} (C:${latest.summary.critical} H:${latest.summary.high} M:${latest.summary.medium} L:${latest.summary.low})\n`);
186
+ }
187
+ }
188
+ function printComparison(comp, format) {
189
+ if (format === "json") {
190
+ console.log(JSON.stringify(comp, null, 2));
191
+ return;
192
+ }
193
+ console.log(`\n Run Comparison: ${comp.runA} → ${comp.runB}`);
194
+ console.log(` ────────────────────────────────────────`);
195
+ console.log(` Unchanged: ${comp.unchanged}`);
196
+ console.log(` Added: ${comp.added.length}`);
197
+ console.log(` Removed: ${comp.removed.length}`);
198
+ console.log("");
199
+ console.log(" Severity Changes:");
200
+ for (const [sev, delta] of Object.entries(comp.severityDelta)) {
201
+ const sign = delta > 0 ? "+" : "";
202
+ const icon = delta > 0 ? "📈" : delta < 0 ? "📉" : "➡️";
203
+ console.log(` ${sev.padEnd(10)} ${sign}${delta} ${icon}`);
204
+ }
205
+ if (comp.added.length > 0) {
206
+ console.log("\n New Findings:");
207
+ for (const f of comp.added.slice(0, 10)) {
208
+ console.log(` + [${f.severity.toUpperCase()}] ${f.ruleId} — ${f.title.slice(0, 50)}`);
209
+ }
210
+ if (comp.added.length > 10)
211
+ console.log(` ... and ${comp.added.length - 10} more`);
212
+ }
213
+ if (comp.removed.length > 0) {
214
+ console.log("\n Resolved Findings:");
215
+ for (const f of comp.removed.slice(0, 10)) {
216
+ console.log(` - [${f.severity.toUpperCase()}] ${f.ruleId} — ${f.title.slice(0, 50)}`);
217
+ }
218
+ if (comp.removed.length > 10)
219
+ console.log(` ... and ${comp.removed.length - 10} more`);
220
+ }
221
+ if (Object.keys(comp.ruleChanges).length > 0) {
222
+ console.log("\n Rule Changes:");
223
+ for (const [rule, changes] of Object.entries(comp.ruleChanges)) {
224
+ console.log(` ${rule.padEnd(15)} +${changes.added} / -${changes.removed}`);
225
+ }
226
+ }
227
+ console.log("");
228
+ }
229
+ //# sourceMappingURL=compare-runs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare-runs.js","sourceRoot":"","sources":["../../src/commands/compare-runs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Finding correlation — link related findings, identify root causes,
3
+ * and detect systemic patterns across evaluations.
4
+ *
5
+ * Stored locally in .judges-correlations.json.
6
+ */
7
+ import type { Finding } from "../types.js";
8
+ interface CorrelationLink {
9
+ findingA: string;
10
+ findingB: string;
11
+ relationship: "same-root-cause" | "related" | "prerequisite" | "duplicate";
12
+ notes?: string;
13
+ createdAt: string;
14
+ }
15
+ interface RootCause {
16
+ id: string;
17
+ title: string;
18
+ description: string;
19
+ relatedFindings: string[];
20
+ severity: "critical" | "high" | "medium" | "low";
21
+ createdAt: string;
22
+ }
23
+ export declare function linkFindings(findingA: string, findingB: string, relationship: CorrelationLink["relationship"], notes?: string): CorrelationLink;
24
+ export declare function addRootCause(title: string, description: string, severity: RootCause["severity"], findingIds: string[]): RootCause;
25
+ export declare function autoCorrelate(findings: Finding[]): CorrelationLink[];
26
+ export declare function runCorrelate(argv: string[]): void;
27
+ export {};
28
+ //# sourceMappingURL=correlate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlate.d.ts","sourceRoot":"","sources":["../../src/commands/correlate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,UAAU,eAAe;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,iBAAiB,GAAG,SAAS,GAAG,cAAc,GAAG,WAAW,CAAC;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,SAAS,EAAE,MAAM,CAAC;CACnB;AAoBD,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,eAAe,CAAC,cAAc,CAAC,EAC7C,KAAK,CAAC,EAAE,MAAM,GACb,eAAe,CAuBjB;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,SAAS,CAAC,UAAU,CAAC,EAC/B,UAAU,EAAE,MAAM,EAAE,GACnB,SAAS,CAaX;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,eAAe,EAAE,CA4CpE;AAID,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA4JjD"}