@vibecheckai/cli 3.1.2 → 3.1.4

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.
Files changed (47) hide show
  1. package/README.md +60 -33
  2. package/bin/registry.js +319 -34
  3. package/bin/runners/CLI_REFACTOR_SUMMARY.md +229 -0
  4. package/bin/runners/REPORT_AUDIT.md +64 -0
  5. package/bin/runners/lib/entitlements-v2.js +97 -28
  6. package/bin/runners/lib/entitlements.js +3 -6
  7. package/bin/runners/lib/init-wizard.js +1 -1
  8. package/bin/runners/lib/report-engine.js +459 -280
  9. package/bin/runners/lib/report-html.js +1154 -1423
  10. package/bin/runners/lib/report-output.js +187 -0
  11. package/bin/runners/lib/report-templates.js +848 -850
  12. package/bin/runners/lib/scan-output.js +545 -0
  13. package/bin/runners/lib/server-usage.js +0 -12
  14. package/bin/runners/lib/ship-output.js +641 -0
  15. package/bin/runners/lib/status-output.js +253 -0
  16. package/bin/runners/lib/terminal-ui.js +853 -0
  17. package/bin/runners/runCheckpoint.js +502 -0
  18. package/bin/runners/runContracts.js +105 -0
  19. package/bin/runners/runExport.js +93 -0
  20. package/bin/runners/runFix.js +31 -24
  21. package/bin/runners/runInit.js +377 -112
  22. package/bin/runners/runInstall.js +1 -5
  23. package/bin/runners/runLabs.js +3 -3
  24. package/bin/runners/runPolish.js +2452 -0
  25. package/bin/runners/runProve.js +2 -2
  26. package/bin/runners/runReport.js +251 -200
  27. package/bin/runners/runRuntime.js +110 -0
  28. package/bin/runners/runScan.js +477 -379
  29. package/bin/runners/runSecurity.js +92 -0
  30. package/bin/runners/runShip.js +137 -207
  31. package/bin/runners/runStatus.js +16 -68
  32. package/bin/runners/utils.js +5 -5
  33. package/bin/vibecheck.js +25 -11
  34. package/mcp-server/index.js +150 -18
  35. package/mcp-server/package.json +2 -2
  36. package/mcp-server/premium-tools.js +13 -13
  37. package/mcp-server/tier-auth.js +292 -27
  38. package/mcp-server/vibecheck-tools.js +9 -9
  39. package/package.json +1 -1
  40. package/bin/runners/runClaimVerifier.js +0 -483
  41. package/bin/runners/runContextCompiler.js +0 -385
  42. package/bin/runners/runGate.js +0 -17
  43. package/bin/runners/runInitGha.js +0 -164
  44. package/bin/runners/runInteractive.js +0 -388
  45. package/bin/runners/runMdc.js +0 -204
  46. package/bin/runners/runMissionGenerator.js +0 -282
  47. package/bin/runners/runTruthpack.js +0 -636
@@ -461,15 +461,25 @@ function printNextSteps(options = {}) {
461
461
  printSection('NEXT STEPS', ICONS.arrow);
462
462
  console.log();
463
463
 
464
- const steps = [
465
- { num: 1, cmd: 'vibecheck scan', desc: 'Run your first scan' },
466
- { num: 2, cmd: 'vibecheck ship', desc: 'Check if ready to ship' },
467
- ];
464
+ const steps = [];
468
465
 
469
- if (options.hasCI) {
470
- steps.push({ num: 3, cmd: 'git push', desc: 'CI will run automatically' });
466
+ if (options.mode === 'connect') {
467
+ steps.push(
468
+ { num: 1, cmd: 'vibecheck scan', desc: 'Run baseline scan' },
469
+ { num: 2, cmd: 'vibecheck checkpoint --save', desc: 'Save baseline for comparison' },
470
+ { num: 3, cmd: 'git push', desc: 'CI will run automatically' },
471
+ );
471
472
  } else {
472
- steps.push({ num: 3, cmd: 'vibecheck init --gha', desc: 'Add CI/CD integration' });
473
+ steps.push(
474
+ { num: 1, cmd: 'vibecheck scan', desc: 'Run your first scan' },
475
+ { num: 2, cmd: 'vibecheck ship', desc: 'Check if ready to ship' },
476
+ );
477
+
478
+ if (options.hasCI) {
479
+ steps.push({ num: 3, cmd: 'git push', desc: 'CI will run automatically' });
480
+ } else {
481
+ steps.push({ num: 3, cmd: 'vibecheck init --connect', desc: 'Add GitHub integration [STARTER]' });
482
+ }
473
483
  }
474
484
 
475
485
  for (const step of steps) {
@@ -530,14 +540,18 @@ function printComplianceInfo(complianceType) {
530
540
  function printHelp() {
531
541
  console.log(BANNER_FULL);
532
542
  console.log(`
533
- ${c.bold}Usage:${c.reset} vibecheck init [options]
543
+ ${c.bold}Usage:${c.reset} vibecheck init [mode] [options]
534
544
 
535
- ${c.bold}Enterprise Project Setup${c.reset} — Configure for production-grade verification.
545
+ ${c.bold}MODES${c.reset}
546
+ ${colors.success}--local${c.reset} ${c.green}[FREE]${c.reset} Full local setup (default)
547
+ Creates truthpack, contracts, MDC/IDE rules
548
+ ${colors.accent}--connect${c.reset} ${c.cyan}[STARTER]${c.reset} + GitHub Actions, PR comments, dashboard sync
536
549
 
537
550
  ${c.bold}Basic Options:${c.reset}
538
551
  ${colors.accent}--path, -p <dir>${c.reset} Project path ${c.dim}(default: current directory)${c.reset}
539
552
  ${colors.accent}--quick, -q${c.reset} Skip wizard, use defaults
540
553
  ${colors.accent}--git-hooks${c.reset} Install git pre-push hook
554
+ ${colors.accent}--json${c.reset} Output results as JSON
541
555
  ${colors.accent}--help, -h${c.reset} Show this help
542
556
 
543
557
  ${colors.enterprise}${c.bold}Enterprise Options:${c.reset}
@@ -563,38 +577,29 @@ function printHelp() {
563
577
  ${colors.accent}--mcp${c.reset} Generate MCP server config
564
578
  ${colors.accent}--strict${c.reset} Enable strict mode
565
579
 
566
- ${c.bold}Created Files:${c.reset}
580
+ ${c.bold}Created Files (--local):${c.reset}
567
581
  ${c.dim}.vibecheck/config.json${c.reset} Main configuration
568
- ${c.dim}.vibecheck/invariants.yml${c.reset} Ship killers & warnings
569
- ${c.dim}.vibecheck/security-policy.json${c.reset} Security headers, CORS
570
- ${c.dim}.vibecheck/team.json${c.reset} Team/environment config
571
- ${c.dim}.vibecheck/mcp.json${c.reset} MCP server config
572
- ${c.dim}.github/workflows/vibecheck.yml${c.reset} GitHub Actions
573
-
574
- ${c.bold}Detection Includes:${c.reset}
575
- ${colors.framework}Frameworks${c.reset} Next.js, Remix, Nuxt, SvelteKit, Fastify, Express
576
- ${colors.database}Databases${c.reset} Prisma, Drizzle, Mongoose, Supabase, Firebase
577
- ${colors.auth}Auth${c.reset} NextAuth, Clerk, Auth0, Lucia, Passport
578
- ${colors.payment}Payments${c.reset} Stripe, Lemon Squeezy, Paddle
579
- ${colors.ci}CI/CD${c.reset} GitHub Actions, GitLab CI, CircleCI
580
- ${colors.deploy}Deploy${c.reset} Vercel, Netlify, Railway, Docker, K8s
581
- ${colors.testing}Testing${c.reset} Jest, Vitest, Playwright, Cypress
582
+ ${c.dim}.vibecheck/truthpack.json${c.reset} Routes, env, auth, billing truth
583
+ ${c.dim}.vibecheck/contracts/${c.reset} Contract definitions
584
+ ${c.dim}.cursor/rules/*.mdc${c.reset} Cursor IDE rules
585
+ ${c.dim}.windsurf/rules.md${c.reset} Windsurf IDE rules
582
586
 
583
- ${c.bold}Examples:${c.reset}
584
- ${c.dim}# Interactive wizard${c.reset}
585
- vibecheck init
587
+ ${c.bold}Additional Files (--connect):${c.reset}
588
+ ${c.dim}.github/workflows/vibecheck.yml${c.reset} GitHub Actions workflow
589
+ ${c.dim}.github/workflows/vibecheck-pr.yml${c.reset} PR check workflow
586
590
 
587
- ${c.dim}# Quick setup with defaults${c.reset}
588
- vibecheck init --quick
591
+ ${c.bold}Examples:${c.reset}
592
+ ${c.dim}# Full local setup (default)${c.reset}
593
+ vibecheck init --local
589
594
 
590
- ${c.dim}# Enterprise with GitHub Actions${c.reset}
591
- vibecheck init --enterprise --gha
595
+ ${c.dim}# Local + GitHub integration${c.reset}
596
+ vibecheck init --connect
592
597
 
593
- ${c.dim}# SOC 2 compliance baseline${c.reset}
594
- vibecheck init --soc2
598
+ ${c.dim}# Quick setup${c.reset}
599
+ vibecheck init --quick
595
600
 
596
- ${c.dim}# Full enterprise setup${c.reset}
597
- vibecheck init --full
601
+ ${c.dim}# Enterprise with compliance${c.reset}
602
+ vibecheck init --enterprise --soc2
598
603
  `);
599
604
  }
600
605
 
@@ -608,6 +613,10 @@ function parseArgs(args) {
608
613
  gitHooks: false,
609
614
  help: false,
610
615
  quick: false,
616
+ json: false,
617
+ // Mode flags (--local is default, --connect requires STARTER)
618
+ local: false,
619
+ connect: false,
611
620
  // Enterprise options
612
621
  enterprise: false,
613
622
  ci: false,
@@ -626,6 +635,11 @@ function parseArgs(args) {
626
635
  if (a === "--git-hooks") out.gitHooks = true;
627
636
  if (a === "--help" || a === "-h") out.help = true;
628
637
  if (a === "--quick" || a === "-q") out.quick = true;
638
+ if (a === "--json") out.json = true;
639
+
640
+ // Mode flags
641
+ if (a === "--local" || a === "-l") out.local = true;
642
+ if (a === "--connect" || a === "-c") out.connect = true;
629
643
 
630
644
  // Enterprise flags
631
645
  if (a === "--enterprise" || a === "-e") out.enterprise = true;
@@ -661,8 +675,15 @@ function parseArgs(args) {
661
675
  out.ci = true;
662
676
  out.team = true;
663
677
  out.mcp = true;
678
+ out.connect = true;
664
679
  }
665
680
  }
681
+
682
+ // Default to --local if neither mode specified
683
+ if (!out.local && !out.connect) {
684
+ out.local = true;
685
+ }
686
+
666
687
  return out;
667
688
  }
668
689
 
@@ -670,6 +691,236 @@ function parseArgs(args) {
670
691
  // MAIN INIT FUNCTION
671
692
  // ═══════════════════════════════════════════════════════════════════════════════
672
693
 
694
+ // ═══════════════════════════════════════════════════════════════════════════════
695
+ // LOCAL MODE SETUP - Full local initialization
696
+ // ═══════════════════════════════════════════════════════════════════════════════
697
+
698
+ async function runLocalSetup(targetDir, projectName, opts, filesCreated) {
699
+ printSection('LOCAL SETUP', ICONS.setup);
700
+ console.log();
701
+
702
+ const vibecheckDir = path.join(targetDir, ".vibecheck");
703
+
704
+ // 1. Create .vibecheck/ directory structure
705
+ const dirs = [
706
+ vibecheckDir,
707
+ path.join(vibecheckDir, "results"),
708
+ path.join(vibecheckDir, "reports"),
709
+ path.join(vibecheckDir, "contracts"),
710
+ path.join(vibecheckDir, "missions"),
711
+ path.join(vibecheckDir, "checkpoints"),
712
+ path.join(vibecheckDir, "runs"),
713
+ ];
714
+
715
+ for (const dir of dirs) {
716
+ if (!fs.existsSync(dir)) {
717
+ fs.mkdirSync(dir, { recursive: true });
718
+ }
719
+ }
720
+ printSetupStep('.vibecheck/', 'success', 'directory structure created');
721
+ filesCreated.push('.vibecheck/');
722
+
723
+ // 2. Create config.json
724
+ const configPath = path.join(vibecheckDir, "config.json");
725
+ if (!fs.existsSync(configPath)) {
726
+ const config = {
727
+ version: "2.0.0",
728
+ project: projectName,
729
+ createdAt: new Date().toISOString(),
730
+ checks: ["routes", "env", "auth", "security"],
731
+ output: ".vibecheck",
732
+ policy: {
733
+ allowlist: { domains: [], packages: [] },
734
+ ignore: { paths: ["node_modules", "__tests__", "*.test.*", "*.spec.*"] },
735
+ },
736
+ thresholds: {
737
+ minScore: 70,
738
+ maxBlockers: 0,
739
+ maxWarnings: 10,
740
+ },
741
+ };
742
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
743
+ printSetupStep('config.json', 'success', 'configuration created');
744
+ filesCreated.push('.vibecheck/config.json');
745
+ } else {
746
+ printSetupStep('config.json', 'exists', 'already exists');
747
+ }
748
+
749
+ // 3. Generate truthpack
750
+ startSpinner('Building truthpack...', colors.accent);
751
+ try {
752
+ const { runCtx } = require("./runCtx");
753
+ await runCtx(["build", "--path", targetDir, "--quiet"]);
754
+ stopSpinner('Truthpack generated', true);
755
+ filesCreated.push('.vibecheck/truthpack.json');
756
+ } catch (e) {
757
+ stopSpinner('Truthpack generation failed (will retry on scan)', false);
758
+ }
759
+
760
+ // 4. Generate contracts
761
+ const contractsDir = path.join(vibecheckDir, "contracts");
762
+
763
+ // Routes contract
764
+ const routeContractPath = path.join(contractsDir, "routes.contract.json");
765
+ if (!fs.existsSync(routeContractPath)) {
766
+ const routeContract = {
767
+ version: "1.0.0",
768
+ generatedAt: new Date().toISOString(),
769
+ routes: [],
770
+ description: "Route contract - populated by scan",
771
+ };
772
+ fs.writeFileSync(routeContractPath, JSON.stringify(routeContract, null, 2));
773
+ printSetupStep('routes.contract.json', 'success', 'route contract created');
774
+ filesCreated.push('.vibecheck/contracts/routes.contract.json');
775
+ }
776
+
777
+ // Env contract
778
+ const envContractPath = path.join(contractsDir, "env.contract.json");
779
+ if (!fs.existsSync(envContractPath)) {
780
+ const envContract = {
781
+ version: "1.0.0",
782
+ generatedAt: new Date().toISOString(),
783
+ required: [],
784
+ optional: [],
785
+ description: "Environment contract - populated by scan",
786
+ };
787
+ fs.writeFileSync(envContractPath, JSON.stringify(envContract, null, 2));
788
+ printSetupStep('env.contract.json', 'success', 'env contract created');
789
+ filesCreated.push('.vibecheck/contracts/env.contract.json');
790
+ }
791
+
792
+ // 5. Generate IDE rules (MDC for Cursor, rules for others)
793
+ startSpinner('Generating IDE rules...', colors.accent);
794
+ try {
795
+ const { runContext } = require("./runContext");
796
+ await runContext(["--path", targetDir, "--quiet"]);
797
+ stopSpinner('IDE rules generated', true);
798
+ filesCreated.push('.cursor/rules/', '.windsurf/', '.github/copilot-instructions.md');
799
+ } catch (e) {
800
+ stopSpinner('IDE rules skipped (run vibecheck context later)', false);
801
+ }
802
+
803
+ // 6. Create .vibecheckrc at project root
804
+ const rcPath = path.join(targetDir, ".vibecheckrc.json");
805
+ if (!fs.existsSync(rcPath)) {
806
+ const rc = {
807
+ extends: ".vibecheck/config.json",
808
+ tier: "free",
809
+ };
810
+ fs.writeFileSync(rcPath, JSON.stringify(rc, null, 2));
811
+ printSetupStep('.vibecheckrc.json', 'success', 'root config created');
812
+ filesCreated.push('.vibecheckrc.json');
813
+ }
814
+
815
+ // 7. Update .gitignore
816
+ const gitignorePath = path.join(targetDir, ".gitignore");
817
+ if (fs.existsSync(gitignorePath)) {
818
+ let gitignore = fs.readFileSync(gitignorePath, "utf-8");
819
+ const additions = [];
820
+ if (!gitignore.includes(".vibecheck/results/")) additions.push(".vibecheck/results/");
821
+ if (!gitignore.includes(".vibecheck/runs/")) additions.push(".vibecheck/runs/");
822
+ if (!gitignore.includes(".vibecheck/checkpoints/")) additions.push(".vibecheck/checkpoints/");
823
+
824
+ if (additions.length > 0) {
825
+ gitignore += `\n# vibecheck (generated outputs)\n${additions.join("\n")}\n`;
826
+ fs.writeFileSync(gitignorePath, gitignore);
827
+ printSetupStep('.gitignore', 'success', 'updated with vibecheck paths');
828
+ }
829
+ }
830
+
831
+ return filesCreated;
832
+ }
833
+
834
+ // ═══════════════════════════════════════════════════════════════════════════════
835
+ // CONNECT MODE SETUP - GitHub integration
836
+ // ═══════════════════════════════════════════════════════════════════════════════
837
+
838
+ async function runConnectSetup(targetDir, projectName, opts, filesCreated) {
839
+ // Check entitlement
840
+ const entitlements = require("./lib/entitlements-v2");
841
+ const access = await entitlements.enforce("init.connect", { silent: true });
842
+
843
+ if (!access.allowed) {
844
+ console.log();
845
+ console.log(` ${colors.warning}${ICONS.warning}${c.reset} ${c.bold}--connect requires STARTER plan${c.reset}`);
846
+ console.log(` ${c.dim}Upgrade at: https://vibecheckai.dev/pricing${c.reset}`);
847
+ console.log();
848
+ console.log(` ${c.dim}Local setup completed. Run 'vibecheck init --connect' after upgrading.${c.reset}`);
849
+ return filesCreated;
850
+ }
851
+
852
+ printSection('GITHUB INTEGRATION', ICONS.ci);
853
+ console.log();
854
+
855
+ // 1. Create GitHub workflows directory
856
+ const workflowsDir = path.join(targetDir, ".github", "workflows");
857
+ if (!fs.existsSync(workflowsDir)) {
858
+ fs.mkdirSync(workflowsDir, { recursive: true });
859
+ }
860
+
861
+ // 2. Copy main workflow template
862
+ const mainWorkflowPath = path.join(workflowsDir, "vibecheck.yml");
863
+ if (!fs.existsSync(mainWorkflowPath)) {
864
+ // Read template
865
+ const templatePath = path.join(__dirname, "..", "..", "templates", "github-actions", "vibecheck.yml");
866
+ if (fs.existsSync(templatePath)) {
867
+ fs.copyFileSync(templatePath, mainWorkflowPath);
868
+ printSetupStep('vibecheck.yml', 'success', 'main workflow created');
869
+ filesCreated.push('.github/workflows/vibecheck.yml');
870
+ } else {
871
+ // Inline template as fallback
872
+ const workflow = `# Vibecheck CI/CD Workflow
873
+ name: Vibecheck
874
+ on:
875
+ push:
876
+ branches: [main, master]
877
+ pull_request:
878
+
879
+ jobs:
880
+ vibecheck:
881
+ runs-on: ubuntu-latest
882
+ steps:
883
+ - uses: actions/checkout@v4
884
+ - uses: actions/setup-node@v4
885
+ with:
886
+ node-version: '20'
887
+ - run: npm ci
888
+ - run: npx vibecheck scan --json > .vibecheck/results/scan.json
889
+ - run: npx vibecheck ship --ci
890
+ `;
891
+ fs.writeFileSync(mainWorkflowPath, workflow);
892
+ printSetupStep('vibecheck.yml', 'success', 'main workflow created');
893
+ filesCreated.push('.github/workflows/vibecheck.yml');
894
+ }
895
+ } else {
896
+ printSetupStep('vibecheck.yml', 'exists', 'already exists');
897
+ }
898
+
899
+ // 3. Copy PR workflow template
900
+ const prWorkflowPath = path.join(workflowsDir, "vibecheck-pr.yml");
901
+ if (!fs.existsSync(prWorkflowPath)) {
902
+ const templatePath = path.join(__dirname, "..", "..", "templates", "github-actions", "vibecheck-pr.yml");
903
+ if (fs.existsSync(templatePath)) {
904
+ fs.copyFileSync(templatePath, prWorkflowPath);
905
+ printSetupStep('vibecheck-pr.yml', 'success', 'PR workflow created');
906
+ filesCreated.push('.github/workflows/vibecheck-pr.yml');
907
+ }
908
+ }
909
+
910
+ // 4. Provide setup instructions
911
+ console.log();
912
+ console.log(` ${colors.info}${ICONS.info}${c.reset} ${c.bold}GitHub Setup Required:${c.reset}`);
913
+ console.log(` 1. Add ${c.cyan}VIBECHECK_API_KEY${c.reset} to repository secrets`);
914
+ console.log(` 2. Push to trigger first workflow run`);
915
+ console.log();
916
+
917
+ return filesCreated;
918
+ }
919
+
920
+ // ═══════════════════════════════════════════════════════════════════════════════
921
+ // MAIN INIT FUNCTION
922
+ // ═══════════════════════════════════════════════════════════════════════════════
923
+
673
924
  async function runInit(args) {
674
925
  const opts = parseArgs(args);
675
926
 
@@ -678,14 +929,20 @@ async function runInit(args) {
678
929
  return 0;
679
930
  }
680
931
 
932
+ // --quick mode delegates to runInstall (zero-friction onboarding)
933
+ if (opts.quick) {
934
+ const { runInstall } = require("./runInstall");
935
+ return await runInstall(args);
936
+ }
937
+
681
938
  const targetDir = path.resolve(opts.path);
682
939
  const projectName = path.basename(targetDir);
683
940
 
684
941
  // Enterprise mode - comprehensive setup
685
942
  const useEnterprise = opts.enterprise || opts.ci || opts.compliance ||
686
- opts.team || opts.mcp || opts.detect || opts.full;
943
+ opts.team || opts.mcp || opts.detect;
687
944
 
688
- if (EnterpriseInit && useEnterprise) {
945
+ if (EnterpriseInit && useEnterprise && !opts.local && !opts.connect) {
689
946
  printBanner();
690
947
  printEnterpriseHeader(opts);
691
948
 
@@ -706,112 +963,120 @@ async function runInit(args) {
706
963
 
707
964
  startSpinner('Detecting project configuration...', colors.accent);
708
965
 
709
- const { detectAll } = require("./lib/enterprise-detect");
710
- const detection = detectAll(targetDir);
711
-
712
- stopSpinner('Detection complete', true);
713
-
714
- printDetectionResults(detection);
715
-
716
- console.log();
717
- console.log(` ${c.dim}Full JSON output:${c.reset}`);
718
- console.log(JSON.stringify(detection, null, 2));
966
+ try {
967
+ const { detectAll } = require("./lib/enterprise-detect");
968
+ const detection = detectAll(targetDir);
969
+ stopSpinner('Detection complete', true);
970
+ printDetectionResults(detection);
971
+ console.log();
972
+ console.log(` ${c.dim}Full JSON output:${c.reset}`);
973
+ console.log(JSON.stringify(detection, null, 2));
974
+ } catch (e) {
975
+ stopSpinner('Detection failed', false);
976
+ console.log(` ${colors.error}Error:${c.reset} ${e.message}`);
977
+ }
719
978
  return 0;
720
979
  }
721
980
 
722
- // Use wizard for interactive setup (unless --quick)
723
- if (InitWizard && !opts.quick) {
724
- const wizard = new InitWizard(targetDir, opts);
725
- return await wizard.run();
726
- }
727
-
728
981
  // ═══════════════════════════════════════════════════════════════════════════
729
- // QUICK MODE - Enhanced Legacy Behavior
982
+ // NEW: --local and --connect modes
730
983
  // ═══════════════════════════════════════════════════════════════════════════
731
984
 
732
- printBanner();
733
-
734
- console.log(` ${c.dim}Project:${c.reset} ${c.bold}${projectName}${c.reset}`);
735
- console.log(` ${c.dim}Path:${c.reset} ${targetDir}`);
736
- console.log(` ${c.dim}Mode:${c.reset} ${colors.accent}Quick Setup${c.reset}`);
737
-
738
- printSection('SETUP', ICONS.setup);
739
- console.log();
985
+ if (!opts.json) {
986
+ printBanner();
987
+
988
+ const mode = opts.connect ? 'Local + Connect' : 'Local';
989
+ const tierBadge = opts.connect ? `${c.cyan}[STARTER]${c.reset}` : `${c.green}[FREE]${c.reset}`;
990
+
991
+ console.log(` ${c.dim}Project:${c.reset} ${c.bold}${projectName}${c.reset}`);
992
+ console.log(` ${c.dim}Path:${c.reset} ${targetDir}`);
993
+ console.log(` ${c.dim}Mode:${c.reset} ${colors.accent}${mode}${c.reset} ${tierBadge}`);
994
+ }
740
995
 
741
- const filesCreated = [];
996
+ let filesCreated = [];
997
+ const result = {
998
+ success: true,
999
+ project: projectName,
1000
+ path: targetDir,
1001
+ mode: opts.connect ? 'connect' : 'local',
1002
+ filesCreated: [],
1003
+ errors: [],
1004
+ };
742
1005
 
743
- // Create config file
744
- const configPath = path.join(targetDir, ".vibecheckrc");
745
- if (!fs.existsSync(configPath)) {
746
- const defaultConfig = {
747
- version: "1.0.0",
748
- checks: ["integrity"],
749
- output: ".vibecheck",
750
- policy: {
751
- allowlist: { domains: [], packages: [] },
752
- ignore: { paths: ["node_modules", "__tests__", "*.test.*"] },
753
- },
754
- };
755
- fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2));
756
- printSetupStep('.vibecheckrc', 'success', 'configuration created');
757
- filesCreated.push('.vibecheckrc');
758
- } else {
759
- printSetupStep('.vibecheckrc', 'exists', 'already exists');
1006
+ // Always run local setup first
1007
+ if (opts.local || opts.connect) {
1008
+ try {
1009
+ filesCreated = await runLocalSetup(targetDir, projectName, opts, filesCreated);
1010
+ } catch (e) {
1011
+ result.errors.push({ step: 'local', error: e.message });
1012
+ if (!opts.json) {
1013
+ console.log(` ${colors.error}${ICONS.cross}${c.reset} Local setup error: ${e.message}`);
1014
+ }
1015
+ }
760
1016
  }
761
-
762
- // Create output directory
763
- const outputDir = path.join(targetDir, ".vibecheck");
764
- if (!fs.existsSync(outputDir)) {
765
- fs.mkdirSync(outputDir, { recursive: true });
766
- printSetupStep('.vibecheck/', 'success', 'output directory created');
767
- filesCreated.push('.vibecheck/');
768
- } else {
769
- printSetupStep('.vibecheck/', 'exists', 'already exists');
1017
+
1018
+ // Run connect setup if requested
1019
+ if (opts.connect) {
1020
+ try {
1021
+ filesCreated = await runConnectSetup(targetDir, projectName, opts, filesCreated);
1022
+ } catch (e) {
1023
+ result.errors.push({ step: 'connect', error: e.message });
1024
+ if (!opts.json) {
1025
+ console.log(` ${colors.error}${ICONS.cross}${c.reset} Connect setup error: ${e.message}`);
1026
+ }
1027
+ }
770
1028
  }
771
-
772
- // Install git hooks if requested
1029
+
1030
+ // Git hooks if requested
773
1031
  if (opts.gitHooks) {
774
1032
  const huskyDir = path.join(targetDir, ".husky");
775
1033
  if (!fs.existsSync(huskyDir)) {
776
1034
  fs.mkdirSync(huskyDir, { recursive: true });
777
1035
  }
778
-
779
1036
  const prePushHook = `#!/usr/bin/env sh
780
1037
  . "$(dirname -- "$0")/_/husky.sh"
781
1038
 
782
1039
  echo "🚦 Running vibecheck gate..."
783
- npx vibecheck gate
1040
+ npx vibecheck ship --ci
784
1041
 
785
1042
  if [ $? -ne 0 ]; then
786
1043
  echo "❌ Push blocked: Gate failed!"
787
1044
  exit 1
788
1045
  fi
789
1046
  `;
790
- fs.writeFileSync(path.join(huskyDir, "pre-push"), prePushHook, {
791
- mode: 0o755,
792
- });
793
- printSetupStep('.husky/pre-push', 'success', 'git hook installed');
1047
+ fs.writeFileSync(path.join(huskyDir, "pre-push"), prePushHook, { mode: 0o755 });
1048
+ if (!opts.json) {
1049
+ printSetupStep('.husky/pre-push', 'success', 'git hook installed');
1050
+ }
794
1051
  filesCreated.push('.husky/pre-push');
795
1052
  }
796
-
797
- // Add to .gitignore
798
- const gitignorePath = path.join(targetDir, ".gitignore");
799
- if (fs.existsSync(gitignorePath)) {
800
- let gitignore = fs.readFileSync(gitignorePath, "utf-8");
801
- if (!gitignore.includes(".vibecheck/")) {
802
- gitignore += "\n# vibecheck\n.vibecheck/\n";
803
- fs.writeFileSync(gitignorePath, gitignore);
804
- printSetupStep('.gitignore', 'success', 'added .vibecheck/');
805
- } else {
806
- printSetupStep('.gitignore', 'skipped', 'already configured');
807
- }
1053
+
1054
+ result.filesCreated = filesCreated;
1055
+
1056
+ // JSON output
1057
+ if (opts.json) {
1058
+ console.log(JSON.stringify(result, null, 2));
1059
+ return result.errors.length > 0 ? 1 : 0;
808
1060
  }
809
-
1061
+
810
1062
  // Success card
811
- printSuccessCard(projectName, 'Quick Setup', filesCreated.length);
1063
+ const mode = opts.connect ? 'Local + Connect' : 'Local Setup';
1064
+ printSuccessCard(projectName, mode, filesCreated.length);
1065
+
1066
+ // Init summary
1067
+ printSection('INIT SUMMARY', ICONS.check);
1068
+ console.log();
1069
+ console.log(` ${colors.success}${ICONS.check}${c.reset} .vibecheck/ structure created`);
1070
+ console.log(` ${colors.success}${ICONS.check}${c.reset} Truthpack generated`);
1071
+ console.log(` ${colors.success}${ICONS.check}${c.reset} Contracts initialized`);
1072
+ console.log(` ${colors.success}${ICONS.check}${c.reset} IDE rules generated`);
1073
+ if (opts.connect) {
1074
+ console.log(` ${colors.success}${ICONS.check}${c.reset} GitHub Actions workflows installed`);
1075
+ }
1076
+ console.log();
812
1077
 
813
1078
  // Next steps
814
- printNextSteps({ hasCI: false });
1079
+ printNextSteps({ hasCI: opts.connect, mode: opts.connect ? 'connect' : 'local' });
815
1080
 
816
1081
  return 0;
817
1082
  }
@@ -264,11 +264,7 @@ async function runInstall(argsOrContext = {}) {
264
264
  console.log(` ${colors.shipGreen}${ICONS.check}${c.reset} ${ICONS.file} ${colors.accent}package.json${c.reset} ${c.dim}(${changedScripts.join(', ')})${c.reset}`);
265
265
  }
266
266
 
267
- // Next steps
268
- const runner = pm === "pnpm" ? "pnpm" : pm === "yarn" ? "yarn" : "npm run";
269
- printSection('NEXT STEP', ICONS.arrow);
270
- console.log();
271
- console.log(` ${colors.accent}${runner} vibecheck:ship${c.reset}`);
267
+ // Installation complete
272
268
  console.log();
273
269
  console.log(` ${colors.shipGreen}${ICONS.sparkle}${c.reset} Installation complete!`);
274
270
  console.log();
@@ -29,9 +29,9 @@ const LABS_FEATURES = {
29
29
  runner: () => require("./runLaunch").runLaunch,
30
30
  },
31
31
  "dashboard": {
32
- status: "experimental",
33
- description: "Real-time monitoring dashboard",
34
- runner: () => require("./runDashboard").runDashboard,
32
+ status: "stub",
33
+ description: "Real-time monitoring dashboard (coming soon)",
34
+ eta: "Q2 2025",
35
35
  },
36
36
  "permissions": {
37
37
  status: "experimental",