@kevinrabun/judges 3.46.0 → 3.48.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.
- package/CHANGELOG.md +24 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +112 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/adoption-report.d.ts +8 -0
- package/dist/commands/adoption-report.d.ts.map +1 -0
- package/dist/commands/adoption-report.js +219 -0
- package/dist/commands/adoption-report.js.map +1 -0
- package/dist/commands/ai-model-trust.d.ts +17 -0
- package/dist/commands/ai-model-trust.d.ts.map +1 -0
- package/dist/commands/ai-model-trust.js +235 -0
- package/dist/commands/ai-model-trust.js.map +1 -0
- package/dist/commands/ai-prompt-audit.d.ts +23 -0
- package/dist/commands/ai-prompt-audit.d.ts.map +1 -0
- package/dist/commands/ai-prompt-audit.js +255 -0
- package/dist/commands/ai-prompt-audit.js.map +1 -0
- package/dist/commands/audit-trail.d.ts +18 -0
- package/dist/commands/audit-trail.d.ts.map +1 -0
- package/dist/commands/audit-trail.js +155 -0
- package/dist/commands/audit-trail.js.map +1 -0
- package/dist/commands/auto-fix.d.ts +18 -0
- package/dist/commands/auto-fix.d.ts.map +1 -0
- package/dist/commands/auto-fix.js +241 -0
- package/dist/commands/auto-fix.js.map +1 -0
- package/dist/commands/code-owner-suggest.d.ts +17 -0
- package/dist/commands/code-owner-suggest.d.ts.map +1 -0
- package/dist/commands/code-owner-suggest.js +215 -0
- package/dist/commands/code-owner-suggest.js.map +1 -0
- package/dist/commands/cost-forecast.d.ts +19 -0
- package/dist/commands/cost-forecast.d.ts.map +1 -0
- package/dist/commands/cost-forecast.js +194 -0
- package/dist/commands/cost-forecast.js.map +1 -0
- package/dist/commands/dep-correlate.d.ts +9 -0
- package/dist/commands/dep-correlate.d.ts.map +1 -0
- package/dist/commands/dep-correlate.js +208 -0
- package/dist/commands/dep-correlate.js.map +1 -0
- package/dist/commands/doc-gen.d.ts +8 -0
- package/dist/commands/doc-gen.d.ts.map +1 -0
- package/dist/commands/doc-gen.js +209 -0
- package/dist/commands/doc-gen.js.map +1 -0
- package/dist/commands/judge-author.d.ts +8 -0
- package/dist/commands/judge-author.d.ts.map +1 -0
- package/dist/commands/judge-author.js +261 -0
- package/dist/commands/judge-author.js.map +1 -0
- package/dist/commands/pattern-registry.d.ts +23 -0
- package/dist/commands/pattern-registry.d.ts.map +1 -0
- package/dist/commands/pattern-registry.js +227 -0
- package/dist/commands/pattern-registry.js.map +1 -0
- package/dist/commands/perf-hotspot.d.ts +8 -0
- package/dist/commands/perf-hotspot.d.ts.map +1 -0
- package/dist/commands/perf-hotspot.js +274 -0
- package/dist/commands/perf-hotspot.js.map +1 -0
- package/dist/commands/pr-quality-gate.d.ts +29 -0
- package/dist/commands/pr-quality-gate.d.ts.map +1 -0
- package/dist/commands/pr-quality-gate.js +208 -0
- package/dist/commands/pr-quality-gate.js.map +1 -0
- package/dist/commands/security-maturity.d.ts +8 -0
- package/dist/commands/security-maturity.d.ts.map +1 -0
- package/dist/commands/security-maturity.js +313 -0
- package/dist/commands/security-maturity.js.map +1 -0
- package/dist/commands/team-leaderboard.d.ts +25 -0
- package/dist/commands/team-leaderboard.d.ts.map +1 -0
- package/dist/commands/team-leaderboard.js +228 -0
- package/dist/commands/team-leaderboard.js.map +1 -0
- package/dist/commands/team-rules-sync.d.ts +8 -0
- package/dist/commands/team-rules-sync.d.ts.map +1 -0
- package/dist/commands/team-rules-sync.js +251 -0
- package/dist/commands/team-rules-sync.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern registry — team knowledge sharing via a local
|
|
3
|
+
* repository of security patterns and anti-patterns.
|
|
4
|
+
*
|
|
5
|
+
* All data stays in .judges-patterns/ directory.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from "fs";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
const PATTERN_DIR = ".judges-patterns";
|
|
10
|
+
// ─── Built-in patterns ─────────────────────────────────────────────────────
|
|
11
|
+
const BUILTIN_PATTERNS = [
|
|
12
|
+
{
|
|
13
|
+
id: "sql-parameterized",
|
|
14
|
+
title: "Parameterized SQL Queries",
|
|
15
|
+
category: "injection",
|
|
16
|
+
type: "pattern",
|
|
17
|
+
language: "typescript",
|
|
18
|
+
description: "Always use parameterized queries to prevent SQL injection",
|
|
19
|
+
example: 'db.query("SELECT * FROM users WHERE id = $1", [userId])',
|
|
20
|
+
author: "judges",
|
|
21
|
+
tags: ["sql", "injection", "security"],
|
|
22
|
+
createdAt: "2025-01-01",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "sql-concat-antipattern",
|
|
26
|
+
title: "String Concatenation in SQL",
|
|
27
|
+
category: "injection",
|
|
28
|
+
type: "anti-pattern",
|
|
29
|
+
language: "typescript",
|
|
30
|
+
description: "Never concatenate user input into SQL queries",
|
|
31
|
+
example: 'db.query("SELECT * FROM users WHERE id = " + userId)',
|
|
32
|
+
fix: 'db.query("SELECT * FROM users WHERE id = $1", [userId])',
|
|
33
|
+
author: "judges",
|
|
34
|
+
tags: ["sql", "injection", "security"],
|
|
35
|
+
createdAt: "2025-01-01",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "input-validation",
|
|
39
|
+
title: "Input Validation Pattern",
|
|
40
|
+
category: "validation",
|
|
41
|
+
type: "pattern",
|
|
42
|
+
language: "typescript",
|
|
43
|
+
description: "Validate all user input at system boundaries",
|
|
44
|
+
example: 'if (!schema.safeParse(req.body).success) return res.status(400).json({ error: "Invalid input" })',
|
|
45
|
+
author: "judges",
|
|
46
|
+
tags: ["validation", "input", "security"],
|
|
47
|
+
createdAt: "2025-01-01",
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: "error-exposure-antipattern",
|
|
51
|
+
title: "Stack Trace Exposure",
|
|
52
|
+
category: "error-handling",
|
|
53
|
+
type: "anti-pattern",
|
|
54
|
+
language: "typescript",
|
|
55
|
+
description: "Never expose stack traces or internal errors to users",
|
|
56
|
+
example: "res.status(500).json({ error: err.stack })",
|
|
57
|
+
fix: 'res.status(500).json({ error: "Internal server error" })',
|
|
58
|
+
author: "judges",
|
|
59
|
+
tags: ["error", "information-leak", "security"],
|
|
60
|
+
createdAt: "2025-01-01",
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
// ─── Core ───────────────────────────────────────────────────────────────────
|
|
64
|
+
function ensureDir() {
|
|
65
|
+
if (!existsSync(PATTERN_DIR))
|
|
66
|
+
mkdirSync(PATTERN_DIR, { recursive: true });
|
|
67
|
+
}
|
|
68
|
+
function loadPatterns() {
|
|
69
|
+
ensureDir();
|
|
70
|
+
const files = readdirSync(PATTERN_DIR).filter((f) => f.endsWith(".json"));
|
|
71
|
+
const custom = [];
|
|
72
|
+
for (const f of files) {
|
|
73
|
+
try {
|
|
74
|
+
custom.push(JSON.parse(readFileSync(join(PATTERN_DIR, f), "utf-8")));
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
/* skip invalid files */
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return [...BUILTIN_PATTERNS, ...custom];
|
|
81
|
+
}
|
|
82
|
+
function sanitizeId(id) {
|
|
83
|
+
return id
|
|
84
|
+
.replace(/[^a-zA-Z0-9-]/g, "-")
|
|
85
|
+
.toLowerCase()
|
|
86
|
+
.slice(0, 50);
|
|
87
|
+
}
|
|
88
|
+
export function addPattern(pattern) {
|
|
89
|
+
ensureDir();
|
|
90
|
+
const id = sanitizeId(pattern.title);
|
|
91
|
+
const full = {
|
|
92
|
+
...pattern,
|
|
93
|
+
id,
|
|
94
|
+
createdAt: new Date().toISOString().slice(0, 10),
|
|
95
|
+
};
|
|
96
|
+
writeFileSync(join(PATTERN_DIR, `${id}.json`), JSON.stringify(full, null, 2));
|
|
97
|
+
return full;
|
|
98
|
+
}
|
|
99
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
100
|
+
export function runPatternRegistry(argv) {
|
|
101
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
102
|
+
console.log(`
|
|
103
|
+
judges pattern-registry — Team security pattern knowledge repository
|
|
104
|
+
|
|
105
|
+
Usage:
|
|
106
|
+
judges pattern-registry --list
|
|
107
|
+
judges pattern-registry --show sql-parameterized
|
|
108
|
+
judges pattern-registry --add --title "CSRF Token Check" --category csrf --type pattern --lang typescript --desc "Always verify CSRF tokens" --example "verifyCSRF(req.headers['x-csrf-token'])" --author "alice@co.com"
|
|
109
|
+
judges pattern-registry --search injection
|
|
110
|
+
judges pattern-registry --anti-patterns
|
|
111
|
+
|
|
112
|
+
Options:
|
|
113
|
+
--list List all patterns
|
|
114
|
+
--show <id> Show pattern details
|
|
115
|
+
--add Add a new pattern
|
|
116
|
+
--title <text> Pattern title
|
|
117
|
+
--category <name> Category (injection, validation, auth, etc.)
|
|
118
|
+
--type <kind> pattern or anti-pattern
|
|
119
|
+
--lang <language> Programming language
|
|
120
|
+
--desc <text> Description
|
|
121
|
+
--example <code> Code example
|
|
122
|
+
--fix <code> Fix for anti-patterns
|
|
123
|
+
--author <name> Author name
|
|
124
|
+
--search <term> Search patterns by keyword
|
|
125
|
+
--anti-patterns Show only anti-patterns
|
|
126
|
+
--format json JSON output
|
|
127
|
+
--help, -h Show this help
|
|
128
|
+
`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
132
|
+
const patterns = loadPatterns();
|
|
133
|
+
// Anti-patterns only
|
|
134
|
+
if (argv.includes("--anti-patterns")) {
|
|
135
|
+
const antiPatterns = patterns.filter((p) => p.type === "anti-pattern");
|
|
136
|
+
if (format === "json") {
|
|
137
|
+
console.log(JSON.stringify(antiPatterns, null, 2));
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
console.log(`\n Anti-Patterns (${antiPatterns.length})\n ──────────────────────────`);
|
|
141
|
+
for (const p of antiPatterns) {
|
|
142
|
+
console.log(` ❌ ${p.id.padEnd(30)} ${p.title}`);
|
|
143
|
+
console.log(` ${p.description}`);
|
|
144
|
+
if (p.fix)
|
|
145
|
+
console.log(` Fix: ${p.fix}`);
|
|
146
|
+
console.log("");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
// Search
|
|
152
|
+
const searchTerm = argv.find((_a, i) => argv[i - 1] === "--search");
|
|
153
|
+
if (searchTerm) {
|
|
154
|
+
const term = searchTerm.toLowerCase();
|
|
155
|
+
const matches = patterns.filter((p) => p.title.toLowerCase().includes(term) ||
|
|
156
|
+
p.description.toLowerCase().includes(term) ||
|
|
157
|
+
p.tags.some((t) => t.includes(term)) ||
|
|
158
|
+
p.category.includes(term));
|
|
159
|
+
if (format === "json") {
|
|
160
|
+
console.log(JSON.stringify(matches, null, 2));
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
console.log(`\n Search: "${searchTerm}" (${matches.length} matches)\n ──────────────────────────`);
|
|
164
|
+
for (const p of matches) {
|
|
165
|
+
const icon = p.type === "pattern" ? "✅" : "❌";
|
|
166
|
+
console.log(` ${icon} ${p.id.padEnd(30)} ${p.title}`);
|
|
167
|
+
}
|
|
168
|
+
console.log("");
|
|
169
|
+
}
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
// Show specific
|
|
173
|
+
const showId = argv.find((_a, i) => argv[i - 1] === "--show");
|
|
174
|
+
if (showId) {
|
|
175
|
+
const p = patterns.find((pat) => pat.id === showId);
|
|
176
|
+
if (!p) {
|
|
177
|
+
console.error(` Pattern not found: ${showId}`);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (format === "json") {
|
|
181
|
+
console.log(JSON.stringify(p, null, 2));
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
const icon = p.type === "pattern" ? "✅" : "❌";
|
|
185
|
+
console.log(`\n ${icon} ${p.title}`);
|
|
186
|
+
console.log(` ──────────────────────────`);
|
|
187
|
+
console.log(` Category: ${p.category}`);
|
|
188
|
+
console.log(` Type: ${p.type}`);
|
|
189
|
+
console.log(` Language: ${p.language}`);
|
|
190
|
+
console.log(` Author: ${p.author}`);
|
|
191
|
+
console.log(` Tags: ${p.tags.join(", ")}`);
|
|
192
|
+
console.log(`\n ${p.description}`);
|
|
193
|
+
console.log(`\n Example: ${p.example}`);
|
|
194
|
+
if (p.fix)
|
|
195
|
+
console.log(` Fix: ${p.fix}`);
|
|
196
|
+
console.log("");
|
|
197
|
+
}
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
// Add pattern
|
|
201
|
+
if (argv.includes("--add")) {
|
|
202
|
+
const title = argv.find((_a, i) => argv[i - 1] === "--title") || "Untitled";
|
|
203
|
+
const category = argv.find((_a, i) => argv[i - 1] === "--category") || "general";
|
|
204
|
+
const type = (argv.find((_a, i) => argv[i - 1] === "--type") || "pattern");
|
|
205
|
+
const language = argv.find((_a, i) => argv[i - 1] === "--lang") || "typescript";
|
|
206
|
+
const description = argv.find((_a, i) => argv[i - 1] === "--desc") || "";
|
|
207
|
+
const example = argv.find((_a, i) => argv[i - 1] === "--example") || "";
|
|
208
|
+
const fix = argv.find((_a, i) => argv[i - 1] === "--fix");
|
|
209
|
+
const author = argv.find((_a, i) => argv[i - 1] === "--author") || "anonymous";
|
|
210
|
+
const p = addPattern({ title, category, type, language, description, example, fix, author, tags: [category] });
|
|
211
|
+
console.log(` ✅ Pattern added: ${p.id}`);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
// List all
|
|
215
|
+
if (format === "json") {
|
|
216
|
+
console.log(JSON.stringify(patterns, null, 2));
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
console.log(`\n Pattern Registry (${patterns.length} patterns)\n ──────────────────────────`);
|
|
220
|
+
for (const p of patterns) {
|
|
221
|
+
const icon = p.type === "pattern" ? "✅" : "❌";
|
|
222
|
+
console.log(` ${icon} ${p.id.padEnd(30)} ${p.category.padEnd(15)} ${p.title}`);
|
|
223
|
+
}
|
|
224
|
+
console.log(`\n Use: judges pattern-registry --show <id>\n`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=pattern-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-registry.js","sourceRoot":"","sources":["../../src/commands/pattern-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance hotspot detection — scans code for common
|
|
3
|
+
* performance anti-patterns using pattern-based analysis.
|
|
4
|
+
*
|
|
5
|
+
* All data stored locally.
|
|
6
|
+
*/
|
|
7
|
+
export declare function runPerfHotspot(argv: string[]): void;
|
|
8
|
+
//# sourceMappingURL=perf-hotspot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"perf-hotspot.d.ts","sourceRoot":"","sources":["../../src/commands/perf-hotspot.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgMH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA6HnD"}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance hotspot detection — scans code for common
|
|
3
|
+
* performance anti-patterns using pattern-based analysis.
|
|
4
|
+
*
|
|
5
|
+
* All data stored locally.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, existsSync, mkdirSync, writeFileSync, readdirSync } from "fs";
|
|
8
|
+
import { join, extname } from "path";
|
|
9
|
+
// ─── Patterns ───────────────────────────────────────────────────────────────
|
|
10
|
+
const PERF_PATTERNS = [
|
|
11
|
+
{
|
|
12
|
+
id: "n-plus-one",
|
|
13
|
+
name: "N+1 Query Pattern",
|
|
14
|
+
severity: "critical",
|
|
15
|
+
description: "Database query inside a loop",
|
|
16
|
+
regex: /for\s*\(.*\)\s*\{[^}]*(?:\.query|\.execute|\.find|\.fetch|\.select|await\s+db\.|await\s+prisma\.)/s,
|
|
17
|
+
extensions: [".ts", ".js", ".py", ".java", ".go", ".rb"],
|
|
18
|
+
recommendation: "Batch queries outside the loop or use eager loading / JOIN",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: "unbounded-collection",
|
|
22
|
+
name: "Unbounded Collection Fetch",
|
|
23
|
+
severity: "high",
|
|
24
|
+
description: "Fetching all records without limit/pagination",
|
|
25
|
+
regex: /\.findAll\(\s*\)|\.find\(\s*\{\s*\}\s*\)|SELECT\s+\*\s+FROM\s+\w+\s*(?:WHERE|;|\)|$)/i,
|
|
26
|
+
extensions: [".ts", ".js", ".py", ".java", ".go", ".rb"],
|
|
27
|
+
recommendation: "Add LIMIT/pagination or use cursor-based fetching",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: "sync-io-hot-path",
|
|
31
|
+
name: "Synchronous I/O in Hot Path",
|
|
32
|
+
severity: "high",
|
|
33
|
+
description: "Synchronous file/network I/O that could block event loop",
|
|
34
|
+
regex: /readFileSync|writeFileSync|execSync|spawnSync/,
|
|
35
|
+
extensions: [".ts", ".js"],
|
|
36
|
+
recommendation: "Use async variants (readFile, writeFile, exec) in request handlers",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "string-concat-loop",
|
|
40
|
+
name: "String Concatenation in Loop",
|
|
41
|
+
severity: "medium",
|
|
42
|
+
description: "String concatenation inside a loop (O(n²) in some languages)",
|
|
43
|
+
regex: /for\s*\(.*\)\s*\{[^}]*\+=\s*["'`]|for\s*\(.*\)\s*\{[^}]*\+=\s*\w+/s,
|
|
44
|
+
extensions: [".ts", ".js", ".py", ".java", ".go", ".cs"],
|
|
45
|
+
recommendation: "Use array.join(), StringBuilder, or strings.Builder",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: "missing-index-hint",
|
|
49
|
+
name: "Missing Index Hint",
|
|
50
|
+
severity: "medium",
|
|
51
|
+
description: "Query with WHERE clause on non-obvious columns",
|
|
52
|
+
regex: /WHERE\s+\w+\.\w+\s*(?:=|LIKE|IN|>|<)\s*/i,
|
|
53
|
+
extensions: [".sql", ".ts", ".js", ".py", ".java"],
|
|
54
|
+
recommendation: "Ensure queried columns have appropriate database indexes",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "excessive-json-parse",
|
|
58
|
+
name: "Repeated JSON Parse/Stringify",
|
|
59
|
+
severity: "medium",
|
|
60
|
+
description: "JSON.parse/stringify inside loops or frequently called functions",
|
|
61
|
+
regex: /for\s*\(.*\)\s*\{[^}]*JSON\.(?:parse|stringify)/s,
|
|
62
|
+
extensions: [".ts", ".js"],
|
|
63
|
+
recommendation: "Parse once and reuse the object; consider streaming parsers for large data",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: "regex-in-loop",
|
|
67
|
+
name: "Regex Compilation in Loop",
|
|
68
|
+
severity: "low",
|
|
69
|
+
description: "Creating new RegExp objects inside loops",
|
|
70
|
+
regex: /for\s*\(.*\)\s*\{[^}]*new\s+RegExp\(/s,
|
|
71
|
+
extensions: [".ts", ".js", ".py", ".java"],
|
|
72
|
+
recommendation: "Compile regex once outside the loop and reuse",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: "large-object-spread",
|
|
76
|
+
name: "Large Object Spread in Loop",
|
|
77
|
+
severity: "medium",
|
|
78
|
+
description: "Object spread operator inside loops creates many copies",
|
|
79
|
+
regex: /for\s*\(.*\)\s*\{[^}]*\.\.\.\w+/s,
|
|
80
|
+
extensions: [".ts", ".js"],
|
|
81
|
+
recommendation: "Mutate directly or use Object.assign for better performance",
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
// ─── Scanner ────────────────────────────────────────────────────────────────
|
|
85
|
+
function scanFile(filePath, patterns) {
|
|
86
|
+
const ext = extname(filePath);
|
|
87
|
+
const applicable = patterns.filter((p) => p.extensions.includes(ext));
|
|
88
|
+
if (applicable.length === 0)
|
|
89
|
+
return [];
|
|
90
|
+
let content;
|
|
91
|
+
try {
|
|
92
|
+
content = readFileSync(filePath, "utf-8");
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
const lines = content.split("\n");
|
|
98
|
+
const hotspots = [];
|
|
99
|
+
for (const pattern of applicable) {
|
|
100
|
+
const match = pattern.regex.exec(content);
|
|
101
|
+
if (match) {
|
|
102
|
+
const beforeMatch = content.substring(0, match.index);
|
|
103
|
+
const lineNum = beforeMatch.split("\n").length;
|
|
104
|
+
hotspots.push({
|
|
105
|
+
file: filePath,
|
|
106
|
+
line: lineNum,
|
|
107
|
+
patternId: pattern.id,
|
|
108
|
+
patternName: pattern.name,
|
|
109
|
+
severity: pattern.severity,
|
|
110
|
+
snippet: lines[lineNum - 1]?.trim() || "",
|
|
111
|
+
recommendation: pattern.recommendation,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return hotspots;
|
|
116
|
+
}
|
|
117
|
+
function collectFiles(dir, exts, maxFiles) {
|
|
118
|
+
const result = [];
|
|
119
|
+
const skipDirs = new Set(["node_modules", ".git", "dist", "build", "coverage", ".next"]);
|
|
120
|
+
function walk(d) {
|
|
121
|
+
if (result.length >= maxFiles)
|
|
122
|
+
return;
|
|
123
|
+
let entries;
|
|
124
|
+
try {
|
|
125
|
+
entries = readdirSync(d, { withFileTypes: true }).map((e) => (typeof e === "string" ? e : e.name));
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
for (const entry of entries) {
|
|
131
|
+
if (result.length >= maxFiles)
|
|
132
|
+
return;
|
|
133
|
+
const full = join(d, entry);
|
|
134
|
+
if (skipDirs.has(entry))
|
|
135
|
+
continue;
|
|
136
|
+
try {
|
|
137
|
+
const stat = readFileSync(full, "utf-8"); // test readable
|
|
138
|
+
void stat;
|
|
139
|
+
if (exts.includes(extname(entry))) {
|
|
140
|
+
result.push(full);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// might be a directory
|
|
145
|
+
try {
|
|
146
|
+
const sub = readdirSync(full);
|
|
147
|
+
void sub;
|
|
148
|
+
walk(full);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// skip
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
walk(dir);
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
160
|
+
const STORE = ".judges-perf-hotspots";
|
|
161
|
+
export function runPerfHotspot(argv) {
|
|
162
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
163
|
+
console.log(`
|
|
164
|
+
judges perf-hotspot — Performance hotspot detection
|
|
165
|
+
|
|
166
|
+
Usage:
|
|
167
|
+
judges perf-hotspot [dir]
|
|
168
|
+
judges perf-hotspot src/ --severity critical,high
|
|
169
|
+
judges perf-hotspot --patterns
|
|
170
|
+
judges perf-hotspot --history
|
|
171
|
+
|
|
172
|
+
Options:
|
|
173
|
+
--severity <levels> Filter by severity (comma-separated)
|
|
174
|
+
--patterns List all performance patterns
|
|
175
|
+
--history Show scan history
|
|
176
|
+
--format json JSON output
|
|
177
|
+
--help, -h Show this help
|
|
178
|
+
`);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
182
|
+
// List patterns
|
|
183
|
+
if (argv.includes("--patterns")) {
|
|
184
|
+
if (format === "json") {
|
|
185
|
+
console.log(JSON.stringify(PERF_PATTERNS.map(({ regex: _r, ...rest }) => rest), null, 2));
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
console.log(`\n Performance Anti-Patterns (${PERF_PATTERNS.length})\n ──────────────────────────`);
|
|
189
|
+
for (const p of PERF_PATTERNS) {
|
|
190
|
+
console.log(` [${p.severity.toUpperCase().padEnd(8)}] ${p.id.padEnd(25)} ${p.name}`);
|
|
191
|
+
}
|
|
192
|
+
console.log("");
|
|
193
|
+
}
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
// History
|
|
197
|
+
if (argv.includes("--history")) {
|
|
198
|
+
const histPath = join(STORE, "scan-history.json");
|
|
199
|
+
const history = existsSync(histPath) ? JSON.parse(readFileSync(histPath, "utf-8")) : [];
|
|
200
|
+
if (format === "json") {
|
|
201
|
+
console.log(JSON.stringify(history, null, 2));
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
if (history.length === 0) {
|
|
205
|
+
console.log(" No scan history.");
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
console.log(`\n Scan History\n ──────────────────────────`);
|
|
209
|
+
for (const h of history.slice(-10)) {
|
|
210
|
+
console.log(` ${h.timestamp} ${h.scannedFiles} files ${h.hotspots} hotspots`);
|
|
211
|
+
}
|
|
212
|
+
console.log("");
|
|
213
|
+
}
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
// Scan
|
|
217
|
+
const scanDir = argv.find((a) => !a.startsWith("--") && !argv[argv.indexOf(a) - 1]?.startsWith("--")) || ".";
|
|
218
|
+
const sevFilter = argv.find((_a, i) => argv[i - 1] === "--severity");
|
|
219
|
+
const allowedSev = sevFilter ? sevFilter.split(",") : null;
|
|
220
|
+
const allExts = [...new Set(PERF_PATTERNS.flatMap((p) => p.extensions))];
|
|
221
|
+
const files = collectFiles(scanDir, allExts, 500);
|
|
222
|
+
let hotspots = [];
|
|
223
|
+
for (const file of files) {
|
|
224
|
+
hotspots.push(...scanFile(file, PERF_PATTERNS));
|
|
225
|
+
}
|
|
226
|
+
if (allowedSev) {
|
|
227
|
+
hotspots = hotspots.filter((h) => allowedSev.includes(h.severity));
|
|
228
|
+
}
|
|
229
|
+
const report = {
|
|
230
|
+
hotspots,
|
|
231
|
+
scannedFiles: files.length,
|
|
232
|
+
patternsChecked: PERF_PATTERNS.length,
|
|
233
|
+
timestamp: new Date().toISOString(),
|
|
234
|
+
};
|
|
235
|
+
// Save history
|
|
236
|
+
if (!existsSync(STORE))
|
|
237
|
+
mkdirSync(STORE, { recursive: true });
|
|
238
|
+
const histPath = join(STORE, "scan-history.json");
|
|
239
|
+
const history = existsSync(histPath) ? JSON.parse(readFileSync(histPath, "utf-8")) : [];
|
|
240
|
+
history.push({ timestamp: report.timestamp, scannedFiles: report.scannedFiles, hotspots: hotspots.length });
|
|
241
|
+
writeFileSync(histPath, JSON.stringify(history, null, 2));
|
|
242
|
+
if (format === "json") {
|
|
243
|
+
console.log(JSON.stringify(report, null, 2));
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
console.log(`\n Performance Hotspot Scan`);
|
|
247
|
+
console.log(` Scanned: ${report.scannedFiles} files Patterns: ${report.patternsChecked}`);
|
|
248
|
+
console.log(` Found: ${hotspots.length} hotspots\n ──────────────────────────`);
|
|
249
|
+
if (hotspots.length === 0) {
|
|
250
|
+
console.log(` ✅ No performance hotspots detected\n`);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const grouped = new Map();
|
|
254
|
+
for (const h of hotspots) {
|
|
255
|
+
const key = h.severity;
|
|
256
|
+
if (!grouped.has(key))
|
|
257
|
+
grouped.set(key, []);
|
|
258
|
+
grouped.get(key).push(h);
|
|
259
|
+
}
|
|
260
|
+
for (const sev of ["critical", "high", "medium", "low"]) {
|
|
261
|
+
const items = grouped.get(sev);
|
|
262
|
+
if (!items)
|
|
263
|
+
continue;
|
|
264
|
+
console.log(`\n ${sev.toUpperCase()} (${items.length})`);
|
|
265
|
+
for (const h of items) {
|
|
266
|
+
console.log(` ${h.file}:${h.line} — ${h.patternName}`);
|
|
267
|
+
console.log(` ${h.snippet}`);
|
|
268
|
+
console.log(` → ${h.recommendation}`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
console.log("");
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=perf-hotspot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"perf-hotspot.js","sourceRoot":"","sources":["../../src/commands/perf-hotspot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PR quality gate — automated pass/fail gate for PRs with
|
|
3
|
+
* configurable thresholds for auto-approval.
|
|
4
|
+
*
|
|
5
|
+
* All decisions are local — integrates via output format.
|
|
6
|
+
*/
|
|
7
|
+
interface GatePolicy {
|
|
8
|
+
maxCritical: number;
|
|
9
|
+
maxHigh: number;
|
|
10
|
+
maxTotal: number;
|
|
11
|
+
requireTestCoverage: boolean;
|
|
12
|
+
autoApproveBelow: number;
|
|
13
|
+
}
|
|
14
|
+
interface GateResult {
|
|
15
|
+
passed: boolean;
|
|
16
|
+
reason: string;
|
|
17
|
+
critical: number;
|
|
18
|
+
high: number;
|
|
19
|
+
medium: number;
|
|
20
|
+
low: number;
|
|
21
|
+
total: number;
|
|
22
|
+
score: number;
|
|
23
|
+
policy: GatePolicy;
|
|
24
|
+
timestamp: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function evaluateGate(critical: number, high: number, medium: number, low: number, score: number): GateResult;
|
|
27
|
+
export declare function runPrQualityGate(argv: string[]): void;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=pr-quality-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr-quality-gate.d.ts","sourceRoot":"","sources":["../../src/commands/pr-quality-gate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,UAAU,UAAU;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,UAAU,UAAU;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAsDD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,CAyCnH;AAID,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA0HrD"}
|