vibecheck-ai 2.0.1 → 5.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 (456) hide show
  1. package/bin/.generated +25 -0
  2. package/bin/_deprecations.js +463 -0
  3. package/bin/_router.js +46 -0
  4. package/bin/cli-hygiene.js +241 -0
  5. package/bin/dev/run-v2-torture.js +30 -0
  6. package/bin/registry.js +656 -0
  7. package/bin/runners/CLI_REFACTOR_SUMMARY.md +229 -0
  8. package/bin/runners/ENHANCEMENT_GUIDE.md +121 -0
  9. package/bin/runners/REPORT_AUDIT.md +64 -0
  10. package/bin/runners/cli-utils.js +1070 -0
  11. package/bin/runners/context/ai-task-decomposer.js +337 -0
  12. package/bin/runners/context/analyzer.js +513 -0
  13. package/bin/runners/context/api-contracts.js +427 -0
  14. package/bin/runners/context/context-diff.js +342 -0
  15. package/bin/runners/context/context-pruner.js +291 -0
  16. package/bin/runners/context/dependency-graph.js +414 -0
  17. package/bin/runners/context/generators/claude.js +107 -0
  18. package/bin/runners/context/generators/codex.js +108 -0
  19. package/bin/runners/context/generators/copilot.js +119 -0
  20. package/bin/runners/context/generators/cursor-enhanced.js +2525 -0
  21. package/bin/runners/context/generators/cursor.js +514 -0
  22. package/bin/runners/context/generators/mcp.js +169 -0
  23. package/bin/runners/context/generators/windsurf.js +180 -0
  24. package/bin/runners/context/git-context.js +304 -0
  25. package/bin/runners/context/index.js +1110 -0
  26. package/bin/runners/context/insights.js +173 -0
  27. package/bin/runners/context/mcp-server/generate-rules.js +337 -0
  28. package/bin/runners/context/mcp-server/index.js +1176 -0
  29. package/bin/runners/context/mcp-server/package.json +24 -0
  30. package/bin/runners/context/memory.js +200 -0
  31. package/bin/runners/context/monorepo.js +215 -0
  32. package/bin/runners/context/multi-repo-federation.js +404 -0
  33. package/bin/runners/context/patterns.js +253 -0
  34. package/bin/runners/context/proof-context.js +1264 -0
  35. package/bin/runners/context/security-scanner.js +541 -0
  36. package/bin/runners/context/semantic-search.js +350 -0
  37. package/bin/runners/context/shared.js +264 -0
  38. package/bin/runners/context/team-conventions.js +336 -0
  39. package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -0
  40. package/bin/runners/lib/agent-firewall/ai/false-positive-analyzer.js +474 -0
  41. package/bin/runners/lib/agent-firewall/change-packet/builder.js +488 -0
  42. package/bin/runners/lib/agent-firewall/change-packet/schema.json +228 -0
  43. package/bin/runners/lib/agent-firewall/change-packet/store.js +200 -0
  44. package/bin/runners/lib/agent-firewall/claims/claim-types.js +21 -0
  45. package/bin/runners/lib/agent-firewall/claims/extractor.js +303 -0
  46. package/bin/runners/lib/agent-firewall/claims/patterns.js +24 -0
  47. package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
  48. package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
  49. package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
  50. package/bin/runners/lib/agent-firewall/enforcement/gateway.js +1059 -0
  51. package/bin/runners/lib/agent-firewall/enforcement/index.js +98 -0
  52. package/bin/runners/lib/agent-firewall/enforcement/mode.js +318 -0
  53. package/bin/runners/lib/agent-firewall/enforcement/orchestrator.js +484 -0
  54. package/bin/runners/lib/agent-firewall/enforcement/proof-artifact.js +418 -0
  55. package/bin/runners/lib/agent-firewall/enforcement/schemas/change-event.schema.json +173 -0
  56. package/bin/runners/lib/agent-firewall/enforcement/schemas/intent.schema.json +181 -0
  57. package/bin/runners/lib/agent-firewall/enforcement/schemas/verdict.schema.json +222 -0
  58. package/bin/runners/lib/agent-firewall/enforcement/verdict-v2.js +333 -0
  59. package/bin/runners/lib/agent-firewall/evidence/auth-evidence.js +88 -0
  60. package/bin/runners/lib/agent-firewall/evidence/contract-evidence.js +75 -0
  61. package/bin/runners/lib/agent-firewall/evidence/env-evidence.js +127 -0
  62. package/bin/runners/lib/agent-firewall/evidence/resolver.js +102 -0
  63. package/bin/runners/lib/agent-firewall/evidence/route-evidence.js +213 -0
  64. package/bin/runners/lib/agent-firewall/evidence/side-effect-evidence.js +145 -0
  65. package/bin/runners/lib/agent-firewall/fs-hook/daemon.js +19 -0
  66. package/bin/runners/lib/agent-firewall/fs-hook/installer.js +87 -0
  67. package/bin/runners/lib/agent-firewall/fs-hook/watcher.js +184 -0
  68. package/bin/runners/lib/agent-firewall/git-hook/pre-commit.js +163 -0
  69. package/bin/runners/lib/agent-firewall/ide-extension/cursor.js +107 -0
  70. package/bin/runners/lib/agent-firewall/ide-extension/vscode.js +68 -0
  71. package/bin/runners/lib/agent-firewall/ide-extension/windsurf.js +66 -0
  72. package/bin/runners/lib/agent-firewall/index.js +200 -0
  73. package/bin/runners/lib/agent-firewall/integration/index.js +20 -0
  74. package/bin/runners/lib/agent-firewall/integration/ship-gate.js +437 -0
  75. package/bin/runners/lib/agent-firewall/intent/alignment-engine.js +634 -0
  76. package/bin/runners/lib/agent-firewall/intent/auto-detect.js +426 -0
  77. package/bin/runners/lib/agent-firewall/intent/index.js +102 -0
  78. package/bin/runners/lib/agent-firewall/intent/schema.js +352 -0
  79. package/bin/runners/lib/agent-firewall/intent/store.js +283 -0
  80. package/bin/runners/lib/agent-firewall/interception/fs-interceptor.js +502 -0
  81. package/bin/runners/lib/agent-firewall/interception/index.js +23 -0
  82. package/bin/runners/lib/agent-firewall/interceptor/base.js +308 -0
  83. package/bin/runners/lib/agent-firewall/interceptor/cursor.js +35 -0
  84. package/bin/runners/lib/agent-firewall/interceptor/vscode.js +35 -0
  85. package/bin/runners/lib/agent-firewall/interceptor/windsurf.js +34 -0
  86. package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
  87. package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
  88. package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
  89. package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
  90. package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
  91. package/bin/runners/lib/agent-firewall/logger.js +141 -0
  92. package/bin/runners/lib/agent-firewall/policy/default-policy.json +90 -0
  93. package/bin/runners/lib/agent-firewall/policy/engine.js +103 -0
  94. package/bin/runners/lib/agent-firewall/policy/loader.js +451 -0
  95. package/bin/runners/lib/agent-firewall/policy/rules/auth-drift.js +50 -0
  96. package/bin/runners/lib/agent-firewall/policy/rules/contract-drift.js +50 -0
  97. package/bin/runners/lib/agent-firewall/policy/rules/fake-success.js +79 -0
  98. package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +227 -0
  99. package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +191 -0
  100. package/bin/runners/lib/agent-firewall/policy/rules/scope.js +93 -0
  101. package/bin/runners/lib/agent-firewall/policy/rules/unsafe-side-effect.js +57 -0
  102. package/bin/runners/lib/agent-firewall/policy/schema.json +183 -0
  103. package/bin/runners/lib/agent-firewall/policy/verdict.js +54 -0
  104. package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
  105. package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
  106. package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
  107. package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
  108. package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
  109. package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
  110. package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
  111. package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
  112. package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
  113. package/bin/runners/lib/agent-firewall/risk/thresholds.js +322 -0
  114. package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
  115. package/bin/runners/lib/agent-firewall/session/collector.js +451 -0
  116. package/bin/runners/lib/agent-firewall/session/index.js +26 -0
  117. package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
  118. package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
  119. package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
  120. package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
  121. package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
  122. package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
  123. package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
  124. package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
  125. package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
  126. package/bin/runners/lib/agent-firewall/truthpack/index.js +67 -0
  127. package/bin/runners/lib/agent-firewall/truthpack/loader.js +137 -0
  128. package/bin/runners/lib/agent-firewall/unblock/planner.js +337 -0
  129. package/bin/runners/lib/agent-firewall/utils/ignore-checker.js +118 -0
  130. package/bin/runners/lib/ai-bridge.js +416 -0
  131. package/bin/runners/lib/analysis-core.js +309 -0
  132. package/bin/runners/lib/analyzers.js +2500 -0
  133. package/bin/runners/lib/api-client.js +269 -0
  134. package/bin/runners/lib/approve-output.js +235 -0
  135. package/bin/runners/lib/artifact-envelope.js +540 -0
  136. package/bin/runners/lib/assets/vibecheck-logo.png +0 -0
  137. package/bin/runners/lib/audit-bridge.js +391 -0
  138. package/bin/runners/lib/auth-shared.js +977 -0
  139. package/bin/runners/lib/auth-truth.js +193 -0
  140. package/bin/runners/lib/auth.js +215 -0
  141. package/bin/runners/lib/authority-badge.js +425 -0
  142. package/bin/runners/lib/backup.js +62 -0
  143. package/bin/runners/lib/billing.js +107 -0
  144. package/bin/runners/lib/checkpoint.js +941 -0
  145. package/bin/runners/lib/claims.js +118 -0
  146. package/bin/runners/lib/classify-output.js +204 -0
  147. package/bin/runners/lib/cleanup/engine.js +571 -0
  148. package/bin/runners/lib/cleanup/index.js +53 -0
  149. package/bin/runners/lib/cleanup/output.js +375 -0
  150. package/bin/runners/lib/cleanup/rules.js +1060 -0
  151. package/bin/runners/lib/cli-output.js +400 -0
  152. package/bin/runners/lib/cli-ui.js +540 -0
  153. package/bin/runners/lib/compliance-bridge-new.js +0 -0
  154. package/bin/runners/lib/compliance-bridge.js +165 -0
  155. package/bin/runners/lib/contracts/auth-contract.js +202 -0
  156. package/bin/runners/lib/contracts/env-contract.js +181 -0
  157. package/bin/runners/lib/contracts/external-contract.js +206 -0
  158. package/bin/runners/lib/contracts/guard.js +168 -0
  159. package/bin/runners/lib/contracts/index.js +89 -0
  160. package/bin/runners/lib/contracts/plan-validator.js +311 -0
  161. package/bin/runners/lib/contracts/route-contract.js +199 -0
  162. package/bin/runners/lib/contracts.js +804 -0
  163. package/bin/runners/lib/default-config.js +127 -0
  164. package/bin/runners/lib/detect.js +89 -0
  165. package/bin/runners/lib/detectors-v2.js +622 -0
  166. package/bin/runners/lib/doctor/autofix.js +254 -0
  167. package/bin/runners/lib/doctor/diagnosis-receipt.js +454 -0
  168. package/bin/runners/lib/doctor/failure-signatures.js +526 -0
  169. package/bin/runners/lib/doctor/fix-script.js +336 -0
  170. package/bin/runners/lib/doctor/index.js +37 -0
  171. package/bin/runners/lib/doctor/modules/build-tools.js +453 -0
  172. package/bin/runners/lib/doctor/modules/dependencies.js +325 -0
  173. package/bin/runners/lib/doctor/modules/index.js +105 -0
  174. package/bin/runners/lib/doctor/modules/network.js +250 -0
  175. package/bin/runners/lib/doctor/modules/os-quirks.js +706 -0
  176. package/bin/runners/lib/doctor/modules/project.js +312 -0
  177. package/bin/runners/lib/doctor/modules/repo-integrity.js +485 -0
  178. package/bin/runners/lib/doctor/modules/runtime.js +224 -0
  179. package/bin/runners/lib/doctor/modules/security.js +350 -0
  180. package/bin/runners/lib/doctor/modules/system.js +213 -0
  181. package/bin/runners/lib/doctor/modules/vibecheck.js +394 -0
  182. package/bin/runners/lib/doctor/reporter.js +262 -0
  183. package/bin/runners/lib/doctor/safe-repair.js +384 -0
  184. package/bin/runners/lib/doctor/service.js +262 -0
  185. package/bin/runners/lib/doctor/types.js +113 -0
  186. package/bin/runners/lib/doctor/ui.js +263 -0
  187. package/bin/runners/lib/doctor-enhanced.js +233 -0
  188. package/bin/runners/lib/doctor-output.js +226 -0
  189. package/bin/runners/lib/doctor-v2.js +608 -0
  190. package/bin/runners/lib/drift.js +425 -0
  191. package/bin/runners/lib/enforcement.js +72 -0
  192. package/bin/runners/lib/engine/ast-cache.js +210 -0
  193. package/bin/runners/lib/engine/auth-extractor.js +211 -0
  194. package/bin/runners/lib/engine/billing-extractor.js +112 -0
  195. package/bin/runners/lib/engine/enforcement-extractor.js +100 -0
  196. package/bin/runners/lib/engine/env-extractor.js +207 -0
  197. package/bin/runners/lib/engine/express-extractor.js +208 -0
  198. package/bin/runners/lib/engine/extractors.js +849 -0
  199. package/bin/runners/lib/engine/index.js +207 -0
  200. package/bin/runners/lib/engine/repo-index.js +514 -0
  201. package/bin/runners/lib/engine/types.js +124 -0
  202. package/bin/runners/lib/engines/accessibility-engine.js +190 -0
  203. package/bin/runners/lib/engines/api-consistency-engine.js +162 -0
  204. package/bin/runners/lib/engines/ast-cache.js +99 -0
  205. package/bin/runners/lib/engines/attack-detector.js +1192 -0
  206. package/bin/runners/lib/engines/code-quality-engine.js +255 -0
  207. package/bin/runners/lib/engines/console-logs-engine.js +115 -0
  208. package/bin/runners/lib/engines/cross-file-analysis-engine.js +268 -0
  209. package/bin/runners/lib/engines/dead-code-engine.js +198 -0
  210. package/bin/runners/lib/engines/deprecated-api-engine.js +226 -0
  211. package/bin/runners/lib/engines/empty-catch-engine.js +150 -0
  212. package/bin/runners/lib/engines/file-filter.js +131 -0
  213. package/bin/runners/lib/engines/hardcoded-secrets-engine.js +251 -0
  214. package/bin/runners/lib/engines/mock-data-engine.js +272 -0
  215. package/bin/runners/lib/engines/parallel-processor.js +71 -0
  216. package/bin/runners/lib/engines/performance-issues-engine.js +265 -0
  217. package/bin/runners/lib/engines/security-vulnerabilities-engine.js +243 -0
  218. package/bin/runners/lib/engines/todo-fixme-engine.js +115 -0
  219. package/bin/runners/lib/engines/type-aware-engine.js +152 -0
  220. package/bin/runners/lib/engines/unsafe-regex-engine.js +225 -0
  221. package/bin/runners/lib/engines/vibecheck-engines/README.md +53 -0
  222. package/bin/runners/lib/engines/vibecheck-engines/index.js +15 -0
  223. package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
  224. package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
  225. package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
  226. package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
  227. package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
  228. package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
  229. package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
  230. package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +139 -0
  231. package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
  232. package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
  233. package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
  234. package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
  235. package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
  236. package/bin/runners/lib/engines/vibecheck-engines/package.json +13 -0
  237. package/bin/runners/lib/enterprise-detect.js +603 -0
  238. package/bin/runners/lib/enterprise-init.js +942 -0
  239. package/bin/runners/lib/entitlements-v2.js +265 -0
  240. package/bin/runners/lib/entitlements.generated.js +0 -0
  241. package/bin/runners/lib/entitlements.js +340 -0
  242. package/bin/runners/lib/env-resolver.js +417 -0
  243. package/bin/runners/lib/env-template.js +66 -0
  244. package/bin/runners/lib/env.js +189 -0
  245. package/bin/runners/lib/error-handler.js +368 -0
  246. package/bin/runners/lib/error-messages.js +289 -0
  247. package/bin/runners/lib/evidence-pack.js +684 -0
  248. package/bin/runners/lib/exit-codes.js +275 -0
  249. package/bin/runners/lib/extractors/client-calls.js +990 -0
  250. package/bin/runners/lib/extractors/fastify-route-dump.js +573 -0
  251. package/bin/runners/lib/extractors/fastify-routes.js +426 -0
  252. package/bin/runners/lib/extractors/index.js +363 -0
  253. package/bin/runners/lib/extractors/next-routes.js +524 -0
  254. package/bin/runners/lib/extractors/proof-graph.js +431 -0
  255. package/bin/runners/lib/extractors/route-matcher.js +451 -0
  256. package/bin/runners/lib/extractors/truthpack-v2.js +377 -0
  257. package/bin/runners/lib/extractors/ui-bindings.js +547 -0
  258. package/bin/runners/lib/finding-id.js +69 -0
  259. package/bin/runners/lib/finding-sorter.js +89 -0
  260. package/bin/runners/lib/findings-schema.js +281 -0
  261. package/bin/runners/lib/fingerprint.js +377 -0
  262. package/bin/runners/lib/firewall-prompt.js +50 -0
  263. package/bin/runners/lib/fix-output.js +228 -0
  264. package/bin/runners/lib/global-flags.js +250 -0
  265. package/bin/runners/lib/graph/graph-builder.js +265 -0
  266. package/bin/runners/lib/graph/html-renderer.js +413 -0
  267. package/bin/runners/lib/graph/index.js +32 -0
  268. package/bin/runners/lib/graph/runtime-collector.js +215 -0
  269. package/bin/runners/lib/graph/static-extractor.js +518 -0
  270. package/bin/runners/lib/help-formatter.js +413 -0
  271. package/bin/runners/lib/html-proof-report.js +913 -0
  272. package/bin/runners/lib/html-report.js +650 -0
  273. package/bin/runners/lib/init-wizard.js +601 -0
  274. package/bin/runners/lib/interactive-menu.js +1496 -0
  275. package/bin/runners/lib/json-output.js +76 -0
  276. package/bin/runners/lib/llm.js +75 -0
  277. package/bin/runners/lib/logger.js +38 -0
  278. package/bin/runners/lib/meter.js +61 -0
  279. package/bin/runners/lib/missions/briefing.js +427 -0
  280. package/bin/runners/lib/missions/checkpoint.js +753 -0
  281. package/bin/runners/lib/missions/evidence.js +126 -0
  282. package/bin/runners/lib/missions/hardening.js +851 -0
  283. package/bin/runners/lib/missions/plan.js +648 -0
  284. package/bin/runners/lib/missions/safety-gates.js +645 -0
  285. package/bin/runners/lib/missions/schema.js +478 -0
  286. package/bin/runners/lib/missions/templates.js +317 -0
  287. package/bin/runners/lib/next-action.js +560 -0
  288. package/bin/runners/lib/packs/bundle.js +675 -0
  289. package/bin/runners/lib/packs/evidence-pack.js +671 -0
  290. package/bin/runners/lib/packs/pack-factory.js +837 -0
  291. package/bin/runners/lib/packs/permissions-pack.js +686 -0
  292. package/bin/runners/lib/packs/proof-graph-pack.js +779 -0
  293. package/bin/runners/lib/patch.js +40 -0
  294. package/bin/runners/lib/permissions/auth-model.js +213 -0
  295. package/bin/runners/lib/permissions/idor-prover.js +205 -0
  296. package/bin/runners/lib/permissions/index.js +45 -0
  297. package/bin/runners/lib/permissions/matrix-builder.js +198 -0
  298. package/bin/runners/lib/pkgjson.js +28 -0
  299. package/bin/runners/lib/policy.js +295 -0
  300. package/bin/runners/lib/polish/accessibility.js +62 -0
  301. package/bin/runners/lib/polish/analyzer.js +93 -0
  302. package/bin/runners/lib/polish/backend.js +87 -0
  303. package/bin/runners/lib/polish/configuration.js +83 -0
  304. package/bin/runners/lib/polish/documentation.js +83 -0
  305. package/bin/runners/lib/polish/frontend.js +817 -0
  306. package/bin/runners/lib/polish/index.js +27 -0
  307. package/bin/runners/lib/polish/infrastructure.js +80 -0
  308. package/bin/runners/lib/polish/internationalization.js +85 -0
  309. package/bin/runners/lib/polish/libraries.js +180 -0
  310. package/bin/runners/lib/polish/observability.js +75 -0
  311. package/bin/runners/lib/polish/performance.js +64 -0
  312. package/bin/runners/lib/polish/privacy.js +110 -0
  313. package/bin/runners/lib/polish/resilience.js +92 -0
  314. package/bin/runners/lib/polish/security.js +78 -0
  315. package/bin/runners/lib/polish/seo.js +71 -0
  316. package/bin/runners/lib/polish/styles.js +62 -0
  317. package/bin/runners/lib/polish/utils.js +104 -0
  318. package/bin/runners/lib/preflight.js +142 -0
  319. package/bin/runners/lib/prerequisites.js +149 -0
  320. package/bin/runners/lib/prove-output.js +220 -0
  321. package/bin/runners/lib/reality/correlation-detectors.js +359 -0
  322. package/bin/runners/lib/reality/index.js +318 -0
  323. package/bin/runners/lib/reality/request-hashing.js +416 -0
  324. package/bin/runners/lib/reality/request-mapper.js +453 -0
  325. package/bin/runners/lib/reality/safety-rails.js +463 -0
  326. package/bin/runners/lib/reality/semantic-snapshot.js +408 -0
  327. package/bin/runners/lib/reality/toast-detector.js +393 -0
  328. package/bin/runners/lib/reality-findings.js +84 -0
  329. package/bin/runners/lib/reality-output.js +231 -0
  330. package/bin/runners/lib/receipts.js +179 -0
  331. package/bin/runners/lib/redact.js +29 -0
  332. package/bin/runners/lib/replay/capsule-manager.js +154 -0
  333. package/bin/runners/lib/replay/index.js +263 -0
  334. package/bin/runners/lib/replay/player.js +348 -0
  335. package/bin/runners/lib/replay/recorder.js +331 -0
  336. package/bin/runners/lib/report-engine.js +626 -0
  337. package/bin/runners/lib/report-html.js +1233 -0
  338. package/bin/runners/lib/report-output.js +366 -0
  339. package/bin/runners/lib/report-templates.js +967 -0
  340. package/bin/runners/lib/report.js +135 -0
  341. package/bin/runners/lib/route-detection.js +1209 -0
  342. package/bin/runners/lib/route-truth.js +1322 -0
  343. package/bin/runners/lib/safelist/index.js +96 -0
  344. package/bin/runners/lib/safelist/integration.js +334 -0
  345. package/bin/runners/lib/safelist/matcher.js +696 -0
  346. package/bin/runners/lib/safelist/schema.js +948 -0
  347. package/bin/runners/lib/safelist/store.js +438 -0
  348. package/bin/runners/lib/sandbox/index.js +59 -0
  349. package/bin/runners/lib/sandbox/proof-chain.js +399 -0
  350. package/bin/runners/lib/sandbox/sandbox-runner.js +205 -0
  351. package/bin/runners/lib/sandbox/worktree.js +174 -0
  352. package/bin/runners/lib/scan-cache.js +330 -0
  353. package/bin/runners/lib/scan-output-schema.js +344 -0
  354. package/bin/runners/lib/scan-output.js +631 -0
  355. package/bin/runners/lib/scan-runner.js +135 -0
  356. package/bin/runners/lib/schema-validator.js +350 -0
  357. package/bin/runners/lib/schemas/ajv-validator.js +464 -0
  358. package/bin/runners/lib/schemas/contracts.schema.json +160 -0
  359. package/bin/runners/lib/schemas/error-envelope.schema.json +105 -0
  360. package/bin/runners/lib/schemas/finding-v3.schema.json +151 -0
  361. package/bin/runners/lib/schemas/finding.schema.json +100 -0
  362. package/bin/runners/lib/schemas/mission-pack.schema.json +206 -0
  363. package/bin/runners/lib/schemas/proof-graph.schema.json +176 -0
  364. package/bin/runners/lib/schemas/reality-report.schema.json +162 -0
  365. package/bin/runners/lib/schemas/report-artifact.schema.json +120 -0
  366. package/bin/runners/lib/schemas/run-request.schema.json +108 -0
  367. package/bin/runners/lib/schemas/share-pack.schema.json +180 -0
  368. package/bin/runners/lib/schemas/ship-manifest.schema.json +251 -0
  369. package/bin/runners/lib/schemas/ship-report.schema.json +117 -0
  370. package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -0
  371. package/bin/runners/lib/schemas/validator.js +465 -0
  372. package/bin/runners/lib/schemas/verdict.schema.json +140 -0
  373. package/bin/runners/lib/score-history.js +282 -0
  374. package/bin/runners/lib/security-bridge.js +249 -0
  375. package/bin/runners/lib/server-usage.js +513 -0
  376. package/bin/runners/lib/share-pack.js +239 -0
  377. package/bin/runners/lib/ship-gate.js +832 -0
  378. package/bin/runners/lib/ship-manifest.js +1153 -0
  379. package/bin/runners/lib/ship-output-enterprise.js +239 -0
  380. package/bin/runners/lib/ship-output.js +1128 -0
  381. package/bin/runners/lib/snippets.js +67 -0
  382. package/bin/runners/lib/status-output.js +340 -0
  383. package/bin/runners/lib/terminal-ui.js +356 -0
  384. package/bin/runners/lib/truth.js +1691 -0
  385. package/bin/runners/lib/ui.js +562 -0
  386. package/bin/runners/lib/unified-cli-output.js +947 -0
  387. package/bin/runners/lib/unified-output.js +197 -0
  388. package/bin/runners/lib/upsell.js +410 -0
  389. package/bin/runners/lib/usage.js +153 -0
  390. package/bin/runners/lib/validate-patch.js +156 -0
  391. package/bin/runners/lib/verdict-engine.js +628 -0
  392. package/bin/runners/lib/verification.js +345 -0
  393. package/bin/runners/lib/why-tree.js +650 -0
  394. package/bin/runners/reality/engine.js +917 -0
  395. package/bin/runners/reality/flows.js +122 -0
  396. package/bin/runners/reality/report.js +378 -0
  397. package/bin/runners/reality/session.js +193 -0
  398. package/bin/runners/runAIAgent.js +229 -0
  399. package/bin/runners/runAgent.d.ts +5 -0
  400. package/bin/runners/runAgent.js +161 -0
  401. package/bin/runners/runAllowlist.js +418 -0
  402. package/bin/runners/runApprove.js +320 -0
  403. package/bin/runners/runAudit.js +692 -0
  404. package/bin/runners/runAuth.js +731 -0
  405. package/bin/runners/runCI.js +353 -0
  406. package/bin/runners/runCheckpoint.js +530 -0
  407. package/bin/runners/runClassify.js +928 -0
  408. package/bin/runners/runCleanup.js +343 -0
  409. package/bin/runners/runContext.d.ts +4 -0
  410. package/bin/runners/runContext.js +175 -0
  411. package/bin/runners/runDoctor.js +877 -0
  412. package/bin/runners/runEvidencePack.js +362 -0
  413. package/bin/runners/runFirewall.d.ts +5 -0
  414. package/bin/runners/runFirewall.js +134 -0
  415. package/bin/runners/runFirewallHook.d.ts +5 -0
  416. package/bin/runners/runFirewallHook.js +56 -0
  417. package/bin/runners/runFix.js +1355 -0
  418. package/bin/runners/runForge.js +451 -0
  419. package/bin/runners/runGuard.js +262 -0
  420. package/bin/runners/runInit.js +1927 -0
  421. package/bin/runners/runIntent.js +906 -0
  422. package/bin/runners/runKickoff.js +878 -0
  423. package/bin/runners/runLabs.js +424 -0
  424. package/bin/runners/runLaunch.js +2000 -0
  425. package/bin/runners/runLink.js +785 -0
  426. package/bin/runners/runMcp.js +1875 -0
  427. package/bin/runners/runPacks.js +2089 -0
  428. package/bin/runners/runPolish.d.ts +4 -0
  429. package/bin/runners/runPolish.js +390 -0
  430. package/bin/runners/runPromptFirewall.js +211 -0
  431. package/bin/runners/runProve.js +1411 -0
  432. package/bin/runners/runQuickstart.js +531 -0
  433. package/bin/runners/runReality.js +2260 -0
  434. package/bin/runners/runReport.js +726 -0
  435. package/bin/runners/runRuntime.js +110 -0
  436. package/bin/runners/runSafelist.js +1190 -0
  437. package/bin/runners/runScan.js +688 -0
  438. package/bin/runners/runShield.js +1282 -0
  439. package/bin/runners/runShip.js +1660 -0
  440. package/bin/runners/runTruth.d.ts +5 -0
  441. package/bin/runners/runTruth.js +101 -0
  442. package/bin/runners/runValidate.js +179 -0
  443. package/bin/runners/runWatch.js +478 -0
  444. package/bin/runners/utils.js +360 -0
  445. package/bin/scan.js +617 -0
  446. package/bin/vibecheck.js +1617 -0
  447. package/dist/guardrail/index.d.ts +2405 -0
  448. package/dist/guardrail/index.js +9747 -0
  449. package/dist/guardrail/index.js.map +1 -0
  450. package/dist/scanner/index.d.ts +282 -0
  451. package/dist/scanner/index.js +3395 -0
  452. package/dist/scanner/index.js.map +1 -0
  453. package/package.json +123 -104
  454. package/README.md +0 -491
  455. package/dist/index.js +0 -99711
  456. package/dist/index.js.map +0 -1
@@ -0,0 +1,1411 @@
1
+ /**
2
+ * vibecheck prove - One Command Reality Proof
3
+ *
4
+ * ═══════════════════════════════════════════════════════════════════════════════
5
+ * ENTERPRISE EDITION - World-Class Terminal Experience
6
+ * ═══════════════════════════════════════════════════════════════════════════════
7
+ *
8
+ * Orchestrates the complete "make it real" loop:
9
+ * 1. ctx - Refresh truthpack
10
+ * 2. reality --verify-auth - Runtime proof
11
+ * 3. ship - Static + runtime verdict
12
+ * 4. If BLOCK: fix --loop --apply
13
+ * 5. Re-run reality + ship to confirm SHIP
14
+ *
15
+ * One command = one outcome: either it's real, or it keeps fixing until it is.
16
+ */
17
+
18
+ "use strict";
19
+
20
+ const fs = require("fs");
21
+ const path = require("path");
22
+ const { buildTruthpackSmart, writeTruthpack, detectFastifyEntry } = require("./lib/truth");
23
+ const { shipCore } = require("./runShip");
24
+ const { findContractDrift, loadContracts, hasContracts, getDriftSummary } = require("./lib/drift");
25
+ const {
26
+ generateRunId,
27
+ createJsonOutput,
28
+ writeJsonOutput,
29
+ saveArtifact
30
+ } = require("./lib/cli-output");
31
+ const { EXIT, verdictToExitCode, exitCodeToVerdict } = require("./lib/exit-codes");
32
+ const { parseGlobalFlags, shouldShowBanner } = require("./lib/global-flags");
33
+ const upsell = require("./lib/upsell");
34
+
35
+ let runReality;
36
+ try {
37
+ runReality = require("./runReality").runReality;
38
+ } catch {
39
+ runReality = null;
40
+ }
41
+
42
+ let runFixCore;
43
+ try {
44
+ runFixCore = require("./runFix").runFixCore;
45
+ } catch {
46
+ runFixCore = null;
47
+ }
48
+
49
+ // ═══════════════════════════════════════════════════════════════════════════════
50
+ // ADVANCED TERMINAL - ANSI CODES & UTILITIES
51
+ // ═══════════════════════════════════════════════════════════════════════════════
52
+
53
+ const c = {
54
+ reset: '\x1b[0m',
55
+ bold: '\x1b[1m',
56
+ dim: '\x1b[2m',
57
+ italic: '\x1b[3m',
58
+ underline: '\x1b[4m',
59
+ blink: '\x1b[5m',
60
+ inverse: '\x1b[7m',
61
+ hidden: '\x1b[8m',
62
+ strike: '\x1b[9m',
63
+ // Colors
64
+ black: '\x1b[30m',
65
+ red: '\x1b[31m',
66
+ green: '\x1b[32m',
67
+ yellow: '\x1b[33m',
68
+ blue: '\x1b[34m',
69
+ magenta: '\x1b[35m',
70
+ cyan: '\x1b[36m',
71
+ white: '\x1b[37m',
72
+ // Bright colors
73
+ gray: '\x1b[90m',
74
+ brightRed: '\x1b[91m',
75
+ brightGreen: '\x1b[92m',
76
+ brightYellow: '\x1b[93m',
77
+ brightBlue: '\x1b[94m',
78
+ brightMagenta: '\x1b[95m',
79
+ brightCyan: '\x1b[96m',
80
+ brightWhite: '\x1b[97m',
81
+ // Background
82
+ bgBlack: '\x1b[40m',
83
+ bgRed: '\x1b[41m',
84
+ bgGreen: '\x1b[42m',
85
+ bgYellow: '\x1b[43m',
86
+ bgBlue: '\x1b[44m',
87
+ bgMagenta: '\x1b[45m',
88
+ bgCyan: '\x1b[46m',
89
+ bgWhite: '\x1b[47m',
90
+ bgBrightBlack: '\x1b[100m',
91
+ // Cursor control
92
+ cursorUp: (n = 1) => `\x1b[${n}A`,
93
+ cursorDown: (n = 1) => `\x1b[${n}B`,
94
+ cursorRight: (n = 1) => `\x1b[${n}C`,
95
+ cursorLeft: (n = 1) => `\x1b[${n}D`,
96
+ clearLine: '\x1b[2K',
97
+ clearScreen: '\x1b[2J',
98
+ saveCursor: '\x1b[s',
99
+ restoreCursor: '\x1b[u',
100
+ hideCursor: '\x1b[?25l',
101
+ showCursor: '\x1b[?25h',
102
+ };
103
+
104
+ // True color support
105
+ const rgb = (r, g, b) => `\x1b[38;2;${r};${g};${b}m`;
106
+ const bgRgb = (r, g, b) => `\x1b[48;2;${r};${g};${b}m`;
107
+
108
+ // Premium color palette
109
+ const colors = {
110
+ // Gradient for banner (purple/magenta theme for "prove")
111
+ gradient1: rgb(180, 100, 255), // Light purple
112
+ gradient2: rgb(150, 80, 255), // Purple
113
+ gradient3: rgb(120, 60, 255), // Deep purple
114
+ gradient4: rgb(100, 50, 220), // Blue-purple
115
+ gradient5: rgb(80, 40, 200), // Dark purple
116
+ gradient6: rgb(60, 30, 180), // Deepest
117
+
118
+ // Accent colors
119
+ science: rgb(180, 100, 255), // Scientific purple
120
+ reality: rgb(255, 150, 100), // Reality orange
121
+ truth: rgb(100, 200, 255), // Truth blue
122
+ fix: rgb(100, 255, 200), // Fix green
123
+
124
+ // Verdict colors
125
+ shipGreen: rgb(0, 255, 150),
126
+ warnAmber: rgb(255, 200, 0),
127
+ blockRed: rgb(255, 80, 80),
128
+
129
+ // UI colors
130
+ accent: rgb(180, 130, 255),
131
+ muted: rgb(120, 100, 140),
132
+ subtle: rgb(80, 70, 100),
133
+ highlight: rgb(255, 255, 255),
134
+
135
+ // Step colors
136
+ step1: rgb(100, 200, 255), // Context - blue
137
+ step2: rgb(255, 150, 100), // Reality - orange
138
+ step3: rgb(0, 255, 150), // Ship - green
139
+ step4: rgb(255, 200, 100), // Fix - yellow
140
+ step5: rgb(180, 100, 255), // Verify - purple
141
+ };
142
+
143
+ // ═══════════════════════════════════════════════════════════════════════════════
144
+ // PREMIUM BANNER
145
+ // ═══════════════════════════════════════════════════════════════════════════════
146
+
147
+ const PROVE_BANNER = `
148
+ ${rgb(200, 120, 255)} ██████╗ ██████╗ ██████╗ ██╗ ██╗███████╗${c.reset}
149
+ ${rgb(180, 100, 255)} ██╔══██╗██╔══██╗██╔═══██╗██║ ██║██╔════╝${c.reset}
150
+ ${rgb(160, 80, 255)} ██████╔╝██████╔╝██║ ██║██║ ██║█████╗ ${c.reset}
151
+ ${rgb(140, 60, 255)} ██╔═══╝ ██╔══██╗██║ ██║╚██╗ ██╔╝██╔══╝ ${c.reset}
152
+ ${rgb(120, 40, 255)} ██║ ██║ ██║╚██████╔╝ ╚████╔╝ ███████╗${c.reset}
153
+ ${rgb(100, 20, 255)} ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═══╝ ╚══════╝${c.reset}
154
+ `;
155
+
156
+ const BANNER_FULL = `
157
+ ${rgb(200, 120, 255)} ██╗ ██╗██╗██████╗ ███████╗ ██████╗██╗ ██╗███████╗ ██████╗██╗ ██╗${c.reset}
158
+ ${rgb(180, 100, 255)} ██║ ██║██║██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔════╝██║ ██╔╝${c.reset}
159
+ ${rgb(160, 80, 255)} ██║ ██║██║██████╔╝█████╗ ██║ ███████║█████╗ ██║ █████╔╝ ${c.reset}
160
+ ${rgb(140, 60, 255)} ╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██║ ██╔══██║██╔══╝ ██║ ██╔═██╗ ${c.reset}
161
+ ${rgb(120, 40, 255)} ╚████╔╝ ██║██████╔╝███████╗╚██████╗██║ ██║███████╗╚██████╗██║ ██╗${c.reset}
162
+ ${rgb(100, 20, 255)} ╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝${c.reset}
163
+
164
+ ${c.dim} ┌─────────────────────────────────────────────────────────────────────┐${c.reset}
165
+ ${c.dim} │${c.reset} ${rgb(180, 100, 255)}🔬${c.reset} ${c.bold}PROVE${c.reset} ${c.dim}•${c.reset} ${rgb(200, 200, 200)}One Command${c.reset} ${c.dim}•${c.reset} ${rgb(150, 150, 150)}Reality Proof${c.reset} ${c.dim}•${c.reset} ${rgb(100, 100, 100)}Make It Real${c.reset} ${c.dim}│${c.reset}
166
+ ${c.dim} └─────────────────────────────────────────────────────────────────────┘${c.reset}
167
+ `;
168
+
169
+ // ═══════════════════════════════════════════════════════════════════════════════
170
+ // ICONS & SYMBOLS
171
+ // ═══════════════════════════════════════════════════════════════════════════════
172
+
173
+ const ICONS = {
174
+ // Steps
175
+ context: '📋',
176
+ reality: '🎭',
177
+ ship: '🚀',
178
+ fix: '🔧',
179
+ verify: '✅',
180
+ prove: '🔬',
181
+
182
+ // Status
183
+ check: '✓',
184
+ cross: '✗',
185
+ warning: '⚠',
186
+ info: 'ℹ',
187
+ arrow: '→',
188
+ bullet: '•',
189
+
190
+ // Actions
191
+ running: '▶',
192
+ complete: '●',
193
+ pending: '○',
194
+ skip: '◌',
195
+
196
+ // Objects
197
+ route: '🛤️',
198
+ env: '🌍',
199
+ auth: '🔒',
200
+ clock: '⏱',
201
+ target: '🎯',
202
+ lightning: '⚡',
203
+ loop: '🔄',
204
+ doc: '📄',
205
+ folder: '📁',
206
+ graph: '📊',
207
+
208
+ // Misc
209
+ sparkle: '✨',
210
+ fire: '🔥',
211
+ star: '★',
212
+ microscope: '🔬',
213
+ beaker: '🧪',
214
+ dna: '🧬',
215
+ };
216
+
217
+ // ═══════════════════════════════════════════════════════════════════════════════
218
+ // BOX DRAWING
219
+ // ═══════════════════════════════════════════════════════════════════════════════
220
+
221
+ const BOX = {
222
+ topLeft: '╭', topRight: '╮', bottomLeft: '╰', bottomRight: '╯',
223
+ horizontal: '─', vertical: '│',
224
+ teeRight: '├', teeLeft: '┤', teeDown: '┬', teeUp: '┴',
225
+ cross: '┼',
226
+ // Double line
227
+ dTopLeft: '╔', dTopRight: '╗', dBottomLeft: '╚', dBottomRight: '╝',
228
+ dHorizontal: '═', dVertical: '║',
229
+ // Heavy
230
+ hTopLeft: '┏', hTopRight: '┓', hBottomLeft: '┗', hBottomRight: '┛',
231
+ hHorizontal: '━', hVertical: '┃',
232
+ };
233
+
234
+ // ═══════════════════════════════════════════════════════════════════════════════
235
+ // SPINNER & PROGRESS
236
+ // ═══════════════════════════════════════════════════════════════════════════════
237
+
238
+ const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
239
+ const SPINNER_DOTS = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];
240
+ const SPINNER_DNA = ['🧬', '🔬', '🧪', '⚗️', '🧫', '🔭'];
241
+
242
+ let spinnerIndex = 0;
243
+ let spinnerInterval = null;
244
+ let spinnerStartTime = null;
245
+
246
+ function formatDuration(ms) {
247
+ if (ms < 1000) return `${ms}ms`;
248
+ if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
249
+ const mins = Math.floor(ms / 60000);
250
+ const secs = Math.floor((ms % 60000) / 1000);
251
+ return `${mins}m ${secs}s`;
252
+ }
253
+
254
+ function formatNumber(num) {
255
+ return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
256
+ }
257
+
258
+ function truncate(str, len) {
259
+ if (!str) return '';
260
+ if (str.length <= len) return str;
261
+ return str.slice(0, len - 3) + '...';
262
+ }
263
+
264
+ function padCenter(str, width) {
265
+ const padding = Math.max(0, width - str.length);
266
+ const left = Math.floor(padding / 2);
267
+ const right = padding - left;
268
+ return ' '.repeat(left) + str + ' '.repeat(right);
269
+ }
270
+
271
+ function progressBar(percent, width = 30, opts = {}) {
272
+ const filled = Math.round((percent / 100) * width);
273
+ const empty = width - filled;
274
+
275
+ let filledColor;
276
+ if (opts.color) {
277
+ filledColor = opts.color;
278
+ } else if (percent >= 80) {
279
+ filledColor = colors.shipGreen;
280
+ } else if (percent >= 50) {
281
+ filledColor = colors.warnAmber;
282
+ } else {
283
+ filledColor = colors.blockRed;
284
+ }
285
+
286
+ const filledChar = opts.filled || '█';
287
+ const emptyChar = opts.empty || '░';
288
+
289
+ return `${filledColor}${filledChar.repeat(filled)}${c.dim}${emptyChar.repeat(empty)}${c.reset}`;
290
+ }
291
+
292
+ function startSpinner(message, color = colors.science) {
293
+ spinnerStartTime = Date.now();
294
+ process.stdout.write(c.hideCursor);
295
+
296
+ spinnerInterval = setInterval(() => {
297
+ const elapsed = formatDuration(Date.now() - spinnerStartTime);
298
+ process.stdout.write(`\r${c.clearLine} ${color}${SPINNER_DOTS[spinnerIndex]}${c.reset} ${message} ${c.dim}${elapsed}${c.reset}`);
299
+ spinnerIndex = (spinnerIndex + 1) % SPINNER_DOTS.length;
300
+ }, 80);
301
+ }
302
+
303
+ function stopSpinner(message, success = true) {
304
+ if (spinnerInterval) {
305
+ clearInterval(spinnerInterval);
306
+ spinnerInterval = null;
307
+ }
308
+ const elapsed = spinnerStartTime ? formatDuration(Date.now() - spinnerStartTime) : '';
309
+ const icon = success ? `${colors.shipGreen}${ICONS.check}${c.reset}` : `${colors.blockRed}${ICONS.cross}${c.reset}`;
310
+ process.stdout.write(`\r${c.clearLine} ${icon} ${message} ${c.dim}${elapsed}${c.reset}\n`);
311
+ process.stdout.write(c.showCursor);
312
+ spinnerStartTime = null;
313
+ }
314
+
315
+ function updateSpinner(message) {
316
+ if (spinnerInterval) {
317
+ // Just update the message, spinner keeps running
318
+ }
319
+ }
320
+
321
+ // ═══════════════════════════════════════════════════════════════════════════════
322
+ // SECTION HEADERS
323
+ // ═══════════════════════════════════════════════════════════════════════════════
324
+
325
+ function printBanner() {
326
+ console.log(BANNER_FULL);
327
+ }
328
+
329
+ function printCompactBanner() {
330
+ console.log(PROVE_BANNER);
331
+ }
332
+
333
+ function printDivider(char = '─', width = 69, color = c.dim) {
334
+ console.log(`${color} ${char.repeat(width)}${c.reset}`);
335
+ }
336
+
337
+ function printSection(title, icon = '◆') {
338
+ console.log();
339
+ console.log(` ${colors.accent}${icon}${c.reset} ${c.bold}${title}${c.reset}`);
340
+ printDivider();
341
+ }
342
+
343
+ // ═══════════════════════════════════════════════════════════════════════════════
344
+ // STEP DISPLAY - THE PROVE PIPELINE VISUALIZATION
345
+ // ═══════════════════════════════════════════════════════════════════════════════
346
+
347
+ function getStepConfig(stepNum) {
348
+ const configs = {
349
+ 1: { icon: ICONS.context, name: 'CONTEXT', color: colors.step1, desc: 'Refresh truthpack' },
350
+ 2: { icon: ICONS.reality, name: 'REALITY', color: colors.step2, desc: 'Runtime UI proof' },
351
+ 3: { icon: ICONS.ship, name: 'SHIP', color: colors.step3, desc: 'Static verdict' },
352
+ 4: { icon: ICONS.fix, name: 'FIX', color: colors.step4, desc: 'Auto-fix loop' },
353
+ 5: { icon: ICONS.verify, name: 'VERIFY', color: colors.step5, desc: 'Final verification' },
354
+ };
355
+ return configs[stepNum] || { icon: ICONS.bullet, name: `STEP ${stepNum}`, color: colors.accent, desc: '' };
356
+ }
357
+
358
+ function printStepHeader(stepNum, subtitle = null) {
359
+ const config = getStepConfig(stepNum);
360
+
361
+ console.log();
362
+ console.log(` ${config.color}${BOX.hTopLeft}${BOX.hHorizontal.repeat(3)}${c.reset} ${config.icon} ${c.bold}Step ${stepNum}: ${config.name}${c.reset}`);
363
+
364
+ if (subtitle) {
365
+ console.log(` ${config.color}${BOX.hVertical}${c.reset} ${c.dim}${subtitle}${c.reset}`);
366
+ } else {
367
+ console.log(` ${config.color}${BOX.hVertical}${c.reset} ${c.dim}${config.desc}${c.reset}`);
368
+ }
369
+
370
+ console.log(` ${config.color}${BOX.hBottomLeft}${BOX.hHorizontal.repeat(66)}${c.reset}`);
371
+ }
372
+
373
+ function printStepResult(stepNum, status, details = {}) {
374
+ const config = getStepConfig(stepNum);
375
+
376
+ let statusIcon, statusColor, statusText;
377
+
378
+ switch (status) {
379
+ case 'ok':
380
+ case 'SHIP':
381
+ case 'CLEAN':
382
+ statusIcon = ICONS.check;
383
+ statusColor = colors.shipGreen;
384
+ statusText = status === 'SHIP' ? 'SHIP' : status === 'CLEAN' ? 'CLEAN' : 'Complete';
385
+ break;
386
+ case 'WARN':
387
+ statusIcon = ICONS.warning;
388
+ statusColor = colors.warnAmber;
389
+ statusText = 'WARN';
390
+ break;
391
+ case 'BLOCK':
392
+ case 'error':
393
+ statusIcon = ICONS.cross;
394
+ statusColor = colors.blockRed;
395
+ statusText = status === 'BLOCK' ? 'BLOCK' : 'Failed';
396
+ break;
397
+ case 'skipped':
398
+ statusIcon = ICONS.skip;
399
+ statusColor = colors.muted;
400
+ statusText = 'Skipped';
401
+ break;
402
+ default:
403
+ statusIcon = ICONS.info;
404
+ statusColor = colors.accent;
405
+ statusText = status;
406
+ }
407
+
408
+ let resultLine = ` ${statusColor}${statusIcon}${c.reset} ${c.bold}${statusText}${c.reset}`;
409
+
410
+ // Add details
411
+ const detailParts = [];
412
+ if (details.routes !== undefined) detailParts.push(`${details.routes} routes`);
413
+ if (details.envVars !== undefined) detailParts.push(`${details.envVars} env vars`);
414
+ if (details.findings !== undefined) {
415
+ if (typeof details.findings === 'object') {
416
+ detailParts.push(`${details.findings.BLOCK || 0} blockers, ${details.findings.WARN || 0} warnings`);
417
+ } else {
418
+ detailParts.push(`${details.findings} findings`);
419
+ }
420
+ }
421
+ if (details.coverage !== undefined && details.coverage !== null) {
422
+ detailParts.push(`${details.coverage}% coverage`);
423
+ }
424
+ if (details.pagesVisited !== undefined) detailParts.push(`${details.pagesVisited} pages`);
425
+ if (details.reason) detailParts.push(details.reason);
426
+ if (details.error) detailParts.push(`error: ${truncate(details.error, 40)}`);
427
+
428
+ if (detailParts.length > 0) {
429
+ resultLine += ` ${c.dim}(${detailParts.join(', ')})${c.reset}`;
430
+ }
431
+
432
+ console.log(resultLine);
433
+ }
434
+
435
+ // ═══════════════════════════════════════════════════════════════════════════════
436
+ // PIPELINE PROGRESS VISUALIZATION
437
+ // ═══════════════════════════════════════════════════════════════════════════════
438
+
439
+ function printPipelineOverview(steps = []) {
440
+ console.log();
441
+ console.log(` ${c.dim}Pipeline:${c.reset}`);
442
+
443
+ let pipeline = ' ';
444
+ const stepConfigs = [1, 2, 3, 4, 5].map(n => getStepConfig(n));
445
+
446
+ for (let i = 0; i < stepConfigs.length; i++) {
447
+ const step = stepConfigs[i];
448
+ const stepStatus = steps[i];
449
+
450
+ let color = colors.muted;
451
+ let icon = ICONS.pending;
452
+
453
+ if (stepStatus === 'complete') {
454
+ color = colors.shipGreen;
455
+ icon = ICONS.complete;
456
+ } else if (stepStatus === 'running') {
457
+ color = step.color;
458
+ icon = ICONS.running;
459
+ } else if (stepStatus === 'error') {
460
+ color = colors.blockRed;
461
+ icon = ICONS.cross;
462
+ } else if (stepStatus === 'skipped') {
463
+ color = colors.muted;
464
+ icon = ICONS.skip;
465
+ }
466
+
467
+ pipeline += `${color}${icon}${c.reset}`;
468
+
469
+ if (i < stepConfigs.length - 1) {
470
+ const connectorColor = stepStatus === 'complete' ? colors.shipGreen : colors.muted;
471
+ pipeline += `${connectorColor}───${c.reset}`;
472
+ }
473
+ }
474
+
475
+ console.log(pipeline);
476
+
477
+ // Labels
478
+ let labels = ' ';
479
+ for (let i = 0; i < stepConfigs.length; i++) {
480
+ const step = stepConfigs[i];
481
+ labels += `${c.dim}${step.name.slice(0, 3)}${c.reset}`;
482
+ if (i < stepConfigs.length - 1) {
483
+ labels += ' ';
484
+ }
485
+ }
486
+ console.log(labels);
487
+ }
488
+
489
+ // ═══════════════════════════════════════════════════════════════════════════════
490
+ // FIX LOOP VISUALIZATION
491
+ // ═══════════════════════════════════════════════════════════════════════════════
492
+
493
+ function printFixLoopHeader(round, maxRounds) {
494
+ const progress = Math.round((round / maxRounds) * 100);
495
+
496
+ console.log();
497
+ console.log(` ${colors.step4}${BOX.topLeft}${BOX.horizontal.repeat(3)}${c.reset} ${ICONS.loop} ${c.bold}Fix Round ${round}/${maxRounds}${c.reset}`);
498
+ console.log(` ${colors.step4}${BOX.vertical}${c.reset} ${progressBar(progress, 20, { color: colors.step4 })} ${c.dim}${progress}%${c.reset}`);
499
+ console.log(` ${colors.step4}${BOX.bottomLeft}${BOX.horizontal.repeat(50)}${c.reset}`);
500
+ }
501
+
502
+ function printMissionStatus(mission, status, detail = null) {
503
+ let icon, color;
504
+
505
+ switch (status) {
506
+ case 'planning':
507
+ icon = ICONS.target;
508
+ color = colors.accent;
509
+ break;
510
+ case 'applying':
511
+ icon = ICONS.lightning;
512
+ color = colors.step4;
513
+ break;
514
+ case 'success':
515
+ icon = ICONS.check;
516
+ color = colors.shipGreen;
517
+ break;
518
+ case 'failed':
519
+ icon = ICONS.cross;
520
+ color = colors.blockRed;
521
+ break;
522
+ case 'skipped':
523
+ icon = ICONS.skip;
524
+ color = colors.muted;
525
+ break;
526
+ default:
527
+ icon = ICONS.bullet;
528
+ color = colors.muted;
529
+ }
530
+
531
+ let line = ` ${color}${icon}${c.reset} ${truncate(mission.title || mission, 50)}`;
532
+ if (detail) {
533
+ line += ` ${c.dim}${detail}${c.reset}`;
534
+ }
535
+ console.log(line);
536
+ }
537
+
538
+ // ═══════════════════════════════════════════════════════════════════════════════
539
+ // FINAL VERDICT DISPLAY
540
+ // ═══════════════════════════════════════════════════════════════════════════════
541
+
542
+ function getVerdictConfig(verdict) {
543
+ if (verdict === 'SHIP') {
544
+ return {
545
+ icon: '🚀',
546
+ headline: 'PROVED REAL',
547
+ tagline: 'Your app is verified and ready to ship!',
548
+ color: colors.shipGreen,
549
+ bgColor: bgRgb(0, 80, 50),
550
+ borderColor: rgb(0, 200, 120),
551
+ };
552
+ }
553
+
554
+ if (verdict === 'WARN') {
555
+ return {
556
+ icon: '⚠️',
557
+ headline: 'PARTIALLY PROVED',
558
+ tagline: 'Some warnings remain - review before shipping',
559
+ color: colors.warnAmber,
560
+ bgColor: bgRgb(80, 60, 0),
561
+ borderColor: rgb(200, 160, 0),
562
+ };
563
+ }
564
+
565
+ return {
566
+ icon: '🛑',
567
+ headline: 'NOT PROVED',
568
+ tagline: 'Blockers remain - cannot verify readiness',
569
+ color: colors.blockRed,
570
+ bgColor: bgRgb(80, 20, 20),
571
+ borderColor: rgb(200, 60, 60),
572
+ };
573
+ }
574
+
575
+ function printFinalVerdict(verdict, duration, fixRounds, findings) {
576
+ const config = getVerdictConfig(verdict);
577
+ const w = 68;
578
+
579
+ console.log();
580
+ console.log();
581
+
582
+ // Top border
583
+ console.log(` ${config.borderColor}${BOX.dTopLeft}${BOX.dHorizontal.repeat(w)}${BOX.dTopRight}${c.reset}`);
584
+
585
+ // Empty line
586
+ console.log(` ${config.borderColor}${BOX.dVertical}${c.reset}${' '.repeat(w)}${config.borderColor}${BOX.dVertical}${c.reset}`);
587
+
588
+ // Icon and headline
589
+ const headlineText = `${config.icon} ${config.headline}`;
590
+ const headlinePadded = padCenter(headlineText, w);
591
+ console.log(` ${config.borderColor}${BOX.dVertical}${c.reset}${config.color}${c.bold}${headlinePadded}${c.reset}${config.borderColor}${BOX.dVertical}${c.reset}`);
592
+
593
+ // Tagline
594
+ const taglinePadded = padCenter(config.tagline, w);
595
+ console.log(` ${config.borderColor}${BOX.dVertical}${c.reset}${c.dim}${taglinePadded}${c.reset}${config.borderColor}${BOX.dVertical}${c.reset}`);
596
+
597
+ // Empty line
598
+ console.log(` ${config.borderColor}${BOX.dVertical}${c.reset}${' '.repeat(w)}${config.borderColor}${BOX.dVertical}${c.reset}`);
599
+
600
+ // Stats row
601
+ const stats = `Duration: ${c.bold}${duration}${c.reset} ${c.dim}•${c.reset} Fix Rounds: ${c.bold}${fixRounds}${c.reset} ${c.dim}•${c.reset} Findings: ${c.bold}${findings}${c.reset}`;
602
+ const statsPadded = padCenter(stats.replace(/\x1b\[[0-9;]*m/g, '').length < w ? stats : stats, w);
603
+ // We need to calculate visible length for padding
604
+ const visibleStats = `Duration: ${duration} • Fix Rounds: ${fixRounds} • Findings: ${findings}`;
605
+ const leftPad = Math.floor((w - visibleStats.length) / 2);
606
+ const rightPad = w - visibleStats.length - leftPad;
607
+ console.log(` ${config.borderColor}${BOX.dVertical}${c.reset}${' '.repeat(leftPad)}Duration: ${c.bold}${duration}${c.reset} ${c.dim}•${c.reset} Fix Rounds: ${c.bold}${fixRounds}${c.reset} ${c.dim}•${c.reset} Findings: ${c.bold}${findings}${c.reset}${' '.repeat(rightPad)}${config.borderColor}${BOX.dVertical}${c.reset}`);
608
+
609
+ // Empty line
610
+ console.log(` ${config.borderColor}${BOX.dVertical}${c.reset}${' '.repeat(w)}${config.borderColor}${BOX.dVertical}${c.reset}`);
611
+
612
+ // Bottom border
613
+ console.log(` ${config.borderColor}${BOX.dBottomLeft}${BOX.dHorizontal.repeat(w)}${BOX.dBottomRight}${c.reset}`);
614
+
615
+ console.log();
616
+ }
617
+
618
+ // ═══════════════════════════════════════════════════════════════════════════════
619
+ // TIMELINE SUMMARY
620
+ // ═══════════════════════════════════════════════════════════════════════════════
621
+
622
+ function printTimelineSummary(timeline) {
623
+ printSection('PROOF TIMELINE', ICONS.graph);
624
+ console.log();
625
+
626
+ for (const entry of timeline) {
627
+ const stepNum = typeof entry.step === 'number' ? entry.step : parseInt(entry.step) || 0;
628
+ const config = getStepConfig(stepNum);
629
+
630
+ let statusIcon, statusColor;
631
+
632
+ if (entry.status === 'ok' || entry.status === 'SHIP' || entry.status === 'CLEAN') {
633
+ statusIcon = ICONS.check;
634
+ statusColor = colors.shipGreen;
635
+ } else if (entry.status === 'WARN') {
636
+ statusIcon = ICONS.warning;
637
+ statusColor = colors.warnAmber;
638
+ } else if (entry.status === 'BLOCK' || entry.status === 'error') {
639
+ statusIcon = ICONS.cross;
640
+ statusColor = colors.blockRed;
641
+ } else if (entry.status === 'skipped') {
642
+ statusIcon = ICONS.skip;
643
+ statusColor = colors.muted;
644
+ } else {
645
+ statusIcon = ICONS.bullet;
646
+ statusColor = colors.accent;
647
+ }
648
+
649
+ let line = ` ${statusColor}${statusIcon}${c.reset} ${c.bold}${entry.action.toUpperCase().padEnd(10)}${c.reset}`;
650
+
651
+ // Add relevant details
652
+ const details = [];
653
+ if (entry.routes !== undefined) details.push(`${entry.routes} routes`);
654
+ if (entry.verdict) details.push(entry.verdict);
655
+ if (entry.findingsCount !== undefined) details.push(`${entry.findingsCount} findings`);
656
+ if (entry.coverage !== undefined && entry.coverage !== null) details.push(`${entry.coverage}% coverage`);
657
+ if (entry.reason) details.push(entry.reason);
658
+
659
+ if (details.length > 0) {
660
+ line += ` ${c.dim}${details.join(' · ')}${c.reset}`;
661
+ }
662
+
663
+ console.log(line);
664
+ }
665
+ }
666
+
667
+ // ═══════════════════════════════════════════════════════════════════════════════
668
+ // HELP DISPLAY
669
+ // ═══════════════════════════════════════════════════════════════════════════════
670
+
671
+ function printHelp(showBanner = true) {
672
+ if (showBanner && shouldShowBanner({})) {
673
+ console.log(BANNER_FULL);
674
+ }
675
+ console.log(`
676
+ ${c.bold}Usage:${c.reset} vibecheck prove --url <url> [options]
677
+
678
+ ${c.bold}One Command Reality Proof${c.reset} — Undeniable evidence that your app works.
679
+
680
+ Produces a shareable proof bundle with ${c.bold}video${c.reset} + ${c.bold}network evidence${c.reset} showing
681
+ real user flows hitting real APIs. Drop it into CI and instantly trust the verdict.
682
+
683
+ ${c.bold}What You Get:${c.reset}
684
+ ${colors.shipGreen}🎬${c.reset} Video recordings of browser sessions
685
+ ${colors.shipGreen}📡${c.reset} Network traffic capture (HAR files)
686
+ ${colors.shipGreen}📊${c.reset} Playwright traces (viewable at trace.playwright.dev)
687
+ ${colors.shipGreen}📄${c.reset} Beautiful HTML proof report
688
+
689
+ ${c.bold}Pipeline:${c.reset}
690
+ ${colors.step1}1. CTX${c.reset} Refresh truthpack (ground truth)
691
+ ${colors.step2}2. REALITY${c.reset} Runtime UI proof with video + network capture
692
+ ${colors.step3}3. SHIP${c.reset} Static + runtime verdict
693
+ ${colors.step4}4. FIX${c.reset} Auto-fix if BLOCK ${c.dim}(up to N rounds)${c.reset}
694
+ ${colors.step5}5. VERIFY${c.reset} Re-run to confirm SHIP
695
+
696
+ ${c.bold}Options:${c.reset}
697
+ ${colors.accent}--url, -u <url>${c.reset} Base URL for runtime testing ${c.dim}(required)${c.reset}
698
+ ${colors.accent}--auth <email:pass>${c.reset} Login credentials for auth verification
699
+ ${colors.accent}--storage-state <path>${c.reset} Playwright session state file
700
+ ${colors.accent}--stability-runs <n>${c.reset} Multiple runs for flakiness ${c.dim}(default: 2)${c.reset}
701
+ ${colors.accent}--max-fix-rounds <n>${c.reset} Max auto-fix attempts ${c.dim}(default: 3)${c.reset}
702
+ ${colors.accent}--skip-reality${c.reset} Skip runtime crawling (static only)
703
+ ${colors.accent}--skip-fix${c.reset} Don't auto-fix, just diagnose
704
+ ${colors.accent}--headed${c.reset} Run browser in headed mode
705
+ ${colors.accent}--ci${c.reset} CI-friendly output (GitHub Actions)
706
+
707
+ ${c.bold}Recording Options:${c.reset} ${c.dim}(all enabled by default)${c.reset}
708
+ ${colors.accent}--no-video${c.reset} Disable video recording
709
+ ${colors.accent}--no-trace${c.reset} Disable Playwright traces
710
+ ${colors.accent}--no-har${c.reset} Disable HAR network capture
711
+
712
+ ${c.bold}Evidence Pack:${c.reset}
713
+ ${colors.accent}--bundle${c.reset} Generate shareable evidence pack (zip with videos, traces, screenshots)
714
+
715
+ ${c.bold}Exit Codes:${c.reset}
716
+ ${colors.shipGreen}0${c.reset} SHIP — Proved real, ready to deploy
717
+ ${colors.warnAmber}1${c.reset} WARN — Warnings found, review recommended
718
+ ${colors.blockRed}2${c.reset} BLOCK — Blockers found, not proved
719
+
720
+ ${c.bold}Examples:${c.reset}
721
+ ${c.dim}# Full proof with video + network evidence${c.reset}
722
+ vibecheck prove --url http://localhost:3000
723
+
724
+ ${c.dim}# With authentication (two-pass verification)${c.reset}
725
+ vibecheck prove --url http://localhost:3000 --auth user@test.com:pass
726
+
727
+ ${c.dim}# CI integration (GitHub Actions)${c.reset}
728
+ npx vibecheck prove --url \$APP_URL --ci
729
+
730
+ ${c.dim}# Quick check (no recordings)${c.reset}
731
+ vibecheck prove --url http://localhost:3000 --no-video --no-trace
732
+
733
+ ${c.bold}CI Integration:${c.reset}
734
+ ${c.dim}# Add to .github/workflows/test.yml:${c.reset}
735
+ - name: Reality Proof
736
+ run: npx vibecheck prove --url \${{ env.APP_URL }} --ci
737
+ - uses: actions/upload-artifact@v4
738
+ with:
739
+ name: proof-report
740
+ path: .vibecheck/prove/*/proof-report.html
741
+ `);
742
+ }
743
+
744
+ // ═══════════════════════════════════════════════════════════════════════════════
745
+ // UTILITIES
746
+ // ═══════════════════════════════════════════════════════════════════════════════
747
+
748
+ function ensureDir(p) {
749
+ fs.mkdirSync(p, { recursive: true });
750
+ }
751
+
752
+ function stamp() {
753
+ const d = new Date();
754
+ const z = (n) => String(n).padStart(2, "0");
755
+ return `${d.getFullYear()}${z(d.getMonth() + 1)}${z(d.getDate())}_${z(d.getHours())}${z(d.getMinutes())}${z(d.getSeconds())}`;
756
+ }
757
+
758
+ // ═══════════════════════════════════════════════════════════════════════════════
759
+ // MAIN PROVE FUNCTION
760
+ // ═══════════════════════════════════════════════════════════════════════════════
761
+
762
+ async function runProve(argsOrOpts = {}, context = {}) {
763
+ // Extract runId from context or generate new one
764
+ const runId = context.runId || generateRunId();
765
+ const startTime = context.startTime || new Date().toISOString();
766
+ const executionStart = Date.now();
767
+
768
+ // Handle array args from CLI
769
+ if (Array.isArray(argsOrOpts)) {
770
+ // Parse global flags first
771
+ const { flags: globalFlags, cleanArgs } = parseGlobalFlags(argsOrOpts);
772
+
773
+ if (globalFlags.help) {
774
+ printHelp(shouldShowBanner(globalFlags));
775
+ return 0;
776
+ }
777
+
778
+ const getArg = (flags) => {
779
+ for (const f of flags) {
780
+ const idx = cleanArgs.indexOf(f);
781
+ if (idx !== -1 && idx < cleanArgs.length - 1) return cleanArgs[idx + 1];
782
+ }
783
+ return undefined;
784
+ };
785
+ argsOrOpts = {
786
+ ...globalFlags, // Merge global flags (json, verbose, noBanner, quiet, ci, etc.)
787
+ url: getArg(["--url", "-u"]),
788
+ auth: getArg(["--auth"]),
789
+ storageState: getArg(["--storage-state"]),
790
+ fastifyEntry: getArg(["--fastify-entry"]),
791
+ maxFixRounds: parseInt(getArg(["--max-fix-rounds"]) || "3", 10),
792
+ skipReality: cleanArgs.includes("--skip-reality"),
793
+ skipFix: cleanArgs.includes("--skip-fix"),
794
+ headed: cleanArgs.includes("--headed"),
795
+ danger: cleanArgs.includes("--danger"),
796
+ // Recording options - enabled by default for "undeniable proof"
797
+ noVideo: cleanArgs.includes("--no-video"),
798
+ noTrace: cleanArgs.includes("--no-trace"),
799
+ noHar: cleanArgs.includes("--no-har"),
800
+ stabilityRuns: parseInt(getArg(["--stability-runs"]) || "2", 10),
801
+ flakyThreshold: parseFloat(getArg(["--flaky-threshold"]) || "0.66"),
802
+ maxPages: parseInt(getArg(["--max-pages"]) || "18", 10),
803
+ evidencePack: cleanArgs.includes("--evidence-pack") || cleanArgs.includes("--bundle"),
804
+ output: getArg(["--output", "-o"]),
805
+ };
806
+ }
807
+
808
+ const {
809
+ repoRoot,
810
+ url,
811
+ auth,
812
+ storageState,
813
+ fastifyEntry,
814
+ maxFixRounds = 3,
815
+ maxMissions = 8,
816
+ maxSteps = 10,
817
+ skipReality = false,
818
+ skipFix = false,
819
+ headed = false,
820
+ danger = false,
821
+ maxPages = 18,
822
+ maxDepth = 2,
823
+ timeoutMs = 15000,
824
+ // Recording enabled by default for undeniable proof
825
+ noVideo = false,
826
+ noTrace = false,
827
+ noHar = false,
828
+ stabilityRuns = 2,
829
+ flakyThreshold = 0.66,
830
+ json = false,
831
+ output = null,
832
+ ci = false,
833
+ evidencePack = false
834
+ } = argsOrOpts;
835
+
836
+ const root = repoRoot || process.cwd();
837
+ const projectName = path.basename(root);
838
+
839
+ // Initialize pipeline status
840
+ const pipelineStatus = ['pending', 'pending', 'pending', 'pending', 'pending'];
841
+ const outDir = path.join(root, ".vibecheck", "prove", stamp());
842
+ ensureDir(outDir);
843
+
844
+ const timeline = [];
845
+ let finalVerdict = "UNKNOWN";
846
+
847
+ // Print banner (unless JSON or CI mode)
848
+ if (!json && !ci) {
849
+ printBanner();
850
+
851
+ console.log(` ${c.dim}Project:${c.reset} ${c.bold}${projectName}${c.reset}`);
852
+ console.log(` ${c.dim}Path:${c.reset} ${root}`);
853
+ if (url) {
854
+ console.log(` ${c.dim}URL:${c.reset} ${colors.accent}${url}${c.reset}`);
855
+ }
856
+ console.log(` ${c.dim}Fix Rounds:${c.reset} ${maxFixRounds} max`);
857
+
858
+ // Show pipeline overview
859
+ printPipelineOverview(pipelineStatus);
860
+ }
861
+
862
+ // ═══════════════════════════════════════════════════════════════════════════
863
+ // STEP 1: CTX - Refresh truthpack
864
+ // ═══════════════════════════════════════════════════════════════════════════
865
+ printStepHeader(1);
866
+ pipelineStatus[0] = 'running';
867
+
868
+ startSpinner('Refreshing truthpack...', colors.step1);
869
+
870
+ try {
871
+ const fastEntry = fastifyEntry || (await detectFastifyEntry(root));
872
+ const truthpack = await buildTruthpackSmart({ repoRoot: root, fastifyEntry: fastEntry });
873
+ writeTruthpack(root, truthpack);
874
+
875
+ stopSpinner('Truthpack refreshed', true);
876
+
877
+ timeline.push({
878
+ step: 1,
879
+ action: "ctx",
880
+ status: "ok",
881
+ routes: truthpack.routes?.server?.length || 0,
882
+ envVars: truthpack.env?.vars?.length || 0
883
+ });
884
+
885
+ printStepResult(1, 'ok', {
886
+ routes: truthpack.routes?.server?.length || 0,
887
+ envVars: truthpack.env?.vars?.length || 0
888
+ });
889
+
890
+ // Check for contract drift after truthpack refresh
891
+ if (hasContracts(root)) {
892
+ const contracts = loadContracts(root);
893
+ const driftFindings = findContractDrift(contracts, truthpack);
894
+ const driftSummary = getDriftSummary(driftFindings);
895
+
896
+ if (driftSummary.hasDrift) {
897
+ console.log(` ${driftSummary.blocks > 0 ? colors.warnAmber + ICONS.warning : colors.muted + ICONS.info}${c.reset} Contract drift: ${driftSummary.blocks} blocks, ${driftSummary.warns} warnings`);
898
+ timeline.push({
899
+ step: "1.5",
900
+ action: "drift_check",
901
+ status: driftSummary.verdict,
902
+ blocks: driftSummary.blocks,
903
+ warns: driftSummary.warns
904
+ });
905
+
906
+ if (driftSummary.blocks > 0) {
907
+ console.log(` ${c.dim}Run 'vibecheck ctx sync' to update contracts${c.reset}`);
908
+ }
909
+ }
910
+ }
911
+
912
+ pipelineStatus[0] = 'complete';
913
+ } catch (err) {
914
+ stopSpinner(`Context refresh failed: ${err.message}`, false);
915
+ timeline.push({ step: 1, action: "ctx", status: "error", error: err.message });
916
+ pipelineStatus[0] = 'error';
917
+ }
918
+
919
+ // ═══════════════════════════════════════════════════════════════════════════
920
+ // STEP 2: REALITY - Runtime UI proof (if URL provided)
921
+ // ═══════════════════════════════════════════════════════════════════════════
922
+ if (url && !skipReality && runReality) {
923
+ printStepHeader(2, url);
924
+ pipelineStatus[1] = 'running';
925
+
926
+ startSpinner('Running reality check with video + network capture...', colors.step2);
927
+
928
+ try {
929
+ // Enable all recording by default for undeniable proof
930
+ await runReality({
931
+ repoRoot: root,
932
+ url,
933
+ auth,
934
+ storageState,
935
+ verifyAuth: !!auth || !!storageState,
936
+ headed,
937
+ maxPages,
938
+ maxDepth,
939
+ danger,
940
+ timeoutMs,
941
+ // Recording enabled by default for "prove" - undeniable evidence
942
+ recordVideo: !noVideo,
943
+ recordTrace: !noTrace,
944
+ recordHar: !noHar,
945
+ // Multiple stability runs for flakiness reduction
946
+ stabilityRuns: stabilityRuns,
947
+ flakyThreshold: 0.66
948
+ });
949
+
950
+ // Read reality report for timeline
951
+ const realityPath = path.join(root, ".vibecheck", "reality", "last_reality.json");
952
+ if (fs.existsSync(realityPath)) {
953
+ const reality = JSON.parse(fs.readFileSync(realityPath, "utf8"));
954
+ const blocks = (reality.findings || []).filter(f => f.severity === "BLOCK").length;
955
+ const warns = (reality.findings || []).filter(f => f.severity === "WARN").length;
956
+
957
+ stopSpinner('Reality check complete', true);
958
+
959
+ timeline.push({
960
+ step: 2,
961
+ action: "reality",
962
+ status: blocks ? "BLOCK" : warns ? "WARN" : "CLEAN",
963
+ findings: { BLOCK: blocks, WARN: warns },
964
+ pagesVisited: reality.passes?.anon?.pagesVisited?.length || 0,
965
+ coverage: reality.coverage?.percent || null
966
+ });
967
+
968
+ printStepResult(2, blocks ? 'BLOCK' : warns ? 'WARN' : 'CLEAN', {
969
+ findings: { BLOCK: blocks, WARN: warns },
970
+ pagesVisited: reality.passes?.anon?.pagesVisited?.length || 0,
971
+ coverage: reality.coverage?.percent
972
+ });
973
+
974
+ pipelineStatus[1] = blocks ? 'error' : 'complete';
975
+ }
976
+ } catch (err) {
977
+ stopSpinner(`Reality check failed: ${err.message}`, false);
978
+ timeline.push({ step: 2, action: "reality", status: "error", error: err.message });
979
+ pipelineStatus[1] = 'error';
980
+ }
981
+ } else {
982
+ const reason = !url ? 'no --url provided' : '--skip-reality flag';
983
+ console.log();
984
+ console.log(` ${colors.muted}${ICONS.skip}${c.reset} ${c.dim}Step 2: REALITY skipped (${reason})${c.reset}`);
985
+ timeline.push({ step: 2, action: "reality", status: "skipped", reason });
986
+ pipelineStatus[1] = 'skipped';
987
+ }
988
+
989
+ // ═══════════════════════════════════════════════════════════════════════════
990
+ // STEP 3: SHIP - Get initial verdict
991
+ // ═══════════════════════════════════════════════════════════════════════════
992
+ printStepHeader(3);
993
+ pipelineStatus[2] = 'running';
994
+
995
+ startSpinner('Running ship check...', colors.step3);
996
+
997
+ let shipResult = await shipCore({ repoRoot: root, fastifyEntry, noWrite: false });
998
+
999
+ stopSpinner('Ship check complete', true);
1000
+
1001
+ timeline.push({
1002
+ step: 3,
1003
+ action: "ship",
1004
+ verdict: shipResult.verdict,
1005
+ findingsCount: shipResult.report?.findings?.length || 0
1006
+ });
1007
+
1008
+ printStepResult(3, shipResult.verdict, {
1009
+ findings: shipResult.report?.findings?.length || 0
1010
+ });
1011
+
1012
+ pipelineStatus[2] = shipResult.verdict === 'SHIP' ? 'complete' : shipResult.verdict === 'WARN' ? 'complete' : 'error';
1013
+
1014
+ // ═══════════════════════════════════════════════════════════════════════════
1015
+ // STEP 4: FIX LOOP - If BLOCK, attempt loop fix
1016
+ // ═══════════════════════════════════════════════════════════════════════════
1017
+ let fixRound = 0;
1018
+
1019
+ while (shipResult.verdict === "BLOCK" && !skipFix && fixRound < maxFixRounds) {
1020
+ fixRound++;
1021
+
1022
+ if (fixRound === 1) {
1023
+ printStepHeader(4, `Up to ${maxFixRounds} rounds`);
1024
+ pipelineStatus[3] = 'running';
1025
+ }
1026
+
1027
+ printFixLoopHeader(fixRound, maxFixRounds);
1028
+
1029
+ try {
1030
+ // Import fix dependencies lazily
1031
+ const { planMissions } = require("./lib/missions/plan");
1032
+ const { templateForMissionType } = require("./lib/missions/templates");
1033
+ const { expandEvidence } = require("./lib/missions/evidence");
1034
+ const { buildRealityFirewall } = require("./lib/firewall-prompt");
1035
+ const { generatePatchJson } = require("./lib/llm");
1036
+ const { applyUnifiedDiff } = require("./lib/patch");
1037
+ const { backupFiles, restoreBackup } = require("./lib/backup");
1038
+ const { validatePatchResponse } = require("./lib/validate-patch");
1039
+
1040
+ const findings = shipResult.report?.findings || [];
1041
+ const missions = planMissions(findings, { maxMissions, blocksOnlyFirst: true });
1042
+
1043
+ if (!missions.length) {
1044
+ console.log(` ${colors.warnAmber}${ICONS.warning}${c.reset} No fixable missions found`);
1045
+ timeline.push({ step: `4.${fixRound}`, action: "fix", status: "no_missions" });
1046
+ break;
1047
+ }
1048
+
1049
+ console.log(` ${c.dim}Planning ${missions.length} missions...${c.reset}`);
1050
+
1051
+ let fixedAny = false;
1052
+
1053
+ for (const mission of missions.slice(0, 3)) {
1054
+ printMissionStatus(mission, 'planning');
1055
+
1056
+ const targetFindings = findings.filter(f => mission.targetFindingIds.includes(f.id));
1057
+ const template = templateForMissionType(mission.type);
1058
+
1059
+ const expanded = await expandEvidence({
1060
+ repoRoot: root,
1061
+ truthpack: shipResult.truthpack,
1062
+ mission,
1063
+ targetFindings
1064
+ });
1065
+
1066
+ const prompt = buildRealityFirewall({
1067
+ truthpackSummary: {
1068
+ serverRoutes: shipResult.truthpack?.routes?.server?.length || 0,
1069
+ clientRefs: shipResult.truthpack?.routes?.clientRefs?.length || 0,
1070
+ envVars: shipResult.truthpack?.env?.vars?.length || 0
1071
+ },
1072
+ mission,
1073
+ template,
1074
+ findings: targetFindings,
1075
+ fileSnippets: expanded.snippets,
1076
+ allowedFiles: expanded.allowedFiles
1077
+ });
1078
+
1079
+ printMissionStatus(mission, 'applying');
1080
+
1081
+ try {
1082
+ const patchResponse = await generatePatchJson(prompt);
1083
+
1084
+ if (!patchResponse || patchResponse.status !== "ok" || !patchResponse.edits?.length) {
1085
+ printMissionStatus(mission, 'skipped', 'no patch generated');
1086
+ continue;
1087
+ }
1088
+
1089
+ const validation = validatePatchResponse(patchResponse, {
1090
+ allowedFiles: expanded.allowedFiles,
1091
+ beforeTruthpack: shipResult.truthpack
1092
+ });
1093
+
1094
+ if (!validation.valid) {
1095
+ printMissionStatus(mission, 'failed', `validation: ${validation.reason}`);
1096
+ continue;
1097
+ }
1098
+
1099
+ // Backup before applying
1100
+ const touchedFiles = patchResponse.edits.map(e => e.path).filter(Boolean);
1101
+ const backupRoot = path.join(outDir, `backup_${fixRound}_${mission.id}`);
1102
+ backupFiles(root, touchedFiles, backupRoot);
1103
+
1104
+ // Apply patches
1105
+ let appliedAny = false;
1106
+ for (const edit of patchResponse.edits) {
1107
+ if (!edit.diff || !edit.path) continue;
1108
+
1109
+ try {
1110
+ await applyUnifiedDiff(root, edit.diff);
1111
+ appliedAny = true;
1112
+ } catch (e) {
1113
+ // Patch failed
1114
+ }
1115
+ }
1116
+
1117
+ if (appliedAny) {
1118
+ fixedAny = true;
1119
+ printMissionStatus(mission, 'success', `${patchResponse.edits.length} edits`);
1120
+ } else {
1121
+ printMissionStatus(mission, 'failed', 'patch apply failed');
1122
+ }
1123
+ } catch (e) {
1124
+ printMissionStatus(mission, 'failed', `LLM error: ${truncate(e.message, 30)}`);
1125
+ }
1126
+ }
1127
+
1128
+ timeline.push({
1129
+ step: `4.${fixRound}`,
1130
+ action: "fix",
1131
+ status: fixedAny ? "applied" : "no_changes",
1132
+ missionsAttempted: Math.min(missions.length, 3)
1133
+ });
1134
+
1135
+ if (!fixedAny) {
1136
+ console.log(` ${colors.warnAmber}${ICONS.warning}${c.reset} No fixes applied this round`);
1137
+ break;
1138
+ }
1139
+
1140
+ // Re-run ship to check progress
1141
+ startSpinner('Re-checking ship verdict...', colors.step3);
1142
+ shipResult = await shipCore({ repoRoot: root, fastifyEntry, noWrite: false });
1143
+ stopSpinner('Ship check complete', true);
1144
+
1145
+ printStepResult(3, shipResult.verdict, {
1146
+ findings: shipResult.report?.findings?.length || 0
1147
+ });
1148
+
1149
+ } catch (err) {
1150
+ console.log(` ${colors.blockRed}${ICONS.cross}${c.reset} Fix error: ${err.message}`);
1151
+ timeline.push({ step: `4.${fixRound}`, action: "fix", status: "error", error: err.message });
1152
+ break;
1153
+ }
1154
+ }
1155
+
1156
+ if (fixRound > 0) {
1157
+ pipelineStatus[3] = shipResult.verdict === 'SHIP' ? 'complete' : 'error';
1158
+ } else if (skipFix) {
1159
+ pipelineStatus[3] = 'skipped';
1160
+ } else if (shipResult.verdict !== 'BLOCK') {
1161
+ pipelineStatus[3] = 'skipped';
1162
+ }
1163
+
1164
+ // ═══════════════════════════════════════════════════════════════════════════
1165
+ // STEP 5: FINAL VERIFICATION - Re-run reality + ship
1166
+ // ═══════════════════════════════════════════════════════════════════════════
1167
+ if (url && !skipReality && runReality && fixRound > 0) {
1168
+ printStepHeader(5);
1169
+ pipelineStatus[4] = 'running';
1170
+
1171
+ startSpinner('Running final verification with recording...', colors.step5);
1172
+
1173
+ try {
1174
+ await runReality({
1175
+ repoRoot: root,
1176
+ url,
1177
+ auth,
1178
+ storageState,
1179
+ verifyAuth: !!auth || !!storageState,
1180
+ headed,
1181
+ maxPages,
1182
+ maxDepth,
1183
+ danger,
1184
+ timeoutMs,
1185
+ // Recording for final proof
1186
+ recordVideo: !noVideo,
1187
+ recordTrace: !noTrace,
1188
+ recordHar: !noHar,
1189
+ stabilityRuns: 1 // Single run for verification
1190
+ });
1191
+
1192
+ shipResult = await shipCore({ repoRoot: root, fastifyEntry, noWrite: false });
1193
+
1194
+ stopSpinner('Final verification complete', true);
1195
+
1196
+ timeline.push({
1197
+ step: 5,
1198
+ action: "verify",
1199
+ verdict: shipResult.verdict,
1200
+ findingsCount: shipResult.report?.findings?.length || 0
1201
+ });
1202
+
1203
+ printStepResult(5, shipResult.verdict, {
1204
+ findings: shipResult.report?.findings?.length || 0
1205
+ });
1206
+
1207
+ pipelineStatus[4] = shipResult.verdict === 'SHIP' ? 'complete' : 'error';
1208
+ } catch (err) {
1209
+ stopSpinner(`Final verification failed: ${err.message}`, false);
1210
+ pipelineStatus[4] = 'error';
1211
+ }
1212
+ } else {
1213
+ pipelineStatus[4] = 'skipped';
1214
+ }
1215
+
1216
+ finalVerdict = shipResult.verdict;
1217
+
1218
+ // ═══════════════════════════════════════════════════════════════════════════
1219
+ // SUMMARY & HTML PROOF REPORT
1220
+ // ═══════════════════════════════════════════════════════════════════════════
1221
+ const duration = Date.now() - executionStart;
1222
+ const durationStr = formatDuration(duration);
1223
+
1224
+ // Load reality report for evidence
1225
+ let realityReport = null;
1226
+ const realityPath = path.join(root, ".vibecheck", "reality", "last_reality.json");
1227
+ try { realityReport = JSON.parse(fs.readFileSync(realityPath, "utf8")); } catch {}
1228
+
1229
+ const report = {
1230
+ meta: {
1231
+ startedAt: new Date(executionStart).toISOString(),
1232
+ finishedAt: new Date().toISOString(),
1233
+ durationMs: duration,
1234
+ url: url || null,
1235
+ fixRounds: fixRound,
1236
+ stabilityRuns: stabilityRuns,
1237
+ recordingEnabled: { video: !noVideo, trace: !noTrace, har: !noHar }
1238
+ },
1239
+ timeline,
1240
+ finalVerdict,
1241
+ finalFindings: shipResult.report?.findings?.length || 0,
1242
+ // Include reality evidence
1243
+ coverage: realityReport?.coverage || null,
1244
+ artifacts: realityReport?.artifacts || null,
1245
+ findings: realityReport?.findings || shipResult.report?.findings || []
1246
+ };
1247
+
1248
+ fs.writeFileSync(path.join(outDir, "prove_report.json"), JSON.stringify(report, null, 2), "utf8");
1249
+
1250
+ // Generate HTML proof report
1251
+ let htmlReportPath = null;
1252
+ try {
1253
+ const { generateHtmlProofReport } = require("./lib/html-proof-report");
1254
+ const htmlContent = generateHtmlProofReport({
1255
+ verdict: finalVerdict,
1256
+ projectName: projectName,
1257
+ url: url,
1258
+ startedAt: new Date(executionStart).toISOString(),
1259
+ finishedAt: new Date().toISOString(),
1260
+ durationMs: duration,
1261
+ findings: report.findings,
1262
+ coverage: report.coverage,
1263
+ passes: realityReport?.passes || {},
1264
+ artifacts: report.artifacts,
1265
+ meta: report.meta,
1266
+ stabilityRuns: stabilityRuns
1267
+ });
1268
+ htmlReportPath = path.join(outDir, "proof-report.html");
1269
+ fs.writeFileSync(htmlReportPath, htmlContent, "utf8");
1270
+ } catch (e) {
1271
+ // HTML report generation failed - non-fatal
1272
+ }
1273
+
1274
+ // Also save a stable pointer
1275
+ const latestPath = path.join(root, ".vibecheck", "prove", "last_prove.json");
1276
+ ensureDir(path.dirname(latestPath));
1277
+ fs.writeFileSync(latestPath, JSON.stringify(report, null, 2), "utf8");
1278
+
1279
+ // Save artifacts
1280
+ saveArtifact(runId, "prove-report", report);
1281
+ saveArtifact(runId, "timeline", timeline);
1282
+
1283
+ // Generate evidence pack if requested
1284
+ let evidencePackPath = null;
1285
+ if (evidencePack) {
1286
+ try {
1287
+ // Lazy load evidence pack module
1288
+ const evidencePackModule = require("../../packages/cli/src/evidence/evidence-pack");
1289
+ const { generateEvidencePack, generateHtmlViewer } = evidencePackModule.default || evidencePackModule;
1290
+
1291
+ if (!json && !ci) {
1292
+ console.log();
1293
+ console.log(` ${colors.accent}${ICONS.doc}${c.reset} Generating evidence pack...`);
1294
+ }
1295
+
1296
+ const result = await generateEvidencePack({
1297
+ projectPath: root,
1298
+ sourceReport: latestPath,
1299
+ sourceType: 'prove',
1300
+ includeVideos: !noVideo,
1301
+ includeTraces: !noTrace,
1302
+ includeHar: !noHar,
1303
+ includeScreenshots: true
1304
+ });
1305
+
1306
+ evidencePackPath = result.packPath;
1307
+
1308
+ // Generate HTML viewer
1309
+ const htmlViewerModule = require("../../packages/cli/src/evidence/html-viewer");
1310
+ const htmlViewer = htmlViewerModule.default || htmlViewerModule;
1311
+ await htmlViewer.generateHtmlViewer({
1312
+ packPath: evidencePackPath,
1313
+ embedMedia: false,
1314
+ title: `Evidence Pack - ${projectName}`
1315
+ });
1316
+
1317
+ if (!json && !ci) {
1318
+ console.log(` ${colors.success}${ICONS.check}${c.reset} Evidence pack generated: ${colors.accent}${path.relative(root, evidencePackPath)}${c.reset}`);
1319
+ }
1320
+ } catch (e) {
1321
+ if (!json && !ci) {
1322
+ console.log(` ${colors.warning}${ICONS.warning}${c.reset} Evidence pack generation failed: ${e.message}`);
1323
+ }
1324
+ }
1325
+ }
1326
+
1327
+ // JSON output mode
1328
+ if (json) {
1329
+ const output = createJsonOutput({
1330
+ runId,
1331
+ command: "prove",
1332
+ startTime: executionStart,
1333
+ exitCode: verdictToExitCode(finalVerdict),
1334
+ verdict: finalVerdict,
1335
+ result: {
1336
+ meta: report.meta,
1337
+ timeline,
1338
+ finalVerdict,
1339
+ fixRounds: fixRound,
1340
+ duration: duration
1341
+ },
1342
+ tier: "pro",
1343
+ version: require("../../package.json").version,
1344
+ artifacts: [
1345
+ {
1346
+ type: "report",
1347
+ path: path.join(outDir, "prove_report.json"),
1348
+ description: "Prove report with timeline"
1349
+ }
1350
+ ]
1351
+ });
1352
+
1353
+ writeJsonOutput(output, output);
1354
+ }
1355
+
1356
+ // Final verdict display (unless JSON or CI mode)
1357
+ if (!json && !ci) {
1358
+ // Use Mission Control format
1359
+ const { formatProveOutput } = require('./lib/prove-output');
1360
+ const steps = timeline.map(t => ({
1361
+ name: t.step || t.action || 'Step',
1362
+ success: t.status === 'success' || t.status === 'complete',
1363
+ error: t.status === 'error' ? t.error : null,
1364
+ }));
1365
+
1366
+ console.log(formatProveOutput({
1367
+ verdict: finalVerdict,
1368
+ finalVerdict,
1369
+ steps,
1370
+ runtimeTests: report.tests?.length || 0,
1371
+ runtimePassed: report.tests?.filter(t => t.passed).length || 0,
1372
+ duration,
1373
+ success: finalVerdict === 'SHIP',
1374
+ }, { version: 'v3.5.5' }));
1375
+
1376
+ // Show artifacts if available
1377
+ if (htmlReportPath) {
1378
+ console.log(`\n ${colors.shipGreen}${ICONS.sparkle}${c.reset} ${c.bold}HTML Proof Report:${c.reset} ${colors.accent}${path.relative(root, htmlReportPath)}${c.reset}`);
1379
+ }
1380
+ } else if (ci) {
1381
+ // CI mode - structured output for easy parsing
1382
+ console.log(`::group::vibecheck prove summary`);
1383
+ console.log(`VERDICT=${finalVerdict}`);
1384
+ console.log(`DURATION=${duration}ms`);
1385
+ console.log(`FIX_ROUNDS=${fixRound}`);
1386
+ console.log(`BLOCKERS=${report.findings.filter(f => f.severity === 'BLOCK').length}`);
1387
+ console.log(`WARNINGS=${report.findings.filter(f => f.severity === 'WARN').length}`);
1388
+ console.log(`COVERAGE=${report.coverage?.percent || 0}%`);
1389
+ if (htmlReportPath) {
1390
+ console.log(`HTML_REPORT=${path.relative(root, htmlReportPath)}`);
1391
+ }
1392
+ console.log(`JSON_REPORT=${path.relative(root, path.join(outDir, 'prove_report.json'))}`);
1393
+ if (evidencePackPath) {
1394
+ console.log(`EVIDENCE_PACK=${path.relative(root, evidencePackPath)}`);
1395
+ }
1396
+ console.log(`::endgroup::`);
1397
+
1398
+ // GitHub Actions annotations
1399
+ if (finalVerdict === 'BLOCK') {
1400
+ console.log(`::error title=Reality Check Failed::${report.findings.filter(f => f.severity === 'BLOCK').length} blockers found`);
1401
+ } else if (finalVerdict === 'WARN') {
1402
+ console.log(`::warning title=Reality Check Passed with Warnings::${report.findings.filter(f => f.severity === 'WARN').length} warnings found`);
1403
+ } else {
1404
+ console.log(`::notice title=Reality Check Passed::App verified with video + network evidence`);
1405
+ }
1406
+ }
1407
+
1408
+ return verdictToExitCode(finalVerdict);
1409
+ }
1410
+
1411
+ module.exports = { runProve };