@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,806 +0,0 @@
1
- /**
2
- * AI Hallucination Detection Engine
3
- *
4
- * The ultimate vibe-coder's reality check. Detects patterns that are typical of
5
- * AI-generated code that "looks good" but doesn't actually work.
6
- *
7
- * Common AI hallucination patterns:
8
- * - Functions that return hardcoded success without doing anything
9
- * - API calls to non-existent endpoints
10
- * - Placeholder implementations that look real
11
- * - Copy-paste patterns from docs that don't fit the codebase
12
- * - "Looks like it works" patterns (console.log success without actual logic)
13
- * - Optimistic error handling (catching errors and doing nothing)
14
- *
15
- * @module ai-hallucination-engine
16
- */
17
-
18
- "use strict";
19
-
20
- const { parseAST, getCachedAST } = require("../ast-cache");
21
- const { shouldSkipFile } = require("../file-filter");
22
-
23
- // ═══════════════════════════════════════════════════════════════════════════════
24
- // HALLUCINATION PATTERNS - What AI tends to generate that doesn't work
25
- // ═══════════════════════════════════════════════════════════════════════════════
26
-
27
- /**
28
- * Patterns that indicate "looks like implementation but isn't"
29
- * High confidence = almost certainly AI hallucination
30
- * Medium confidence = likely hallucination, needs context
31
- * Low confidence = possible hallucination, review recommended
32
- */
33
- const HALLUCINATION_PATTERNS = {
34
- // ═══════════════════════════════════════════════════════════════════════════
35
- // FAKE SUCCESS PATTERNS - Functions that claim success without doing anything
36
- // ═══════════════════════════════════════════════════════════════════════════
37
- fakeSuccess: {
38
- patterns: [
39
- // Return success without any preceding logic
40
- {
41
- regex: /return\s*{\s*success:\s*true\s*,?\s*(?:message:\s*["'][^"']*["'])?\s*}/,
42
- name: "hardcoded-success-object",
43
- confidence: 0.85,
44
- severity: "BLOCK",
45
- message: "Returns success object without performing actual operation",
46
- },
47
- // Async function that just resolves with success
48
- {
49
- regex: /async\s+(?:function\s+)?\w+\s*\([^)]*\)\s*{\s*return\s*(?:Promise\.resolve\()?\s*(?:true|{[^}]*success[^}]*})/,
50
- name: "async-fake-success",
51
- confidence: 0.80,
52
- severity: "BLOCK",
53
- message: "Async function immediately returns success without async work",
54
- },
55
- // API handler that just returns 200 without processing
56
- {
57
- regex: /(?:res|response)\.(?:status\(200\)|json|send)\s*\(\s*{\s*(?:success|ok|status):\s*(?:true|["'](?:ok|success)["'])/,
58
- name: "api-fake-success",
59
- confidence: 0.75,
60
- severity: "WARN",
61
- message: "API endpoint returns success without apparent processing",
62
- },
63
- ],
64
- },
65
-
66
- // ═══════════════════════════════════════════════════════════════════════════
67
- // OPTIMISTIC ERROR HANDLING - Catches errors and pretends everything is fine
68
- // ═══════════════════════════════════════════════════════════════════════════
69
- optimisticErrors: {
70
- patterns: [
71
- // Catch block that returns success anyway
72
- {
73
- regex: /catch\s*\([^)]*\)\s*{\s*(?:\/\/[^\n]*\n\s*)?return\s*{\s*success:\s*true/,
74
- name: "catch-returns-success",
75
- confidence: 0.95,
76
- severity: "BLOCK",
77
- message: "Catches error but returns success anyway - hiding failures",
78
- },
79
- // Catch block with just console.log (no actual handling)
80
- {
81
- regex: /catch\s*\(\s*(?:e|err|error|_)\s*\)\s*{\s*console\.(?:log|error)\s*\([^)]+\)\s*;?\s*}/,
82
- name: "catch-log-only",
83
- confidence: 0.70,
84
- severity: "WARN",
85
- message: "Error caught and logged but not handled - silent failure",
86
- },
87
- // Empty catch with comment
88
- {
89
- regex: /catch\s*\([^)]*\)\s*{\s*\/\/\s*(?:TODO|FIXME|handle|ignore)/i,
90
- name: "catch-todo-comment",
91
- confidence: 0.90,
92
- severity: "BLOCK",
93
- message: "Error handling deferred with TODO comment - unhandled errors",
94
- },
95
- ],
96
- },
97
-
98
- // ═══════════════════════════════════════════════════════════════════════════
99
- // STUB IMPLEMENTATIONS - Functions that look implemented but aren't
100
- // ═══════════════════════════════════════════════════════════════════════════
101
- stubImplementations: {
102
- patterns: [
103
- // Function body is just a comment
104
- {
105
- regex: /(?:async\s+)?(?:function\s+\w+|\w+\s*=\s*(?:async\s+)?(?:function|\([^)]*\)\s*=>))\s*[^{]*{\s*\/\/[^\n]*\n\s*}/,
106
- name: "comment-only-function",
107
- confidence: 0.95,
108
- severity: "BLOCK",
109
- message: "Function contains only a comment - not implemented",
110
- },
111
- // Function that just throws "not implemented"
112
- {
113
- regex: /{\s*throw\s+(?:new\s+Error\()?["'](?:not\s+implemented|TODO|NYI|TBD)/i,
114
- name: "throws-not-implemented",
115
- confidence: 0.90,
116
- severity: "BLOCK",
117
- message: "Function explicitly throws 'not implemented'",
118
- },
119
- // Function that returns undefined/null without logic
120
- {
121
- regex: /(?:async\s+)?(?:function\s+\w+|\w+\s*=\s*(?:async\s+)?(?:function|\([^)]*\)\s*=>))\s*[^{]*{\s*return\s*(?:undefined|null|void\s*0)\s*;?\s*}/,
122
- name: "returns-nothing",
123
- confidence: 0.85,
124
- severity: "WARN",
125
- message: "Function returns undefined/null without performing work",
126
- },
127
- ],
128
- },
129
-
130
- // ═══════════════════════════════════════════════════════════════════════════
131
- // HALLUCINATED API PATTERNS - API calls that look real but use fake endpoints
132
- // ═══════════════════════════════════════════════════════════════════════════
133
- hallucinatedAPIs: {
134
- patterns: [
135
- // Fetch to example/placeholder URLs
136
- {
137
- regex: /fetch\s*\(\s*["']https?:\/\/(?:example\.com|api\.example|your-api|my-api|placeholder)/i,
138
- name: "fetch-example-url",
139
- confidence: 0.95,
140
- severity: "BLOCK",
141
- message: "Fetch call to example/placeholder URL - not real endpoint",
142
- },
143
- // API URL patterns that look generated
144
- {
145
- regex: /(?:apiUrl|API_URL|baseUrl|BASE_URL)\s*[=:]\s*["']https?:\/\/(?:localhost|example\.com|your-|my-|api\.)/i,
146
- name: "placeholder-api-url",
147
- confidence: 0.80,
148
- severity: "WARN",
149
- message: "API URL appears to be a placeholder",
150
- },
151
- // GraphQL queries to fake endpoints
152
- {
153
- regex: /(?:query|mutation)\s+\w+\s*{[^}]*}\s*['"],?\s*["']https?:\/\/(?:example|placeholder|your-)/i,
154
- name: "graphql-fake-endpoint",
155
- confidence: 0.90,
156
- severity: "BLOCK",
157
- message: "GraphQL query pointing to placeholder endpoint",
158
- },
159
- ],
160
- },
161
-
162
- // ═══════════════════════════════════════════════════════════════════════════
163
- // FAKE DATA PATTERNS - Looks like real data but isn't
164
- // ═══════════════════════════════════════════════════════════════════════════
165
- fakeData: {
166
- patterns: [
167
- // Hardcoded UUIDs that look generated
168
- {
169
- regex: /["'](?:12345678-1234-1234-1234-123456789012|00000000-0000-0000-0000-000000000000|xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)["']/,
170
- name: "placeholder-uuid",
171
- confidence: 0.95,
172
- severity: "BLOCK",
173
- message: "Placeholder UUID detected - should be dynamic",
174
- },
175
- // Demo/test email patterns in non-test files
176
- {
177
- regex: /["'](?:test@test\.com|user@example\.com|admin@admin\.com|demo@demo\.com)["']/i,
178
- name: "placeholder-email",
179
- confidence: 0.80,
180
- severity: "WARN",
181
- message: "Placeholder email in production code",
182
- },
183
- // Hardcoded API keys that look fake
184
- {
185
- regex: /(?:api[_-]?key|apiKey|API_KEY)\s*[=:]\s*["'](?:your[-_]?api[-_]?key|xxx+|test[-_]?key|sk[-_]test|pk[-_]test)/i,
186
- name: "placeholder-api-key",
187
- confidence: 0.90,
188
- severity: "BLOCK",
189
- message: "Placeholder API key - needs real credentials",
190
- },
191
- ],
192
- },
193
-
194
- // ═══════════════════════════════════════════════════════════════════════════
195
- // COPY-PASTE PATTERNS - Code that looks copied from docs/examples
196
- // ═══════════════════════════════════════════════════════════════════════════
197
- copyPaste: {
198
- patterns: [
199
- // Comments that look like documentation examples
200
- {
201
- regex: /\/\/\s*(?:Example|Sample|Demo|Tutorial|From the docs|Copy this)/i,
202
- name: "example-comment",
203
- confidence: 0.60,
204
- severity: "WARN",
205
- message: "Code appears to be copied from documentation/example",
206
- },
207
- // TODO comments with implementation details
208
- {
209
- regex: /\/\/\s*TODO:\s*(?:implement|add|fix|handle|complete|finish)/i,
210
- name: "todo-implement",
211
- confidence: 0.85,
212
- severity: "BLOCK",
213
- message: "TODO comment indicates missing implementation",
214
- },
215
- // Placeholder function names
216
- {
217
- regex: /function\s+(?:doSomething|handleIt|processData|myFunction|yourFunction|exampleFunction)\s*\(/i,
218
- name: "placeholder-function-name",
219
- confidence: 0.75,
220
- severity: "WARN",
221
- message: "Generic/placeholder function name suggests example code",
222
- },
223
- ],
224
- },
225
-
226
- // ═══════════════════════════════════════════════════════════════════════════
227
- // VIBE-CODED PATTERNS - AI-specific generation patterns
228
- // ═══════════════════════════════════════════════════════════════════════════
229
- vibeCoded: {
230
- patterns: [
231
- // Console.log that claims success without verification
232
- {
233
- regex: /console\.log\s*\(\s*["'](?:Success|Done|Completed|Working)[!.]*["']\s*\)/i,
234
- name: "optimistic-console-log",
235
- confidence: 0.70,
236
- severity: "WARN",
237
- message: "Console log claims success but may not verify actual result",
238
- },
239
- // Return statement immediately after function declaration (no logic)
240
- {
241
- regex: /(?:async\s+)?function\s+\w+\s*\([^)]*\)\s*{\s*return\s+/,
242
- name: "immediate-return",
243
- confidence: 0.50,
244
- severity: "INFO",
245
- message: "Function immediately returns - may lack implementation",
246
- },
247
- // Multiple similar patterns (likely AI batch generation)
248
- {
249
- regex: /(?:const|let|var)\s+(\w+)1\s*=.*\n.*\1(?:2|_2)\s*=/,
250
- name: "sequential-naming",
251
- confidence: 0.60,
252
- severity: "INFO",
253
- message: "Sequential variable naming suggests AI-generated batch code",
254
- },
255
- ],
256
- },
257
- };
258
-
259
- // ═══════════════════════════════════════════════════════════════════════════════
260
- // AST-BASED DETECTION - More accurate detection using AST analysis
261
- // ═══════════════════════════════════════════════════════════════════════════════
262
-
263
- /**
264
- * AST-based hallucination patterns for more accurate detection
265
- */
266
- const AST_PATTERNS = {
267
- /**
268
- * Detect empty or near-empty functions
269
- */
270
- emptyFunctions: (ast, filePath) => {
271
- const findings = [];
272
-
273
- const checkFunction = (node, name) => {
274
- if (!node.body) return;
275
-
276
- const body = node.body.type === "BlockStatement" ? node.body.body : [node.body];
277
-
278
- // Check for empty body
279
- if (body.length === 0) {
280
- findings.push({
281
- type: "empty-function",
282
- name,
283
- line: node.loc?.start?.line || 1,
284
- confidence: 0.90,
285
- severity: "BLOCK",
286
- message: `Function '${name}' has empty body - not implemented`,
287
- });
288
- return;
289
- }
290
-
291
- // Check for body with only comments
292
- const nonCommentStatements = body.filter(stmt =>
293
- stmt.type !== "EmptyStatement" &&
294
- !(stmt.type === "ExpressionStatement" && stmt.expression?.type === "Literal")
295
- );
296
-
297
- // Check for body with only return undefined/null
298
- if (body.length === 1 && body[0].type === "ReturnStatement") {
299
- const arg = body[0].argument;
300
- if (!arg || (arg.type === "Identifier" && arg.name === "undefined") ||
301
- (arg.type === "Literal" && arg.value === null)) {
302
- findings.push({
303
- type: "returns-nothing-function",
304
- name,
305
- line: node.loc?.start?.line || 1,
306
- confidence: 0.85,
307
- severity: "WARN",
308
- message: `Function '${name}' only returns null/undefined - stub implementation`,
309
- });
310
- }
311
- }
312
- };
313
-
314
- // Walk AST to find functions
315
- const walk = (node) => {
316
- if (!node || typeof node !== "object") return;
317
-
318
- if (node.type === "FunctionDeclaration" && node.id) {
319
- checkFunction(node, node.id.name);
320
- }
321
-
322
- if (node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") {
323
- // Try to get name from parent
324
- const name = node.id?.name || "anonymous";
325
- checkFunction(node, name);
326
- }
327
-
328
- // Recurse
329
- for (const key of Object.keys(node)) {
330
- const child = node[key];
331
- if (Array.isArray(child)) {
332
- child.forEach(walk);
333
- } else if (child && typeof child === "object") {
334
- walk(child);
335
- }
336
- }
337
- };
338
-
339
- if (ast.program) {
340
- walk(ast.program);
341
- } else {
342
- walk(ast);
343
- }
344
-
345
- return findings;
346
- },
347
-
348
- /**
349
- * Detect async functions without await
350
- */
351
- asyncWithoutAwait: (ast, filePath) => {
352
- const findings = [];
353
-
354
- const checkAsyncFunction = (node, name) => {
355
- if (!node.async) return;
356
-
357
- let hasAwait = false;
358
-
359
- const walkForAwait = (n) => {
360
- if (!n || typeof n !== "object") return;
361
- if (n.type === "AwaitExpression") {
362
- hasAwait = true;
363
- return;
364
- }
365
- // Don't recurse into nested functions
366
- if (n.type === "FunctionExpression" || n.type === "ArrowFunctionExpression" ||
367
- n.type === "FunctionDeclaration") {
368
- return;
369
- }
370
- for (const key of Object.keys(n)) {
371
- const child = n[key];
372
- if (Array.isArray(child)) {
373
- child.forEach(walkForAwait);
374
- } else if (child && typeof child === "object") {
375
- walkForAwait(child);
376
- }
377
- }
378
- };
379
-
380
- walkForAwait(node.body);
381
-
382
- if (!hasAwait) {
383
- findings.push({
384
- type: "async-without-await",
385
- name,
386
- line: node.loc?.start?.line || 1,
387
- confidence: 0.75,
388
- severity: "WARN",
389
- message: `Async function '${name}' never uses await - may be unnecessary`,
390
- });
391
- }
392
- };
393
-
394
- const walk = (node) => {
395
- if (!node || typeof node !== "object") return;
396
-
397
- if (node.type === "FunctionDeclaration" && node.async && node.id) {
398
- checkAsyncFunction(node, node.id.name);
399
- }
400
-
401
- if ((node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") && node.async) {
402
- const name = node.id?.name || "anonymous";
403
- checkAsyncFunction(node, name);
404
- }
405
-
406
- for (const key of Object.keys(node)) {
407
- const child = node[key];
408
- if (Array.isArray(child)) {
409
- child.forEach(walk);
410
- } else if (child && typeof child === "object") {
411
- walk(child);
412
- }
413
- }
414
- };
415
-
416
- if (ast.program) {
417
- walk(ast.program);
418
- } else {
419
- walk(ast);
420
- }
421
-
422
- return findings;
423
- },
424
-
425
- /**
426
- * Detect catch blocks that swallow errors
427
- */
428
- swallowedErrors: (ast, filePath) => {
429
- const findings = [];
430
-
431
- const walk = (node) => {
432
- if (!node || typeof node !== "object") return;
433
-
434
- if (node.type === "CatchClause") {
435
- const body = node.body?.body || [];
436
-
437
- // Empty catch
438
- if (body.length === 0) {
439
- findings.push({
440
- type: "empty-catch",
441
- line: node.loc?.start?.line || 1,
442
- confidence: 0.95,
443
- severity: "BLOCK",
444
- message: "Empty catch block silently swallows errors",
445
- });
446
- }
447
-
448
- // Catch with only console.log
449
- if (body.length === 1 && body[0].type === "ExpressionStatement") {
450
- const expr = body[0].expression;
451
- if (expr.type === "CallExpression" &&
452
- expr.callee?.object?.name === "console") {
453
- findings.push({
454
- type: "catch-log-only",
455
- line: node.loc?.start?.line || 1,
456
- confidence: 0.70,
457
- severity: "WARN",
458
- message: "Catch block only logs error - doesn't handle or rethrow",
459
- });
460
- }
461
- }
462
-
463
- // Catch that returns success
464
- const lastStmt = body[body.length - 1];
465
- if (lastStmt?.type === "ReturnStatement" && lastStmt.argument?.type === "ObjectExpression") {
466
- const props = lastStmt.argument.properties || [];
467
- const successProp = props.find(p =>
468
- p.key?.name === "success" && p.value?.value === true
469
- );
470
- if (successProp) {
471
- findings.push({
472
- type: "catch-returns-success",
473
- line: node.loc?.start?.line || 1,
474
- confidence: 0.95,
475
- severity: "BLOCK",
476
- message: "Catch block returns success:true - hiding errors from callers",
477
- });
478
- }
479
- }
480
- }
481
-
482
- for (const key of Object.keys(node)) {
483
- const child = node[key];
484
- if (Array.isArray(child)) {
485
- child.forEach(walk);
486
- } else if (child && typeof child === "object") {
487
- walk(child);
488
- }
489
- }
490
- };
491
-
492
- if (ast.program) {
493
- walk(ast.program);
494
- } else {
495
- walk(ast);
496
- }
497
-
498
- return findings;
499
- },
500
- };
501
-
502
- // ═══════════════════════════════════════════════════════════════════════════════
503
- // CONTEXT DETECTION - Reduce false positives based on context
504
- // ═══════════════════════════════════════════════════════════════════════════════
505
-
506
- /**
507
- * Check if file is a test file
508
- */
509
- function isTestFile(filePath) {
510
- const patterns = [
511
- /\.test\.[jt]sx?$/,
512
- /\.spec\.[jt]sx?$/,
513
- /\/__tests__\//,
514
- /\/test\//,
515
- /\/tests\//,
516
- /\.stories\.[jt]sx?$/,
517
- /\.mock\.[jt]sx?$/,
518
- ];
519
- return patterns.some(p => p.test(filePath));
520
- }
521
-
522
- /**
523
- * Check if file is a config file
524
- */
525
- function isConfigFile(filePath) {
526
- const patterns = [
527
- /\.config\.[jt]s$/,
528
- /config\/.*\.[jt]s$/,
529
- /\.env/,
530
- /tsconfig/,
531
- /package\.json$/,
532
- ];
533
- return patterns.some(p => p.test(filePath));
534
- }
535
-
536
- /**
537
- * Check if file is documentation/examples
538
- */
539
- function isDocFile(filePath) {
540
- const patterns = [
541
- /\/examples?\//,
542
- /\/docs?\//,
543
- /\/demo\//,
544
- /README/,
545
- /CHANGELOG/,
546
- /\.md$/,
547
- ];
548
- return patterns.some(p => p.test(filePath));
549
- }
550
-
551
- // ═══════════════════════════════════════════════════════════════════════════════
552
- // MAIN DETECTION FUNCTION
553
- // ═══════════════════════════════════════════════════════════════════════════════
554
-
555
- /**
556
- * Analyze a file for AI hallucination patterns
557
- * @param {string} content - File content
558
- * @param {string} filePath - File path
559
- * @param {object} options - Analysis options
560
- * @returns {Array} Array of findings
561
- */
562
- function analyzeAIHallucinations(content, filePath, options = {}) {
563
- // Skip test files unless explicitly included
564
- if (isTestFile(filePath) && !options.includeTests) {
565
- return [];
566
- }
567
-
568
- // Skip config and doc files
569
- if (isConfigFile(filePath) || isDocFile(filePath)) {
570
- return [];
571
- }
572
-
573
- const findings = [];
574
- const lines = content.split("\n");
575
- let findingId = 0;
576
-
577
- // Pattern-based detection
578
- for (const [category, { patterns }] of Object.entries(HALLUCINATION_PATTERNS)) {
579
- for (const pattern of patterns) {
580
- for (let i = 0; i < lines.length; i++) {
581
- const line = lines[i];
582
- const match = line.match(pattern.regex);
583
-
584
- if (match) {
585
- // Context check - look at surrounding lines for false positive indicators
586
- const contextBefore = lines.slice(Math.max(0, i - 3), i).join("\n");
587
- const contextAfter = lines.slice(i + 1, Math.min(lines.length, i + 4)).join("\n");
588
-
589
- // Skip if in test context
590
- if (/test|spec|mock|stub|fake|__mocks__/i.test(contextBefore + contextAfter)) {
591
- continue;
592
- }
593
-
594
- // Skip if there's actual logic around it
595
- if (/await|async|fetch|axios|database|db\.|prisma|mongoose/i.test(contextBefore)) {
596
- continue;
597
- }
598
-
599
- findings.push({
600
- id: `AI-HALL-${String(++findingId).padStart(3, "0")}`,
601
- category: "AIHallucination",
602
- type: pattern.name,
603
- severity: pattern.severity,
604
- confidence: pattern.confidence,
605
- file: filePath,
606
- line: i + 1,
607
- column: match.index + 1,
608
- evidence: {
609
- snippet: line.trim().slice(0, 200),
610
- context: `${contextBefore}\n>>> ${line}\n${contextAfter}`.slice(0, 500),
611
- pattern: pattern.regex.source,
612
- },
613
- message: pattern.message,
614
- category_detail: category,
615
- fixHints: getFixHints(category, pattern.name),
616
- });
617
- }
618
- }
619
- }
620
- }
621
-
622
- // AST-based detection for more accuracy
623
- if (!options.skipAST) {
624
- try {
625
- const ast = getCachedAST(filePath, content);
626
-
627
- if (ast) {
628
- for (const [name, detector] of Object.entries(AST_PATTERNS)) {
629
- const astFindings = detector(ast, filePath);
630
-
631
- for (const finding of astFindings) {
632
- findings.push({
633
- id: `AI-HALL-${String(++findingId).padStart(3, "0")}`,
634
- category: "AIHallucination",
635
- type: finding.type,
636
- severity: finding.severity,
637
- confidence: finding.confidence,
638
- file: filePath,
639
- line: finding.line,
640
- evidence: {
641
- snippet: lines[finding.line - 1]?.trim().slice(0, 200) || "",
642
- context: finding.message,
643
- },
644
- message: finding.message,
645
- category_detail: name,
646
- fixHints: getFixHints(name, finding.type),
647
- astVerified: true, // Higher confidence - verified by AST
648
- });
649
- }
650
- }
651
- }
652
- } catch (e) {
653
- // AST parsing failed - continue with pattern-based results
654
- }
655
- }
656
-
657
- return findings;
658
- }
659
-
660
- /**
661
- * Get fix hints for a finding
662
- */
663
- function getFixHints(category, type) {
664
- const hints = {
665
- fakeSuccess: [
666
- "Implement actual business logic before returning success",
667
- "Verify operation completed before returning success response",
668
- "Add proper error handling and return appropriate status",
669
- ],
670
- optimisticErrors: [
671
- "Either rethrow the error or handle it properly",
672
- "Return an error response instead of success when catching errors",
673
- "Log the error AND take appropriate action (retry, fallback, or propagate)",
674
- ],
675
- stubImplementations: [
676
- "Replace TODO/stub with actual implementation",
677
- "If not ready, mark the function as deprecated or throw 'Not implemented'",
678
- "Remove the function if it's not needed",
679
- ],
680
- hallucinatedAPIs: [
681
- "Replace placeholder URL with actual API endpoint",
682
- "Use environment variables for API URLs",
683
- "Verify the endpoint exists and is accessible",
684
- ],
685
- fakeData: [
686
- "Replace placeholder data with dynamic/real values",
687
- "Use environment variables for sensitive data",
688
- "Generate proper UUIDs/IDs dynamically",
689
- ],
690
- copyPaste: [
691
- "Customize the example code for your specific use case",
692
- "Remove or implement TODO comments",
693
- "Rename generic function names to be descriptive",
694
- ],
695
- vibeCoded: [
696
- "Verify the success claim with actual checks",
697
- "Add proper logic before the return statement",
698
- "Review AI-generated code for correctness",
699
- ],
700
- };
701
-
702
- return hints[category] || [
703
- "Review this code for correctness",
704
- "Ensure the implementation matches the intent",
705
- "Add proper error handling and validation",
706
- ];
707
- }
708
-
709
- /**
710
- * Calculate vibe score for a file based on hallucination findings
711
- * @param {Array} findings - Findings from analysis
712
- * @returns {object} Vibe score metrics
713
- */
714
- function calculateVibeScore(findings) {
715
- if (!findings || findings.length === 0) {
716
- return {
717
- score: 100,
718
- grade: "A",
719
- label: "Production Ready",
720
- riskLevel: "low",
721
- deductions: [],
722
- };
723
- }
724
-
725
- let score = 100;
726
- const deductions = [];
727
-
728
- for (const finding of findings) {
729
- let deduction = 0;
730
-
731
- switch (finding.severity) {
732
- case "BLOCK":
733
- deduction = 15 * finding.confidence;
734
- break;
735
- case "WARN":
736
- deduction = 8 * finding.confidence;
737
- break;
738
- case "INFO":
739
- deduction = 3 * finding.confidence;
740
- break;
741
- }
742
-
743
- // AST-verified findings have higher impact
744
- if (finding.astVerified) {
745
- deduction *= 1.2;
746
- }
747
-
748
- score -= deduction;
749
- deductions.push({
750
- type: finding.type,
751
- deduction: Math.round(deduction * 10) / 10,
752
- reason: finding.message,
753
- });
754
- }
755
-
756
- score = Math.max(0, Math.round(score));
757
-
758
- // Calculate grade
759
- let grade, label, riskLevel;
760
- if (score >= 90) {
761
- grade = "A";
762
- label = "Production Ready";
763
- riskLevel = "low";
764
- } else if (score >= 80) {
765
- grade = "B";
766
- label = "Minor Issues";
767
- riskLevel = "low";
768
- } else if (score >= 70) {
769
- grade = "C";
770
- label = "Needs Review";
771
- riskLevel = "medium";
772
- } else if (score >= 50) {
773
- grade = "D";
774
- label = "Significant Issues";
775
- riskLevel = "high";
776
- } else {
777
- grade = "F";
778
- label = "Not Production Ready";
779
- riskLevel = "critical";
780
- }
781
-
782
- return {
783
- score,
784
- grade,
785
- label,
786
- riskLevel,
787
- deductions,
788
- totalFindings: findings.length,
789
- blockers: findings.filter(f => f.severity === "BLOCK").length,
790
- warnings: findings.filter(f => f.severity === "WARN").length,
791
- };
792
- }
793
-
794
- // ═══════════════════════════════════════════════════════════════════════════════
795
- // EXPORTS
796
- // ═══════════════════════════════════════════════════════════════════════════════
797
-
798
- module.exports = {
799
- analyzeAIHallucinations,
800
- calculateVibeScore,
801
- HALLUCINATION_PATTERNS,
802
- AST_PATTERNS,
803
- isTestFile,
804
- isConfigFile,
805
- isDocFile,
806
- };