@kevinrabun/judges 3.58.0 → 3.59.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 +12 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +56 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/api-misuse.d.ts +5 -0
- package/dist/commands/api-misuse.d.ts.map +1 -0
- package/dist/commands/api-misuse.js +261 -0
- package/dist/commands/api-misuse.js.map +1 -0
- package/dist/commands/completion-audit.d.ts +5 -0
- package/dist/commands/completion-audit.d.ts.map +1 -0
- package/dist/commands/completion-audit.js +297 -0
- package/dist/commands/completion-audit.js.map +1 -0
- package/dist/commands/cross-file-consistency.d.ts +5 -0
- package/dist/commands/cross-file-consistency.d.ts.map +1 -0
- package/dist/commands/cross-file-consistency.js +255 -0
- package/dist/commands/cross-file-consistency.js.map +1 -0
- package/dist/commands/example-leak.d.ts +5 -0
- package/dist/commands/example-leak.d.ts.map +1 -0
- package/dist/commands/example-leak.js +233 -0
- package/dist/commands/example-leak.js.map +1 -0
- package/dist/commands/logic-lint.d.ts +5 -0
- package/dist/commands/logic-lint.d.ts.map +1 -0
- package/dist/commands/logic-lint.js +256 -0
- package/dist/commands/logic-lint.js.map +1 -0
- package/dist/commands/phantom-import.d.ts +5 -0
- package/dist/commands/phantom-import.d.ts.map +1 -0
- package/dist/commands/phantom-import.js +261 -0
- package/dist/commands/phantom-import.js.map +1 -0
- package/dist/commands/review-focus.d.ts +5 -0
- package/dist/commands/review-focus.d.ts.map +1 -0
- package/dist/commands/review-focus.js +197 -0
- package/dist/commands/review-focus.js.map +1 -0
- package/dist/commands/spec-conform.d.ts +5 -0
- package/dist/commands/spec-conform.d.ts.map +1 -0
- package/dist/commands/spec-conform.js +305 -0
- package/dist/commands/spec-conform.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logic lint — detect common logic errors that AI code generators produce.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, readdirSync, statSync } from "fs";
|
|
5
|
+
import { join, extname } from "path";
|
|
6
|
+
// ─── File Collection ────────────────────────────────────────────────────────
|
|
7
|
+
const CODE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".py", ".java", ".go", ".rs", ".cs"]);
|
|
8
|
+
function collectFiles(dir, max = 300) {
|
|
9
|
+
const files = [];
|
|
10
|
+
function walk(d) {
|
|
11
|
+
if (files.length >= max)
|
|
12
|
+
return;
|
|
13
|
+
let entries;
|
|
14
|
+
try {
|
|
15
|
+
entries = readdirSync(d);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
for (const e of entries) {
|
|
21
|
+
if (files.length >= max)
|
|
22
|
+
return;
|
|
23
|
+
if (e.startsWith(".") || e === "node_modules" || e === "dist" || e === "build")
|
|
24
|
+
continue;
|
|
25
|
+
const full = join(d, e);
|
|
26
|
+
try {
|
|
27
|
+
if (statSync(full).isDirectory())
|
|
28
|
+
walk(full);
|
|
29
|
+
else if (CODE_EXTS.has(extname(full)))
|
|
30
|
+
files.push(full);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
/* skip */
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
walk(dir);
|
|
38
|
+
return files;
|
|
39
|
+
}
|
|
40
|
+
// ─── Analysis ───────────────────────────────────────────────────────────────
|
|
41
|
+
function analyzeFile(filepath) {
|
|
42
|
+
const issues = [];
|
|
43
|
+
let content;
|
|
44
|
+
try {
|
|
45
|
+
content = readFileSync(filepath, "utf-8");
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return issues;
|
|
49
|
+
}
|
|
50
|
+
const lines = content.split("\n");
|
|
51
|
+
for (let i = 0; i < lines.length; i++) {
|
|
52
|
+
const line = lines[i];
|
|
53
|
+
const trimmed = line.trim();
|
|
54
|
+
// Tautological comparison: x === x, x !== x
|
|
55
|
+
if (/(\w+)\s*===\s*\1(?!\w)/.test(trimmed) || /(\w+)\s*!==\s*\1(?!\w)/.test(trimmed)) {
|
|
56
|
+
const match = trimmed.match(/(\w+)\s*[!=]==\s*\1(?!\w)/);
|
|
57
|
+
if (match && match[1] !== "NaN") {
|
|
58
|
+
issues.push({
|
|
59
|
+
file: filepath,
|
|
60
|
+
line: i + 1,
|
|
61
|
+
issue: "Tautological comparison",
|
|
62
|
+
severity: "high",
|
|
63
|
+
detail: `\`${match[1]}\` compared to itself — always true (===) or always false (!==)`,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Assignment in condition (single = in if/while)
|
|
68
|
+
if (/(?:if|while)\s*\(\s*[^=!<>]*[^=!<>]=[^=]/.test(trimmed) &&
|
|
69
|
+
!/==|!=|<=|>=/.test(trimmed.replace(/=[^=]/, "XX"))) {
|
|
70
|
+
if (!/===|!==/.test(trimmed)) {
|
|
71
|
+
issues.push({
|
|
72
|
+
file: filepath,
|
|
73
|
+
line: i + 1,
|
|
74
|
+
issue: "Assignment in condition",
|
|
75
|
+
severity: "high",
|
|
76
|
+
detail: "Single `=` in if/while condition — likely meant `===` or `==`",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Unreachable code after return/throw/break/continue
|
|
81
|
+
if (/^\s*(?:return|throw|break|continue)\b/.test(trimmed) && !trimmed.endsWith("{")) {
|
|
82
|
+
const nextLine = (lines[i + 1] || "").trim();
|
|
83
|
+
if (nextLine &&
|
|
84
|
+
nextLine !== "}" &&
|
|
85
|
+
nextLine !== "}" &&
|
|
86
|
+
!/^\s*(?:case|default|\/\/|\/\*|\*|else|catch|finally)/.test(nextLine)) {
|
|
87
|
+
issues.push({
|
|
88
|
+
file: filepath,
|
|
89
|
+
line: i + 2,
|
|
90
|
+
issue: "Unreachable code after flow control",
|
|
91
|
+
severity: "medium",
|
|
92
|
+
detail: "Code after return/throw/break/continue is never executed",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Off-by-one: <= array.length in loop (should be <)
|
|
97
|
+
if (/for\s*\([^;]*;\s*\w+\s*<=\s*\w+\.length\s*;/.test(trimmed)) {
|
|
98
|
+
issues.push({
|
|
99
|
+
file: filepath,
|
|
100
|
+
line: i + 1,
|
|
101
|
+
issue: "Off-by-one in loop bound",
|
|
102
|
+
severity: "high",
|
|
103
|
+
detail: "`<= .length` iterates one past the end — use `< .length`",
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// Constant condition in if/while
|
|
107
|
+
if (/(?:if|while)\s*\(\s*(?:true|false|1|0|null|undefined)\s*\)/.test(trimmed)) {
|
|
108
|
+
if (!/while\s*\(\s*true\s*\)/.test(trimmed)) {
|
|
109
|
+
issues.push({
|
|
110
|
+
file: filepath,
|
|
111
|
+
line: i + 1,
|
|
112
|
+
issue: "Constant condition",
|
|
113
|
+
severity: "medium",
|
|
114
|
+
detail: "Condition is always true or always false — branch is never taken or always taken",
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Inverted null check: if (x) { x = ... } vs if (!x) { x = ... }
|
|
119
|
+
if (/if\s*\(\s*(\w+)\s*\)\s*\{/.test(trimmed)) {
|
|
120
|
+
const varName = trimmed.match(/if\s*\(\s*(\w+)\s*\)/)?.[1];
|
|
121
|
+
const nextLines = lines.slice(i + 1, Math.min(i + 3, lines.length)).join("\n");
|
|
122
|
+
if (varName && new RegExp(`${varName}\\s*=\\s*(?:null|undefined|"")`).test(nextLines)) {
|
|
123
|
+
issues.push({
|
|
124
|
+
file: filepath,
|
|
125
|
+
line: i + 1,
|
|
126
|
+
issue: "Likely inverted null check",
|
|
127
|
+
severity: "medium",
|
|
128
|
+
detail: `Checking \`${varName}\` is truthy then setting it to null — did you mean \`!${varName}\`?`,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Mismatched operator precedence: a && b || c (missing parentheses)
|
|
133
|
+
if (/\w+\s*&&\s*\w+\s*\|\|\s*\w+/.test(trimmed) && !trimmed.includes("(")) {
|
|
134
|
+
issues.push({
|
|
135
|
+
file: filepath,
|
|
136
|
+
line: i + 1,
|
|
137
|
+
issue: "Ambiguous operator precedence",
|
|
138
|
+
severity: "low",
|
|
139
|
+
detail: "`&&` and `||` mixed without parentheses — intention is unclear",
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
// Empty catch block
|
|
143
|
+
if (/catch\s*\([^)]*\)\s*\{\s*\}/.test(trimmed)) {
|
|
144
|
+
issues.push({
|
|
145
|
+
file: filepath,
|
|
146
|
+
line: i + 1,
|
|
147
|
+
issue: "Empty catch block",
|
|
148
|
+
severity: "medium",
|
|
149
|
+
detail: "Errors silently swallowed — at minimum log the error",
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
// typeof compared to wrong string
|
|
153
|
+
if (/typeof\s+\w+\s*===?\s*['"]/.test(trimmed)) {
|
|
154
|
+
const typeVal = trimmed.match(/typeof\s+\w+\s*===?\s*['"]([\w]+)['"]/)?.[1];
|
|
155
|
+
const validTypes = new Set([
|
|
156
|
+
"string",
|
|
157
|
+
"number",
|
|
158
|
+
"boolean",
|
|
159
|
+
"object",
|
|
160
|
+
"function",
|
|
161
|
+
"undefined",
|
|
162
|
+
"symbol",
|
|
163
|
+
"bigint",
|
|
164
|
+
]);
|
|
165
|
+
if (typeVal && !validTypes.has(typeVal)) {
|
|
166
|
+
issues.push({
|
|
167
|
+
file: filepath,
|
|
168
|
+
line: i + 1,
|
|
169
|
+
issue: "Invalid typeof comparison",
|
|
170
|
+
severity: "high",
|
|
171
|
+
detail: `typeof never returns "${typeVal}" — valid values: ${[...validTypes].join(", ")}`,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Doubled negation logic: !!x === false or !(!x)
|
|
176
|
+
if (/!!\w+\s*===?\s*false/.test(trimmed) || /!\s*\(\s*!\s*\w+\s*\)/.test(trimmed)) {
|
|
177
|
+
issues.push({
|
|
178
|
+
file: filepath,
|
|
179
|
+
line: i + 1,
|
|
180
|
+
issue: "Redundant double negation",
|
|
181
|
+
severity: "low",
|
|
182
|
+
detail: "Double negation with false comparison — simplify the expression",
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
// Floating point equality
|
|
186
|
+
if (/(?:===?|!==?)\s*(?:\d+\.\d+|Math\.\w+)/.test(trimmed) && !/\.length|\.size|\.count|\.index/.test(trimmed)) {
|
|
187
|
+
if (/\d+\.\d+/.test(trimmed)) {
|
|
188
|
+
issues.push({
|
|
189
|
+
file: filepath,
|
|
190
|
+
line: i + 1,
|
|
191
|
+
issue: "Floating-point equality",
|
|
192
|
+
severity: "medium",
|
|
193
|
+
detail: "Exact equality with floating-point values is unreliable — use tolerance comparison (Math.abs(a-b) < epsilon)",
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return issues;
|
|
199
|
+
}
|
|
200
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
201
|
+
export function runLogicLint(argv) {
|
|
202
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
203
|
+
console.log(`
|
|
204
|
+
judges logic-lint — Detect common logic errors in AI-generated code
|
|
205
|
+
|
|
206
|
+
Usage:
|
|
207
|
+
judges logic-lint [dir]
|
|
208
|
+
judges logic-lint src/ --format json
|
|
209
|
+
|
|
210
|
+
Options:
|
|
211
|
+
[dir] Directory to scan (default: .)
|
|
212
|
+
--format json JSON output
|
|
213
|
+
--help, -h Show this help
|
|
214
|
+
|
|
215
|
+
Checks: tautological comparisons, assignment in conditions, off-by-one loops,
|
|
216
|
+
unreachable code, constant conditions, inverted null checks, ambiguous precedence,
|
|
217
|
+
empty catch blocks, invalid typeof, floating-point equality.
|
|
218
|
+
`);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
222
|
+
const dir = argv.find((a) => !a.startsWith("-") && argv.indexOf(a) > 0) || ".";
|
|
223
|
+
const files = collectFiles(dir);
|
|
224
|
+
const allIssues = [];
|
|
225
|
+
for (const f of files)
|
|
226
|
+
allIssues.push(...analyzeFile(f));
|
|
227
|
+
const highCount = allIssues.filter((i) => i.severity === "high").length;
|
|
228
|
+
const medCount = allIssues.filter((i) => i.severity === "medium").length;
|
|
229
|
+
const score = Math.max(0, 100 - highCount * 12 - medCount * 5);
|
|
230
|
+
if (format === "json") {
|
|
231
|
+
console.log(JSON.stringify({
|
|
232
|
+
issues: allIssues,
|
|
233
|
+
score,
|
|
234
|
+
summary: { high: highCount, medium: medCount, total: allIssues.length },
|
|
235
|
+
timestamp: new Date().toISOString(),
|
|
236
|
+
}, null, 2));
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
const badge = score >= 80 ? "✅ CLEAN" : score >= 50 ? "⚠️ SUSPECT" : "❌ BUGGY";
|
|
240
|
+
console.log(`\n Logic Lint: ${badge} (${score}/100)\n ─────────────────────────────`);
|
|
241
|
+
if (allIssues.length === 0) {
|
|
242
|
+
console.log(" No logic issues detected.\n");
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
for (const issue of allIssues.slice(0, 25)) {
|
|
246
|
+
const icon = issue.severity === "high" ? "🔴" : issue.severity === "medium" ? "🟡" : "🔵";
|
|
247
|
+
console.log(` ${icon} ${issue.issue}`);
|
|
248
|
+
console.log(` ${issue.file}:${issue.line}`);
|
|
249
|
+
console.log(` ${issue.detail}`);
|
|
250
|
+
}
|
|
251
|
+
if (allIssues.length > 25)
|
|
252
|
+
console.log(` ... and ${allIssues.length - 25} more`);
|
|
253
|
+
console.log(`\n Total: ${allIssues.length} | High: ${highCount} | Medium: ${medCount} | Score: ${score}/100\n`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=logic-lint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logic-lint.js","sourceRoot":"","sources":["../../src/commands/logic-lint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phantom-import.d.ts","sourceRoot":"","sources":["../../src/commands/phantom-import.ts"],"names":[],"mappings":"AAAA;;GAEG;AA8NH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CA8DrD"}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phantom import — detect hallucinated imports, non-existent modules, and wrong export names.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, readdirSync, statSync, existsSync } from "fs";
|
|
5
|
+
import { join, extname, dirname, resolve } from "path";
|
|
6
|
+
// ─── File Collection ────────────────────────────────────────────────────────
|
|
7
|
+
const CODE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx"]);
|
|
8
|
+
function collectFiles(dir, max = 300) {
|
|
9
|
+
const files = [];
|
|
10
|
+
function walk(d) {
|
|
11
|
+
if (files.length >= max)
|
|
12
|
+
return;
|
|
13
|
+
let entries;
|
|
14
|
+
try {
|
|
15
|
+
entries = readdirSync(d);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
for (const e of entries) {
|
|
21
|
+
if (files.length >= max)
|
|
22
|
+
return;
|
|
23
|
+
if (e.startsWith(".") || e === "node_modules" || e === "dist" || e === "build")
|
|
24
|
+
continue;
|
|
25
|
+
const full = join(d, e);
|
|
26
|
+
try {
|
|
27
|
+
if (statSync(full).isDirectory())
|
|
28
|
+
walk(full);
|
|
29
|
+
else if (CODE_EXTS.has(extname(full)))
|
|
30
|
+
files.push(full);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
/* skip */
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
walk(dir);
|
|
38
|
+
return files;
|
|
39
|
+
}
|
|
40
|
+
// ─── Exports Index ──────────────────────────────────────────────────────────
|
|
41
|
+
function buildExportsMap(files) {
|
|
42
|
+
const exports = new Map();
|
|
43
|
+
for (const filepath of files) {
|
|
44
|
+
let content;
|
|
45
|
+
try {
|
|
46
|
+
content = readFileSync(filepath, "utf-8");
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const names = new Set();
|
|
52
|
+
// export function/class/const/let/var/type/interface/enum
|
|
53
|
+
for (const m of content.matchAll(/export\s+(?:default\s+)?(?:function|class|const|let|var|type|interface|enum)\s+(\w+)/g)) {
|
|
54
|
+
names.add(m[1]);
|
|
55
|
+
}
|
|
56
|
+
// export { ... }
|
|
57
|
+
for (const m of content.matchAll(/export\s*\{([^}]+)\}/g)) {
|
|
58
|
+
for (const name of m[1].split(",")) {
|
|
59
|
+
const cleaned = name
|
|
60
|
+
.trim()
|
|
61
|
+
.split(/\s+as\s+/)[0]
|
|
62
|
+
.trim();
|
|
63
|
+
if (cleaned)
|
|
64
|
+
names.add(cleaned);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// export default
|
|
68
|
+
if (/export\s+default\s/.test(content))
|
|
69
|
+
names.add("default");
|
|
70
|
+
exports.set(filepath, names);
|
|
71
|
+
}
|
|
72
|
+
return exports;
|
|
73
|
+
}
|
|
74
|
+
// ─── Analysis ───────────────────────────────────────────────────────────────
|
|
75
|
+
function analyzeFile(filepath, exportsMap, projectDir) {
|
|
76
|
+
const issues = [];
|
|
77
|
+
let content;
|
|
78
|
+
try {
|
|
79
|
+
content = readFileSync(filepath, "utf-8");
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return issues;
|
|
83
|
+
}
|
|
84
|
+
const lines = content.split("\n");
|
|
85
|
+
for (let i = 0; i < lines.length; i++) {
|
|
86
|
+
const line = lines[i];
|
|
87
|
+
// import from relative path
|
|
88
|
+
const relImport = line.match(/import\s+(?:\{[^}]*\}|[\w*]+(?:\s*,\s*\{[^}]*\})?)\s+from\s+['"](\.[^'"]+)['"]/);
|
|
89
|
+
if (relImport) {
|
|
90
|
+
const importPath = relImport[1];
|
|
91
|
+
const dir = dirname(filepath);
|
|
92
|
+
const candidates = [
|
|
93
|
+
resolve(dir, importPath),
|
|
94
|
+
resolve(dir, importPath + ".ts"),
|
|
95
|
+
resolve(dir, importPath + ".tsx"),
|
|
96
|
+
resolve(dir, importPath + ".js"),
|
|
97
|
+
resolve(dir, importPath + ".jsx"),
|
|
98
|
+
resolve(dir, importPath, "index.ts"),
|
|
99
|
+
resolve(dir, importPath, "index.js"),
|
|
100
|
+
];
|
|
101
|
+
const resolved = candidates.find((c) => existsSync(c));
|
|
102
|
+
if (!resolved) {
|
|
103
|
+
issues.push({
|
|
104
|
+
file: filepath,
|
|
105
|
+
line: i + 1,
|
|
106
|
+
issue: "Import resolves to non-existent file",
|
|
107
|
+
severity: "high",
|
|
108
|
+
detail: `\`${importPath}\` does not exist — AI may have hallucinated this module path`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// Check named imports exist in target
|
|
113
|
+
const namedMatch = line.match(/import\s*\{([^}]+)\}\s*from/);
|
|
114
|
+
if (namedMatch) {
|
|
115
|
+
const targetExports = exportsMap.get(resolved);
|
|
116
|
+
if (targetExports) {
|
|
117
|
+
const imported = namedMatch[1]
|
|
118
|
+
.split(",")
|
|
119
|
+
.map((n) => n
|
|
120
|
+
.trim()
|
|
121
|
+
.split(/\s+as\s+/)[0]
|
|
122
|
+
.trim())
|
|
123
|
+
.filter(Boolean);
|
|
124
|
+
for (const name of imported) {
|
|
125
|
+
if (!targetExports.has(name)) {
|
|
126
|
+
issues.push({
|
|
127
|
+
file: filepath,
|
|
128
|
+
line: i + 1,
|
|
129
|
+
issue: "Named import does not exist in target",
|
|
130
|
+
severity: "high",
|
|
131
|
+
detail: `\`${name}\` is not exported from \`${importPath}\` — may be a hallucinated export name`,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Common hallucinated npm packages (AI often invents package names)
|
|
140
|
+
const npmImport = line.match(/import\s+.*\s+from\s+['"]([a-z@][a-z0-9./_-]*)['"]/);
|
|
141
|
+
if (npmImport && !npmImport[1].startsWith(".")) {
|
|
142
|
+
const pkg = npmImport[1]
|
|
143
|
+
.split("/")
|
|
144
|
+
.slice(0, npmImport[1].startsWith("@") ? 2 : 1)
|
|
145
|
+
.join("/");
|
|
146
|
+
// Check if package exists in node_modules
|
|
147
|
+
const nmPath = join(projectDir, "node_modules", pkg);
|
|
148
|
+
if (!existsSync(nmPath)) {
|
|
149
|
+
// Check if it's in package.json
|
|
150
|
+
try {
|
|
151
|
+
const pkgJson = JSON.parse(readFileSync(join(projectDir, "package.json"), "utf-8"));
|
|
152
|
+
const allDeps = { ...pkgJson.dependencies, ...pkgJson.devDependencies, ...pkgJson.peerDependencies };
|
|
153
|
+
if (!allDeps[pkg]) {
|
|
154
|
+
issues.push({
|
|
155
|
+
file: filepath,
|
|
156
|
+
line: i + 1,
|
|
157
|
+
issue: "Import from uninstalled package",
|
|
158
|
+
severity: "high",
|
|
159
|
+
detail: `\`${pkg}\` is not in package.json or node_modules — may be a hallucinated package`,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
/* skip */
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// require() of non-existent relative path
|
|
169
|
+
const requireMatch = line.match(/require\s*\(\s*['"](\.[^'"]+)['"]\s*\)/);
|
|
170
|
+
if (requireMatch) {
|
|
171
|
+
const reqPath = requireMatch[1];
|
|
172
|
+
const dir = dirname(filepath);
|
|
173
|
+
const candidates = [
|
|
174
|
+
resolve(dir, reqPath),
|
|
175
|
+
resolve(dir, reqPath + ".ts"),
|
|
176
|
+
resolve(dir, reqPath + ".js"),
|
|
177
|
+
resolve(dir, reqPath + ".json"),
|
|
178
|
+
resolve(dir, reqPath, "index.js"),
|
|
179
|
+
];
|
|
180
|
+
if (!candidates.some((c) => existsSync(c))) {
|
|
181
|
+
issues.push({
|
|
182
|
+
file: filepath,
|
|
183
|
+
line: i + 1,
|
|
184
|
+
issue: "require() of non-existent module",
|
|
185
|
+
severity: "high",
|
|
186
|
+
detail: `\`${reqPath}\` does not resolve to any file — may be hallucinated`,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Importing from deprecated / removed Node.js APIs
|
|
191
|
+
const deprecatedImport = line.match(/(?:import|require)\s*(?:\(?\s*['"])(sys|_linklist|constants|punycode|domain|v8\/tools|node:sys)['"](?:\))?/);
|
|
192
|
+
if (deprecatedImport) {
|
|
193
|
+
issues.push({
|
|
194
|
+
file: filepath,
|
|
195
|
+
line: i + 1,
|
|
196
|
+
issue: "Import of deprecated Node.js module",
|
|
197
|
+
severity: "medium",
|
|
198
|
+
detail: `\`${deprecatedImport[1]}\` is deprecated or removed — AI may be referencing outdated API`,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return issues;
|
|
203
|
+
}
|
|
204
|
+
// ─── CLI ────────────────────────────────────────────────────────────────────
|
|
205
|
+
export function runPhantomImport(argv) {
|
|
206
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
207
|
+
console.log(`
|
|
208
|
+
judges phantom-import — Detect hallucinated imports and non-existent modules
|
|
209
|
+
|
|
210
|
+
Usage:
|
|
211
|
+
judges phantom-import [dir]
|
|
212
|
+
judges phantom-import src/ --format json
|
|
213
|
+
|
|
214
|
+
Options:
|
|
215
|
+
[dir] Directory to scan (default: .)
|
|
216
|
+
--format json JSON output
|
|
217
|
+
--help, -h Show this help
|
|
218
|
+
|
|
219
|
+
Checks: non-existent relative imports, hallucinated named exports, uninstalled packages,
|
|
220
|
+
deprecated Node.js modules, require() of missing files.
|
|
221
|
+
`);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const format = argv.find((_a, i) => argv[i - 1] === "--format") || "text";
|
|
225
|
+
const dir = argv.find((a) => !a.startsWith("-") && argv.indexOf(a) > 0) || ".";
|
|
226
|
+
const projectDir = resolve(dir);
|
|
227
|
+
const files = collectFiles(dir);
|
|
228
|
+
const exportsMap = buildExportsMap(files);
|
|
229
|
+
const allIssues = [];
|
|
230
|
+
for (const f of files)
|
|
231
|
+
allIssues.push(...analyzeFile(f, exportsMap, projectDir));
|
|
232
|
+
const highCount = allIssues.filter((i) => i.severity === "high").length;
|
|
233
|
+
const medCount = allIssues.filter((i) => i.severity === "medium").length;
|
|
234
|
+
const score = Math.max(0, 100 - highCount * 15 - medCount * 5);
|
|
235
|
+
if (format === "json") {
|
|
236
|
+
console.log(JSON.stringify({
|
|
237
|
+
issues: allIssues,
|
|
238
|
+
score,
|
|
239
|
+
summary: { high: highCount, medium: medCount, total: allIssues.length },
|
|
240
|
+
timestamp: new Date().toISOString(),
|
|
241
|
+
}, null, 2));
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
const badge = score >= 80 ? "✅ CLEAN" : score >= 50 ? "⚠️ SUSPECT" : "❌ PHANTOMS";
|
|
245
|
+
console.log(`\n Phantom Import: ${badge} (${score}/100)\n ─────────────────────────────`);
|
|
246
|
+
if (allIssues.length === 0) {
|
|
247
|
+
console.log(" No phantom imports detected.\n");
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
for (const issue of allIssues.slice(0, 25)) {
|
|
251
|
+
const icon = issue.severity === "high" ? "🔴" : issue.severity === "medium" ? "🟡" : "🔵";
|
|
252
|
+
console.log(` ${icon} ${issue.issue}`);
|
|
253
|
+
console.log(` ${issue.file}:${issue.line}`);
|
|
254
|
+
console.log(` ${issue.detail}`);
|
|
255
|
+
}
|
|
256
|
+
if (allIssues.length > 25)
|
|
257
|
+
console.log(` ... and ${allIssues.length - 25} more`);
|
|
258
|
+
console.log(`\n Total: ${allIssues.length} | High: ${highCount} | Medium: ${medCount} | Score: ${score}/100\n`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=phantom-import.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phantom-import.js","sourceRoot":"","sources":["../../src/commands/phantom-import.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-focus.d.ts","sourceRoot":"","sources":["../../src/commands/review-focus.ts"],"names":[],"mappings":"AAAA;;GAEG;AA6JH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAuEnD"}
|