@vibecheckai/cli 3.4.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/registry.js +243 -152
- package/bin/runners/cli-utils.js +2 -33
- package/bin/runners/context/generators/cursor.js +49 -2
- package/bin/runners/lib/agent-firewall/learning/learning-engine.js +849 -0
- package/bin/runners/lib/analyzers.js +544 -19
- package/bin/runners/lib/audit-logger.js +532 -0
- package/bin/runners/lib/authority/authorities/architecture.js +364 -0
- package/bin/runners/lib/authority/authorities/compliance.js +341 -0
- package/bin/runners/lib/authority/authorities/human.js +343 -0
- package/bin/runners/lib/authority/authorities/quality.js +420 -0
- package/bin/runners/lib/authority/authorities/security.js +228 -0
- package/bin/runners/lib/authority/index.js +293 -0
- package/bin/runners/lib/authority-badge.js +425 -425
- package/bin/runners/lib/bundle/bundle-intelligence.js +846 -0
- package/bin/runners/lib/cli-charts.js +368 -0
- package/bin/runners/lib/cli-config-display.js +405 -0
- package/bin/runners/lib/cli-demo.js +275 -0
- package/bin/runners/lib/cli-errors.js +438 -0
- package/bin/runners/lib/cli-help-formatter.js +439 -0
- package/bin/runners/lib/cli-interactive-menu.js +509 -0
- package/bin/runners/lib/cli-prompts.js +441 -0
- package/bin/runners/lib/cli-scan-cards.js +362 -0
- package/bin/runners/lib/compliance-reporter.js +710 -0
- package/bin/runners/lib/conductor/index.js +671 -0
- package/bin/runners/lib/easy/README.md +123 -0
- package/bin/runners/lib/easy/index.js +140 -0
- package/bin/runners/lib/easy/interactive-wizard.js +788 -0
- package/bin/runners/lib/easy/one-click-firewall.js +564 -0
- package/bin/runners/lib/easy/zero-config-reality.js +714 -0
- package/bin/runners/lib/engines/accessibility-engine.js +218 -18
- package/bin/runners/lib/engines/api-consistency-engine.js +335 -30
- package/bin/runners/lib/engines/async-patterns-engine.js +444 -0
- package/bin/runners/lib/engines/bundle-size-engine.js +433 -0
- package/bin/runners/lib/engines/confidence-scoring.js +276 -0
- package/bin/runners/lib/engines/context-detection.js +264 -0
- package/bin/runners/lib/engines/cross-file-analysis-engine.js +292 -27
- package/bin/runners/lib/engines/database-patterns-engine.js +429 -0
- package/bin/runners/lib/engines/duplicate-code-engine.js +354 -0
- package/bin/runners/lib/engines/empty-catch-engine.js +127 -17
- package/bin/runners/lib/engines/env-variables-engine.js +458 -0
- package/bin/runners/lib/engines/error-handling-engine.js +437 -0
- package/bin/runners/lib/engines/false-positive-prevention.js +630 -0
- package/bin/runners/lib/engines/framework-adapters/index.js +607 -0
- package/bin/runners/lib/engines/framework-detection.js +508 -0
- package/bin/runners/lib/engines/import-order-engine.js +429 -0
- package/bin/runners/lib/engines/mock-data-engine.js +53 -10
- package/bin/runners/lib/engines/naming-conventions-engine.js +544 -0
- package/bin/runners/lib/engines/noise-reduction-engine.js +452 -0
- package/bin/runners/lib/engines/orchestrator.js +334 -0
- package/bin/runners/lib/engines/performance-issues-engine.js +176 -36
- package/bin/runners/lib/engines/react-patterns-engine.js +457 -0
- package/bin/runners/lib/engines/security-vulnerabilities-engine.js +382 -54
- package/bin/runners/lib/engines/type-aware-engine.js +263 -39
- package/bin/runners/lib/engines/vibecheck-engines/index.js +122 -13
- package/bin/runners/lib/engines/vibecheck-engines/lib/ai-hallucination-engine.js +806 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +373 -73
- package/bin/runners/lib/engines/vibecheck-engines/lib/smart-fix-engine.js +577 -0
- package/bin/runners/lib/engines/vibecheck-engines/lib/vibe-score-engine.js +543 -0
- package/bin/runners/lib/engines/vibecheck-engines.js +514 -0
- package/bin/runners/lib/enhanced-features/index.js +305 -0
- package/bin/runners/lib/enhanced-output.js +631 -0
- package/bin/runners/lib/enterprise.js +300 -0
- package/bin/runners/lib/entitlements-v2.js +103 -11
- package/bin/runners/lib/firewall/command-validator.js +351 -0
- package/bin/runners/lib/firewall/config.js +341 -0
- package/bin/runners/lib/firewall/content-validator.js +519 -0
- package/bin/runners/lib/firewall/index.js +101 -0
- package/bin/runners/lib/firewall/path-validator.js +256 -0
- package/bin/runners/lib/html-proof-report.js +350 -700
- package/bin/runners/lib/intelligence/cross-repo-intelligence.js +817 -0
- package/bin/runners/lib/mcp-utils.js +425 -0
- package/bin/runners/lib/missions/plan.js +46 -6
- package/bin/runners/lib/missions/templates.js +232 -0
- package/bin/runners/lib/output/index.js +1022 -0
- package/bin/runners/lib/policy-engine.js +652 -0
- package/bin/runners/lib/polish/autofix/accessibility-fixes.js +333 -0
- package/bin/runners/lib/polish/autofix/async-handlers.js +273 -0
- package/bin/runners/lib/polish/autofix/dead-code.js +280 -0
- package/bin/runners/lib/polish/autofix/imports-optimizer.js +344 -0
- package/bin/runners/lib/polish/autofix/index.js +200 -0
- package/bin/runners/lib/polish/autofix/remove-consoles.js +209 -0
- package/bin/runners/lib/polish/autofix/strengthen-types.js +245 -0
- package/bin/runners/lib/polish/backend-checks.js +148 -0
- package/bin/runners/lib/polish/documentation-checks.js +111 -0
- package/bin/runners/lib/polish/frontend-checks.js +168 -0
- package/bin/runners/lib/polish/index.js +71 -0
- package/bin/runners/lib/polish/infrastructure-checks.js +131 -0
- package/bin/runners/lib/polish/library-detection.js +175 -0
- package/bin/runners/lib/polish/performance-checks.js +100 -0
- package/bin/runners/lib/polish/security-checks.js +148 -0
- package/bin/runners/lib/polish/utils.js +203 -0
- package/bin/runners/lib/prompt-builder.js +540 -0
- package/bin/runners/lib/proof-certificate.js +634 -0
- package/bin/runners/lib/reality/accessibility-audit.js +946 -0
- package/bin/runners/lib/reality/api-contract-validator.js +1012 -0
- package/bin/runners/lib/reality/chaos-engineering.js +1084 -0
- package/bin/runners/lib/reality/performance-tracker.js +1077 -0
- package/bin/runners/lib/reality/scenario-generator.js +1404 -0
- package/bin/runners/lib/reality/visual-regression.js +852 -0
- package/bin/runners/lib/reality-profiler.js +717 -0
- package/bin/runners/lib/replay/flight-recorder-viewer.js +1160 -0
- package/bin/runners/lib/review/ai-code-review.js +832 -0
- package/bin/runners/lib/rules/custom-rule-engine.js +985 -0
- package/bin/runners/lib/sbom-generator.js +641 -0
- package/bin/runners/lib/scan-output-enhanced.js +512 -0
- package/bin/runners/lib/scan-output.js +47 -0
- package/bin/runners/lib/security/owasp-scanner.js +939 -0
- package/bin/runners/lib/terminal-ui.js +113 -1
- package/bin/runners/lib/unified-cli-output.js +603 -430
- package/bin/runners/lib/validators/contract-validator.js +283 -0
- package/bin/runners/lib/validators/dead-export-detector.js +279 -0
- package/bin/runners/lib/validators/dep-audit.js +245 -0
- package/bin/runners/lib/validators/env-validator.js +319 -0
- package/bin/runners/lib/validators/index.js +120 -0
- package/bin/runners/lib/validators/license-checker.js +252 -0
- package/bin/runners/lib/validators/route-validator.js +290 -0
- package/bin/runners/runAIAgent.js +5 -10
- package/bin/runners/runAgent.js +3 -0
- package/bin/runners/runApprove.js +1233 -1200
- package/bin/runners/runAuth.js +22 -1
- package/bin/runners/runAuthority.js +528 -0
- package/bin/runners/runCheckpoint.js +4 -24
- package/bin/runners/runClassify.js +862 -859
- package/bin/runners/runConductor.js +772 -0
- package/bin/runners/runContainer.js +366 -0
- package/bin/runners/runContext.js +3 -0
- package/bin/runners/runDoctor.js +28 -41
- package/bin/runners/runEasy.js +410 -0
- package/bin/runners/runFirewall.js +3 -0
- package/bin/runners/runFirewallHook.js +3 -0
- package/bin/runners/runFix.js +76 -66
- package/bin/runners/runGuard.js +411 -18
- package/bin/runners/runIaC.js +372 -0
- package/bin/runners/runInit.js +10 -60
- package/bin/runners/runMcp.js +11 -12
- package/bin/runners/runPolish.js +240 -64
- package/bin/runners/runPromptFirewall.js +5 -12
- package/bin/runners/runProve.js +20 -55
- package/bin/runners/runReality.js +68 -59
- package/bin/runners/runReport.js +31 -5
- package/bin/runners/runRuntime.js +5 -8
- package/bin/runners/runScan.js +194 -1286
- package/bin/runners/runShip.js +695 -47
- package/bin/runners/runTruth.js +3 -0
- package/bin/runners/runValidate.js +7 -11
- package/bin/runners/runVibe.js +791 -0
- package/bin/runners/runWatch.js +14 -23
- package/bin/vibecheck.js +175 -56
- package/mcp-server/index.js +190 -14
- package/mcp-server/package.json +1 -1
- package/mcp-server/tools-v3.js +397 -64
- package/mcp-server/tools.js +495 -0
- package/package.json +1 -1
- package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +0 -164
- package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +0 -291
- package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +0 -83
- package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +0 -198
- package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +0 -275
- package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +0 -167
- package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +0 -217
- package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +0 -140
- package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +0 -164
- package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +0 -234
- package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +0 -217
- package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +0 -78
- package/mcp-server/index-v1.js +0 -698
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced Scan Output - Beautiful scan results with charts and Pro upselling
|
|
3
|
+
*
|
|
4
|
+
* Integrates:
|
|
5
|
+
* - Verdict cards with health scores
|
|
6
|
+
* - Severity distribution charts
|
|
7
|
+
* - Category breakdown
|
|
8
|
+
* - Trend analysis (if baseline exists)
|
|
9
|
+
* - Pro feature upselling
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
"use strict";
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
ansi,
|
|
16
|
+
sym,
|
|
17
|
+
box,
|
|
18
|
+
padRight,
|
|
19
|
+
padLeft,
|
|
20
|
+
center,
|
|
21
|
+
truncate,
|
|
22
|
+
visibleLength,
|
|
23
|
+
progressBar,
|
|
24
|
+
renderTable,
|
|
25
|
+
renderSectionHeader,
|
|
26
|
+
renderSuccess,
|
|
27
|
+
renderWarning,
|
|
28
|
+
renderInfo,
|
|
29
|
+
renderBullet,
|
|
30
|
+
formatDuration,
|
|
31
|
+
getTierBadge,
|
|
32
|
+
WIDTH,
|
|
33
|
+
} = require("./unified-cli-output");
|
|
34
|
+
|
|
35
|
+
const {
|
|
36
|
+
horizontalBarChart,
|
|
37
|
+
severityBreakdown,
|
|
38
|
+
sparkline,
|
|
39
|
+
trendIndicator,
|
|
40
|
+
statsSummary,
|
|
41
|
+
healthGauge,
|
|
42
|
+
} = require("./cli-charts");
|
|
43
|
+
|
|
44
|
+
const {
|
|
45
|
+
verdictCard,
|
|
46
|
+
compactVerdict,
|
|
47
|
+
comparisonCard,
|
|
48
|
+
quickSummary,
|
|
49
|
+
} = require("./cli-scan-cards");
|
|
50
|
+
|
|
51
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
52
|
+
// CONFIGURATION
|
|
53
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
54
|
+
|
|
55
|
+
const PRO_FEATURES = {
|
|
56
|
+
autofix: {
|
|
57
|
+
name: 'Auto-Fix',
|
|
58
|
+
description: 'AI-powered automatic code fixes',
|
|
59
|
+
command: 'vibecheck fix --apply',
|
|
60
|
+
},
|
|
61
|
+
reality: {
|
|
62
|
+
name: 'Reality Proof',
|
|
63
|
+
description: 'Runtime verification with Playwright',
|
|
64
|
+
command: 'vibecheck scan --reality',
|
|
65
|
+
},
|
|
66
|
+
badge: {
|
|
67
|
+
name: 'Status Badge',
|
|
68
|
+
description: 'Embeddable health badge for README',
|
|
69
|
+
command: 'vibecheck ship --badge',
|
|
70
|
+
},
|
|
71
|
+
ci: {
|
|
72
|
+
name: 'CI Integration',
|
|
73
|
+
description: 'GitHub Actions & CI/CD workflows',
|
|
74
|
+
command: 'vibecheck init --ci',
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
79
|
+
// MAIN ENHANCED OUTPUT
|
|
80
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Render enhanced scan output with charts and upselling
|
|
84
|
+
* @param {Object} result - Scan result
|
|
85
|
+
* @param {Object} options - Display options
|
|
86
|
+
*/
|
|
87
|
+
function renderEnhancedScanOutput(result, options = {}) {
|
|
88
|
+
const {
|
|
89
|
+
tier = 'free',
|
|
90
|
+
showCharts = true,
|
|
91
|
+
showUpsell = true,
|
|
92
|
+
baseline = null,
|
|
93
|
+
compact = false,
|
|
94
|
+
json = false,
|
|
95
|
+
} = options;
|
|
96
|
+
|
|
97
|
+
// Extract data
|
|
98
|
+
const {
|
|
99
|
+
verdict = 'WARN',
|
|
100
|
+
score = 0,
|
|
101
|
+
findings = [],
|
|
102
|
+
duration = 0,
|
|
103
|
+
filesScanned = 0,
|
|
104
|
+
projectName = '',
|
|
105
|
+
} = normalizeResult(result);
|
|
106
|
+
|
|
107
|
+
// JSON output
|
|
108
|
+
if (json) {
|
|
109
|
+
return JSON.stringify({
|
|
110
|
+
verdict,
|
|
111
|
+
score,
|
|
112
|
+
findings: findings.length,
|
|
113
|
+
duration,
|
|
114
|
+
filesScanned,
|
|
115
|
+
severityCounts: getSeverityCounts(findings),
|
|
116
|
+
}, null, 2);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Compact mode
|
|
120
|
+
if (compact) {
|
|
121
|
+
console.log(compactVerdict({ verdict, score, findings, duration }));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const lines = [];
|
|
126
|
+
const isPro = tier === 'pro';
|
|
127
|
+
const hasIssues = findings.length > 0;
|
|
128
|
+
|
|
129
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
130
|
+
// 1. VERDICT CARD
|
|
131
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
132
|
+
|
|
133
|
+
lines.push('');
|
|
134
|
+
lines.push(verdictCard({ verdict, score, findings, duration, filesScanned, projectName }));
|
|
135
|
+
|
|
136
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
137
|
+
// 2. SEVERITY DISTRIBUTION CHART
|
|
138
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
139
|
+
|
|
140
|
+
if (showCharts && hasIssues) {
|
|
141
|
+
const sevCounts = getSeverityCounts(findings);
|
|
142
|
+
|
|
143
|
+
lines.push('');
|
|
144
|
+
lines.push(renderSectionHeader('Issue Distribution', sym.chart));
|
|
145
|
+
|
|
146
|
+
// Severity bar chart
|
|
147
|
+
lines.push(horizontalBarChart([
|
|
148
|
+
{ label: 'Critical', value: sevCounts.critical, color: ansi.red },
|
|
149
|
+
{ label: 'High', value: sevCounts.high, color: ansi.yellow },
|
|
150
|
+
{ label: 'Medium', value: sevCounts.medium, color: ansi.yellow },
|
|
151
|
+
{ label: 'Low', value: sevCounts.low, color: ansi.blue },
|
|
152
|
+
].filter(item => item.value > 0), { width: 25, showPercent: true }));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
156
|
+
// 3. CATEGORY BREAKDOWN
|
|
157
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
158
|
+
|
|
159
|
+
if (showCharts && hasIssues) {
|
|
160
|
+
const categoryCounts = getCategoryCounts(findings);
|
|
161
|
+
const topCategories = Object.entries(categoryCounts)
|
|
162
|
+
.sort((a, b) => b[1] - a[1])
|
|
163
|
+
.slice(0, 5);
|
|
164
|
+
|
|
165
|
+
if (topCategories.length > 0) {
|
|
166
|
+
lines.push('');
|
|
167
|
+
lines.push(renderSectionHeader('By Category', sym.folder));
|
|
168
|
+
|
|
169
|
+
lines.push(horizontalBarChart(
|
|
170
|
+
topCategories.map(([cat, count]) => ({
|
|
171
|
+
label: formatCategory(cat),
|
|
172
|
+
value: count,
|
|
173
|
+
color: ansi.cyan,
|
|
174
|
+
})),
|
|
175
|
+
{ width: 25, showPercent: false }
|
|
176
|
+
));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
181
|
+
// 4. BASELINE COMPARISON (if available)
|
|
182
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
183
|
+
|
|
184
|
+
if (baseline && showCharts) {
|
|
185
|
+
lines.push('');
|
|
186
|
+
lines.push(renderSectionHeader('vs Previous Scan', sym.chart));
|
|
187
|
+
lines.push(comparisonCard(
|
|
188
|
+
{ score: baseline.score, findings: baseline.findings || [] },
|
|
189
|
+
{ score, findings }
|
|
190
|
+
));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
194
|
+
// 5. TOP FINDINGS TABLE
|
|
195
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
196
|
+
|
|
197
|
+
if (hasIssues) {
|
|
198
|
+
lines.push('');
|
|
199
|
+
lines.push(renderSectionHeader(`Top Issues (${Math.min(findings.length, 8)} of ${findings.length})`, sym.warning));
|
|
200
|
+
lines.push(renderFindingsTable(findings.slice(0, 8)));
|
|
201
|
+
|
|
202
|
+
if (findings.length > 8) {
|
|
203
|
+
lines.push(` ${ansi.dim}... and ${findings.length - 8} more issues${ansi.reset}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
208
|
+
// 6. PRO UPSELL SECTION
|
|
209
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
210
|
+
|
|
211
|
+
if (showUpsell && !isPro) {
|
|
212
|
+
lines.push('');
|
|
213
|
+
lines.push(renderProUpsell(findings, verdict, tier));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
217
|
+
// 7. NEXT STEPS
|
|
218
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
219
|
+
|
|
220
|
+
lines.push('');
|
|
221
|
+
lines.push(renderNextSteps(verdict, hasIssues, isPro));
|
|
222
|
+
|
|
223
|
+
// Output
|
|
224
|
+
console.log(lines.join('\n'));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
228
|
+
// PRO UPSELL
|
|
229
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
230
|
+
|
|
231
|
+
function renderProUpsell(findings, verdict, tier) {
|
|
232
|
+
const lines = [];
|
|
233
|
+
const issueCount = findings.length;
|
|
234
|
+
|
|
235
|
+
lines.push(` ${ansi.gray}${box.dTopLeft}${box.dHorizontal.repeat(WIDTH - 6)}${box.dTopRight}${ansi.reset}`);
|
|
236
|
+
lines.push(` ${ansi.gray}${box.dVertical}${ansi.reset}${' '.repeat(WIDTH - 6)}${ansi.gray}${box.dVertical}${ansi.reset}`);
|
|
237
|
+
|
|
238
|
+
// Header
|
|
239
|
+
const headerText = `${ansi.magenta}${sym.star}${ansi.reset} ${ansi.bold}UPGRADE TO PRO${ansi.reset}`;
|
|
240
|
+
lines.push(` ${ansi.gray}${box.dVertical}${ansi.reset}${center(headerText, WIDTH - 6 + 10)}${ansi.gray}${box.dVertical}${ansi.reset}`);
|
|
241
|
+
|
|
242
|
+
lines.push(` ${ansi.gray}${box.dVertical}${ansi.reset}${' '.repeat(WIDTH - 6)}${ansi.gray}${box.dVertical}${ansi.reset}`);
|
|
243
|
+
|
|
244
|
+
// Context-aware upsell messages
|
|
245
|
+
if (issueCount > 0) {
|
|
246
|
+
const fixMsg = ` Fix all ${ansi.bold}${issueCount} issues${ansi.reset} automatically with AI-powered auto-fix`;
|
|
247
|
+
lines.push(` ${ansi.gray}${box.dVertical}${ansi.reset}${fixMsg}${' '.repeat(Math.max(0, WIDTH - 6 - visibleLength(fixMsg)))}${ansi.gray}${box.dVertical}${ansi.reset}`);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
lines.push(` ${ansi.gray}${box.dVertical}${ansi.reset}${' '.repeat(WIDTH - 6)}${ansi.gray}${box.dVertical}${ansi.reset}`);
|
|
251
|
+
|
|
252
|
+
// Feature list
|
|
253
|
+
const features = [
|
|
254
|
+
`${ansi.cyan}${sym.wrench}${ansi.reset} Auto-Fix: AI applies fixes automatically`,
|
|
255
|
+
`${ansi.cyan}${sym.shield}${ansi.reset} Reality Proof: Runtime verification`,
|
|
256
|
+
`${ansi.cyan}${sym.chart}${ansi.reset} CI Integration: GitHub Actions ready`,
|
|
257
|
+
`${ansi.cyan}${sym.star}${ansi.reset} Status Badge: Show health in README`,
|
|
258
|
+
];
|
|
259
|
+
|
|
260
|
+
for (const feature of features) {
|
|
261
|
+
const featureLine = ` ${feature}`;
|
|
262
|
+
lines.push(` ${ansi.gray}${box.dVertical}${ansi.reset}${featureLine}${' '.repeat(Math.max(0, WIDTH - 6 - visibleLength(featureLine)))}${ansi.gray}${box.dVertical}${ansi.reset}`);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
lines.push(` ${ansi.gray}${box.dVertical}${ansi.reset}${' '.repeat(WIDTH - 6)}${ansi.gray}${box.dVertical}${ansi.reset}`);
|
|
266
|
+
|
|
267
|
+
// CTA
|
|
268
|
+
const ctaText = `${ansi.cyan}https://vibecheckai.dev/pricing${ansi.reset}`;
|
|
269
|
+
lines.push(` ${ansi.gray}${box.dVertical}${ansi.reset}${center(`Upgrade ${sym.arrow} ${ctaText}`, WIDTH - 6 + 10)}${ansi.gray}${box.dVertical}${ansi.reset}`);
|
|
270
|
+
|
|
271
|
+
lines.push(` ${ansi.gray}${box.dVertical}${ansi.reset}${' '.repeat(WIDTH - 6)}${ansi.gray}${box.dVertical}${ansi.reset}`);
|
|
272
|
+
lines.push(` ${ansi.gray}${box.dBottomLeft}${box.dHorizontal.repeat(WIDTH - 6)}${box.dBottomRight}${ansi.reset}`);
|
|
273
|
+
|
|
274
|
+
return lines.join('\n');
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
278
|
+
// CONTEXTUAL PRO PROMPTS (for inline use)
|
|
279
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Get contextual Pro upsell message based on current action
|
|
283
|
+
* @param {string} context - Context: 'scan', 'fix', 'ship', etc.
|
|
284
|
+
* @param {Object} data - Context data
|
|
285
|
+
*/
|
|
286
|
+
function getProPrompt(context, data = {}) {
|
|
287
|
+
const prompts = {
|
|
288
|
+
scan_issues: (count) => ({
|
|
289
|
+
message: `${ansi.magenta}${sym.star} PRO${ansi.reset} ${ansi.dim}Auto-fix ${count} issues instantly${ansi.reset}`,
|
|
290
|
+
command: 'vibecheck fix --apply',
|
|
291
|
+
cta: 'Try Pro free for 14 days',
|
|
292
|
+
}),
|
|
293
|
+
scan_clean: () => ({
|
|
294
|
+
message: `${ansi.magenta}${sym.star} PRO${ansi.reset} ${ansi.dim}Generate status badge for your README${ansi.reset}`,
|
|
295
|
+
command: 'vibecheck ship --badge',
|
|
296
|
+
cta: 'Show off your clean code',
|
|
297
|
+
}),
|
|
298
|
+
fix_plan: (count) => ({
|
|
299
|
+
message: `${ansi.magenta}${sym.star} PRO${ansi.reset} ${ansi.dim}Apply all ${count} fixes automatically${ansi.reset}`,
|
|
300
|
+
command: 'vibecheck fix --apply',
|
|
301
|
+
cta: 'Upgrade to apply fixes',
|
|
302
|
+
}),
|
|
303
|
+
ship_warn: () => ({
|
|
304
|
+
message: `${ansi.magenta}${sym.star} PRO${ansi.reset} ${ansi.dim}Get detailed fix suggestions${ansi.reset}`,
|
|
305
|
+
command: 'vibecheck fix --explain',
|
|
306
|
+
cta: 'Understand every issue',
|
|
307
|
+
}),
|
|
308
|
+
ci_setup: () => ({
|
|
309
|
+
message: `${ansi.magenta}${sym.star} PRO${ansi.reset} ${ansi.dim}Add to CI/CD pipeline${ansi.reset}`,
|
|
310
|
+
command: 'vibecheck init --ci',
|
|
311
|
+
cta: 'Automate quality checks',
|
|
312
|
+
}),
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const key = context;
|
|
316
|
+
const promptFn = prompts[key];
|
|
317
|
+
|
|
318
|
+
if (!promptFn) return null;
|
|
319
|
+
|
|
320
|
+
const prompt = typeof promptFn === 'function'
|
|
321
|
+
? promptFn(data.count || data.issueCount || 0)
|
|
322
|
+
: promptFn;
|
|
323
|
+
|
|
324
|
+
return prompt;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Render inline Pro prompt
|
|
329
|
+
* @param {string} context - Context
|
|
330
|
+
* @param {Object} data - Data
|
|
331
|
+
*/
|
|
332
|
+
function renderInlineProPrompt(context, data = {}) {
|
|
333
|
+
const prompt = getProPrompt(context, data);
|
|
334
|
+
if (!prompt) return '';
|
|
335
|
+
|
|
336
|
+
return `
|
|
337
|
+
${prompt.message}
|
|
338
|
+
${ansi.dim}${sym.arrow} ${prompt.command}${ansi.reset}
|
|
339
|
+
${ansi.dim}${prompt.cta} at ${ansi.cyan}vibecheckai.dev${ansi.reset}
|
|
340
|
+
`;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
344
|
+
// NEXT STEPS
|
|
345
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
346
|
+
|
|
347
|
+
function renderNextSteps(verdict, hasIssues, isPro) {
|
|
348
|
+
const lines = [];
|
|
349
|
+
|
|
350
|
+
lines.push(` ${ansi.cyan}${sym.pointer}${ansi.reset} ${ansi.bold}Next Steps${ansi.reset}`);
|
|
351
|
+
lines.push(` ${ansi.gray}${box.horizontal.repeat(50)}${ansi.reset}`);
|
|
352
|
+
|
|
353
|
+
if (verdict === 'SHIP' || verdict === 'PASS') {
|
|
354
|
+
lines.push(` ${ansi.green}${sym.rocket}${ansi.reset} Your code is ready to ship!`);
|
|
355
|
+
if (!isPro) {
|
|
356
|
+
lines.push(` ${ansi.dim}${sym.arrow} Run ${ansi.cyan}vibecheck ship --badge${ansi.reset}${ansi.dim} to generate a status badge${ansi.reset} ${ansi.magenta}[PRO]${ansi.reset}`);
|
|
357
|
+
}
|
|
358
|
+
lines.push(` ${ansi.dim}${sym.arrow} Run ${ansi.cyan}vibecheck guard${ansi.reset}${ansi.dim} to validate AI-generated code${ansi.reset}`);
|
|
359
|
+
} else if (hasIssues) {
|
|
360
|
+
if (!isPro) {
|
|
361
|
+
lines.push(` ${ansi.dim}${sym.arrow} Run ${ansi.cyan}vibecheck fix --plan${ansi.reset}${ansi.dim} to see fix suggestions${ansi.reset}`);
|
|
362
|
+
lines.push(` ${ansi.dim}${sym.arrow} Run ${ansi.cyan}vibecheck fix --apply${ansi.reset}${ansi.dim} to auto-fix issues${ansi.reset} ${ansi.magenta}[PRO]${ansi.reset}`);
|
|
363
|
+
} else {
|
|
364
|
+
lines.push(` ${ansi.dim}${sym.arrow} Run ${ansi.cyan}vibecheck fix --apply${ansi.reset}${ansi.dim} to auto-fix issues${ansi.reset}`);
|
|
365
|
+
}
|
|
366
|
+
lines.push(` ${ansi.dim}${sym.arrow} Run ${ansi.cyan}vibecheck scan --baseline${ansi.reset}${ansi.dim} to track progress${ansi.reset}`);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
lines.push('');
|
|
370
|
+
return lines.join('\n');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
374
|
+
// FINDINGS TABLE
|
|
375
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
376
|
+
|
|
377
|
+
function renderFindingsTable(findings) {
|
|
378
|
+
const sevIcons = {
|
|
379
|
+
critical: `${ansi.red}${sym.critical}${ansi.reset}`,
|
|
380
|
+
high: `${ansi.yellow}${sym.high}${ansi.reset}`,
|
|
381
|
+
medium: `${ansi.yellow}${sym.medium}${ansi.reset}`,
|
|
382
|
+
low: `${ansi.blue}${sym.low}${ansi.reset}`,
|
|
383
|
+
info: `${ansi.gray}${sym.info}${ansi.reset}`,
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
return renderTable({
|
|
387
|
+
columns: [
|
|
388
|
+
{
|
|
389
|
+
header: 'Sev',
|
|
390
|
+
key: 'severity',
|
|
391
|
+
width: 8,
|
|
392
|
+
format: (v) => sevIcons[v] || sevIcons.info,
|
|
393
|
+
},
|
|
394
|
+
{ header: 'Category', key: 'category', width: 14, format: formatCategory },
|
|
395
|
+
{ header: 'Issue', key: 'message', width: 45 },
|
|
396
|
+
],
|
|
397
|
+
data: findings.map(f => ({
|
|
398
|
+
severity: normalizeSeverity(f.severity),
|
|
399
|
+
category: f.category || f.type || 'Other',
|
|
400
|
+
message: f.message || f.title || f.description || '',
|
|
401
|
+
})),
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
406
|
+
// UTILITIES
|
|
407
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
408
|
+
|
|
409
|
+
function normalizeResult(result) {
|
|
410
|
+
// Handle different result structures
|
|
411
|
+
if (result.verdict && typeof result.verdict === 'object') {
|
|
412
|
+
return {
|
|
413
|
+
verdict: result.verdict.verdict || 'WARN',
|
|
414
|
+
score: result.verdict.score || calculateScore(result.findings || []),
|
|
415
|
+
findings: result.findings || [],
|
|
416
|
+
duration: result.timings?.total || result.duration || 0,
|
|
417
|
+
filesScanned: result.timings?.filesScanned || result.scannedFiles || 0,
|
|
418
|
+
projectName: result.projectName || '',
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return {
|
|
423
|
+
verdict: result.verdict || 'WARN',
|
|
424
|
+
score: result.score || calculateScore(result.findings || []),
|
|
425
|
+
findings: result.findings || [],
|
|
426
|
+
duration: result.duration || result.timings?.total || 0,
|
|
427
|
+
filesScanned: result.filesScanned || result.scannedFiles || 0,
|
|
428
|
+
projectName: result.projectName || '',
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function calculateScore(findings) {
|
|
433
|
+
if (!findings || findings.length === 0) return 100;
|
|
434
|
+
|
|
435
|
+
const deductions = findings.reduce((sum, f) => {
|
|
436
|
+
const sev = normalizeSeverity(f.severity);
|
|
437
|
+
if (sev === 'critical') return sum + 25;
|
|
438
|
+
if (sev === 'high') return sum + 15;
|
|
439
|
+
if (sev === 'medium') return sum + 5;
|
|
440
|
+
if (sev === 'low') return sum + 2;
|
|
441
|
+
return sum;
|
|
442
|
+
}, 0);
|
|
443
|
+
|
|
444
|
+
return Math.max(0, 100 - deductions);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function normalizeSeverity(severity) {
|
|
448
|
+
if (!severity) return 'medium';
|
|
449
|
+
const sev = String(severity).toLowerCase();
|
|
450
|
+
if (sev === 'block' || sev === 'critical') return 'critical';
|
|
451
|
+
if (sev === 'high') return 'high';
|
|
452
|
+
if (sev === 'warn' || sev === 'warning' || sev === 'medium') return 'medium';
|
|
453
|
+
if (sev === 'info' || sev === 'low') return 'low';
|
|
454
|
+
return 'medium';
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function getSeverityCounts(findings) {
|
|
458
|
+
const counts = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
|
|
459
|
+
|
|
460
|
+
for (const f of findings) {
|
|
461
|
+
const sev = normalizeSeverity(f.severity);
|
|
462
|
+
counts[sev] = (counts[sev] || 0) + 1;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
return counts;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function getCategoryCounts(findings) {
|
|
469
|
+
const counts = {};
|
|
470
|
+
|
|
471
|
+
for (const f of findings) {
|
|
472
|
+
const cat = f.category || f.type || f.ruleId || 'Other';
|
|
473
|
+
counts[cat] = (counts[cat] || 0) + 1;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
return counts;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function formatCategory(cat) {
|
|
480
|
+
const categoryLabels = {
|
|
481
|
+
'EnvContract': 'Env Vars',
|
|
482
|
+
'MissingRoute': 'Routes',
|
|
483
|
+
'GhostAuth': 'Auth',
|
|
484
|
+
'FakeSuccess': 'Fake APIs',
|
|
485
|
+
'MockData': 'Mock Data',
|
|
486
|
+
'Secrets': 'Secrets',
|
|
487
|
+
'ConsoleLog': 'Console',
|
|
488
|
+
'TodoFixme': 'TODOs',
|
|
489
|
+
'CodeQuality': 'Quality',
|
|
490
|
+
'Security': 'Security',
|
|
491
|
+
'Performance': 'Performance',
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
return categoryLabels[cat] || cat;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
498
|
+
// EXPORTS
|
|
499
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
500
|
+
|
|
501
|
+
module.exports = {
|
|
502
|
+
renderEnhancedScanOutput,
|
|
503
|
+
renderProUpsell,
|
|
504
|
+
renderInlineProPrompt,
|
|
505
|
+
getProPrompt,
|
|
506
|
+
renderNextSteps,
|
|
507
|
+
renderFindingsTable,
|
|
508
|
+
normalizeResult,
|
|
509
|
+
calculateScore,
|
|
510
|
+
getSeverityCounts,
|
|
511
|
+
getCategoryCounts,
|
|
512
|
+
};
|
|
@@ -510,8 +510,52 @@ function renderLayers(layers) {
|
|
|
510
510
|
return ''; // Implement if needed
|
|
511
511
|
}
|
|
512
512
|
|
|
513
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
514
|
+
// ENHANCED OUTPUT (with charts and Pro upselling)
|
|
515
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
516
|
+
|
|
517
|
+
let enhancedOutput;
|
|
518
|
+
try {
|
|
519
|
+
enhancedOutput = require('./scan-output-enhanced');
|
|
520
|
+
} catch (e) {
|
|
521
|
+
enhancedOutput = null;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Format scan output with enhanced visuals (charts, upsell)
|
|
526
|
+
* Falls back to standard output if enhanced module not available
|
|
527
|
+
*/
|
|
528
|
+
function formatScanOutputEnhanced(result, options = {}) {
|
|
529
|
+
if (enhancedOutput && !options.legacy) {
|
|
530
|
+
enhancedOutput.renderEnhancedScanOutput(result, options);
|
|
531
|
+
return ''; // Output is printed directly
|
|
532
|
+
}
|
|
533
|
+
return formatScanOutput(result, options);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Get Pro upsell prompt for current context
|
|
538
|
+
*/
|
|
539
|
+
function getProUpsellPrompt(context, data = {}) {
|
|
540
|
+
if (enhancedOutput) {
|
|
541
|
+
return enhancedOutput.getProPrompt(context, data);
|
|
542
|
+
}
|
|
543
|
+
return null;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Render inline Pro upsell
|
|
548
|
+
*/
|
|
549
|
+
function renderProUpsell(context, data = {}) {
|
|
550
|
+
if (enhancedOutput) {
|
|
551
|
+
return enhancedOutput.renderInlineProPrompt(context, data);
|
|
552
|
+
}
|
|
553
|
+
return '';
|
|
554
|
+
}
|
|
555
|
+
|
|
513
556
|
module.exports = {
|
|
514
557
|
formatScanOutput,
|
|
558
|
+
formatScanOutputEnhanced,
|
|
515
559
|
calculateScore,
|
|
516
560
|
getExitCode,
|
|
517
561
|
printError,
|
|
@@ -521,4 +565,7 @@ module.exports = {
|
|
|
521
565
|
renderBreakdown,
|
|
522
566
|
renderBlockers,
|
|
523
567
|
renderLayers,
|
|
568
|
+
// Pro upsell
|
|
569
|
+
getProUpsellPrompt,
|
|
570
|
+
renderProUpsell,
|
|
524
571
|
};
|