@kevinrabun/judges 3.103.0 → 3.104.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +63 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/finding-cross-file-link.d.ts +2 -0
  6. package/dist/commands/finding-cross-file-link.d.ts.map +1 -0
  7. package/dist/commands/finding-cross-file-link.js +102 -0
  8. package/dist/commands/finding-cross-file-link.js.map +1 -0
  9. package/dist/commands/finding-hotspot-detect.d.ts +2 -0
  10. package/dist/commands/finding-hotspot-detect.d.ts.map +1 -0
  11. package/dist/commands/finding-hotspot-detect.js +121 -0
  12. package/dist/commands/finding-hotspot-detect.js.map +1 -0
  13. package/dist/commands/finding-similar-match.d.ts +2 -0
  14. package/dist/commands/finding-similar-match.d.ts.map +1 -0
  15. package/dist/commands/finding-similar-match.js +113 -0
  16. package/dist/commands/finding-similar-match.js.map +1 -0
  17. package/dist/commands/review-code-health-score.d.ts +2 -0
  18. package/dist/commands/review-code-health-score.d.ts.map +1 -0
  19. package/dist/commands/review-code-health-score.js +101 -0
  20. package/dist/commands/review-code-health-score.js.map +1 -0
  21. package/dist/commands/review-focus-area.d.ts +2 -0
  22. package/dist/commands/review-focus-area.d.ts.map +1 -0
  23. package/dist/commands/review-focus-area.js +97 -0
  24. package/dist/commands/review-focus-area.js.map +1 -0
  25. package/dist/commands/review-pr-size-check.d.ts +2 -0
  26. package/dist/commands/review-pr-size-check.d.ts.map +1 -0
  27. package/dist/commands/review-pr-size-check.js +99 -0
  28. package/dist/commands/review-pr-size-check.js.map +1 -0
  29. package/dist/commands/review-team-analytics.d.ts +2 -0
  30. package/dist/commands/review-team-analytics.d.ts.map +1 -0
  31. package/dist/commands/review-team-analytics.js +95 -0
  32. package/dist/commands/review-team-analytics.js.map +1 -0
  33. package/dist/commands/review-template-suggest.d.ts +2 -0
  34. package/dist/commands/review-template-suggest.d.ts.map +1 -0
  35. package/dist/commands/review-template-suggest.js +120 -0
  36. package/dist/commands/review-template-suggest.js.map +1 -0
  37. package/dist/commands/review-velocity-track.d.ts +2 -0
  38. package/dist/commands/review-velocity-track.d.ts.map +1 -0
  39. package/dist/commands/review-velocity-track.js +95 -0
  40. package/dist/commands/review-velocity-track.js.map +1 -0
  41. package/package.json +1 -1
  42. package/server.json +2 -2
@@ -0,0 +1,99 @@
1
+ import { readFileSync, existsSync } from "fs";
2
+ import { join } from "path";
3
+ function checkPrSize(files) {
4
+ let totalLines = 0;
5
+ const fileGroups = new Map();
6
+ for (const file of files) {
7
+ const parts = file.split("/");
8
+ const dir = parts.length > 1 ? parts.slice(0, -1).join("/") : ".";
9
+ const group = fileGroups.get(dir);
10
+ if (group !== undefined) {
11
+ group.push(file);
12
+ }
13
+ else {
14
+ fileGroups.set(dir, [file]);
15
+ }
16
+ totalLines += 50;
17
+ }
18
+ let category;
19
+ let recommendation;
20
+ if (files.length > 20 || totalLines > 1000) {
21
+ category = "too-large";
22
+ recommendation = "PR is too large for effective review — strongly recommend splitting";
23
+ }
24
+ else if (files.length > 10 || totalLines > 500) {
25
+ category = "large";
26
+ recommendation = "Large PR — consider splitting for better review quality";
27
+ }
28
+ else if (files.length > 5) {
29
+ category = "medium";
30
+ recommendation = "Moderate size — reviewable but could benefit from split";
31
+ }
32
+ else {
33
+ category = "small";
34
+ recommendation = "Good size for thorough review";
35
+ }
36
+ const splitSuggestions = [];
37
+ if (fileGroups.size > 3 && files.length > 10) {
38
+ for (const [dir, dirFiles] of fileGroups) {
39
+ if (dirFiles.length >= 3) {
40
+ splitSuggestions.push(`Split ${dir}/ changes (${dirFiles.length} files) into separate PR`);
41
+ }
42
+ }
43
+ }
44
+ const hasTests = files.some((f) => f.includes("test") || f.includes("spec"));
45
+ const hasSource = files.some((f) => f.endsWith(".ts") || f.endsWith(".js") || f.endsWith(".py") || f.endsWith(".go"));
46
+ if (hasTests && hasSource && files.length > 8) {
47
+ splitSuggestions.push("Consider separating test changes from source changes");
48
+ }
49
+ const hasConfig = files.some((f) => f.endsWith(".json") || f.endsWith(".yml") || f.endsWith(".yaml"));
50
+ if (hasConfig && hasSource && files.length > 8) {
51
+ splitSuggestions.push("Consider separating config changes from source changes");
52
+ }
53
+ return { fileCount: files.length, totalLines, category, recommendation, splitSuggestions };
54
+ }
55
+ export function runReviewPrSizeCheck(argv) {
56
+ if (argv.includes("--help") || argv.includes("-h")) {
57
+ console.log(`Usage: judges review-pr-size-check [options]
58
+
59
+ Check PR size and suggest splitting.
60
+
61
+ Options:
62
+ --files <path> File listing changed files (one per line)
63
+ --format <fmt> Output format: table (default) or json
64
+ -h, --help Show this help message`);
65
+ return;
66
+ }
67
+ const formatIdx = argv.indexOf("--format");
68
+ const format = formatIdx !== -1 && argv[formatIdx + 1] ? argv[formatIdx + 1] : "table";
69
+ const filesIdx = argv.indexOf("--files");
70
+ const filesPath = filesIdx !== -1 && argv[filesIdx + 1] ? join(process.cwd(), argv[filesIdx + 1]) : null;
71
+ let changedFiles = [];
72
+ if (filesPath !== null && existsSync(filesPath)) {
73
+ changedFiles = readFileSync(filesPath, "utf-8")
74
+ .split("\n")
75
+ .map((l) => l.trim())
76
+ .filter((l) => l.length > 0);
77
+ }
78
+ if (changedFiles.length === 0) {
79
+ console.log("No changed files found. Provide --files with a list of changed files.");
80
+ return;
81
+ }
82
+ const result = checkPrSize(changedFiles);
83
+ if (format === "json") {
84
+ console.log(JSON.stringify(result, null, 2));
85
+ return;
86
+ }
87
+ console.log("\n=== PR Size Check ===\n");
88
+ console.log(`Files: ${result.fileCount}`);
89
+ console.log(`Estimated lines: ${result.totalLines}`);
90
+ console.log(`Category: ${result.category.toUpperCase()}`);
91
+ console.log(`\n${result.recommendation}`);
92
+ if (result.splitSuggestions.length > 0) {
93
+ console.log("\nSplit Suggestions:");
94
+ for (const s of result.splitSuggestions) {
95
+ console.log(` • ${s}`);
96
+ }
97
+ }
98
+ }
99
+ //# sourceMappingURL=review-pr-size-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-pr-size-check.js","sourceRoot":"","sources":["../../src/commands/review-pr-size-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runReviewTeamAnalytics(argv: string[]): void;
2
+ //# sourceMappingURL=review-team-analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-team-analytics.d.ts","sourceRoot":"","sources":["../../src/commands/review-team-analytics.ts"],"names":[],"mappings":"AA4DA,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAsE3D"}
@@ -0,0 +1,95 @@
1
+ import { readFileSync, existsSync, readdirSync } from "fs";
2
+ import { join } from "path";
3
+ function computeTeamAnalytics(verdicts) {
4
+ const totalFindings = verdicts.reduce((sum, v) => sum + (v.findings?.length ?? 0), 0);
5
+ const passCount = verdicts.filter((v) => v.overallVerdict === "pass").length;
6
+ const totalScore = verdicts.reduce((sum, v) => sum + (v.overallScore ?? 0), 0);
7
+ const severityDist = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
8
+ const ruleCounts = new Map();
9
+ for (const v of verdicts) {
10
+ for (const f of v.findings ?? []) {
11
+ severityDist[f.severity] = (severityDist[f.severity] ?? 0) + 1;
12
+ ruleCounts.set(f.ruleId, (ruleCounts.get(f.ruleId) ?? 0) + 1);
13
+ }
14
+ }
15
+ const topRules = [...ruleCounts.entries()]
16
+ .sort((a, b) => b[1] - a[1])
17
+ .slice(0, 10)
18
+ .map(([ruleId, count]) => ({ ruleId, count }));
19
+ const half = Math.floor(verdicts.length / 2);
20
+ const recentScores = verdicts.slice(half).map((v) => v.overallScore ?? 0);
21
+ const olderScores = verdicts.slice(0, half).map((v) => v.overallScore ?? 0);
22
+ const recentAvg = recentScores.length > 0 ? recentScores.reduce((a, b) => a + b, 0) / recentScores.length : 0;
23
+ const olderAvg = olderScores.length > 0 ? olderScores.reduce((a, b) => a + b, 0) / olderScores.length : 0;
24
+ const qualityTrend = recentAvg > olderAvg ? "improving" : recentAvg < olderAvg ? "declining" : "stable";
25
+ return {
26
+ totalReviews: verdicts.length,
27
+ totalFindings,
28
+ avgFindingsPerReview: verdicts.length > 0 ? totalFindings / verdicts.length : 0,
29
+ passRate: verdicts.length > 0 ? passCount / verdicts.length : 0,
30
+ avgScore: verdicts.length > 0 ? totalScore / verdicts.length : 0,
31
+ severityDistribution: severityDist,
32
+ topRules,
33
+ qualityTrend,
34
+ };
35
+ }
36
+ export function runReviewTeamAnalytics(argv) {
37
+ if (argv.includes("--help") || argv.includes("-h")) {
38
+ console.log(`Usage: judges review-team-analytics [options]
39
+
40
+ Team-level review analytics and statistics.
41
+
42
+ Options:
43
+ --dir <path> Directory with verdict JSON files
44
+ --format <fmt> Output format: table (default) or json
45
+ -h, --help Show this help message`);
46
+ return;
47
+ }
48
+ const formatIdx = argv.indexOf("--format");
49
+ const format = formatIdx !== -1 && argv[formatIdx + 1] ? argv[formatIdx + 1] : "table";
50
+ const dirIdx = argv.indexOf("--dir");
51
+ const dirPath = dirIdx !== -1 && argv[dirIdx + 1]
52
+ ? join(process.cwd(), argv[dirIdx + 1])
53
+ : join(process.cwd(), ".judges", "history");
54
+ const verdicts = [];
55
+ if (existsSync(dirPath)) {
56
+ const files = readdirSync(dirPath).filter((f) => f.endsWith(".json")).sort();
57
+ for (const file of files) {
58
+ const data = JSON.parse(readFileSync(join(dirPath, file), "utf-8"));
59
+ verdicts.push(data);
60
+ }
61
+ }
62
+ const defaultPath = join(process.cwd(), ".judges", "last-verdict.json");
63
+ if (existsSync(defaultPath)) {
64
+ verdicts.push(JSON.parse(readFileSync(defaultPath, "utf-8")));
65
+ }
66
+ if (verdicts.length === 0) {
67
+ console.log("No verdict data found. Run reviews first or provide --dir.");
68
+ return;
69
+ }
70
+ const analytics = computeTeamAnalytics(verdicts);
71
+ if (format === "json") {
72
+ console.log(JSON.stringify(analytics, null, 2));
73
+ return;
74
+ }
75
+ console.log("\n=== Team Review Analytics ===\n");
76
+ console.log(`Reviews: ${analytics.totalReviews}`);
77
+ console.log(`Total findings: ${analytics.totalFindings}`);
78
+ console.log(`Avg findings/review: ${analytics.avgFindingsPerReview.toFixed(1)}`);
79
+ console.log(`Pass rate: ${(analytics.passRate * 100).toFixed(1)}%`);
80
+ console.log(`Avg score: ${analytics.avgScore.toFixed(1)}`);
81
+ console.log(`Quality trend: ${analytics.qualityTrend}`);
82
+ console.log("\nSeverity Distribution:");
83
+ for (const [sev, count] of Object.entries(analytics.severityDistribution)) {
84
+ if (count > 0) {
85
+ console.log(` ${sev}: ${count}`);
86
+ }
87
+ }
88
+ if (analytics.topRules.length > 0) {
89
+ console.log("\nTop Rules:");
90
+ for (const rule of analytics.topRules) {
91
+ console.log(` ${rule.ruleId}: ${rule.count}`);
92
+ }
93
+ }
94
+ }
95
+ //# sourceMappingURL=review-team-analytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-team-analytics.js","sourceRoot":"","sources":["../../src/commands/review-team-analytics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runReviewTemplateSuggest(argv: string[]): void;
2
+ //# sourceMappingURL=review-template-suggest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-template-suggest.d.ts","sourceRoot":"","sources":["../../src/commands/review-template-suggest.ts"],"names":[],"mappings":"AA8FA,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAoD7D"}
@@ -0,0 +1,120 @@
1
+ import { readFileSync, existsSync } from "fs";
2
+ import { join } from "path";
3
+ const TEMPLATES = {
4
+ "bug-fix": {
5
+ changeType: "Bug Fix",
6
+ template: "bug-fix-review",
7
+ focusAreas: ["Root cause analysis", "Regression test coverage", "Edge cases"],
8
+ checklistItems: [
9
+ "Bug root cause identified",
10
+ "Fix addresses root cause, not just symptom",
11
+ "Regression tests added",
12
+ "No unintended side effects",
13
+ ],
14
+ },
15
+ feature: {
16
+ changeType: "New Feature",
17
+ template: "feature-review",
18
+ focusAreas: ["Design alignment", "Security review", "Performance impact", "Documentation"],
19
+ checklistItems: [
20
+ "Feature matches requirements",
21
+ "Security implications reviewed",
22
+ "Performance tested",
23
+ "Documentation updated",
24
+ "Tests cover happy and error paths",
25
+ ],
26
+ },
27
+ refactor: {
28
+ changeType: "Refactor",
29
+ template: "refactor-review",
30
+ focusAreas: ["Behavior preservation", "Test coverage unchanged", "Code clarity"],
31
+ checklistItems: [
32
+ "No behavioral changes introduced",
33
+ "All existing tests still pass",
34
+ "Code readability improved",
35
+ "No new dependencies added unnecessarily",
36
+ ],
37
+ },
38
+ config: {
39
+ changeType: "Configuration",
40
+ template: "config-review",
41
+ focusAreas: ["Secret exposure", "Environment parity", "Breaking changes"],
42
+ checklistItems: [
43
+ "No secrets or credentials exposed",
44
+ "Compatible with all environments",
45
+ "Backward compatible or migration documented",
46
+ ],
47
+ },
48
+ dependency: {
49
+ changeType: "Dependency Update",
50
+ template: "dependency-review",
51
+ focusAreas: ["Security advisories", "Breaking changes", "License compatibility"],
52
+ checklistItems: [
53
+ "No known vulnerabilities in new version",
54
+ "Breaking changes reviewed",
55
+ "License still compatible",
56
+ "Lock file updated consistently",
57
+ ],
58
+ },
59
+ };
60
+ function detectChangeType(files) {
61
+ const hasConfig = files.some((f) => f.endsWith(".json") || f.endsWith(".yml") || f.endsWith(".yaml") || f.endsWith(".toml") || f.endsWith(".env"));
62
+ const hasDeps = files.some((f) => f.includes("package.json") || f.includes("Cargo.toml") || f.includes("go.mod") || f.includes("requirements"));
63
+ const hasTests = files.some((f) => f.includes("test") || f.includes("spec"));
64
+ const hasSource = files.some((f) => f.endsWith(".ts") || f.endsWith(".js") || f.endsWith(".py") || f.endsWith(".go") || f.endsWith(".rs"));
65
+ if (hasDeps)
66
+ return "dependency";
67
+ if (hasConfig && !hasSource)
68
+ return "config";
69
+ if (hasTests && hasSource)
70
+ return "bug-fix";
71
+ if (hasSource)
72
+ return "feature";
73
+ return "refactor";
74
+ }
75
+ export function runReviewTemplateSuggest(argv) {
76
+ if (argv.includes("--help") || argv.includes("-h")) {
77
+ console.log(`Usage: judges review-template-suggest [options]
78
+
79
+ Suggest review templates based on change type.
80
+
81
+ Options:
82
+ --files <path> File listing changed files (one per line)
83
+ --type <type> Override change type: bug-fix, feature, refactor, config, dependency
84
+ --format <fmt> Output format: table (default) or json
85
+ -h, --help Show this help message`);
86
+ return;
87
+ }
88
+ const formatIdx = argv.indexOf("--format");
89
+ const format = formatIdx !== -1 && argv[formatIdx + 1] ? argv[formatIdx + 1] : "table";
90
+ const typeIdx = argv.indexOf("--type");
91
+ let changeType = typeIdx !== -1 && argv[typeIdx + 1] ? argv[typeIdx + 1] : "";
92
+ if (changeType === "") {
93
+ const filesIdx = argv.indexOf("--files");
94
+ const filesPath = filesIdx !== -1 && argv[filesIdx + 1] ? join(process.cwd(), argv[filesIdx + 1]) : null;
95
+ let changedFiles = [];
96
+ if (filesPath !== null && existsSync(filesPath)) {
97
+ changedFiles = readFileSync(filesPath, "utf-8")
98
+ .split("\n")
99
+ .map((l) => l.trim())
100
+ .filter((l) => l.length > 0);
101
+ }
102
+ changeType = changedFiles.length > 0 ? detectChangeType(changedFiles) : "feature";
103
+ }
104
+ const suggestion = TEMPLATES[changeType] ?? TEMPLATES["feature"];
105
+ if (format === "json") {
106
+ console.log(JSON.stringify(suggestion, null, 2));
107
+ return;
108
+ }
109
+ console.log(`\n=== Review Template: ${suggestion.changeType} ===\n`);
110
+ console.log(`Template: ${suggestion.template}`);
111
+ console.log("\nFocus Areas:");
112
+ for (const area of suggestion.focusAreas) {
113
+ console.log(` • ${area}`);
114
+ }
115
+ console.log("\nChecklist:");
116
+ for (const item of suggestion.checklistItems) {
117
+ console.log(` ☐ ${item}`);
118
+ }
119
+ }
120
+ //# sourceMappingURL=review-template-suggest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-template-suggest.js","sourceRoot":"","sources":["../../src/commands/review-template-suggest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runReviewVelocityTrack(argv: string[]): void;
2
+ //# sourceMappingURL=review-velocity-track.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-velocity-track.d.ts","sourceRoot":"","sources":["../../src/commands/review-velocity-track.ts"],"names":[],"mappings":"AAsDA,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA0E3D"}
@@ -0,0 +1,95 @@
1
+ import { readFileSync, existsSync, readdirSync } from "fs";
2
+ import { join } from "path";
3
+ function computeVelocity(verdicts) {
4
+ const periods = new Map();
5
+ for (const entry of verdicts) {
6
+ const date = entry.timestamp.substring(0, 10);
7
+ const group = periods.get(date);
8
+ if (group !== undefined) {
9
+ group.push(entry.verdict);
10
+ }
11
+ else {
12
+ periods.set(date, [entry.verdict]);
13
+ }
14
+ }
15
+ const velocityData = [];
16
+ const sortedPeriods = [...periods.keys()].sort();
17
+ for (const period of sortedPeriods) {
18
+ const vdcts = periods.get(period) ?? [];
19
+ const totalFindings = vdcts.reduce((sum, v) => sum + (v.findings?.length ?? 0), 0);
20
+ const passCount = vdcts.filter((v) => v.overallVerdict === "pass").length;
21
+ const totalScore = vdcts.reduce((sum, v) => sum + (v.overallScore ?? 0), 0);
22
+ velocityData.push({
23
+ period,
24
+ reviewCount: vdcts.length,
25
+ totalFindings,
26
+ avgFindings: vdcts.length > 0 ? totalFindings / vdcts.length : 0,
27
+ passRate: vdcts.length > 0 ? passCount / vdcts.length : 0,
28
+ avgScore: vdcts.length > 0 ? totalScore / vdcts.length : 0,
29
+ });
30
+ }
31
+ return velocityData;
32
+ }
33
+ export function runReviewVelocityTrack(argv) {
34
+ if (argv.includes("--help") || argv.includes("-h")) {
35
+ console.log(`Usage: judges review-velocity-track [options]
36
+
37
+ Track review velocity and throughput over time.
38
+
39
+ Options:
40
+ --dir <path> Directory with verdict JSON files
41
+ --format <fmt> Output format: table (default) or json
42
+ -h, --help Show this help message`);
43
+ return;
44
+ }
45
+ const formatIdx = argv.indexOf("--format");
46
+ const format = formatIdx !== -1 && argv[formatIdx + 1] ? argv[formatIdx + 1] : "table";
47
+ const dirIdx = argv.indexOf("--dir");
48
+ const dirPath = dirIdx !== -1 && argv[dirIdx + 1]
49
+ ? join(process.cwd(), argv[dirIdx + 1])
50
+ : join(process.cwd(), ".judges", "history");
51
+ const verdicts = [];
52
+ if (existsSync(dirPath)) {
53
+ const files = readdirSync(dirPath).filter((f) => f.endsWith(".json")).sort();
54
+ for (const file of files) {
55
+ const data = JSON.parse(readFileSync(join(dirPath, file), "utf-8"));
56
+ verdicts.push({
57
+ timestamp: data.timestamp ?? file.replace(/\.json$/, ""),
58
+ verdict: data,
59
+ });
60
+ }
61
+ }
62
+ const defaultPath = join(process.cwd(), ".judges", "last-verdict.json");
63
+ if (existsSync(defaultPath)) {
64
+ const data = JSON.parse(readFileSync(defaultPath, "utf-8"));
65
+ verdicts.push({
66
+ timestamp: data.timestamp ?? new Date().toISOString(),
67
+ verdict: data,
68
+ });
69
+ }
70
+ if (verdicts.length === 0) {
71
+ console.log("No verdict data found. Run reviews first or provide --dir.");
72
+ return;
73
+ }
74
+ const velocity = computeVelocity(verdicts);
75
+ if (format === "json") {
76
+ console.log(JSON.stringify(velocity, null, 2));
77
+ return;
78
+ }
79
+ console.log("\n=== Review Velocity ===\n");
80
+ console.log(`Total data points: ${verdicts.length}\n`);
81
+ for (const v of velocity) {
82
+ console.log(`${v.period}: ${v.reviewCount} review(s)`);
83
+ console.log(` Findings: ${v.totalFindings} total, ${v.avgFindings.toFixed(1)} avg`);
84
+ console.log(` Pass rate: ${(v.passRate * 100).toFixed(0)}%`);
85
+ console.log(` Avg score: ${v.avgScore.toFixed(1)}`);
86
+ console.log();
87
+ }
88
+ if (velocity.length >= 2) {
89
+ const first = velocity[0];
90
+ const last = velocity[velocity.length - 1];
91
+ const trend = last.avgScore > first.avgScore ? "improving" : last.avgScore < first.avgScore ? "declining" : "stable";
92
+ console.log(`Trend: ${trend} (${first.avgScore.toFixed(1)} → ${last.avgScore.toFixed(1)})`);
93
+ }
94
+ }
95
+ //# sourceMappingURL=review-velocity-track.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-velocity-track.js","sourceRoot":"","sources":["../../src/commands/review-velocity-track.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kevinrabun/judges",
3
- "version": "3.103.0",
3
+ "version": "3.104.0",
4
4
  "description": "45 specialized judges that evaluate AI-generated code for security, cost, and quality.",
5
5
  "mcpName": "io.github.KevinRabun/judges",
6
6
  "type": "module",
package/server.json CHANGED
@@ -7,12 +7,12 @@
7
7
  "url": "https://github.com/kevinrabun/judges",
8
8
  "source": "github"
9
9
  },
10
- "version": "3.103.0",
10
+ "version": "3.104.0",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "identifier": "@kevinrabun/judges",
15
- "version": "3.103.0",
15
+ "version": "3.104.0",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  }