@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,630 +0,0 @@
1
- /**
2
- * False Positive Prevention Engine - Bulletproof Accuracy
3
- *
4
- * This engine prevents false positives through:
5
- *
6
- * 1. AST-BASED GENERATED CODE DETECTION - Not just path patterns
7
- * 2. FRAMEWORK VERSION AWARENESS - Different rules for different versions
8
- * 3. VENDORED CODE DETECTION - Third-party code in src/
9
- * 4. CODEGEN OUTPUT DETECTION - GraphQL, Prisma, etc.
10
- * 5. CONFIDENCE FEEDBACK TRACKING - Learn from user suppressions
11
- */
12
-
13
- "use strict";
14
-
15
- const fs = require("fs");
16
- const path = require("path");
17
-
18
- // ═══════════════════════════════════════════════════════════════════════════════
19
- // AST-BASED GENERATED CODE DETECTION
20
- // Detects generated code by comments and patterns, not just file paths
21
- // ═══════════════════════════════════════════════════════════════════════════════
22
-
23
- const GENERATED_CODE_MARKERS = {
24
- // Comment-based markers
25
- comments: [
26
- /@generated/i,
27
- /auto-?generated/i,
28
- /do not edit/i,
29
- /do not modify/i,
30
- /this file is generated/i,
31
- /automatically generated/i,
32
- /machine generated/i,
33
- /code generated by/i,
34
- /generated by \w+/i,
35
- /@auto-generated/i,
36
- /eslint-disable-file/i,
37
- /prettier-ignore-start/i,
38
- ],
39
-
40
- // Tool-specific markers
41
- tools: {
42
- prisma: [
43
- /prisma generate/i,
44
- /PrismaClient/,
45
- /@prisma\/client/,
46
- ],
47
- graphql: [
48
- /graphql-codegen/i,
49
- /gql\.tada/i,
50
- /@graphql-typed-document-node/i,
51
- /TypedDocumentNode/,
52
- ],
53
- openapi: [
54
- /openapi-generator/i,
55
- /swagger-codegen/i,
56
- /orval/i,
57
- ],
58
- protobuf: [
59
- /protoc-gen/i,
60
- /google-protobuf/,
61
- ],
62
- trpc: [
63
- /createTRPCProxyClient/,
64
- /TRPCClientError/,
65
- ],
66
- },
67
- };
68
-
69
- // Check first N lines for generated markers
70
- const HEADER_LINES_TO_CHECK = 30;
71
-
72
- function isGeneratedCode(code, filePath = "") {
73
- if (!code) return { isGenerated: false, reason: null };
74
-
75
- const lines = code.split("\n").slice(0, HEADER_LINES_TO_CHECK);
76
- const header = lines.join("\n");
77
-
78
- // Check comment markers
79
- for (const pattern of GENERATED_CODE_MARKERS.comments) {
80
- if (pattern.test(header)) {
81
- return { isGenerated: true, reason: "Generated code marker in comments", pattern: pattern.source };
82
- }
83
- }
84
-
85
- // Check tool-specific markers
86
- for (const [tool, patterns] of Object.entries(GENERATED_CODE_MARKERS.tools)) {
87
- for (const pattern of patterns) {
88
- if (pattern.test(header)) {
89
- return { isGenerated: true, reason: `Generated by ${tool}`, tool };
90
- }
91
- }
92
- }
93
-
94
- // Check file path patterns
95
- const pathPatterns = [
96
- /\/__generated__\//i,
97
- /\/generated\//i,
98
- /\/codegen\//i,
99
- /\.generated\.(ts|js|tsx|jsx)$/i,
100
- /\.gen\.(ts|js|tsx|jsx)$/i,
101
- /\.g\.(ts|js)$/i,
102
- ];
103
-
104
- for (const pattern of pathPatterns) {
105
- if (pattern.test(filePath)) {
106
- return { isGenerated: true, reason: "Generated code path pattern", pattern: pattern.source };
107
- }
108
- }
109
-
110
- return { isGenerated: false, reason: null };
111
- }
112
-
113
- // ═══════════════════════════════════════════════════════════════════════════════
114
- // VENDORED CODE DETECTION
115
- // Detects third-party code copied into src/
116
- // ═══════════════════════════════════════════════════════════════════════════════
117
-
118
- const VENDORED_CODE_MARKERS = [
119
- // License headers
120
- /MIT License/i,
121
- /Apache License/i,
122
- /BSD \d-Clause/i,
123
- /GNU General Public License/i,
124
- /Copyright \(c\) \d{4}/i,
125
- /All rights reserved/i,
126
-
127
- // Common vendored file indicators
128
- /vendored?\/|\/vendor\//i,
129
- /third[_-]?party/i,
130
- /external\//i,
131
-
132
- // Package metadata
133
- /@license/i,
134
- /@author [^@]+<[^>]+>/i,
135
- /@version \d+\.\d+/i,
136
- ];
137
-
138
- const VENDORED_PATH_PATTERNS = [
139
- /\/vendor\//i,
140
- /\/vendored?\//i,
141
- /\/third[_-]?party\//i,
142
- /\/external\//i,
143
- /\/lib\/external\//i,
144
- ];
145
-
146
- function isVendoredCode(code, filePath = "") {
147
- if (!code) return { isVendored: false, reason: null };
148
-
149
- // Check path patterns first (fast)
150
- for (const pattern of VENDORED_PATH_PATTERNS) {
151
- if (pattern.test(filePath)) {
152
- return { isVendored: true, reason: "Vendored path pattern" };
153
- }
154
- }
155
-
156
- // Check content markers
157
- const header = code.split("\n").slice(0, 20).join("\n");
158
-
159
- let licenseCount = 0;
160
- for (const pattern of VENDORED_CODE_MARKERS) {
161
- if (pattern.test(header)) {
162
- licenseCount++;
163
- // Multiple license markers = likely vendored
164
- if (licenseCount >= 2) {
165
- return { isVendored: true, reason: "Multiple license/author markers" };
166
- }
167
- }
168
- }
169
-
170
- return { isVendored: false, reason: null };
171
- }
172
-
173
- // ═══════════════════════════════════════════════════════════════════════════════
174
- // FRAMEWORK VERSION DETECTION
175
- // Detects framework versions to apply version-specific rules
176
- // ═══════════════════════════════════════════════════════════════════════════════
177
-
178
- const FRAMEWORK_VERSION_CACHE = new Map();
179
-
180
- function parseVersion(versionString) {
181
- if (!versionString) return null;
182
-
183
- const match = versionString.match(/(\d+)\.(\d+)(?:\.(\d+))?/);
184
- if (!match) return null;
185
-
186
- return {
187
- major: parseInt(match[1], 10),
188
- minor: parseInt(match[2], 10),
189
- patch: match[3] ? parseInt(match[3], 10) : 0,
190
- raw: versionString,
191
- };
192
- }
193
-
194
- function detectFrameworkVersions(projectPath) {
195
- const cacheKey = projectPath;
196
- if (FRAMEWORK_VERSION_CACHE.has(cacheKey)) {
197
- return FRAMEWORK_VERSION_CACHE.get(cacheKey);
198
- }
199
-
200
- const versions = {
201
- next: null,
202
- react: null,
203
- vue: null,
204
- svelte: null,
205
- express: null,
206
- fastify: null,
207
- nestjs: null,
208
- prisma: null,
209
- typescript: null,
210
- };
211
-
212
- try {
213
- const packageJsonPath = path.join(projectPath, "package.json");
214
- if (fs.existsSync(packageJsonPath)) {
215
- const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
216
- const deps = { ...pkg.dependencies, ...pkg.devDependencies };
217
-
218
- // Extract versions
219
- if (deps.next) versions.next = parseVersion(deps.next);
220
- if (deps.react) versions.react = parseVersion(deps.react);
221
- if (deps.vue) versions.vue = parseVersion(deps.vue);
222
- if (deps.svelte) versions.svelte = parseVersion(deps.svelte);
223
- if (deps.express) versions.express = parseVersion(deps.express);
224
- if (deps.fastify) versions.fastify = parseVersion(deps.fastify);
225
- if (deps["@nestjs/core"]) versions.nestjs = parseVersion(deps["@nestjs/core"]);
226
- if (deps["@prisma/client"]) versions.prisma = parseVersion(deps["@prisma/client"]);
227
- if (deps.typescript) versions.typescript = parseVersion(deps.typescript);
228
- }
229
- } catch {
230
- // Ignore errors
231
- }
232
-
233
- FRAMEWORK_VERSION_CACHE.set(cacheKey, versions);
234
- return versions;
235
- }
236
-
237
- // Version-specific rule adjustments
238
- const VERSION_RULES = {
239
- next: {
240
- // Next.js 13+ has app router with different patterns
241
- 13: {
242
- allowAsyncComponents: true,
243
- allowServerOnlyImports: true,
244
- requireUseClient: true,
245
- },
246
- // Next.js 14+ has improved server actions
247
- 14: {
248
- allowServerActions: true,
249
- requireFormAction: false, // Server actions can be inline
250
- },
251
- },
252
- react: {
253
- // React 18+ has concurrent features
254
- 18: {
255
- allowUseTransition: true,
256
- allowUseDeferredValue: true,
257
- allowUseId: true,
258
- },
259
- // React 19+ has use() hook
260
- 19: {
261
- allowUseHook: true,
262
- allowPromiseInRender: true,
263
- },
264
- },
265
- typescript: {
266
- // TS 5.0+ has new features
267
- 5: {
268
- allowConstTypeParameters: true,
269
- allowDecoratorMetadata: true,
270
- },
271
- },
272
- };
273
-
274
- function getVersionRules(framework, version) {
275
- if (!version || !VERSION_RULES[framework]) return {};
276
-
277
- const rules = {};
278
- const frameworkRules = VERSION_RULES[framework];
279
-
280
- // Apply rules for all versions <= current
281
- for (const [minVersion, versionRules] of Object.entries(frameworkRules)) {
282
- if (version.major >= parseInt(minVersion, 10)) {
283
- Object.assign(rules, versionRules);
284
- }
285
- }
286
-
287
- return rules;
288
- }
289
-
290
- function shouldSkipForFrameworkVersion(finding, projectPath) {
291
- const versions = detectFrameworkVersions(projectPath);
292
-
293
- // Next.js specific rules
294
- if (versions.next) {
295
- const nextRules = getVersionRules("next", versions.next);
296
-
297
- // Skip async component warnings in Next.js 13+
298
- if (nextRules.allowAsyncComponents && finding.type === "async-component") {
299
- return { skip: true, reason: "Async components allowed in Next.js 13+" };
300
- }
301
-
302
- // Skip server-only import warnings in Next.js 13+
303
- if (nextRules.allowServerOnlyImports && finding.type === "server-only-import") {
304
- return { skip: true, reason: "Server-only imports allowed in Next.js 13+ App Router" };
305
- }
306
- }
307
-
308
- // React specific rules
309
- if (versions.react) {
310
- const reactRules = getVersionRules("react", versions.react);
311
-
312
- // Skip use() hook warnings in React 19+
313
- if (reactRules.allowUseHook && finding.type === "unknown-hook" && finding.message?.includes("use(")) {
314
- return { skip: true, reason: "use() hook is valid in React 19+" };
315
- }
316
- }
317
-
318
- return { skip: false, reason: null };
319
- }
320
-
321
- // ═══════════════════════════════════════════════════════════════════════════════
322
- // TEST FILE DETECTION (Enhanced)
323
- // More accurate than just path patterns
324
- // ═══════════════════════════════════════════════════════════════════════════════
325
-
326
- const TEST_FRAMEWORK_IMPORTS = [
327
- /from ['"]vitest['"]/,
328
- /from ['"]jest['"]/,
329
- /from ['"]@testing-library\//,
330
- /from ['"]@playwright\//,
331
- /from ['"]cypress['"]/,
332
- /from ['"]mocha['"]/,
333
- /from ['"]chai['"]/,
334
- /require\(['"]vitest['"]\)/,
335
- /require\(['"]jest['"]\)/,
336
- ];
337
-
338
- const TEST_PATTERNS = [
339
- /\bdescribe\s*\(/,
340
- /\bit\s*\(/,
341
- /\btest\s*\(/,
342
- /\bexpect\s*\(/,
343
- /\bbeforeEach\s*\(/,
344
- /\bafterEach\s*\(/,
345
- /\bbeforeAll\s*\(/,
346
- /\bafterAll\s*\(/,
347
- ];
348
-
349
- function isTestFile(code, filePath = "") {
350
- // Path-based detection (fast)
351
- if (/\.(test|spec)\.(ts|tsx|js|jsx|mjs)$/i.test(filePath)) {
352
- return { isTest: true, reason: "Test file extension" };
353
- }
354
- if (/\/__tests__\/|\/tests?\/|\/e2e\/|\/cypress\//i.test(filePath)) {
355
- return { isTest: true, reason: "Test directory" };
356
- }
357
-
358
- if (!code) return { isTest: false, reason: null };
359
-
360
- // Content-based detection
361
- const header = code.slice(0, 2000); // Check first 2000 chars
362
-
363
- // Check for test framework imports
364
- for (const pattern of TEST_FRAMEWORK_IMPORTS) {
365
- if (pattern.test(header)) {
366
- return { isTest: true, reason: "Test framework import" };
367
- }
368
- }
369
-
370
- // Check for test patterns (must have multiple)
371
- let testPatternCount = 0;
372
- for (const pattern of TEST_PATTERNS) {
373
- if (pattern.test(code)) {
374
- testPatternCount++;
375
- if (testPatternCount >= 2) {
376
- return { isTest: true, reason: "Multiple test patterns" };
377
- }
378
- }
379
- }
380
-
381
- return { isTest: false, reason: null };
382
- }
383
-
384
- // ═══════════════════════════════════════════════════════════════════════════════
385
- // CONFIDENCE FEEDBACK TRACKING
386
- // Learn from user suppressions to improve confidence over time
387
- // ═══════════════════════════════════════════════════════════════════════════════
388
-
389
- const FEEDBACK_FILE = ".vibecheck/feedback.json";
390
-
391
- function loadFeedback(projectPath) {
392
- try {
393
- const feedbackPath = path.join(projectPath, FEEDBACK_FILE);
394
- if (fs.existsSync(feedbackPath)) {
395
- return JSON.parse(fs.readFileSync(feedbackPath, "utf8"));
396
- }
397
- } catch {
398
- // Ignore errors
399
- }
400
-
401
- return {
402
- version: 1,
403
- suppressions: {}, // rule -> { count, lastSeen }
404
- falsePositives: {}, // pattern -> count
405
- truePositives: {}, // pattern -> count
406
- };
407
- }
408
-
409
- function saveFeedback(projectPath, feedback) {
410
- try {
411
- const feedbackPath = path.join(projectPath, FEEDBACK_FILE);
412
- const dir = path.dirname(feedbackPath);
413
- if (!fs.existsSync(dir)) {
414
- fs.mkdirSync(dir, { recursive: true });
415
- }
416
- fs.writeFileSync(feedbackPath, JSON.stringify(feedback, null, 2));
417
- } catch {
418
- // Ignore errors
419
- }
420
- }
421
-
422
- function recordSuppression(projectPath, finding, reason = "user_suppressed") {
423
- const feedback = loadFeedback(projectPath);
424
- const rule = finding.type || finding.category || "unknown";
425
-
426
- if (!feedback.suppressions[rule]) {
427
- feedback.suppressions[rule] = { count: 0, lastSeen: null };
428
- }
429
-
430
- feedback.suppressions[rule].count++;
431
- feedback.suppressions[rule].lastSeen = new Date().toISOString();
432
-
433
- // Track false positive patterns
434
- const message = finding.message || finding.title || "";
435
- const pattern = normalizePattern(message);
436
-
437
- if (reason === "false_positive") {
438
- if (!feedback.falsePositives[pattern]) {
439
- feedback.falsePositives[pattern] = 0;
440
- }
441
- feedback.falsePositives[pattern]++;
442
- }
443
-
444
- saveFeedback(projectPath, feedback);
445
- }
446
-
447
- function normalizePattern(message) {
448
- return message
449
- .toLowerCase()
450
- .replace(/[`'"]/g, "")
451
- .replace(/\d+/g, "N")
452
- .replace(/\s+/g, " ")
453
- .trim()
454
- .slice(0, 100);
455
- }
456
-
457
- function getConfidenceAdjustment(projectPath, finding) {
458
- const feedback = loadFeedback(projectPath);
459
-
460
- let adjustment = 0;
461
-
462
- // Reduce confidence for frequently suppressed rules
463
- const rule = finding.type || finding.category || "unknown";
464
- const suppression = feedback.suppressions[rule];
465
-
466
- if (suppression) {
467
- if (suppression.count >= 10) adjustment -= 0.2;
468
- else if (suppression.count >= 5) adjustment -= 0.1;
469
- else if (suppression.count >= 2) adjustment -= 0.05;
470
- }
471
-
472
- // Reduce confidence for known false positive patterns
473
- const message = finding.message || finding.title || "";
474
- const pattern = normalizePattern(message);
475
- const fpCount = feedback.falsePositives[pattern] || 0;
476
-
477
- if (fpCount >= 5) adjustment -= 0.3;
478
- else if (fpCount >= 2) adjustment -= 0.15;
479
-
480
- return adjustment;
481
- }
482
-
483
- // ═══════════════════════════════════════════════════════════════════════════════
484
- // MAIN FALSE POSITIVE FILTER
485
- // ═══════════════════════════════════════════════════════════════════════════════
486
-
487
- function shouldFilterFinding(finding, code, filePath, projectPath) {
488
- const reasons = [];
489
- let confidenceAdjustment = 0;
490
-
491
- // Check generated code
492
- const generated = isGeneratedCode(code, filePath);
493
- if (generated.isGenerated) {
494
- return {
495
- filter: true,
496
- reason: generated.reason,
497
- confidence: 0,
498
- };
499
- }
500
-
501
- // Check vendored code
502
- const vendored = isVendoredCode(code, filePath);
503
- if (vendored.isVendored) {
504
- return {
505
- filter: true,
506
- reason: vendored.reason,
507
- confidence: 0,
508
- };
509
- }
510
-
511
- // Check test files
512
- const test = isTestFile(code, filePath);
513
- if (test.isTest) {
514
- confidenceAdjustment -= 0.4;
515
- reasons.push("Test file");
516
- }
517
-
518
- // Check framework version rules
519
- const versionSkip = shouldSkipForFrameworkVersion(finding, projectPath);
520
- if (versionSkip.skip) {
521
- return {
522
- filter: true,
523
- reason: versionSkip.reason,
524
- confidence: 0,
525
- };
526
- }
527
-
528
- // Apply feedback-based adjustment
529
- confidenceAdjustment += getConfidenceAdjustment(projectPath, finding);
530
-
531
- // Calculate final confidence
532
- const baseConfidence = finding.confidence || finding.confidenceScore || 0.5;
533
- const finalConfidence = Math.max(0, Math.min(1, baseConfidence + confidenceAdjustment));
534
-
535
- return {
536
- filter: false,
537
- reasons,
538
- confidence: finalConfidence,
539
- originalConfidence: baseConfidence,
540
- adjustment: confidenceAdjustment,
541
- };
542
- }
543
-
544
- function filterFalsePositives(findings, options = {}) {
545
- const { projectPath = ".", minConfidence = 0.3 } = options;
546
-
547
- const filtered = [];
548
- const removed = [];
549
-
550
- for (const finding of findings) {
551
- const filePath = finding.file || finding.filePath || "";
552
-
553
- // Try to get code content (may not be available)
554
- let code = finding.codeSnippet || finding.evidence?.[0]?.snippet || "";
555
- if (!code && filePath) {
556
- try {
557
- const fullPath = path.isAbsolute(filePath) ? filePath : path.join(projectPath, filePath);
558
- if (fs.existsSync(fullPath)) {
559
- code = fs.readFileSync(fullPath, "utf8");
560
- }
561
- } catch {
562
- // Ignore
563
- }
564
- }
565
-
566
- const result = shouldFilterFinding(finding, code, filePath, projectPath);
567
-
568
- if (result.filter) {
569
- removed.push({ finding, reason: result.reason });
570
- continue;
571
- }
572
-
573
- // Update confidence
574
- const updatedFinding = {
575
- ...finding,
576
- confidence: result.confidence,
577
- originalConfidence: result.originalConfidence,
578
- };
579
-
580
- // Filter by final confidence
581
- if (result.confidence >= minConfidence) {
582
- filtered.push(updatedFinding);
583
- } else {
584
- removed.push({ finding: updatedFinding, reason: "Low confidence after adjustments" });
585
- }
586
- }
587
-
588
- return {
589
- findings: filtered,
590
- removed,
591
- stats: {
592
- input: findings.length,
593
- output: filtered.length,
594
- removed: removed.length,
595
- },
596
- };
597
- }
598
-
599
- // ═══════════════════════════════════════════════════════════════════════════════
600
- // EXPORTS
601
- // ═══════════════════════════════════════════════════════════════════════════════
602
-
603
- module.exports = {
604
- // Main functions
605
- filterFalsePositives,
606
- shouldFilterFinding,
607
-
608
- // Detection functions
609
- isGeneratedCode,
610
- isVendoredCode,
611
- isTestFile,
612
-
613
- // Framework version functions
614
- detectFrameworkVersions,
615
- getVersionRules,
616
- shouldSkipForFrameworkVersion,
617
-
618
- // Feedback functions
619
- loadFeedback,
620
- saveFeedback,
621
- recordSuppression,
622
- getConfidenceAdjustment,
623
-
624
- // Constants
625
- GENERATED_CODE_MARKERS,
626
- VENDORED_CODE_MARKERS,
627
- VERSION_RULES,
628
- TEST_FRAMEWORK_IMPORTS,
629
- TEST_PATTERNS,
630
- };