@kevinrabun/judges 3.74.0 → 3.75.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 (38) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +56 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/finding-category.d.ts +5 -0
  6. package/dist/commands/finding-category.d.ts.map +1 -0
  7. package/dist/commands/finding-category.js +110 -0
  8. package/dist/commands/finding-category.js.map +1 -0
  9. package/dist/commands/finding-priority-queue.d.ts +5 -0
  10. package/dist/commands/finding-priority-queue.d.ts.map +1 -0
  11. package/dist/commands/finding-priority-queue.js +132 -0
  12. package/dist/commands/finding-priority-queue.js.map +1 -0
  13. package/dist/commands/finding-remediation-plan.d.ts +5 -0
  14. package/dist/commands/finding-remediation-plan.d.ts.map +1 -0
  15. package/dist/commands/finding-remediation-plan.js +108 -0
  16. package/dist/commands/finding-remediation-plan.js.map +1 -0
  17. package/dist/commands/review-checklist.d.ts +5 -0
  18. package/dist/commands/review-checklist.d.ts.map +1 -0
  19. package/dist/commands/review-checklist.js +145 -0
  20. package/dist/commands/review-checklist.js.map +1 -0
  21. package/dist/commands/review-config-validate.d.ts +5 -0
  22. package/dist/commands/review-config-validate.d.ts.map +1 -0
  23. package/dist/commands/review-config-validate.js +111 -0
  24. package/dist/commands/review-config-validate.js.map +1 -0
  25. package/dist/commands/review-diff-annotate.d.ts +5 -0
  26. package/dist/commands/review-diff-annotate.d.ts.map +1 -0
  27. package/dist/commands/review-diff-annotate.js +105 -0
  28. package/dist/commands/review-diff-annotate.js.map +1 -0
  29. package/dist/commands/review-lock.d.ts +5 -0
  30. package/dist/commands/review-lock.d.ts.map +1 -0
  31. package/dist/commands/review-lock.js +108 -0
  32. package/dist/commands/review-lock.js.map +1 -0
  33. package/dist/commands/review-rate-limit.d.ts +5 -0
  34. package/dist/commands/review-rate-limit.d.ts.map +1 -0
  35. package/dist/commands/review-rate-limit.js +131 -0
  36. package/dist/commands/review-rate-limit.js.map +1 -0
  37. package/package.json +1 -1
  38. package/server.json +2 -2
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Review-config-validate — Validate review configuration files.
3
+ */
4
+ import { readFileSync, existsSync } from "fs";
5
+ // ─── CLI ────────────────────────────────────────────────────────────────────
6
+ export function runReviewConfigValidate(argv) {
7
+ if (argv.includes("--help") || argv.includes("-h")) {
8
+ console.log(`
9
+ judges review-config-validate — Validate review configuration files
10
+
11
+ Usage:
12
+ judges review-config-validate
13
+ judges review-config-validate --file .judgesrc
14
+ judges review-config-validate --strict
15
+
16
+ Options:
17
+ --file <path> Config file to validate (default: .judgesrc)
18
+ --strict Enable strict validation
19
+ --format json JSON output
20
+ --help, -h Show this help
21
+
22
+ Checks configuration for common errors and best practices.
23
+ `);
24
+ return;
25
+ }
26
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
27
+ const configPath = argv.find((_a, i) => argv[i - 1] === "--file") || ".judgesrc";
28
+ const strict = argv.includes("--strict");
29
+ if (!existsSync(configPath)) {
30
+ console.log(`Config file not found: ${configPath}`);
31
+ console.log("Create one with 'judges init' or specify --file.");
32
+ return;
33
+ }
34
+ let config;
35
+ try {
36
+ config = JSON.parse(readFileSync(configPath, "utf-8"));
37
+ }
38
+ catch {
39
+ console.log(`Failed to parse config: ${configPath}`);
40
+ return;
41
+ }
42
+ const issues = [];
43
+ // Check preset
44
+ const validPresets = [
45
+ "strict",
46
+ "lenient",
47
+ "security-only",
48
+ "startup",
49
+ "compliance",
50
+ "performance",
51
+ "react",
52
+ "express",
53
+ "fastapi",
54
+ "django",
55
+ "spring-boot",
56
+ "rails",
57
+ "nextjs",
58
+ ];
59
+ if (config.preset && typeof config.preset === "string" && !validPresets.includes(config.preset)) {
60
+ issues.push({ field: "preset", message: `Unknown preset "${config.preset}"`, severity: "warning" });
61
+ }
62
+ // Check disabledJudges
63
+ if (config.disabledJudges && !Array.isArray(config.disabledJudges)) {
64
+ issues.push({ field: "disabledJudges", message: "Should be an array of judge IDs", severity: "error" });
65
+ }
66
+ // Check disabledRules
67
+ if (config.disabledRules && !Array.isArray(config.disabledRules)) {
68
+ issues.push({ field: "disabledRules", message: "Should be an array of rule IDs", severity: "error" });
69
+ }
70
+ // Check minSeverity
71
+ const validSeverities = ["critical", "high", "medium", "low", "info"];
72
+ if (config.minSeverity && typeof config.minSeverity === "string" && !validSeverities.includes(config.minSeverity)) {
73
+ issues.push({ field: "minSeverity", message: `Invalid severity "${config.minSeverity}"`, severity: "error" });
74
+ }
75
+ // Check ruleOverrides
76
+ if (config.ruleOverrides && typeof config.ruleOverrides !== "object") {
77
+ issues.push({ field: "ruleOverrides", message: "Should be an object", severity: "error" });
78
+ }
79
+ // Strict checks
80
+ if (strict) {
81
+ if (!config.preset) {
82
+ issues.push({ field: "preset", message: "No preset specified (recommended)", severity: "warning" });
83
+ }
84
+ if (Array.isArray(config.disabledJudges) && config.disabledJudges.length > 10) {
85
+ issues.push({
86
+ field: "disabledJudges",
87
+ message: "Many judges disabled — consider using a preset instead",
88
+ severity: "warning",
89
+ });
90
+ }
91
+ }
92
+ const errors = issues.filter((i) => i.severity === "error");
93
+ const warnings = issues.filter((i) => i.severity === "warning");
94
+ if (format === "json") {
95
+ console.log(JSON.stringify({ valid: errors.length === 0, errors: errors.length, warnings: warnings.length, issues }, null, 2));
96
+ return;
97
+ }
98
+ if (issues.length === 0) {
99
+ console.log(`Config valid: ${configPath}`);
100
+ return;
101
+ }
102
+ console.log(`\nConfig Validation: ${configPath}`);
103
+ console.log("─".repeat(50));
104
+ for (const i of issues) {
105
+ const icon = i.severity === "error" ? "ERROR" : "WARN";
106
+ console.log(` [${icon}] ${i.field}: ${i.message}`);
107
+ }
108
+ console.log("─".repeat(50));
109
+ console.log(`${errors.length} error(s), ${warnings.length} warning(s).`);
110
+ }
111
+ //# sourceMappingURL=review-config-validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-config-validate.js","sourceRoot":"","sources":["../../src/commands/review-config-validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Review-diff-annotate — Annotate diff hunks with review findings.
3
+ */
4
+ export declare function runReviewDiffAnnotate(argv: string[]): void;
5
+ //# sourceMappingURL=review-diff-annotate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-diff-annotate.d.ts","sourceRoot":"","sources":["../../src/commands/review-diff-annotate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA0H1D"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Review-diff-annotate — Annotate diff hunks with review findings.
3
+ */
4
+ import { readFileSync, existsSync } from "fs";
5
+ // ─── CLI ────────────────────────────────────────────────────────────────────
6
+ export function runReviewDiffAnnotate(argv) {
7
+ if (argv.includes("--help") || argv.includes("-h")) {
8
+ console.log(`
9
+ judges review-diff-annotate — Annotate diff hunks with review findings
10
+
11
+ Usage:
12
+ judges review-diff-annotate --diff changes.diff --results results.json
13
+
14
+ Options:
15
+ --diff <path> Path to unified diff file
16
+ --results <path> Path to review result JSON
17
+ --format json JSON output
18
+ --help, -h Show this help
19
+
20
+ Overlays review findings onto diff output, showing which changed
21
+ lines have associated findings.
22
+ `);
23
+ return;
24
+ }
25
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
26
+ const diffPath = argv.find((_a, i) => argv[i - 1] === "--diff") || "";
27
+ const resultsPath = argv.find((_a, i) => argv[i - 1] === "--results") || "";
28
+ if (!diffPath || !resultsPath) {
29
+ console.log("Specify --diff and --results paths.");
30
+ return;
31
+ }
32
+ if (!existsSync(diffPath)) {
33
+ console.log(`Diff file not found: ${diffPath}`);
34
+ return;
35
+ }
36
+ if (!existsSync(resultsPath)) {
37
+ console.log(`Results file not found: ${resultsPath}`);
38
+ return;
39
+ }
40
+ const diffContent = readFileSync(diffPath, "utf-8");
41
+ let data;
42
+ try {
43
+ data = JSON.parse(readFileSync(resultsPath, "utf-8"));
44
+ }
45
+ catch {
46
+ console.log(`Failed to parse results: ${resultsPath}`);
47
+ return;
48
+ }
49
+ const findings = Array.isArray(data.findings) ? data.findings : [];
50
+ const lineMap = new Map();
51
+ for (const f of findings) {
52
+ if (Array.isArray(f.lineNumbers)) {
53
+ for (const ln of f.lineNumbers) {
54
+ const existing = lineMap.get(ln) || [];
55
+ existing.push(f);
56
+ lineMap.set(ln, existing);
57
+ }
58
+ }
59
+ }
60
+ // Parse diff and annotate
61
+ const diffLines = diffContent.split("\n");
62
+ const annotated = [];
63
+ let currentLine = 0;
64
+ for (const line of diffLines) {
65
+ // Parse hunk header for line numbers
66
+ const hunkMatch = line.match(/^@@\s+-\d+(?:,\d+)?\s+\+(\d+)/);
67
+ if (hunkMatch) {
68
+ currentLine = parseInt(hunkMatch[1], 10) - 1;
69
+ }
70
+ if (line.startsWith("+") && !line.startsWith("+++")) {
71
+ currentLine++;
72
+ const matched = lineMap.get(currentLine) || [];
73
+ annotated.push({ line, findings: matched });
74
+ }
75
+ else if (line.startsWith("-") && !line.startsWith("---")) {
76
+ annotated.push({ line, findings: [] });
77
+ }
78
+ else {
79
+ if (!line.startsWith("---") && !line.startsWith("+++") && !line.startsWith("@@")) {
80
+ currentLine++;
81
+ }
82
+ annotated.push({ line, findings: [] });
83
+ }
84
+ }
85
+ const annotatedCount = annotated.filter((a) => a.findings.length > 0).length;
86
+ if (format === "json") {
87
+ console.log(JSON.stringify({ totalLines: diffLines.length, annotatedLines: annotatedCount, findings: findings.length }, null, 2));
88
+ return;
89
+ }
90
+ console.log(`\nAnnotated Diff (${annotatedCount} lines with findings):`);
91
+ console.log("═".repeat(70));
92
+ for (const a of annotated) {
93
+ if (a.findings.length > 0) {
94
+ console.log(a.line);
95
+ for (const f of a.findings) {
96
+ console.log(` >>> [${String(f.severity || "?").toUpperCase()}] ${f.ruleId || ""}: ${f.title || ""}`);
97
+ }
98
+ }
99
+ else {
100
+ console.log(a.line);
101
+ }
102
+ }
103
+ console.log("═".repeat(70));
104
+ }
105
+ //# sourceMappingURL=review-diff-annotate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-diff-annotate.js","sourceRoot":"","sources":["../../src/commands/review-diff-annotate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Review-lock — Lock reviews to prevent accidental re-runs.
3
+ */
4
+ export declare function runReviewLock(argv: string[]): void;
5
+ //# sourceMappingURL=review-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-lock.d.ts","sourceRoot":"","sources":["../../src/commands/review-lock.ts"],"names":[],"mappings":"AAAA;;GAEG;AAsCH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAyFlD"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Review-lock — Lock reviews to prevent accidental re-runs.
3
+ */
4
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
5
+ import { dirname } from "path";
6
+ // ─── Storage ────────────────────────────────────────────────────────────────
7
+ const LOCK_FILE = ".judges/review-locks.json";
8
+ function loadStore() {
9
+ if (!existsSync(LOCK_FILE))
10
+ return { version: "1.0.0", locks: [] };
11
+ try {
12
+ return JSON.parse(readFileSync(LOCK_FILE, "utf-8"));
13
+ }
14
+ catch {
15
+ return { version: "1.0.0", locks: [] };
16
+ }
17
+ }
18
+ function saveStore(store) {
19
+ mkdirSync(dirname(LOCK_FILE), { recursive: true });
20
+ writeFileSync(LOCK_FILE, JSON.stringify(store, null, 2), "utf-8");
21
+ }
22
+ // ─── CLI ────────────────────────────────────────────────────────────────────
23
+ export function runReviewLock(argv) {
24
+ if (argv.includes("--help") || argv.includes("-h")) {
25
+ console.log(`
26
+ judges review-lock — Lock reviews to prevent re-runs
27
+
28
+ Usage:
29
+ judges review-lock add --file src/app.ts --reason "approved"
30
+ judges review-lock check --file src/app.ts
31
+ judges review-lock list
32
+ judges review-lock remove --file src/app.ts
33
+ judges review-lock clear
34
+
35
+ Subcommands:
36
+ add Lock a file
37
+ check Check if a file is locked
38
+ list List all locks
39
+ remove Unlock a file
40
+ clear Clear all locks
41
+
42
+ Options:
43
+ --file <path> File path
44
+ --reason <text> Lock reason
45
+ --format json JSON output
46
+ --help, -h Show this help
47
+
48
+ Locks stored in .judges/review-locks.json.
49
+ `);
50
+ return;
51
+ }
52
+ const subcommand = argv.find((a) => ["add", "check", "list", "remove", "clear"].includes(a));
53
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
54
+ const store = loadStore();
55
+ if (subcommand === "add") {
56
+ const file = argv.find((_a, i) => argv[i - 1] === "--file") || "";
57
+ const reason = argv.find((_a, i) => argv[i - 1] === "--reason") || "";
58
+ if (!file) {
59
+ console.log("Specify --file.");
60
+ return;
61
+ }
62
+ store.locks = store.locks.filter((l) => l.file !== file);
63
+ store.locks.push({ file, lockedAt: new Date().toISOString(), reason });
64
+ saveStore(store);
65
+ console.log(`Locked: ${file}`);
66
+ return;
67
+ }
68
+ if (subcommand === "check") {
69
+ const file = argv.find((_a, i) => argv[i - 1] === "--file") || "";
70
+ const lock = store.locks.find((l) => l.file === file);
71
+ if (lock) {
72
+ console.log(`LOCKED: ${file} — ${lock.reason} (${lock.lockedAt.slice(0, 10)})`);
73
+ }
74
+ else {
75
+ console.log(`Not locked: ${file}`);
76
+ }
77
+ return;
78
+ }
79
+ if (subcommand === "remove") {
80
+ const file = argv.find((_a, i) => argv[i - 1] === "--file") || "";
81
+ const before = store.locks.length;
82
+ store.locks = store.locks.filter((l) => l.file !== file);
83
+ saveStore(store);
84
+ console.log(before > store.locks.length ? `Unlocked: ${file}` : `${file} was not locked.`);
85
+ return;
86
+ }
87
+ if (subcommand === "clear") {
88
+ saveStore({ version: "1.0.0", locks: [] });
89
+ console.log("All locks cleared.");
90
+ return;
91
+ }
92
+ // Default: list
93
+ if (store.locks.length === 0) {
94
+ console.log("No review locks.");
95
+ return;
96
+ }
97
+ if (format === "json") {
98
+ console.log(JSON.stringify(store.locks, null, 2));
99
+ return;
100
+ }
101
+ console.log(`\nReview Locks (${store.locks.length}):`);
102
+ console.log("─".repeat(50));
103
+ for (const l of store.locks) {
104
+ console.log(` ${l.file} ${l.lockedAt.slice(0, 10)} ${l.reason}`);
105
+ }
106
+ console.log("─".repeat(50));
107
+ }
108
+ //# sourceMappingURL=review-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-lock.js","sourceRoot":"","sources":["../../src/commands/review-lock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Review-rate-limit — Control review frequency to avoid noise.
3
+ */
4
+ export declare function runReviewRateLimit(argv: string[]): void;
5
+ //# sourceMappingURL=review-rate-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-rate-limit.d.ts","sourceRoot":"","sources":["../../src/commands/review-rate-limit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAqCH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAsHvD"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Review-rate-limit — Control review frequency to avoid noise.
3
+ */
4
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
5
+ import { dirname } from "path";
6
+ // ─── Storage ────────────────────────────────────────────────────────────────
7
+ const RL_FILE = ".judges/rate-limit.json";
8
+ function loadConfig() {
9
+ if (!existsSync(RL_FILE)) {
10
+ return { version: "1.0.0", maxReviewsPerHour: 30, maxReviewsPerDay: 200, cooldownMinutes: 1, history: [] };
11
+ }
12
+ try {
13
+ return JSON.parse(readFileSync(RL_FILE, "utf-8"));
14
+ }
15
+ catch {
16
+ return { version: "1.0.0", maxReviewsPerHour: 30, maxReviewsPerDay: 200, cooldownMinutes: 1, history: [] };
17
+ }
18
+ }
19
+ function saveConfig(config) {
20
+ mkdirSync(dirname(RL_FILE), { recursive: true });
21
+ writeFileSync(RL_FILE, JSON.stringify(config, null, 2), "utf-8");
22
+ }
23
+ // ─── CLI ────────────────────────────────────────────────────────────────────
24
+ export function runReviewRateLimit(argv) {
25
+ if (argv.includes("--help") || argv.includes("-h")) {
26
+ console.log(`
27
+ judges review-rate-limit — Control review frequency
28
+
29
+ Usage:
30
+ judges review-rate-limit Show current limits and usage
31
+ judges review-rate-limit set --per-hour 20 --per-day 100
32
+ judges review-rate-limit check Check if review is allowed now
33
+ judges review-rate-limit record Record a review event
34
+ judges review-rate-limit reset Reset history and limits
35
+
36
+ Subcommands:
37
+ (default) Show limits and usage
38
+ set Configure rate limits
39
+ check Check if within limits
40
+ record Record a review event
41
+ reset Reset all rate limit state
42
+
43
+ Options:
44
+ --per-hour <n> Max reviews per hour
45
+ --per-day <n> Max reviews per day
46
+ --cooldown <n> Cooldown between reviews (minutes)
47
+ --format json JSON output
48
+ --help, -h Show this help
49
+
50
+ Config stored in .judges/rate-limit.json.
51
+ `);
52
+ return;
53
+ }
54
+ const subcommand = argv.find((a) => ["set", "check", "record", "reset"].includes(a));
55
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
56
+ const config = loadConfig();
57
+ if (subcommand === "set") {
58
+ const perHour = argv.find((_a, i) => argv[i - 1] === "--per-hour");
59
+ const perDay = argv.find((_a, i) => argv[i - 1] === "--per-day");
60
+ const cooldown = argv.find((_a, i) => argv[i - 1] === "--cooldown");
61
+ if (perHour)
62
+ config.maxReviewsPerHour = parseInt(perHour, 10);
63
+ if (perDay)
64
+ config.maxReviewsPerDay = parseInt(perDay, 10);
65
+ if (cooldown)
66
+ config.cooldownMinutes = parseInt(cooldown, 10);
67
+ saveConfig(config);
68
+ console.log(`Rate limits: ${config.maxReviewsPerHour}/hr, ${config.maxReviewsPerDay}/day, ${config.cooldownMinutes}min cooldown`);
69
+ return;
70
+ }
71
+ if (subcommand === "record") {
72
+ config.history.push(new Date().toISOString());
73
+ // Prune old entries (keep last 24h)
74
+ const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
75
+ config.history = config.history.filter((t) => t >= cutoff);
76
+ saveConfig(config);
77
+ console.log(`Review recorded. ${config.history.length} reviews in last 24h.`);
78
+ return;
79
+ }
80
+ if (subcommand === "reset") {
81
+ saveConfig({ version: "1.0.0", maxReviewsPerHour: 30, maxReviewsPerDay: 200, cooldownMinutes: 1, history: [] });
82
+ console.log("Rate limits reset to defaults.");
83
+ return;
84
+ }
85
+ // Compute usage
86
+ const now = Date.now();
87
+ const oneHourAgo = new Date(now - 60 * 60 * 1000).toISOString();
88
+ const oneDayAgo = new Date(now - 24 * 60 * 60 * 1000).toISOString();
89
+ const lastHour = config.history.filter((t) => t >= oneHourAgo).length;
90
+ const lastDay = config.history.filter((t) => t >= oneDayAgo).length;
91
+ const lastTimestamp = config.history.length > 0 ? config.history[config.history.length - 1] : null;
92
+ const cooldownOk = !lastTimestamp || now - new Date(lastTimestamp).getTime() >= config.cooldownMinutes * 60 * 1000;
93
+ const hourOk = lastHour < config.maxReviewsPerHour;
94
+ const dayOk = lastDay < config.maxReviewsPerDay;
95
+ const allowed = cooldownOk && hourOk && dayOk;
96
+ if (subcommand === "check") {
97
+ if (format === "json") {
98
+ console.log(JSON.stringify({ allowed, lastHour, lastDay, cooldownOk, hourOk, dayOk }, null, 2));
99
+ return;
100
+ }
101
+ console.log(allowed ? "Review allowed." : "Rate limit exceeded — review blocked.");
102
+ if (!cooldownOk)
103
+ console.log(` Cooldown: wait ${config.cooldownMinutes} min`);
104
+ if (!hourOk)
105
+ console.log(` Hourly: ${lastHour}/${config.maxReviewsPerHour}`);
106
+ if (!dayOk)
107
+ console.log(` Daily: ${lastDay}/${config.maxReviewsPerDay}`);
108
+ return;
109
+ }
110
+ // Default: show
111
+ if (format === "json") {
112
+ console.log(JSON.stringify({
113
+ limits: {
114
+ perHour: config.maxReviewsPerHour,
115
+ perDay: config.maxReviewsPerDay,
116
+ cooldownMinutes: config.cooldownMinutes,
117
+ },
118
+ usage: { lastHour, lastDay },
119
+ allowed,
120
+ }, null, 2));
121
+ return;
122
+ }
123
+ console.log("\nRate Limit Status:");
124
+ console.log("═".repeat(45));
125
+ console.log(` Hourly: ${lastHour} / ${config.maxReviewsPerHour}`);
126
+ console.log(` Daily: ${lastDay} / ${config.maxReviewsPerDay}`);
127
+ console.log(` Cooldown: ${config.cooldownMinutes} min`);
128
+ console.log(` Status: ${allowed ? "OK — review allowed" : "BLOCKED"}`);
129
+ console.log("═".repeat(45));
130
+ }
131
+ //# sourceMappingURL=review-rate-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-rate-limit.js","sourceRoot":"","sources":["../../src/commands/review-rate-limit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAY/B,+EAA+E;AAE/E,MAAM,OAAO,GAAG,yBAAyB,CAAC;AAE1C,SAAS,UAAU;IACjB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,EAAE,EAAE,gBAAgB,EAAE,GAAG,EAAE,eAAe,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC7G,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAoB,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,EAAE,EAAE,gBAAgB,EAAE,GAAG,EAAE,eAAe,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC7G,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,MAAuB;IACzC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AACnE,CAAC;AAED,+EAA+E;AAE/E,MAAM,UAAU,kBAAkB,CAAC,IAAc;IAC/C,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;CAyBf,CAAC,CAAC;QACC,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,UAAU,CAAC,IAAI,MAAM,CAAC;IAC1F,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,IAAI,UAAU,KAAK,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC;QACnF,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC;QACjF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC;QACpF,IAAI,OAAO;YAAE,MAAM,CAAC,iBAAiB,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC9D,IAAI,MAAM;YAAE,MAAM,CAAC,gBAAgB,GAAG,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3D,IAAI,QAAQ;YAAE,MAAM,CAAC,eAAe,GAAG,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC9D,UAAU,CAAC,MAAM,CAAC,CAAC;QACnB,OAAO,CAAC,GAAG,CACT,gBAAgB,MAAM,CAAC,iBAAiB,QAAQ,MAAM,CAAC,gBAAgB,SAAS,MAAM,CAAC,eAAe,cAAc,CACrH,CAAC;QACF,OAAO;IACT,CAAC;IAED,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;QAC9C,oCAAoC;QACpC,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QACxE,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;QAC3D,UAAU,CAAC,MAAM,CAAC,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,oBAAoB,MAAM,CAAC,OAAO,CAAC,MAAM,uBAAuB,CAAC,CAAC;QAC9E,OAAO;IACT,CAAC;IAED,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;QAC3B,UAAU,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,EAAE,EAAE,gBAAgB,EAAE,GAAG,EAAE,eAAe,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QAChH,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;QAC9C,OAAO;IACT,CAAC;IAED,gBAAgB;IAChB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAChE,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAEpE,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,MAAM,CAAC;IACtE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,MAAM,CAAC;IAEpE,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACnG,MAAM,UAAU,GAAG,CAAC,aAAa,IAAI,GAAG,GAAG,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE,IAAI,MAAM,CAAC,eAAe,GAAG,EAAE,GAAG,IAAI,CAAC;IACnH,MAAM,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC,iBAAiB,CAAC;IACnD,MAAM,KAAK,GAAG,OAAO,GAAG,MAAM,CAAC,gBAAgB,CAAC;IAChD,MAAM,OAAO,GAAG,UAAU,IAAI,MAAM,IAAI,KAAK,CAAC;IAE9C,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;QAC3B,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAChG,OAAO;QACT,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,uCAAuC,CAAC,CAAC;QACnF,IAAI,CAAC,UAAU;YAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,MAAM,CAAC,eAAe,MAAM,CAAC,CAAC;QAC/E,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,GAAG,CAAC,aAAa,QAAQ,IAAI,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC;QAC9E,IAAI,CAAC,KAAK;YAAE,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;QAC1E,OAAO;IACT,CAAC;IAED,gBAAgB;IAChB,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CACZ;YACE,MAAM,EAAE;gBACN,OAAO,EAAE,MAAM,CAAC,iBAAiB;gBACjC,MAAM,EAAE,MAAM,CAAC,gBAAgB;gBAC/B,eAAe,EAAE,MAAM,CAAC,eAAe;aACxC;YACD,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE;YAC5B,OAAO;SACR,EACD,IAAI,EACJ,CAAC,CACF,CACF,CAAC;QACF,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,eAAe,QAAQ,MAAM,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC,eAAe,OAAO,MAAM,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,eAAe,MAAM,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,eAAe,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;IAC1E,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AAC9B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kevinrabun/judges",
3
- "version": "3.74.0",
3
+ "version": "3.75.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.74.0",
10
+ "version": "3.75.0",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "identifier": "@kevinrabun/judges",
15
- "version": "3.74.0",
15
+ "version": "3.75.0",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  }