@vibecheckai/cli 3.5.1 → 3.5.3

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 (272) hide show
  1. package/bin/registry.js +406 -154
  2. package/bin/runners/context/analyzer.js +52 -1
  3. package/bin/runners/context/generators/mcp.js +15 -13
  4. package/bin/runners/context/git-context.js +3 -1
  5. package/bin/runners/context/proof-context.js +248 -1
  6. package/bin/runners/context/team-conventions.js +33 -7
  7. package/bin/runners/lib/agent-firewall/ai/false-positive-analyzer.js +474 -0
  8. package/bin/runners/lib/agent-firewall/change-packet/builder.js +488 -0
  9. package/bin/runners/lib/agent-firewall/change-packet/schema.json +228 -0
  10. package/bin/runners/lib/agent-firewall/change-packet/store.js +200 -0
  11. package/bin/runners/lib/agent-firewall/claims/claim-types.js +21 -0
  12. package/bin/runners/lib/agent-firewall/claims/extractor.js +303 -0
  13. package/bin/runners/lib/agent-firewall/claims/patterns.js +24 -0
  14. package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
  15. package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
  16. package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
  17. package/bin/runners/lib/agent-firewall/evidence/auth-evidence.js +88 -0
  18. package/bin/runners/lib/agent-firewall/evidence/contract-evidence.js +75 -0
  19. package/bin/runners/lib/agent-firewall/evidence/env-evidence.js +127 -0
  20. package/bin/runners/lib/agent-firewall/evidence/resolver.js +102 -0
  21. package/bin/runners/lib/agent-firewall/evidence/route-evidence.js +213 -0
  22. package/bin/runners/lib/agent-firewall/evidence/side-effect-evidence.js +145 -0
  23. package/bin/runners/lib/agent-firewall/fs-hook/daemon.js +19 -0
  24. package/bin/runners/lib/agent-firewall/fs-hook/installer.js +87 -0
  25. package/bin/runners/lib/agent-firewall/fs-hook/watcher.js +184 -0
  26. package/bin/runners/lib/agent-firewall/git-hook/pre-commit.js +163 -0
  27. package/bin/runners/lib/agent-firewall/ide-extension/cursor.js +107 -0
  28. package/bin/runners/lib/agent-firewall/ide-extension/vscode.js +68 -0
  29. package/bin/runners/lib/agent-firewall/ide-extension/windsurf.js +66 -0
  30. package/bin/runners/lib/agent-firewall/interceptor/base.js +304 -0
  31. package/bin/runners/lib/agent-firewall/interceptor/cursor.js +35 -0
  32. package/bin/runners/lib/agent-firewall/interceptor/vscode.js +35 -0
  33. package/bin/runners/lib/agent-firewall/interceptor/windsurf.js +34 -0
  34. package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
  35. package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
  36. package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
  37. package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
  38. package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
  39. package/bin/runners/lib/agent-firewall/logger.js +141 -0
  40. package/bin/runners/lib/agent-firewall/policy/default-policy.json +90 -0
  41. package/bin/runners/lib/agent-firewall/policy/engine.js +103 -0
  42. package/bin/runners/lib/agent-firewall/policy/loader.js +451 -0
  43. package/bin/runners/lib/agent-firewall/policy/rules/auth-drift.js +50 -0
  44. package/bin/runners/lib/agent-firewall/policy/rules/contract-drift.js +50 -0
  45. package/bin/runners/lib/agent-firewall/policy/rules/fake-success.js +86 -0
  46. package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +162 -0
  47. package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +189 -0
  48. package/bin/runners/lib/agent-firewall/policy/rules/scope.js +93 -0
  49. package/bin/runners/lib/agent-firewall/policy/rules/unsafe-side-effect.js +57 -0
  50. package/bin/runners/lib/agent-firewall/policy/schema.json +183 -0
  51. package/bin/runners/lib/agent-firewall/policy/verdict.js +54 -0
  52. package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
  53. package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
  54. package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
  55. package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
  56. package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
  57. package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
  58. package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
  59. package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
  60. package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
  61. package/bin/runners/lib/agent-firewall/risk/thresholds.js +321 -0
  62. package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
  63. package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
  64. package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
  65. package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
  66. package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
  67. package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
  68. package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
  69. package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
  70. package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
  71. package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
  72. package/bin/runners/lib/agent-firewall/truthpack/index.js +67 -0
  73. package/bin/runners/lib/agent-firewall/truthpack/loader.js +137 -0
  74. package/bin/runners/lib/agent-firewall/unblock/planner.js +337 -0
  75. package/bin/runners/lib/agent-firewall/utils/ignore-checker.js +118 -0
  76. package/bin/runners/lib/analysis-core.js +220 -182
  77. package/bin/runners/lib/analyzers.js +2145 -224
  78. package/bin/runners/lib/api-client.js +269 -0
  79. package/bin/runners/lib/authority-badge.js +425 -0
  80. package/bin/runners/lib/cli-output.js +242 -210
  81. package/bin/runners/lib/default-config.js +127 -0
  82. package/bin/runners/lib/detectors-v2.js +547 -785
  83. package/bin/runners/lib/doctor/modules/security.js +3 -1
  84. package/bin/runners/lib/engine/ast-cache.js +210 -0
  85. package/bin/runners/lib/engine/auth-extractor.js +211 -0
  86. package/bin/runners/lib/engine/billing-extractor.js +112 -0
  87. package/bin/runners/lib/engine/enforcement-extractor.js +100 -0
  88. package/bin/runners/lib/engine/env-extractor.js +207 -0
  89. package/bin/runners/lib/engine/express-extractor.js +208 -0
  90. package/bin/runners/lib/engine/extractors.js +849 -0
  91. package/bin/runners/lib/engine/index.js +207 -0
  92. package/bin/runners/lib/engine/repo-index.js +514 -0
  93. package/bin/runners/lib/engine/types.js +124 -0
  94. package/bin/runners/lib/engines/accessibility-engine.js +190 -0
  95. package/bin/runners/lib/engines/api-consistency-engine.js +162 -0
  96. package/bin/runners/lib/engines/ast-cache.js +99 -0
  97. package/bin/runners/lib/engines/code-quality-engine.js +255 -0
  98. package/bin/runners/lib/engines/console-logs-engine.js +115 -0
  99. package/bin/runners/lib/engines/cross-file-analysis-engine.js +268 -0
  100. package/bin/runners/lib/engines/dead-code-engine.js +198 -0
  101. package/bin/runners/lib/engines/deprecated-api-engine.js +226 -0
  102. package/bin/runners/lib/engines/empty-catch-engine.js +150 -0
  103. package/bin/runners/lib/engines/file-filter.js +131 -0
  104. package/bin/runners/lib/engines/hardcoded-secrets-engine.js +251 -0
  105. package/bin/runners/lib/engines/mock-data-engine.js +272 -0
  106. package/bin/runners/lib/engines/parallel-processor.js +71 -0
  107. package/bin/runners/lib/engines/performance-issues-engine.js +265 -0
  108. package/bin/runners/lib/engines/security-vulnerabilities-engine.js +243 -0
  109. package/bin/runners/lib/engines/todo-fixme-engine.js +115 -0
  110. package/bin/runners/lib/engines/type-aware-engine.js +152 -0
  111. package/bin/runners/lib/engines/unsafe-regex-engine.js +225 -0
  112. package/bin/runners/lib/engines/vibecheck-engines/README.md +53 -0
  113. package/bin/runners/lib/engines/vibecheck-engines/index.js +15 -0
  114. package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
  115. package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
  116. package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
  117. package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
  118. package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
  119. package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
  120. package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
  121. package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +139 -0
  122. package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
  123. package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
  124. package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
  125. package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
  126. package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
  127. package/bin/runners/lib/engines/vibecheck-engines/package.json +13 -0
  128. package/bin/runners/lib/entitlements-v2.js +152 -446
  129. package/bin/runners/lib/error-handler.js +60 -12
  130. package/bin/runners/lib/error-messages.js +289 -0
  131. package/bin/runners/lib/evidence-pack.js +7 -1
  132. package/bin/runners/lib/exit-codes.js +275 -0
  133. package/bin/runners/lib/finding-id.js +69 -0
  134. package/bin/runners/lib/finding-sorter.js +89 -0
  135. package/bin/runners/lib/fingerprint.js +377 -0
  136. package/bin/runners/lib/global-flags.js +37 -0
  137. package/bin/runners/lib/help-formatter.js +413 -0
  138. package/bin/runners/lib/logger.js +38 -0
  139. package/bin/runners/lib/next-action.js +560 -0
  140. package/bin/runners/lib/prerequisites.js +149 -0
  141. package/bin/runners/lib/route-detection.js +137 -68
  142. package/bin/runners/lib/route-truth.js +1167 -322
  143. package/bin/runners/lib/scan-output.js +504 -463
  144. package/bin/runners/lib/scan-runner.js +135 -0
  145. package/bin/runners/lib/schemas/ajv-validator.js +464 -0
  146. package/bin/runners/lib/schemas/error-envelope.schema.json +105 -0
  147. package/bin/runners/lib/schemas/finding-v3.schema.json +151 -0
  148. package/bin/runners/lib/schemas/report-artifact.schema.json +120 -0
  149. package/bin/runners/lib/schemas/run-request.schema.json +108 -0
  150. package/bin/runners/lib/schemas/validator.js +27 -0
  151. package/bin/runners/lib/schemas/verdict.schema.json +140 -0
  152. package/bin/runners/lib/ship-output-enterprise.js +239 -0
  153. package/bin/runners/lib/ship-output.js +328 -31
  154. package/bin/runners/lib/terminal-ui.js +234 -731
  155. package/bin/runners/lib/truth.js +1332 -308
  156. package/bin/runners/lib/unified-cli-output.js +604 -0
  157. package/bin/runners/lib/unified-output.js +163 -155
  158. package/bin/runners/lib/upsell.js +104 -204
  159. package/bin/runners/runAgent.d.ts +5 -0
  160. package/bin/runners/runAgent.js +161 -0
  161. package/bin/runners/runAllowlist.js +166 -101
  162. package/bin/runners/runApprove.js +1200 -0
  163. package/bin/runners/runAuth.js +373 -95
  164. package/bin/runners/runCheckpoint.js +59 -21
  165. package/bin/runners/runClassify.js +926 -0
  166. package/bin/runners/runContext.d.ts +4 -0
  167. package/bin/runners/runContext.js +136 -24
  168. package/bin/runners/runDoctor.js +115 -67
  169. package/bin/runners/runEvidencePack.js +239 -96
  170. package/bin/runners/runFirewall.d.ts +5 -0
  171. package/bin/runners/runFirewall.js +134 -0
  172. package/bin/runners/runFirewallHook.d.ts +5 -0
  173. package/bin/runners/runFirewallHook.js +56 -0
  174. package/bin/runners/runFix.js +6 -5
  175. package/bin/runners/runGuard.js +212 -118
  176. package/bin/runners/runInit.js +66 -21
  177. package/bin/runners/runLabs.js +204 -121
  178. package/bin/runners/runMcp.js +131 -60
  179. package/bin/runners/runPolish.d.ts +4 -0
  180. package/bin/runners/runPolish.js +43 -20
  181. package/bin/runners/runProof.zip +0 -0
  182. package/bin/runners/runProve.js +15 -5
  183. package/bin/runners/runQuickstart.js +531 -0
  184. package/bin/runners/runReality.js +14 -0
  185. package/bin/runners/runReport.js +36 -4
  186. package/bin/runners/runScan.js +689 -91
  187. package/bin/runners/runShip.js +96 -40
  188. package/bin/runners/runTruth.d.ts +5 -0
  189. package/bin/runners/runTruth.js +101 -0
  190. package/bin/runners/runValidate.js +21 -4
  191. package/bin/runners/runWatch.js +118 -54
  192. package/bin/scan.js +6 -1
  193. package/bin/vibecheck.js +297 -52
  194. package/mcp-server/HARDENING_SUMMARY.md +299 -0
  195. package/mcp-server/agent-firewall-interceptor.js +500 -0
  196. package/mcp-server/authority-tools.js +569 -0
  197. package/mcp-server/conductor/conflict-resolver.js +588 -0
  198. package/mcp-server/conductor/execution-planner.js +544 -0
  199. package/mcp-server/conductor/index.js +377 -0
  200. package/mcp-server/conductor/lock-manager.js +615 -0
  201. package/mcp-server/conductor/request-queue.js +550 -0
  202. package/mcp-server/conductor/session-manager.js +500 -0
  203. package/mcp-server/conductor/tools.js +510 -0
  204. package/mcp-server/deprecation-middleware.js +282 -0
  205. package/mcp-server/handlers/index.ts +15 -0
  206. package/mcp-server/handlers/tool-handler.ts +474 -591
  207. package/mcp-server/index.js +1748 -1099
  208. package/mcp-server/lib/api-client.cjs +13 -0
  209. package/mcp-server/lib/cache-wrapper.cjs +383 -0
  210. package/mcp-server/lib/error-envelope.js +138 -0
  211. package/mcp-server/lib/executor.ts +428 -721
  212. package/mcp-server/lib/index.ts +19 -0
  213. package/mcp-server/lib/logger.cjs +30 -0
  214. package/mcp-server/lib/rate-limiter.js +166 -0
  215. package/mcp-server/lib/sandbox.test.ts +519 -0
  216. package/mcp-server/lib/sandbox.ts +342 -284
  217. package/mcp-server/lib/types.ts +267 -0
  218. package/mcp-server/logger.js +173 -0
  219. package/mcp-server/package.json +11 -27
  220. package/mcp-server/premium-tools.js +2 -2
  221. package/mcp-server/registry/tool-registry.js +794 -0
  222. package/mcp-server/registry/tools.json +507 -378
  223. package/mcp-server/registry.test.ts +334 -0
  224. package/mcp-server/tests/tier-gating.test.js +297 -0
  225. package/mcp-server/tier-auth.js +492 -347
  226. package/mcp-server/tools-v3.js +950 -0
  227. package/mcp-server/truth-context.js +131 -90
  228. package/mcp-server/truth-firewall-tools.js +1612 -1001
  229. package/mcp-server/tsconfig.json +8 -5
  230. package/mcp-server/vibecheck-2.0-tools.js +14 -1
  231. package/mcp-server/vibecheck-mcp-server-3.2.0.tgz +0 -0
  232. package/mcp-server/vibecheck-tools.js +2 -2
  233. package/package.json +4 -3
  234. package/bin/runners/runInstall.js +0 -281
  235. package/mcp-server/ARCHITECTURE.md +0 -339
  236. package/mcp-server/__tests__/cache.test.ts +0 -313
  237. package/mcp-server/__tests__/executor.test.ts +0 -239
  238. package/mcp-server/__tests__/fixtures/exclusion-test/.cache/webpack/cache.pack +0 -1
  239. package/mcp-server/__tests__/fixtures/exclusion-test/.next/server/chunk.js +0 -3
  240. package/mcp-server/__tests__/fixtures/exclusion-test/.turbo/cache.json +0 -3
  241. package/mcp-server/__tests__/fixtures/exclusion-test/.venv/lib/env.py +0 -3
  242. package/mcp-server/__tests__/fixtures/exclusion-test/dist/bundle.js +0 -3
  243. package/mcp-server/__tests__/fixtures/exclusion-test/package.json +0 -5
  244. package/mcp-server/__tests__/fixtures/exclusion-test/src/app.ts +0 -5
  245. package/mcp-server/__tests__/fixtures/exclusion-test/venv/lib/config.py +0 -4
  246. package/mcp-server/__tests__/ids.test.ts +0 -345
  247. package/mcp-server/__tests__/integration/tools.test.ts +0 -410
  248. package/mcp-server/__tests__/registry.test.ts +0 -365
  249. package/mcp-server/__tests__/sandbox.test.ts +0 -323
  250. package/mcp-server/__tests__/schemas.test.ts +0 -372
  251. package/mcp-server/benchmarks/run-benchmarks.ts +0 -304
  252. package/mcp-server/examples/doctor.request.json +0 -14
  253. package/mcp-server/examples/doctor.response.json +0 -53
  254. package/mcp-server/examples/error.response.json +0 -15
  255. package/mcp-server/examples/scan.request.json +0 -14
  256. package/mcp-server/examples/scan.response.json +0 -108
  257. package/mcp-server/index-v3.ts +0 -293
  258. package/mcp-server/index.old.js +0 -4137
  259. package/mcp-server/lib/cache.ts +0 -341
  260. package/mcp-server/lib/errors.ts +0 -346
  261. package/mcp-server/lib/ids.ts +0 -238
  262. package/mcp-server/lib/logger.ts +0 -368
  263. package/mcp-server/lib/metrics.ts +0 -365
  264. package/mcp-server/lib/validator.ts +0 -229
  265. package/mcp-server/package-lock.json +0 -165
  266. package/mcp-server/schemas/error-envelope.schema.json +0 -125
  267. package/mcp-server/schemas/finding.schema.json +0 -167
  268. package/mcp-server/schemas/report-artifact.schema.json +0 -88
  269. package/mcp-server/schemas/run-request.schema.json +0 -75
  270. package/mcp-server/schemas/verdict.schema.json +0 -168
  271. package/mcp-server/tier-auth.d.ts +0 -71
  272. package/mcp-server/vitest.config.ts +0 -16
package/bin/vibecheck.js CHANGED
@@ -795,18 +795,88 @@ ${c.bold}Installation:${c.reset}
795
795
  }
796
796
 
797
797
  // ═══════════════════════════════════════════════════════════════════════════════
798
- // HELP SYSTEM
798
+ // HELP SYSTEM - World-Class CLI Experience
799
799
  // ═══════════════════════════════════════════════════════════════════════════════
800
800
  function printBanner() {
801
801
  const VERSION = getVersion();
802
802
  console.log(`
803
- ${c.dim}${sym.boxTopLeft}${sym.boxHorizontal.repeat(60)}${sym.boxTopRight}${c.reset}
804
- ${c.dim}${sym.boxVertical}${c.reset} ${gradient("VIBECHECK", [[0, 255, 255], [138, 43, 226], [255, 20, 147]])} ${c.dim}v${VERSION}${c.reset}${" ".repeat(60 - 13 - VERSION.length - 4)}${c.dim}${sym.boxVertical}${c.reset}
805
- ${c.dim}${sym.boxVertical}${c.reset} ${c.dim}Ship with confidence. Catch fake features before users do.${c.reset} ${c.dim}${sym.boxVertical}${c.reset}
806
- ${c.dim}${sym.boxBottomLeft}${sym.boxHorizontal.repeat(60)}${sym.boxBottomRight}${c.reset}
803
+ ${c.dim}${sym.boxTopLeft}${sym.boxHorizontal.repeat(64)}${sym.boxTopRight}${c.reset}
804
+ ${c.dim}${sym.boxVertical}${c.reset} ${gradient("VIBECHECK", [[0, 255, 255], [138, 43, 226], [255, 20, 147]])} ${c.dim}v${VERSION}${c.reset}${" ".repeat(64 - 13 - VERSION.length - 4)}${c.dim}${sym.boxVertical}${c.reset}
805
+ ${c.dim}${sym.boxVertical}${c.reset} ${c.dim}${sym.boxVertical}${c.reset}
806
+ ${c.dim}${sym.boxVertical}${c.reset} ${c.bold}Catch AI hallucinations before your users do.${c.reset} ${c.dim}${sym.boxVertical}${c.reset}
807
+ ${c.dim}${sym.boxVertical}${c.reset} ${c.dim}${sym.boxVertical}${c.reset}
808
+ ${c.dim}${sym.boxVertical}${c.reset} ${c.cyan}${sym.check}${c.reset} Detects routes that look real but don't work ${c.dim}${sym.boxVertical}${c.reset}
809
+ ${c.dim}${sym.boxVertical}${c.reset} ${c.cyan}${sym.check}${c.reset} Finds env vars used but never declared ${c.dim}${sym.boxVertical}${c.reset}
810
+ ${c.dim}${sym.boxVertical}${c.reset} ${c.cyan}${sym.check}${c.reset} Flags auth endpoints with no protection ${c.dim}${sym.boxVertical}${c.reset}
811
+ ${c.dim}${sym.boxVertical}${c.reset} ${c.dim}${sym.boxVertical}${c.reset}
812
+ ${c.dim}${sym.boxVertical}${c.reset} ${c.dim}SHIP = proof your code works. Not a vibe check.${c.reset} ${c.dim}${sym.boxVertical}${c.reset}
813
+ ${c.dim}${sym.boxBottomLeft}${sym.boxHorizontal.repeat(64)}${sym.boxBottomRight}${c.reset}
807
814
  `);
808
815
  }
809
816
 
817
+ /**
818
+ * Print command-specific help with rich examples
819
+ */
820
+ function printCommandHelp(cmd) {
821
+ const registry = getRegistry();
822
+ const def = registry.COMMANDS[cmd];
823
+ if (!def) return false;
824
+
825
+ // Build reverse alias map
826
+ const reverseAliases = {};
827
+ for (const [alias, target] of Object.entries(registry.ALIAS_MAP)) {
828
+ if (!reverseAliases[target]) reverseAliases[target] = [];
829
+ reverseAliases[target].push(alias);
830
+ }
831
+
832
+ const aliases = reverseAliases[cmd] || [];
833
+
834
+ // Tier badge (2-tier: FREE / PRO)
835
+ const tierBadge = def.tier === "free" ? `${c.green}[FREE]${c.reset}` :
836
+ def.tier === "pro" ? `${c.magenta}[PRO]${c.reset}` : "";
837
+
838
+ console.log(`
839
+ ${c.bold}${sym.arrowRight} vibecheck ${cmd}${c.reset} ${tierBadge}
840
+ ${aliases.length > 0 ? `${c.dim}Aliases: ${aliases.join(", ")}${c.reset}` : ""}
841
+
842
+ ${def.longDescription || def.description}
843
+ `);
844
+
845
+ // Examples
846
+ if (def.examples && def.examples.length > 0) {
847
+ console.log(` ${c.bold}${sym.star} EXAMPLES${c.reset}\n`);
848
+ for (const ex of def.examples) {
849
+ const exTier = ex.tier === "pro" ? `${c.magenta}[PRO]${c.reset} ` : "";
850
+ console.log(` ${c.dim}#${c.reset} ${ex.description} ${exTier}`);
851
+ console.log(` ${c.cyan}${ex.command}${c.reset}`);
852
+ console.log();
853
+ }
854
+ }
855
+
856
+ // Related commands
857
+ if (def.related && def.related.length > 0) {
858
+ console.log(` ${c.bold}${sym.arrowRight} RELATED COMMANDS${c.reset}\n`);
859
+ for (const relCmd of def.related) {
860
+ const relDef = registry.COMMANDS[relCmd];
861
+ if (relDef) {
862
+ const relTier = relDef.tier === "pro" ? `${c.magenta}[PRO]${c.reset} ` : "";
863
+ console.log(` ${c.cyan}vibecheck ${relCmd}${c.reset} ${relTier}${c.dim}${relDef.description}${c.reset}`);
864
+ }
865
+ }
866
+ console.log();
867
+ }
868
+
869
+ // Documentation link
870
+ if (def.docsUrl) {
871
+ console.log(` ${c.dim}${sym.boxHorizontal.repeat(56)}${c.reset}`);
872
+ console.log(` ${c.dim}Documentation: ${c.underline}${def.docsUrl}${c.reset}`);
873
+ }
874
+
875
+ console.log(` ${c.dim}Run 'vibecheck --help' for all commands.${c.reset}\n`);
876
+
877
+ return true;
878
+ }
879
+
810
880
  function printHelp(showBanner = true) {
811
881
  if (showBanner) printBanner();
812
882
 
@@ -852,10 +922,9 @@ function printHelp(showBanner = true) {
852
922
  console.log(`\n${cat.color}${cat.icon} ${cat.name}${c.reset}\n`);
853
923
 
854
924
  for (const { cmd, description, tier, caps } of commands) {
855
- // Tier badge
925
+ // Tier badge (2-tier: FREE / PRO)
856
926
  let tierBadge = "";
857
927
  if (tier === "free") tierBadge = `${c.green}[FREE]${c.reset} `;
858
- else if (tier === "starter") tierBadge = `${c.cyan}[STARTER]${c.reset} `;
859
928
  else if (tier === "pro") tierBadge = `${c.magenta}[PRO]${c.reset} `;
860
929
 
861
930
  // Aliases (from reverseAliases map built earlier)
@@ -874,39 +943,98 @@ function printHelp(showBanner = true) {
874
943
  console.log(`
875
944
  ${c.dim}${sym.boxHorizontal.repeat(64)}${c.reset}
876
945
 
877
- ${c.green}TIERS${c.reset}
946
+ ${c.green}${sym.star} PRICING TIERS${c.reset}
947
+
948
+ ${c.green}FREE${c.reset} ${c.dim}$0${c.reset} scan, ship, report, context, doctor, polish - full visibility
949
+ ${c.magenta}PRO${c.reset} ${c.dim}$69/mo${c.reset} + autofix, prove, reality, mcp, guard, ai-test, PR comments
878
950
 
879
- ${c.green}FREE${c.reset} $0 init --local, scan, ship (static), report (HTML/MD), doctor, polish
880
- ${c.cyan}STARTER${c.reset} $39/mo + init --connect, scan --autofix, report (SARIF/CSV), mcp, PR comments
881
- ${c.magenta}PRO${c.reset} $99/mo + prove, fix --apply, checkpoint (hallucination), reality (advanced)
951
+ ${c.green}${sym.rocket} QUICK START (2 minutes to first proof)${c.reset}
882
952
 
883
- ${c.green}QUICK START - The 5-Step Journey${c.reset}
953
+ ${c.bold}Option 1: One command${c.reset}
954
+ ${c.cyan}vibecheck quickstart${c.reset} ${c.dim}Runs doctor → ctx → scan → ship → report${c.reset}
884
955
 
885
- 1. ${c.bold}Setup${c.reset} ${c.cyan}vibecheck init --local${c.reset}
886
- 2. ${c.bold}Scan${c.reset} ${c.cyan}vibecheck scan${c.reset}
887
- 3. ${c.bold}Fix${c.reset} ${c.cyan}vibecheck scan --autofix${c.reset} ${c.cyan}[STARTER]${c.reset}
888
- 4. ${c.bold}Prove${c.reset} ${c.cyan}vibecheck prove${c.reset} ${c.magenta}[PRO]${c.reset}
889
- 5. ${c.bold}Ship${c.reset} ${c.cyan}vibecheck ship${c.reset}
956
+ ${c.bold}Option 2: Step by step${c.reset}
957
+ ${c.bold}1.${c.reset} ${c.cyan}vibecheck init${c.reset} ${c.dim}Set up your project${c.reset}
958
+ ${c.bold}2.${c.reset} ${c.cyan}vibecheck scan${c.reset} ${c.dim}Analyze your codebase${c.reset}
959
+ ${c.bold}3.${c.reset} ${c.cyan}vibecheck ship${c.reset} ${c.dim}Get shipping verdict${c.reset}
960
+
961
+ ${c.green}${sym.lightning} COMMON WORKFLOWS${c.reset}
962
+
963
+ ${c.dim}# Quick health check${c.reset}
964
+ ${c.cyan}vibecheck doctor${c.reset}
965
+
966
+ ${c.dim}# Scan and auto-fix${c.reset}
967
+ ${c.cyan}vibecheck scan --autofix${c.reset}
968
+
969
+ ${c.dim}# Full proof with evidence pack${c.reset}
970
+ ${c.cyan}vibecheck prove --url http://localhost:3000 --bundle${c.reset}
890
971
 
891
972
  ${c.bold}GLOBAL OPTIONS${c.reset}
892
973
 
893
- ${c.cyan}--offline, --local${c.reset} Run in offline mode (no API, unlimited local scans)
894
- ${c.cyan}--json${c.reset} Output as JSON
895
- ${c.cyan}--quiet, -q${c.reset} Suppress output
896
- ${c.cyan}--verbose${c.reset} Show detailed output
974
+ ${c.cyan}--help, -h${c.reset} Show help for any command
975
+ ${c.cyan}--json${c.reset} Machine-readable JSON output
976
+ ${c.cyan}--quiet, -q${c.reset} Suppress non-essential output
977
+ ${c.cyan}--verbose${c.reset} Detailed output for debugging
978
+ ${c.cyan}--ci${c.reset} CI mode (quiet + no-banner)
979
+ ${c.cyan}--offline${c.reset} Run without API connection
897
980
  ${c.cyan}--path, -p <dir>${c.reset} Run in specified directory
898
981
 
899
982
  ${c.bold}SHELL COMPLETIONS${c.reset}
900
983
 
901
- ${c.cyan}vibecheck completion bash${c.reset} ${c.dim}# Add to ~/.bashrc${c.reset}
902
- ${c.cyan}vibecheck completion zsh${c.reset} ${c.dim}# Add to ~/.zshrc${c.reset}
903
- ${c.cyan}vibecheck completion fish${c.reset} ${c.dim}# Save to completions dir${c.reset}
984
+ ${c.cyan}vibecheck completion bash${c.reset} ${c.dim}# Bash (add to ~/.bashrc)${c.reset}
985
+ ${c.cyan}vibecheck completion zsh${c.reset} ${c.dim}# Zsh (add to ~/.zshrc)${c.reset}
986
+ ${c.cyan}vibecheck completion fish${c.reset} ${c.dim}# Fish (save to completions)${c.reset}
904
987
 
905
- ${c.dim}Run 'vibecheck <command> --help' for command-specific help.${c.reset}
988
+ ${c.dim}${sym.boxHorizontal.repeat(64)}${c.reset}
989
+ ${c.dim}Run 'vibecheck <command> --help' for detailed command help.${c.reset}
990
+ ${c.dim}Documentation: https://docs.vibecheckai.dev${c.reset}
906
991
  ${c.dim}Pricing: https://vibecheckai.dev/pricing${c.reset}
907
992
  `);
908
993
  }
909
994
 
995
+ // ═══════════════════════════════════════════════════════════════════════════════
996
+ // HELP VALIDATION
997
+ // ═══════════════════════════════════════════════════════════════════════════════
998
+
999
+ /**
1000
+ * Self-test function to verify help output matches actual commands
1001
+ * Run with: node bin/vibecheck.js --self-test
1002
+ */
1003
+ function validateHelpOutput() {
1004
+ const registry = getRegistry();
1005
+ const { COMMANDS, ALIAS_MAP } = registry;
1006
+
1007
+ // Extract commands from help text (simplified - just check registry)
1008
+ const actualCommands = Object.keys(COMMANDS);
1009
+ const actualAliases = Object.keys(ALIAS_MAP);
1010
+ const allActualCommands = [...actualCommands, ...actualAliases];
1011
+
1012
+ // Check for obvious issues
1013
+ const issues = [];
1014
+
1015
+ // Check that all commands have runners
1016
+ for (const [cmd, def] of Object.entries(COMMANDS)) {
1017
+ if (!def.runner) {
1018
+ issues.push(`Command '${cmd}' missing runner`);
1019
+ }
1020
+ }
1021
+
1022
+ // Check that aliases point to valid commands
1023
+ for (const [alias, target] of Object.entries(ALIAS_MAP)) {
1024
+ if (!COMMANDS[target]) {
1025
+ issues.push(`Alias '${alias}' points to non-existent command '${target}'`);
1026
+ }
1027
+ }
1028
+
1029
+ if (issues.length > 0) {
1030
+ console.error('Help output validation failed:');
1031
+ issues.forEach(issue => console.error(` - ${issue}`));
1032
+ return false;
1033
+ }
1034
+
1035
+ return true;
1036
+ }
1037
+
910
1038
  // ═══════════════════════════════════════════════════════════════════════════════
911
1039
  // HELPER FUNCTIONS
912
1040
  // ═══════════════════════════════════════════════════════════════════════════════
@@ -933,6 +1061,50 @@ function formatError(error, config) {
933
1061
  return lines.join("\n");
934
1062
  }
935
1063
 
1064
+ /**
1065
+ * Map error to standardized exit code
1066
+ * @param {Error} error - Error object
1067
+ * @param {boolean} json - Whether JSON output is requested
1068
+ * @returns {number} Exit code
1069
+ */
1070
+ function mapErrorToExitCode(error, json = false) {
1071
+ const EXIT_CODES = {
1072
+ 'AUTH_REQUIRED': 5,
1073
+ 'AUTH_FAILED': 6,
1074
+ 'TIER_REQUIRED': 7,
1075
+ 'RATE_LIMITED': 8,
1076
+ 'NOT_FOUND': 4,
1077
+ 'VALIDATION_ERROR': 3,
1078
+ 'USER_ERROR': 3,
1079
+ 'NETWORK_ERROR': 9,
1080
+ };
1081
+
1082
+ // Check error.code first
1083
+ if (error.code && EXIT_CODES[error.code]) {
1084
+ return EXIT_CODES[error.code];
1085
+ }
1086
+
1087
+ // Check error.exitCode
1088
+ if (error.exitCode !== undefined) {
1089
+ return error.exitCode;
1090
+ }
1091
+
1092
+ // Check error message for common patterns
1093
+ const message = error.message?.toLowerCase() || '';
1094
+ if (message.includes('not found') || message.includes('not exist')) {
1095
+ return 4; // NOT_FOUND
1096
+ }
1097
+ if (message.includes('auth') || message.includes('login')) {
1098
+ return 5; // AUTH_REQUIRED
1099
+ }
1100
+ if (message.includes('network') || message.includes('connection')) {
1101
+ return 9; // NETWORK_ERROR
1102
+ }
1103
+
1104
+ // Default to internal error
1105
+ return 10; // INTERNAL_ERROR
1106
+ }
1107
+
936
1108
  // ═══════════════════════════════════════════════════════════════════════════════
937
1109
  // FLAG PARSING
938
1110
  // ═══════════════════════════════════════════════════════════════════════════════
@@ -1032,6 +1204,16 @@ async function main() {
1032
1204
  process.exit(0);
1033
1205
  }
1034
1206
 
1207
+ // Handle self-test flag (for CI validation)
1208
+ if (cleanArgs.includes('--self-test')) {
1209
+ const registry = getRegistry();
1210
+ if (!validateHelpOutput()) {
1211
+ process.exit(1);
1212
+ }
1213
+ console.log('Self-test passed: Help output matches command registry');
1214
+ process.exit(0);
1215
+ }
1216
+
1035
1217
  // Load config and state
1036
1218
  const config = loadConfig();
1037
1219
  const state = loadState();
@@ -1074,6 +1256,14 @@ async function main() {
1074
1256
  }
1075
1257
  let cmdArgs = cleanArgs.slice(1);
1076
1258
 
1259
+ // Handle command-specific help (vibecheck <cmd> --help)
1260
+ if (globalFlags.help && cmd && COMMANDS[cmd]) {
1261
+ // Try our rich help first, then fall back to runner's --help
1262
+ if (printCommandHelp(cmd)) {
1263
+ process.exit(0);
1264
+ }
1265
+ }
1266
+
1077
1267
  // Pass --help to runner if specified with command
1078
1268
  if (globalFlags.help) cmdArgs = ["--help", ...cmdArgs];
1079
1269
 
@@ -1117,47 +1307,80 @@ async function main() {
1117
1307
  const cmdDef = COMMANDS[cmd];
1118
1308
  let authInfo = { key: null };
1119
1309
 
1120
- // Check for offline mode (via flag or env var)
1310
+ // Check for offline/dev mode (via flag or env var)
1311
+ // SECURITY: VIBECHECK_DEV_PRO only works in non-production to prevent auth bypass
1312
+ const isDevProAllowed = process.env.NODE_ENV !== 'production' &&
1313
+ process.env.CI !== 'true' &&
1314
+ process.env.CI !== '1' &&
1315
+ process.env.VIBECHECK_DEV_PRO === '1';
1121
1316
  const isOffline = globalFlags.offline ||
1122
1317
  process.env.VIBECHECK_OFFLINE === '1' ||
1123
- process.env.VIBECHECK_LOCAL === '1';
1318
+ process.env.VIBECHECK_LOCAL === '1' ||
1319
+ isDevProAllowed;
1124
1320
 
1125
1321
  // Auth check (unless skipAuth or offline mode)
1126
- if (!cmdDef.skipAuth && !isOffline) {
1322
+ // Only allow login, logout, whoami, and help without auth
1323
+ const authExemptCommands = ['login', 'logout', 'whoami', 'help', '--help', '-h', 'version', '--version'];
1324
+ const needsAuth = !authExemptCommands.includes(cmd) && !cmdDef.skipAuth && !isOffline;
1325
+
1326
+ if (needsAuth) {
1127
1327
  const auth = getAuthModule();
1128
1328
  const { key } = auth.getApiKey();
1129
1329
  authInfo.key = key;
1130
1330
 
1331
+ // If no API key, prompt for login
1332
+ if (!key) {
1333
+ console.log(`\n ${c.red}❌ Authentication Required${c.reset}`);
1334
+ console.log(` Please log in to use vibecheck.\n`);
1335
+ console.log(` ${c.cyan}Options:${c.reset}`);
1336
+ console.log(` 1. Press ${c.yellow}Enter${c.reset} to open browser and sign up`);
1337
+ console.log(` 2. Visit ${c.underline}https://vibecheckai.dev${c.reset} directly`);
1338
+ console.log(` 3. Run ${c.cyan}vibecheck login${c.reset} after getting your API key\n`);
1339
+
1340
+ // Wait for Enter key
1341
+ const readline = getReadline();
1342
+ readline.createInterface({
1343
+ input: process.stdin,
1344
+ output: process.stdout
1345
+ }).question('', async () => {
1346
+ try {
1347
+ const https = getHttps();
1348
+ const url = 'https://vibecheckai.dev';
1349
+ console.log(`\n Opening ${c.underline}${url}${c.reset} in your browser...\n`);
1350
+
1351
+ // Try to open browser
1352
+ const start = process.platform === 'darwin' ? 'open' :
1353
+ process.platform === 'win32' ? 'start' : 'xdg-open';
1354
+ require('child_process').exec(`${start} ${url}`);
1355
+ } catch (e) {
1356
+ console.log(` Could not open browser. Please visit: ${c.underline}https://vibecheckai.dev${c.reset}`);
1357
+ }
1358
+ process.exit(0);
1359
+ });
1360
+
1361
+ // Keep process alive
1362
+ return new Promise(() => {});
1363
+ }
1364
+
1131
1365
  const access = await checkCommandAccess(cmd, cmdArgs, authInfo);
1132
1366
 
1133
1367
  if (!access.allowed) {
1134
1368
  console.log(access.reason);
1135
- process.exit(access.exitCode || 3);
1136
- }
1137
-
1138
- // Downgrade notice
1139
- if (access.downgrade && !config.quiet) {
1140
- const upsell = getUpsell();
1141
- console.log(upsell.formatDowngrade(cmd, {
1142
- currentTier: access.tier,
1143
- effectiveMode: access.downgrade,
1144
- caps: access.caps,
1145
- }));
1146
- }
1147
-
1148
- // Tier badge
1149
- if (!config.quiet && !config.noBanner) {
1150
- if (access.tier === "pro") {
1151
- console.log(`${c.magenta}${sym.arrowRight} PRO${c.reset} ${c.dim}feature${c.reset}`);
1152
- } else if (access.tier === "complete") {
1153
- console.log(`${c.yellow}${sym.arrowRight} COMPLETE${c.reset} ${c.dim}feature${c.reset}`);
1369
+
1370
+ // Show upgrade prompt if tier insufficient
1371
+ if (access.upgradeUrl) {
1372
+ console.log(`\n ${c.cyan}Upgrade:${c.reset} ${access.upgradeUrl}`);
1154
1373
  }
1374
+
1375
+ return 1;
1155
1376
  }
1156
1377
 
1157
1378
  authInfo.access = access;
1158
1379
  } else if (isOffline) {
1159
1380
  // Offline mode - provide basic access info
1160
- if (!config.quiet && !config.noBanner) {
1381
+ // Suppress message if JSON/SARIF output is requested (check both global flags and command args)
1382
+ const hasJsonOutput = globalFlags.json || cmdArgs.includes('--json') || cmdArgs.includes('--sarif');
1383
+ if (!config.quiet && !config.noBanner && !hasJsonOutput) {
1161
1384
  console.log(`${c.cyan}${sym.arrowRight} OFFLINE${c.reset} ${c.dim}mode - local scanning without API${c.reset}`);
1162
1385
  }
1163
1386
  authInfo.access = {
@@ -1186,7 +1409,7 @@ async function main() {
1186
1409
  const runner = getRunner(cmd);
1187
1410
  if (!runner) {
1188
1411
  console.error(`${c.red}${sym.error}${c.reset} Failed to load runner for: ${cmd}`);
1189
- process.exit(1);
1412
+ process.exit(4); // NOT_FOUND
1190
1413
  }
1191
1414
 
1192
1415
  const context = {
@@ -1201,10 +1424,32 @@ async function main() {
1201
1424
  };
1202
1425
 
1203
1426
  // Execute command - all commands use consistent runner signature
1204
- exitCode = await runner(cmdArgs, context);
1427
+ const result = await runner(cmdArgs, context);
1428
+
1429
+ // Ensure result has standardized exit code
1430
+ if (typeof result === 'object' && result.exitCode !== undefined) {
1431
+ exitCode = result.exitCode;
1432
+ } else if (typeof result === 'number') {
1433
+ exitCode = result;
1434
+ } else {
1435
+ exitCode = 0; // SUCCESS
1436
+ }
1205
1437
  } catch (error) {
1206
- console.error(formatError(error, config));
1207
- exitCode = 1;
1438
+ // Map errors to exit codes
1439
+ exitCode = mapErrorToExitCode(error, globalFlags.json);
1440
+
1441
+ if (globalFlags.json) {
1442
+ console.log(JSON.stringify({
1443
+ success: false,
1444
+ error: {
1445
+ code: error.code || 'INTERNAL_ERROR',
1446
+ message: error.message,
1447
+ },
1448
+ exitCode,
1449
+ }, null, 2));
1450
+ } else {
1451
+ console.error(formatError(error, config));
1452
+ }
1208
1453
  }
1209
1454
 
1210
1455
  // Create receipt for paid commands