@kevinrabun/judges 3.52.0 → 3.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +112 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/approve-chain.d.ts +8 -0
  6. package/dist/commands/approve-chain.d.ts.map +1 -0
  7. package/dist/commands/approve-chain.js +235 -0
  8. package/dist/commands/approve-chain.js.map +1 -0
  9. package/dist/commands/coach-mode.d.ts +8 -0
  10. package/dist/commands/coach-mode.d.ts.map +1 -0
  11. package/dist/commands/coach-mode.js +230 -0
  12. package/dist/commands/coach-mode.js.map +1 -0
  13. package/dist/commands/code-similarity.d.ts +9 -0
  14. package/dist/commands/code-similarity.d.ts.map +1 -0
  15. package/dist/commands/code-similarity.js +232 -0
  16. package/dist/commands/code-similarity.js.map +1 -0
  17. package/dist/commands/compliance-weight.d.ts +9 -0
  18. package/dist/commands/compliance-weight.d.ts.map +1 -0
  19. package/dist/commands/compliance-weight.js +273 -0
  20. package/dist/commands/compliance-weight.js.map +1 -0
  21. package/dist/commands/context-inject.d.ts +9 -0
  22. package/dist/commands/context-inject.d.ts.map +1 -0
  23. package/dist/commands/context-inject.js +212 -0
  24. package/dist/commands/context-inject.js.map +1 -0
  25. package/dist/commands/cross-pr-regression.d.ts +9 -0
  26. package/dist/commands/cross-pr-regression.d.ts.map +1 -0
  27. package/dist/commands/cross-pr-regression.js +298 -0
  28. package/dist/commands/cross-pr-regression.js.map +1 -0
  29. package/dist/commands/doc-drift.d.ts +9 -0
  30. package/dist/commands/doc-drift.d.ts.map +1 -0
  31. package/dist/commands/doc-drift.js +259 -0
  32. package/dist/commands/doc-drift.js.map +1 -0
  33. package/dist/commands/exception-consistency.d.ts +7 -0
  34. package/dist/commands/exception-consistency.d.ts.map +1 -0
  35. package/dist/commands/exception-consistency.js +193 -0
  36. package/dist/commands/exception-consistency.js.map +1 -0
  37. package/dist/commands/finding-contest.d.ts +8 -0
  38. package/dist/commands/finding-contest.d.ts.map +1 -0
  39. package/dist/commands/finding-contest.js +193 -0
  40. package/dist/commands/finding-contest.js.map +1 -0
  41. package/dist/commands/habit-tracker.d.ts +8 -0
  42. package/dist/commands/habit-tracker.d.ts.map +1 -0
  43. package/dist/commands/habit-tracker.js +195 -0
  44. package/dist/commands/habit-tracker.js.map +1 -0
  45. package/dist/commands/prompt-replay.d.ts +8 -0
  46. package/dist/commands/prompt-replay.d.ts.map +1 -0
  47. package/dist/commands/prompt-replay.js +177 -0
  48. package/dist/commands/prompt-replay.js.map +1 -0
  49. package/dist/commands/refactor-safety.d.ts +9 -0
  50. package/dist/commands/refactor-safety.d.ts.map +1 -0
  51. package/dist/commands/refactor-safety.js +274 -0
  52. package/dist/commands/refactor-safety.js.map +1 -0
  53. package/dist/commands/resource-cleanup.d.ts +7 -0
  54. package/dist/commands/resource-cleanup.d.ts.map +1 -0
  55. package/dist/commands/resource-cleanup.js +236 -0
  56. package/dist/commands/resource-cleanup.js.map +1 -0
  57. package/dist/commands/review-replay.d.ts +9 -0
  58. package/dist/commands/review-replay.d.ts.map +1 -0
  59. package/dist/commands/review-replay.js +265 -0
  60. package/dist/commands/review-replay.js.map +1 -0
  61. package/dist/commands/snippet-eval.d.ts +8 -0
  62. package/dist/commands/snippet-eval.d.ts.map +1 -0
  63. package/dist/commands/snippet-eval.js +224 -0
  64. package/dist/commands/snippet-eval.js.map +1 -0
  65. package/dist/commands/team-trust.d.ts +8 -0
  66. package/dist/commands/team-trust.d.ts.map +1 -0
  67. package/dist/commands/team-trust.js +175 -0
  68. package/dist/commands/team-trust.js.map +1 -0
  69. package/package.json +1 -1
  70. package/server.json +2 -2
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Finding contest — gamified challenge mode where developers compete
3
+ * to fix the most findings in a codebase within a time window.
4
+ *
5
+ * Results stored locally in `.judges-contests/`.
6
+ */
7
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
8
+ import { join } from "path";
9
+ // ─── Storage ────────────────────────────────────────────────────────────────
10
+ const DATA_DIR = ".judges-contests";
11
+ function ensureDir() {
12
+ if (!existsSync(DATA_DIR))
13
+ mkdirSync(DATA_DIR, { recursive: true });
14
+ }
15
+ function loadContest(id) {
16
+ const file = join(DATA_DIR, `${id}.json`);
17
+ if (!existsSync(file))
18
+ return null;
19
+ try {
20
+ return JSON.parse(readFileSync(file, "utf-8"));
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ function saveContest(contest) {
27
+ ensureDir();
28
+ writeFileSync(join(DATA_DIR, `${contest.id}.json`), JSON.stringify(contest, null, 2));
29
+ }
30
+ function getActiveContest() {
31
+ ensureDir();
32
+ const indexFile = join(DATA_DIR, "active.json");
33
+ if (!existsSync(indexFile))
34
+ return null;
35
+ try {
36
+ const data = JSON.parse(readFileSync(indexFile, "utf-8"));
37
+ return loadContest(data.id);
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ function setActiveContest(id) {
44
+ ensureDir();
45
+ const indexFile = join(DATA_DIR, "active.json");
46
+ if (id)
47
+ writeFileSync(indexFile, JSON.stringify({ id }));
48
+ else if (existsSync(indexFile))
49
+ writeFileSync(indexFile, "{}");
50
+ }
51
+ // ─── Scoring ────────────────────────────────────────────────────────────────
52
+ const SEVERITY_POINTS = { critical: 10, high: 5, medium: 3, low: 1 };
53
+ // ─── CLI ────────────────────────────────────────────────────────────────────
54
+ export function runFindingContest(argv) {
55
+ if (argv.includes("--help") || argv.includes("-h")) {
56
+ console.log(`
57
+ judges finding-contest — Gamified fix challenge
58
+
59
+ Usage:
60
+ judges finding-contest --start --duration 60 --findings 25
61
+ judges finding-contest --fix --participant "alice" --rule SEC-001 --severity high
62
+ judges finding-contest --leaderboard
63
+ judges finding-contest --end
64
+
65
+ Options:
66
+ --start Start a new contest
67
+ --duration <min> Contest duration in minutes (default: 60)
68
+ --findings <n> Initial finding count (default: 20)
69
+ --fix Record a fix
70
+ --participant <name> Participant name
71
+ --rule <id> Rule ID that was fixed
72
+ --severity <level> Severity of the fixed finding
73
+ --leaderboard Show current leaderboard
74
+ --end End active contest and show final results
75
+ --format json JSON output
76
+ --help, -h Show this help
77
+ `);
78
+ return;
79
+ }
80
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
81
+ const isStart = argv.includes("--start");
82
+ const isFix = argv.includes("--fix");
83
+ const isLeaderboard = argv.includes("--leaderboard");
84
+ const isEnd = argv.includes("--end");
85
+ if (isStart) {
86
+ const duration = parseInt(argv.find((_a, i) => argv[i - 1] === "--duration") || "60");
87
+ const findings = parseInt(argv.find((_a, i) => argv[i - 1] === "--findings") || "20");
88
+ const now = new Date();
89
+ const contest = {
90
+ id: `contest-${Date.now()}`,
91
+ durationMinutes: duration,
92
+ startedAt: now.toISOString(),
93
+ endsAt: new Date(now.getTime() + duration * 60000).toISOString(),
94
+ status: "active",
95
+ initialFindings: findings,
96
+ entries: [],
97
+ };
98
+ saveContest(contest);
99
+ setActiveContest(contest.id);
100
+ console.log(`\n 🏁 Contest Started!`);
101
+ console.log(` ──────────────────────────`);
102
+ console.log(` ID: ${contest.id}`);
103
+ console.log(` Duration: ${duration} minutes`);
104
+ console.log(` Findings to fix: ${findings}`);
105
+ console.log(` Ends at: ${contest.endsAt}`);
106
+ console.log(`\n Use: judges finding-contest --fix --participant "name" --rule RULE-ID --severity level\n`);
107
+ return;
108
+ }
109
+ if (isFix) {
110
+ const contest = getActiveContest();
111
+ if (!contest || contest.status !== "active") {
112
+ console.error(" No active contest. Use --start to begin one.");
113
+ return;
114
+ }
115
+ // Check if contest has expired
116
+ if (new Date() > new Date(contest.endsAt)) {
117
+ contest.status = "completed";
118
+ saveContest(contest);
119
+ setActiveContest(null);
120
+ console.log(" ⏰ Contest has ended! Use --leaderboard to see results.");
121
+ return;
122
+ }
123
+ const participant = argv.find((_a, i) => argv[i - 1] === "--participant") || "";
124
+ const ruleId = argv.find((_a, i) => argv[i - 1] === "--rule") || "unknown";
125
+ const severity = argv.find((_a, i) => argv[i - 1] === "--severity") || "medium";
126
+ if (!participant) {
127
+ console.error(" --participant is required");
128
+ return;
129
+ }
130
+ let entry = contest.entries.find((e) => e.participant === participant);
131
+ if (!entry) {
132
+ entry = { participant, fixCount: 0, sevPoints: 0, startedAt: new Date().toISOString(), fixes: [] };
133
+ contest.entries.push(entry);
134
+ }
135
+ const points = SEVERITY_POINTS[severity] || 3;
136
+ entry.fixCount++;
137
+ entry.sevPoints += points;
138
+ entry.fixes.push({ ruleId, severity, fixedAt: new Date().toISOString() });
139
+ saveContest(contest);
140
+ console.log(` ✅ ${participant} fixed ${ruleId} [${severity}] — +${points} points (total: ${entry.sevPoints})`);
141
+ return;
142
+ }
143
+ if (isLeaderboard || isEnd) {
144
+ const contest = getActiveContest() ||
145
+ (() => {
146
+ // Try to find latest completed contest
147
+ ensureDir();
148
+ return null;
149
+ })();
150
+ if (!contest) {
151
+ console.error(" No contest found. Use --start to begin one.");
152
+ return;
153
+ }
154
+ if (isEnd && contest.status === "active") {
155
+ contest.status = "completed";
156
+ saveContest(contest);
157
+ setActiveContest(null);
158
+ }
159
+ const sorted = [...contest.entries].sort((a, b) => b.sevPoints - a.sevPoints);
160
+ const totalFixed = sorted.reduce((s, e) => s + e.fixCount, 0);
161
+ if (format === "json") {
162
+ console.log(JSON.stringify({
163
+ contest: { id: contest.id, status: contest.status, duration: contest.durationMinutes },
164
+ leaderboard: sorted,
165
+ totalFixed,
166
+ timestamp: new Date().toISOString(),
167
+ }, null, 2));
168
+ }
169
+ else {
170
+ const statusIcon = contest.status === "active" ? "🟢 ACTIVE" : "🏁 COMPLETED";
171
+ console.log(`\n Finding Contest ${statusIcon}\n ──────────────────────────`);
172
+ console.log(` ID: ${contest.id} | Duration: ${contest.durationMinutes}m | Findings: ${contest.initialFindings} → ${contest.initialFindings - totalFixed}\n`);
173
+ if (sorted.length === 0) {
174
+ console.log(" No fixes recorded yet!");
175
+ }
176
+ else {
177
+ for (let i = 0; i < sorted.length; i++) {
178
+ const e = sorted[i];
179
+ const medal = i === 0 ? "🥇" : i === 1 ? "🥈" : i === 2 ? "🥉" : " ";
180
+ console.log(` ${medal} ${e.participant.padEnd(20)} ${String(e.sevPoints).padStart(5)} pts | ${e.fixCount} fixes`);
181
+ }
182
+ }
183
+ if (contest.status === "active") {
184
+ const remaining = Math.max(0, Math.floor((new Date(contest.endsAt).getTime() - Date.now()) / 60000));
185
+ console.log(`\n ⏱️ ${remaining} minutes remaining`);
186
+ }
187
+ console.log("");
188
+ }
189
+ return;
190
+ }
191
+ console.log(" Use --start, --fix, --leaderboard, or --end. See --help for details.");
192
+ }
193
+ //# sourceMappingURL=finding-contest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-contest.js","sourceRoot":"","sources":["../../src/commands/finding-contest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Habit tracker — track recurring finding patterns per developer or
3
+ * AI model and surface personalized improvement suggestions.
4
+ *
5
+ * Data stored locally in `.judges-habits/`.
6
+ */
7
+ export declare function runHabitTracker(argv: string[]): void;
8
+ //# sourceMappingURL=habit-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"habit-tracker.d.ts","sourceRoot":"","sources":["../../src/commands/habit-tracker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAsGH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAoIpD"}
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Habit tracker — track recurring finding patterns per developer or
3
+ * AI model and surface personalized improvement suggestions.
4
+ *
5
+ * Data stored locally in `.judges-habits/`.
6
+ */
7
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
8
+ import { join } from "path";
9
+ // ─── Storage ────────────────────────────────────────────────────────────────
10
+ const DATA_DIR = ".judges-habits";
11
+ function ensureDir() {
12
+ if (!existsSync(DATA_DIR))
13
+ mkdirSync(DATA_DIR, { recursive: true });
14
+ }
15
+ function loadProfile(author) {
16
+ const file = join(DATA_DIR, `${author}.json`);
17
+ if (!existsSync(file))
18
+ return null;
19
+ try {
20
+ return JSON.parse(readFileSync(file, "utf-8"));
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ function saveProfile(profile) {
27
+ ensureDir();
28
+ writeFileSync(join(DATA_DIR, `${profile.author}.json`), JSON.stringify(profile, null, 2));
29
+ }
30
+ // ─── Learning Resources ────────────────────────────────────────────────────
31
+ const CATEGORY_RESOURCES = {
32
+ "sql-injection": [
33
+ "Use parameterized queries",
34
+ "Review OWASP SQL Injection Prevention Cheat Sheet",
35
+ "Enable SQL linting in CI",
36
+ ],
37
+ xss: [
38
+ "Sanitize all user input before rendering",
39
+ "Use Content Security Policy headers",
40
+ "Review OWASP XSS Prevention Cheat Sheet",
41
+ ],
42
+ "hardcoded-secret": [
43
+ "Use environment variables for secrets",
44
+ "Set up a secrets manager",
45
+ "Add secret scanning to pre-commit hooks",
46
+ ],
47
+ "empty-catch": [
48
+ "Always log or re-throw caught exceptions",
49
+ "Use error monitoring (Sentry, etc.)",
50
+ "Define error handling strategy per module",
51
+ ],
52
+ "missing-auth": [
53
+ "Apply auth middleware to all routes",
54
+ "Review OWASP Authentication Cheat Sheet",
55
+ "Implement role-based access control",
56
+ ],
57
+ "insecure-crypto": [
58
+ "Use crypto.randomUUID() for tokens",
59
+ "Use bcrypt/scrypt for password hashing",
60
+ "Never use MD5 or SHA1 for security",
61
+ ],
62
+ "error-handling": [
63
+ "Define a consistent error hierarchy",
64
+ "Use Result types or Either monads",
65
+ "Log errors with correlation IDs",
66
+ ],
67
+ performance: ["Profile before optimizing", "Use pagination for list endpoints", "Cache frequently accessed data"],
68
+ "code-quality": [
69
+ "Follow single responsibility principle",
70
+ "Reduce cyclomatic complexity",
71
+ "Write meaningful test names",
72
+ ],
73
+ documentation: ["Keep JSDoc in sync with code", "Document public API contracts", "Add examples to complex functions"],
74
+ };
75
+ function getResources(category) {
76
+ const key = Object.keys(CATEGORY_RESOURCES).find((k) => category.toLowerCase().includes(k));
77
+ return key
78
+ ? CATEGORY_RESOURCES[key]
79
+ : ["Review team coding standards", "Add targeted linting rules", "Consider pair programming for this area"];
80
+ }
81
+ // ─── CLI ────────────────────────────────────────────────────────────────────
82
+ export function runHabitTracker(argv) {
83
+ if (argv.includes("--help") || argv.includes("-h")) {
84
+ console.log(`
85
+ judges habit-tracker — Track recurring finding patterns
86
+
87
+ Usage:
88
+ judges habit-tracker --record --author "alice" --category "sql-injection"
89
+ judges habit-tracker --record --author "copilot" --category "empty-catch" --count 3
90
+ judges habit-tracker --show --author "alice"
91
+ judges habit-tracker --digest --author "alice"
92
+
93
+ Options:
94
+ --record Record finding occurrence
95
+ --author <name> Developer or AI model name
96
+ --category <name> Finding category (e.g., sql-injection, xss, empty-catch)
97
+ --count <n> Number of occurrences (default: 1)
98
+ --show Show author's habit profile
99
+ --digest Show improvement digest with resources
100
+ --format json JSON output
101
+ --help, -h Show this help
102
+ `);
103
+ return;
104
+ }
105
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
106
+ const isRecord = argv.includes("--record");
107
+ const isDigest = argv.includes("--digest");
108
+ const authorName = argv.find((_a, i) => argv[i - 1] === "--author") || "";
109
+ const category = argv.find((_a, i) => argv[i - 1] === "--category") || "";
110
+ const count = parseInt(argv.find((_a, i) => argv[i - 1] === "--count") || "1");
111
+ if (!authorName) {
112
+ console.error(" --author is required");
113
+ return;
114
+ }
115
+ if (isRecord) {
116
+ if (!category) {
117
+ console.error(" --category is required for --record");
118
+ return;
119
+ }
120
+ const profile = loadProfile(authorName) || {
121
+ author: authorName,
122
+ entries: [],
123
+ totalFindings: 0,
124
+ topCategory: "",
125
+ lastUpdated: "",
126
+ };
127
+ let entry = profile.entries.find((e) => e.category === category);
128
+ if (!entry) {
129
+ entry = { category, count: 0, lastSeen: "", trend: "stable", resources: getResources(category) };
130
+ profile.entries.push(entry);
131
+ }
132
+ const prevCount = entry.count;
133
+ entry.count += count;
134
+ entry.lastSeen = new Date().toISOString();
135
+ entry.trend = entry.count > prevCount * 1.5 ? "rising" : entry.count < prevCount * 0.7 ? "declining" : "stable";
136
+ profile.totalFindings += count;
137
+ profile.topCategory = profile.entries.sort((a, b) => b.count - a.count)[0]?.category || "";
138
+ profile.lastUpdated = new Date().toISOString();
139
+ saveProfile(profile);
140
+ console.log(` ✅ Recorded ${count}x ${category} for ${authorName} (total: ${entry.count})`);
141
+ return;
142
+ }
143
+ if (isDigest) {
144
+ const profile = loadProfile(authorName);
145
+ if (!profile || profile.entries.length === 0) {
146
+ console.log(` No data for ${authorName}. Use --record to add findings.`);
147
+ return;
148
+ }
149
+ const sorted = [...profile.entries].sort((a, b) => b.count - a.count);
150
+ const top3 = sorted.slice(0, 3);
151
+ if (format === "json") {
152
+ console.log(JSON.stringify({
153
+ author: authorName,
154
+ digest: top3,
155
+ totalFindings: profile.totalFindings,
156
+ timestamp: new Date().toISOString(),
157
+ }, null, 2));
158
+ }
159
+ else {
160
+ console.log(`\n Weekly Improvement Digest for ${authorName}\n ──────────────────────────`);
161
+ console.log(` Total findings: ${profile.totalFindings} across ${profile.entries.length} categories\n`);
162
+ for (const entry of top3) {
163
+ const trendIcon = entry.trend === "rising" ? "📈" : entry.trend === "declining" ? "📉" : "➡️";
164
+ console.log(` ${trendIcon} ${entry.category} — ${entry.count} occurrences (${entry.trend})`);
165
+ console.log(" Suggested improvements:");
166
+ for (const r of entry.resources) {
167
+ console.log(` • ${r}`);
168
+ }
169
+ console.log("");
170
+ }
171
+ }
172
+ return;
173
+ }
174
+ // Default: show profile
175
+ const profile = loadProfile(authorName);
176
+ if (!profile || profile.entries.length === 0) {
177
+ console.log(` No data for ${authorName}. Use --record to add findings.`);
178
+ return;
179
+ }
180
+ if (format === "json") {
181
+ console.log(JSON.stringify(profile, null, 2));
182
+ }
183
+ else {
184
+ console.log(`\n Habit Profile: ${authorName}\n ──────────────────────────`);
185
+ console.log(` Total: ${profile.totalFindings} | Categories: ${profile.entries.length} | Top: ${profile.topCategory}\n`);
186
+ const sorted = [...profile.entries].sort((a, b) => b.count - a.count);
187
+ for (const entry of sorted) {
188
+ const bar = "█".repeat(Math.min(20, Math.floor((entry.count / Math.max(1, profile.totalFindings)) * 40)));
189
+ const trendIcon = entry.trend === "rising" ? "↑" : entry.trend === "declining" ? "↓" : "→";
190
+ console.log(` ${entry.category.padEnd(25)} ${String(entry.count).padStart(4)} ${bar} ${trendIcon}`);
191
+ }
192
+ console.log("");
193
+ }
194
+ }
195
+ //# sourceMappingURL=habit-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"habit-tracker.js","sourceRoot":"","sources":["../../src/commands/habit-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Prompt replay — reverse-engineer the probable AI prompt that generated
3
+ * flagged code and suggest improved prompts that produce compliant output.
4
+ *
5
+ * Turns Judges into a prompt engineering coach.
6
+ */
7
+ export declare function runPromptReplay(argv: string[]): void;
8
+ //# sourceMappingURL=prompt-replay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-replay.d.ts","sourceRoot":"","sources":["../../src/commands/prompt-replay.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA+IH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAsEpD"}
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Prompt replay — reverse-engineer the probable AI prompt that generated
3
+ * flagged code and suggest improved prompts that produce compliant output.
4
+ *
5
+ * Turns Judges into a prompt engineering coach.
6
+ */
7
+ import { readFileSync, existsSync } from "fs";
8
+ // ─── Pattern → Prompt Map ───────────────────────────────────────────────────
9
+ const PATTERN_PROMPTS = [
10
+ {
11
+ pattern: /sql.?inject|string\s+concat.*query|`\$\{.*\}.*(?:SELECT|INSERT|UPDATE|DELETE)/i,
12
+ category: "SQL Injection",
13
+ probablePrompt: "Generate a function to query the database for user records",
14
+ improvedPrompt: "Generate a function to query the database for user records using parameterized queries. Use prepared statements, never string concatenation for SQL. Include input validation.",
15
+ rationale: "AI models default to string interpolation for SQL unless explicitly told to use parameterized queries",
16
+ },
17
+ {
18
+ pattern: /innerHTML|dangerouslySetInnerHTML|document\.write/i,
19
+ category: "XSS Vulnerability",
20
+ probablePrompt: "Create a component that renders user content",
21
+ improvedPrompt: "Create a component that renders user content. Sanitize all user inputs using DOMPurify before rendering. Never use innerHTML or dangerouslySetInnerHTML with unsanitized data.",
22
+ rationale: "AI models use innerHTML for simplicity unless instructed to sanitize",
23
+ },
24
+ {
25
+ pattern: /hardcoded.?(secret|password|key|token)|['"][A-Za-z0-9+/]{20,}['"]/i,
26
+ category: "Hardcoded Secrets",
27
+ probablePrompt: "Set up API authentication with the service",
28
+ improvedPrompt: "Set up API authentication with the service. Read all secrets from environment variables or a secrets manager. Never hardcode API keys, passwords, or tokens in source code.",
29
+ rationale: "AI models often embed placeholder credentials that developers forget to replace",
30
+ },
31
+ {
32
+ pattern: /eval\s*\(|new\s+Function\s*\(/i,
33
+ category: "Code Injection via eval",
34
+ probablePrompt: "Create a dynamic expression evaluator",
35
+ improvedPrompt: "Create a dynamic expression evaluator. Do NOT use eval() or new Function(). Use a safe expression parser library (e.g., mathjs, expr-eval) or a whitelist-based approach.",
36
+ rationale: "AI models reach for eval() as the shortest path to dynamic execution",
37
+ },
38
+ {
39
+ pattern: /catch\s*\([^)]*\)\s*\{\s*\}/,
40
+ category: "Empty Catch Blocks",
41
+ probablePrompt: "Add error handling to this function",
42
+ improvedPrompt: "Add error handling to this function. Every catch block must either log the error, re-throw it, or return a meaningful error response. Never swallow exceptions silently.",
43
+ rationale: "AI models often add empty try/catch to 'handle errors' without actual handling",
44
+ },
45
+ {
46
+ pattern: /console\.(log|debug)\s*\(.*(?:password|token|secret|key|credential)/i,
47
+ category: "Sensitive Data Logging",
48
+ probablePrompt: "Add logging to track authentication flow",
49
+ improvedPrompt: "Add logging to track authentication flow. Never log passwords, tokens, secrets, or PII. Use structured logging with severity levels. Redact sensitive fields.",
50
+ rationale: "AI models log everything requested without considering data sensitivity",
51
+ },
52
+ {
53
+ pattern: /(?:http:\/\/|fetch\s*\(['"]http:)/i,
54
+ category: "Insecure HTTP",
55
+ probablePrompt: "Fetch data from the API endpoint",
56
+ improvedPrompt: "Fetch data from the API endpoint using HTTPS. Never use plain HTTP for API calls. Validate SSL certificates. Set appropriate timeouts.",
57
+ rationale: "AI models sometimes use http:// in examples without upgrading to https://",
58
+ },
59
+ {
60
+ pattern: /Math\.random\s*\(\)|crypto\.createHash\s*\(\s*['"]md5['"]\)/i,
61
+ category: "Weak Cryptography",
62
+ probablePrompt: "Generate a unique token/hash for the user session",
63
+ improvedPrompt: "Generate a unique token for the user session using crypto.randomUUID() or crypto.randomBytes(). For hashing, use SHA-256 or bcrypt. Never use Math.random() for security or MD5 for hashing.",
64
+ rationale: "AI models default to Math.random() or MD5 which are cryptographically insecure",
65
+ },
66
+ {
67
+ pattern: /\.exec\s*\(|child_process|spawn\s*\(.*\$|execSync\s*\(.*\+/i,
68
+ category: "Command Injection",
69
+ probablePrompt: "Execute a system command with user-provided parameters",
70
+ improvedPrompt: "Execute a system command with user-provided parameters. Use an allowlist of permitted commands. Pass arguments as an array (spawn), never via string concatenation. Validate and sanitize all inputs.",
71
+ rationale: "AI models concatenate user input into shell commands without sanitization",
72
+ },
73
+ {
74
+ pattern: /cors\(\s*\)|Access-Control-Allow-Origin.*\*/i,
75
+ category: "Permissive CORS",
76
+ probablePrompt: "Enable CORS for the API",
77
+ improvedPrompt: "Enable CORS for the API. Specify allowed origins explicitly (never use '*' in production). Set appropriate methods, headers, and credentials options.",
78
+ rationale: "AI models default to permissive CORS (allow all) for simplicity",
79
+ },
80
+ {
81
+ pattern: /(?:app|router)\.(get|post|put|delete)\s*\([^)]*(?!.*(?:auth|middleware|protect|guard))/i,
82
+ category: "Missing Auth Middleware",
83
+ probablePrompt: "Create REST API endpoints for the resource",
84
+ improvedPrompt: "Create REST API endpoints for the resource. Apply authentication middleware to all routes. Use authorization checks for role-based access. Apply rate limiting to prevent abuse.",
85
+ rationale: "AI models create routes without auth middleware unless explicitly instructed",
86
+ },
87
+ {
88
+ pattern: /(?:SELECT|INSERT|UPDATE|DELETE)\s+.*\*\s+FROM/i,
89
+ category: "SELECT * Usage",
90
+ probablePrompt: "Query all records from the table",
91
+ improvedPrompt: "Query records from the table. Select only the specific columns needed, never use SELECT *. Add pagination with LIMIT/OFFSET. Include proper WHERE clauses.",
92
+ rationale: "AI models use SELECT * for convenience, which exposes unnecessary data and hurts performance",
93
+ },
94
+ ];
95
+ // ─── Analysis ───────────────────────────────────────────────────────────────
96
+ function analyzeCode(content) {
97
+ const suggestions = [];
98
+ const seen = new Set();
99
+ for (const entry of PATTERN_PROMPTS) {
100
+ if (entry.pattern.test(content) && !seen.has(entry.category)) {
101
+ seen.add(entry.category);
102
+ suggestions.push({
103
+ findingPattern: entry.category,
104
+ probablePrompt: entry.probablePrompt,
105
+ improvedPrompt: entry.improvedPrompt,
106
+ rationale: entry.rationale,
107
+ });
108
+ }
109
+ }
110
+ return suggestions;
111
+ }
112
+ // ─── CLI ────────────────────────────────────────────────────────────────────
113
+ export function runPromptReplay(argv) {
114
+ if (argv.includes("--help") || argv.includes("-h")) {
115
+ console.log(`
116
+ judges prompt-replay — Reverse-engineer AI prompts and suggest improvements
117
+
118
+ Usage:
119
+ judges prompt-replay <file>
120
+ judges prompt-replay src/api.ts --format json
121
+ judges prompt-replay --demo
122
+
123
+ Options:
124
+ <file> File to analyze for AI-generated anti-patterns
125
+ --demo Run with built-in demo code
126
+ --format json JSON output
127
+ --help, -h Show this help
128
+
129
+ Detects AI-generated anti-patterns and suggests improved prompts that
130
+ would produce compliant code on the first try.
131
+ `);
132
+ return;
133
+ }
134
+ const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
135
+ const isDemo = argv.includes("--demo");
136
+ let content;
137
+ if (isDemo) {
138
+ content = `
139
+ const query = "SELECT * FROM users WHERE id = " + userId;
140
+ document.innerHTML = userInput;
141
+ const apiKey = "sk-1234567890abcdef";
142
+ try { riskyOperation(); } catch (e) {}
143
+ console.log("Auth token: " + token);
144
+ fetch("http://api.example.com/data");
145
+ const sessionId = Math.random().toString(36);
146
+ app.get("/admin/users", (req, res) => { res.json(users); });
147
+ `;
148
+ }
149
+ else {
150
+ const file = argv.find((a) => !a.startsWith("-")) || "";
151
+ if (!file || !existsSync(file)) {
152
+ console.error(" Specify a file to analyze or use --demo");
153
+ return;
154
+ }
155
+ content = readFileSync(file, "utf-8");
156
+ }
157
+ const suggestions = analyzeCode(content);
158
+ if (format === "json") {
159
+ console.log(JSON.stringify({ suggestions, total: suggestions.length, timestamp: new Date().toISOString() }, null, 2));
160
+ }
161
+ else {
162
+ console.log(`\n Prompt Replay — ${suggestions.length} AI prompt improvement(s) found\n ──────────────────────────`);
163
+ if (suggestions.length === 0) {
164
+ console.log(" ✅ No common AI anti-patterns detected");
165
+ }
166
+ else {
167
+ for (const s of suggestions) {
168
+ console.log(`\n 🔍 ${s.findingPattern}`);
169
+ console.log(` Probable AI prompt: "${s.probablePrompt}"`);
170
+ console.log(` 💡 Improved prompt: "${s.improvedPrompt}"`);
171
+ console.log(` 📝 ${s.rationale}`);
172
+ }
173
+ }
174
+ console.log("");
175
+ }
176
+ }
177
+ //# sourceMappingURL=prompt-replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-replay.js","sourceRoot":"","sources":["../../src/commands/prompt-replay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Refactor safety — analyze proposed refactorings for breaking changes,
3
+ * incomplete migrations, orphaned references, and behavioral changes.
4
+ *
5
+ * Compares two directory snapshots or a list of changed files against
6
+ * the broader codebase to detect incomplete refactors.
7
+ */
8
+ export declare function runRefactorSafety(argv: string[]): void;
9
+ //# sourceMappingURL=refactor-safety.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refactor-safety.d.ts","sourceRoot":"","sources":["../../src/commands/refactor-safety.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4NH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA4EtD"}