@kevinrabun/judges 3.83.0 → 3.84.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-cluster-analysis.d.ts +5 -0
  6. package/dist/commands/finding-cluster-analysis.d.ts.map +1 -0
  7. package/dist/commands/finding-cluster-analysis.js +134 -0
  8. package/dist/commands/finding-cluster-analysis.js.map +1 -0
  9. package/dist/commands/finding-evidence-chain.d.ts +5 -0
  10. package/dist/commands/finding-evidence-chain.d.ts.map +1 -0
  11. package/dist/commands/finding-evidence-chain.js +148 -0
  12. package/dist/commands/finding-evidence-chain.js.map +1 -0
  13. package/dist/commands/finding-fix-priority.d.ts +5 -0
  14. package/dist/commands/finding-fix-priority.d.ts.map +1 -0
  15. package/dist/commands/finding-fix-priority.js +99 -0
  16. package/dist/commands/finding-fix-priority.js.map +1 -0
  17. package/dist/commands/finding-noise-filter.d.ts +8 -0
  18. package/dist/commands/finding-noise-filter.d.ts.map +1 -0
  19. package/dist/commands/finding-noise-filter.js +141 -0
  20. package/dist/commands/finding-noise-filter.js.map +1 -0
  21. package/dist/commands/finding-trend-report.d.ts +5 -0
  22. package/dist/commands/finding-trend-report.d.ts.map +1 -0
  23. package/dist/commands/finding-trend-report.js +108 -0
  24. package/dist/commands/finding-trend-report.js.map +1 -0
  25. package/dist/commands/review-commit-hook.d.ts +8 -0
  26. package/dist/commands/review-commit-hook.d.ts.map +1 -0
  27. package/dist/commands/review-commit-hook.js +135 -0
  28. package/dist/commands/review-commit-hook.js.map +1 -0
  29. package/dist/commands/review-file-complexity.d.ts +5 -0
  30. package/dist/commands/review-file-complexity.d.ts.map +1 -0
  31. package/dist/commands/review-file-complexity.js +138 -0
  32. package/dist/commands/review-file-complexity.js.map +1 -0
  33. package/dist/commands/review-quota-check.d.ts +5 -0
  34. package/dist/commands/review-quota-check.d.ts.map +1 -0
  35. package/dist/commands/review-quota-check.js +98 -0
  36. package/dist/commands/review-quota-check.js.map +1 -0
  37. package/dist/commands/review-session-save.d.ts +5 -0
  38. package/dist/commands/review-session-save.d.ts.map +1 -0
  39. package/dist/commands/review-session-save.js +174 -0
  40. package/dist/commands/review-session-save.js.map +1 -0
  41. package/package.json +1 -1
  42. package/server.json +2 -2
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Finding-trend-report — Generate trend reports from historical findings.
3
+ */
4
+ import { readFileSync, existsSync, readdirSync } from "fs";
5
+ import { join } from "path";
6
+ // ─── Helpers ────────────────────────────────────────────────────────────────
7
+ function loadVerdictHistory(dir) {
8
+ if (!existsSync(dir))
9
+ return [];
10
+ const results = [];
11
+ const files = readdirSync(dir);
12
+ for (const f of files) {
13
+ if (!String(f).endsWith(".json"))
14
+ continue;
15
+ try {
16
+ const data = JSON.parse(readFileSync(join(dir, String(f)), "utf-8"));
17
+ if (data && data.findings) {
18
+ const date = data.timestamp || String(f).replace(".json", "");
19
+ results.push({ date, verdict: data });
20
+ }
21
+ }
22
+ catch {
23
+ /* skip */
24
+ }
25
+ }
26
+ return results.sort((a, b) => a.date.localeCompare(b.date));
27
+ }
28
+ function buildTrend(history) {
29
+ return history.map((h) => ({
30
+ date: h.date,
31
+ totalFindings: h.verdict.findings.length,
32
+ criticalCount: h.verdict.criticalCount,
33
+ highCount: h.verdict.highCount,
34
+ score: h.verdict.overallScore,
35
+ ruleCount: new Set(h.verdict.findings.map((f) => f.ruleId)).size,
36
+ }));
37
+ }
38
+ // ─── CLI ────────────────────────────────────────────────────────────────────
39
+ export function runFindingTrendReport(argv) {
40
+ const dirIdx = argv.indexOf("--dir");
41
+ const formatIdx = argv.indexOf("--format");
42
+ const lastIdx = argv.indexOf("--last");
43
+ const dir = dirIdx >= 0 ? argv[dirIdx + 1] : join(process.cwd(), ".judges", "verdicts");
44
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
45
+ const last = lastIdx >= 0 ? parseInt(argv[lastIdx + 1], 10) : 0;
46
+ if (argv.includes("--help") || argv.includes("-h")) {
47
+ console.log(`
48
+ judges finding-trend-report — Generate trend reports
49
+
50
+ Usage:
51
+ judges finding-trend-report [--dir <path>] [--format table|json|chart]
52
+ [--last <n>]
53
+
54
+ Options:
55
+ --dir <path> Directory with historical verdict files
56
+ --format <fmt> Output format: table (default), json, chart
57
+ --last <n> Show only last N data points
58
+ --help, -h Show this help
59
+ `);
60
+ return;
61
+ }
62
+ const history = loadVerdictHistory(dir);
63
+ if (history.length === 0) {
64
+ console.log("No verdict history found.");
65
+ return;
66
+ }
67
+ let trend = buildTrend(history);
68
+ if (last > 0)
69
+ trend = trend.slice(-last);
70
+ if (format === "json") {
71
+ console.log(JSON.stringify(trend, null, 2));
72
+ return;
73
+ }
74
+ if (format === "chart") {
75
+ console.log("\nFinding Trend (ASCII Chart)");
76
+ console.log("═".repeat(60));
77
+ const maxFindings = Math.max(...trend.map((t) => t.totalFindings), 1);
78
+ for (const t of trend) {
79
+ const barLen = Math.round((t.totalFindings / maxFindings) * 40);
80
+ const bar = "█".repeat(barLen);
81
+ const dateStr = t.date.slice(0, 10).padEnd(12);
82
+ console.log(`${dateStr} ${bar} ${t.totalFindings}`);
83
+ }
84
+ console.log("═".repeat(60));
85
+ return;
86
+ }
87
+ console.log(`\nFinding Trend Report (${trend.length} data points)`);
88
+ console.log("═".repeat(70));
89
+ console.log(`${"Date".padEnd(22)} ${"Findings".padEnd(10)} ${"Crit".padEnd(6)} ${"High".padEnd(6)} ${"Score".padEnd(7)} Rules`);
90
+ console.log("─".repeat(70));
91
+ for (const t of trend) {
92
+ const dateStr = t.date.slice(0, 19).padEnd(22);
93
+ console.log(`${dateStr} ${String(t.totalFindings).padEnd(10)} ${String(t.criticalCount).padEnd(6)} ` +
94
+ `${String(t.highCount).padEnd(6)} ${String(t.score).padEnd(7)} ${t.ruleCount}`);
95
+ }
96
+ if (trend.length >= 2) {
97
+ const first = trend[0];
98
+ const latest = trend[trend.length - 1];
99
+ const findingDelta = latest.totalFindings - first.totalFindings;
100
+ const scoreDelta = latest.score - first.score;
101
+ console.log("─".repeat(70));
102
+ const fd = findingDelta >= 0 ? `+${findingDelta}` : `${findingDelta}`;
103
+ const sd = scoreDelta >= 0 ? `+${scoreDelta}` : `${scoreDelta}`;
104
+ console.log(`Trend: findings ${fd}, score ${sd}`);
105
+ }
106
+ console.log("═".repeat(70));
107
+ }
108
+ //# sourceMappingURL=finding-trend-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-trend-report.js","sourceRoot":"","sources":["../../src/commands/finding-trend-report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Review-commit-hook — Generate git commit hook configuration for Judges.
3
+ *
4
+ * Creates pre-commit or pre-push hook scripts that automatically
5
+ * run Judges review on staged/changed files.
6
+ */
7
+ export declare function runReviewCommitHook(argv: string[]): void;
8
+ //# sourceMappingURL=review-commit-hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-commit-hook.d.ts","sourceRoot":"","sources":["../../src/commands/review-commit-hook.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqEH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA+DxD"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Review-commit-hook — Generate git commit hook configuration for Judges.
3
+ *
4
+ * Creates pre-commit or pre-push hook scripts that automatically
5
+ * run Judges review on staged/changed files.
6
+ */
7
+ import { writeFileSync, existsSync, mkdirSync, chmodSync } from "fs";
8
+ import { join } from "path";
9
+ // ─── Helpers ────────────────────────────────────────────────────────────────
10
+ const PRE_COMMIT_SCRIPT = `#!/bin/sh
11
+ # Judges Panel pre-commit hook
12
+ # Runs code review on staged files
13
+
14
+ STAGED=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\\.(ts|js|tsx|jsx|py|java|go|rs|cs|cpp|c|rb|php)$')
15
+
16
+ if [ -z "$STAGED" ]; then
17
+ exit 0
18
+ fi
19
+
20
+ echo "Running Judges review on staged files..."
21
+
22
+ FAILED=0
23
+ for FILE in $STAGED; do
24
+ npx judges eval --file "$FILE" --fail-on-findings 2>/dev/null
25
+ if [ $? -ne 0 ]; then
26
+ FAILED=1
27
+ fi
28
+ done
29
+
30
+ if [ $FAILED -ne 0 ]; then
31
+ echo ""
32
+ echo "Judges found issues. Fix them or use --no-verify to skip."
33
+ exit 1
34
+ fi
35
+
36
+ exit 0
37
+ `;
38
+ const PRE_PUSH_SCRIPT = `#!/bin/sh
39
+ # Judges Panel pre-push hook
40
+ # Runs code review on changed files before push
41
+
42
+ CHANGED=$(git diff --name-only HEAD~1 | grep -E '\\.(ts|js|tsx|jsx|py|java|go|rs|cs|cpp|c|rb|php)$')
43
+
44
+ if [ -z "$CHANGED" ]; then
45
+ exit 0
46
+ fi
47
+
48
+ echo "Running Judges review before push..."
49
+
50
+ FAILED=0
51
+ for FILE in $CHANGED; do
52
+ if [ -f "$FILE" ]; then
53
+ npx judges eval --file "$FILE" --fail-on-findings 2>/dev/null
54
+ if [ $? -ne 0 ]; then
55
+ FAILED=1
56
+ fi
57
+ fi
58
+ done
59
+
60
+ if [ $FAILED -ne 0 ]; then
61
+ echo ""
62
+ echo "Judges found issues. Fix or use --no-verify to skip."
63
+ exit 1
64
+ fi
65
+
66
+ exit 0
67
+ `;
68
+ // ─── CLI ────────────────────────────────────────────────────────────────────
69
+ export function runReviewCommitHook(argv) {
70
+ const sub = argv[0];
71
+ if (!sub || sub === "--help" || sub === "-h") {
72
+ console.log(`
73
+ judges review-commit-hook — Set up git hooks for Judges
74
+
75
+ Usage:
76
+ judges review-commit-hook install [--type pre-commit|pre-push|both]
77
+ judges review-commit-hook show [--type pre-commit|pre-push]
78
+ judges review-commit-hook remove [--type pre-commit|pre-push|both]
79
+
80
+ Options:
81
+ --type <hook> Hook type (default: pre-commit)
82
+ --help, -h Show this help
83
+ `);
84
+ return;
85
+ }
86
+ const args = argv.slice(1);
87
+ const typeIdx = args.indexOf("--type");
88
+ const hookType = typeIdx >= 0 ? args[typeIdx + 1] : "pre-commit";
89
+ if (sub === "install") {
90
+ const hooksDir = join(process.cwd(), ".git", "hooks");
91
+ if (!existsSync(join(process.cwd(), ".git"))) {
92
+ console.error("Error: not a git repository");
93
+ process.exitCode = 1;
94
+ return;
95
+ }
96
+ if (!existsSync(hooksDir))
97
+ mkdirSync(hooksDir, { recursive: true });
98
+ const types = hookType === "both" ? ["pre-commit", "pre-push"] : [hookType];
99
+ for (const t of types) {
100
+ const script = t === "pre-push" ? PRE_PUSH_SCRIPT : PRE_COMMIT_SCRIPT;
101
+ const hookPath = join(hooksDir, t);
102
+ writeFileSync(hookPath, script);
103
+ try {
104
+ chmodSync(hookPath, 0o755);
105
+ }
106
+ catch {
107
+ /* Windows doesn't need chmod */
108
+ }
109
+ console.log(`Installed ${t} hook: ${hookPath}`);
110
+ }
111
+ }
112
+ else if (sub === "show") {
113
+ const script = hookType === "pre-push" ? PRE_PUSH_SCRIPT : PRE_COMMIT_SCRIPT;
114
+ console.log(script);
115
+ }
116
+ else if (sub === "remove") {
117
+ const hooksDir = join(process.cwd(), ".git", "hooks");
118
+ const types = hookType === "both" ? ["pre-commit", "pre-push"] : [hookType];
119
+ for (const t of types) {
120
+ const hookPath = join(hooksDir, t);
121
+ if (existsSync(hookPath)) {
122
+ writeFileSync(hookPath, "#!/bin/sh\nexit 0\n");
123
+ console.log(`Removed ${t} hook`);
124
+ }
125
+ else {
126
+ console.log(`No ${t} hook found`);
127
+ }
128
+ }
129
+ }
130
+ else {
131
+ console.error(`Unknown subcommand: ${sub}. Use --help for usage.`);
132
+ process.exitCode = 1;
133
+ }
134
+ }
135
+ //# sourceMappingURL=review-commit-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-commit-hook.js","sourceRoot":"","sources":["../../src/commands/review-commit-hook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Review-file-complexity — Analyze file complexity metrics.
3
+ */
4
+ export declare function runReviewFileComplexity(argv: string[]): void;
5
+ //# sourceMappingURL=review-file-complexity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-file-complexity.d.ts","sourceRoot":"","sources":["../../src/commands/review-file-complexity.ts"],"names":[],"mappings":"AAAA;;GAEG;AAmGH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAsE5D"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Review-file-complexity — Analyze file complexity metrics.
3
+ */
4
+ import { readFileSync, existsSync } from "fs";
5
+ // ─── Helpers ────────────────────────────────────────────────────────────────
6
+ function analyzeComplexity(filePath) {
7
+ const content = readFileSync(filePath, "utf-8");
8
+ const lines = content.split("\n");
9
+ const totalLines = lines.length;
10
+ let codeLines = 0;
11
+ let blankLines = 0;
12
+ let commentLines = 0;
13
+ let functions = 0;
14
+ let maxIndentDepth = 0;
15
+ let totalLineLength = 0;
16
+ const funcPatterns = [/\bfunction\b/, /=>\s*[{(]/, /\bdef\b/, /\bfunc\b/, /\bfn\b/];
17
+ for (const line of lines) {
18
+ const trimmed = line.trim();
19
+ if (trimmed.length === 0) {
20
+ blankLines++;
21
+ continue;
22
+ }
23
+ if (trimmed.startsWith("//") || trimmed.startsWith("#") || trimmed.startsWith("*") || trimmed.startsWith("/*")) {
24
+ commentLines++;
25
+ continue;
26
+ }
27
+ codeLines++;
28
+ totalLineLength += trimmed.length;
29
+ // calculate indent depth
30
+ const indent = line.length - line.trimStart().length;
31
+ const depth = Math.floor(indent / 2);
32
+ if (depth > maxIndentDepth)
33
+ maxIndentDepth = depth;
34
+ // count functions
35
+ for (const p of funcPatterns) {
36
+ if (p.test(trimmed)) {
37
+ functions++;
38
+ break;
39
+ }
40
+ }
41
+ }
42
+ const avgLineLength = codeLines > 0 ? Math.round(totalLineLength / codeLines) : 0;
43
+ // Compute complexity score (0-100)
44
+ let score = 0;
45
+ if (totalLines > 300)
46
+ score += 15;
47
+ else if (totalLines > 150)
48
+ score += 8;
49
+ if (functions > 20)
50
+ score += 20;
51
+ else if (functions > 10)
52
+ score += 10;
53
+ if (maxIndentDepth > 8)
54
+ score += 25;
55
+ else if (maxIndentDepth > 5)
56
+ score += 15;
57
+ else if (maxIndentDepth > 3)
58
+ score += 5;
59
+ if (avgLineLength > 100)
60
+ score += 15;
61
+ else if (avgLineLength > 80)
62
+ score += 8;
63
+ if (commentLines === 0 && codeLines > 50)
64
+ score += 10;
65
+ if (codeLines > 0 && blankLines / codeLines < 0.05)
66
+ score += 5;
67
+ const risk = score >= 60 ? "critical" : score >= 40 ? "high" : score >= 20 ? "medium" : "low";
68
+ return {
69
+ filePath,
70
+ lines: totalLines,
71
+ codeLines,
72
+ blankLines,
73
+ commentLines,
74
+ functions,
75
+ maxIndentDepth,
76
+ avgLineLength,
77
+ complexityScore: score,
78
+ risk,
79
+ };
80
+ }
81
+ // ─── CLI ────────────────────────────────────────────────────────────────────
82
+ export function runReviewFileComplexity(argv) {
83
+ const formatIdx = argv.indexOf("--format");
84
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
85
+ if (argv.includes("--help") || argv.includes("-h")) {
86
+ console.log(`
87
+ judges review-file-complexity — Analyze file complexity
88
+
89
+ Usage:
90
+ judges review-file-complexity <file1> [file2 ...] [--format table|json]
91
+
92
+ Options:
93
+ --format <fmt> Output format: table (default), json
94
+ --help, -h Show this help
95
+ `);
96
+ return;
97
+ }
98
+ const files = argv.filter((a) => !a.startsWith("--") && (argv.indexOf(a) === 0 || argv[argv.indexOf(a) - 1] !== "--format"));
99
+ if (files.length === 0) {
100
+ console.error("Error: provide one or more file paths");
101
+ process.exitCode = 1;
102
+ return;
103
+ }
104
+ const results = [];
105
+ for (const f of files) {
106
+ if (!existsSync(f)) {
107
+ console.error(`Warning: not found: ${f}`);
108
+ continue;
109
+ }
110
+ try {
111
+ results.push(analyzeComplexity(f));
112
+ }
113
+ catch {
114
+ console.error(`Warning: cannot read: ${f}`);
115
+ }
116
+ }
117
+ if (results.length === 0) {
118
+ console.error("Error: no valid files");
119
+ process.exitCode = 1;
120
+ return;
121
+ }
122
+ if (format === "json") {
123
+ console.log(JSON.stringify(results, null, 2));
124
+ return;
125
+ }
126
+ console.log(`\nFile Complexity Analysis (${results.length} files)`);
127
+ console.log("═".repeat(80));
128
+ console.log(`${"File".padEnd(35)} ${"Lines".padEnd(7)} ${"Code".padEnd(7)} ${"Funcs".padEnd(7)} ${"Depth".padEnd(7)} ${"Score".padEnd(7)} Risk`);
129
+ console.log("─".repeat(80));
130
+ for (const r of results.sort((a, b) => b.complexityScore - a.complexityScore)) {
131
+ const name = r.filePath.length > 33 ? "…" + r.filePath.slice(-32) : r.filePath;
132
+ console.log(`${name.padEnd(35)} ${String(r.lines).padEnd(7)} ${String(r.codeLines).padEnd(7)} ${String(r.functions).padEnd(7)} ${String(r.maxIndentDepth).padEnd(7)} ${String(r.complexityScore).padEnd(7)} ${r.risk}`);
133
+ }
134
+ console.log("═".repeat(80));
135
+ const avgScore = Math.round(results.reduce((s, r) => s + r.complexityScore, 0) / results.length);
136
+ console.log(`\nAverage complexity score: ${avgScore}`);
137
+ }
138
+ //# sourceMappingURL=review-file-complexity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-file-complexity.js","sourceRoot":"","sources":["../../src/commands/review-file-complexity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Review-quota-check — Check review quotas and rate limits.
3
+ */
4
+ export declare function runReviewQuotaCheck(argv: string[]): void;
5
+ //# sourceMappingURL=review-quota-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-quota-check.d.ts","sourceRoot":"","sources":["../../src/commands/review-quota-check.ts"],"names":[],"mappings":"AAAA;;GAEG;AAqEH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAiDxD"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Review-quota-check — Check review quotas and rate limits.
3
+ */
4
+ import { readFileSync, existsSync, readdirSync } from "fs";
5
+ // ─── Helpers ────────────────────────────────────────────────────────────────
6
+ function todayStr() {
7
+ return new Date().toISOString().slice(0, 10);
8
+ }
9
+ function checkQuota(dir, limit) {
10
+ const today = todayStr();
11
+ const recentReviews = [];
12
+ let filesReviewed = 0;
13
+ if (!existsSync(dir)) {
14
+ return {
15
+ directory: dir,
16
+ filesReviewed: 0,
17
+ dailyLimit: limit,
18
+ remainingToday: limit,
19
+ isOverLimit: false,
20
+ todayDate: today,
21
+ recentReviews,
22
+ };
23
+ }
24
+ const files = readdirSync(dir);
25
+ for (const f of files) {
26
+ if (!f.endsWith(".json"))
27
+ continue;
28
+ const full = dir.endsWith("/") || dir.endsWith("\\") ? dir + f : dir + "/" + f;
29
+ try {
30
+ const raw = readFileSync(full, "utf-8");
31
+ const data = JSON.parse(raw);
32
+ const ts = data.timestamp || data.date || "";
33
+ if (typeof ts === "string" && ts.startsWith(today)) {
34
+ filesReviewed++;
35
+ recentReviews.push(f);
36
+ }
37
+ }
38
+ catch {
39
+ // skip invalid
40
+ }
41
+ }
42
+ return {
43
+ directory: dir,
44
+ filesReviewed,
45
+ dailyLimit: limit,
46
+ remainingToday: Math.max(0, limit - filesReviewed),
47
+ isOverLimit: filesReviewed >= limit,
48
+ todayDate: today,
49
+ recentReviews,
50
+ };
51
+ }
52
+ // ─── CLI ────────────────────────────────────────────────────────────────────
53
+ export function runReviewQuotaCheck(argv) {
54
+ const dirIdx = argv.indexOf("--dir");
55
+ const limitIdx = argv.indexOf("--limit");
56
+ const formatIdx = argv.indexOf("--format");
57
+ const dir = dirIdx >= 0 ? argv[dirIdx + 1] : ".judges/verdicts";
58
+ const limit = limitIdx >= 0 ? parseInt(argv[limitIdx + 1], 10) : 100;
59
+ const format = formatIdx >= 0 ? argv[formatIdx + 1] : "table";
60
+ if (argv.includes("--help") || argv.includes("-h")) {
61
+ console.log(`
62
+ judges review-quota-check — Check review quotas and limits
63
+
64
+ Usage:
65
+ judges review-quota-check [--dir <path>] [--limit <n>] [--format table|json]
66
+
67
+ Options:
68
+ --dir <path> Verdict directory (default: .judges/verdicts)
69
+ --limit <n> Daily review limit (default: 100)
70
+ --format <fmt> Output format: table (default), json
71
+ --help, -h Show this help
72
+ `);
73
+ return;
74
+ }
75
+ const status = checkQuota(dir, limit);
76
+ if (format === "json") {
77
+ console.log(JSON.stringify(status, null, 2));
78
+ return;
79
+ }
80
+ console.log(`\nReview Quota Status (${status.todayDate})`);
81
+ console.log("═".repeat(50));
82
+ console.log(` Directory: ${status.directory}`);
83
+ console.log(` Reviews today: ${status.filesReviewed}`);
84
+ console.log(` Daily limit: ${status.dailyLimit}`);
85
+ console.log(` Remaining: ${status.remainingToday}`);
86
+ console.log(` Status: ${status.isOverLimit ? "OVER LIMIT" : "OK"}`);
87
+ console.log("═".repeat(50));
88
+ if (status.recentReviews.length > 0) {
89
+ console.log("\nRecent reviews today:");
90
+ for (const r of status.recentReviews.slice(0, 10)) {
91
+ console.log(` - ${r}`);
92
+ }
93
+ if (status.recentReviews.length > 10) {
94
+ console.log(` ... and ${status.recentReviews.length - 10} more`);
95
+ }
96
+ }
97
+ }
98
+ //# sourceMappingURL=review-quota-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-quota-check.js","sourceRoot":"","sources":["../../src/commands/review-quota-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Review-session-save — Save and restore review sessions.
3
+ */
4
+ export declare function runReviewSessionSave(argv: string[]): void;
5
+ //# sourceMappingURL=review-session-save.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-session-save.d.ts","sourceRoot":"","sources":["../../src/commands/review-session-save.ts"],"names":[],"mappings":"AAAA;;GAEG;AAmDH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAuJzD"}