@vibecheckai/cli 2.8.2 → 3.0.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.
Files changed (454) hide show
  1. package/README.md +8 -8
  2. package/bin/_deprecations.js +35 -0
  3. package/bin/_router.js +46 -0
  4. package/bin/cli-hygiene.js +241 -0
  5. package/bin/guardrail.js +834 -0
  6. package/bin/runners/cli-utils.js +1070 -0
  7. package/bin/runners/context/ai-task-decomposer.js +337 -0
  8. package/bin/runners/context/analyzer.js +462 -0
  9. package/bin/runners/context/api-contracts.js +427 -0
  10. package/bin/runners/context/context-diff.js +342 -0
  11. package/bin/runners/context/context-pruner.js +291 -0
  12. package/bin/runners/context/dependency-graph.js +414 -0
  13. package/bin/runners/context/generators/claude.js +107 -0
  14. package/bin/runners/context/generators/codex.js +108 -0
  15. package/bin/runners/context/generators/copilot.js +119 -0
  16. package/bin/runners/context/generators/cursor.js +514 -0
  17. package/bin/runners/context/generators/mcp.js +151 -0
  18. package/bin/runners/context/generators/windsurf.js +180 -0
  19. package/bin/runners/context/git-context.js +302 -0
  20. package/bin/runners/context/index.js +1042 -0
  21. package/bin/runners/context/insights.js +173 -0
  22. package/bin/runners/context/mcp-server/generate-rules.js +337 -0
  23. package/bin/runners/context/mcp-server/index.js +1176 -0
  24. package/bin/runners/context/mcp-server/package.json +24 -0
  25. package/bin/runners/context/memory.js +200 -0
  26. package/bin/runners/context/monorepo.js +215 -0
  27. package/bin/runners/context/multi-repo-federation.js +404 -0
  28. package/bin/runners/context/patterns.js +253 -0
  29. package/bin/runners/context/proof-context.js +972 -0
  30. package/bin/runners/context/security-scanner.js +303 -0
  31. package/bin/runners/context/semantic-search.js +350 -0
  32. package/bin/runners/context/shared.js +264 -0
  33. package/bin/runners/context/team-conventions.js +310 -0
  34. package/bin/runners/lib/ai-bridge.js +416 -0
  35. package/bin/runners/lib/analysis-core.js +271 -0
  36. package/bin/runners/lib/analyzers.js +541 -0
  37. package/bin/runners/lib/audit-bridge.js +391 -0
  38. package/bin/runners/lib/auth-truth.js +193 -0
  39. package/bin/runners/lib/auth.js +215 -0
  40. package/bin/runners/lib/backup.js +62 -0
  41. package/bin/runners/lib/billing.js +107 -0
  42. package/bin/runners/lib/claims.js +118 -0
  43. package/bin/runners/lib/cli-ui.js +540 -0
  44. package/bin/runners/lib/compliance-bridge-new.js +0 -0
  45. package/bin/runners/lib/compliance-bridge.js +165 -0
  46. package/bin/runners/lib/contracts/auth-contract.js +194 -0
  47. package/bin/runners/lib/contracts/env-contract.js +178 -0
  48. package/bin/runners/lib/contracts/external-contract.js +198 -0
  49. package/bin/runners/lib/contracts/guard.js +168 -0
  50. package/bin/runners/lib/contracts/index.js +89 -0
  51. package/bin/runners/lib/contracts/plan-validator.js +311 -0
  52. package/bin/runners/lib/contracts/route-contract.js +192 -0
  53. package/bin/runners/lib/detect.js +89 -0
  54. package/bin/runners/lib/doctor/autofix.js +254 -0
  55. package/bin/runners/lib/doctor/index.js +37 -0
  56. package/bin/runners/lib/doctor/modules/dependencies.js +325 -0
  57. package/bin/runners/lib/doctor/modules/index.js +46 -0
  58. package/bin/runners/lib/doctor/modules/network.js +250 -0
  59. package/bin/runners/lib/doctor/modules/project.js +312 -0
  60. package/bin/runners/lib/doctor/modules/runtime.js +224 -0
  61. package/bin/runners/lib/doctor/modules/security.js +348 -0
  62. package/bin/runners/lib/doctor/modules/system.js +213 -0
  63. package/bin/runners/lib/doctor/modules/vibecheck.js +394 -0
  64. package/bin/runners/lib/doctor/reporter.js +262 -0
  65. package/bin/runners/lib/doctor/service.js +262 -0
  66. package/bin/runners/lib/doctor/types.js +113 -0
  67. package/bin/runners/lib/doctor/ui.js +263 -0
  68. package/bin/runners/lib/doctor-enhanced.js +233 -0
  69. package/bin/runners/lib/doctor-v2.js +608 -0
  70. package/bin/runners/lib/enforcement.js +72 -0
  71. package/bin/runners/lib/enterprise-detect.js +603 -0
  72. package/bin/runners/lib/enterprise-init.js +942 -0
  73. package/bin/runners/lib/entitlements-v2.js +381 -0
  74. package/bin/runners/lib/entitlements.generated.js +0 -0
  75. package/bin/runners/lib/entitlements.js +332 -0
  76. package/bin/runners/lib/env-template.js +66 -0
  77. package/bin/runners/lib/env.js +189 -0
  78. package/bin/runners/lib/error-handler.js +320 -0
  79. package/bin/runners/lib/firewall-prompt.js +50 -0
  80. package/bin/runners/lib/graph/graph-builder.js +265 -0
  81. package/bin/runners/lib/graph/html-renderer.js +413 -0
  82. package/bin/runners/lib/graph/index.js +32 -0
  83. package/bin/runners/lib/graph/runtime-collector.js +215 -0
  84. package/bin/runners/lib/graph/static-extractor.js +518 -0
  85. package/bin/runners/lib/init-wizard.js +308 -0
  86. package/bin/runners/lib/json-output.js +76 -0
  87. package/bin/runners/lib/llm.js +75 -0
  88. package/bin/runners/lib/meter.js +61 -0
  89. package/bin/runners/lib/missions/evidence.js +126 -0
  90. package/bin/runners/lib/missions/plan.js +69 -0
  91. package/bin/runners/lib/missions/templates.js +147 -0
  92. package/bin/runners/lib/patch.js +40 -0
  93. package/bin/runners/lib/permissions/auth-model.js +213 -0
  94. package/bin/runners/lib/permissions/idor-prover.js +205 -0
  95. package/bin/runners/lib/permissions/index.js +45 -0
  96. package/bin/runners/lib/permissions/matrix-builder.js +198 -0
  97. package/bin/runners/lib/pkgjson.js +28 -0
  98. package/bin/runners/lib/preflight.js +142 -0
  99. package/bin/runners/lib/reality-findings.js +84 -0
  100. package/bin/runners/lib/redact.js +29 -0
  101. package/bin/runners/lib/replay/capsule-manager.js +154 -0
  102. package/bin/runners/lib/replay/index.js +263 -0
  103. package/bin/runners/lib/replay/player.js +348 -0
  104. package/bin/runners/lib/replay/recorder.js +331 -0
  105. package/bin/runners/lib/report-engine.js +447 -0
  106. package/bin/runners/lib/report-html.js +1117 -0
  107. package/bin/runners/lib/report-templates.js +964 -0
  108. package/bin/runners/lib/route-detection.js +1140 -0
  109. package/bin/runners/lib/route-truth.js +477 -0
  110. package/bin/runners/lib/sandbox/index.js +59 -0
  111. package/bin/runners/lib/sandbox/proof-chain.js +399 -0
  112. package/bin/runners/lib/sandbox/sandbox-runner.js +205 -0
  113. package/bin/runners/lib/sandbox/worktree.js +174 -0
  114. package/bin/runners/lib/scan-cache.js +330 -0
  115. package/bin/runners/lib/scan-output-schema.js +344 -0
  116. package/bin/runners/lib/score-history.js +282 -0
  117. package/bin/runners/lib/security-bridge.js +249 -0
  118. package/bin/runners/lib/server-usage.js +513 -0
  119. package/bin/runners/lib/share-pack.js +239 -0
  120. package/bin/runners/lib/snippets.js +67 -0
  121. package/bin/runners/lib/truth.js +667 -0
  122. package/bin/runners/lib/unified-output.js +189 -0
  123. package/bin/runners/lib/validate-patch.js +156 -0
  124. package/bin/runners/lib/verification.js +345 -0
  125. package/bin/runners/reality/engine.js +917 -0
  126. package/bin/runners/reality/flows.js +122 -0
  127. package/bin/runners/reality/report.js +378 -0
  128. package/bin/runners/reality/session.js +193 -0
  129. package/bin/runners/runAIAgent.js +2 -0
  130. package/bin/runners/runAudit.js +2 -0
  131. package/bin/runners/runAuth.js +106 -0
  132. package/bin/runners/runAutopilot.js +2 -0
  133. package/bin/runners/runBadge.js +2 -0
  134. package/bin/runners/runCertify.js +2 -0
  135. package/bin/runners/runClaimVerifier.js +483 -0
  136. package/bin/runners/runContext.js +56 -0
  137. package/bin/runners/runContextCompiler.js +385 -0
  138. package/bin/runners/runCtx.js +187 -0
  139. package/bin/runners/runCtxGuard.js +176 -0
  140. package/bin/runners/runCtxSync.js +116 -0
  141. package/bin/runners/runDashboard.js +10 -0
  142. package/bin/runners/runDoctor.js +245 -0
  143. package/bin/runners/runEnhancedShip.js +2 -0
  144. package/bin/runners/runFix.js +735 -0
  145. package/bin/runners/runFixPacks.js +2 -0
  146. package/bin/runners/runGate.js +17 -0
  147. package/bin/runners/runGraph.js +283 -0
  148. package/bin/runners/runInit.js +260 -0
  149. package/bin/runners/runInitGha.js +101 -0
  150. package/bin/runners/runInstall.js +76 -0
  151. package/bin/runners/runInteractive.js +388 -0
  152. package/bin/runners/runLaunch.js +2 -0
  153. package/bin/runners/runMcp.js +19 -0
  154. package/bin/runners/runMdc.js +2 -0
  155. package/bin/runners/runMissionGenerator.js +282 -0
  156. package/bin/runners/runNaturalLanguage.js +3 -0
  157. package/bin/runners/runPR.js +96 -0
  158. package/bin/runners/runPermissions.js +290 -0
  159. package/bin/runners/runPromptFirewall.js +211 -0
  160. package/bin/runners/runProof.js +2 -0
  161. package/bin/runners/runProve.js +392 -0
  162. package/bin/runners/runReality.js +489 -0
  163. package/bin/runners/runRealitySniff.js +2 -0
  164. package/bin/runners/runReplay.js +469 -0
  165. package/bin/runners/runReport.js +478 -0
  166. package/bin/runners/runScan.js +835 -0
  167. package/bin/runners/runShare.js +34 -0
  168. package/bin/runners/runShip.js +1062 -0
  169. package/bin/runners/runStatus.js +136 -0
  170. package/bin/runners/runTruthpack.js +634 -0
  171. package/bin/runners/runUpgrade.js +2 -0
  172. package/bin/runners/runValidate.js +2 -0
  173. package/bin/runners/runVerifyAgentOutput.js +2 -0
  174. package/bin/runners/runWatch.js +230 -0
  175. package/bin/runners/utils.js +360 -0
  176. package/bin/scan.js +612 -0
  177. package/bin/vibecheck.js +834 -0
  178. package/package.json +11 -11
  179. package/dist/autopatch/verified-autopatch.d.ts +0 -111
  180. package/dist/autopatch/verified-autopatch.d.ts.map +0 -1
  181. package/dist/autopatch/verified-autopatch.js +0 -503
  182. package/dist/autopatch/verified-autopatch.js.map +0 -1
  183. package/dist/bundles/index.js +0 -8
  184. package/dist/bundles/vibecheck-core.js +0 -25799
  185. package/dist/bundles/vibecheck-security.js +0 -208693
  186. package/dist/bundles/vibecheck-ship.js +0 -2318
  187. package/dist/commands/baseline.d.ts +0 -7
  188. package/dist/commands/baseline.d.ts.map +0 -1
  189. package/dist/commands/baseline.js +0 -79
  190. package/dist/commands/baseline.js.map +0 -1
  191. package/dist/commands/cache.d.ts +0 -13
  192. package/dist/commands/cache.d.ts.map +0 -1
  193. package/dist/commands/cache.js +0 -165
  194. package/dist/commands/cache.js.map +0 -1
  195. package/dist/commands/checkpoint.d.ts +0 -8
  196. package/dist/commands/checkpoint.d.ts.map +0 -1
  197. package/dist/commands/checkpoint.js +0 -35
  198. package/dist/commands/checkpoint.js.map +0 -1
  199. package/dist/commands/doctor.d.ts +0 -17
  200. package/dist/commands/doctor.d.ts.map +0 -1
  201. package/dist/commands/doctor.js +0 -226
  202. package/dist/commands/doctor.js.map +0 -1
  203. package/dist/commands/evidence.d.ts +0 -45
  204. package/dist/commands/evidence.d.ts.map +0 -1
  205. package/dist/commands/evidence.js +0 -197
  206. package/dist/commands/evidence.js.map +0 -1
  207. package/dist/commands/explain.d.ts +0 -8
  208. package/dist/commands/explain.d.ts.map +0 -1
  209. package/dist/commands/explain.js +0 -52
  210. package/dist/commands/explain.js.map +0 -1
  211. package/dist/commands/fix-consolidated.d.ts +0 -19
  212. package/dist/commands/fix-consolidated.d.ts.map +0 -1
  213. package/dist/commands/fix-consolidated.js +0 -165
  214. package/dist/commands/fix-consolidated.js.map +0 -1
  215. package/dist/commands/index.d.ts +0 -8
  216. package/dist/commands/index.d.ts.map +0 -1
  217. package/dist/commands/index.js +0 -15
  218. package/dist/commands/index.js.map +0 -1
  219. package/dist/commands/init.d.ts +0 -8
  220. package/dist/commands/init.d.ts.map +0 -1
  221. package/dist/commands/init.js +0 -125
  222. package/dist/commands/init.js.map +0 -1
  223. package/dist/commands/launcher.d.ts +0 -10
  224. package/dist/commands/launcher.d.ts.map +0 -1
  225. package/dist/commands/launcher.js +0 -174
  226. package/dist/commands/launcher.js.map +0 -1
  227. package/dist/commands/on.d.ts +0 -8
  228. package/dist/commands/on.d.ts.map +0 -1
  229. package/dist/commands/on.js +0 -123
  230. package/dist/commands/on.js.map +0 -1
  231. package/dist/commands/replay.d.ts +0 -8
  232. package/dist/commands/replay.d.ts.map +0 -1
  233. package/dist/commands/replay.js +0 -52
  234. package/dist/commands/replay.js.map +0 -1
  235. package/dist/commands/scan-consolidated.d.ts +0 -61
  236. package/dist/commands/scan-consolidated.d.ts.map +0 -1
  237. package/dist/commands/scan-consolidated.js +0 -243
  238. package/dist/commands/scan-consolidated.js.map +0 -1
  239. package/dist/commands/scan-secrets.d.ts +0 -47
  240. package/dist/commands/scan-secrets.d.ts.map +0 -1
  241. package/dist/commands/scan-secrets.js +0 -225
  242. package/dist/commands/scan-secrets.js.map +0 -1
  243. package/dist/commands/scan-vulnerabilities-enhanced.d.ts +0 -41
  244. package/dist/commands/scan-vulnerabilities-enhanced.d.ts.map +0 -1
  245. package/dist/commands/scan-vulnerabilities-enhanced.js +0 -368
  246. package/dist/commands/scan-vulnerabilities-enhanced.js.map +0 -1
  247. package/dist/commands/scan-vulnerabilities-osv.d.ts +0 -58
  248. package/dist/commands/scan-vulnerabilities-osv.d.ts.map +0 -1
  249. package/dist/commands/scan-vulnerabilities-osv.js +0 -722
  250. package/dist/commands/scan-vulnerabilities-osv.js.map +0 -1
  251. package/dist/commands/scan-vulnerabilities.d.ts +0 -32
  252. package/dist/commands/scan-vulnerabilities.d.ts.map +0 -1
  253. package/dist/commands/scan-vulnerabilities.js +0 -283
  254. package/dist/commands/scan-vulnerabilities.js.map +0 -1
  255. package/dist/commands/secrets-allowlist.d.ts +0 -7
  256. package/dist/commands/secrets-allowlist.d.ts.map +0 -1
  257. package/dist/commands/secrets-allowlist.js +0 -85
  258. package/dist/commands/secrets-allowlist.js.map +0 -1
  259. package/dist/commands/ship-consolidated.d.ts +0 -58
  260. package/dist/commands/ship-consolidated.d.ts.map +0 -1
  261. package/dist/commands/ship-consolidated.js +0 -515
  262. package/dist/commands/ship-consolidated.js.map +0 -1
  263. package/dist/commands/stats.d.ts +0 -8
  264. package/dist/commands/stats.d.ts.map +0 -1
  265. package/dist/commands/stats.js +0 -134
  266. package/dist/commands/stats.js.map +0 -1
  267. package/dist/commands/upgrade.d.ts +0 -8
  268. package/dist/commands/upgrade.d.ts.map +0 -1
  269. package/dist/commands/upgrade.js +0 -30
  270. package/dist/commands/upgrade.js.map +0 -1
  271. package/dist/fix/applicator.d.ts +0 -44
  272. package/dist/fix/applicator.d.ts.map +0 -1
  273. package/dist/fix/applicator.js +0 -144
  274. package/dist/fix/applicator.js.map +0 -1
  275. package/dist/fix/backup.d.ts +0 -38
  276. package/dist/fix/backup.d.ts.map +0 -1
  277. package/dist/fix/backup.js +0 -154
  278. package/dist/fix/backup.js.map +0 -1
  279. package/dist/fix/engine.d.ts +0 -55
  280. package/dist/fix/engine.d.ts.map +0 -1
  281. package/dist/fix/engine.js +0 -285
  282. package/dist/fix/engine.js.map +0 -1
  283. package/dist/fix/index.d.ts +0 -5
  284. package/dist/fix/index.d.ts.map +0 -1
  285. package/dist/fix/index.js +0 -12
  286. package/dist/fix/index.js.map +0 -1
  287. package/dist/fix/interactive.d.ts +0 -22
  288. package/dist/fix/interactive.d.ts.map +0 -1
  289. package/dist/fix/interactive.js +0 -172
  290. package/dist/fix/interactive.js.map +0 -1
  291. package/dist/formatters/index.d.ts +0 -6
  292. package/dist/formatters/index.d.ts.map +0 -1
  293. package/dist/formatters/index.js +0 -11
  294. package/dist/formatters/index.js.map +0 -1
  295. package/dist/formatters/sarif-enhanced.d.ts +0 -78
  296. package/dist/formatters/sarif-enhanced.d.ts.map +0 -1
  297. package/dist/formatters/sarif-enhanced.js +0 -144
  298. package/dist/formatters/sarif-enhanced.js.map +0 -1
  299. package/dist/formatters/sarif-v2.d.ts +0 -121
  300. package/dist/formatters/sarif-v2.d.ts.map +0 -1
  301. package/dist/formatters/sarif-v2.js +0 -356
  302. package/dist/formatters/sarif-v2.js.map +0 -1
  303. package/dist/formatters/sarif.d.ts +0 -72
  304. package/dist/formatters/sarif.d.ts.map +0 -1
  305. package/dist/formatters/sarif.js +0 -146
  306. package/dist/formatters/sarif.js.map +0 -1
  307. package/dist/index.d.ts +0 -61
  308. package/dist/index.d.ts.map +0 -1
  309. package/dist/index.js +0 -4388
  310. package/dist/index.js.map +0 -1
  311. package/dist/init/ci-generator.d.ts +0 -18
  312. package/dist/init/ci-generator.d.ts.map +0 -1
  313. package/dist/init/ci-generator.js +0 -317
  314. package/dist/init/ci-generator.js.map +0 -1
  315. package/dist/init/detect-framework.d.ts +0 -15
  316. package/dist/init/detect-framework.d.ts.map +0 -1
  317. package/dist/init/detect-framework.js +0 -301
  318. package/dist/init/detect-framework.js.map +0 -1
  319. package/dist/init/hooks-installer.d.ts +0 -22
  320. package/dist/init/hooks-installer.d.ts.map +0 -1
  321. package/dist/init/hooks-installer.js +0 -310
  322. package/dist/init/hooks-installer.js.map +0 -1
  323. package/dist/init/index.d.ts +0 -8
  324. package/dist/init/index.d.ts.map +0 -1
  325. package/dist/init/index.js +0 -22
  326. package/dist/init/index.js.map +0 -1
  327. package/dist/init/templates.d.ts +0 -402
  328. package/dist/init/templates.d.ts.map +0 -1
  329. package/dist/init/templates.js +0 -240
  330. package/dist/init/templates.js.map +0 -1
  331. package/dist/mcp/server.d.ts +0 -12
  332. package/dist/mcp/server.d.ts.map +0 -1
  333. package/dist/mcp/server.js +0 -42
  334. package/dist/mcp/server.js.map +0 -1
  335. package/dist/mcp/telemetry.d.ts +0 -40
  336. package/dist/mcp/telemetry.d.ts.map +0 -1
  337. package/dist/mcp/telemetry.js +0 -98
  338. package/dist/mcp/telemetry.js.map +0 -1
  339. package/dist/reality/no-dead-buttons/button-sweep-generator.d.ts +0 -32
  340. package/dist/reality/no-dead-buttons/button-sweep-generator.d.ts.map +0 -1
  341. package/dist/reality/no-dead-buttons/button-sweep-generator.js +0 -236
  342. package/dist/reality/no-dead-buttons/button-sweep-generator.js.map +0 -1
  343. package/dist/reality/no-dead-buttons/index.d.ts +0 -11
  344. package/dist/reality/no-dead-buttons/index.d.ts.map +0 -1
  345. package/dist/reality/no-dead-buttons/index.js +0 -18
  346. package/dist/reality/no-dead-buttons/index.js.map +0 -1
  347. package/dist/reality/no-dead-buttons/static-scanner.d.ts +0 -34
  348. package/dist/reality/no-dead-buttons/static-scanner.d.ts.map +0 -1
  349. package/dist/reality/no-dead-buttons/static-scanner.js +0 -230
  350. package/dist/reality/no-dead-buttons/static-scanner.js.map +0 -1
  351. package/dist/reality/reality-graph.d.ts +0 -192
  352. package/dist/reality/reality-graph.d.ts.map +0 -1
  353. package/dist/reality/reality-graph.js +0 -600
  354. package/dist/reality/reality-graph.js.map +0 -1
  355. package/dist/reality/reality-runner.d.ts +0 -89
  356. package/dist/reality/reality-runner.d.ts.map +0 -1
  357. package/dist/reality/reality-runner.js +0 -540
  358. package/dist/reality/reality-runner.js.map +0 -1
  359. package/dist/reality/receipt-generator.d.ts +0 -152
  360. package/dist/reality/receipt-generator.d.ts.map +0 -1
  361. package/dist/reality/receipt-generator.js +0 -495
  362. package/dist/reality/receipt-generator.js.map +0 -1
  363. package/dist/reality/runtime-tracer.d.ts +0 -75
  364. package/dist/reality/runtime-tracer.d.ts.map +0 -1
  365. package/dist/reality/runtime-tracer.js +0 -109
  366. package/dist/reality/runtime-tracer.js.map +0 -1
  367. package/dist/runtime/auth-utils.d.ts +0 -43
  368. package/dist/runtime/auth-utils.d.ts.map +0 -1
  369. package/dist/runtime/auth-utils.js +0 -130
  370. package/dist/runtime/auth-utils.js.map +0 -1
  371. package/dist/runtime/client.d.ts +0 -74
  372. package/dist/runtime/client.d.ts.map +0 -1
  373. package/dist/runtime/client.js +0 -222
  374. package/dist/runtime/client.js.map +0 -1
  375. package/dist/runtime/creds.d.ts +0 -48
  376. package/dist/runtime/creds.d.ts.map +0 -1
  377. package/dist/runtime/creds.js +0 -245
  378. package/dist/runtime/creds.js.map +0 -1
  379. package/dist/runtime/exit-codes.d.ts +0 -49
  380. package/dist/runtime/exit-codes.d.ts.map +0 -1
  381. package/dist/runtime/exit-codes.js +0 -93
  382. package/dist/runtime/exit-codes.js.map +0 -1
  383. package/dist/runtime/index.d.ts +0 -9
  384. package/dist/runtime/index.d.ts.map +0 -1
  385. package/dist/runtime/index.js +0 -25
  386. package/dist/runtime/index.js.map +0 -1
  387. package/dist/runtime/json-output.d.ts +0 -42
  388. package/dist/runtime/json-output.d.ts.map +0 -1
  389. package/dist/runtime/json-output.js +0 -59
  390. package/dist/runtime/json-output.js.map +0 -1
  391. package/dist/runtime/semver.d.ts +0 -37
  392. package/dist/runtime/semver.d.ts.map +0 -1
  393. package/dist/runtime/semver.js +0 -110
  394. package/dist/runtime/semver.js.map +0 -1
  395. package/dist/scan/dead-ui-detector.d.ts +0 -48
  396. package/dist/scan/dead-ui-detector.d.ts.map +0 -1
  397. package/dist/scan/dead-ui-detector.js +0 -170
  398. package/dist/scan/dead-ui-detector.js.map +0 -1
  399. package/dist/scan/playwright-sweep.d.ts +0 -40
  400. package/dist/scan/playwright-sweep.d.ts.map +0 -1
  401. package/dist/scan/playwright-sweep.js +0 -216
  402. package/dist/scan/playwright-sweep.js.map +0 -1
  403. package/dist/scan/proof-bundle.d.ts +0 -25
  404. package/dist/scan/proof-bundle.d.ts.map +0 -1
  405. package/dist/scan/proof-bundle.js +0 -203
  406. package/dist/scan/proof-bundle.js.map +0 -1
  407. package/dist/scan/proof-graph.d.ts +0 -59
  408. package/dist/scan/proof-graph.d.ts.map +0 -1
  409. package/dist/scan/proof-graph.js +0 -64
  410. package/dist/scan/proof-graph.js.map +0 -1
  411. package/dist/scan/reality-sniff.d.ts +0 -56
  412. package/dist/scan/reality-sniff.d.ts.map +0 -1
  413. package/dist/scan/reality-sniff.js +0 -200
  414. package/dist/scan/reality-sniff.js.map +0 -1
  415. package/dist/scan/structural-verifier.d.ts +0 -20
  416. package/dist/scan/structural-verifier.d.ts.map +0 -1
  417. package/dist/scan/structural-verifier.js +0 -112
  418. package/dist/scan/structural-verifier.js.map +0 -1
  419. package/dist/scan/verification-engine.d.ts +0 -47
  420. package/dist/scan/verification-engine.d.ts.map +0 -1
  421. package/dist/scan/verification-engine.js +0 -141
  422. package/dist/scan/verification-engine.js.map +0 -1
  423. package/dist/scanner/baseline.d.ts +0 -52
  424. package/dist/scanner/baseline.d.ts.map +0 -1
  425. package/dist/scanner/baseline.js +0 -85
  426. package/dist/scanner/baseline.js.map +0 -1
  427. package/dist/scanner/incremental.d.ts +0 -30
  428. package/dist/scanner/incremental.d.ts.map +0 -1
  429. package/dist/scanner/incremental.js +0 -82
  430. package/dist/scanner/incremental.js.map +0 -1
  431. package/dist/scanner/parallel.d.ts +0 -43
  432. package/dist/scanner/parallel.d.ts.map +0 -1
  433. package/dist/scanner/parallel.js +0 -99
  434. package/dist/scanner/parallel.js.map +0 -1
  435. package/dist/standalone.d.ts +0 -1
  436. package/dist/standalone.d.ts.map +0 -1
  437. package/dist/standalone.js +0 -1
  438. package/dist/standalone.js.map +0 -1
  439. package/dist/truth-pack/index.d.ts +0 -102
  440. package/dist/truth-pack/index.d.ts.map +0 -1
  441. package/dist/truth-pack/index.js +0 -694
  442. package/dist/truth-pack/index.js.map +0 -1
  443. package/dist/ui/frame.d.ts +0 -68
  444. package/dist/ui/frame.d.ts.map +0 -1
  445. package/dist/ui/frame.js +0 -165
  446. package/dist/ui/frame.js.map +0 -1
  447. package/dist/ui/index.d.ts +0 -5
  448. package/dist/ui/index.d.ts.map +0 -1
  449. package/dist/ui/index.js +0 -16
  450. package/dist/ui/index.js.map +0 -1
  451. package/dist/ui.d.ts +0 -36
  452. package/dist/ui.d.ts.map +0 -1
  453. package/dist/ui.js +0 -45
  454. package/dist/ui.js.map +0 -1
@@ -0,0 +1,835 @@
1
+ /**
2
+ * vibecheck Scan - Route Integrity & Code Analysis
3
+ *
4
+ * The ultimate scanner combining:
5
+ * - Route integrity (dead links, orphan routes, coverage)
6
+ * - Security analysis (secrets, auth, vulnerabilities)
7
+ * - Code quality (mocks, placeholders, hygiene)
8
+ *
9
+ * Modes:
10
+ * - vibecheck scan: Layer 1 (AST) - Fast static analysis
11
+ * - vibecheck scan --truth: Layer 1+2 (+ build manifests) - CI/ship
12
+ * - vibecheck scan --reality --url <url>: Layer 1+2+3 (+ Playwright) - Full proof
13
+ */
14
+
15
+ const path = require("path");
16
+ const fs = require("fs");
17
+ const { withErrorHandling, createUserError } = require("./lib/error-handler");
18
+ const { enforceLimit, trackUsage } = require("./lib/entitlements");
19
+ const { emitScanStart, emitScanComplete } = require("./lib/audit-bridge");
20
+
21
+ // ═══════════════════════════════════════════════════════════════════════════════
22
+ // ADVANCED TERMINAL - ANSI CODES & UTILITIES
23
+ // ═══════════════════════════════════════════════════════════════════════════════
24
+
25
+ const c = {
26
+ reset: '\x1b[0m',
27
+ bold: '\x1b[1m',
28
+ dim: '\x1b[2m',
29
+ italic: '\x1b[3m',
30
+ underline: '\x1b[4m',
31
+ blink: '\x1b[5m',
32
+ inverse: '\x1b[7m',
33
+ hidden: '\x1b[8m',
34
+ strike: '\x1b[9m',
35
+ // Colors
36
+ black: '\x1b[30m',
37
+ red: '\x1b[31m',
38
+ green: '\x1b[32m',
39
+ yellow: '\x1b[33m',
40
+ blue: '\x1b[34m',
41
+ magenta: '\x1b[35m',
42
+ cyan: '\x1b[36m',
43
+ white: '\x1b[37m',
44
+ // Bright colors
45
+ gray: '\x1b[90m',
46
+ brightRed: '\x1b[91m',
47
+ brightGreen: '\x1b[92m',
48
+ brightYellow: '\x1b[93m',
49
+ brightBlue: '\x1b[94m',
50
+ brightMagenta: '\x1b[95m',
51
+ brightCyan: '\x1b[96m',
52
+ brightWhite: '\x1b[97m',
53
+ // Background
54
+ bgBlack: '\x1b[40m',
55
+ bgRed: '\x1b[41m',
56
+ bgGreen: '\x1b[42m',
57
+ bgYellow: '\x1b[43m',
58
+ bgBlue: '\x1b[44m',
59
+ bgMagenta: '\x1b[45m',
60
+ bgCyan: '\x1b[46m',
61
+ bgWhite: '\x1b[47m',
62
+ bgBrightBlack: '\x1b[100m',
63
+ bgBrightRed: '\x1b[101m',
64
+ bgBrightGreen: '\x1b[102m',
65
+ bgBrightYellow: '\x1b[103m',
66
+ // Cursor
67
+ cursorUp: (n = 1) => `\x1b[${n}A`,
68
+ cursorDown: (n = 1) => `\x1b[${n}B`,
69
+ cursorRight: (n = 1) => `\x1b[${n}C`,
70
+ cursorLeft: (n = 1) => `\x1b[${n}D`,
71
+ clearLine: '\x1b[2K',
72
+ clearScreen: '\x1b[2J',
73
+ saveCursor: '\x1b[s',
74
+ restoreCursor: '\x1b[u',
75
+ hideCursor: '\x1b[?25l',
76
+ showCursor: '\x1b[?25h',
77
+ };
78
+
79
+ // 256-color support
80
+ const rgb = (r, g, b) => `\x1b[38;2;${r};${g};${b}m`;
81
+ const bgRgb = (r, g, b) => `\x1b[48;2;${r};${g};${b}m`;
82
+
83
+ // Gradient colors for the banner
84
+ const gradientCyan = rgb(0, 255, 255);
85
+ const gradientBlue = rgb(100, 149, 237);
86
+ const gradientPurple = rgb(138, 43, 226);
87
+ const gradientPink = rgb(255, 105, 180);
88
+ const gradientOrange = rgb(255, 165, 0);
89
+
90
+ const BANNER = `
91
+ ${rgb(0, 200, 255)} ██████╗ ██╗ ██╗ █████╗ ██████╗ ██████╗ ██████╗ █████╗ ██╗██╗ ${c.reset}
92
+ ${rgb(30, 180, 255)} ██╔════╝ ██║ ██║██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔══██╗██║██║ ${c.reset}
93
+ ${rgb(60, 160, 255)} ██║ ███╗██║ ██║███████║██████╔╝██║ ██║██████╔╝███████║██║██║ ${c.reset}
94
+ ${rgb(90, 140, 255)} ██║ ██║██║ ██║██╔══██║██╔══██╗██║ ██║██╔══██╗██╔══██║██║██║ ${c.reset}
95
+ ${rgb(120, 120, 255)} ╚██████╔╝╚██████╔╝██║ ██║██║ ██║██████╔╝██║ ██║██║ ██║██║███████╗${c.reset}
96
+ ${rgb(150, 100, 255)} ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚══════╝${c.reset}
97
+
98
+ ${c.dim} ┌─────────────────────────────────────────────────────────────────────┐${c.reset}
99
+ ${c.dim} │${c.reset} ${rgb(255, 255, 255)}${c.bold}Route Integrity${c.reset} ${c.dim}•${c.reset} ${rgb(200, 200, 200)}Security${c.reset} ${c.dim}•${c.reset} ${rgb(150, 150, 150)}Quality${c.reset} ${c.dim}•${c.reset} ${rgb(100, 100, 100)}Ship with Confidence${c.reset} ${c.dim}│${c.reset}
100
+ ${c.dim} └─────────────────────────────────────────────────────────────────────┘${c.reset}
101
+ `;
102
+
103
+ // ═══════════════════════════════════════════════════════════════════════════════
104
+ // TERMINAL UTILITIES
105
+ // ═══════════════════════════════════════════════════════════════════════════════
106
+
107
+ const BOX_CHARS = {
108
+ topLeft: '╭', topRight: '╮', bottomLeft: '╰', bottomRight: '╯',
109
+ horizontal: '─', vertical: '│',
110
+ teeRight: '├', teeLeft: '┤', teeDown: '┬', teeUp: '┴',
111
+ cross: '┼',
112
+ };
113
+
114
+ const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
115
+ let spinnerIndex = 0;
116
+ let spinnerInterval = null;
117
+
118
+ function formatNumber(num) {
119
+ return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
120
+ }
121
+
122
+ function truncate(str, len) {
123
+ if (str.length <= len) return str;
124
+ return str.slice(0, len - 3) + '...';
125
+ }
126
+
127
+ function progressBar(percent, width = 30) {
128
+ const filled = Math.round((percent / 100) * width);
129
+ const empty = width - filled;
130
+ const filledColor = percent >= 80 ? rgb(0, 255, 100) : percent >= 50 ? rgb(255, 200, 0) : rgb(255, 80, 80);
131
+ return `${filledColor}${'█'.repeat(filled)}${c.dim}${'░'.repeat(empty)}${c.reset}`;
132
+ }
133
+
134
+ function startSpinner(message) {
135
+ process.stdout.write(c.hideCursor);
136
+ spinnerInterval = setInterval(() => {
137
+ process.stdout.write(`\r ${c.cyan}${SPINNER_FRAMES[spinnerIndex]}${c.reset} ${message} `);
138
+ spinnerIndex = (spinnerIndex + 1) % SPINNER_FRAMES.length;
139
+ }, 80);
140
+ }
141
+
142
+ function stopSpinner(message, success = true) {
143
+ if (spinnerInterval) {
144
+ clearInterval(spinnerInterval);
145
+ spinnerInterval = null;
146
+ }
147
+ const icon = success ? `${c.green}✓${c.reset}` : `${c.red}✗${c.reset}`;
148
+ process.stdout.write(`\r${c.clearLine} ${icon} ${message}\n`);
149
+ process.stdout.write(c.showCursor);
150
+ }
151
+
152
+ function printBanner() {
153
+ console.log(BANNER);
154
+ }
155
+
156
+ function printDivider(char = '─', color = c.dim) {
157
+ console.log(`${color} ${char.repeat(69)}${c.reset}`);
158
+ }
159
+
160
+ function printSection(title, icon = '◆') {
161
+ console.log();
162
+ console.log(` ${rgb(100, 200, 255)}${icon}${c.reset} ${c.bold}${title}${c.reset}`);
163
+ printDivider();
164
+ }
165
+
166
+ // ═══════════════════════════════════════════════════════════════════════════════
167
+ // SCORE DISPLAY
168
+ // ═══════════════════════════════════════════════════════════════════════════════
169
+
170
+ function getScoreColor(score) {
171
+ if (score >= 90) return rgb(0, 255, 100);
172
+ if (score >= 80) return rgb(100, 255, 100);
173
+ if (score >= 70) return rgb(200, 255, 0);
174
+ if (score >= 60) return rgb(255, 200, 0);
175
+ if (score >= 50) return rgb(255, 150, 0);
176
+ return rgb(255, 80, 80);
177
+ }
178
+
179
+ function getGradeColor(grade) {
180
+ const colors = {
181
+ 'A': rgb(0, 255, 100),
182
+ 'B': rgb(100, 255, 100),
183
+ 'C': rgb(255, 200, 0),
184
+ 'D': rgb(255, 150, 0),
185
+ 'F': rgb(255, 80, 80),
186
+ };
187
+ return colors[grade] || c.white;
188
+ }
189
+
190
+ function printScoreCard(score, grade, canShip) {
191
+ const scoreColor = getScoreColor(score);
192
+ const gradeColor = getGradeColor(grade);
193
+
194
+ console.log();
195
+ console.log(` ${c.dim}╭────────────────────────────────────────────────────────────────╮${c.reset}`);
196
+ console.log(` ${c.dim}│${c.reset} ${c.dim}│${c.reset}`);
197
+
198
+ const scoreStr = `${score}`;
199
+ const scorePadding = ' '.repeat(Math.max(0, 3 - scoreStr.length));
200
+ console.log(` ${c.dim}│${c.reset} ${c.dim}INTEGRITY SCORE${c.reset} ${scoreColor}${c.bold}${scorePadding}${scoreStr}${c.reset}${c.dim}/100${c.reset} ${c.dim}GRADE${c.reset} ${gradeColor}${c.bold}${grade}${c.reset} ${c.dim}│${c.reset}`);
201
+ console.log(` ${c.dim}│${c.reset} ${c.dim}│${c.reset}`);
202
+ console.log(` ${c.dim}│${c.reset} ${progressBar(score, 40)} ${c.dim}│${c.reset}`);
203
+ console.log(` ${c.dim}│${c.reset} ${c.dim}│${c.reset}`);
204
+
205
+ if (canShip) {
206
+ console.log(` ${c.dim}│${c.reset} ${bgRgb(0, 150, 80)}${c.bold} ✓ CLEAR TO SHIP ${c.reset} ${c.dim}│${c.reset}`);
207
+ } else {
208
+ console.log(` ${c.dim}│${c.reset} ${bgRgb(200, 50, 50)}${c.bold} ✗ NOT SHIP READY ${c.reset} ${c.dim}│${c.reset}`);
209
+ }
210
+
211
+ console.log(` ${c.dim}│${c.reset} ${c.dim}│${c.reset}`);
212
+ console.log(` ${c.dim}╰────────────────────────────────────────────────────────────────╯${c.reset}`);
213
+ }
214
+
215
+ // ═══════════════════════════════════════════════════════════════════════════════
216
+ // COVERAGE MAP VISUALIZATION
217
+ // ═══════════════════════════════════════════════════════════════════════════════
218
+
219
+ function printCoverageMap(coverageMap) {
220
+ printSection('NAVIGATION COVERAGE', '🗺️');
221
+
222
+ const pct = coverageMap.coveragePercent;
223
+ const color = pct >= 80 ? rgb(0, 255, 100) : pct >= 60 ? rgb(255, 200, 0) : rgb(255, 80, 80);
224
+
225
+ console.log();
226
+ console.log(` ${color}${c.bold}${pct}%${c.reset} ${c.dim}of shipped routes reachable from${c.reset} ${c.cyan}/${c.reset}`);
227
+ console.log(` ${progressBar(pct, 50)}`);
228
+ console.log();
229
+ console.log(` ${c.dim}Routes:${c.reset} ${coverageMap.reachableFromRoot}${c.dim}/${c.reset}${coverageMap.totalShippedRoutes} ${c.dim}reachable${c.reset}`);
230
+
231
+ if (coverageMap.isolatedClusters && coverageMap.isolatedClusters.length > 0) {
232
+ console.log();
233
+ console.log(` ${c.yellow}⚠${c.reset} ${c.dim}Isolated clusters:${c.reset}`);
234
+ for (const cluster of coverageMap.isolatedClusters.slice(0, 3)) {
235
+ const auth = cluster.requiresAuth ? ` ${c.dim}(auth)${c.reset}` : '';
236
+ console.log(` ${c.dim}├─${c.reset} ${c.bold}${cluster.name}${c.reset}${auth} ${c.dim}(${cluster.nodeIds.length} routes)${c.reset}`);
237
+ }
238
+ }
239
+
240
+ if (coverageMap.unreachableRoutes && coverageMap.unreachableRoutes.length > 0) {
241
+ console.log();
242
+ console.log(` ${c.red}✗${c.reset} ${c.dim}Unreachable routes:${c.reset}`);
243
+ for (const route of coverageMap.unreachableRoutes.slice(0, 5)) {
244
+ console.log(` ${c.dim}├─${c.reset} ${c.red}${route}${c.reset}`);
245
+ }
246
+ if (coverageMap.unreachableRoutes.length > 5) {
247
+ console.log(` ${c.dim}└─ ... and ${coverageMap.unreachableRoutes.length - 5} more${c.reset}`);
248
+ }
249
+ }
250
+ }
251
+
252
+ // ═══════════════════════════════════════════════════════════════════════════════
253
+ // BREAKDOWN DISPLAY
254
+ // ═══════════════════════════════════════════════════════════════════════════════
255
+
256
+ function printBreakdown(breakdown) {
257
+ printSection('BREAKDOWN', '📊');
258
+ console.log();
259
+
260
+ const items = [
261
+ { key: 'deadLinks', label: 'Dead Links', icon: '🔗', color: rgb(255, 100, 100) },
262
+ { key: 'orphanRoutes', label: 'Orphan Routes', icon: '👻', color: rgb(200, 150, 255) },
263
+ { key: 'runtimeFailures', label: 'Runtime 404s', icon: '💥', color: rgb(255, 80, 80) },
264
+ { key: 'unresolvedDynamic', label: 'Unresolved Dynamic', icon: '❓', color: rgb(255, 200, 100) },
265
+ { key: 'placeholders', label: 'Placeholders', icon: '📝', color: rgb(255, 180, 100) },
266
+ ];
267
+
268
+ for (const item of items) {
269
+ const data = breakdown[item.key] || { count: 0, penalty: 0 };
270
+ const status = data.count === 0 ? `${c.green}✓${c.reset}` : `${c.red}✗${c.reset}`;
271
+ const countColor = data.count === 0 ? c.green : item.color;
272
+ const countStr = String(data.count).padStart(3);
273
+ const penaltyStr = data.penalty > 0 ? `${c.dim}-${data.penalty} pts${c.reset}` : `${c.dim} ---${c.reset}`;
274
+
275
+ console.log(` ${status} ${item.icon} ${item.label.padEnd(22)} ${countColor}${c.bold}${countStr}${c.reset} ${penaltyStr}`);
276
+ }
277
+ }
278
+
279
+ // ═══════════════════════════════════════════════════════════════════════════════
280
+ // BLOCKERS DISPLAY
281
+ // ═══════════════════════════════════════════════════════════════════════════════
282
+
283
+ function printBlockers(blockers) {
284
+ if (!blockers || blockers.length === 0) {
285
+ printSection('SHIP BLOCKERS', '🚀');
286
+ console.log();
287
+ console.log(` ${c.green}${c.bold}✓ No blockers! You're clear to ship.${c.reset}`);
288
+ return;
289
+ }
290
+
291
+ printSection(`SHIP BLOCKERS (${blockers.length})`, '🚨');
292
+ console.log();
293
+
294
+ for (const blocker of blockers.slice(0, 8)) {
295
+ const sevColor = blocker.severity === 'critical' ? bgRgb(180, 40, 40) : bgRgb(180, 120, 0);
296
+ const sevLabel = blocker.severity === 'critical' ? 'CRITICAL' : ' HIGH ';
297
+
298
+ console.log(` ${sevColor}${c.bold} ${sevLabel} ${c.reset} ${c.bold}${truncate(blocker.title, 45)}${c.reset}`);
299
+ console.log(` ${c.dim} ${truncate(blocker.description, 55)}${c.reset}`);
300
+ if (blocker.file) {
301
+ const fileDisplay = path.basename(blocker.file) + (blocker.line ? `:${blocker.line}` : '');
302
+ console.log(` ${c.dim} ${c.reset}${c.cyan}${fileDisplay}${c.reset}`);
303
+ }
304
+ if (blocker.fixSuggestion) {
305
+ console.log(` ${c.dim} ${c.green}→ ${blocker.fixSuggestion}${c.reset}`);
306
+ }
307
+ console.log();
308
+ }
309
+
310
+ if (blockers.length > 8) {
311
+ console.log(` ${c.dim}... and ${blockers.length - 8} more blockers (see full report)${c.reset}`);
312
+ }
313
+ }
314
+
315
+ // ═══════════════════════════════════════════════════════════════════════════════
316
+ // LAYERS DISPLAY
317
+ // ═══════════════════════════════════════════════════════════════════════════════
318
+
319
+ function printLayers(layers) {
320
+ printSection('ANALYSIS LAYERS', '⚡');
321
+ console.log();
322
+
323
+ const layerInfo = {
324
+ ast: { name: 'AST Analysis', icon: '🔍', desc: 'Static code analysis' },
325
+ truth: { name: 'Build Truth', icon: '📦', desc: 'Manifest verification' },
326
+ reality: { name: 'Reality Proof', icon: '🎭', desc: 'Playwright crawl' },
327
+ };
328
+
329
+ for (const layer of layers) {
330
+ const info = layerInfo[layer.layer] || { name: layer.layer, icon: '○', desc: '' };
331
+ const status = layer.executed ? `${c.green}✓${c.reset}` : `${c.dim}○${c.reset}`;
332
+ const duration = layer.executed ? `${c.dim}${layer.duration}ms${c.reset}` : `${c.dim}skipped${c.reset}`;
333
+ const findings = layer.executed ? `${c.cyan}${layer.findings}${c.reset} ${c.dim}findings${c.reset}` : '';
334
+
335
+ console.log(` ${status} ${info.icon} ${c.bold}${info.name.padEnd(15)}${c.reset} ${duration.padEnd(20)} ${findings}`);
336
+ }
337
+ }
338
+
339
+ // ═══════════════════════════════════════════════════════════════════════════════
340
+ // ARGS PARSER
341
+ // ═══════════════════════════════════════════════════════════════════════════════
342
+
343
+ function parseArgs(args) {
344
+ const opts = {
345
+ path: process.cwd(),
346
+ truth: false,
347
+ reality: false,
348
+ realitySniff: false,
349
+ baseUrl: null,
350
+ json: false,
351
+ sarif: false,
352
+ verbose: false,
353
+ help: false,
354
+ };
355
+
356
+ for (let i = 0; i < args.length; i++) {
357
+ const arg = args[i];
358
+
359
+ if (arg === '--truth' || arg === '-t') opts.truth = true;
360
+ else if (arg === '--reality' || arg === '-r') { opts.reality = true; opts.truth = true; }
361
+ else if (arg === '--reality-sniff' || arg === '--sniff') opts.realitySniff = true;
362
+ else if (arg === '--url' || arg === '-u') { opts.baseUrl = args[++i]; opts.reality = true; opts.truth = true; }
363
+ else if (arg === '--json') opts.json = true;
364
+ else if (arg === '--sarif') opts.sarif = true;
365
+ else if (arg === '--verbose' || arg === '-v') opts.verbose = true;
366
+ else if (arg === '--help' || arg === '-h') opts.help = true;
367
+ else if (arg === '--path' || arg === '-p') opts.path = args[++i];
368
+ else if (arg.startsWith('--path=')) opts.path = arg.split('=')[1];
369
+ else if (!arg.startsWith('-')) opts.path = path.resolve(arg);
370
+ }
371
+
372
+ return opts;
373
+ }
374
+
375
+ function printHelp() {
376
+ console.log(BANNER);
377
+ console.log(`
378
+ ${c.bold}Usage:${c.reset} vibecheck scan [path] [options]
379
+
380
+ ${c.bold}Scan Modes:${c.reset}
381
+ ${c.cyan}(default)${c.reset} Layer 1: AST static analysis ${c.dim}(fast)${c.reset}
382
+ ${c.cyan}--truth, -t${c.reset} Layer 1+2: Include build manifest verification ${c.dim}(CI/ship)${c.reset}
383
+ ${c.cyan}--reality, -r${c.reset} Layer 1+2+3: Include Playwright runtime proof ${c.dim}(full)${c.reset}
384
+ ${c.cyan}--reality-sniff${c.reset} Include Reality Sniff AI artifact detection ${c.dim}(recommended)${c.reset}
385
+
386
+ ${c.bold}Options:${c.reset}
387
+ ${c.cyan}--url, -u${c.reset} Base URL for reality testing (e.g., http://localhost:3000)
388
+ ${c.cyan}--verbose, -v${c.reset} Show detailed progress
389
+ ${c.cyan}--json${c.reset} Output results as JSON
390
+ ${c.cyan}--sarif${c.reset} Output in SARIF format (GitHub code scanning)
391
+ ${c.cyan}--help, -h${c.reset} Show this help
392
+
393
+ ${c.bold}Examples:${c.reset}
394
+ ${c.dim}# Quick scan (AST only)${c.reset}
395
+ vibecheck scan
396
+
397
+ ${c.dim}# CI/CD scan with manifest verification${c.reset}
398
+ vibecheck scan --truth
399
+
400
+ ${c.dim}# Full proof with Playwright${c.reset}
401
+ vibecheck scan --reality --url http://localhost:3000
402
+ `);
403
+ }
404
+
405
+ // ═══════════════════════════════════════════════════════════════════════════════
406
+ // MAIN SCAN FUNCTION - ROUTE INTEGRITY SYSTEM
407
+ // ═══════════════════════════════════════════════════════════════════════════════
408
+
409
+ async function runScan(args) {
410
+ const opts = parseArgs(args);
411
+
412
+ // Show help if requested
413
+ if (opts.help) {
414
+ printHelp();
415
+ return 0;
416
+ }
417
+
418
+ // Entitlement check (graceful offline handling)
419
+ try {
420
+ await enforceLimit('scans');
421
+ await trackUsage('scans');
422
+ } catch (err) {
423
+ if (err.code === 'LIMIT_EXCEEDED') {
424
+ console.error(err.upgradePrompt || err.message);
425
+ return 1;
426
+ }
427
+ // Network error - fall back to free tier only (SECURITY: never grant paid features offline)
428
+ if (err.code === 'ECONNREFUSED' || err.code === 'ETIMEDOUT' || err.code === 'ENOTFOUND' || err.name === 'NetworkError') {
429
+ console.warn(` ${c.yellow}⚠${c.reset} API unavailable, running in ${c.green}FREE${c.reset} tier mode`);
430
+ console.warn(` ${c.dim}Paid features require API connection. Continuing with free features only.${c.reset}\n`);
431
+ // Continue with free tier features only - scan command is free tier
432
+ } else {
433
+ throw err; // Re-throw unexpected errors
434
+ }
435
+ }
436
+
437
+ // Print banner
438
+ printBanner();
439
+
440
+ const projectPath = path.resolve(opts.path);
441
+ const startTime = Date.now();
442
+
443
+ // Emit audit event for scan start
444
+ emitScanStart(projectPath, args);
445
+ const projectName = path.basename(projectPath);
446
+
447
+ // Validate project path
448
+ if (!fs.existsSync(projectPath)) {
449
+ throw createUserError(`Project path does not exist: ${projectPath}`, "ValidationError");
450
+ }
451
+
452
+ // Determine layers
453
+ const layers = {
454
+ ast: true,
455
+ truth: opts.truth,
456
+ reality: opts.reality,
457
+ realitySniff: opts.realitySniff,
458
+ };
459
+
460
+ // Print scan info
461
+ const layerNames = [];
462
+ if (layers.ast) layerNames.push('AST');
463
+ if (layers.truth) layerNames.push('Truth');
464
+ if (layers.reality) layerNames.push('Reality');
465
+ if (layers.realitySniff) layerNames.push('Reality Sniff');
466
+
467
+ console.log(` ${c.dim}Project:${c.reset} ${c.bold}${projectName}${c.reset}`);
468
+ console.log(` ${c.dim}Path:${c.reset} ${projectPath}`);
469
+ console.log(` ${c.dim}Layers:${c.reset} ${c.cyan}${layerNames.join(' → ')}${c.reset}`);
470
+ console.log();
471
+
472
+ // Reality layer requires URL
473
+ if (opts.reality && !opts.baseUrl) {
474
+ console.log(` ${c.yellow}⚠${c.reset} ${c.bold}Reality layer requires --url${c.reset}`);
475
+ console.log(` ${c.dim}Example: vibecheck scan --reality --url http://localhost:3000${c.reset}`);
476
+ console.log();
477
+ return 1;
478
+ }
479
+
480
+ try {
481
+ // Import systems
482
+ const { scanRouteIntegrity } = require('../../dist/lib/route-integrity');
483
+
484
+ // Try to import new unified output system (may not be compiled yet)
485
+ let buildVerdictOutput, normalizeFinding, formatStandardOutput, formatScanOutput, getExitCode, CacheManager;
486
+ let useUnifiedOutput = false;
487
+
488
+ try {
489
+ const outputContract = require('../../dist/lib/cli/output-contract');
490
+ buildVerdictOutput = outputContract.buildVerdictOutput;
491
+ normalizeFinding = outputContract.normalizeFinding;
492
+ formatStandardOutput = outputContract.formatStandardOutput;
493
+
494
+ const unifiedOutput = require('./lib/unified-output');
495
+ formatScanOutput = unifiedOutput.formatScanOutput;
496
+ getExitCode = unifiedOutput.getExitCode;
497
+
498
+ const cacheModule = require('../../dist/lib/cli/cache-manager');
499
+ CacheManager = cacheModule.CacheManager;
500
+ useUnifiedOutput = true;
501
+ } catch (error) {
502
+ // Fallback to old system if new one not available
503
+ if (opts.verbose) {
504
+ console.warn('Unified output system not available, using legacy format');
505
+ }
506
+ useUnifiedOutput = false;
507
+ }
508
+
509
+ // Initialize cache if available
510
+ let cache = null;
511
+ let cached = false;
512
+ let cachedResult = null;
513
+
514
+ if (CacheManager) {
515
+ cache = new CacheManager(projectPath);
516
+ const cacheKey = 'scan';
517
+
518
+ // Compute project hash for caching
519
+ const sourceFiles = await findSourceFiles(projectPath);
520
+ const projectHash = await cache.computeProjectHash(sourceFiles, { layers, baseUrl: opts.baseUrl });
521
+
522
+ // Check cache
523
+ if (!opts.verbose) {
524
+ cachedResult = await cache.get(cacheKey, projectHash);
525
+ if (cachedResult && buildVerdictOutput) {
526
+ cached = true;
527
+ // Use cached result
528
+ const verdict = buildVerdictOutput(cachedResult.findings, cachedResult.timings, true);
529
+ const output = formatStandardOutput(verdict, cachedResult.findings, cachedResult.scanId, projectPath, {
530
+ version: require('../../package.json').version || '1.0.0',
531
+ nodeVersion: process.version,
532
+ platform: process.platform,
533
+ });
534
+
535
+ if (opts.json) {
536
+ console.log(JSON.stringify(output, null, 2));
537
+ return getExitCode(verdict);
538
+ }
539
+
540
+ console.log(formatScanOutput({ verdict, findings: cachedResult.findings }, { verbose: opts.verbose, json: opts.json }));
541
+ return getExitCode(verdict);
542
+ }
543
+ }
544
+ }
545
+
546
+ // Start scanning with spinner
547
+ const timings = { discovery: 0, analysis: 0, verification: 0, detection: 0, total: 0 };
548
+ timings.discovery = Date.now();
549
+
550
+ startSpinner('Analyzing codebase...');
551
+
552
+ const result = await scanRouteIntegrity({
553
+ projectPath,
554
+ layers,
555
+ baseUrl: opts.baseUrl,
556
+ verbose: opts.verbose,
557
+ onProgress: opts.verbose ? (phase, progress) => {
558
+ stopSpinner(`${phase}: ${Math.round(progress)}%`, true);
559
+ if (progress < 100) startSpinner(`Running ${phase}...`);
560
+ } : undefined,
561
+ });
562
+
563
+ timings.analysis = Date.now() - timings.discovery;
564
+
565
+ // Run new detection engines (Dead UI, Billing Bypass, Fake Success)
566
+ let detectionFindings = [];
567
+ try {
568
+ startSpinner('Running detection engines...');
569
+ const detectionStart = Date.now();
570
+
571
+ // Dynamic import for TypeScript detection engines
572
+ const { DeadUIDetector } = require('../../dist/engines/detection/dead-ui-detector');
573
+ const { BillingBypassDetector } = require('../../dist/engines/detection/billing-bypass-detector');
574
+ const { FakeSuccessDetector } = require('../../dist/engines/detection/fake-success-detector');
575
+
576
+ const exclude = ['node_modules', '.git', 'dist', 'build', '.next', 'coverage', '_archive'];
577
+
578
+ // Run detectors in parallel
579
+ const [deadUIResult, billingResult, fakeSuccessResult] = await Promise.all([
580
+ new DeadUIDetector(projectPath).scan({ exclude }),
581
+ new BillingBypassDetector(projectPath).scan({ exclude }),
582
+ new FakeSuccessDetector(projectPath).scan({ exclude }),
583
+ ]);
584
+
585
+ // Convert to normalized findings format
586
+ for (const finding of deadUIResult.findings) {
587
+ detectionFindings.push({
588
+ id: finding.id,
589
+ ruleId: finding.type,
590
+ category: 'DEAD_UI',
591
+ severity: finding.severity,
592
+ title: finding.message,
593
+ description: finding.suggestion,
594
+ file: finding.file,
595
+ line: finding.line,
596
+ evidence: finding.evidence,
597
+ autofixAvailable: false,
598
+ verdict: 'FAIL',
599
+ });
600
+ }
601
+
602
+ for (const finding of billingResult.findings) {
603
+ detectionFindings.push({
604
+ id: finding.id,
605
+ ruleId: finding.type,
606
+ category: 'BILLING',
607
+ severity: finding.severity,
608
+ title: finding.message,
609
+ description: finding.suggestion,
610
+ file: finding.file,
611
+ line: finding.line,
612
+ evidence: finding.evidence,
613
+ autofixAvailable: false,
614
+ verdict: 'FAIL',
615
+ });
616
+ }
617
+
618
+ for (const finding of fakeSuccessResult.findings) {
619
+ detectionFindings.push({
620
+ id: finding.id,
621
+ ruleId: finding.type,
622
+ category: 'FAKE_SUCCESS',
623
+ severity: finding.severity,
624
+ title: finding.message,
625
+ description: finding.suggestion,
626
+ file: finding.file,
627
+ line: finding.line,
628
+ evidence: finding.evidence,
629
+ autofixAvailable: false,
630
+ verdict: 'FAIL',
631
+ });
632
+ }
633
+
634
+ timings.detection = Date.now() - detectionStart;
635
+ stopSpinner(`Detection complete (${detectionFindings.length} findings)`, true);
636
+ } catch (detectionError) {
637
+ // Detection engines not compiled yet - continue without them
638
+ if (opts.verbose) {
639
+ console.log(` ${c.dim}Detection engines not available: ${detectionError.message}${c.reset}`);
640
+ }
641
+ stopSpinner('Detection skipped (not compiled)', true);
642
+ }
643
+
644
+ timings.verification = Date.now() - timings.analysis - timings.discovery;
645
+ timings.total = Date.now() - startTime;
646
+
647
+ stopSpinner('Analysis complete', true);
648
+
649
+ const { report, outputPaths } = result;
650
+
651
+ // Normalize findings with stable IDs
652
+ const existingIDs = new Set();
653
+ const normalizedFindings = [];
654
+
655
+ // Normalize route integrity findings
656
+ if (report.shipBlockers) {
657
+ for (let i = 0; i < report.shipBlockers.length; i++) {
658
+ const blocker = report.shipBlockers[i];
659
+ const category = blocker.category || 'ROUTE';
660
+ const normalized = normalizeFinding(blocker, category, i, existingIDs);
661
+ normalizedFindings.push(normalized);
662
+ }
663
+ }
664
+
665
+ // Normalize Reality Sniff findings if present
666
+ if (report.realitySniffFindings) {
667
+ for (let i = 0; i < report.realitySniffFindings.length; i++) {
668
+ const finding = report.realitySniffFindings[i];
669
+ const category = finding.ruleId?.startsWith('auth') ? 'AUTH' : 'REALITY';
670
+ const normalized = normalizeFinding(finding, category, normalizedFindings.length, existingIDs);
671
+ normalizedFindings.push(normalized);
672
+ }
673
+ }
674
+
675
+ // Add detection engine findings (Dead UI, Billing, Fake Success)
676
+ for (const finding of detectionFindings) {
677
+ normalizedFindings.push(finding);
678
+ }
679
+
680
+ // Use new unified output if available, otherwise fallback to old format
681
+ if (useUnifiedOutput && buildVerdictOutput && normalizeFinding) {
682
+ // Normalize findings with stable IDs
683
+ const existingIDs = new Set();
684
+ const normalizedFindings = [];
685
+
686
+ // Normalize route integrity findings
687
+ if (report.shipBlockers) {
688
+ for (let i = 0; i < report.shipBlockers.length; i++) {
689
+ const blocker = report.shipBlockers[i];
690
+ const category = blocker.category || 'ROUTE';
691
+ const normalized = normalizeFinding(blocker, category, i, existingIDs);
692
+ normalizedFindings.push(normalized);
693
+ }
694
+ }
695
+
696
+ // Normalize Reality Sniff findings if present
697
+ if (report.realitySniffFindings) {
698
+ for (let i = 0; i < report.realitySniffFindings.length; i++) {
699
+ const finding = report.realitySniffFindings[i];
700
+ const category = finding.ruleId?.startsWith('auth') ? 'AUTH' : 'REALITY';
701
+ const normalized = normalizeFinding(finding, category, normalizedFindings.length, existingIDs);
702
+ normalizedFindings.push(normalized);
703
+ }
704
+ }
705
+
706
+ // Add detection engine findings (Dead UI, Billing, Fake Success)
707
+ for (const finding of detectionFindings) {
708
+ normalizedFindings.push(finding);
709
+ }
710
+
711
+ // Build verdict
712
+ const verdict = buildVerdictOutput(normalizedFindings, timings, false);
713
+ const scanId = `scan_${Date.now()}`;
714
+
715
+ // Cache result
716
+ if (cache) {
717
+ const sourceFiles = await findSourceFiles(projectPath);
718
+ const projectHash = await cache.computeProjectHash(sourceFiles, { layers, baseUrl: opts.baseUrl });
719
+ await cache.set('scan', projectHash, {
720
+ findings: normalizedFindings,
721
+ timings,
722
+ scanId,
723
+ }, {
724
+ filesScanned: sourceFiles.length,
725
+ findings: normalizedFindings.length,
726
+ duration: timings.total,
727
+ });
728
+ }
729
+
730
+ // Build standard output
731
+ const standardOutput = formatStandardOutput(verdict, normalizedFindings, scanId, projectPath, {
732
+ version: require('../../package.json').version || '1.0.0',
733
+ nodeVersion: process.version,
734
+ platform: process.platform,
735
+ });
736
+
737
+ // JSON output mode
738
+ if (opts.json) {
739
+ console.log(JSON.stringify(standardOutput, null, 2));
740
+ return getExitCode(verdict);
741
+ }
742
+
743
+ // SARIF output mode
744
+ if (opts.sarif) {
745
+ const sarifContent = fs.readFileSync(outputPaths.sarif, 'utf8');
746
+ console.log(sarifContent);
747
+ return report.score.overall >= 70 ? 0 : 1;
748
+ }
749
+
750
+ // ═══════════════════════════════════════════════════════════════════════════
751
+ // UNIFIED OUTPUT
752
+ // ═══════════════════════════════════════════════════════════════════════════
753
+
754
+ // Use unified output formatter
755
+ console.log(formatScanOutput({ verdict, findings: normalizedFindings }, { verbose: opts.verbose, json: false }));
756
+
757
+ // Additional details if verbose
758
+ if (opts.verbose) {
759
+ printBreakdown(report.score.breakdown);
760
+ printCoverageMap(report.coverageMap);
761
+ printLayers(report.layers);
762
+
763
+ printSection('REPORTS', '📄');
764
+ console.log();
765
+ console.log(` ${c.cyan}${outputPaths.md}${c.reset}`);
766
+ console.log(` ${c.dim}${outputPaths.json}${c.reset}`);
767
+ if (outputPaths.sarif) {
768
+ console.log(` ${c.dim}${outputPaths.sarif}${c.reset}`);
769
+ }
770
+ }
771
+
772
+ // Emit audit event for scan complete
773
+ emitScanComplete(projectPath, verdict.verdict === 'PASS' ? 'success' : 'failure', {
774
+ score: report.score?.overall || (verdict.verdict === 'PASS' ? 100 : 50),
775
+ grade: report.score?.grade || (verdict.verdict === 'PASS' ? 'A' : 'F'),
776
+ issueCount: verdict.summary.blockers,
777
+ durationMs: timings.total,
778
+ });
779
+
780
+ return getExitCode(verdict);
781
+ } // End of if (useUnifiedOutput)
782
+
783
+ } catch (error) {
784
+ stopSpinner(`Scan failed: ${error.message}`, false);
785
+
786
+ // Use unified error handling
787
+ const { printError, EXIT_CODES } = require('./lib/unified-output');
788
+ const exitCode = printError(error, 'Scan');
789
+
790
+ // Emit audit event for scan error
791
+ emitScanComplete(projectPath, 'error', {
792
+ errorCode: error.code || 'SCAN_ERROR',
793
+ errorMessage: error.message,
794
+ durationMs: Date.now() - startTime,
795
+ });
796
+
797
+ return exitCode;
798
+ }
799
+ }
800
+
801
+ // Helper function to find source files for cache hash
802
+ async function findSourceFiles(projectPath) {
803
+ const files = [];
804
+ const fs = require('fs');
805
+ const path = require('path');
806
+
807
+ async function walk(dir) {
808
+ try {
809
+ const entries = await fs.promises.readdir(dir, { withFileTypes: true });
810
+ for (const entry of entries) {
811
+ const fullPath = path.join(dir, entry.name);
812
+ if (entry.isDirectory()) {
813
+ if (!entry.name.startsWith('.') && entry.name !== 'node_modules') {
814
+ await walk(fullPath);
815
+ }
816
+ } else if (entry.isFile()) {
817
+ const ext = path.extname(entry.name).toLowerCase();
818
+ if (['.ts', '.tsx', '.js', '.jsx'].includes(ext)) {
819
+ files.push(fullPath);
820
+ }
821
+ }
822
+ }
823
+ } catch {
824
+ // Skip inaccessible directories
825
+ }
826
+ }
827
+
828
+ await walk(projectPath);
829
+ return files;
830
+ }
831
+
832
+ // Export with error handling wrapper
833
+ module.exports = {
834
+ runScan: withErrorHandling(runScan, "Scan failed"),
835
+ };