@vibecheckai/cli 3.5.5 → 3.6.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.
@@ -39,6 +39,9 @@ const { EXIT, verdictToExitCode } = require('./lib/exit-codes');
39
39
  const entitlements = require('./lib/entitlements-v2');
40
40
  const upsell = require('./lib/upsell');
41
41
 
42
+ // Mission Control output formatter
43
+ const { formatFixOutput } = require('./lib/fix-output');
44
+
42
45
  // ═══════════════════════════════════════════════════════════════════════════════
43
46
  // ADVANCED TERMINAL - ANSI CODES & UTILITIES
44
47
  // ═══════════════════════════════════════════════════════════════════════════════
@@ -539,12 +542,19 @@ async function runFix(args) {
539
542
  stopSpinner('Codebase analyzed', true);
540
543
 
541
544
  if (first.verdict === "SHIP") {
542
- printSection('STATUS', ICONS.rocket);
543
- console.log();
544
- console.log(` ${colors.shipGreen}${ICONS.sparkle}${c.reset} ${c.bold}Already SHIP!${c.reset} No fixes needed.`);
545
- console.log();
546
- printDivider('═', 69, colors.shipGreen);
547
- console.log();
545
+ // Mission Control output
546
+ if (!opts.json && !opts.quiet) {
547
+ console.log(formatFixOutput({
548
+ missions: [],
549
+ verdict: first.verdict,
550
+ beforeVerdict: first.verdict,
551
+ afterVerdict: first.verdict,
552
+ appliedMissions: 0,
553
+ totalMissions: 0,
554
+ duration: 0,
555
+ success: true,
556
+ }, { apply: opts.apply, promptOnly: opts.promptOnly, loop: opts.loop || opts.autopilot }));
557
+ }
548
558
  return 0;
549
559
  }
550
560
 
@@ -610,11 +620,6 @@ async function runFix(args) {
610
620
 
611
621
  if (before.verdict === "SHIP") {
612
622
  const duration = Date.now() - startTime;
613
- printSection('MISSION COMPLETE', ICONS.rocket);
614
- console.log();
615
- console.log(` ${colors.shipGreen}${ICONS.sparkle}${c.reset} ${c.bold}SHIP achieved in ${step - 1} steps!${c.reset}`);
616
- console.log(` ${c.dim}Duration: ${formatDuration(duration)}${c.reset}`);
617
- console.log();
618
623
 
619
624
  // Generate share bundle if requested
620
625
  if (opts.share) {
@@ -622,15 +627,25 @@ async function runFix(args) {
622
627
  startSpinner('Generating share bundle...', 'dots');
623
628
  const shareResult = buildSharePack({ repoRoot: root, missionDirAbs: outDir });
624
629
  stopSpinner('Share bundle generated', true);
625
- console.log(` ${ICONS.package} ${colors.accent}${path.relative(root, shareResult.outputDir)}${c.reset}`);
626
630
  } catch (e) {
627
631
  stopSpinner('Share bundle failed', false);
628
- console.log(` ${c.dim}${e.message}${c.reset}`);
629
632
  }
630
633
  }
631
634
 
632
- printDivider('═', 69, colors.shipGreen);
633
- console.log();
635
+ // Mission Control output
636
+ if (!opts.json && !opts.quiet) {
637
+ console.log(formatFixOutput({
638
+ missions,
639
+ verdict: before.verdict,
640
+ beforeVerdict: first.verdict,
641
+ afterVerdict: before.verdict,
642
+ appliedMissions: step - 1,
643
+ totalMissions: missions.length,
644
+ duration,
645
+ success: true,
646
+ }, { apply: opts.apply, promptOnly: opts.promptOnly, loop: opts.loop || opts.autopilot }));
647
+ }
648
+
634
649
  return 0;
635
650
  }
636
651
 
@@ -802,11 +817,7 @@ async function runFix(args) {
802
817
 
803
818
  // Max steps reached
804
819
  const duration = Date.now() - startTime;
805
- printSection('MAX STEPS', ICONS.warning);
806
- console.log();
807
- console.log(` ${colors.warnAmber}${ICONS.warning}${c.reset} Max steps reached (${maxSteps})`);
808
- console.log(` ${c.dim}Duration: ${formatDuration(duration)}${c.reset}`);
809
- console.log();
820
+ const lastShip = await shipCore({ repoRoot: root, fastifyEntry: opts.fastifyEntry, noWrite: false });
810
821
 
811
822
  // Generate share bundle if requested
812
823
  if (opts.share) {
@@ -814,13 +825,25 @@ async function runFix(args) {
814
825
  startSpinner('Generating share bundle...', 'dots');
815
826
  const shareResult = buildSharePack({ repoRoot: root, missionDirAbs: outDir });
816
827
  stopSpinner('Share bundle generated', true);
817
- console.log(` ${ICONS.package} ${colors.accent}${path.relative(root, shareResult.outputDir)}${c.reset}`);
818
828
  } catch (e) {
819
829
  stopSpinner('Share bundle failed', false);
820
- console.log(` ${c.dim}${e.message}${c.reset}`);
821
830
  }
822
831
  }
823
832
 
833
+ // Mission Control output
834
+ if (!opts.json && !opts.quiet) {
835
+ console.log(formatFixOutput({
836
+ missions,
837
+ verdict: lastShip.verdict,
838
+ beforeVerdict: first.verdict,
839
+ afterVerdict: lastShip.verdict,
840
+ appliedMissions: maxSteps,
841
+ totalMissions: missions.length,
842
+ duration,
843
+ success: false,
844
+ }, { apply: opts.apply, promptOnly: opts.promptOnly, loop: opts.loop || opts.autopilot }));
845
+ }
846
+
824
847
  return EXIT.WARNINGS; // Max steps reached, incomplete
825
848
  }
826
849
 
@@ -1355,68 +1355,28 @@ async function runProve(argsOrOpts = {}, context = {}) {
1355
1355
 
1356
1356
  // Final verdict display (unless JSON or CI mode)
1357
1357
  if (!json && !ci) {
1358
- printFinalVerdict(finalVerdict, durationStr, fixRound, shipResult.report?.findings?.length || 0);
1358
+ // Use Mission Control format
1359
+ const { formatProveOutput } = require('./lib/prove-output');
1360
+ const steps = timeline.map(t => ({
1361
+ name: t.step || t.action || 'Step',
1362
+ success: t.status === 'success' || t.status === 'complete',
1363
+ error: t.status === 'error' ? t.error : null,
1364
+ }));
1359
1365
 
1360
- // Timeline summary
1361
- printTimelineSummary(timeline);
1362
-
1363
- // Report links
1364
- printSection('PROOF ARTIFACTS', ICONS.doc);
1365
- console.log();
1366
+ console.log(formatProveOutput({
1367
+ verdict: finalVerdict,
1368
+ finalVerdict,
1369
+ steps,
1370
+ runtimeTests: report.tests?.length || 0,
1371
+ runtimePassed: report.tests?.filter(t => t.passed).length || 0,
1372
+ duration,
1373
+ success: finalVerdict === 'SHIP',
1374
+ }, { version: 'v3.5.5' }));
1366
1375
 
1367
- // Highlight the HTML proof report
1376
+ // Show artifacts if available
1368
1377
  if (htmlReportPath) {
1369
- console.log(` ${colors.shipGreen}${ICONS.sparkle}${c.reset} ${c.bold}HTML Proof Report:${c.reset}`);
1370
- console.log(` ${colors.accent}${path.relative(root, htmlReportPath)}${c.reset}`);
1371
- console.log(` ${c.dim}↳ Open in browser to see video evidence${c.reset}`);
1372
- console.log();
1373
- }
1374
-
1375
- // Show video/trace artifacts if available
1376
- if (report.artifacts) {
1377
- if (report.artifacts.videos?.anon || report.artifacts.videos?.auth) {
1378
- console.log(` ${c.dim}🎬 Videos:${c.reset} ${report.artifacts.videos?.directory || 'N/A'}`);
1379
- }
1380
- if (report.artifacts.traces?.anon || report.artifacts.traces?.auth) {
1381
- console.log(` ${c.dim}📊 Traces:${c.reset} ${report.artifacts.traces?.directory || 'N/A'}`);
1382
- console.log(` ${c.dim}↳ Upload to trace.playwright.dev for debugging${c.reset}`);
1383
- }
1384
- if (report.artifacts.har?.directory) {
1385
- console.log(` ${c.dim}📡 HAR:${c.reset} ${report.artifacts.har?.directory || 'N/A'}`);
1386
- }
1387
- console.log();
1378
+ console.log(`\n ${colors.shipGreen}${ICONS.sparkle}${c.reset} ${c.bold}HTML Proof Report:${c.reset} ${colors.accent}${path.relative(root, htmlReportPath)}${c.reset}`);
1388
1379
  }
1389
-
1390
- console.log(` ${c.dim}JSON Report:${c.reset} ${path.relative(root, path.join(outDir, 'prove_report.json'))}`);
1391
- console.log();
1392
-
1393
- // CI Integration tip
1394
- printSection('CI INTEGRATION', ICONS.lightning);
1395
- console.log();
1396
- console.log(` ${c.dim}Add to your CI pipeline:${c.reset}`);
1397
- console.log(` ${colors.accent}npx vibecheck prove --url \$APP_URL --ci${c.reset}`);
1398
- console.log(` ${c.dim}Exit codes: 0=SHIP, 1=WARN, 2=BLOCK${c.reset}`);
1399
- console.log();
1400
-
1401
- // Next steps if not proved
1402
- if (finalVerdict !== 'SHIP') {
1403
- printSection('NEXT STEPS', ICONS.lightning);
1404
- console.log();
1405
- if (skipFix) {
1406
- console.log(` ${colors.accent}vibecheck prove --url ${url || '<url>'}${c.reset} ${c.dim}Enable auto-fix${c.reset}`);
1407
- } else if (fixRound >= maxFixRounds) {
1408
- console.log(` ${colors.accent}vibecheck prove --max-fix-rounds ${maxFixRounds + 2}${c.reset} ${c.dim}Try more fix rounds${c.reset}`);
1409
- }
1410
- console.log(` ${colors.accent}vibecheck ship --fix${c.reset} ${c.dim}Manual fix mode${c.reset}`);
1411
- console.log();
1412
- }
1413
-
1414
- // Upsell for upgrade
1415
- console.log(upsell.formatNextSteps("prove", finalVerdict, "free"));
1416
- console.log();
1417
- console.log(` ${c.dim}${upsell.sym.star} Upgrade for unlimited prove runs + video artifacts${c.reset}`);
1418
- console.log(` ${c.dim}${upsell.sym.arrow} ${upsell.PRICING_URL}${c.reset}`);
1419
- console.log();
1420
1380
  } else if (ci) {
1421
1381
  // CI mode - structured output for easy parsing
1422
1382
  console.log(`::group::vibecheck prove summary`);
@@ -2046,48 +2046,34 @@ async function runReality(argsOrOpts = {}) {
2046
2046
  // OUTPUT
2047
2047
  // ═══════════════════════════════════════════════════════════════════════════
2048
2048
 
2049
- // Coverage card
2050
- printCoverageCard(coverage, anonPass.pagesVisited.length, authPass?.pagesVisited?.length, maxPages);
2049
+ // Determine verdict
2050
+ const verdict = blocks > 0 ? 'BLOCK' : warns > 0 ? 'WARN' : 'SHIP';
2051
2051
 
2052
- // Findings breakdown
2053
- printFindingsBreakdown(findings);
2054
-
2055
- // Blocker details
2056
- printBlockerDetails(findings);
2057
-
2058
- // Verdict card
2059
- printVerdictCard(blocks, warns, duration);
2060
-
2061
- // Report links
2062
- printSection('REPORTS', ICONS.page);
2063
- console.log();
2064
- console.log(` ${colors.accent}${path.relative(root, outBase)}/reality_report.json${c.reset}`);
2065
- console.log(` ${c.dim}${path.join('.vibecheck', 'reality', 'last_reality.json')}${c.reset}`);
2066
- if (anonPass.findings.some(f => f.screenshot) || authPass?.findings?.some(f => f.screenshot)) {
2067
- console.log(` ${colors.accent}${ICONS.screenshot} ${path.relative(root, shotsDir)}/${c.reset} ${c.dim}(screenshots)${c.reset}`);
2068
- }
2069
- console.log();
2070
-
2071
- // Next steps if issues found
2072
- if (blocks > 0 || warns > 0) {
2073
- printSection('NEXT STEPS', ICONS.lightning);
2074
- console.log();
2075
- console.log(` ${colors.accent}vibecheck fix${c.reset} ${c.dim}Auto-fix dead UI issues${c.reset}`);
2076
- console.log(` ${colors.accent}vibecheck ship${c.reset} ${c.dim}Re-check ship readiness${c.reset}`);
2077
- console.log();
2078
- }
2079
-
2080
- // Upsell for free tier users running in preview mode
2081
- const currentTier = entitlements.getCurrentTierSync ? entitlements.getCurrentTierSync() : 'free';
2082
- if (currentTier === 'free') {
2083
- console.log(upsell.formatEarnedUpsell({
2084
- cmd: "reality",
2085
- why: "cap_hit",
2086
- topIssues: findings.slice(0, 5),
2087
- upgradeTier: "starter",
2052
+ // Use Mission Control format
2053
+ if (!opts.json && !opts.quiet) {
2054
+ const { formatRealityOutput } = require('./lib/reality-output');
2055
+
2056
+ // Build test results from findings
2057
+ const tests = findings.map(f => ({
2058
+ name: f.title || f.category || 'Test',
2059
+ route: f.page || f.url || '',
2060
+ passed: f.severity !== 'BLOCK',
2088
2061
  }));
2089
- console.log(upsell.formatNextSteps("reality", blocks > 0 ? "BLOCK" : warns > 0 ? "WARN" : "SHIP", currentTier));
2090
- console.log();
2062
+
2063
+ console.log(formatRealityOutput({
2064
+ verdict,
2065
+ tests,
2066
+ passed: tests.filter(t => t.passed).length,
2067
+ failed: tests.filter(t => !t.passed).length,
2068
+ warnings: warns,
2069
+ coverage: coverage.percent || 0,
2070
+ duration,
2071
+ url: baseUrl,
2072
+ success: verdict === 'SHIP',
2073
+ }, { projectPath: root, version: 'v3.5.5' }));
2074
+
2075
+ // Show report path
2076
+ console.log(`\n ${colors.accent}Report:${c.reset} ${path.relative(root, outBase)}/reality_report.json`);
2091
2077
  }
2092
2078
 
2093
2079
  process.exitCode = blocks ? 2 : warns ? 1 : 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibecheckai/cli",
3
- "version": "3.5.5",
3
+ "version": "3.6.0",
4
4
  "description": "Vibecheck CLI - Ship with confidence. One verdict: SHIP | WARN | BLOCK.",
5
5
  "main": "bin/vibecheck.js",
6
6
  "bin": {