@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
package/bin/runners/runAuth.js
CHANGED
|
@@ -15,6 +15,8 @@ const {
|
|
|
15
15
|
} = require("./lib/auth");
|
|
16
16
|
const { EXIT } = require("./lib/exit-codes");
|
|
17
17
|
const { parseGlobalFlags, shouldSuppressOutput, isJsonMode } = require("./lib/global-flags");
|
|
18
|
+
const { getTier, getLimits, FREE_FEATURES, PRO_FEATURES } = require("./lib/entitlements-v2");
|
|
19
|
+
const { printActionableError } = require("./lib/error-messages");
|
|
18
20
|
const {
|
|
19
21
|
ansi,
|
|
20
22
|
sym,
|
|
@@ -30,9 +32,6 @@ const {
|
|
|
30
32
|
TIER,
|
|
31
33
|
} = require("./lib/unified-cli-output");
|
|
32
34
|
|
|
33
|
-
// Unified Output System
|
|
34
|
-
const { output } = require("./lib/output/index.js");
|
|
35
|
-
|
|
36
35
|
async function prompt(question) {
|
|
37
36
|
const rl = readline.createInterface({
|
|
38
37
|
input: process.stdin,
|
|
@@ -154,10 +153,10 @@ async function runLogin(args) {
|
|
|
154
153
|
if (json) {
|
|
155
154
|
console.log(JSON.stringify({ success: false, error: "Invalid API key format" }));
|
|
156
155
|
} else {
|
|
157
|
-
|
|
158
|
-
console.log(` ${ansi.dim}API keys should be at least 20 characters.${ansi.reset}`);
|
|
156
|
+
printActionableError('INVALID_API_KEY', { command: 'login' });
|
|
159
157
|
}
|
|
160
|
-
|
|
158
|
+
// Return AUTH_FAILED for invalid key format (matches test expectations)
|
|
159
|
+
return EXIT.AUTH_FAILED;
|
|
161
160
|
}
|
|
162
161
|
|
|
163
162
|
const spinner = !quiet && !json ? new Spinner("Verifying API key").start() : null;
|
|
@@ -193,25 +192,7 @@ async function runLogin(args) {
|
|
|
193
192
|
console.log(JSON.stringify(result));
|
|
194
193
|
} else if (!quiet) {
|
|
195
194
|
spinner?.succeed(`Logged in as ${ansi.bold}${result.user}${ansi.reset}`);
|
|
196
|
-
console.log(` ${ansi.dim}Plan:${ansi.reset} ${getTierBadge(result.plan)}`);
|
|
197
|
-
console.log();
|
|
198
|
-
|
|
199
|
-
// Show available features based on plan
|
|
200
|
-
const isPro = result.plan !== 'free';
|
|
201
|
-
if (isPro) {
|
|
202
|
-
console.log(` ${ansi.green}✓${ansi.reset} ${ansi.bold}PRO features unlocked:${ansi.reset}`);
|
|
203
|
-
console.log(` ${ansi.cyan}vibecheck fix${ansi.reset} ${ansi.dim}AI-powered code fixes${ansi.reset}`);
|
|
204
|
-
console.log(` ${ansi.cyan}vibecheck ship${ansi.reset} ${ansi.dim}Ship readiness + badges${ansi.reset}`);
|
|
205
|
-
console.log(` ${ansi.cyan}vibecheck prove${ansi.reset} ${ansi.dim}Runtime proof generation${ansi.reset}`);
|
|
206
|
-
console.log(` ${ansi.cyan}vibecheck mcp${ansi.reset} ${ansi.dim}Full MCP server access${ansi.reset}`);
|
|
207
|
-
} else {
|
|
208
|
-
console.log(` ${ansi.gray}╭${'─'.repeat(52)}╮${ansi.reset}`);
|
|
209
|
-
console.log(` ${ansi.gray}│${ansi.reset} ${ansi.magenta}★${ansi.reset} Upgrade to ${ansi.bold}PRO${ansi.reset} for AI fixes, ship badges, ${ansi.gray}│${ansi.reset}`);
|
|
210
|
-
console.log(` ${ansi.gray}│${ansi.reset} CI enforcement, and full MCP access ${ansi.gray}│${ansi.reset}`);
|
|
211
|
-
console.log(` ${ansi.gray}│${ansi.reset} ${ansi.cyan}vibecheck upgrade${ansi.reset} or ${ansi.dim}vibecheckai.dev/pricing${ansi.reset} ${ansi.gray}│${ansi.reset}`);
|
|
212
|
-
console.log(` ${ansi.gray}╰${'─'.repeat(52)}╯${ansi.reset}`);
|
|
213
|
-
}
|
|
214
|
-
console.log();
|
|
195
|
+
console.log(` ${ansi.dim}Plan:${ansi.reset} ${getTierBadge(result.plan)}\n`);
|
|
215
196
|
}
|
|
216
197
|
|
|
217
198
|
return EXIT.SUCCESS;
|
|
@@ -310,10 +291,16 @@ async function runWhoami(args) {
|
|
|
310
291
|
const { key, source } = getApiKey();
|
|
311
292
|
|
|
312
293
|
if (!key) {
|
|
313
|
-
const result =
|
|
294
|
+
const result = json ? {
|
|
295
|
+
success: false,
|
|
296
|
+
error: {
|
|
297
|
+
code: "AUTH_REQUIRED",
|
|
298
|
+
message: "Not logged in",
|
|
299
|
+
},
|
|
300
|
+
} : { authenticated: false, message: "Not logged in" };
|
|
314
301
|
|
|
315
302
|
if (json) {
|
|
316
|
-
console.log(JSON.stringify(result));
|
|
303
|
+
console.log(JSON.stringify(result, null, 2));
|
|
317
304
|
} else {
|
|
318
305
|
renderWarning("Not logged in");
|
|
319
306
|
console.log(` ${ansi.dim}Run "vibecheck login" or set VIBECHECK_API_KEY.${ansi.reset}\n`);
|
|
@@ -329,7 +316,13 @@ async function runWhoami(args) {
|
|
|
329
316
|
} catch (apiError) {
|
|
330
317
|
spinner?.fail(`Failed to fetch: ${apiError.message}`);
|
|
331
318
|
if (json) {
|
|
332
|
-
console.log(JSON.stringify({
|
|
319
|
+
console.log(JSON.stringify({
|
|
320
|
+
success: false,
|
|
321
|
+
error: {
|
|
322
|
+
code: "NETWORK_ERROR",
|
|
323
|
+
message: apiError.message,
|
|
324
|
+
},
|
|
325
|
+
}, null, 2));
|
|
333
326
|
}
|
|
334
327
|
return EXIT.NETWORK_ERROR;
|
|
335
328
|
}
|
|
@@ -337,7 +330,13 @@ async function runWhoami(args) {
|
|
|
337
330
|
if (!entitlements) {
|
|
338
331
|
spinner?.fail("Invalid API key or server unreachable");
|
|
339
332
|
if (json) {
|
|
340
|
-
console.log(JSON.stringify({
|
|
333
|
+
console.log(JSON.stringify({
|
|
334
|
+
success: false,
|
|
335
|
+
error: {
|
|
336
|
+
code: "AUTH_FAILED",
|
|
337
|
+
message: "Invalid API key",
|
|
338
|
+
},
|
|
339
|
+
}, null, 2));
|
|
341
340
|
} else {
|
|
342
341
|
console.log(` ${ansi.dim}Run "vibecheck login" to re-authenticate.${ansi.reset}\n`);
|
|
343
342
|
}
|
|
@@ -346,16 +345,38 @@ async function runWhoami(args) {
|
|
|
346
345
|
|
|
347
346
|
spinner?.stop(null, null, null); // Clear spinner without message
|
|
348
347
|
|
|
348
|
+
// Determine tier (map plan to tier)
|
|
349
|
+
const plan = entitlements.plan || entitlements.tier || "free";
|
|
350
|
+
const tier = plan === "free" ? "free" : "pro";
|
|
351
|
+
|
|
352
|
+
// Get features available for this tier
|
|
353
|
+
const features = tier === "pro" ? PRO_FEATURES : FREE_FEATURES;
|
|
354
|
+
|
|
355
|
+
// Get limits for this tier
|
|
356
|
+
const tierLimits = getLimits(tier);
|
|
357
|
+
|
|
358
|
+
// Build result object
|
|
349
359
|
const result = {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
360
|
+
success: true,
|
|
361
|
+
data: {
|
|
362
|
+
user: {
|
|
363
|
+
id: entitlements.user?.id || entitlements.userId,
|
|
364
|
+
email: entitlements.user?.email || entitlements.email,
|
|
365
|
+
name: entitlements.user?.name,
|
|
366
|
+
},
|
|
367
|
+
tier: tier,
|
|
368
|
+
features: features,
|
|
369
|
+
limits: {
|
|
370
|
+
scansPerMonth: entitlements.limits?.scansPerMonth ?? tierLimits.maxScansPerMonth,
|
|
371
|
+
filesPerScan: entitlements.limits?.filesPerScan ?? tierLimits.maxFilesPerScan,
|
|
372
|
+
reportFormats: tierLimits.reportFormats,
|
|
373
|
+
},
|
|
374
|
+
usage: {
|
|
375
|
+
scansThisMonth: entitlements.usage?.scansThisMonth || 0,
|
|
376
|
+
filesScanned: entitlements.usage?.filesScanned || 0,
|
|
377
|
+
},
|
|
355
378
|
},
|
|
356
|
-
|
|
357
|
-
limits: entitlements.limits,
|
|
358
|
-
scopes: entitlements.scopes,
|
|
379
|
+
timestamp: new Date().toISOString(),
|
|
359
380
|
};
|
|
360
381
|
|
|
361
382
|
if (json) {
|
|
@@ -364,27 +385,28 @@ async function runWhoami(args) {
|
|
|
364
385
|
renderSectionHeader("Account", sym.key);
|
|
365
386
|
|
|
366
387
|
renderKeyValue([
|
|
367
|
-
{ label: "User", value: `${ansi.bold}${result.user.name}${ansi.reset} ${ansi.dim}(${result.user.id})${ansi.reset}` },
|
|
368
|
-
{ label: "
|
|
388
|
+
{ label: "User", value: `${ansi.bold}${result.data.user.name || 'Unknown'}${ansi.reset} ${ansi.dim}(${result.data.user.id || 'N/A'})${ansi.reset}` },
|
|
389
|
+
{ label: "Tier", value: getTierBadge(tier) },
|
|
369
390
|
{ label: "Source", value: source === "env" ? "Environment Variable" : "Local Config" },
|
|
370
|
-
{ label: "
|
|
391
|
+
{ label: "Scans this month", value: `${result.data.usage.scansThisMonth}/${result.data.limits.scansPerMonth === -1 ? '∞' : result.data.limits.scansPerMonth}` },
|
|
371
392
|
]);
|
|
372
393
|
|
|
373
|
-
|
|
394
|
+
const scopes = entitlements.scopes || [];
|
|
395
|
+
if (scopes.length > 0) {
|
|
374
396
|
console.log();
|
|
375
397
|
console.log(` ${ansi.dim}Scopes:${ansi.reset}`);
|
|
376
|
-
|
|
398
|
+
scopes.forEach(s => console.log(` ${ansi.gray}${sym.bullet}${ansi.reset} ${s}`));
|
|
377
399
|
}
|
|
378
400
|
|
|
379
401
|
// Tier-specific upsell
|
|
380
|
-
if (
|
|
402
|
+
if (tier === "free") {
|
|
381
403
|
renderFooter({
|
|
382
404
|
nextSteps: [
|
|
383
405
|
{ cmd: "vibecheck scan", desc: "analyze your codebase" },
|
|
384
406
|
],
|
|
385
407
|
showUpsell: true,
|
|
386
408
|
});
|
|
387
|
-
} else if (
|
|
409
|
+
} else if (plan === "starter") {
|
|
388
410
|
console.log();
|
|
389
411
|
console.log(` ${ansi.dim}${sym.star}${ansi.reset} ${ansi.magenta}PRO${ansi.reset}${ansi.dim}: proof loops + badge generation + priority support${ansi.reset}`);
|
|
390
412
|
console.log(` ${ansi.dim} Upgrade ${sym.arrow} https://vibecheckai.dev${ansi.reset}\n`);
|
|
@@ -396,7 +418,13 @@ async function runWhoami(args) {
|
|
|
396
418
|
return EXIT.SUCCESS;
|
|
397
419
|
} catch (error) {
|
|
398
420
|
if (json) {
|
|
399
|
-
console.log(JSON.stringify({
|
|
421
|
+
console.log(JSON.stringify({
|
|
422
|
+
success: false,
|
|
423
|
+
error: {
|
|
424
|
+
code: error.code || "INTERNAL_ERROR",
|
|
425
|
+
message: error.message,
|
|
426
|
+
},
|
|
427
|
+
}, null, 2));
|
|
400
428
|
} else {
|
|
401
429
|
renderError(`Whoami failed: ${error.message}`);
|
|
402
430
|
}
|
|
@@ -15,15 +15,37 @@ const path = require("path");
|
|
|
15
15
|
const entitlements = require("./lib/entitlements-v2");
|
|
16
16
|
const { parseGlobalFlags, shouldShowBanner, shouldSuppressOutput, isJsonMode } = require("./lib/global-flags");
|
|
17
17
|
const { EXIT } = require("./lib/exit-codes");
|
|
18
|
+
const { ensureScanResults } = require("./lib/prerequisites");
|
|
19
|
+
const { printActionableError } = require("./lib/error-messages");
|
|
18
20
|
|
|
19
21
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
20
|
-
// TERMINAL
|
|
22
|
+
// TERMINAL STYLING
|
|
21
23
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
22
24
|
|
|
23
|
-
const
|
|
25
|
+
const c = {
|
|
26
|
+
reset: '\x1b[0m',
|
|
27
|
+
bold: '\x1b[1m',
|
|
28
|
+
dim: '\x1b[2m',
|
|
29
|
+
red: '\x1b[31m',
|
|
30
|
+
green: '\x1b[32m',
|
|
31
|
+
yellow: '\x1b[33m',
|
|
32
|
+
blue: '\x1b[34m',
|
|
33
|
+
magenta: '\x1b[35m',
|
|
34
|
+
cyan: '\x1b[36m',
|
|
35
|
+
};
|
|
24
36
|
|
|
25
|
-
|
|
26
|
-
|
|
37
|
+
const icons = {
|
|
38
|
+
check: '✓',
|
|
39
|
+
cross: '✗',
|
|
40
|
+
arrow: '→',
|
|
41
|
+
warning: '⚠',
|
|
42
|
+
info: 'ℹ',
|
|
43
|
+
star: '★',
|
|
44
|
+
rocket: '🚀',
|
|
45
|
+
target: '🎯',
|
|
46
|
+
chart: '📊',
|
|
47
|
+
brain: '🧠',
|
|
48
|
+
};
|
|
27
49
|
|
|
28
50
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
29
51
|
// CHECKPOINT CORE
|
|
@@ -280,7 +302,7 @@ async function runCheckpoint(args) {
|
|
|
280
302
|
if (json) {
|
|
281
303
|
console.log(JSON.stringify({ success: false, error: `Project path does not exist: ${projectPath}` }));
|
|
282
304
|
} else {
|
|
283
|
-
|
|
305
|
+
printActionableError('PROJECT_PATH_NOT_FOUND', { command: 'checkpoint', path: projectPath });
|
|
284
306
|
}
|
|
285
307
|
return EXIT.NOT_FOUND;
|
|
286
308
|
}
|
|
@@ -333,13 +355,31 @@ async function runCheckpoint(args) {
|
|
|
333
355
|
}
|
|
334
356
|
|
|
335
357
|
if (!current) {
|
|
336
|
-
if (
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
358
|
+
// Auto-run scan if results are missing (unless in CI or explicitly disabled)
|
|
359
|
+
if (!opts.ci && !opts.noAutoRun && !process.env.CI) {
|
|
360
|
+
const scanPrereq = await ensureScanResults(projectPath, {
|
|
361
|
+
quiet,
|
|
362
|
+
json,
|
|
363
|
+
ci: opts.ci,
|
|
364
|
+
colors: c,
|
|
365
|
+
icons,
|
|
366
|
+
ansi: c,
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
if (scanPrereq.success) {
|
|
370
|
+
// Reload after scan
|
|
371
|
+
current = loadResults(latestPath);
|
|
372
|
+
}
|
|
341
373
|
}
|
|
342
|
-
|
|
374
|
+
|
|
375
|
+
if (!current) {
|
|
376
|
+
if (json) {
|
|
377
|
+
console.log(JSON.stringify({ success: false, error: "No current results found" }));
|
|
378
|
+
} else if (!quiet) {
|
|
379
|
+
printActionableError('NO_SCAN_RESULTS', { command: 'checkpoint' });
|
|
380
|
+
}
|
|
381
|
+
return EXIT.NOT_FOUND;
|
|
382
|
+
}
|
|
343
383
|
}
|
|
344
384
|
|
|
345
385
|
// Extract findings arrays
|
|
@@ -19,6 +19,14 @@ const { withErrorHandling, createUserError } = require("./lib/error-handler");
|
|
|
19
19
|
const { parseGlobalFlags, shouldShowBanner } = require("./lib/global-flags");
|
|
20
20
|
const { EXIT } = require("./lib/exit-codes");
|
|
21
21
|
|
|
22
|
+
// Engine V2 support (when VIBECHECK_ENGINE_V2=1)
|
|
23
|
+
let createIndex = null;
|
|
24
|
+
try {
|
|
25
|
+
createIndex = require("./lib/engine").createIndex;
|
|
26
|
+
} catch {
|
|
27
|
+
// Engine V2 not available, use legacy file walking
|
|
28
|
+
}
|
|
29
|
+
|
|
22
30
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
23
31
|
// TERMINAL UI
|
|
24
32
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -29,9 +37,6 @@ const {
|
|
|
29
37
|
Spinner,
|
|
30
38
|
} = require("./lib/terminal-ui");
|
|
31
39
|
|
|
32
|
-
// Unified Output System
|
|
33
|
-
const { output } = require("./lib/output/index.js");
|
|
34
|
-
|
|
35
40
|
const BANNER = `
|
|
36
41
|
${ansi.rgb(0, 200, 255)} ██╗ ██╗██╗██████╗ ███████╗ ██████╗██╗ ██╗███████╗ ██████╗██╗ ██╗${ansi.reset}
|
|
37
42
|
${ansi.rgb(30, 180, 255)} ██║ ██║██║██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔════╝██║ ██╔╝${ansi.reset}
|
|
@@ -218,12 +223,34 @@ const EXCLUDED_DIRS = new Set([
|
|
|
218
223
|
]);
|
|
219
224
|
|
|
220
225
|
/**
|
|
221
|
-
* Find all source files
|
|
226
|
+
* Find all source files using RepoIndex (V2) or legacy walk
|
|
222
227
|
*/
|
|
223
228
|
async function findSourceFiles(rootPath, maxFiles) {
|
|
224
|
-
const files = [];
|
|
225
229
|
const extensions = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']);
|
|
226
230
|
|
|
231
|
+
// Use RepoIndex if V2 is enabled and available
|
|
232
|
+
if (process.env.VIBECHECK_ENGINE_V2 === "1" && createIndex) {
|
|
233
|
+
const index = await createIndex(rootPath);
|
|
234
|
+
const jsFiles = index.getJsFiles();
|
|
235
|
+
|
|
236
|
+
const files = jsFiles
|
|
237
|
+
.slice(0, maxFiles)
|
|
238
|
+
.map(f => ({
|
|
239
|
+
path: f.abs,
|
|
240
|
+
relativePath: f.rel,
|
|
241
|
+
name: path.basename(f.abs),
|
|
242
|
+
ext: f.ext,
|
|
243
|
+
_indexContent: index.getContent(f.abs), // Cache content from index
|
|
244
|
+
}));
|
|
245
|
+
|
|
246
|
+
// Store index reference for cleanup
|
|
247
|
+
files._index = index;
|
|
248
|
+
return files;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Legacy file walking
|
|
252
|
+
const files = [];
|
|
253
|
+
|
|
227
254
|
async function walk(dir, depth = 0) {
|
|
228
255
|
if (depth > 20 || files.length >= maxFiles) return;
|
|
229
256
|
|
|
@@ -377,7 +404,7 @@ async function runInventoryAnalysis(projectPath, opts, spinner) {
|
|
|
377
404
|
const startTime = Date.now();
|
|
378
405
|
|
|
379
406
|
// Find source files
|
|
380
|
-
spinner.update('Discovering source files...');
|
|
407
|
+
if (spinner) spinner.update('Discovering source files...');
|
|
381
408
|
const files = await findSourceFiles(projectPath, opts.maxFiles);
|
|
382
409
|
|
|
383
410
|
if (files.length === 0) {
|
|
@@ -395,16 +422,17 @@ async function runInventoryAnalysis(projectPath, opts, spinner) {
|
|
|
395
422
|
};
|
|
396
423
|
}
|
|
397
424
|
|
|
398
|
-
spinner.update(`Analyzing ${files.length} files...`);
|
|
425
|
+
if (spinner) spinner.update(`Analyzing ${files.length} files...`);
|
|
399
426
|
|
|
400
|
-
// Read all file contents
|
|
427
|
+
// Read all file contents (use cached content from RepoIndex when available)
|
|
401
428
|
const fileContents = new Map();
|
|
402
429
|
const fileHashes = new Map();
|
|
403
430
|
const normalizedHashes = new Map();
|
|
404
431
|
|
|
405
432
|
for (const file of files) {
|
|
406
433
|
try {
|
|
407
|
-
|
|
434
|
+
// Use cached content from RepoIndex if available (V2 optimization)
|
|
435
|
+
const content = file._indexContent || await fs.promises.readFile(file.path, 'utf-8');
|
|
408
436
|
const lines = content.split('\n').length;
|
|
409
437
|
fileContents.set(file.relativePath, { content, lines });
|
|
410
438
|
|
|
@@ -419,11 +447,16 @@ async function runInventoryAnalysis(projectPath, opts, spinner) {
|
|
|
419
447
|
}
|
|
420
448
|
}
|
|
421
449
|
|
|
450
|
+
// Cleanup RepoIndex cache if used
|
|
451
|
+
if (files._index) {
|
|
452
|
+
files._index.clearContentCache();
|
|
453
|
+
}
|
|
454
|
+
|
|
422
455
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
423
456
|
// DUPLICATE DETECTION
|
|
424
457
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
425
458
|
|
|
426
|
-
spinner.update('Detecting duplicates...');
|
|
459
|
+
if (spinner) spinner.update('Detecting duplicates...');
|
|
427
460
|
|
|
428
461
|
const duplicationMap = [];
|
|
429
462
|
const exactDuplicates = new Map(); // hash -> [files]
|
|
@@ -493,7 +526,7 @@ async function runInventoryAnalysis(projectPath, opts, spinner) {
|
|
|
493
526
|
|
|
494
527
|
// Semantic duplicates (token-based similarity)
|
|
495
528
|
if (opts.includeSemantic) {
|
|
496
|
-
spinner.update('Computing semantic similarity...');
|
|
529
|
+
if (spinner) spinner.update('Computing semantic similarity...');
|
|
497
530
|
|
|
498
531
|
const tokenSets = new Map();
|
|
499
532
|
for (const [filePath, { content }] of fileContents.entries()) {
|
|
@@ -543,7 +576,7 @@ async function runInventoryAnalysis(projectPath, opts, spinner) {
|
|
|
543
576
|
// LEGACY CODE DETECTION
|
|
544
577
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
545
578
|
|
|
546
|
-
spinner.update('Detecting legacy code...');
|
|
579
|
+
if (spinner) spinner.update('Detecting legacy code...');
|
|
547
580
|
|
|
548
581
|
const legacyMap = [];
|
|
549
582
|
|
|
@@ -567,7 +600,7 @@ async function runInventoryAnalysis(projectPath, opts, spinner) {
|
|
|
567
600
|
// RISK CLASSIFICATION
|
|
568
601
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
569
602
|
|
|
570
|
-
spinner.update('Classifying risk levels...');
|
|
603
|
+
if (spinner) spinner.update('Classifying risk levels...');
|
|
571
604
|
|
|
572
605
|
const riskClassifications = [];
|
|
573
606
|
|
|
@@ -789,8 +822,14 @@ async function runClassify(args) {
|
|
|
789
822
|
return 0;
|
|
790
823
|
}
|
|
791
824
|
|
|
792
|
-
//
|
|
793
|
-
if (
|
|
825
|
+
// CRITICAL: Check for JSON output FIRST - skip all banners/output if this flag is set
|
|
826
|
+
if (opts.json) {
|
|
827
|
+
process.env.NO_COLOR = '1';
|
|
828
|
+
// Skip all banner/output until we output JSON
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// Print banner (skip if JSON mode)
|
|
832
|
+
if (shouldShowBanner(opts) && !opts.json) {
|
|
794
833
|
printBanner();
|
|
795
834
|
}
|
|
796
835
|
|
|
@@ -801,20 +840,22 @@ async function runClassify(args) {
|
|
|
801
840
|
throw createUserError(`Project path does not exist: ${projectPath}`, "ValidationError");
|
|
802
841
|
}
|
|
803
842
|
|
|
804
|
-
if (!opts.quiet) {
|
|
843
|
+
if (!opts.quiet && !opts.json) {
|
|
805
844
|
console.log(` ${ansi.dim}Project:${ansi.reset} ${ansi.bold}${path.basename(projectPath)}${ansi.reset}`);
|
|
806
845
|
console.log(` ${ansi.dim}Authority:${ansi.reset} ${colors.accent}inventory${ansi.reset} (FREE tier)`);
|
|
807
846
|
console.log();
|
|
808
847
|
}
|
|
809
848
|
|
|
810
|
-
// Run analysis
|
|
811
|
-
const spinner = new Spinner({ color: colors.primary });
|
|
812
|
-
spinner.start('Starting inventory analysis...');
|
|
849
|
+
// Run analysis (skip spinner if JSON mode)
|
|
850
|
+
const spinner = !opts.json ? new Spinner({ color: colors.primary }) : null;
|
|
851
|
+
if (spinner) spinner.start('Starting inventory analysis...');
|
|
813
852
|
|
|
814
853
|
try {
|
|
815
854
|
const result = await runInventoryAnalysis(projectPath, opts, spinner);
|
|
816
855
|
|
|
817
|
-
spinner
|
|
856
|
+
if (spinner) {
|
|
857
|
+
spinner.succeed(`Analysis complete (${result.summary.analysisTimeMs}ms)`);
|
|
858
|
+
}
|
|
818
859
|
|
|
819
860
|
// Construct full output
|
|
820
861
|
const output = {
|
|
@@ -828,7 +869,11 @@ async function runClassify(args) {
|
|
|
828
869
|
|
|
829
870
|
// Output based on format
|
|
830
871
|
if (opts.json) {
|
|
872
|
+
// CRITICAL: Output ONLY JSON, no banners/colors
|
|
873
|
+
process.env.NO_COLOR = '1';
|
|
831
874
|
console.log(JSON.stringify(output, null, 2));
|
|
875
|
+
// Exit immediately after JSON output
|
|
876
|
+
return EXIT.SUCCESS;
|
|
832
877
|
} else if (opts.format === 'markdown') {
|
|
833
878
|
console.log(formatMarkdownOutput(result, projectPath));
|
|
834
879
|
} else {
|
|
@@ -852,7 +897,26 @@ async function runClassify(args) {
|
|
|
852
897
|
return EXIT.SUCCESS;
|
|
853
898
|
|
|
854
899
|
} catch (error) {
|
|
855
|
-
spinner
|
|
900
|
+
if (spinner && !opts.json) {
|
|
901
|
+
spinner.fail(`Analysis failed: ${error.message}`);
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
// JSON error output
|
|
905
|
+
if (opts.json) {
|
|
906
|
+
process.env.NO_COLOR = '1';
|
|
907
|
+
const errorOutput = {
|
|
908
|
+
success: false,
|
|
909
|
+
error: {
|
|
910
|
+
code: error.code || 'CLASSIFY_ERROR',
|
|
911
|
+
message: error.message,
|
|
912
|
+
},
|
|
913
|
+
exitCode: error.code === 'VALIDATION_ERROR' ? EXIT.USER_ERROR : EXIT.INTERNAL_ERROR
|
|
914
|
+
};
|
|
915
|
+
console.log(JSON.stringify(errorOutput, null, 2));
|
|
916
|
+
process.exit(errorOutput.exitCode);
|
|
917
|
+
return errorOutput.exitCode;
|
|
918
|
+
}
|
|
919
|
+
|
|
856
920
|
throw error;
|
|
857
921
|
}
|
|
858
922
|
}
|
|
@@ -24,9 +24,6 @@ const {
|
|
|
24
24
|
getTierFromKey,
|
|
25
25
|
} = require("./lib/unified-cli-output");
|
|
26
26
|
|
|
27
|
-
// Unified Output System
|
|
28
|
-
const { output } = require("./lib/output/index.js");
|
|
29
|
-
|
|
30
27
|
async function runContext(args) {
|
|
31
28
|
const { flags: globalFlags, cleanArgs } = parseGlobalFlags(args);
|
|
32
29
|
const quiet = shouldSuppressOutput(globalFlags);
|
package/bin/runners/runDoctor.js
CHANGED
|
@@ -24,15 +24,44 @@ const { formatWorkflowUpsell } = require("./lib/upsell");
|
|
|
24
24
|
const { getApiKey } = require("./lib/auth");
|
|
25
25
|
|
|
26
26
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
27
|
-
// TERMINAL
|
|
27
|
+
// ADVANCED TERMINAL - ANSI CODES & UTILITIES
|
|
28
28
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
29
29
|
|
|
30
|
-
const
|
|
30
|
+
const c = {
|
|
31
|
+
reset: '\x1b[0m',
|
|
32
|
+
bold: '\x1b[1m',
|
|
33
|
+
dim: '\x1b[2m',
|
|
34
|
+
italic: '\x1b[3m',
|
|
35
|
+
underline: '\x1b[4m',
|
|
36
|
+
// Colors
|
|
37
|
+
black: '\x1b[30m',
|
|
38
|
+
red: '\x1b[31m',
|
|
39
|
+
green: '\x1b[32m',
|
|
40
|
+
yellow: '\x1b[33m',
|
|
41
|
+
blue: '\x1b[34m',
|
|
42
|
+
magenta: '\x1b[35m',
|
|
43
|
+
cyan: '\x1b[36m',
|
|
44
|
+
white: '\x1b[37m',
|
|
45
|
+
// Bright colors
|
|
46
|
+
gray: '\x1b[90m',
|
|
47
|
+
brightRed: '\x1b[91m',
|
|
48
|
+
brightGreen: '\x1b[92m',
|
|
49
|
+
brightYellow: '\x1b[93m',
|
|
50
|
+
brightBlue: '\x1b[94m',
|
|
51
|
+
brightMagenta: '\x1b[95m',
|
|
52
|
+
brightCyan: '\x1b[96m',
|
|
53
|
+
brightWhite: '\x1b[97m',
|
|
54
|
+
// Cursor control
|
|
55
|
+
clearLine: '\x1b[2K',
|
|
56
|
+
hideCursor: '\x1b[?25l',
|
|
57
|
+
showCursor: '\x1b[?25h',
|
|
58
|
+
};
|
|
31
59
|
|
|
32
|
-
//
|
|
33
|
-
const
|
|
60
|
+
// 256-color / True color support
|
|
61
|
+
const rgb = (r, g, b) => `\x1b[38;2;${r};${g};${b}m`;
|
|
62
|
+
const bgRgb = (r, g, b) => `\x1b[48;2;${r};${g};${b}m`;
|
|
34
63
|
|
|
35
|
-
//
|
|
64
|
+
// Premium color palette
|
|
36
65
|
const colors = {
|
|
37
66
|
// Gradients for banner
|
|
38
67
|
gradient1: rgb(100, 200, 255), // Light blue
|
|
@@ -276,13 +305,6 @@ async function runDoctor(args, context = {}) {
|
|
|
276
305
|
const json = isJsonMode(opts);
|
|
277
306
|
const executionStart = Date.now();
|
|
278
307
|
|
|
279
|
-
// Configure unified output mode
|
|
280
|
-
output.setMode({
|
|
281
|
-
json: json,
|
|
282
|
-
quiet: quiet,
|
|
283
|
-
ci: opts.ci
|
|
284
|
-
});
|
|
285
|
-
|
|
286
308
|
if (opts.help) {
|
|
287
309
|
printHelp(shouldShowBanner(opts));
|
|
288
310
|
return EXIT.SUCCESS;
|
|
@@ -581,20 +603,14 @@ function runDoctorLegacy() {
|
|
|
581
603
|
|
|
582
604
|
// Get tier for upsell
|
|
583
605
|
const { key } = getApiKey();
|
|
584
|
-
const currentTier = key ? "
|
|
606
|
+
const currentTier = key ? "starter" : "free";
|
|
585
607
|
|
|
586
608
|
if (hasIssues) {
|
|
587
609
|
console.log(" ❌ Issues found. Fix them and run doctor again.");
|
|
588
610
|
console.log();
|
|
589
|
-
|
|
611
|
+
console.log(` ${c.dim}Need help?${c.reset} ${colors.accent}vibecheck fix${c.reset} ${c.dim}can auto-repair many issues${c.reset}`);
|
|
590
612
|
if (currentTier === "free") {
|
|
591
|
-
console.log(` ${c.
|
|
592
|
-
console.log(` ${c.gray}│${c.reset} ${c.magenta}★ PRO${c.reset} Auto-fix environment issues with AI ${c.gray}│${c.reset}`);
|
|
593
|
-
console.log(` ${c.gray}│${c.reset} ${c.cyan}vibecheck fix${c.reset} can auto-repair many issues ${c.gray}│${c.reset}`);
|
|
594
|
-
console.log(` ${c.gray}│${c.reset} ${c.dim}https://vibecheckai.dev/pricing${c.reset} ${c.gray}│${c.reset}`);
|
|
595
|
-
console.log(` ${c.gray}╰${'─'.repeat(58)}╯${c.reset}`);
|
|
596
|
-
} else {
|
|
597
|
-
console.log(` ${c.dim}Need help?${c.reset} ${colors.accent}vibecheck fix${c.reset} ${c.dim}can auto-repair many issues${c.reset}`);
|
|
613
|
+
console.log(` ${c.dim}Requires STARTER plan • vibecheckai.dev${c.reset}`);
|
|
598
614
|
}
|
|
599
615
|
console.log();
|
|
600
616
|
return EXIT.BLOCKING;
|
|
@@ -602,13 +618,10 @@ function runDoctorLegacy() {
|
|
|
602
618
|
console.log(" ✅ Environment healthy!");
|
|
603
619
|
console.log();
|
|
604
620
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
console.log(` ${
|
|
609
|
-
console.log(` ${c.gray}│${c.reset} ${c.magenta}★ PRO${c.reset} AI-powered fixes, CI gates, ship badges ${c.gray}│${c.reset}`);
|
|
610
|
-
console.log(` ${c.gray}│${c.reset} ${c.dim}https://vibecheckai.dev/pricing${c.reset} ${c.gray}│${c.reset}`);
|
|
611
|
-
console.log(` ${c.gray}╰${'─'.repeat(58)}╯${c.reset}`);
|
|
621
|
+
// Workflow upsell
|
|
622
|
+
const workflow = formatWorkflowUpsell("doctor", currentTier);
|
|
623
|
+
if (workflow) {
|
|
624
|
+
console.log(` ${workflow}`);
|
|
612
625
|
} else {
|
|
613
626
|
console.log(` ${c.dim}Ready to scan?${c.reset} ${colors.accent}vibecheck scan${c.reset} ${c.dim}finds AI mistakes before they ship${c.reset}`);
|
|
614
627
|
}
|