@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,452 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Noise Reduction Engine - Bulletproof Signal-to-Noise Ratio
|
|
3
|
-
*
|
|
4
|
-
* This engine ensures vibecheck findings are high-signal and actionable.
|
|
5
|
-
* It addresses alert fatigue through:
|
|
6
|
-
*
|
|
7
|
-
* 1. ADAPTIVE CAPS - Project size determines finding limits
|
|
8
|
-
* 2. QUALITY SCORING - Each finding gets a signal quality score
|
|
9
|
-
* 3. SMART DEDUPLICATION - Similar findings are grouped
|
|
10
|
-
* 4. PRIORITY RANKING - Critical path findings surface first
|
|
11
|
-
* 5. CONFIGURABLE THRESHOLDS - Per-rule severity/confidence tuning
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
"use strict";
|
|
15
|
-
|
|
16
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
17
|
-
// ADAPTIVE FINDING CAPS
|
|
18
|
-
// Based on project size to prevent overwhelming large codebases
|
|
19
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
20
|
-
|
|
21
|
-
const PROJECT_SIZE_THRESHOLDS = {
|
|
22
|
-
tiny: { files: 50, lines: 5000 }, // Small scripts, MVPs
|
|
23
|
-
small: { files: 200, lines: 20000 }, // Side projects
|
|
24
|
-
medium: { files: 500, lines: 50000 }, // Standard apps
|
|
25
|
-
large: { files: 1500, lines: 150000 }, // Production apps
|
|
26
|
-
huge: { files: 5000, lines: 500000 }, // Enterprise/monorepos
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const ADAPTIVE_CAPS = {
|
|
30
|
-
tiny: { blockers: 5, warnings: 10, info: 5, total: 20 },
|
|
31
|
-
small: { blockers: 10, warnings: 20, info: 10, total: 40 },
|
|
32
|
-
medium: { blockers: 15, warnings: 35, info: 15, total: 65 },
|
|
33
|
-
large: { blockers: 25, warnings: 50, info: 25, total: 100 },
|
|
34
|
-
huge: { blockers: 40, warnings: 80, info: 40, total: 160 },
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
function detectProjectSize(stats) {
|
|
38
|
-
const { fileCount = 0, lineCount = 0 } = stats;
|
|
39
|
-
|
|
40
|
-
if (fileCount <= PROJECT_SIZE_THRESHOLDS.tiny.files && lineCount <= PROJECT_SIZE_THRESHOLDS.tiny.lines) return 'tiny';
|
|
41
|
-
if (fileCount <= PROJECT_SIZE_THRESHOLDS.small.files && lineCount <= PROJECT_SIZE_THRESHOLDS.small.lines) return 'small';
|
|
42
|
-
if (fileCount <= PROJECT_SIZE_THRESHOLDS.medium.files && lineCount <= PROJECT_SIZE_THRESHOLDS.medium.lines) return 'medium';
|
|
43
|
-
if (fileCount <= PROJECT_SIZE_THRESHOLDS.large.files && lineCount <= PROJECT_SIZE_THRESHOLDS.large.lines) return 'large';
|
|
44
|
-
return 'huge';
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function getAdaptiveCaps(projectStats) {
|
|
48
|
-
const size = detectProjectSize(projectStats);
|
|
49
|
-
return { size, caps: ADAPTIVE_CAPS[size] };
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
53
|
-
// FINDING QUALITY SCORING
|
|
54
|
-
// Determines how "actionable" a finding is (0.0 - 1.0)
|
|
55
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
56
|
-
|
|
57
|
-
const QUALITY_FACTORS = {
|
|
58
|
-
// Positive factors (increase quality)
|
|
59
|
-
hasEvidence: 0.15, // Finding includes evidence
|
|
60
|
-
hasFixHint: 0.10, // Finding includes fix suggestion
|
|
61
|
-
astVerified: 0.20, // Verified via AST, not just regex
|
|
62
|
-
highConfidence: 0.15, // Confidence >= 0.8
|
|
63
|
-
criticalPath: 0.15, // In critical code path (routes, auth, payments)
|
|
64
|
-
multipleOccurrences: 0.05, // Pattern appears multiple times
|
|
65
|
-
recentlyIntroduced: 0.10, // New in recent commit (if git info available)
|
|
66
|
-
|
|
67
|
-
// Negative factors (decrease quality)
|
|
68
|
-
inTestFile: -0.30, // In test file
|
|
69
|
-
inConfigFile: -0.15, // In config file
|
|
70
|
-
inGeneratedCode: -0.40, // In generated/vendored code
|
|
71
|
-
lowConfidence: -0.20, // Confidence < 0.5
|
|
72
|
-
commonFalsePositive: -0.25, // Known false positive pattern
|
|
73
|
-
inComment: -0.30, // In a comment
|
|
74
|
-
inString: -0.15, // In a string literal
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// Critical path patterns - findings here are more important
|
|
78
|
-
const CRITICAL_PATH_PATTERNS = [
|
|
79
|
-
/\/(api|routes|pages|app)\//i,
|
|
80
|
-
/\/(auth|login|logout|session|oauth)\//i,
|
|
81
|
-
/\/(payment|billing|checkout|stripe|subscription)\//i,
|
|
82
|
-
/\/(admin|dashboard|settings)\//i,
|
|
83
|
-
/middleware\.(ts|js)$/i,
|
|
84
|
-
/route\.(ts|js)$/i,
|
|
85
|
-
/\[(.*?)\]\.(ts|js|tsx|jsx)$/i, // Dynamic routes
|
|
86
|
-
];
|
|
87
|
-
|
|
88
|
-
// Known false positive patterns to penalize
|
|
89
|
-
const KNOWN_FALSE_POSITIVE_PATTERNS = [
|
|
90
|
-
// Tailwind placeholder classes
|
|
91
|
-
/placeholder:[a-zA-Z-]+/,
|
|
92
|
-
// Environment variable checks
|
|
93
|
-
/process\.env\.\w+\s*===?\s*['"]true['"]/,
|
|
94
|
-
// Test data in test utilities
|
|
95
|
-
/createMock|mockData|testData|fixtureData/i,
|
|
96
|
-
// Documentation examples
|
|
97
|
-
/example\.com|localhost:3000|127\.0\.0\.1/,
|
|
98
|
-
];
|
|
99
|
-
|
|
100
|
-
function calculateQualityScore(finding, context = {}) {
|
|
101
|
-
let score = 0.5; // Base score
|
|
102
|
-
|
|
103
|
-
// Positive factors
|
|
104
|
-
if (finding.evidence?.length > 0) score += QUALITY_FACTORS.hasEvidence;
|
|
105
|
-
if (finding.fixHint || finding.fixHints?.length > 0) score += QUALITY_FACTORS.hasFixHint;
|
|
106
|
-
if (finding.astVerified || finding.verificationMethod === 'ast') score += QUALITY_FACTORS.astVerified;
|
|
107
|
-
if ((finding.confidence || finding.confidenceScore || 0) >= 0.8) score += QUALITY_FACTORS.highConfidence;
|
|
108
|
-
if (finding.occurrenceCount > 1) score += QUALITY_FACTORS.multipleOccurrences;
|
|
109
|
-
if (context.recentCommit) score += QUALITY_FACTORS.recentlyIntroduced;
|
|
110
|
-
|
|
111
|
-
// Check critical path
|
|
112
|
-
const filePath = finding.file || finding.filePath || '';
|
|
113
|
-
if (CRITICAL_PATH_PATTERNS.some(p => p.test(filePath))) {
|
|
114
|
-
score += QUALITY_FACTORS.criticalPath;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Negative factors
|
|
118
|
-
if (context.isTestFile || /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filePath)) {
|
|
119
|
-
score += QUALITY_FACTORS.inTestFile;
|
|
120
|
-
}
|
|
121
|
-
if (context.isConfigFile || /\.config\.(ts|js|mjs|cjs)$/.test(filePath)) {
|
|
122
|
-
score += QUALITY_FACTORS.inConfigFile;
|
|
123
|
-
}
|
|
124
|
-
if (context.isGeneratedCode || /\/(generated|__generated__|codegen)\//i.test(filePath)) {
|
|
125
|
-
score += QUALITY_FACTORS.inGeneratedCode;
|
|
126
|
-
}
|
|
127
|
-
if ((finding.confidence || finding.confidenceScore || 0.5) < 0.5) {
|
|
128
|
-
score += QUALITY_FACTORS.lowConfidence;
|
|
129
|
-
}
|
|
130
|
-
if (finding.inComment) score += QUALITY_FACTORS.inComment;
|
|
131
|
-
if (finding.inString) score += QUALITY_FACTORS.inString;
|
|
132
|
-
|
|
133
|
-
// Check for known false positive patterns
|
|
134
|
-
const message = finding.message || finding.title || '';
|
|
135
|
-
const code = finding.codeSnippet || finding.evidence?.[0]?.snippet || '';
|
|
136
|
-
if (KNOWN_FALSE_POSITIVE_PATTERNS.some(p => p.test(message) || p.test(code))) {
|
|
137
|
-
score += QUALITY_FACTORS.commonFalsePositive;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Clamp to 0.0 - 1.0
|
|
141
|
-
return Math.max(0, Math.min(1, score));
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
145
|
-
// SMART DEDUPLICATION
|
|
146
|
-
// Groups similar findings to reduce noise
|
|
147
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
148
|
-
|
|
149
|
-
function normalizeMessage(message) {
|
|
150
|
-
return (message || '')
|
|
151
|
-
.toLowerCase()
|
|
152
|
-
.replace(/[`'"]/g, '')
|
|
153
|
-
.replace(/\s+/g, ' ')
|
|
154
|
-
.replace(/line \d+/gi, 'line N')
|
|
155
|
-
.replace(/\d+/g, 'N')
|
|
156
|
-
.trim();
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function generateDedupeKey(finding) {
|
|
160
|
-
const file = (finding.file || finding.filePath || '').replace(/\\/g, '/');
|
|
161
|
-
const type = finding.type || finding.category || 'unknown';
|
|
162
|
-
const line = finding.line || 0;
|
|
163
|
-
|
|
164
|
-
return `${type}:${file}:${line}`;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function generateSimilarityKey(finding) {
|
|
168
|
-
const type = finding.type || finding.category || 'unknown';
|
|
169
|
-
const normalizedMsg = normalizeMessage(finding.message || finding.title);
|
|
170
|
-
|
|
171
|
-
// Group by type + similar message
|
|
172
|
-
return `${type}:${normalizedMsg.slice(0, 50)}`;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function deduplicateFindings(findings, options = {}) {
|
|
176
|
-
const { groupSimilar = true, keepHighestQuality = true } = options;
|
|
177
|
-
|
|
178
|
-
// Exact deduplication
|
|
179
|
-
const exactDedupeMap = new Map();
|
|
180
|
-
|
|
181
|
-
for (const finding of findings) {
|
|
182
|
-
const key = generateDedupeKey(finding);
|
|
183
|
-
|
|
184
|
-
if (exactDedupeMap.has(key)) {
|
|
185
|
-
const existing = exactDedupeMap.get(key);
|
|
186
|
-
// Keep highest quality/confidence
|
|
187
|
-
if (keepHighestQuality) {
|
|
188
|
-
const existingScore = existing.qualityScore || calculateQualityScore(existing);
|
|
189
|
-
const newScore = finding.qualityScore || calculateQualityScore(finding);
|
|
190
|
-
if (newScore > existingScore) {
|
|
191
|
-
finding.occurrenceCount = (existing.occurrenceCount || 1) + 1;
|
|
192
|
-
exactDedupeMap.set(key, finding);
|
|
193
|
-
} else {
|
|
194
|
-
existing.occurrenceCount = (existing.occurrenceCount || 1) + 1;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
} else {
|
|
198
|
-
exactDedupeMap.set(key, { ...finding, occurrenceCount: finding.occurrenceCount || 1 });
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
let dedupedFindings = Array.from(exactDedupeMap.values());
|
|
203
|
-
|
|
204
|
-
// Group similar findings
|
|
205
|
-
if (groupSimilar) {
|
|
206
|
-
const similarityMap = new Map();
|
|
207
|
-
|
|
208
|
-
for (const finding of dedupedFindings) {
|
|
209
|
-
const key = generateSimilarityKey(finding);
|
|
210
|
-
|
|
211
|
-
if (!similarityMap.has(key)) {
|
|
212
|
-
similarityMap.set(key, { primary: finding, similar: [] });
|
|
213
|
-
} else {
|
|
214
|
-
similarityMap.get(key).similar.push(finding);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// For groups with many similar findings, show count instead of all
|
|
219
|
-
dedupedFindings = [];
|
|
220
|
-
for (const [, group] of similarityMap) {
|
|
221
|
-
if (group.similar.length >= 3) {
|
|
222
|
-
// Collapse into single finding with count
|
|
223
|
-
group.primary.similarCount = group.similar.length;
|
|
224
|
-
group.primary.collapsedFiles = group.similar.map(f => f.file || f.filePath).filter(Boolean);
|
|
225
|
-
dedupedFindings.push(group.primary);
|
|
226
|
-
} else {
|
|
227
|
-
dedupedFindings.push(group.primary, ...group.similar);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return dedupedFindings;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
236
|
-
// PRIORITY RANKING
|
|
237
|
-
// Sort findings by importance
|
|
238
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
239
|
-
|
|
240
|
-
const SEVERITY_ORDER = {
|
|
241
|
-
'BLOCK': 0, 'block': 0, 'critical': 0, 'error': 0,
|
|
242
|
-
'WARN': 1, 'warn': 1, 'warning': 1, 'high': 1, 'medium': 1,
|
|
243
|
-
'INFO': 2, 'info': 2, 'low': 2, 'hint': 2,
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
function rankFindings(findings) {
|
|
247
|
-
return findings.sort((a, b) => {
|
|
248
|
-
// 1. Severity (BLOCK > WARN > INFO)
|
|
249
|
-
const sevA = SEVERITY_ORDER[a.severity] ?? 3;
|
|
250
|
-
const sevB = SEVERITY_ORDER[b.severity] ?? 3;
|
|
251
|
-
if (sevA !== sevB) return sevA - sevB;
|
|
252
|
-
|
|
253
|
-
// 2. Quality score (higher is better)
|
|
254
|
-
const qualA = a.qualityScore || calculateQualityScore(a);
|
|
255
|
-
const qualB = b.qualityScore || calculateQualityScore(b);
|
|
256
|
-
if (Math.abs(qualA - qualB) > 0.1) return qualB - qualA;
|
|
257
|
-
|
|
258
|
-
// 3. Confidence (higher is better)
|
|
259
|
-
const confA = a.confidence || a.confidenceScore || 0.5;
|
|
260
|
-
const confB = b.confidence || b.confidenceScore || 0.5;
|
|
261
|
-
if (Math.abs(confA - confB) > 0.1) return confB - confA;
|
|
262
|
-
|
|
263
|
-
// 4. Critical path first
|
|
264
|
-
const fileA = a.file || a.filePath || '';
|
|
265
|
-
const fileB = b.file || b.filePath || '';
|
|
266
|
-
const critA = CRITICAL_PATH_PATTERNS.some(p => p.test(fileA)) ? 0 : 1;
|
|
267
|
-
const critB = CRITICAL_PATH_PATTERNS.some(p => p.test(fileB)) ? 0 : 1;
|
|
268
|
-
if (critA !== critB) return critA - critB;
|
|
269
|
-
|
|
270
|
-
// 5. File path (alphabetical for stability)
|
|
271
|
-
return fileA.localeCompare(fileB);
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
276
|
-
// CONFIGURABLE THRESHOLDS
|
|
277
|
-
// Per-rule severity and confidence tuning
|
|
278
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
279
|
-
|
|
280
|
-
const DEFAULT_RULE_CONFIG = {
|
|
281
|
-
minConfidence: 0.5, // Minimum confidence to report
|
|
282
|
-
maxPerFile: 5, // Maximum findings per file per rule
|
|
283
|
-
maxTotal: 50, // Maximum total findings for this rule
|
|
284
|
-
severity: null, // Override severity (null = use engine default)
|
|
285
|
-
enabled: true, // Enable/disable rule
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
function loadRuleConfig(config, ruleName) {
|
|
289
|
-
const rules = config?.rules || {};
|
|
290
|
-
const ruleConfig = rules[ruleName] || {};
|
|
291
|
-
|
|
292
|
-
return {
|
|
293
|
-
...DEFAULT_RULE_CONFIG,
|
|
294
|
-
...ruleConfig,
|
|
295
|
-
// Handle legacy config formats
|
|
296
|
-
minConfidence: ruleConfig.minConfidence ?? ruleConfig.confidence ?? DEFAULT_RULE_CONFIG.minConfidence,
|
|
297
|
-
enabled: ruleConfig.enabled !== false,
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
function applyRuleConfig(findings, config) {
|
|
302
|
-
const ruleGroups = new Map();
|
|
303
|
-
|
|
304
|
-
// Group by rule
|
|
305
|
-
for (const finding of findings) {
|
|
306
|
-
const rule = finding.type || finding.category || finding.ruleId || 'unknown';
|
|
307
|
-
if (!ruleGroups.has(rule)) ruleGroups.set(rule, []);
|
|
308
|
-
ruleGroups.get(rule).push(finding);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
const filtered = [];
|
|
312
|
-
|
|
313
|
-
for (const [rule, ruleFindings] of ruleGroups) {
|
|
314
|
-
const ruleConfig = loadRuleConfig(config, rule);
|
|
315
|
-
|
|
316
|
-
// Skip disabled rules
|
|
317
|
-
if (!ruleConfig.enabled) continue;
|
|
318
|
-
|
|
319
|
-
// Filter by confidence
|
|
320
|
-
let applicable = ruleFindings.filter(f => {
|
|
321
|
-
const conf = f.confidence || f.confidenceScore || 0.5;
|
|
322
|
-
return conf >= ruleConfig.minConfidence;
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
// Override severity if configured
|
|
326
|
-
if (ruleConfig.severity) {
|
|
327
|
-
applicable = applicable.map(f => ({ ...f, severity: ruleConfig.severity }));
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// Apply per-file limit
|
|
331
|
-
if (ruleConfig.maxPerFile) {
|
|
332
|
-
const byFile = new Map();
|
|
333
|
-
applicable = applicable.filter(f => {
|
|
334
|
-
const file = f.file || f.filePath || '';
|
|
335
|
-
const count = byFile.get(file) || 0;
|
|
336
|
-
if (count >= ruleConfig.maxPerFile) return false;
|
|
337
|
-
byFile.set(file, count + 1);
|
|
338
|
-
return true;
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Apply total limit
|
|
343
|
-
if (ruleConfig.maxTotal && applicable.length > ruleConfig.maxTotal) {
|
|
344
|
-
applicable = applicable.slice(0, ruleConfig.maxTotal);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
filtered.push(...applicable);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
return filtered;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
354
|
-
// MAIN NOISE REDUCTION PIPELINE
|
|
355
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
356
|
-
|
|
357
|
-
function reduceNoise(findings, options = {}) {
|
|
358
|
-
const {
|
|
359
|
-
projectStats = {}, // { fileCount, lineCount }
|
|
360
|
-
config = {}, // .vibecheckrc content
|
|
361
|
-
minQualityScore = 0.3, // Minimum quality to include
|
|
362
|
-
verbose = false,
|
|
363
|
-
} = options;
|
|
364
|
-
|
|
365
|
-
const startCount = findings.length;
|
|
366
|
-
|
|
367
|
-
// Step 1: Calculate quality scores
|
|
368
|
-
let processed = findings.map(f => ({
|
|
369
|
-
...f,
|
|
370
|
-
qualityScore: calculateQualityScore(f, options.context || {}),
|
|
371
|
-
}));
|
|
372
|
-
|
|
373
|
-
// Step 2: Apply rule-specific config
|
|
374
|
-
processed = applyRuleConfig(processed, config);
|
|
375
|
-
|
|
376
|
-
// Step 3: Filter by quality score
|
|
377
|
-
processed = processed.filter(f => f.qualityScore >= minQualityScore);
|
|
378
|
-
|
|
379
|
-
// Step 4: Deduplicate
|
|
380
|
-
processed = deduplicateFindings(processed, {
|
|
381
|
-
groupSimilar: options.groupSimilar !== false,
|
|
382
|
-
keepHighestQuality: true,
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
// Step 5: Rank by priority
|
|
386
|
-
processed = rankFindings(processed);
|
|
387
|
-
|
|
388
|
-
// Step 6: Apply adaptive caps
|
|
389
|
-
const { size, caps } = getAdaptiveCaps(projectStats);
|
|
390
|
-
|
|
391
|
-
const blockers = processed.filter(f => ['BLOCK', 'block', 'critical', 'error'].includes(f.severity));
|
|
392
|
-
const warnings = processed.filter(f => ['WARN', 'warn', 'warning', 'high', 'medium'].includes(f.severity));
|
|
393
|
-
const info = processed.filter(f => ['INFO', 'info', 'low', 'hint'].includes(f.severity));
|
|
394
|
-
|
|
395
|
-
const cappedBlockers = blockers.slice(0, caps.blockers);
|
|
396
|
-
const cappedWarnings = warnings.slice(0, caps.warnings);
|
|
397
|
-
const cappedInfo = info.slice(0, caps.info);
|
|
398
|
-
|
|
399
|
-
const capped = [...cappedBlockers, ...cappedWarnings, ...cappedInfo].slice(0, caps.total);
|
|
400
|
-
|
|
401
|
-
// Generate reduction stats
|
|
402
|
-
const stats = {
|
|
403
|
-
input: startCount,
|
|
404
|
-
output: capped.length,
|
|
405
|
-
reduction: Math.round((1 - capped.length / Math.max(startCount, 1)) * 100),
|
|
406
|
-
projectSize: size,
|
|
407
|
-
caps,
|
|
408
|
-
breakdown: {
|
|
409
|
-
blockers: { total: blockers.length, shown: cappedBlockers.length },
|
|
410
|
-
warnings: { total: warnings.length, shown: cappedWarnings.length },
|
|
411
|
-
info: { total: info.length, shown: cappedInfo.length },
|
|
412
|
-
},
|
|
413
|
-
hidden: {
|
|
414
|
-
byQuality: findings.length - processed.length,
|
|
415
|
-
byCaps: processed.length - capped.length,
|
|
416
|
-
},
|
|
417
|
-
};
|
|
418
|
-
|
|
419
|
-
if (verbose) {
|
|
420
|
-
console.log(`\n[Noise Reduction] ${stats.input} → ${stats.output} findings (${stats.reduction}% reduction)`);
|
|
421
|
-
console.log(` Project size: ${size} | Caps: ${JSON.stringify(caps)}`);
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
return { findings: capped, stats };
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
428
|
-
// EXPORTS
|
|
429
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
430
|
-
|
|
431
|
-
module.exports = {
|
|
432
|
-
// Main function
|
|
433
|
-
reduceNoise,
|
|
434
|
-
|
|
435
|
-
// Individual components (for testing/customization)
|
|
436
|
-
detectProjectSize,
|
|
437
|
-
getAdaptiveCaps,
|
|
438
|
-
calculateQualityScore,
|
|
439
|
-
deduplicateFindings,
|
|
440
|
-
rankFindings,
|
|
441
|
-
applyRuleConfig,
|
|
442
|
-
loadRuleConfig,
|
|
443
|
-
|
|
444
|
-
// Constants (for external configuration)
|
|
445
|
-
PROJECT_SIZE_THRESHOLDS,
|
|
446
|
-
ADAPTIVE_CAPS,
|
|
447
|
-
QUALITY_FACTORS,
|
|
448
|
-
CRITICAL_PATH_PATTERNS,
|
|
449
|
-
KNOWN_FALSE_POSITIVE_PATTERNS,
|
|
450
|
-
DEFAULT_RULE_CONFIG,
|
|
451
|
-
SEVERITY_ORDER,
|
|
452
|
-
};
|