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