@kevinrabun/judges 3.90.0 → 3.92.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 (78) hide show
  1. package/CHANGELOG.md +26 -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/finding-auto-group.d.ts +5 -0
  6. package/dist/commands/finding-auto-group.d.ts.map +1 -0
  7. package/dist/commands/finding-auto-group.js +109 -0
  8. package/dist/commands/finding-auto-group.js.map +1 -0
  9. package/dist/commands/finding-blast-radius.d.ts +5 -0
  10. package/dist/commands/finding-blast-radius.d.ts.map +1 -0
  11. package/dist/commands/finding-blast-radius.js +92 -0
  12. package/dist/commands/finding-blast-radius.js.map +1 -0
  13. package/dist/commands/finding-cross-ref.d.ts +5 -0
  14. package/dist/commands/finding-cross-ref.d.ts.map +1 -0
  15. package/dist/commands/finding-cross-ref.js +99 -0
  16. package/dist/commands/finding-cross-ref.js.map +1 -0
  17. package/dist/commands/finding-hotspot-map.d.ts +5 -0
  18. package/dist/commands/finding-hotspot-map.d.ts.map +1 -0
  19. package/dist/commands/finding-hotspot-map.js +107 -0
  20. package/dist/commands/finding-hotspot-map.js.map +1 -0
  21. package/dist/commands/finding-metadata-enrich.d.ts +5 -0
  22. package/dist/commands/finding-metadata-enrich.d.ts.map +1 -0
  23. package/dist/commands/finding-metadata-enrich.js +93 -0
  24. package/dist/commands/finding-metadata-enrich.js.map +1 -0
  25. package/dist/commands/finding-pattern-detect.d.ts +5 -0
  26. package/dist/commands/finding-pattern-detect.d.ts.map +1 -0
  27. package/dist/commands/finding-pattern-detect.js +128 -0
  28. package/dist/commands/finding-pattern-detect.js.map +1 -0
  29. package/dist/commands/finding-suppression-list.d.ts +5 -0
  30. package/dist/commands/finding-suppression-list.d.ts.map +1 -0
  31. package/dist/commands/finding-suppression-list.js +120 -0
  32. package/dist/commands/finding-suppression-list.js.map +1 -0
  33. package/dist/commands/review-annotation-export.d.ts +5 -0
  34. package/dist/commands/review-annotation-export.d.ts.map +1 -0
  35. package/dist/commands/review-annotation-export.js +106 -0
  36. package/dist/commands/review-annotation-export.js.map +1 -0
  37. package/dist/commands/review-cache-warm.d.ts +5 -0
  38. package/dist/commands/review-cache-warm.d.ts.map +1 -0
  39. package/dist/commands/review-cache-warm.js +71 -0
  40. package/dist/commands/review-cache-warm.js.map +1 -0
  41. package/dist/commands/review-ci-gate.d.ts +5 -0
  42. package/dist/commands/review-ci-gate.d.ts.map +1 -0
  43. package/dist/commands/review-ci-gate.js +115 -0
  44. package/dist/commands/review-ci-gate.js.map +1 -0
  45. package/dist/commands/review-coverage-gap.d.ts +5 -0
  46. package/dist/commands/review-coverage-gap.d.ts.map +1 -0
  47. package/dist/commands/review-coverage-gap.js +121 -0
  48. package/dist/commands/review-coverage-gap.js.map +1 -0
  49. package/dist/commands/review-feedback-loop.d.ts +5 -0
  50. package/dist/commands/review-feedback-loop.d.ts.map +1 -0
  51. package/dist/commands/review-feedback-loop.js +114 -0
  52. package/dist/commands/review-feedback-loop.js.map +1 -0
  53. package/dist/commands/review-merge-config.d.ts +5 -0
  54. package/dist/commands/review-merge-config.d.ts.map +1 -0
  55. package/dist/commands/review-merge-config.js +120 -0
  56. package/dist/commands/review-merge-config.js.map +1 -0
  57. package/dist/commands/review-onboard-wizard.d.ts +5 -0
  58. package/dist/commands/review-onboard-wizard.d.ts.map +1 -0
  59. package/dist/commands/review-onboard-wizard.js +93 -0
  60. package/dist/commands/review-onboard-wizard.js.map +1 -0
  61. package/dist/commands/review-parallel-run.d.ts +5 -0
  62. package/dist/commands/review-parallel-run.d.ts.map +1 -0
  63. package/dist/commands/review-parallel-run.js +117 -0
  64. package/dist/commands/review-parallel-run.js.map +1 -0
  65. package/dist/commands/review-plugin-status.d.ts +5 -0
  66. package/dist/commands/review-plugin-status.d.ts.map +1 -0
  67. package/dist/commands/review-plugin-status.js +54 -0
  68. package/dist/commands/review-plugin-status.js.map +1 -0
  69. package/dist/commands/review-quality-score.d.ts +5 -0
  70. package/dist/commands/review-quality-score.d.ts.map +1 -0
  71. package/dist/commands/review-quality-score.js +128 -0
  72. package/dist/commands/review-quality-score.js.map +1 -0
  73. package/dist/commands/review-team-stats.d.ts +5 -0
  74. package/dist/commands/review-team-stats.d.ts.map +1 -0
  75. package/dist/commands/review-team-stats.js +98 -0
  76. package/dist/commands/review-team-stats.js.map +1 -0
  77. package/package.json +1 -1
  78. package/server.json +2 -2
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Review-coverage-gap — Identify gaps in review coverage.
3
+ */
4
+ import { readFileSync, existsSync } from "fs";
5
+ import { defaultRegistry } from "../judge-registry.js";
6
+ // ─── Analysis ───────────────────────────────────────────────────────────────
7
+ function findCoverageGaps(verdict) {
8
+ const gaps = [];
9
+ const judges = defaultRegistry.getJudges();
10
+ const activeJudgeIds = new Set(verdict.evaluations.map((e) => e.judgeId));
11
+ // Missing judge coverage
12
+ for (const j of judges) {
13
+ if (!activeJudgeIds.has(j.id)) {
14
+ gaps.push({
15
+ type: "missing-judge",
16
+ detail: `Judge ${j.id} (${j.domain}) did not participate`,
17
+ severity: "medium",
18
+ suggestion: `Enable judge ${j.id} for broader coverage`,
19
+ });
20
+ }
21
+ }
22
+ // Low confidence findings
23
+ const lowConf = verdict.findings.filter((f) => f.confidence !== undefined && f.confidence !== null && f.confidence < 0.5);
24
+ if (lowConf.length > 0) {
25
+ gaps.push({
26
+ type: "low-confidence",
27
+ detail: `${lowConf.length} findings have confidence < 50%`,
28
+ severity: "low",
29
+ suggestion: "Review low-confidence findings manually for accuracy",
30
+ });
31
+ }
32
+ // Uncovered line ranges (findings with no line numbers)
33
+ const noLines = verdict.findings.filter((f) => !f.lineNumbers || f.lineNumbers.length === 0);
34
+ if (noLines.length > 0) {
35
+ gaps.push({
36
+ type: "uncovered-lines",
37
+ detail: `${noLines.length} findings have no line number information`,
38
+ severity: "low",
39
+ suggestion: "Some findings lack precise location data",
40
+ });
41
+ }
42
+ // Low evaluation scores
43
+ const lowScoreEvals = verdict.evaluations.filter((e) => e.score < 40);
44
+ for (const e of lowScoreEvals) {
45
+ gaps.push({
46
+ type: "low-confidence",
47
+ detail: `Judge ${e.judgeId} gave score ${e.score}`,
48
+ severity: "high",
49
+ suggestion: `Investigate why ${e.judgeId} rated code so poorly`,
50
+ });
51
+ }
52
+ return gaps.sort((a, b) => {
53
+ const sevOrder = { high: 0, medium: 1, low: 2 };
54
+ return (sevOrder[a.severity] || 2) - (sevOrder[b.severity] || 2);
55
+ });
56
+ }
57
+ // ─── CLI ────────────────────────────────────────────────────────────────────
58
+ export function runReviewCoverageGap(argv) {
59
+ const fileIdx = argv.indexOf("--file");
60
+ const formatIdx = argv.indexOf("--format");
61
+ const filePath = fileIdx >= 0 ? argv[fileIdx + 1] : undefined;
62
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
63
+ if (argv.includes("--help") || argv.includes("-h")) {
64
+ console.log(`
65
+ judges review-coverage-gap — Identify review coverage gaps
66
+
67
+ Usage:
68
+ judges review-coverage-gap --file <verdict.json> [--format table|json]
69
+
70
+ Options:
71
+ --file <path> Path to verdict JSON file (required)
72
+ --format <fmt> Output format: table (default), json
73
+ --help, -h Show this help
74
+ `);
75
+ return;
76
+ }
77
+ if (!filePath) {
78
+ console.error("Error: --file required");
79
+ process.exitCode = 1;
80
+ return;
81
+ }
82
+ if (!existsSync(filePath)) {
83
+ console.error(`Error: not found: ${filePath}`);
84
+ process.exitCode = 1;
85
+ return;
86
+ }
87
+ let verdict;
88
+ try {
89
+ verdict = JSON.parse(readFileSync(filePath, "utf-8"));
90
+ }
91
+ catch {
92
+ console.error("Error: invalid JSON");
93
+ process.exitCode = 1;
94
+ return;
95
+ }
96
+ const gaps = findCoverageGaps(verdict);
97
+ if (format === "json") {
98
+ console.log(JSON.stringify(gaps, null, 2));
99
+ return;
100
+ }
101
+ console.log(`\nCoverage Gaps (${gaps.length} found)`);
102
+ console.log("═".repeat(70));
103
+ console.log(`${"Type".padEnd(18)} ${"Severity".padEnd(10)} Detail`);
104
+ console.log("─".repeat(70));
105
+ for (const g of gaps) {
106
+ const detail = g.detail.length > 38 ? g.detail.slice(0, 38) + "…" : g.detail;
107
+ console.log(`${g.type.padEnd(18)} ${g.severity.padEnd(10)} ${detail}`);
108
+ }
109
+ if (gaps.length > 0) {
110
+ console.log(`\n Suggestions:`);
111
+ const seen = new Set();
112
+ for (const g of gaps) {
113
+ if (!seen.has(g.suggestion)) {
114
+ seen.add(g.suggestion);
115
+ console.log(` - ${g.suggestion}`);
116
+ }
117
+ }
118
+ }
119
+ console.log("═".repeat(70));
120
+ }
121
+ //# sourceMappingURL=review-coverage-gap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-coverage-gap.js","sourceRoot":"","sources":["../../src/commands/review-coverage-gap.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAE9C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAWvD,+EAA+E;AAE/E,SAAS,gBAAgB,CAAC,OAAwB;IAChD,MAAM,IAAI,GAAkB,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,EAAE,CAAC;IAC3C,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAE1E,yBAAyB;IACzB,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC;gBACR,IAAI,EAAE,eAAe;gBACrB,MAAM,EAAE,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,uBAAuB;gBACzD,QAAQ,EAAE,QAAQ;gBAClB,UAAU,EAAE,gBAAgB,CAAC,CAAC,EAAE,uBAAuB;aACxD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,0BAA0B;IAC1B,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CACrC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,SAAS,IAAI,CAAC,CAAC,UAAU,KAAK,IAAI,IAAI,CAAC,CAAC,UAAU,GAAG,GAAG,CACjF,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,gBAAgB;YACtB,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,iCAAiC;YAC1D,QAAQ,EAAE,KAAK;YACf,UAAU,EAAE,sDAAsD;SACnE,CAAC,CAAC;IACL,CAAC;IAED,wDAAwD;IACxD,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;IAC7F,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,iBAAiB;YACvB,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,2CAA2C;YACpE,QAAQ,EAAE,KAAK;YACf,UAAU,EAAE,0CAA0C;SACvD,CAAC,CAAC;IACL,CAAC;IAED,wBAAwB;IACxB,MAAM,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;IACtE,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,gBAAgB;YACtB,MAAM,EAAE,SAAS,CAAC,CAAC,OAAO,eAAe,CAAC,CAAC,KAAK,EAAE;YAClD,QAAQ,EAAE,MAAM;YAChB,UAAU,EAAE,mBAAmB,CAAC,CAAC,OAAO,uBAAuB;SAChE,CAAC,CAAC;IACL,CAAC;IAED,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACxB,MAAM,QAAQ,GAA2B,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;QACxE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,+EAA+E;AAE/E,MAAM,UAAU,oBAAoB,CAAC,IAAc;IACjD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9D,MAAM,MAAM,GAAG,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAE9D,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;CAUf,CAAC,CAAC;QACC,OAAO;IACT,CAAC;IAED,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACxC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,qBAAqB,QAAQ,EAAE,CAAC,CAAC;QAC/C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,IAAI,OAAwB,CAAC;IAC7B,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACrC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAEvC,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3C,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,CAAC,MAAM,SAAS,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;IACpE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAE5B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC7E,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAChC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC5B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Review-feedback-loop — Track review feedback and improvement over time.
3
+ */
4
+ export declare function runReviewFeedbackLoop(argv: string[]): void;
5
+ //# sourceMappingURL=review-feedback-loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-feedback-loop.d.ts","sourceRoot":"","sources":["../../src/commands/review-feedback-loop.ts"],"names":[],"mappings":"AAAA;;GAEG;AAkFH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA2E1D"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Review-feedback-loop — Track review feedback and improvement over time.
3
+ */
4
+ import { readFileSync, writeFileSync, existsSync } from "fs";
5
+ // ─── Logic ──────────────────────────────────────────────────────────────────
6
+ function loadLog(path) {
7
+ if (!existsSync(path)) {
8
+ return { version: 1, entries: [] };
9
+ }
10
+ try {
11
+ return JSON.parse(readFileSync(path, "utf-8"));
12
+ }
13
+ catch {
14
+ return { version: 1, entries: [] };
15
+ }
16
+ }
17
+ function analyze(log) {
18
+ const total = log.entries.length;
19
+ if (total === 0) {
20
+ return {
21
+ total: 0,
22
+ trend: "stable",
23
+ avgScore: 0,
24
+ recentAvgScore: 0,
25
+ scoreDelta: 0,
26
+ avgFindings: 0,
27
+ recentAvgFindings: 0,
28
+ findingDelta: 0,
29
+ };
30
+ }
31
+ const scores = log.entries.map((e) => e.score);
32
+ const findings = log.entries.map((e) => e.findingCount);
33
+ const avgScore = Math.round(scores.reduce((a, b) => a + b, 0) / total);
34
+ const avgFindings = Math.round(findings.reduce((a, b) => a + b, 0) / total);
35
+ const recentCount = Math.min(5, total);
36
+ const recentScores = scores.slice(-recentCount);
37
+ const recentFindings = findings.slice(-recentCount);
38
+ const recentAvgScore = Math.round(recentScores.reduce((a, b) => a + b, 0) / recentCount);
39
+ const recentAvgFindings = Math.round(recentFindings.reduce((a, b) => a + b, 0) / recentCount);
40
+ const scoreDelta = recentAvgScore - avgScore;
41
+ const findingDelta = recentAvgFindings - avgFindings;
42
+ let trend = "stable";
43
+ if (scoreDelta > 5)
44
+ trend = "improving";
45
+ else if (scoreDelta < -5)
46
+ trend = "declining";
47
+ return { total, trend, avgScore, recentAvgScore, scoreDelta, avgFindings, recentAvgFindings, findingDelta };
48
+ }
49
+ // ─── CLI ────────────────────────────────────────────────────────────────────
50
+ export function runReviewFeedbackLoop(argv) {
51
+ const fileIdx = argv.indexOf("--file");
52
+ const logIdx = argv.indexOf("--log");
53
+ const formatIdx = argv.indexOf("--format");
54
+ const filePath = fileIdx >= 0 ? argv[fileIdx + 1] : undefined;
55
+ const logPath = logIdx >= 0 ? argv[logIdx + 1] : ".judges-feedback.json";
56
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
57
+ if (argv.includes("--help") || argv.includes("-h")) {
58
+ console.log(`
59
+ judges review-feedback-loop — Track review feedback over time
60
+
61
+ Usage:
62
+ judges review-feedback-loop [--file <verdict.json>] [--log <path>]
63
+ [--format table|json]
64
+
65
+ Options:
66
+ --file <path> Add verdict to feedback log
67
+ --log <path> Feedback log file (default: .judges-feedback.json)
68
+ --format <fmt> Output format: table (default), json
69
+ --help, -h Show this help
70
+ `);
71
+ return;
72
+ }
73
+ const log = loadLog(logPath);
74
+ // Add mode
75
+ if (filePath) {
76
+ if (!existsSync(filePath)) {
77
+ console.error(`Error: not found: ${filePath}`);
78
+ process.exitCode = 1;
79
+ return;
80
+ }
81
+ let verdict;
82
+ try {
83
+ verdict = JSON.parse(readFileSync(filePath, "utf-8"));
84
+ }
85
+ catch {
86
+ console.error("Error: invalid JSON");
87
+ process.exitCode = 1;
88
+ return;
89
+ }
90
+ log.entries.push({
91
+ timestamp: new Date().toISOString(),
92
+ score: verdict.overallScore,
93
+ findingCount: verdict.findings.length,
94
+ criticalCount: verdict.criticalCount,
95
+ verdict: verdict.overallVerdict,
96
+ });
97
+ writeFileSync(logPath, JSON.stringify(log, null, 2));
98
+ console.log(`Added entry to feedback log (${log.entries.length} total)`);
99
+ return;
100
+ }
101
+ // Analyze mode
102
+ const result = analyze(log);
103
+ if (format === "json") {
104
+ console.log(JSON.stringify(result, null, 2));
105
+ return;
106
+ }
107
+ console.log(`\nFeedback Loop Analysis (${result.total} entries)`);
108
+ console.log("═".repeat(50));
109
+ console.log(` Trend: ${result.trend}`);
110
+ console.log(` Avg Score: ${result.avgScore} (recent: ${result.recentAvgScore}, Δ${result.scoreDelta >= 0 ? "+" : ""}${result.scoreDelta})`);
111
+ console.log(` Avg Findings: ${result.avgFindings} (recent: ${result.recentAvgFindings}, Δ${result.findingDelta >= 0 ? "+" : ""}${result.findingDelta})`);
112
+ console.log("═".repeat(50));
113
+ }
114
+ //# sourceMappingURL=review-feedback-loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-feedback-loop.js","sourceRoot":"","sources":["../../src/commands/review-feedback-loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Review-merge-config — Merge multiple Judges configuration files.
3
+ */
4
+ export declare function runReviewMergeConfig(argv: string[]): void;
5
+ //# sourceMappingURL=review-merge-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-merge-config.d.ts","sourceRoot":"","sources":["../../src/commands/review-merge-config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoEH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA0EzD"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Review-merge-config — Merge multiple Judges configuration files.
3
+ */
4
+ import { readFileSync, writeFileSync, existsSync } from "fs";
5
+ // ─── Analysis ───────────────────────────────────────────────────────────────
6
+ function mergeConfigs(configs) {
7
+ const merged = {};
8
+ const conflicts = [];
9
+ const sources = configs.map((c) => c.path);
10
+ // merge presets — last wins, track conflicts
11
+ const presets = configs.filter((c) => c.config.preset).map((c) => c.config.preset);
12
+ if (presets.length > 1 && new Set(presets).size > 1) {
13
+ conflicts.push({ key: "preset", values: presets });
14
+ }
15
+ if (presets.length > 0) {
16
+ merged.preset = presets[presets.length - 1];
17
+ }
18
+ // merge disabled judges — union
19
+ const allDisabled = new Set();
20
+ for (const c of configs) {
21
+ if (c.config.disabledJudges) {
22
+ for (const j of c.config.disabledJudges) {
23
+ allDisabled.add(j);
24
+ }
25
+ }
26
+ }
27
+ if (allDisabled.size > 0) {
28
+ merged.disabledJudges = [...allDisabled];
29
+ }
30
+ // merge disabled rules — union
31
+ const allDisabledRules = new Set();
32
+ for (const c of configs) {
33
+ if (c.config.disabledRules) {
34
+ for (const r of c.config.disabledRules) {
35
+ allDisabledRules.add(r);
36
+ }
37
+ }
38
+ }
39
+ if (allDisabledRules.size > 0) {
40
+ merged.disabledRules = [...allDisabledRules];
41
+ }
42
+ // merge minSeverity — most restrictive (highest)
43
+ const severityOrder = ["low", "medium", "high", "critical"];
44
+ const severities = configs.filter((c) => c.config.minSeverity).map((c) => c.config.minSeverity);
45
+ if (severities.length > 0) {
46
+ const maxSev = severities.reduce((a, b) => (severityOrder.indexOf(a) > severityOrder.indexOf(b) ? a : b));
47
+ merged.minSeverity = maxSev;
48
+ }
49
+ return { merged, sources, conflicts };
50
+ }
51
+ // ─── CLI ────────────────────────────────────────────────────────────────────
52
+ export function runReviewMergeConfig(argv) {
53
+ const filesIdx = argv.indexOf("--files");
54
+ const outputIdx = argv.indexOf("--output");
55
+ const formatIdx = argv.indexOf("--format");
56
+ const outputPath = outputIdx >= 0 ? argv[outputIdx + 1] : undefined;
57
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
58
+ if (argv.includes("--help") || argv.includes("-h")) {
59
+ console.log(`
60
+ judges review-merge-config — Merge configuration files
61
+
62
+ Usage:
63
+ judges review-merge-config --files <a.json,b.json,...> [--output <out.json>]
64
+ [--format table|json]
65
+
66
+ Options:
67
+ --files <paths> Comma-separated config file paths (required)
68
+ --output <path> Write merged config to file
69
+ --format <fmt> Output format: table (default), json
70
+ --help, -h Show this help
71
+ `);
72
+ return;
73
+ }
74
+ const filesArg = filesIdx >= 0 ? argv[filesIdx + 1] : undefined;
75
+ if (!filesArg) {
76
+ console.error("Error: --files required");
77
+ process.exitCode = 1;
78
+ return;
79
+ }
80
+ const filePaths = filesArg.split(",").map((f) => f.trim());
81
+ const configs = [];
82
+ for (const fp of filePaths) {
83
+ if (!existsSync(fp)) {
84
+ console.error(`Error: not found: ${fp}`);
85
+ process.exitCode = 1;
86
+ return;
87
+ }
88
+ try {
89
+ configs.push({ path: fp, config: JSON.parse(readFileSync(fp, "utf-8")) });
90
+ }
91
+ catch {
92
+ console.error(`Error: invalid JSON: ${fp}`);
93
+ process.exitCode = 1;
94
+ return;
95
+ }
96
+ }
97
+ const result = mergeConfigs(configs);
98
+ if (outputPath) {
99
+ writeFileSync(outputPath, JSON.stringify(result.merged, null, 2));
100
+ console.log(`Merged config written to ${outputPath}`);
101
+ return;
102
+ }
103
+ if (format === "json") {
104
+ console.log(JSON.stringify(result, null, 2));
105
+ return;
106
+ }
107
+ console.log(`\nMerged Configuration (${result.sources.length} sources)`);
108
+ console.log("═".repeat(60));
109
+ console.log(` Sources: ${result.sources.join(", ")}`);
110
+ console.log(` Merged config:`);
111
+ console.log(` ${JSON.stringify(result.merged, null, 2).replace(/\n/g, "\n ")}`);
112
+ if (result.conflicts.length > 0) {
113
+ console.log(`\n Conflicts (${result.conflicts.length}):`);
114
+ for (const c of result.conflicts) {
115
+ console.log(` ${c.key}: ${c.values.join(" vs ")}`);
116
+ }
117
+ }
118
+ console.log("═".repeat(60));
119
+ }
120
+ //# sourceMappingURL=review-merge-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-merge-config.js","sourceRoot":"","sources":["../../src/commands/review-merge-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Review-onboard-wizard — Interactive onboarding wizard for new users.
3
+ */
4
+ export declare function runReviewOnboardWizard(argv: string[]): void;
5
+ //# sourceMappingURL=review-onboard-wizard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-onboard-wizard.d.ts","sourceRoot":"","sources":["../../src/commands/review-onboard-wizard.ts"],"names":[],"mappings":"AAAA;;GAEG;AAgDH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAgE3D"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Review-onboard-wizard — Interactive onboarding wizard for new users.
3
+ */
4
+ import { writeFileSync, existsSync, mkdirSync } from "fs";
5
+ import { dirname } from "path";
6
+ import { defaultRegistry } from "../judge-registry.js";
7
+ // ─── Wizard Logic ───────────────────────────────────────────────────────────
8
+ function generateProfile(team, language, focus) {
9
+ const judges = defaultRegistry.getJudges();
10
+ // suggest judges based on focus areas
11
+ const suggested = judges.filter((j) => {
12
+ const jName = `${j.id} ${j.domain}`.toLowerCase();
13
+ return focus.some((f) => jName.includes(f.toLowerCase()));
14
+ });
15
+ // pick preset based on focus
16
+ let preset = "default";
17
+ if (focus.includes("security"))
18
+ preset = "security-focused";
19
+ else if (focus.includes("performance"))
20
+ preset = "performance";
21
+ else if (focus.includes("quality"))
22
+ preset = "strict";
23
+ return {
24
+ version: 1,
25
+ team,
26
+ language,
27
+ focus,
28
+ preset,
29
+ suggestedJudges: suggested.map((j) => j.id).slice(0, 10),
30
+ configPath: ".judgesrc.json",
31
+ };
32
+ }
33
+ // ─── CLI ────────────────────────────────────────────────────────────────────
34
+ export function runReviewOnboardWizard(argv) {
35
+ const teamIdx = argv.indexOf("--team");
36
+ const langIdx = argv.indexOf("--language");
37
+ const focusIdx = argv.indexOf("--focus");
38
+ const outputIdx = argv.indexOf("--output");
39
+ const formatIdx = argv.indexOf("--format");
40
+ const team = teamIdx >= 0 ? argv[teamIdx + 1] : "default";
41
+ const language = langIdx >= 0 ? argv[langIdx + 1] : "typescript";
42
+ const focusArg = focusIdx >= 0 ? argv[focusIdx + 1] : "security,quality";
43
+ const outputPath = outputIdx >= 0 ? argv[outputIdx + 1] : undefined;
44
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
45
+ if (argv.includes("--help") || argv.includes("-h")) {
46
+ console.log(`
47
+ judges review-onboard-wizard — Onboarding wizard
48
+
49
+ Usage:
50
+ judges review-onboard-wizard [--team <name>] [--language <lang>]
51
+ [--focus <areas>] [--output <file>]
52
+ [--format table|json]
53
+
54
+ Options:
55
+ --team <name> Team name (default: default)
56
+ --language <lang> Primary language (default: typescript)
57
+ --focus <areas> Comma-separated focus areas (e.g., security,quality)
58
+ --output <path> Write config to file
59
+ --format <fmt> Output format: table (default), json
60
+ --help, -h Show this help
61
+ `);
62
+ return;
63
+ }
64
+ const focus = focusArg.split(",").map((f) => f.trim());
65
+ const profile = generateProfile(team, language, focus);
66
+ if (outputPath) {
67
+ const dir = dirname(outputPath);
68
+ if (!existsSync(dir)) {
69
+ mkdirSync(dir, { recursive: true });
70
+ }
71
+ writeFileSync(outputPath, JSON.stringify(profile, null, 2));
72
+ console.log(`Onboard profile written to ${outputPath}`);
73
+ return;
74
+ }
75
+ if (format === "json") {
76
+ console.log(JSON.stringify(profile, null, 2));
77
+ return;
78
+ }
79
+ console.log(`\nOnboarding Wizard`);
80
+ console.log("═".repeat(55));
81
+ console.log(` Team: ${profile.team}`);
82
+ console.log(` Language: ${profile.language}`);
83
+ console.log(` Focus: ${profile.focus.join(", ")}`);
84
+ console.log(` Preset: ${profile.preset}`);
85
+ console.log(` Config: ${profile.configPath}`);
86
+ console.log(`\n Suggested Judges (${profile.suggestedJudges.length}):`);
87
+ for (const j of profile.suggestedJudges) {
88
+ console.log(` - ${j}`);
89
+ }
90
+ console.log("═".repeat(55));
91
+ console.log("\nTo get started, run: judges eval --file <your-file>");
92
+ }
93
+ //# sourceMappingURL=review-onboard-wizard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-onboard-wizard.js","sourceRoot":"","sources":["../../src/commands/review-onboard-wizard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Review-parallel-run — Configure and summarize parallel review runs.
3
+ */
4
+ export declare function runReviewParallelRun(argv: string[]): void;
5
+ //# sourceMappingURL=review-parallel-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-parallel-run.d.ts","sourceRoot":"","sources":["../../src/commands/review-parallel-run.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoEH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA2EzD"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Review-parallel-run — Configure and summarize parallel review runs.
3
+ */
4
+ import { readFileSync, existsSync, readdirSync } from "fs";
5
+ // ─── Analysis ───────────────────────────────────────────────────────────────
6
+ function summarizeParallel(verdicts) {
7
+ const totalRuns = verdicts.length;
8
+ const scores = verdicts.map((v) => v.overallScore);
9
+ const avgScore = Math.round(scores.reduce((a, b) => a + b, 0) / totalRuns);
10
+ // variance
11
+ const variance = scores.reduce((sum, s) => sum + Math.pow(s - avgScore, 2), 0) / totalRuns;
12
+ const scoreVariance = Math.round(Math.sqrt(variance) * 10) / 10;
13
+ // verdict agreement
14
+ const verdictCounts = new Map();
15
+ for (const v of verdicts) {
16
+ verdictCounts.set(v.overallVerdict, (verdictCounts.get(v.overallVerdict) || 0) + 1);
17
+ }
18
+ const maxVerdictEntry = [...verdictCounts.entries()].sort((a, b) => b[1] - a[1])[0];
19
+ const consensusVerdict = maxVerdictEntry[0];
20
+ const verdictAgreement = Math.round((maxVerdictEntry[1] / totalRuns) * 100);
21
+ // finding consensus
22
+ const findingCounts = new Map();
23
+ for (const v of verdicts) {
24
+ const seen = new Set();
25
+ for (const f of v.findings) {
26
+ if (!seen.has(f.ruleId)) {
27
+ seen.add(f.ruleId);
28
+ const existing = findingCounts.get(f.ruleId);
29
+ if (existing) {
30
+ existing.count++;
31
+ }
32
+ else {
33
+ findingCounts.set(f.ruleId, { title: f.title, count: 1 });
34
+ }
35
+ }
36
+ }
37
+ }
38
+ const mergedFindings = [...findingCounts.entries()]
39
+ .map(([ruleId, data]) => ({
40
+ ruleId,
41
+ title: data.title,
42
+ agreedCount: data.count,
43
+ totalRuns,
44
+ }))
45
+ .sort((a, b) => b.agreedCount - a.agreedCount);
46
+ return { totalRuns, scores, avgScore, scoreVariance, consensusVerdict, verdictAgreement, mergedFindings };
47
+ }
48
+ // ─── CLI ────────────────────────────────────────────────────────────────────
49
+ export function runReviewParallelRun(argv) {
50
+ const dirIdx = argv.indexOf("--dir");
51
+ const formatIdx = argv.indexOf("--format");
52
+ const minAgreeIdx = argv.indexOf("--min-agree");
53
+ const dirPath = dirIdx >= 0 ? argv[dirIdx + 1] : undefined;
54
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
55
+ const minAgree = minAgreeIdx >= 0 ? parseInt(argv[minAgreeIdx + 1], 10) : 1;
56
+ if (argv.includes("--help") || argv.includes("-h")) {
57
+ console.log(`
58
+ judges review-parallel-run — Summarize parallel review runs
59
+
60
+ Usage:
61
+ judges review-parallel-run --dir <verdicts-dir> [--min-agree <n>]
62
+ [--format table|json]
63
+
64
+ Options:
65
+ --dir <path> Directory of verdict JSON files (required)
66
+ --min-agree <n> Minimum agreement count to include finding (default: 1)
67
+ --format <fmt> Output format: table (default), json
68
+ --help, -h Show this help
69
+ `);
70
+ return;
71
+ }
72
+ if (!dirPath) {
73
+ console.error("Error: --dir required");
74
+ process.exitCode = 1;
75
+ return;
76
+ }
77
+ if (!existsSync(dirPath)) {
78
+ console.error(`Error: not found: ${dirPath}`);
79
+ process.exitCode = 1;
80
+ return;
81
+ }
82
+ const files = readdirSync(dirPath).filter((f) => f.endsWith(".json"));
83
+ const verdicts = [];
84
+ for (const file of files) {
85
+ try {
86
+ verdicts.push(JSON.parse(readFileSync(`${dirPath}/${file}`, "utf-8")));
87
+ }
88
+ catch {
89
+ // skip
90
+ }
91
+ }
92
+ if (verdicts.length === 0) {
93
+ console.error("Error: no valid verdict files found");
94
+ process.exitCode = 1;
95
+ return;
96
+ }
97
+ const summary = summarizeParallel(verdicts);
98
+ const filtered = summary.mergedFindings.filter((f) => f.agreedCount >= minAgree);
99
+ if (format === "json") {
100
+ console.log(JSON.stringify({ ...summary, mergedFindings: filtered }, null, 2));
101
+ return;
102
+ }
103
+ console.log(`\nParallel Run Summary (${summary.totalRuns} runs)`);
104
+ console.log("═".repeat(70));
105
+ console.log(` Avg Score: ${summary.avgScore} | Variance: ${summary.scoreVariance}`);
106
+ console.log(` Consensus: ${summary.consensusVerdict} (${summary.verdictAgreement}% agreement)`);
107
+ console.log("─".repeat(70));
108
+ console.log(`${"Rule".padEnd(22)} ${"Agreement".padEnd(14)} Title`);
109
+ console.log("─".repeat(70));
110
+ for (const f of filtered.slice(0, 20)) {
111
+ const rule = f.ruleId.length > 20 ? f.ruleId.slice(0, 20) + "…" : f.ruleId;
112
+ const title = f.title.length > 30 ? f.title.slice(0, 30) + "…" : f.title;
113
+ console.log(`${rule.padEnd(22)} ${f.agreedCount}/${f.totalRuns}${" ".repeat(10)} ${title}`);
114
+ }
115
+ console.log("═".repeat(70));
116
+ }
117
+ //# sourceMappingURL=review-parallel-run.js.map