@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,817 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cross-Repository Intelligence Engine
|
|
3
|
-
*
|
|
4
|
-
* ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
-
* COMPETITIVE MOAT FEATURE - Ecosystem-Wide Learning
|
|
6
|
-
* ═══════════════════════════════════════════════════════════════════════════════
|
|
7
|
-
*
|
|
8
|
-
* This engine aggregates anonymized patterns and learnings across all Vibecheck
|
|
9
|
-
* users to provide smarter, more accurate detection. Think of it as a
|
|
10
|
-
* "collective intelligence" for code quality.
|
|
11
|
-
*
|
|
12
|
-
* Features:
|
|
13
|
-
* - Anonymized pattern sharing (opt-in)
|
|
14
|
-
* - Framework-specific best practices learned from real codebases
|
|
15
|
-
* - Common vulnerability patterns across the ecosystem
|
|
16
|
-
* - False positive patterns that should be auto-dismissed
|
|
17
|
-
* - Trending issues (new CVEs, emerging anti-patterns)
|
|
18
|
-
* - Technology stack fingerprinting for tailored rules
|
|
19
|
-
*
|
|
20
|
-
* Privacy:
|
|
21
|
-
* - All data is anonymized (hashed patterns, no code snippets)
|
|
22
|
-
* - Opt-in only
|
|
23
|
-
* - Local-first (works offline with periodic sync)
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
"use strict";
|
|
27
|
-
|
|
28
|
-
const fs = require("fs");
|
|
29
|
-
const path = require("path");
|
|
30
|
-
const crypto = require("crypto");
|
|
31
|
-
|
|
32
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
33
|
-
// INTELLIGENCE DATABASE SCHEMA
|
|
34
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
35
|
-
|
|
36
|
-
const DEFAULT_INTELLIGENCE_DB = {
|
|
37
|
-
version: "1.0.0",
|
|
38
|
-
lastSync: null,
|
|
39
|
-
|
|
40
|
-
// Patterns learned from ecosystem
|
|
41
|
-
patterns: {
|
|
42
|
-
// Pattern hash -> { frequency, confidence, frameworks, example }
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
// Framework-specific intelligence
|
|
46
|
-
frameworks: {
|
|
47
|
-
// Framework name -> { patterns, bestPractices, commonIssues }
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
// Common false positives across ecosystem
|
|
51
|
-
falsePositives: {
|
|
52
|
-
// Pattern hash -> { dismissalRate, contexts }
|
|
53
|
-
},
|
|
54
|
-
|
|
55
|
-
// Trending issues
|
|
56
|
-
trending: {
|
|
57
|
-
// Issue type -> { count, growth, severity, firstSeen }
|
|
58
|
-
},
|
|
59
|
-
|
|
60
|
-
// Technology recommendations
|
|
61
|
-
recommendations: {
|
|
62
|
-
// Stack fingerprint -> [recommendations]
|
|
63
|
-
},
|
|
64
|
-
|
|
65
|
-
// Benchmark data
|
|
66
|
-
benchmarks: {
|
|
67
|
-
// Metric -> { p50, p75, p90, p99 }
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
72
|
-
// STACK FINGERPRINTER
|
|
73
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
74
|
-
|
|
75
|
-
class StackFingerprinter {
|
|
76
|
-
constructor(projectRoot) {
|
|
77
|
-
this.projectRoot = projectRoot;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Analyze project to determine technology stack
|
|
82
|
-
*/
|
|
83
|
-
async fingerprint() {
|
|
84
|
-
const fingerprint = {
|
|
85
|
-
language: null,
|
|
86
|
-
framework: null,
|
|
87
|
-
ui: null,
|
|
88
|
-
database: null,
|
|
89
|
-
authentication: null,
|
|
90
|
-
testing: null,
|
|
91
|
-
deployment: null,
|
|
92
|
-
packages: [],
|
|
93
|
-
patterns: []
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
// Read package.json for Node projects
|
|
97
|
-
const packageJson = this.readPackageJson();
|
|
98
|
-
if (packageJson) {
|
|
99
|
-
fingerprint.language = "javascript";
|
|
100
|
-
this.analyzePackageJson(packageJson, fingerprint);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Check for other languages
|
|
104
|
-
if (!fingerprint.language) {
|
|
105
|
-
fingerprint.language = this.detectLanguage();
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Detect patterns from file structure
|
|
109
|
-
this.analyzeFileStructure(fingerprint);
|
|
110
|
-
|
|
111
|
-
// Calculate fingerprint hash
|
|
112
|
-
fingerprint.hash = this.calculateHash(fingerprint);
|
|
113
|
-
|
|
114
|
-
return fingerprint;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
readPackageJson() {
|
|
118
|
-
const packagePath = path.join(this.projectRoot, "package.json");
|
|
119
|
-
if (fs.existsSync(packagePath)) {
|
|
120
|
-
try {
|
|
121
|
-
return JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
122
|
-
} catch {
|
|
123
|
-
return null;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
analyzePackageJson(pkg, fingerprint) {
|
|
130
|
-
const deps = {
|
|
131
|
-
...pkg.dependencies,
|
|
132
|
-
...pkg.devDependencies
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
// Framework detection
|
|
136
|
-
if (deps.next) {
|
|
137
|
-
fingerprint.framework = "nextjs";
|
|
138
|
-
fingerprint.ui = "react";
|
|
139
|
-
} else if (deps.nuxt) {
|
|
140
|
-
fingerprint.framework = "nuxt";
|
|
141
|
-
fingerprint.ui = "vue";
|
|
142
|
-
} else if (deps.react) {
|
|
143
|
-
fingerprint.framework = deps["react-router"] ? "react-router" : "react";
|
|
144
|
-
fingerprint.ui = "react";
|
|
145
|
-
} else if (deps.vue) {
|
|
146
|
-
fingerprint.framework = deps["vue-router"] ? "vue-router" : "vue";
|
|
147
|
-
fingerprint.ui = "vue";
|
|
148
|
-
} else if (deps.angular) {
|
|
149
|
-
fingerprint.framework = "angular";
|
|
150
|
-
fingerprint.ui = "angular";
|
|
151
|
-
} else if (deps.express) {
|
|
152
|
-
fingerprint.framework = "express";
|
|
153
|
-
} else if (deps.fastify) {
|
|
154
|
-
fingerprint.framework = "fastify";
|
|
155
|
-
} else if (deps.hono) {
|
|
156
|
-
fingerprint.framework = "hono";
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Database detection
|
|
160
|
-
if (deps.prisma || deps["@prisma/client"]) {
|
|
161
|
-
fingerprint.database = "prisma";
|
|
162
|
-
} else if (deps.mongoose) {
|
|
163
|
-
fingerprint.database = "mongodb";
|
|
164
|
-
} else if (deps.pg || deps.postgres) {
|
|
165
|
-
fingerprint.database = "postgresql";
|
|
166
|
-
} else if (deps.mysql || deps.mysql2) {
|
|
167
|
-
fingerprint.database = "mysql";
|
|
168
|
-
} else if (deps.drizzle || deps["drizzle-orm"]) {
|
|
169
|
-
fingerprint.database = "drizzle";
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Auth detection
|
|
173
|
-
if (deps["next-auth"] || deps["@auth/core"]) {
|
|
174
|
-
fingerprint.authentication = "next-auth";
|
|
175
|
-
} else if (deps.passport) {
|
|
176
|
-
fingerprint.authentication = "passport";
|
|
177
|
-
} else if (deps["@clerk/nextjs"]) {
|
|
178
|
-
fingerprint.authentication = "clerk";
|
|
179
|
-
} else if (deps["@supabase/supabase-js"]) {
|
|
180
|
-
fingerprint.authentication = "supabase";
|
|
181
|
-
} else if (deps.firebase) {
|
|
182
|
-
fingerprint.authentication = "firebase";
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Testing detection
|
|
186
|
-
if (deps.jest) {
|
|
187
|
-
fingerprint.testing = "jest";
|
|
188
|
-
} else if (deps.vitest) {
|
|
189
|
-
fingerprint.testing = "vitest";
|
|
190
|
-
} else if (deps.playwright) {
|
|
191
|
-
fingerprint.testing = "playwright";
|
|
192
|
-
} else if (deps.cypress) {
|
|
193
|
-
fingerprint.testing = "cypress";
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Store top packages for pattern matching
|
|
197
|
-
fingerprint.packages = Object.keys(deps)
|
|
198
|
-
.filter(d => !d.startsWith("@types/"))
|
|
199
|
-
.slice(0, 50);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
detectLanguage() {
|
|
203
|
-
const indicators = {
|
|
204
|
-
"requirements.txt": "python",
|
|
205
|
-
"pyproject.toml": "python",
|
|
206
|
-
"Cargo.toml": "rust",
|
|
207
|
-
"go.mod": "go",
|
|
208
|
-
"pom.xml": "java",
|
|
209
|
-
"build.gradle": "java",
|
|
210
|
-
"Gemfile": "ruby",
|
|
211
|
-
"composer.json": "php"
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
for (const [file, lang] of Object.entries(indicators)) {
|
|
215
|
-
if (fs.existsSync(path.join(this.projectRoot, file))) {
|
|
216
|
-
return lang;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return "unknown";
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
analyzeFileStructure(fingerprint) {
|
|
224
|
-
const patterns = [];
|
|
225
|
-
|
|
226
|
-
// Check for common patterns
|
|
227
|
-
const checks = [
|
|
228
|
-
{ path: "app", pattern: "app-directory" },
|
|
229
|
-
{ path: "pages", pattern: "pages-router" },
|
|
230
|
-
{ path: "src/components", pattern: "component-structure" },
|
|
231
|
-
{ path: "lib", pattern: "lib-utils" },
|
|
232
|
-
{ path: "utils", pattern: "utils-folder" },
|
|
233
|
-
{ path: "hooks", pattern: "custom-hooks" },
|
|
234
|
-
{ path: "services", pattern: "service-layer" },
|
|
235
|
-
{ path: "api", pattern: "api-layer" },
|
|
236
|
-
{ path: ".github/workflows", pattern: "github-actions" },
|
|
237
|
-
{ path: "docker-compose.yml", pattern: "docker" },
|
|
238
|
-
{ path: "kubernetes", pattern: "kubernetes" },
|
|
239
|
-
{ path: "terraform", pattern: "terraform" }
|
|
240
|
-
];
|
|
241
|
-
|
|
242
|
-
for (const check of checks) {
|
|
243
|
-
if (fs.existsSync(path.join(this.projectRoot, check.path))) {
|
|
244
|
-
patterns.push(check.pattern);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
fingerprint.patterns = patterns;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
calculateHash(fingerprint) {
|
|
252
|
-
const normalized = JSON.stringify({
|
|
253
|
-
language: fingerprint.language,
|
|
254
|
-
framework: fingerprint.framework,
|
|
255
|
-
database: fingerprint.database,
|
|
256
|
-
patterns: fingerprint.patterns.sort()
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
return crypto.createHash("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
264
|
-
// CROSS-REPO INTELLIGENCE ENGINE
|
|
265
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
266
|
-
|
|
267
|
-
class CrossRepoIntelligence {
|
|
268
|
-
constructor(options = {}) {
|
|
269
|
-
this.projectRoot = options.projectRoot || process.cwd();
|
|
270
|
-
this.dbPath = options.dbPath ||
|
|
271
|
-
path.join(this.projectRoot, ".vibecheck", "intelligence", "cross-repo.json");
|
|
272
|
-
this.globalDbPath = options.globalDbPath ||
|
|
273
|
-
path.join(process.env.HOME || process.env.USERPROFILE, ".vibecheck", "global-intelligence.json");
|
|
274
|
-
this.syncEndpoint = options.syncEndpoint || "https://api.vibecheck.dev/intelligence";
|
|
275
|
-
this.optedIn = options.optedIn || false;
|
|
276
|
-
|
|
277
|
-
this.db = this.loadDatabase();
|
|
278
|
-
this.fingerprinter = new StackFingerprinter(this.projectRoot);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Load or initialize the intelligence database
|
|
283
|
-
*/
|
|
284
|
-
loadDatabase() {
|
|
285
|
-
// Try project-local DB first
|
|
286
|
-
if (fs.existsSync(this.dbPath)) {
|
|
287
|
-
try {
|
|
288
|
-
return JSON.parse(fs.readFileSync(this.dbPath, "utf8"));
|
|
289
|
-
} catch {
|
|
290
|
-
// Fall through to default
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// Try global DB
|
|
295
|
-
if (fs.existsSync(this.globalDbPath)) {
|
|
296
|
-
try {
|
|
297
|
-
return JSON.parse(fs.readFileSync(this.globalDbPath, "utf8"));
|
|
298
|
-
} catch {
|
|
299
|
-
// Fall through to default
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
return { ...DEFAULT_INTELLIGENCE_DB };
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Save the intelligence database
|
|
308
|
-
*/
|
|
309
|
-
saveDatabase() {
|
|
310
|
-
try {
|
|
311
|
-
const dir = path.dirname(this.dbPath);
|
|
312
|
-
if (!fs.existsSync(dir)) {
|
|
313
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
fs.writeFileSync(this.dbPath, JSON.stringify(this.db, null, 2), "utf8");
|
|
317
|
-
|
|
318
|
-
// Also save to global
|
|
319
|
-
const globalDir = path.dirname(this.globalDbPath);
|
|
320
|
-
if (!fs.existsSync(globalDir)) {
|
|
321
|
-
fs.mkdirSync(globalDir, { recursive: true });
|
|
322
|
-
}
|
|
323
|
-
fs.writeFileSync(this.globalDbPath, JSON.stringify(this.db, null, 2), "utf8");
|
|
324
|
-
} catch {
|
|
325
|
-
// Silently fail - intelligence is enhancement not requirement
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
330
|
-
// PATTERN LEARNING
|
|
331
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Learn from a finding
|
|
335
|
-
*/
|
|
336
|
-
learnFromFinding(finding, outcome) {
|
|
337
|
-
const patternHash = this.hashPattern(finding);
|
|
338
|
-
|
|
339
|
-
if (!this.db.patterns[patternHash]) {
|
|
340
|
-
this.db.patterns[patternHash] = {
|
|
341
|
-
type: finding.type,
|
|
342
|
-
frequency: 0,
|
|
343
|
-
fixed: 0,
|
|
344
|
-
dismissed: 0,
|
|
345
|
-
confidence: finding.confidence || 0.5,
|
|
346
|
-
frameworks: [],
|
|
347
|
-
firstSeen: new Date().toISOString()
|
|
348
|
-
};
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
const pattern = this.db.patterns[patternHash];
|
|
352
|
-
pattern.frequency++;
|
|
353
|
-
pattern.lastSeen = new Date().toISOString();
|
|
354
|
-
|
|
355
|
-
switch (outcome) {
|
|
356
|
-
case "fixed":
|
|
357
|
-
pattern.fixed++;
|
|
358
|
-
pattern.confidence = Math.min(1, pattern.confidence + 0.01);
|
|
359
|
-
break;
|
|
360
|
-
case "dismissed":
|
|
361
|
-
pattern.dismissed++;
|
|
362
|
-
pattern.confidence = Math.max(0, pattern.confidence - 0.02);
|
|
363
|
-
break;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// Track framework association
|
|
367
|
-
if (finding.framework && !pattern.frameworks.includes(finding.framework)) {
|
|
368
|
-
pattern.frameworks.push(finding.framework);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
this.saveDatabase();
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
/**
|
|
375
|
-
* Learn from multiple findings in a scan
|
|
376
|
-
*/
|
|
377
|
-
learnFromScan(findings, fingerprint) {
|
|
378
|
-
// Update framework intelligence
|
|
379
|
-
if (fingerprint.framework) {
|
|
380
|
-
if (!this.db.frameworks[fingerprint.framework]) {
|
|
381
|
-
this.db.frameworks[fingerprint.framework] = {
|
|
382
|
-
scans: 0,
|
|
383
|
-
commonIssues: {},
|
|
384
|
-
bestPractices: [],
|
|
385
|
-
avgFindingsPerScan: 0
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
const fwData = this.db.frameworks[fingerprint.framework];
|
|
390
|
-
fwData.scans++;
|
|
391
|
-
|
|
392
|
-
// Track common issues for this framework
|
|
393
|
-
for (const finding of findings) {
|
|
394
|
-
const issueType = finding.type;
|
|
395
|
-
if (!fwData.commonIssues[issueType]) {
|
|
396
|
-
fwData.commonIssues[issueType] = { count: 0, severity: finding.severity };
|
|
397
|
-
}
|
|
398
|
-
fwData.commonIssues[issueType].count++;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// Update average findings
|
|
402
|
-
fwData.avgFindingsPerScan =
|
|
403
|
-
(fwData.avgFindingsPerScan * (fwData.scans - 1) + findings.length) / fwData.scans;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
// Update trending issues
|
|
407
|
-
for (const finding of findings) {
|
|
408
|
-
const issueType = finding.type;
|
|
409
|
-
if (!this.db.trending[issueType]) {
|
|
410
|
-
this.db.trending[issueType] = {
|
|
411
|
-
count: 0,
|
|
412
|
-
severity: finding.severity,
|
|
413
|
-
firstSeen: new Date().toISOString(),
|
|
414
|
-
lastSeen: new Date().toISOString()
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
this.db.trending[issueType].count++;
|
|
418
|
-
this.db.trending[issueType].lastSeen = new Date().toISOString();
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
// Update benchmarks
|
|
422
|
-
this.updateBenchmarks(findings, fingerprint);
|
|
423
|
-
|
|
424
|
-
this.saveDatabase();
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
/**
|
|
428
|
-
* Track false positive patterns
|
|
429
|
-
*/
|
|
430
|
-
learnFalsePositive(finding, context) {
|
|
431
|
-
const patternHash = this.hashPattern(finding);
|
|
432
|
-
|
|
433
|
-
if (!this.db.falsePositives[patternHash]) {
|
|
434
|
-
this.db.falsePositives[patternHash] = {
|
|
435
|
-
type: finding.type,
|
|
436
|
-
dismissals: 0,
|
|
437
|
-
contexts: [],
|
|
438
|
-
confidence: 0
|
|
439
|
-
};
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
const fp = this.db.falsePositives[patternHash];
|
|
443
|
-
fp.dismissals++;
|
|
444
|
-
|
|
445
|
-
// Track context where this is dismissed
|
|
446
|
-
if (context && !fp.contexts.includes(context)) {
|
|
447
|
-
fp.contexts.push(context);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// Calculate false positive confidence
|
|
451
|
-
const pattern = this.db.patterns[patternHash];
|
|
452
|
-
if (pattern && pattern.frequency > 0) {
|
|
453
|
-
fp.confidence = fp.dismissals / pattern.frequency;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
this.saveDatabase();
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
460
|
-
// RECOMMENDATIONS
|
|
461
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
462
|
-
|
|
463
|
-
/**
|
|
464
|
-
* Get recommendations based on stack fingerprint
|
|
465
|
-
*/
|
|
466
|
-
async getRecommendations() {
|
|
467
|
-
const fingerprint = await this.fingerprinter.fingerprint();
|
|
468
|
-
const recommendations = [];
|
|
469
|
-
|
|
470
|
-
// Framework-specific recommendations
|
|
471
|
-
if (fingerprint.framework && this.db.frameworks[fingerprint.framework]) {
|
|
472
|
-
const fwData = this.db.frameworks[fingerprint.framework];
|
|
473
|
-
|
|
474
|
-
// Warn about common issues for this framework
|
|
475
|
-
const sortedIssues = Object.entries(fwData.commonIssues)
|
|
476
|
-
.sort((a, b) => b[1].count - a[1].count)
|
|
477
|
-
.slice(0, 5);
|
|
478
|
-
|
|
479
|
-
for (const [issueType, data] of sortedIssues) {
|
|
480
|
-
recommendations.push({
|
|
481
|
-
type: "framework_common_issue",
|
|
482
|
-
priority: data.severity === "BLOCK" ? "high" : "medium",
|
|
483
|
-
message: `${issueType} is commonly found in ${fingerprint.framework} projects`,
|
|
484
|
-
action: `Consider adding specific rules to catch ${issueType}`
|
|
485
|
-
});
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// Check for missing best practices based on stack
|
|
490
|
-
const missingPractices = this.checkMissingPractices(fingerprint);
|
|
491
|
-
for (const practice of missingPractices) {
|
|
492
|
-
recommendations.push({
|
|
493
|
-
type: "missing_best_practice",
|
|
494
|
-
priority: "medium",
|
|
495
|
-
message: practice.message,
|
|
496
|
-
action: practice.action
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
// Trending issue warnings
|
|
501
|
-
const trending = this.getTrendingIssues(5);
|
|
502
|
-
for (const issue of trending) {
|
|
503
|
-
recommendations.push({
|
|
504
|
-
type: "trending_issue",
|
|
505
|
-
priority: issue.severity === "BLOCK" ? "high" : "low",
|
|
506
|
-
message: `${issue.type} is trending (${issue.count} occurrences)`,
|
|
507
|
-
action: `Review code for ${issue.type} patterns`
|
|
508
|
-
});
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
// Benchmark comparison
|
|
512
|
-
const benchmarkRecs = this.compareToBenchmarks(fingerprint);
|
|
513
|
-
recommendations.push(...benchmarkRecs);
|
|
514
|
-
|
|
515
|
-
return {
|
|
516
|
-
fingerprint,
|
|
517
|
-
recommendations: recommendations.sort((a, b) => {
|
|
518
|
-
const priority = { high: 0, medium: 1, low: 2 };
|
|
519
|
-
return priority[a.priority] - priority[b.priority];
|
|
520
|
-
})
|
|
521
|
-
};
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
/**
|
|
525
|
-
* Check for missing best practices
|
|
526
|
-
*/
|
|
527
|
-
checkMissingPractices(fingerprint) {
|
|
528
|
-
const practices = [];
|
|
529
|
-
|
|
530
|
-
// Check for common missing patterns
|
|
531
|
-
if (fingerprint.framework === "nextjs" && !fingerprint.patterns.includes("app-directory")) {
|
|
532
|
-
practices.push({
|
|
533
|
-
message: "Consider migrating to App Directory for better performance",
|
|
534
|
-
action: "Review Next.js 13+ App Router documentation"
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
if (!fingerprint.testing) {
|
|
539
|
-
practices.push({
|
|
540
|
-
message: "No testing framework detected",
|
|
541
|
-
action: "Add testing with Vitest or Jest"
|
|
542
|
-
});
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
if (!fingerprint.patterns.includes("github-actions") &&
|
|
546
|
-
!fingerprint.patterns.includes("docker")) {
|
|
547
|
-
practices.push({
|
|
548
|
-
message: "No CI/CD configuration detected",
|
|
549
|
-
action: "Set up GitHub Actions or similar CI/CD"
|
|
550
|
-
});
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
return practices;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
/**
|
|
557
|
-
* Get trending issues
|
|
558
|
-
*/
|
|
559
|
-
getTrendingIssues(limit = 10) {
|
|
560
|
-
return Object.entries(this.db.trending)
|
|
561
|
-
.map(([type, data]) => ({ type, ...data }))
|
|
562
|
-
.sort((a, b) => b.count - a.count)
|
|
563
|
-
.slice(0, limit);
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
/**
|
|
567
|
-
* Compare to ecosystem benchmarks
|
|
568
|
-
*/
|
|
569
|
-
compareToBenchmarks(fingerprint) {
|
|
570
|
-
const recommendations = [];
|
|
571
|
-
|
|
572
|
-
if (!this.db.benchmarks.findingsPerScan) return recommendations;
|
|
573
|
-
|
|
574
|
-
const fwData = this.db.frameworks[fingerprint.framework];
|
|
575
|
-
if (fwData && this.db.benchmarks.findingsPerScan) {
|
|
576
|
-
const benchmark = this.db.benchmarks.findingsPerScan;
|
|
577
|
-
|
|
578
|
-
if (fwData.avgFindingsPerScan > benchmark.p75) {
|
|
579
|
-
recommendations.push({
|
|
580
|
-
type: "above_benchmark",
|
|
581
|
-
priority: "medium",
|
|
582
|
-
message: `Your project has more issues than 75% of similar projects`,
|
|
583
|
-
action: "Focus on reducing findings to improve code quality"
|
|
584
|
-
});
|
|
585
|
-
} else if (fwData.avgFindingsPerScan < benchmark.p25) {
|
|
586
|
-
recommendations.push({
|
|
587
|
-
type: "below_benchmark",
|
|
588
|
-
priority: "low",
|
|
589
|
-
message: `Your project has fewer issues than 75% of similar projects`,
|
|
590
|
-
action: "Great job! Consider adding stricter rules"
|
|
591
|
-
});
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
return recommendations;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
599
|
-
// CONFIDENCE ADJUSTMENT
|
|
600
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
601
|
-
|
|
602
|
-
/**
|
|
603
|
-
* Get adjusted confidence based on ecosystem data
|
|
604
|
-
*/
|
|
605
|
-
getAdjustedConfidence(finding, fingerprint) {
|
|
606
|
-
const patternHash = this.hashPattern(finding);
|
|
607
|
-
let adjustment = 0;
|
|
608
|
-
|
|
609
|
-
// Check false positive history
|
|
610
|
-
const fpData = this.db.falsePositives[patternHash];
|
|
611
|
-
if (fpData && fpData.confidence > 0.5) {
|
|
612
|
-
adjustment -= fpData.confidence * 0.2;
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
// Check pattern data
|
|
616
|
-
const patternData = this.db.patterns[patternHash];
|
|
617
|
-
if (patternData && patternData.frequency >= 10) {
|
|
618
|
-
const fixRate = patternData.fixed / patternData.frequency;
|
|
619
|
-
adjustment += (fixRate - 0.5) * 0.1;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
// Framework-specific adjustment
|
|
623
|
-
if (fingerprint.framework) {
|
|
624
|
-
const fwData = this.db.frameworks[fingerprint.framework];
|
|
625
|
-
if (fwData?.commonIssues[finding.type]) {
|
|
626
|
-
// Common in framework = slightly higher confidence
|
|
627
|
-
adjustment += 0.05;
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
const originalConfidence = finding.confidence || 0.5;
|
|
632
|
-
const adjustedConfidence = Math.max(0, Math.min(1, originalConfidence + adjustment));
|
|
633
|
-
|
|
634
|
-
return {
|
|
635
|
-
original: originalConfidence,
|
|
636
|
-
adjusted: adjustedConfidence,
|
|
637
|
-
adjustment,
|
|
638
|
-
factors: {
|
|
639
|
-
falsePositiveHistory: fpData?.confidence || 0,
|
|
640
|
-
ecosystemFixRate: patternData ? patternData.fixed / Math.max(1, patternData.frequency) : 0,
|
|
641
|
-
frameworkCommon: !!this.db.frameworks[fingerprint.framework]?.commonIssues[finding.type]
|
|
642
|
-
}
|
|
643
|
-
};
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
/**
|
|
647
|
-
* Check if should auto-dismiss based on ecosystem
|
|
648
|
-
*/
|
|
649
|
-
shouldAutoDismiss(finding) {
|
|
650
|
-
const patternHash = this.hashPattern(finding);
|
|
651
|
-
const fpData = this.db.falsePositives[patternHash];
|
|
652
|
-
|
|
653
|
-
// Auto-dismiss if ecosystem false positive rate is very high
|
|
654
|
-
if (fpData && fpData.confidence > 0.8 && fpData.dismissals >= 100) {
|
|
655
|
-
return {
|
|
656
|
-
dismiss: true,
|
|
657
|
-
reason: `Dismissed by ${fpData.confidence * 100}% of users (${fpData.dismissals} times)`,
|
|
658
|
-
confidence: 1 - fpData.confidence
|
|
659
|
-
};
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
return { dismiss: false };
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
666
|
-
// BENCHMARKS
|
|
667
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
668
|
-
|
|
669
|
-
/**
|
|
670
|
-
* Update benchmarks from scan data
|
|
671
|
-
*/
|
|
672
|
-
updateBenchmarks(findings, fingerprint) {
|
|
673
|
-
if (!this.db.benchmarks.findingsPerScan) {
|
|
674
|
-
this.db.benchmarks.findingsPerScan = {
|
|
675
|
-
samples: [],
|
|
676
|
-
p25: 0,
|
|
677
|
-
p50: 0,
|
|
678
|
-
p75: 0,
|
|
679
|
-
p90: 0
|
|
680
|
-
};
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
const benchmark = this.db.benchmarks.findingsPerScan;
|
|
684
|
-
benchmark.samples.push(findings.length);
|
|
685
|
-
|
|
686
|
-
// Keep only last 1000 samples
|
|
687
|
-
if (benchmark.samples.length > 1000) {
|
|
688
|
-
benchmark.samples = benchmark.samples.slice(-1000);
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
// Calculate percentiles
|
|
692
|
-
const sorted = [...benchmark.samples].sort((a, b) => a - b);
|
|
693
|
-
benchmark.p25 = sorted[Math.floor(sorted.length * 0.25)];
|
|
694
|
-
benchmark.p50 = sorted[Math.floor(sorted.length * 0.5)];
|
|
695
|
-
benchmark.p75 = sorted[Math.floor(sorted.length * 0.75)];
|
|
696
|
-
benchmark.p90 = sorted[Math.floor(sorted.length * 0.9)];
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
/**
|
|
700
|
-
* Get benchmark data
|
|
701
|
-
*/
|
|
702
|
-
getBenchmarks() {
|
|
703
|
-
return {
|
|
704
|
-
findingsPerScan: this.db.benchmarks.findingsPerScan
|
|
705
|
-
? {
|
|
706
|
-
p25: this.db.benchmarks.findingsPerScan.p25,
|
|
707
|
-
p50: this.db.benchmarks.findingsPerScan.p50,
|
|
708
|
-
p75: this.db.benchmarks.findingsPerScan.p75,
|
|
709
|
-
p90: this.db.benchmarks.findingsPerScan.p90,
|
|
710
|
-
sampleSize: this.db.benchmarks.findingsPerScan.samples?.length || 0
|
|
711
|
-
}
|
|
712
|
-
: null
|
|
713
|
-
};
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
717
|
-
// SYNC (Placeholder for cloud sync)
|
|
718
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
719
|
-
|
|
720
|
-
/**
|
|
721
|
-
* Sync with cloud intelligence (opt-in)
|
|
722
|
-
*/
|
|
723
|
-
async sync() {
|
|
724
|
-
if (!this.optedIn) {
|
|
725
|
-
return { synced: false, reason: "Not opted in" };
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
// This would sync anonymized data with cloud service
|
|
729
|
-
// For now, just update timestamp
|
|
730
|
-
this.db.lastSync = new Date().toISOString();
|
|
731
|
-
this.saveDatabase();
|
|
732
|
-
|
|
733
|
-
return { synced: true, timestamp: this.db.lastSync };
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
/**
|
|
737
|
-
* Export anonymized intelligence for sharing
|
|
738
|
-
*/
|
|
739
|
-
exportAnonymized() {
|
|
740
|
-
return {
|
|
741
|
-
version: this.db.version,
|
|
742
|
-
patterns: Object.entries(this.db.patterns)
|
|
743
|
-
.filter(([, data]) => data.frequency >= 5)
|
|
744
|
-
.map(([hash, data]) => ({
|
|
745
|
-
hash,
|
|
746
|
-
type: data.type,
|
|
747
|
-
frequency: data.frequency,
|
|
748
|
-
confidence: data.confidence,
|
|
749
|
-
frameworks: data.frameworks
|
|
750
|
-
})),
|
|
751
|
-
falsePositives: Object.entries(this.db.falsePositives)
|
|
752
|
-
.filter(([, data]) => data.dismissals >= 10)
|
|
753
|
-
.map(([hash, data]) => ({
|
|
754
|
-
hash,
|
|
755
|
-
type: data.type,
|
|
756
|
-
confidence: data.confidence
|
|
757
|
-
})),
|
|
758
|
-
trending: Object.entries(this.db.trending)
|
|
759
|
-
.slice(0, 20)
|
|
760
|
-
.map(([type, data]) => ({
|
|
761
|
-
type,
|
|
762
|
-
count: data.count,
|
|
763
|
-
severity: data.severity
|
|
764
|
-
})),
|
|
765
|
-
benchmarks: this.getBenchmarks()
|
|
766
|
-
};
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
770
|
-
// UTILITIES
|
|
771
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
772
|
-
|
|
773
|
-
/**
|
|
774
|
-
* Hash a finding pattern
|
|
775
|
-
*/
|
|
776
|
-
hashPattern(finding) {
|
|
777
|
-
const normalized = JSON.stringify({
|
|
778
|
-
type: finding.type,
|
|
779
|
-
message: finding.message?.replace(/[0-9]+/g, "N").slice(0, 100),
|
|
780
|
-
severity: finding.severity
|
|
781
|
-
});
|
|
782
|
-
|
|
783
|
-
return crypto.createHash("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
/**
|
|
787
|
-
* Get intelligence summary
|
|
788
|
-
*/
|
|
789
|
-
getSummary() {
|
|
790
|
-
return {
|
|
791
|
-
patternsTracked: Object.keys(this.db.patterns).length,
|
|
792
|
-
falsePositivesTracked: Object.keys(this.db.falsePositives).length,
|
|
793
|
-
frameworksTracked: Object.keys(this.db.frameworks).length,
|
|
794
|
-
trendingIssues: Object.keys(this.db.trending).length,
|
|
795
|
-
lastSync: this.db.lastSync,
|
|
796
|
-
optedIn: this.optedIn
|
|
797
|
-
};
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
/**
|
|
801
|
-
* Reset intelligence data
|
|
802
|
-
*/
|
|
803
|
-
reset() {
|
|
804
|
-
this.db = { ...DEFAULT_INTELLIGENCE_DB };
|
|
805
|
-
this.saveDatabase();
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
810
|
-
// EXPORTS
|
|
811
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
812
|
-
|
|
813
|
-
module.exports = {
|
|
814
|
-
CrossRepoIntelligence,
|
|
815
|
-
StackFingerprinter,
|
|
816
|
-
DEFAULT_INTELLIGENCE_DB
|
|
817
|
-
};
|