@vibecheckai/cli 3.5.0 → 3.5.2

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 (224) hide show
  1. package/bin/registry.js +214 -237
  2. package/bin/runners/cli-utils.js +33 -2
  3. package/bin/runners/context/analyzer.js +52 -1
  4. package/bin/runners/context/generators/cursor.js +2 -49
  5. package/bin/runners/context/git-context.js +3 -1
  6. package/bin/runners/context/team-conventions.js +33 -7
  7. package/bin/runners/lib/analysis-core.js +25 -5
  8. package/bin/runners/lib/analyzers.js +431 -481
  9. package/bin/runners/lib/default-config.js +127 -0
  10. package/bin/runners/lib/doctor/modules/security.js +3 -1
  11. package/bin/runners/lib/engine/ast-cache.js +210 -0
  12. package/bin/runners/lib/engine/auth-extractor.js +211 -0
  13. package/bin/runners/lib/engine/billing-extractor.js +112 -0
  14. package/bin/runners/lib/engine/enforcement-extractor.js +100 -0
  15. package/bin/runners/lib/engine/env-extractor.js +207 -0
  16. package/bin/runners/lib/engine/express-extractor.js +208 -0
  17. package/bin/runners/lib/engine/extractors.js +849 -0
  18. package/bin/runners/lib/engine/index.js +207 -0
  19. package/bin/runners/lib/engine/repo-index.js +514 -0
  20. package/bin/runners/lib/engine/types.js +124 -0
  21. package/bin/runners/lib/engines/accessibility-engine.js +18 -218
  22. package/bin/runners/lib/engines/api-consistency-engine.js +30 -335
  23. package/bin/runners/lib/engines/cross-file-analysis-engine.js +27 -292
  24. package/bin/runners/lib/engines/empty-catch-engine.js +17 -127
  25. package/bin/runners/lib/engines/mock-data-engine.js +10 -53
  26. package/bin/runners/lib/engines/performance-issues-engine.js +36 -176
  27. package/bin/runners/lib/engines/security-vulnerabilities-engine.js +54 -382
  28. package/bin/runners/lib/engines/type-aware-engine.js +39 -263
  29. package/bin/runners/lib/engines/vibecheck-engines/index.js +13 -122
  30. package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
  31. package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
  32. package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
  33. package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
  34. package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
  35. package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
  36. package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
  37. package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +73 -373
  38. package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
  39. package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
  40. package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
  41. package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
  42. package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
  43. package/bin/runners/lib/entitlements-v2.js +73 -97
  44. package/bin/runners/lib/error-handler.js +44 -3
  45. package/bin/runners/lib/error-messages.js +289 -0
  46. package/bin/runners/lib/evidence-pack.js +7 -1
  47. package/bin/runners/lib/finding-id.js +69 -0
  48. package/bin/runners/lib/finding-sorter.js +89 -0
  49. package/bin/runners/lib/html-proof-report.js +700 -350
  50. package/bin/runners/lib/missions/plan.js +6 -46
  51. package/bin/runners/lib/missions/templates.js +0 -232
  52. package/bin/runners/lib/next-action.js +560 -0
  53. package/bin/runners/lib/prerequisites.js +149 -0
  54. package/bin/runners/lib/route-detection.js +137 -68
  55. package/bin/runners/lib/scan-output.js +91 -76
  56. package/bin/runners/lib/scan-runner.js +135 -0
  57. package/bin/runners/lib/schemas/ajv-validator.js +464 -0
  58. package/bin/runners/lib/schemas/error-envelope.schema.json +105 -0
  59. package/bin/runners/lib/schemas/finding-v3.schema.json +151 -0
  60. package/bin/runners/lib/schemas/report-artifact.schema.json +120 -0
  61. package/bin/runners/lib/schemas/run-request.schema.json +108 -0
  62. package/bin/runners/lib/schemas/validator.js +27 -0
  63. package/bin/runners/lib/schemas/verdict.schema.json +140 -0
  64. package/bin/runners/lib/ship-output-enterprise.js +23 -23
  65. package/bin/runners/lib/ship-output.js +75 -31
  66. package/bin/runners/lib/terminal-ui.js +6 -113
  67. package/bin/runners/lib/truth.js +351 -10
  68. package/bin/runners/lib/unified-cli-output.js +430 -603
  69. package/bin/runners/lib/unified-output.js +13 -9
  70. package/bin/runners/runAIAgent.js +10 -5
  71. package/bin/runners/runAgent.js +0 -3
  72. package/bin/runners/runAllowlist.js +389 -0
  73. package/bin/runners/runApprove.js +0 -33
  74. package/bin/runners/runAuth.js +73 -45
  75. package/bin/runners/runCheckpoint.js +51 -11
  76. package/bin/runners/runClassify.js +85 -21
  77. package/bin/runners/runContext.js +0 -3
  78. package/bin/runners/runDoctor.js +41 -28
  79. package/bin/runners/runEvidencePack.js +362 -0
  80. package/bin/runners/runFirewall.js +0 -3
  81. package/bin/runners/runFirewallHook.js +0 -3
  82. package/bin/runners/runFix.js +66 -76
  83. package/bin/runners/runGuard.js +18 -411
  84. package/bin/runners/runInit.js +113 -30
  85. package/bin/runners/runLabs.js +424 -0
  86. package/bin/runners/runMcp.js +19 -25
  87. package/bin/runners/runPolish.js +64 -240
  88. package/bin/runners/runPromptFirewall.js +12 -5
  89. package/bin/runners/runProve.js +57 -22
  90. package/bin/runners/runQuickstart.js +531 -0
  91. package/bin/runners/runReality.js +59 -68
  92. package/bin/runners/runReport.js +38 -33
  93. package/bin/runners/runRuntime.js +8 -5
  94. package/bin/runners/runScan.js +1413 -190
  95. package/bin/runners/runShip.js +113 -719
  96. package/bin/runners/runTruth.js +0 -3
  97. package/bin/runners/runValidate.js +13 -9
  98. package/bin/runners/runWatch.js +23 -14
  99. package/bin/scan.js +6 -1
  100. package/bin/vibecheck.js +204 -185
  101. package/mcp-server/deprecation-middleware.js +282 -0
  102. package/mcp-server/handlers/index.ts +15 -0
  103. package/mcp-server/handlers/tool-handler.ts +554 -0
  104. package/mcp-server/index-v1.js +698 -0
  105. package/mcp-server/index.js +210 -238
  106. package/mcp-server/lib/cache-wrapper.cjs +383 -0
  107. package/mcp-server/lib/error-envelope.js +138 -0
  108. package/mcp-server/lib/executor.ts +499 -0
  109. package/mcp-server/lib/index.ts +19 -0
  110. package/mcp-server/lib/rate-limiter.js +166 -0
  111. package/mcp-server/lib/sandbox.test.ts +519 -0
  112. package/mcp-server/lib/sandbox.ts +395 -0
  113. package/mcp-server/lib/types.ts +267 -0
  114. package/mcp-server/package.json +12 -3
  115. package/mcp-server/registry/tool-registry.js +794 -0
  116. package/mcp-server/registry/tools.json +605 -0
  117. package/mcp-server/registry.test.ts +334 -0
  118. package/mcp-server/tests/tier-gating.test.js +297 -0
  119. package/mcp-server/tier-auth.js +378 -45
  120. package/mcp-server/tools-v3.js +353 -442
  121. package/mcp-server/tsconfig.json +37 -0
  122. package/mcp-server/vibecheck-2.0-tools.js +14 -1
  123. package/package.json +1 -1
  124. package/bin/runners/lib/agent-firewall/learning/learning-engine.js +0 -849
  125. package/bin/runners/lib/audit-logger.js +0 -532
  126. package/bin/runners/lib/authority/authorities/architecture.js +0 -364
  127. package/bin/runners/lib/authority/authorities/compliance.js +0 -341
  128. package/bin/runners/lib/authority/authorities/human.js +0 -343
  129. package/bin/runners/lib/authority/authorities/quality.js +0 -420
  130. package/bin/runners/lib/authority/authorities/security.js +0 -228
  131. package/bin/runners/lib/authority/index.js +0 -293
  132. package/bin/runners/lib/bundle/bundle-intelligence.js +0 -846
  133. package/bin/runners/lib/cli-charts.js +0 -368
  134. package/bin/runners/lib/cli-config-display.js +0 -405
  135. package/bin/runners/lib/cli-demo.js +0 -275
  136. package/bin/runners/lib/cli-errors.js +0 -438
  137. package/bin/runners/lib/cli-help-formatter.js +0 -439
  138. package/bin/runners/lib/cli-interactive-menu.js +0 -509
  139. package/bin/runners/lib/cli-prompts.js +0 -441
  140. package/bin/runners/lib/cli-scan-cards.js +0 -362
  141. package/bin/runners/lib/compliance-reporter.js +0 -710
  142. package/bin/runners/lib/conductor/index.js +0 -671
  143. package/bin/runners/lib/easy/README.md +0 -123
  144. package/bin/runners/lib/easy/index.js +0 -140
  145. package/bin/runners/lib/easy/interactive-wizard.js +0 -788
  146. package/bin/runners/lib/easy/one-click-firewall.js +0 -564
  147. package/bin/runners/lib/easy/zero-config-reality.js +0 -714
  148. package/bin/runners/lib/engines/async-patterns-engine.js +0 -444
  149. package/bin/runners/lib/engines/bundle-size-engine.js +0 -433
  150. package/bin/runners/lib/engines/confidence-scoring.js +0 -276
  151. package/bin/runners/lib/engines/context-detection.js +0 -264
  152. package/bin/runners/lib/engines/database-patterns-engine.js +0 -429
  153. package/bin/runners/lib/engines/duplicate-code-engine.js +0 -354
  154. package/bin/runners/lib/engines/env-variables-engine.js +0 -458
  155. package/bin/runners/lib/engines/error-handling-engine.js +0 -437
  156. package/bin/runners/lib/engines/false-positive-prevention.js +0 -630
  157. package/bin/runners/lib/engines/framework-adapters/index.js +0 -607
  158. package/bin/runners/lib/engines/framework-detection.js +0 -508
  159. package/bin/runners/lib/engines/import-order-engine.js +0 -429
  160. package/bin/runners/lib/engines/naming-conventions-engine.js +0 -544
  161. package/bin/runners/lib/engines/noise-reduction-engine.js +0 -452
  162. package/bin/runners/lib/engines/orchestrator.js +0 -334
  163. package/bin/runners/lib/engines/react-patterns-engine.js +0 -457
  164. package/bin/runners/lib/engines/vibecheck-engines/lib/ai-hallucination-engine.js +0 -806
  165. package/bin/runners/lib/engines/vibecheck-engines/lib/smart-fix-engine.js +0 -577
  166. package/bin/runners/lib/engines/vibecheck-engines/lib/vibe-score-engine.js +0 -543
  167. package/bin/runners/lib/engines/vibecheck-engines.js +0 -514
  168. package/bin/runners/lib/enhanced-features/index.js +0 -305
  169. package/bin/runners/lib/enhanced-output.js +0 -631
  170. package/bin/runners/lib/enterprise.js +0 -300
  171. package/bin/runners/lib/firewall/command-validator.js +0 -351
  172. package/bin/runners/lib/firewall/config.js +0 -341
  173. package/bin/runners/lib/firewall/content-validator.js +0 -519
  174. package/bin/runners/lib/firewall/index.js +0 -101
  175. package/bin/runners/lib/firewall/path-validator.js +0 -256
  176. package/bin/runners/lib/intelligence/cross-repo-intelligence.js +0 -817
  177. package/bin/runners/lib/mcp-utils.js +0 -425
  178. package/bin/runners/lib/output/index.js +0 -1022
  179. package/bin/runners/lib/policy-engine.js +0 -652
  180. package/bin/runners/lib/polish/autofix/accessibility-fixes.js +0 -333
  181. package/bin/runners/lib/polish/autofix/async-handlers.js +0 -273
  182. package/bin/runners/lib/polish/autofix/dead-code.js +0 -280
  183. package/bin/runners/lib/polish/autofix/imports-optimizer.js +0 -344
  184. package/bin/runners/lib/polish/autofix/index.js +0 -200
  185. package/bin/runners/lib/polish/autofix/remove-consoles.js +0 -209
  186. package/bin/runners/lib/polish/autofix/strengthen-types.js +0 -245
  187. package/bin/runners/lib/polish/backend-checks.js +0 -148
  188. package/bin/runners/lib/polish/documentation-checks.js +0 -111
  189. package/bin/runners/lib/polish/frontend-checks.js +0 -168
  190. package/bin/runners/lib/polish/index.js +0 -71
  191. package/bin/runners/lib/polish/infrastructure-checks.js +0 -131
  192. package/bin/runners/lib/polish/library-detection.js +0 -175
  193. package/bin/runners/lib/polish/performance-checks.js +0 -100
  194. package/bin/runners/lib/polish/security-checks.js +0 -148
  195. package/bin/runners/lib/polish/utils.js +0 -203
  196. package/bin/runners/lib/prompt-builder.js +0 -540
  197. package/bin/runners/lib/proof-certificate.js +0 -634
  198. package/bin/runners/lib/reality/accessibility-audit.js +0 -946
  199. package/bin/runners/lib/reality/api-contract-validator.js +0 -1012
  200. package/bin/runners/lib/reality/chaos-engineering.js +0 -1084
  201. package/bin/runners/lib/reality/performance-tracker.js +0 -1077
  202. package/bin/runners/lib/reality/scenario-generator.js +0 -1404
  203. package/bin/runners/lib/reality/visual-regression.js +0 -852
  204. package/bin/runners/lib/reality-profiler.js +0 -717
  205. package/bin/runners/lib/replay/flight-recorder-viewer.js +0 -1160
  206. package/bin/runners/lib/review/ai-code-review.js +0 -832
  207. package/bin/runners/lib/rules/custom-rule-engine.js +0 -985
  208. package/bin/runners/lib/sbom-generator.js +0 -641
  209. package/bin/runners/lib/scan-output-enhanced.js +0 -512
  210. package/bin/runners/lib/security/owasp-scanner.js +0 -939
  211. package/bin/runners/lib/validators/contract-validator.js +0 -283
  212. package/bin/runners/lib/validators/dead-export-detector.js +0 -279
  213. package/bin/runners/lib/validators/dep-audit.js +0 -245
  214. package/bin/runners/lib/validators/env-validator.js +0 -319
  215. package/bin/runners/lib/validators/index.js +0 -120
  216. package/bin/runners/lib/validators/license-checker.js +0 -252
  217. package/bin/runners/lib/validators/route-validator.js +0 -290
  218. package/bin/runners/runAuthority.js +0 -528
  219. package/bin/runners/runConductor.js +0 -772
  220. package/bin/runners/runContainer.js +0 -366
  221. package/bin/runners/runEasy.js +0 -410
  222. package/bin/runners/runIaC.js +0 -372
  223. package/bin/runners/runVibe.js +0 -791
  224. package/mcp-server/tools.js +0 -495
@@ -1,19 +1,12 @@
1
1
  /**
2
2
  * Mock Data Detection Engine
3
3
  * Uses AST analysis to detect mock/test data patterns in production code
4
- * Enhanced with context-aware detection to reduce false positives
5
4
  */
6
5
 
7
6
  const { getAST, parseCode } = require("./ast-cache");
8
7
  const traverse = require("@babel/traverse").default;
9
8
  const t = require("@babel/types");
10
9
  const { shouldExcludeFile } = require("./file-filter");
11
- const {
12
- detectFalsePositive,
13
- quickFalsePositiveCheck,
14
- isTailwindPlaceholderModifier,
15
- isLegitimateUILabel,
16
- } = require("./context-detection");
17
10
 
18
11
  /**
19
12
  * Check if a string literal looks like mock/test data
@@ -113,25 +106,6 @@ function isSuspiciousSetTimeout(node) {
113
106
  return false;
114
107
  }
115
108
 
116
- /**
117
- * Check if a finding should be skipped due to context
118
- */
119
- function shouldSkipFinding(line, lineIndex, lines, patternType) {
120
- // Quick pre-filter for common false positives
121
- if (quickFalsePositiveCheck(line)) {
122
- return true;
123
- }
124
-
125
- // Detailed context analysis
126
- const result = detectFalsePositive(line, line, {
127
- lineIndex,
128
- allLines: lines,
129
- patternType,
130
- });
131
-
132
- return result.isFalsePositive;
133
- }
134
-
135
109
  /**
136
110
  * Analyze a file for mock data patterns
137
111
  */
@@ -151,16 +125,10 @@ function analyzeMockData(code, filePath) {
151
125
  VariableDeclarator(path) {
152
126
  const id = path.node.id;
153
127
  const init = path.node.init;
154
- const line = getLineNumber(path.node, code);
155
- const lineContent = lines[line - 1] || "";
156
-
157
- // Skip if this line is a false positive (CSS class, UI label, etc.)
158
- if (shouldSkipFinding(lineContent, line - 1, lines, "mock")) {
159
- return;
160
- }
161
128
 
162
129
  // Check variable name
163
130
  if (t.isIdentifier(id) && isMockVariableName(id.name)) {
131
+ const line = getLineNumber(path.node, code);
164
132
  findings.push({
165
133
  type: "mock_variable",
166
134
  severity: "WARN",
@@ -170,13 +138,14 @@ function analyzeMockData(code, filePath) {
170
138
  column: path.node.loc.start.column,
171
139
  title: `Mock data variable: ${id.name}`,
172
140
  message: `Variable name suggests mock/test data: ${id.name}`,
173
- codeSnippet: lineContent.trim(),
141
+ codeSnippet: lines[line - 1]?.trim(),
174
142
  confidence: "high",
175
143
  });
176
144
  }
177
145
 
178
146
  // Check initializer value
179
147
  if (init && t.isStringLiteral(init) && isMockString(init.value)) {
148
+ const line = getLineNumber(path.node, code);
180
149
  findings.push({
181
150
  type: "mock_string_literal",
182
151
  severity: "WARN",
@@ -186,7 +155,7 @@ function analyzeMockData(code, filePath) {
186
155
  column: path.node.loc.start.column,
187
156
  title: "Mock/test string literal detected",
188
157
  message: `String value appears to be mock data: "${init.value.substring(0, 50)}"`,
189
- codeSnippet: lineContent.trim(),
158
+ codeSnippet: lines[line - 1]?.trim(),
190
159
  confidence: "med",
191
160
  });
192
161
  }
@@ -196,15 +165,9 @@ function analyzeMockData(code, filePath) {
196
165
  ObjectProperty(path) {
197
166
  const key = path.node.key;
198
167
  const value = path.node.value;
199
- const line = getLineNumber(path.node, code);
200
- const lineContent = lines[line - 1] || "";
201
-
202
- // Skip if this line is a false positive (CSS class, UI label, etc.)
203
- if (shouldSkipFinding(lineContent, line - 1, lines, "mock")) {
204
- return;
205
- }
206
168
 
207
169
  if (t.isIdentifier(key) && isMockVariableName(key.name)) {
170
+ const line = getLineNumber(path.node, code);
208
171
  findings.push({
209
172
  type: "mock_object_property",
210
173
  severity: "WARN",
@@ -214,12 +177,13 @@ function analyzeMockData(code, filePath) {
214
177
  column: path.node.loc.start.column,
215
178
  title: `Mock data property: ${key.name}`,
216
179
  message: `Object property name suggests mock data: ${key.name}`,
217
- codeSnippet: lineContent.trim(),
180
+ codeSnippet: lines[line - 1]?.trim(),
218
181
  confidence: "med",
219
182
  });
220
183
  }
221
184
 
222
185
  if (t.isStringLiteral(value) && isMockString(value.value)) {
186
+ const line = getLineNumber(path.node, code);
223
187
  findings.push({
224
188
  type: "mock_property_value",
225
189
  severity: "WARN",
@@ -229,7 +193,7 @@ function analyzeMockData(code, filePath) {
229
193
  column: path.node.loc.start.column,
230
194
  title: "Mock string in object property",
231
195
  message: `Property value appears to be mock data: "${value.value.substring(0, 50)}"`,
232
- codeSnippet: lineContent.trim(),
196
+ codeSnippet: lines[line - 1]?.trim(),
233
197
  confidence: "med",
234
198
  });
235
199
  }
@@ -272,17 +236,10 @@ function analyzeMockData(code, filePath) {
272
236
 
273
237
  // Check template literals
274
238
  TemplateLiteral(path) {
275
- const line = getLineNumber(path.node, code);
276
- const lineContent = lines[line - 1] || "";
277
-
278
- // Skip if this line is a false positive (CSS class, UI label, etc.)
279
- if (shouldSkipFinding(lineContent, line - 1, lines, "mock")) {
280
- return;
281
- }
282
-
283
239
  const quasis = path.node.quasis;
284
240
  for (const quasi of quasis) {
285
241
  if (quasi.value && isMockString(quasi.value.raw)) {
242
+ const line = getLineNumber(path.node, code);
286
243
  findings.push({
287
244
  type: "mock_template_literal",
288
245
  severity: "WARN",
@@ -292,7 +249,7 @@ function analyzeMockData(code, filePath) {
292
249
  column: path.node.loc.start.column,
293
250
  title: "Mock data in template literal",
294
251
  message: `Template literal contains mock/test data pattern`,
295
- codeSnippet: lineContent.trim(),
252
+ codeSnippet: lines[line - 1]?.trim(),
296
253
  confidence: "med",
297
254
  });
298
255
  break;
@@ -1,10 +1,6 @@
1
1
  /**
2
2
  * Performance Issues Detection Engine
3
3
  * Detects memory leaks, inefficient loops, large bundle sizes, and performance anti-patterns
4
- * Enhanced with framework-aware detection:
5
- * - React Server Components (different rules apply)
6
- * - Next.js App Router patterns
7
- * - Client-only hooks in server components
8
4
  */
9
5
 
10
6
  const { getAST } = require("./ast-cache");
@@ -12,32 +8,6 @@ const traverse = require("@babel/traverse").default;
12
8
  const t = require("@babel/types");
13
9
  const { shouldExcludeFile } = require("./file-filter");
14
10
 
15
- /**
16
- * Check if file is a React Server Component
17
- */
18
- function isServerComponent(code, filePath) {
19
- const normalizedPath = filePath.replace(/\\/g, "/");
20
-
21
- // Check if it's in app directory (Next.js App Router)
22
- if (!normalizedPath.includes("/app/")) {
23
- return false;
24
- }
25
-
26
- // Check for "use client" directive - if present, it's NOT a server component
27
- if (/['"]use client['"]/.test(code)) {
28
- return false;
29
- }
30
-
31
- return true;
32
- }
33
-
34
- /**
35
- * Check if file is a client component
36
- */
37
- function isClientComponent(code) {
38
- return /['"]use client['"]/.test(code);
39
- }
40
-
41
11
  /**
42
12
  * Analyze a file for performance issues
43
13
  */
@@ -51,77 +21,48 @@ function analyzePerformanceIssues(code, filePath) {
51
21
  if (!ast) return findings;
52
22
 
53
23
  const lines = code.split("\n");
54
-
55
- // Determine component type
56
- const isRSC = isServerComponent(code, filePath);
57
- const isCC = isClientComponent(code);
58
24
 
59
25
  // Memory leaks: Event listeners not removed
60
- // Skip for Server Components (no DOM access)
61
- if (!isRSC) {
62
- traverse(ast, {
63
- CallExpression(path) {
64
- const node = path.node;
26
+ traverse(ast, {
27
+ CallExpression(path) {
28
+ const node = path.node;
29
+
30
+ // Check for addEventListener without corresponding removeEventListener
31
+ if (t.isMemberExpression(node.callee)) {
32
+ const prop = node.callee.property;
65
33
 
66
- // Check for addEventListener without corresponding removeEventListener
67
- if (t.isMemberExpression(node.callee)) {
68
- const prop = node.callee.property;
34
+ if (t.isIdentifier(prop) && prop.name === "addEventListener") {
35
+ // Check if there's a corresponding removeEventListener in the same scope
36
+ const scope = path.scope;
37
+ const hasRemoveListener = scope.getAllBindings().some((binding, name) => {
38
+ return name.includes("removeEventListener") || name.includes("removeListener");
39
+ });
69
40
 
70
- if (t.isIdentifier(prop) && prop.name === "addEventListener") {
71
- // Check if there's a corresponding removeEventListener in the same scope
72
- const scope = path.scope;
73
- let hasRemoveListener = false;
74
- try {
75
- const bindings = scope.getAllBindings();
76
- for (const name in bindings) {
77
- if (name.includes("removeEventListener") || name.includes("removeListener")) {
78
- hasRemoveListener = true;
79
- break;
80
- }
81
- }
82
- } catch (e) {
83
- // Scope traversal can fail, assume safe
84
- hasRemoveListener = true;
85
- }
86
-
87
- // Also check if it's in a useEffect cleanup (React)
88
- const parent = path.findParent(p =>
89
- t.isCallExpression(p.node) &&
90
- t.isIdentifier(p.node.callee, { name: "useEffect" })
91
- );
92
-
93
- // Check if there's a cleanup function returning removeEventListener
94
- if (parent) {
95
- const useEffectArg = parent.node.arguments[0];
96
- if (t.isArrowFunctionExpression(useEffectArg) || t.isFunctionExpression(useEffectArg)) {
97
- const funcCode = code.substring(useEffectArg.start, useEffectArg.end);
98
- if (/return.*removeEventListener|removeEventListener.*return/s.test(funcCode)) {
99
- hasRemoveListener = true;
100
- }
101
- }
102
- }
103
-
104
- if (!hasRemoveListener && !parent) {
105
- const line = node.loc.start.line;
106
- findings.push({
107
- type: "memory_leak",
108
- severity: "WARN",
109
- category: "Performance",
110
- file: filePath,
111
- line,
112
- column: node.loc.start.column,
113
- title: "Potential memory leak: Event listener not removed",
114
- message: "addEventListener called without corresponding removeEventListener. Use useEffect cleanup.",
115
- codeSnippet: lines[line - 1]?.trim(),
116
- confidence: "med",
117
- fixHint: "Add cleanup in useEffect: useEffect(() => { el.addEventListener(...); return () => el.removeEventListener(...); }, [])",
118
- });
119
- }
41
+ // Also check if it's in a useEffect cleanup (React)
42
+ const parent = path.findParent(p =>
43
+ t.isCallExpression(p.node) &&
44
+ t.isIdentifier(p.node.callee, { name: "useEffect" })
45
+ );
46
+
47
+ if (!hasRemoveListener && !parent) {
48
+ const line = node.loc.start.line;
49
+ findings.push({
50
+ type: "memory_leak",
51
+ severity: "WARN",
52
+ category: "Performance",
53
+ file: filePath,
54
+ line,
55
+ column: node.loc.start.column,
56
+ title: "Potential memory leak: Event listener not removed",
57
+ message: "addEventListener called without corresponding removeEventListener",
58
+ codeSnippet: lines[line - 1]?.trim(),
59
+ confidence: "med",
60
+ });
120
61
  }
121
62
  }
122
- },
123
- });
124
- }
63
+ }
64
+ },
65
+ });
125
66
 
126
67
  // Inefficient loops: nested loops with O(n²) complexity
127
68
  // Only flag if depth >= 4 (3 levels is often acceptable)
@@ -310,93 +251,12 @@ function analyzePerformanceIssues(code, filePath) {
310
251
  message: `Importing entire ${source} library - use tree-shaking or import specific functions`,
311
252
  codeSnippet: lines[line - 1]?.trim(),
312
253
  confidence: "med",
313
- fixHint: `Import specific functions: import { specificFn } from '${source}/specificFn'`,
314
254
  });
315
255
  }
316
256
  }
317
257
  },
318
258
  });
319
259
 
320
- // React Server Components: Detect client-only hooks used in server components
321
- if (isRSC) {
322
- const clientOnlyHooks = [
323
- "useState",
324
- "useEffect",
325
- "useLayoutEffect",
326
- "useRef",
327
- "useCallback",
328
- "useMemo",
329
- "useReducer",
330
- "useContext",
331
- "useImperativeHandle",
332
- "useDebugValue",
333
- ];
334
-
335
- traverse(ast, {
336
- CallExpression(path) {
337
- const node = path.node;
338
-
339
- if (t.isIdentifier(node.callee)) {
340
- const hookName = node.callee.name;
341
-
342
- if (clientOnlyHooks.includes(hookName)) {
343
- const line = node.loc.start.line;
344
- findings.push({
345
- type: "client_hook_in_server_component",
346
- severity: "BLOCK",
347
- category: "Performance",
348
- file: filePath,
349
- line,
350
- column: node.loc.start.column,
351
- title: `Client-only hook '${hookName}' used in Server Component`,
352
- message: `${hookName} cannot be used in Server Components. Add 'use client' directive or move to a client component.`,
353
- codeSnippet: lines[line - 1]?.trim(),
354
- confidence: "high",
355
- fixHint: "Add 'use client' at the top of the file, or extract this logic to a client component",
356
- });
357
- }
358
- }
359
- },
360
- });
361
- }
362
-
363
- // Detect async/await in client components that should be server components
364
- if (isCC) {
365
- // Check for database queries in client components
366
- const serverOnlyPatterns = [
367
- /prisma\./,
368
- /db\./,
369
- /\.findUnique\(/,
370
- /\.findMany\(/,
371
- /\.create\(/,
372
- /\.update\(/,
373
- /\.delete\(/,
374
- /fs\./,
375
- /readFile/,
376
- /writeFile/,
377
- ];
378
-
379
- if (serverOnlyPatterns.some(p => p.test(code))) {
380
- const normalizedPath = filePath.replace(/\\/g, "/");
381
- // Only warn if in app directory where RSC is available
382
- if (normalizedPath.includes("/app/")) {
383
- findings.push({
384
- type: "server_code_in_client_component",
385
- severity: "WARN",
386
- category: "Performance",
387
- file: filePath,
388
- line: 1,
389
- column: 0,
390
- title: "Server-only code in Client Component",
391
- message: "Database/filesystem operations should be in Server Components for better performance",
392
- codeSnippet: "'use client'",
393
- confidence: "med",
394
- fixHint: "Remove 'use client' and move client interactivity to child components",
395
- });
396
- }
397
- }
398
- }
399
-
400
260
  return findings;
401
261
  }
402
262