@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.
- package/bin/registry.js +214 -237
- package/bin/runners/cli-utils.js +33 -2
- package/bin/runners/context/analyzer.js +52 -1
- package/bin/runners/context/generators/cursor.js +2 -49
- package/bin/runners/context/git-context.js +3 -1
- package/bin/runners/context/team-conventions.js +33 -7
- package/bin/runners/lib/analysis-core.js +25 -5
- package/bin/runners/lib/analyzers.js +431 -481
- package/bin/runners/lib/default-config.js +127 -0
- package/bin/runners/lib/doctor/modules/security.js +3 -1
- package/bin/runners/lib/engine/ast-cache.js +210 -0
- package/bin/runners/lib/engine/auth-extractor.js +211 -0
- package/bin/runners/lib/engine/billing-extractor.js +112 -0
- package/bin/runners/lib/engine/enforcement-extractor.js +100 -0
- package/bin/runners/lib/engine/env-extractor.js +207 -0
- package/bin/runners/lib/engine/express-extractor.js +208 -0
- package/bin/runners/lib/engine/extractors.js +849 -0
- package/bin/runners/lib/engine/index.js +207 -0
- package/bin/runners/lib/engine/repo-index.js +514 -0
- package/bin/runners/lib/engine/types.js +124 -0
- package/bin/runners/lib/engines/accessibility-engine.js +18 -218
- package/bin/runners/lib/engines/api-consistency-engine.js +30 -335
- package/bin/runners/lib/engines/cross-file-analysis-engine.js +27 -292
- package/bin/runners/lib/engines/empty-catch-engine.js +17 -127
- package/bin/runners/lib/engines/mock-data-engine.js +10 -53
- package/bin/runners/lib/engines/performance-issues-engine.js +36 -176
- package/bin/runners/lib/engines/security-vulnerabilities-engine.js +54 -382
- package/bin/runners/lib/engines/type-aware-engine.js +39 -263
- package/bin/runners/lib/engines/vibecheck-engines/index.js +13 -122
- package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +73 -373
- package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
- package/bin/runners/lib/entitlements-v2.js +73 -97
- package/bin/runners/lib/error-handler.js +44 -3
- package/bin/runners/lib/error-messages.js +289 -0
- package/bin/runners/lib/evidence-pack.js +7 -1
- package/bin/runners/lib/finding-id.js +69 -0
- package/bin/runners/lib/finding-sorter.js +89 -0
- package/bin/runners/lib/html-proof-report.js +700 -350
- package/bin/runners/lib/missions/plan.js +6 -46
- package/bin/runners/lib/missions/templates.js +0 -232
- package/bin/runners/lib/next-action.js +560 -0
- package/bin/runners/lib/prerequisites.js +149 -0
- package/bin/runners/lib/route-detection.js +137 -68
- package/bin/runners/lib/scan-output.js +91 -76
- package/bin/runners/lib/scan-runner.js +135 -0
- package/bin/runners/lib/schemas/ajv-validator.js +464 -0
- package/bin/runners/lib/schemas/error-envelope.schema.json +105 -0
- package/bin/runners/lib/schemas/finding-v3.schema.json +151 -0
- package/bin/runners/lib/schemas/report-artifact.schema.json +120 -0
- package/bin/runners/lib/schemas/run-request.schema.json +108 -0
- package/bin/runners/lib/schemas/validator.js +27 -0
- package/bin/runners/lib/schemas/verdict.schema.json +140 -0
- package/bin/runners/lib/ship-output-enterprise.js +23 -23
- package/bin/runners/lib/ship-output.js +75 -31
- package/bin/runners/lib/terminal-ui.js +6 -113
- package/bin/runners/lib/truth.js +351 -10
- package/bin/runners/lib/unified-cli-output.js +430 -603
- package/bin/runners/lib/unified-output.js +13 -9
- package/bin/runners/runAIAgent.js +10 -5
- package/bin/runners/runAgent.js +0 -3
- package/bin/runners/runAllowlist.js +389 -0
- package/bin/runners/runApprove.js +0 -33
- package/bin/runners/runAuth.js +73 -45
- package/bin/runners/runCheckpoint.js +51 -11
- package/bin/runners/runClassify.js +85 -21
- package/bin/runners/runContext.js +0 -3
- package/bin/runners/runDoctor.js +41 -28
- package/bin/runners/runEvidencePack.js +362 -0
- package/bin/runners/runFirewall.js +0 -3
- package/bin/runners/runFirewallHook.js +0 -3
- package/bin/runners/runFix.js +66 -76
- package/bin/runners/runGuard.js +18 -411
- package/bin/runners/runInit.js +113 -30
- package/bin/runners/runLabs.js +424 -0
- package/bin/runners/runMcp.js +19 -25
- package/bin/runners/runPolish.js +64 -240
- package/bin/runners/runPromptFirewall.js +12 -5
- package/bin/runners/runProve.js +57 -22
- package/bin/runners/runQuickstart.js +531 -0
- package/bin/runners/runReality.js +59 -68
- package/bin/runners/runReport.js +38 -33
- package/bin/runners/runRuntime.js +8 -5
- package/bin/runners/runScan.js +1413 -190
- package/bin/runners/runShip.js +113 -719
- package/bin/runners/runTruth.js +0 -3
- package/bin/runners/runValidate.js +13 -9
- package/bin/runners/runWatch.js +23 -14
- package/bin/scan.js +6 -1
- package/bin/vibecheck.js +204 -185
- package/mcp-server/deprecation-middleware.js +282 -0
- package/mcp-server/handlers/index.ts +15 -0
- package/mcp-server/handlers/tool-handler.ts +554 -0
- package/mcp-server/index-v1.js +698 -0
- package/mcp-server/index.js +210 -238
- package/mcp-server/lib/cache-wrapper.cjs +383 -0
- package/mcp-server/lib/error-envelope.js +138 -0
- package/mcp-server/lib/executor.ts +499 -0
- package/mcp-server/lib/index.ts +19 -0
- package/mcp-server/lib/rate-limiter.js +166 -0
- package/mcp-server/lib/sandbox.test.ts +519 -0
- package/mcp-server/lib/sandbox.ts +395 -0
- package/mcp-server/lib/types.ts +267 -0
- package/mcp-server/package.json +12 -3
- package/mcp-server/registry/tool-registry.js +794 -0
- package/mcp-server/registry/tools.json +605 -0
- package/mcp-server/registry.test.ts +334 -0
- package/mcp-server/tests/tier-gating.test.js +297 -0
- package/mcp-server/tier-auth.js +378 -45
- package/mcp-server/tools-v3.js +353 -442
- package/mcp-server/tsconfig.json +37 -0
- package/mcp-server/vibecheck-2.0-tools.js +14 -1
- package/package.json +1 -1
- package/bin/runners/lib/agent-firewall/learning/learning-engine.js +0 -849
- package/bin/runners/lib/audit-logger.js +0 -532
- package/bin/runners/lib/authority/authorities/architecture.js +0 -364
- package/bin/runners/lib/authority/authorities/compliance.js +0 -341
- package/bin/runners/lib/authority/authorities/human.js +0 -343
- package/bin/runners/lib/authority/authorities/quality.js +0 -420
- package/bin/runners/lib/authority/authorities/security.js +0 -228
- package/bin/runners/lib/authority/index.js +0 -293
- package/bin/runners/lib/bundle/bundle-intelligence.js +0 -846
- package/bin/runners/lib/cli-charts.js +0 -368
- package/bin/runners/lib/cli-config-display.js +0 -405
- package/bin/runners/lib/cli-demo.js +0 -275
- package/bin/runners/lib/cli-errors.js +0 -438
- package/bin/runners/lib/cli-help-formatter.js +0 -439
- package/bin/runners/lib/cli-interactive-menu.js +0 -509
- package/bin/runners/lib/cli-prompts.js +0 -441
- package/bin/runners/lib/cli-scan-cards.js +0 -362
- package/bin/runners/lib/compliance-reporter.js +0 -710
- package/bin/runners/lib/conductor/index.js +0 -671
- package/bin/runners/lib/easy/README.md +0 -123
- package/bin/runners/lib/easy/index.js +0 -140
- package/bin/runners/lib/easy/interactive-wizard.js +0 -788
- package/bin/runners/lib/easy/one-click-firewall.js +0 -564
- package/bin/runners/lib/easy/zero-config-reality.js +0 -714
- package/bin/runners/lib/engines/async-patterns-engine.js +0 -444
- package/bin/runners/lib/engines/bundle-size-engine.js +0 -433
- package/bin/runners/lib/engines/confidence-scoring.js +0 -276
- package/bin/runners/lib/engines/context-detection.js +0 -264
- package/bin/runners/lib/engines/database-patterns-engine.js +0 -429
- package/bin/runners/lib/engines/duplicate-code-engine.js +0 -354
- package/bin/runners/lib/engines/env-variables-engine.js +0 -458
- package/bin/runners/lib/engines/error-handling-engine.js +0 -437
- package/bin/runners/lib/engines/false-positive-prevention.js +0 -630
- package/bin/runners/lib/engines/framework-adapters/index.js +0 -607
- package/bin/runners/lib/engines/framework-detection.js +0 -508
- package/bin/runners/lib/engines/import-order-engine.js +0 -429
- package/bin/runners/lib/engines/naming-conventions-engine.js +0 -544
- package/bin/runners/lib/engines/noise-reduction-engine.js +0 -452
- package/bin/runners/lib/engines/orchestrator.js +0 -334
- package/bin/runners/lib/engines/react-patterns-engine.js +0 -457
- package/bin/runners/lib/engines/vibecheck-engines/lib/ai-hallucination-engine.js +0 -806
- package/bin/runners/lib/engines/vibecheck-engines/lib/smart-fix-engine.js +0 -577
- package/bin/runners/lib/engines/vibecheck-engines/lib/vibe-score-engine.js +0 -543
- package/bin/runners/lib/engines/vibecheck-engines.js +0 -514
- package/bin/runners/lib/enhanced-features/index.js +0 -305
- package/bin/runners/lib/enhanced-output.js +0 -631
- package/bin/runners/lib/enterprise.js +0 -300
- package/bin/runners/lib/firewall/command-validator.js +0 -351
- package/bin/runners/lib/firewall/config.js +0 -341
- package/bin/runners/lib/firewall/content-validator.js +0 -519
- package/bin/runners/lib/firewall/index.js +0 -101
- package/bin/runners/lib/firewall/path-validator.js +0 -256
- package/bin/runners/lib/intelligence/cross-repo-intelligence.js +0 -817
- package/bin/runners/lib/mcp-utils.js +0 -425
- package/bin/runners/lib/output/index.js +0 -1022
- package/bin/runners/lib/policy-engine.js +0 -652
- package/bin/runners/lib/polish/autofix/accessibility-fixes.js +0 -333
- package/bin/runners/lib/polish/autofix/async-handlers.js +0 -273
- package/bin/runners/lib/polish/autofix/dead-code.js +0 -280
- package/bin/runners/lib/polish/autofix/imports-optimizer.js +0 -344
- package/bin/runners/lib/polish/autofix/index.js +0 -200
- package/bin/runners/lib/polish/autofix/remove-consoles.js +0 -209
- package/bin/runners/lib/polish/autofix/strengthen-types.js +0 -245
- package/bin/runners/lib/polish/backend-checks.js +0 -148
- package/bin/runners/lib/polish/documentation-checks.js +0 -111
- package/bin/runners/lib/polish/frontend-checks.js +0 -168
- package/bin/runners/lib/polish/index.js +0 -71
- package/bin/runners/lib/polish/infrastructure-checks.js +0 -131
- package/bin/runners/lib/polish/library-detection.js +0 -175
- package/bin/runners/lib/polish/performance-checks.js +0 -100
- package/bin/runners/lib/polish/security-checks.js +0 -148
- package/bin/runners/lib/polish/utils.js +0 -203
- package/bin/runners/lib/prompt-builder.js +0 -540
- package/bin/runners/lib/proof-certificate.js +0 -634
- package/bin/runners/lib/reality/accessibility-audit.js +0 -946
- package/bin/runners/lib/reality/api-contract-validator.js +0 -1012
- package/bin/runners/lib/reality/chaos-engineering.js +0 -1084
- package/bin/runners/lib/reality/performance-tracker.js +0 -1077
- package/bin/runners/lib/reality/scenario-generator.js +0 -1404
- package/bin/runners/lib/reality/visual-regression.js +0 -852
- package/bin/runners/lib/reality-profiler.js +0 -717
- package/bin/runners/lib/replay/flight-recorder-viewer.js +0 -1160
- package/bin/runners/lib/review/ai-code-review.js +0 -832
- package/bin/runners/lib/rules/custom-rule-engine.js +0 -985
- package/bin/runners/lib/sbom-generator.js +0 -641
- package/bin/runners/lib/scan-output-enhanced.js +0 -512
- package/bin/runners/lib/security/owasp-scanner.js +0 -939
- package/bin/runners/lib/validators/contract-validator.js +0 -283
- package/bin/runners/lib/validators/dead-export-detector.js +0 -279
- package/bin/runners/lib/validators/dep-audit.js +0 -245
- package/bin/runners/lib/validators/env-validator.js +0 -319
- package/bin/runners/lib/validators/index.js +0 -120
- package/bin/runners/lib/validators/license-checker.js +0 -252
- package/bin/runners/lib/validators/route-validator.js +0 -290
- package/bin/runners/runAuthority.js +0 -528
- package/bin/runners/runConductor.js +0 -772
- package/bin/runners/runContainer.js +0 -366
- package/bin/runners/runEasy.js +0 -410
- package/bin/runners/runIaC.js +0 -372
- package/bin/runners/runVibe.js +0 -791
- 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
|
-
};
|