@vibecheckai/cli 3.3.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/registry.js +389 -269
- package/bin/runners/cli-utils.js +2 -33
- package/bin/runners/context/generators/cursor.js +49 -2
- package/bin/runners/lib/agent-firewall/learning/learning-engine.js +849 -0
- package/bin/runners/lib/analyzers.js +599 -142
- package/bin/runners/lib/audit-logger.js +532 -0
- package/bin/runners/lib/authority/authorities/architecture.js +364 -0
- package/bin/runners/lib/authority/authorities/compliance.js +341 -0
- package/bin/runners/lib/authority/authorities/human.js +343 -0
- package/bin/runners/lib/authority/authorities/quality.js +420 -0
- package/bin/runners/lib/authority/authorities/security.js +228 -0
- package/bin/runners/lib/authority/index.js +293 -0
- package/bin/runners/lib/authority-badge.js +425 -425
- package/bin/runners/lib/bundle/bundle-intelligence.js +846 -0
- package/bin/runners/lib/cli-charts.js +368 -0
- package/bin/runners/lib/cli-config-display.js +405 -0
- package/bin/runners/lib/cli-demo.js +275 -0
- package/bin/runners/lib/cli-errors.js +438 -0
- package/bin/runners/lib/cli-help-formatter.js +439 -0
- package/bin/runners/lib/cli-interactive-menu.js +509 -0
- package/bin/runners/lib/cli-prompts.js +441 -0
- package/bin/runners/lib/cli-scan-cards.js +362 -0
- package/bin/runners/lib/compliance-reporter.js +710 -0
- package/bin/runners/lib/conductor/index.js +671 -0
- package/bin/runners/lib/easy/README.md +123 -0
- package/bin/runners/lib/easy/index.js +140 -0
- package/bin/runners/lib/easy/interactive-wizard.js +788 -0
- package/bin/runners/lib/easy/one-click-firewall.js +564 -0
- package/bin/runners/lib/easy/zero-config-reality.js +714 -0
- package/bin/runners/lib/engines/accessibility-engine.js +218 -18
- package/bin/runners/lib/engines/api-consistency-engine.js +335 -30
- package/bin/runners/lib/engines/async-patterns-engine.js +444 -0
- package/bin/runners/lib/engines/bundle-size-engine.js +433 -0
- package/bin/runners/lib/engines/confidence-scoring.js +276 -0
- package/bin/runners/lib/engines/context-detection.js +264 -0
- package/bin/runners/lib/engines/cross-file-analysis-engine.js +292 -27
- package/bin/runners/lib/engines/database-patterns-engine.js +429 -0
- package/bin/runners/lib/engines/duplicate-code-engine.js +354 -0
- package/bin/runners/lib/engines/empty-catch-engine.js +127 -17
- package/bin/runners/lib/engines/env-variables-engine.js +458 -0
- package/bin/runners/lib/engines/error-handling-engine.js +437 -0
- package/bin/runners/lib/engines/false-positive-prevention.js +630 -0
- package/bin/runners/lib/engines/framework-adapters/index.js +607 -0
- package/bin/runners/lib/engines/framework-detection.js +508 -0
- package/bin/runners/lib/engines/import-order-engine.js +429 -0
- package/bin/runners/lib/engines/mock-data-engine.js +53 -10
- package/bin/runners/lib/engines/naming-conventions-engine.js +544 -0
- package/bin/runners/lib/engines/noise-reduction-engine.js +452 -0
- package/bin/runners/lib/engines/orchestrator.js +334 -0
- package/bin/runners/lib/engines/performance-issues-engine.js +176 -36
- package/bin/runners/lib/engines/react-patterns-engine.js +457 -0
- package/bin/runners/lib/engines/security-vulnerabilities-engine.js +382 -54
- package/bin/runners/lib/engines/type-aware-engine.js +263 -39
- package/bin/runners/lib/engines/vibecheck-engines/index.js +122 -13
- package/bin/runners/lib/engines/vibecheck-engines/lib/ai-hallucination-engine.js +806 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +373 -73
- package/bin/runners/lib/engines/vibecheck-engines/lib/smart-fix-engine.js +577 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/vibe-score-engine.js +543 -0
- package/bin/runners/lib/engines/vibecheck-engines.js +514 -0
- package/bin/runners/lib/enhanced-features/index.js +305 -0
- package/bin/runners/lib/enhanced-output.js +631 -0
- package/bin/runners/lib/enterprise.js +300 -0
- package/bin/runners/lib/entitlements-v2.js +161 -478
- package/bin/runners/lib/firewall/command-validator.js +351 -0
- package/bin/runners/lib/firewall/config.js +341 -0
- package/bin/runners/lib/firewall/content-validator.js +519 -0
- package/bin/runners/lib/firewall/index.js +101 -0
- package/bin/runners/lib/firewall/path-validator.js +256 -0
- package/bin/runners/lib/html-proof-report.js +350 -700
- package/bin/runners/lib/intelligence/cross-repo-intelligence.js +817 -0
- package/bin/runners/lib/mcp-utils.js +425 -0
- package/bin/runners/lib/missions/plan.js +46 -6
- package/bin/runners/lib/missions/templates.js +232 -0
- package/bin/runners/lib/output/index.js +1022 -0
- package/bin/runners/lib/policy-engine.js +652 -0
- package/bin/runners/lib/polish/autofix/accessibility-fixes.js +333 -0
- package/bin/runners/lib/polish/autofix/async-handlers.js +273 -0
- package/bin/runners/lib/polish/autofix/dead-code.js +280 -0
- package/bin/runners/lib/polish/autofix/imports-optimizer.js +344 -0
- package/bin/runners/lib/polish/autofix/index.js +200 -0
- package/bin/runners/lib/polish/autofix/remove-consoles.js +209 -0
- package/bin/runners/lib/polish/autofix/strengthen-types.js +245 -0
- package/bin/runners/lib/polish/backend-checks.js +148 -0
- package/bin/runners/lib/polish/documentation-checks.js +111 -0
- package/bin/runners/lib/polish/frontend-checks.js +168 -0
- package/bin/runners/lib/polish/index.js +71 -0
- package/bin/runners/lib/polish/infrastructure-checks.js +131 -0
- package/bin/runners/lib/polish/library-detection.js +175 -0
- package/bin/runners/lib/polish/performance-checks.js +100 -0
- package/bin/runners/lib/polish/security-checks.js +148 -0
- package/bin/runners/lib/polish/utils.js +203 -0
- package/bin/runners/lib/prompt-builder.js +540 -0
- package/bin/runners/lib/proof-certificate.js +634 -0
- package/bin/runners/lib/reality/accessibility-audit.js +946 -0
- package/bin/runners/lib/reality/api-contract-validator.js +1012 -0
- package/bin/runners/lib/reality/chaos-engineering.js +1084 -0
- package/bin/runners/lib/reality/performance-tracker.js +1077 -0
- package/bin/runners/lib/reality/scenario-generator.js +1404 -0
- package/bin/runners/lib/reality/visual-regression.js +852 -0
- package/bin/runners/lib/reality-profiler.js +717 -0
- package/bin/runners/lib/replay/flight-recorder-viewer.js +1160 -0
- package/bin/runners/lib/review/ai-code-review.js +832 -0
- package/bin/runners/lib/rules/custom-rule-engine.js +985 -0
- package/bin/runners/lib/sbom-generator.js +641 -0
- package/bin/runners/lib/scan-output-enhanced.js +512 -0
- package/bin/runners/lib/scan-output.js +65 -19
- package/bin/runners/lib/security/owasp-scanner.js +939 -0
- package/bin/runners/lib/ship-output.js +18 -25
- package/bin/runners/lib/terminal-ui.js +113 -1
- package/bin/runners/lib/unified-cli-output.js +603 -430
- package/bin/runners/lib/upsell.js +90 -338
- package/bin/runners/lib/validators/contract-validator.js +283 -0
- package/bin/runners/lib/validators/dead-export-detector.js +279 -0
- package/bin/runners/lib/validators/dep-audit.js +245 -0
- package/bin/runners/lib/validators/env-validator.js +319 -0
- package/bin/runners/lib/validators/index.js +120 -0
- package/bin/runners/lib/validators/license-checker.js +252 -0
- package/bin/runners/lib/validators/route-validator.js +290 -0
- package/bin/runners/runAIAgent.js +5 -10
- package/bin/runners/runAgent.js +3 -0
- package/bin/runners/runApprove.js +1233 -1200
- package/bin/runners/runAuth.js +22 -1
- package/bin/runners/runAuthority.js +528 -0
- package/bin/runners/runCheckpoint.js +4 -24
- package/bin/runners/runClassify.js +862 -859
- package/bin/runners/runConductor.js +772 -0
- package/bin/runners/runContainer.js +366 -0
- package/bin/runners/runContext.js +3 -0
- package/bin/runners/runDoctor.js +28 -41
- package/bin/runners/runEasy.js +410 -0
- package/bin/runners/runFirewall.js +3 -0
- package/bin/runners/runFirewallHook.js +3 -0
- package/bin/runners/runFix.js +76 -66
- package/bin/runners/runGuard.js +411 -18
- package/bin/runners/runIaC.js +372 -0
- package/bin/runners/runInit.js +10 -60
- package/bin/runners/runMcp.js +11 -12
- package/bin/runners/runPolish.js +240 -64
- package/bin/runners/runPromptFirewall.js +5 -12
- package/bin/runners/runProve.js +20 -55
- package/bin/runners/runReality.js +68 -59
- package/bin/runners/runReport.js +31 -5
- package/bin/runners/runRuntime.js +5 -8
- package/bin/runners/runScan.js +194 -1273
- package/bin/runners/runShip.js +695 -47
- package/bin/runners/runTruth.js +3 -0
- package/bin/runners/runValidate.js +7 -11
- package/bin/runners/runVibe.js +791 -0
- package/bin/runners/runWatch.js +14 -23
- package/bin/vibecheck.js +179 -65
- package/mcp-server/index.js +202 -636
- package/mcp-server/lib/api-client.cjs +7 -299
- package/mcp-server/package.json +1 -1
- package/mcp-server/tier-auth.js +175 -574
- package/mcp-server/tools-v3.js +800 -505
- package/mcp-server/tools.js +495 -0
- package/package.json +1 -1
- package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +0 -164
- package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +0 -291
- package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +0 -83
- package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +0 -198
- package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +0 -275
- package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +0 -167
- package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +0 -217
- package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +0 -140
- package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +0 -164
- package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +0 -234
- package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +0 -217
- package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +0 -78
- package/mcp-server/index-v1.js +0 -698
|
@@ -12,6 +12,62 @@ const t = require("@babel/types");
|
|
|
12
12
|
|
|
13
13
|
const { routeMatches } = require("./claims");
|
|
14
14
|
const { matcherCoversPath } = require("./auth-truth");
|
|
15
|
+
const {
|
|
16
|
+
getFrameworks,
|
|
17
|
+
hasFramework,
|
|
18
|
+
getFileContext,
|
|
19
|
+
isServerComponent,
|
|
20
|
+
isClientComponent,
|
|
21
|
+
isRouteHandler,
|
|
22
|
+
FRAMEWORKS,
|
|
23
|
+
} = require("./engines/framework-detection");
|
|
24
|
+
|
|
25
|
+
// V6: Bulletproof noise reduction and false positive prevention
|
|
26
|
+
let noiseReduction, falsePositivePrevention;
|
|
27
|
+
try {
|
|
28
|
+
noiseReduction = require("./engines/noise-reduction-engine");
|
|
29
|
+
falsePositivePrevention = require("./engines/false-positive-prevention");
|
|
30
|
+
} catch {
|
|
31
|
+
// Engines not available - continue without them
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* ============================================================================
|
|
35
|
+
* STANDARD IGNORE PATTERNS
|
|
36
|
+
* Used by all analyzers to exclude non-production code
|
|
37
|
+
* ========================================================================== */
|
|
38
|
+
const STANDARD_IGNORE_PATTERNS = [
|
|
39
|
+
// Core excludes
|
|
40
|
+
"**/node_modules/**",
|
|
41
|
+
"**/.next/**",
|
|
42
|
+
"**/dist/**",
|
|
43
|
+
"**/build/**",
|
|
44
|
+
"**/*.d.ts",
|
|
45
|
+
"**/*.d.ts.map",
|
|
46
|
+
// Test files
|
|
47
|
+
"**/__tests__/**",
|
|
48
|
+
"**/tests/**",
|
|
49
|
+
"**/*.test.ts",
|
|
50
|
+
"**/*.test.tsx",
|
|
51
|
+
"**/*.test.js",
|
|
52
|
+
"**/*.spec.ts",
|
|
53
|
+
"**/*.spec.tsx",
|
|
54
|
+
"**/*.spec.js",
|
|
55
|
+
"**/fixtures/**",
|
|
56
|
+
// Internal tooling
|
|
57
|
+
"**/mcp-server/**",
|
|
58
|
+
"**/bin/**",
|
|
59
|
+
"**/packages/cli/**",
|
|
60
|
+
// Examples and templates
|
|
61
|
+
"**/examples/**",
|
|
62
|
+
"**/templates/**",
|
|
63
|
+
"**/docs/**",
|
|
64
|
+
// Cache and generated
|
|
65
|
+
"**/.guardrail/**",
|
|
66
|
+
"**/.cursor/**",
|
|
67
|
+
"**/.vibecheck/**",
|
|
68
|
+
"**/coverage/**",
|
|
69
|
+
"**/_archive/**",
|
|
70
|
+
];
|
|
15
71
|
|
|
16
72
|
/* ============================================================================
|
|
17
73
|
* WORLD-CLASS INFRA HELPERS
|
|
@@ -914,7 +970,7 @@ function findFakeSuccess(repoRoot) {
|
|
|
914
970
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
915
971
|
cwd: repoRoot,
|
|
916
972
|
absolute: true,
|
|
917
|
-
ignore:
|
|
973
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
918
974
|
});
|
|
919
975
|
|
|
920
976
|
for (const fileAbs of files) {
|
|
@@ -925,6 +981,21 @@ function findFakeSuccess(repoRoot) {
|
|
|
925
981
|
// relevant keywords (toast/push/navigate AND fetch/axios).
|
|
926
982
|
const hasSuccessUI = /\b(toast|\.push|navigate)\b/.test(code);
|
|
927
983
|
const hasNetworkCall = /\b(fetch|axios)\b/.test(code);
|
|
984
|
+
|
|
985
|
+
// Enhanced: Also check for TanStack Query / React Query mutations
|
|
986
|
+
// These have built-in error handling via onError callback
|
|
987
|
+
const hasTanstackMutation = /\buseMutation\b/.test(code);
|
|
988
|
+
const hasTRPCMutation = /\.useMutation\b/.test(code);
|
|
989
|
+
|
|
990
|
+
// Skip files that use TanStack Query mutations with onSuccess/onError
|
|
991
|
+
// These are properly handling async state
|
|
992
|
+
if (hasTanstackMutation || hasTRPCMutation) {
|
|
993
|
+
const hasProperCallbacks = /onSuccess\s*:|onError\s*:|onSettled\s*:/.test(code);
|
|
994
|
+
if (hasProperCallbacks) {
|
|
995
|
+
continue; // Properly handled
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
|
|
928
999
|
if (!hasSuccessUI || !hasNetworkCall) {
|
|
929
1000
|
continue;
|
|
930
1001
|
}
|
|
@@ -1013,18 +1084,58 @@ function findFakeSuccess(repoRoot) {
|
|
|
1013
1084
|
* ========================================================================== */
|
|
1014
1085
|
|
|
1015
1086
|
function looksSensitive(pathStr) {
|
|
1016
|
-
const p = String(pathStr || "");
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1087
|
+
const p = String(pathStr || "").toLowerCase();
|
|
1088
|
+
|
|
1089
|
+
// Sensitive path prefixes
|
|
1090
|
+
const sensitivePathPrefixes = [
|
|
1091
|
+
"/api/admin",
|
|
1092
|
+
"/api/billing",
|
|
1093
|
+
"/api/stripe",
|
|
1094
|
+
"/api/org",
|
|
1095
|
+
"/api/team",
|
|
1096
|
+
"/api/account",
|
|
1097
|
+
"/api/settings",
|
|
1098
|
+
"/api/users",
|
|
1099
|
+
"/api/user",
|
|
1100
|
+
"/api/profile",
|
|
1101
|
+
"/api/dashboard",
|
|
1102
|
+
"/api/private",
|
|
1103
|
+
"/api/internal",
|
|
1104
|
+
"/api/manage",
|
|
1105
|
+
"/api/payment",
|
|
1106
|
+
"/api/subscription",
|
|
1107
|
+
"/api/checkout",
|
|
1108
|
+
"/api/webhook", // Webhooks need verification
|
|
1109
|
+
"/api/upload",
|
|
1110
|
+
"/api/delete",
|
|
1111
|
+
"/api/export",
|
|
1112
|
+
"/api/import",
|
|
1113
|
+
];
|
|
1114
|
+
|
|
1115
|
+
// Sensitive path patterns (regex)
|
|
1116
|
+
const sensitivePathPatterns = [
|
|
1117
|
+
/\/api\/.*\/admin/,
|
|
1118
|
+
/\/api\/.*\/delete/,
|
|
1119
|
+
/\/api\/.*\/edit/,
|
|
1120
|
+
/\/api\/.*\/update/,
|
|
1121
|
+
/\/api\/.*\/create/,
|
|
1122
|
+
/\/api\/.*\/remove/,
|
|
1123
|
+
/\/api\/.*\/modify/,
|
|
1124
|
+
/\/api\/me\b/,
|
|
1125
|
+
/\/api\/\[.*id\]/, // Dynamic user/resource routes
|
|
1126
|
+
];
|
|
1127
|
+
|
|
1128
|
+
// Check prefixes
|
|
1129
|
+
if (sensitivePathPrefixes.some(prefix => p.startsWith(prefix))) {
|
|
1130
|
+
return true;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
// Check patterns
|
|
1134
|
+
if (sensitivePathPatterns.some(pattern => pattern.test(p))) {
|
|
1135
|
+
return true;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
return false;
|
|
1028
1139
|
}
|
|
1029
1140
|
|
|
1030
1141
|
function hasRouteLevelProtection(routeDef) {
|
|
@@ -1037,11 +1148,69 @@ function handlerHasAuthSignal(repoRoot, handlerRel) {
|
|
|
1037
1148
|
if (!fs.existsSync(abs)) return false;
|
|
1038
1149
|
const code = readFileCached(abs);
|
|
1039
1150
|
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
/\
|
|
1043
|
-
/\
|
|
1044
|
-
|
|
1151
|
+
// Next.js / NextAuth patterns
|
|
1152
|
+
const nextAuthPatterns = [
|
|
1153
|
+
/\bgetServerSession\b/,
|
|
1154
|
+
/\bauth\(\)\b/,
|
|
1155
|
+
/\bgetSession\b/,
|
|
1156
|
+
/\buseSession\b/,
|
|
1157
|
+
/\bgetToken\b/,
|
|
1158
|
+
];
|
|
1159
|
+
|
|
1160
|
+
// Clerk patterns
|
|
1161
|
+
const clerkPatterns = [
|
|
1162
|
+
/\bclerk\b/i,
|
|
1163
|
+
/@clerk\/nextjs/,
|
|
1164
|
+
/\bauth\(\)\s*\.\s*userId/,
|
|
1165
|
+
/\bcurrentUser\b/,
|
|
1166
|
+
/\bgetAuth\b/,
|
|
1167
|
+
];
|
|
1168
|
+
|
|
1169
|
+
// Supabase patterns
|
|
1170
|
+
const supabasePatterns = [
|
|
1171
|
+
/\bcreateRouteHandlerClient\b/,
|
|
1172
|
+
/\bcreateServerComponentClient\b/,
|
|
1173
|
+
/\bsupabase\b.*\bauth\b/i,
|
|
1174
|
+
/@supabase/,
|
|
1175
|
+
/\bgetUser\(\)/,
|
|
1176
|
+
];
|
|
1177
|
+
|
|
1178
|
+
// General auth patterns
|
|
1179
|
+
const generalAuthPatterns = [
|
|
1180
|
+
/\b(jwtVerify|verifyToken|verifyJWT)\b/i,
|
|
1181
|
+
/\bauthorization\b/i,
|
|
1182
|
+
/\bbearer\s+token/i,
|
|
1183
|
+
/\b(isAdmin|adminOnly|permissions|rbac)\b/i,
|
|
1184
|
+
/\bauthenticated\b/i,
|
|
1185
|
+
/\brequireAuth\b/i,
|
|
1186
|
+
/\bprotectedProcedure\b/, // tRPC
|
|
1187
|
+
];
|
|
1188
|
+
|
|
1189
|
+
// Next.js App Router specific patterns
|
|
1190
|
+
const appRouterPatterns = [
|
|
1191
|
+
/\bcookies\(\)\s*\.\s*get\s*\(\s*['"](?:session|token|auth)/i,
|
|
1192
|
+
/\bheaders\(\)\s*\.\s*get\s*\(\s*['"]authorization/i,
|
|
1193
|
+
/\bNextResponse\.redirect\s*\(.*(?:login|signin|unauthorized)/i,
|
|
1194
|
+
];
|
|
1195
|
+
|
|
1196
|
+
// tRPC context patterns (context often has auth)
|
|
1197
|
+
const trpcPatterns = [
|
|
1198
|
+
/ctx\.session/,
|
|
1199
|
+
/ctx\.user/,
|
|
1200
|
+
/ctx\.auth/,
|
|
1201
|
+
/\.protectedProcedure/,
|
|
1202
|
+
];
|
|
1203
|
+
|
|
1204
|
+
const allPatterns = [
|
|
1205
|
+
...nextAuthPatterns,
|
|
1206
|
+
...clerkPatterns,
|
|
1207
|
+
...supabasePatterns,
|
|
1208
|
+
...generalAuthPatterns,
|
|
1209
|
+
...appRouterPatterns,
|
|
1210
|
+
...trpcPatterns,
|
|
1211
|
+
];
|
|
1212
|
+
|
|
1213
|
+
return allPatterns.some(pattern => pattern.test(code));
|
|
1045
1214
|
}
|
|
1046
1215
|
|
|
1047
1216
|
function isProtectedByNextMiddleware(truthpack, routePath) {
|
|
@@ -1205,7 +1374,7 @@ function findOwnerModeBypass(repoRoot) {
|
|
|
1205
1374
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
1206
1375
|
cwd: repoRoot,
|
|
1207
1376
|
absolute: true,
|
|
1208
|
-
ignore:
|
|
1377
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
1209
1378
|
});
|
|
1210
1379
|
|
|
1211
1380
|
const patterns = [
|
|
@@ -1250,17 +1419,7 @@ function findMockData(repoRoot) {
|
|
|
1250
1419
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
1251
1420
|
cwd: repoRoot,
|
|
1252
1421
|
absolute: true,
|
|
1253
|
-
ignore:
|
|
1254
|
-
"**/node_modules/**",
|
|
1255
|
-
"**/.next/**",
|
|
1256
|
-
"**/dist/**",
|
|
1257
|
-
"**/build/**",
|
|
1258
|
-
"**/*.test.*",
|
|
1259
|
-
"**/*.spec.*",
|
|
1260
|
-
"**/tests/**",
|
|
1261
|
-
"**/test/**",
|
|
1262
|
-
"**/__tests__/**",
|
|
1263
|
-
],
|
|
1422
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
1264
1423
|
});
|
|
1265
1424
|
|
|
1266
1425
|
for (const fileAbs of files) {
|
|
@@ -1311,13 +1470,7 @@ function findTodoFixme(repoRoot) {
|
|
|
1311
1470
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
1312
1471
|
cwd: repoRoot,
|
|
1313
1472
|
absolute: true,
|
|
1314
|
-
ignore:
|
|
1315
|
-
"**/node_modules/**",
|
|
1316
|
-
"**/.next/**",
|
|
1317
|
-
"**/dist/**",
|
|
1318
|
-
"**/build/**",
|
|
1319
|
-
"**/*.d.ts",
|
|
1320
|
-
],
|
|
1473
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
1321
1474
|
});
|
|
1322
1475
|
|
|
1323
1476
|
for (const fileAbs of files) {
|
|
@@ -1384,13 +1537,7 @@ function findConsoleLogs(repoRoot) {
|
|
|
1384
1537
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
1385
1538
|
cwd: repoRoot,
|
|
1386
1539
|
absolute: true,
|
|
1387
|
-
ignore:
|
|
1388
|
-
"**/node_modules/**",
|
|
1389
|
-
"**/.next/**",
|
|
1390
|
-
"**/dist/**",
|
|
1391
|
-
"**/build/**",
|
|
1392
|
-
"**/*.d.ts",
|
|
1393
|
-
],
|
|
1540
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
1394
1541
|
});
|
|
1395
1542
|
|
|
1396
1543
|
for (const fileAbs of files) {
|
|
@@ -1436,16 +1583,7 @@ function findHardcodedSecrets(repoRoot) {
|
|
|
1436
1583
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx,json}"], {
|
|
1437
1584
|
cwd: repoRoot,
|
|
1438
1585
|
absolute: true,
|
|
1439
|
-
ignore: [
|
|
1440
|
-
"**/node_modules/**",
|
|
1441
|
-
"**/.next/**",
|
|
1442
|
-
"**/dist/**",
|
|
1443
|
-
"**/build/**",
|
|
1444
|
-
"**/package*.json",
|
|
1445
|
-
"**/*.test.*",
|
|
1446
|
-
"**/tests/**",
|
|
1447
|
-
"**/*.d.ts",
|
|
1448
|
-
],
|
|
1586
|
+
ignore: [...STANDARD_IGNORE_PATTERNS, "**/package*.json"],
|
|
1449
1587
|
});
|
|
1450
1588
|
|
|
1451
1589
|
for (const fileAbs of files) {
|
|
@@ -1502,13 +1640,7 @@ function findDeadCode(repoRoot) {
|
|
|
1502
1640
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
1503
1641
|
cwd: repoRoot,
|
|
1504
1642
|
absolute: true,
|
|
1505
|
-
ignore:
|
|
1506
|
-
"**/node_modules/**",
|
|
1507
|
-
"**/.next/**",
|
|
1508
|
-
"**/dist/**",
|
|
1509
|
-
"**/build/**",
|
|
1510
|
-
"**/*.d.ts",
|
|
1511
|
-
],
|
|
1643
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
1512
1644
|
});
|
|
1513
1645
|
|
|
1514
1646
|
for (const fileAbs of files) {
|
|
@@ -1554,13 +1686,7 @@ function findDeprecatedApis(repoRoot) {
|
|
|
1554
1686
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
1555
1687
|
cwd: repoRoot,
|
|
1556
1688
|
absolute: true,
|
|
1557
|
-
ignore:
|
|
1558
|
-
"**/node_modules/**",
|
|
1559
|
-
"**/.next/**",
|
|
1560
|
-
"**/dist/**",
|
|
1561
|
-
"**/build/**",
|
|
1562
|
-
"**/*.d.ts",
|
|
1563
|
-
],
|
|
1689
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
1564
1690
|
});
|
|
1565
1691
|
|
|
1566
1692
|
for (const fileAbs of files) {
|
|
@@ -1606,13 +1732,7 @@ function findEmptyCatch(repoRoot) {
|
|
|
1606
1732
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
1607
1733
|
cwd: repoRoot,
|
|
1608
1734
|
absolute: true,
|
|
1609
|
-
ignore:
|
|
1610
|
-
"**/node_modules/**",
|
|
1611
|
-
"**/.next/**",
|
|
1612
|
-
"**/dist/**",
|
|
1613
|
-
"**/build/**",
|
|
1614
|
-
"**/*.d.ts",
|
|
1615
|
-
],
|
|
1735
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
1616
1736
|
});
|
|
1617
1737
|
|
|
1618
1738
|
for (const fileAbs of files) {
|
|
@@ -1658,13 +1778,7 @@ function findUnsafeRegex(repoRoot) {
|
|
|
1658
1778
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
1659
1779
|
cwd: repoRoot,
|
|
1660
1780
|
absolute: true,
|
|
1661
|
-
ignore:
|
|
1662
|
-
"**/node_modules/**",
|
|
1663
|
-
"**/.next/**",
|
|
1664
|
-
"**/dist/**",
|
|
1665
|
-
"**/build/**",
|
|
1666
|
-
"**/*.d.ts",
|
|
1667
|
-
],
|
|
1781
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
1668
1782
|
});
|
|
1669
1783
|
|
|
1670
1784
|
for (const fileAbs of files) {
|
|
@@ -1712,13 +1826,7 @@ function findSecurityVulnerabilities(repoRoot) {
|
|
|
1712
1826
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
1713
1827
|
cwd: repoRoot,
|
|
1714
1828
|
absolute: true,
|
|
1715
|
-
ignore:
|
|
1716
|
-
"**/node_modules/**",
|
|
1717
|
-
"**/.next/**",
|
|
1718
|
-
"**/dist/**",
|
|
1719
|
-
"**/build/**",
|
|
1720
|
-
"**/*.d.ts",
|
|
1721
|
-
],
|
|
1829
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
1722
1830
|
});
|
|
1723
1831
|
|
|
1724
1832
|
for (const fileAbs of files) {
|
|
@@ -1762,13 +1870,7 @@ function findPerformanceIssues(repoRoot) {
|
|
|
1762
1870
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
1763
1871
|
cwd: repoRoot,
|
|
1764
1872
|
absolute: true,
|
|
1765
|
-
ignore:
|
|
1766
|
-
"**/node_modules/**",
|
|
1767
|
-
"**/.next/**",
|
|
1768
|
-
"**/dist/**",
|
|
1769
|
-
"**/build/**",
|
|
1770
|
-
"**/*.d.ts",
|
|
1771
|
-
],
|
|
1873
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
1772
1874
|
});
|
|
1773
1875
|
|
|
1774
1876
|
for (const fileAbs of files) {
|
|
@@ -1813,13 +1915,7 @@ function findCodeQualityIssues(repoRoot) {
|
|
|
1813
1915
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
1814
1916
|
cwd: repoRoot,
|
|
1815
1917
|
absolute: true,
|
|
1816
|
-
ignore:
|
|
1817
|
-
"**/node_modules/**",
|
|
1818
|
-
"**/.next/**",
|
|
1819
|
-
"**/dist/**",
|
|
1820
|
-
"**/build/**",
|
|
1821
|
-
"**/*.d.ts",
|
|
1822
|
-
],
|
|
1918
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
1823
1919
|
});
|
|
1824
1920
|
|
|
1825
1921
|
for (const fileAbs of files) {
|
|
@@ -1865,16 +1961,7 @@ function findCrossFileIssues(repoRoot) {
|
|
|
1865
1961
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
1866
1962
|
cwd: repoRoot,
|
|
1867
1963
|
absolute: true,
|
|
1868
|
-
ignore:
|
|
1869
|
-
"**/node_modules/**",
|
|
1870
|
-
"**/.next/**",
|
|
1871
|
-
"**/dist/**",
|
|
1872
|
-
"**/build/**",
|
|
1873
|
-
"**/*.d.ts",
|
|
1874
|
-
"**/*.test.*",
|
|
1875
|
-
"**/*.spec.*",
|
|
1876
|
-
"**/tests/**",
|
|
1877
|
-
],
|
|
1964
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
1878
1965
|
});
|
|
1879
1966
|
|
|
1880
1967
|
const engineFindings = analyzeCrossFile(files, repoRoot);
|
|
@@ -1909,13 +1996,7 @@ function findTypeSafetyIssues(repoRoot) {
|
|
|
1909
1996
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
1910
1997
|
cwd: repoRoot,
|
|
1911
1998
|
absolute: true,
|
|
1912
|
-
ignore:
|
|
1913
|
-
"**/node_modules/**",
|
|
1914
|
-
"**/.next/**",
|
|
1915
|
-
"**/dist/**",
|
|
1916
|
-
"**/build/**",
|
|
1917
|
-
"**/*.d.ts",
|
|
1918
|
-
],
|
|
1999
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
1919
2000
|
});
|
|
1920
2001
|
|
|
1921
2002
|
for (const fileAbs of files) {
|
|
@@ -1959,16 +2040,7 @@ function findAccessibilityIssues(repoRoot) {
|
|
|
1959
2040
|
const files = fg.sync(["**/*.{tsx,jsx}"], {
|
|
1960
2041
|
cwd: repoRoot,
|
|
1961
2042
|
absolute: true,
|
|
1962
|
-
ignore:
|
|
1963
|
-
"**/node_modules/**",
|
|
1964
|
-
"**/.next/**",
|
|
1965
|
-
"**/dist/**",
|
|
1966
|
-
"**/build/**",
|
|
1967
|
-
"**/*.d.ts",
|
|
1968
|
-
"**/*.test.*",
|
|
1969
|
-
"**/*.spec.*",
|
|
1970
|
-
"**/tests/**",
|
|
1971
|
-
],
|
|
2043
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
1972
2044
|
});
|
|
1973
2045
|
|
|
1974
2046
|
for (const fileAbs of files) {
|
|
@@ -2012,16 +2084,7 @@ function findAPIConsistencyIssues(repoRoot) {
|
|
|
2012
2084
|
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
2013
2085
|
cwd: repoRoot,
|
|
2014
2086
|
absolute: true,
|
|
2015
|
-
ignore:
|
|
2016
|
-
"**/node_modules/**",
|
|
2017
|
-
"**/.next/**",
|
|
2018
|
-
"**/dist/**",
|
|
2019
|
-
"**/build/**",
|
|
2020
|
-
"**/*.d.ts",
|
|
2021
|
-
"**/*.test.*",
|
|
2022
|
-
"**/*.spec.*",
|
|
2023
|
-
"**/tests/**",
|
|
2024
|
-
],
|
|
2087
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
2025
2088
|
});
|
|
2026
2089
|
|
|
2027
2090
|
for (const fileAbs of files) {
|
|
@@ -2058,14 +2121,397 @@ function findAPIConsistencyIssues(repoRoot) {
|
|
|
2058
2121
|
return findings;
|
|
2059
2122
|
}
|
|
2060
2123
|
|
|
2124
|
+
/* ============================================================================
|
|
2125
|
+
* REACT PATTERNS ANALYZER
|
|
2126
|
+
* Only runs on .tsx/.jsx files for performance
|
|
2127
|
+
* ========================================================================== */
|
|
2128
|
+
|
|
2129
|
+
function findReactPatternIssues(repoRoot) {
|
|
2130
|
+
const { analyzeReactPatterns } = require("./engines/react-patterns-engine");
|
|
2131
|
+
const findings = [];
|
|
2132
|
+
|
|
2133
|
+
// Only scan React files for performance
|
|
2134
|
+
const files = fg.sync(["**/*.{tsx,jsx}"], {
|
|
2135
|
+
cwd: repoRoot,
|
|
2136
|
+
absolute: true,
|
|
2137
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
2138
|
+
});
|
|
2139
|
+
|
|
2140
|
+
for (const fileAbs of files) {
|
|
2141
|
+
try {
|
|
2142
|
+
const code = readFileCached(fileAbs);
|
|
2143
|
+
const fileRel = path.relative(repoRoot, fileAbs).replace(/\\/g, "/");
|
|
2144
|
+
|
|
2145
|
+
const engineFindings = analyzeReactPatterns(code, fileRel);
|
|
2146
|
+
|
|
2147
|
+
// Only include BLOCK and WARN severity for performance
|
|
2148
|
+
for (const finding of engineFindings) {
|
|
2149
|
+
if (finding.severity === "INFO") continue;
|
|
2150
|
+
|
|
2151
|
+
findings.push({
|
|
2152
|
+
id: stableId("F_REACT", `${fileRel}:${finding.type}:${finding.line}`),
|
|
2153
|
+
severity: finding.severity,
|
|
2154
|
+
category: finding.category || "ReactPatterns",
|
|
2155
|
+
title: finding.title,
|
|
2156
|
+
message: finding.message,
|
|
2157
|
+
file: finding.file,
|
|
2158
|
+
line: finding.line,
|
|
2159
|
+
why: "React anti-patterns can cause bugs, performance issues, and maintenance problems.",
|
|
2160
|
+
confidence: finding.confidence,
|
|
2161
|
+
evidence: [{ file: fileRel, reason: finding.title, line: finding.line }],
|
|
2162
|
+
fixHints: [finding.fixHint].filter(Boolean),
|
|
2163
|
+
});
|
|
2164
|
+
}
|
|
2165
|
+
} catch (err) {
|
|
2166
|
+
continue;
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
return findings;
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
/* ============================================================================
|
|
2174
|
+
* ERROR HANDLING ANALYZER
|
|
2175
|
+
* Checks error handling patterns across all JS/TS files
|
|
2176
|
+
* ========================================================================== */
|
|
2177
|
+
|
|
2178
|
+
function findErrorHandlingIssues(repoRoot) {
|
|
2179
|
+
const { analyzeErrorHandling } = require("./engines/error-handling-engine");
|
|
2180
|
+
const findings = [];
|
|
2181
|
+
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
2182
|
+
cwd: repoRoot,
|
|
2183
|
+
absolute: true,
|
|
2184
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
2185
|
+
});
|
|
2186
|
+
|
|
2187
|
+
for (const fileAbs of files) {
|
|
2188
|
+
try {
|
|
2189
|
+
const code = readFileCached(fileAbs);
|
|
2190
|
+
const fileRel = path.relative(repoRoot, fileAbs).replace(/\\/g, "/");
|
|
2191
|
+
|
|
2192
|
+
const engineFindings = analyzeErrorHandling(code, fileRel);
|
|
2193
|
+
|
|
2194
|
+
// Only include BLOCK and WARN severity
|
|
2195
|
+
for (const finding of engineFindings) {
|
|
2196
|
+
if (finding.severity === "INFO") continue;
|
|
2197
|
+
|
|
2198
|
+
findings.push({
|
|
2199
|
+
id: stableId("F_ERROR", `${fileRel}:${finding.type}:${finding.line}`),
|
|
2200
|
+
severity: finding.severity,
|
|
2201
|
+
category: finding.category || "ErrorHandling",
|
|
2202
|
+
title: finding.title,
|
|
2203
|
+
message: finding.message,
|
|
2204
|
+
file: finding.file,
|
|
2205
|
+
line: finding.line,
|
|
2206
|
+
why: "Poor error handling leads to silent failures, security issues, and hard-to-debug problems.",
|
|
2207
|
+
confidence: finding.confidence,
|
|
2208
|
+
evidence: [{ file: fileRel, reason: finding.title, line: finding.line }],
|
|
2209
|
+
fixHints: [finding.fixHint].filter(Boolean),
|
|
2210
|
+
});
|
|
2211
|
+
}
|
|
2212
|
+
} catch (err) {
|
|
2213
|
+
continue;
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2217
|
+
return findings;
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
/* ============================================================================
|
|
2221
|
+
* DATABASE PATTERNS ANALYZER
|
|
2222
|
+
* Only runs when ORM usage is detected (Prisma, Drizzle, etc.)
|
|
2223
|
+
* ========================================================================== */
|
|
2224
|
+
|
|
2225
|
+
function findDatabasePatternIssues(repoRoot) {
|
|
2226
|
+
const { analyzeDatabasePatterns, detectORM } = require("./engines/database-patterns-engine");
|
|
2227
|
+
const findings = [];
|
|
2228
|
+
|
|
2229
|
+
// Quick check: only run if an ORM is likely in use
|
|
2230
|
+
const packageJsonPath = path.join(repoRoot, "package.json");
|
|
2231
|
+
let hasORM = false;
|
|
2232
|
+
|
|
2233
|
+
try {
|
|
2234
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
2235
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
2236
|
+
const ormPackages = ["@prisma/client", "drizzle-orm", "typeorm", "sequelize", "mongoose", "knex"];
|
|
2237
|
+
hasORM = ormPackages.some(pkg => deps[pkg]);
|
|
2238
|
+
} catch (err) {
|
|
2239
|
+
// No package.json or can't read - check files for ORM patterns
|
|
2240
|
+
hasORM = true; // Fall back to checking files
|
|
2241
|
+
}
|
|
2242
|
+
|
|
2243
|
+
if (!hasORM) return findings;
|
|
2244
|
+
|
|
2245
|
+
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
2246
|
+
cwd: repoRoot,
|
|
2247
|
+
absolute: true,
|
|
2248
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
2249
|
+
});
|
|
2250
|
+
|
|
2251
|
+
for (const fileAbs of files) {
|
|
2252
|
+
try {
|
|
2253
|
+
const code = readFileCached(fileAbs);
|
|
2254
|
+
const fileRel = path.relative(repoRoot, fileAbs).replace(/\\/g, "/");
|
|
2255
|
+
|
|
2256
|
+
// Skip files without ORM imports for performance
|
|
2257
|
+
const orm = detectORM(code);
|
|
2258
|
+
if (!orm) continue;
|
|
2259
|
+
|
|
2260
|
+
const engineFindings = analyzeDatabasePatterns(code, fileRel);
|
|
2261
|
+
|
|
2262
|
+
// Only include BLOCK and WARN severity
|
|
2263
|
+
for (const finding of engineFindings) {
|
|
2264
|
+
if (finding.severity === "INFO") continue;
|
|
2265
|
+
|
|
2266
|
+
findings.push({
|
|
2267
|
+
id: stableId("F_DB", `${fileRel}:${finding.type}:${finding.line}`),
|
|
2268
|
+
severity: finding.severity,
|
|
2269
|
+
category: finding.category || "DatabasePatterns",
|
|
2270
|
+
title: finding.title,
|
|
2271
|
+
message: finding.message,
|
|
2272
|
+
file: finding.file,
|
|
2273
|
+
line: finding.line,
|
|
2274
|
+
why: "Database anti-patterns cause performance issues, data integrity problems, and security vulnerabilities.",
|
|
2275
|
+
confidence: finding.confidence,
|
|
2276
|
+
evidence: [{ file: fileRel, reason: finding.title, line: finding.line }],
|
|
2277
|
+
fixHints: [finding.fixHint].filter(Boolean),
|
|
2278
|
+
});
|
|
2279
|
+
}
|
|
2280
|
+
} catch (err) {
|
|
2281
|
+
continue;
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
|
|
2285
|
+
return findings;
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
/* ============================================================================
|
|
2289
|
+
* ASYNC PATTERNS ANALYZER
|
|
2290
|
+
* Detects Promise and async/await anti-patterns
|
|
2291
|
+
* ========================================================================== */
|
|
2292
|
+
|
|
2293
|
+
function findAsyncPatternIssues(repoRoot) {
|
|
2294
|
+
const engines = require("./engines/vibecheck-engines");
|
|
2295
|
+
if (!engines.analyzeAsyncPatterns) return [];
|
|
2296
|
+
|
|
2297
|
+
const findings = [];
|
|
2298
|
+
const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
|
|
2299
|
+
cwd: repoRoot,
|
|
2300
|
+
absolute: true,
|
|
2301
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
2302
|
+
});
|
|
2303
|
+
|
|
2304
|
+
for (const fileAbs of files) {
|
|
2305
|
+
try {
|
|
2306
|
+
const code = readFileCached(fileAbs);
|
|
2307
|
+
const fileRel = path.relative(repoRoot, fileAbs).replace(/\\/g, "/");
|
|
2308
|
+
|
|
2309
|
+
const engineFindings = engines.analyzeAsyncPatterns(code, fileRel);
|
|
2310
|
+
|
|
2311
|
+
// Only include BLOCK and WARN severity
|
|
2312
|
+
for (const finding of engineFindings) {
|
|
2313
|
+
if (finding.severity === "INFO") continue;
|
|
2314
|
+
|
|
2315
|
+
findings.push({
|
|
2316
|
+
id: stableId("F_ASYNC", `${fileRel}:${finding.type}:${finding.line}`),
|
|
2317
|
+
severity: finding.severity,
|
|
2318
|
+
category: finding.category || "AsyncPatterns",
|
|
2319
|
+
title: finding.title,
|
|
2320
|
+
message: finding.message,
|
|
2321
|
+
file: finding.file,
|
|
2322
|
+
line: finding.line,
|
|
2323
|
+
why: "Async anti-patterns cause race conditions, memory leaks, and hard-to-debug failures.",
|
|
2324
|
+
confidence: finding.confidence,
|
|
2325
|
+
evidence: [{ file: fileRel, reason: finding.title, line: finding.line }],
|
|
2326
|
+
fixHints: [finding.fixHint].filter(Boolean),
|
|
2327
|
+
});
|
|
2328
|
+
}
|
|
2329
|
+
} catch (err) {
|
|
2330
|
+
continue;
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
return findings;
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
/* ============================================================================
|
|
2338
|
+
* BUNDLE SIZE ANALYZER
|
|
2339
|
+
* Only runs on client-side code to detect heavy imports
|
|
2340
|
+
* ========================================================================== */
|
|
2341
|
+
|
|
2342
|
+
function findBundleSizeIssues(repoRoot) {
|
|
2343
|
+
const engines = require("./engines/vibecheck-engines");
|
|
2344
|
+
if (!engines.bundleSizeEngine?.analyzeBundleSize) return [];
|
|
2345
|
+
|
|
2346
|
+
const findings = [];
|
|
2347
|
+
|
|
2348
|
+
// Focus on likely client-side code paths
|
|
2349
|
+
const files = fg.sync([
|
|
2350
|
+
"**/app/**/*.{ts,tsx,js,jsx}",
|
|
2351
|
+
"**/pages/**/*.{ts,tsx,js,jsx}",
|
|
2352
|
+
"**/src/**/*.{ts,tsx,js,jsx}",
|
|
2353
|
+
"**/components/**/*.{ts,tsx,js,jsx}",
|
|
2354
|
+
], {
|
|
2355
|
+
cwd: repoRoot,
|
|
2356
|
+
absolute: true,
|
|
2357
|
+
ignore: [
|
|
2358
|
+
...STANDARD_IGNORE_PATTERNS,
|
|
2359
|
+
"**/api/**", // Skip API routes (server-side)
|
|
2360
|
+
"**/server/**",
|
|
2361
|
+
"**/lib/server/**",
|
|
2362
|
+
],
|
|
2363
|
+
});
|
|
2364
|
+
|
|
2365
|
+
for (const fileAbs of files) {
|
|
2366
|
+
try {
|
|
2367
|
+
const code = readFileCached(fileAbs);
|
|
2368
|
+
const fileRel = path.relative(repoRoot, fileAbs).replace(/\\/g, "/");
|
|
2369
|
+
|
|
2370
|
+
const engineFindings = engines.bundleSizeEngine.analyzeBundleSize(code, fileRel);
|
|
2371
|
+
|
|
2372
|
+
// Only include BLOCK and WARN severity
|
|
2373
|
+
for (const finding of engineFindings) {
|
|
2374
|
+
if (finding.severity === "INFO") continue;
|
|
2375
|
+
|
|
2376
|
+
findings.push({
|
|
2377
|
+
id: stableId("F_BUNDLE", `${fileRel}:${finding.type}:${finding.line}`),
|
|
2378
|
+
severity: finding.severity,
|
|
2379
|
+
category: finding.category || "BundleSize",
|
|
2380
|
+
title: finding.title,
|
|
2381
|
+
message: finding.message,
|
|
2382
|
+
file: finding.file,
|
|
2383
|
+
line: finding.line,
|
|
2384
|
+
why: "Large bundles slow down page load and hurt user experience.",
|
|
2385
|
+
confidence: finding.confidence,
|
|
2386
|
+
evidence: [{ file: fileRel, reason: finding.title, line: finding.line }],
|
|
2387
|
+
fixHints: [finding.fixHint].filter(Boolean),
|
|
2388
|
+
});
|
|
2389
|
+
}
|
|
2390
|
+
} catch (err) {
|
|
2391
|
+
continue;
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
|
|
2395
|
+
return findings;
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2398
|
+
/* ============================================================================
|
|
2399
|
+
* V6: BULLETPROOF FINDINGS FILTER
|
|
2400
|
+
* Applies noise reduction and false positive prevention to any findings array
|
|
2401
|
+
* ========================================================================== */
|
|
2402
|
+
|
|
2403
|
+
/**
|
|
2404
|
+
* Apply bulletproof filtering to findings
|
|
2405
|
+
* @param {Array} findings - Raw findings from analyzers
|
|
2406
|
+
* @param {Object} options - Configuration options
|
|
2407
|
+
* @returns {Object} { findings, stats }
|
|
2408
|
+
*/
|
|
2409
|
+
function bulletproofFindings(findings, options = {}) {
|
|
2410
|
+
const {
|
|
2411
|
+
projectPath = ".",
|
|
2412
|
+
projectStats = {},
|
|
2413
|
+
config = {},
|
|
2414
|
+
minConfidence = 0.4,
|
|
2415
|
+
minQualityScore = 0.35,
|
|
2416
|
+
verbose = false,
|
|
2417
|
+
} = options;
|
|
2418
|
+
|
|
2419
|
+
let processed = [...findings];
|
|
2420
|
+
const stats = {
|
|
2421
|
+
input: findings.length,
|
|
2422
|
+
afterFalsePositiveFilter: 0,
|
|
2423
|
+
afterNoiseReduction: 0,
|
|
2424
|
+
output: 0,
|
|
2425
|
+
};
|
|
2426
|
+
|
|
2427
|
+
// Step 1: Filter false positives
|
|
2428
|
+
if (falsePositivePrevention?.filterFalsePositives) {
|
|
2429
|
+
const fpResult = falsePositivePrevention.filterFalsePositives(processed, {
|
|
2430
|
+
projectPath,
|
|
2431
|
+
minConfidence,
|
|
2432
|
+
});
|
|
2433
|
+
processed = fpResult.findings;
|
|
2434
|
+
stats.afterFalsePositiveFilter = processed.length;
|
|
2435
|
+
|
|
2436
|
+
if (verbose && fpResult.removed.length > 0) {
|
|
2437
|
+
console.log(` [FP Filter] Removed ${fpResult.removed.length} false positives`);
|
|
2438
|
+
}
|
|
2439
|
+
} else {
|
|
2440
|
+
stats.afterFalsePositiveFilter = processed.length;
|
|
2441
|
+
}
|
|
2442
|
+
|
|
2443
|
+
// Step 2: Apply noise reduction
|
|
2444
|
+
if (noiseReduction?.reduceNoise) {
|
|
2445
|
+
const nrResult = noiseReduction.reduceNoise(processed, {
|
|
2446
|
+
projectStats,
|
|
2447
|
+
config,
|
|
2448
|
+
minQualityScore,
|
|
2449
|
+
verbose,
|
|
2450
|
+
});
|
|
2451
|
+
processed = nrResult.findings;
|
|
2452
|
+
stats.afterNoiseReduction = processed.length;
|
|
2453
|
+
stats.noiseStats = nrResult.stats;
|
|
2454
|
+
} else {
|
|
2455
|
+
stats.afterNoiseReduction = processed.length;
|
|
2456
|
+
}
|
|
2457
|
+
|
|
2458
|
+
stats.output = processed.length;
|
|
2459
|
+
stats.reduction = Math.round((1 - stats.output / Math.max(stats.input, 1)) * 100);
|
|
2460
|
+
|
|
2461
|
+
return { findings: processed, stats };
|
|
2462
|
+
}
|
|
2463
|
+
|
|
2464
|
+
/**
|
|
2465
|
+
* Get project statistics for adaptive caps
|
|
2466
|
+
*/
|
|
2467
|
+
function getProjectStats(projectPath) {
|
|
2468
|
+
let fileCount = 0;
|
|
2469
|
+
let lineCount = 0;
|
|
2470
|
+
|
|
2471
|
+
try {
|
|
2472
|
+
const files = fg.sync(["**/*.{ts,tsx,js,jsx,mjs,cjs}"], {
|
|
2473
|
+
cwd: projectPath,
|
|
2474
|
+
absolute: true,
|
|
2475
|
+
ignore: STANDARD_IGNORE_PATTERNS,
|
|
2476
|
+
});
|
|
2477
|
+
|
|
2478
|
+
fileCount = files.length;
|
|
2479
|
+
|
|
2480
|
+
// Sample line count from up to 100 files for performance
|
|
2481
|
+
const sampleFiles = files.slice(0, 100);
|
|
2482
|
+
let sampleLines = 0;
|
|
2483
|
+
for (const file of sampleFiles) {
|
|
2484
|
+
try {
|
|
2485
|
+
const content = fs.readFileSync(file, "utf8");
|
|
2486
|
+
sampleLines += content.split("\n").length;
|
|
2487
|
+
} catch {
|
|
2488
|
+
// Ignore errors
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2492
|
+
// Extrapolate line count
|
|
2493
|
+
if (sampleFiles.length > 0) {
|
|
2494
|
+
lineCount = Math.round((sampleLines / sampleFiles.length) * fileCount);
|
|
2495
|
+
}
|
|
2496
|
+
} catch {
|
|
2497
|
+
// Ignore errors
|
|
2498
|
+
}
|
|
2499
|
+
|
|
2500
|
+
return { fileCount, lineCount };
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2061
2503
|
module.exports = {
|
|
2504
|
+
// V6: Bulletproof filtering (apply to any findings array)
|
|
2505
|
+
bulletproofFindings,
|
|
2506
|
+
getProjectStats,
|
|
2507
|
+
|
|
2062
2508
|
// V3: Cache management - call after scan completes to prevent memory leaks
|
|
2063
2509
|
clearFileCache,
|
|
2064
2510
|
|
|
2065
2511
|
// V3: Entropy helper - exported for testing/reuse
|
|
2066
2512
|
getShannonEntropy,
|
|
2067
2513
|
|
|
2068
|
-
//
|
|
2514
|
+
// Core analyzers (route integrity, env, auth)
|
|
2069
2515
|
findMissingRoutes,
|
|
2070
2516
|
findEnvGaps,
|
|
2071
2517
|
findFakeSuccess,
|
|
@@ -2073,6 +2519,8 @@ module.exports = {
|
|
|
2073
2519
|
findStripeWebhookViolations,
|
|
2074
2520
|
findPaidSurfaceNotEnforced,
|
|
2075
2521
|
findOwnerModeBypass,
|
|
2522
|
+
|
|
2523
|
+
// Code quality analyzers (mock, TODO, console, etc.)
|
|
2076
2524
|
findMockData,
|
|
2077
2525
|
findTodoFixme,
|
|
2078
2526
|
findConsoleLogs,
|
|
@@ -2081,13 +2529,22 @@ module.exports = {
|
|
|
2081
2529
|
findDeprecatedApis,
|
|
2082
2530
|
findEmptyCatch,
|
|
2083
2531
|
findUnsafeRegex,
|
|
2084
|
-
|
|
2532
|
+
|
|
2533
|
+
// Enhanced analyzers (security, performance, quality)
|
|
2085
2534
|
findSecurityVulnerabilities,
|
|
2086
2535
|
findPerformanceIssues,
|
|
2087
2536
|
findCodeQualityIssues,
|
|
2537
|
+
|
|
2088
2538
|
// Advanced analyzers
|
|
2089
2539
|
findCrossFileIssues,
|
|
2090
2540
|
findTypeSafetyIssues,
|
|
2091
2541
|
findAccessibilityIssues,
|
|
2092
2542
|
findAPIConsistencyIssues,
|
|
2543
|
+
|
|
2544
|
+
// V5: New pattern analyzers (integrated, not separate commands)
|
|
2545
|
+
findReactPatternIssues, // React best practices (BLOCK/WARN only)
|
|
2546
|
+
findErrorHandlingIssues, // Error handling patterns
|
|
2547
|
+
findDatabasePatternIssues, // N+1, transactions, raw queries
|
|
2548
|
+
findAsyncPatternIssues, // Promise/async anti-patterns
|
|
2549
|
+
findBundleSizeIssues, // Heavy imports, bundle bloat
|
|
2093
2550
|
};
|