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,1927 @@
1
+ /**
2
+ * vibecheck init - Enterprise Project Setup
3
+ *
4
+ * ═══════════════════════════════════════════════════════════════════════════════
5
+ * ENTERPRISE EDITION - World-Class Terminal Experience
6
+ * ═══════════════════════════════════════════════════════════════════════════════
7
+ *
8
+ * Configure your project for production-grade verification.
9
+ * Interactive wizard or quick setup for any project type.
10
+ */
11
+
12
+ const fs = require("fs");
13
+ const path = require("path");
14
+ const { parseGlobalFlags, shouldShowBanner } = require("./lib/global-flags");
15
+ const { EXIT } = require("./lib/exit-codes");
16
+
17
+ // Use enhanced wizard if available
18
+ let InitWizard;
19
+ try {
20
+ InitWizard = require("./lib/init-wizard").InitWizard;
21
+ } catch {
22
+ InitWizard = null;
23
+ }
24
+
25
+ // Enterprise init
26
+ let EnterpriseInit;
27
+ try {
28
+ EnterpriseInit = require("./lib/enterprise-init").EnterpriseInit;
29
+ } catch {
30
+ EnterpriseInit = null;
31
+ }
32
+
33
+ // ═══════════════════════════════════════════════════════════════════════════════
34
+ // ADVANCED TERMINAL - ANSI CODES & UTILITIES
35
+ // ═══════════════════════════════════════════════════════════════════════════════
36
+
37
+ const c = {
38
+ reset: '\x1b[0m',
39
+ bold: '\x1b[1m',
40
+ dim: '\x1b[2m',
41
+ italic: '\x1b[3m',
42
+ underline: '\x1b[4m',
43
+ blink: '\x1b[5m',
44
+ inverse: '\x1b[7m',
45
+ hidden: '\x1b[8m',
46
+ strike: '\x1b[9m',
47
+ // Colors
48
+ black: '\x1b[30m',
49
+ red: '\x1b[31m',
50
+ green: '\x1b[32m',
51
+ yellow: '\x1b[33m',
52
+ blue: '\x1b[34m',
53
+ magenta: '\x1b[35m',
54
+ cyan: '\x1b[36m',
55
+ white: '\x1b[37m',
56
+ // Bright colors
57
+ gray: '\x1b[90m',
58
+ brightRed: '\x1b[91m',
59
+ brightGreen: '\x1b[92m',
60
+ brightYellow: '\x1b[93m',
61
+ brightBlue: '\x1b[94m',
62
+ brightMagenta: '\x1b[95m',
63
+ brightCyan: '\x1b[96m',
64
+ brightWhite: '\x1b[97m',
65
+ // Background
66
+ bgBlack: '\x1b[40m',
67
+ bgRed: '\x1b[41m',
68
+ bgGreen: '\x1b[42m',
69
+ bgYellow: '\x1b[43m',
70
+ bgBlue: '\x1b[44m',
71
+ bgMagenta: '\x1b[45m',
72
+ bgCyan: '\x1b[46m',
73
+ bgWhite: '\x1b[47m',
74
+ // Cursor control
75
+ cursorUp: (n = 1) => `\x1b[${n}A`,
76
+ cursorDown: (n = 1) => `\x1b[${n}B`,
77
+ cursorRight: (n = 1) => `\x1b[${n}C`,
78
+ cursorLeft: (n = 1) => `\x1b[${n}D`,
79
+ clearLine: '\x1b[2K',
80
+ clearScreen: '\x1b[2J',
81
+ saveCursor: '\x1b[s',
82
+ restoreCursor: '\x1b[u',
83
+ hideCursor: '\x1b[?25l',
84
+ showCursor: '\x1b[?25h',
85
+ };
86
+
87
+ // True color support
88
+ const rgb = (r, g, b) => `\x1b[38;2;${r};${g};${b}m`;
89
+ const bgRgb = (r, g, b) => `\x1b[48;2;${r};${g};${b}m`;
90
+
91
+ // Premium color palette (gold/amber theme for "init/setup")
92
+ const colors = {
93
+ // Gradient for banner
94
+ gradient1: rgb(255, 215, 100), // Gold
95
+ gradient2: rgb(255, 200, 80), // Light gold
96
+ gradient3: rgb(255, 180, 60), // Amber
97
+ gradient4: rgb(255, 160, 40), // Deep amber
98
+ gradient5: rgb(255, 140, 20), // Orange-amber
99
+ gradient6: rgb(255, 120, 0), // Deep orange
100
+
101
+ // Category colors
102
+ framework: rgb(100, 200, 255), // Blue
103
+ database: rgb(200, 150, 255), // Purple
104
+ auth: rgb(100, 255, 180), // Green
105
+ payment: rgb(255, 200, 100), // Gold
106
+ ci: rgb(255, 150, 100), // Coral
107
+ deploy: rgb(150, 200, 255), // Light blue
108
+ testing: rgb(200, 255, 150), // Lime
109
+
110
+ // Status colors
111
+ success: rgb(0, 255, 150),
112
+ warning: rgb(255, 200, 0),
113
+ error: rgb(255, 80, 80),
114
+ info: rgb(100, 200, 255),
115
+
116
+ // UI colors
117
+ accent: rgb(255, 200, 100),
118
+ muted: rgb(140, 130, 100),
119
+ subtle: rgb(100, 90, 70),
120
+ highlight: rgb(255, 255, 255),
121
+
122
+ // Enterprise
123
+ enterprise: rgb(200, 150, 255),
124
+ compliance: rgb(100, 200, 150),
125
+ team: rgb(150, 180, 255),
126
+ };
127
+
128
+ // ═══════════════════════════════════════════════════════════════════════════════
129
+ // PREMIUM BANNER
130
+ // ═══════════════════════════════════════════════════════════════════════════════
131
+
132
+ const INIT_BANNER = `
133
+ ${rgb(255, 220, 120)} ██╗███╗ ██╗██╗████████╗${c.reset}
134
+ ${rgb(255, 200, 100)} ██║████╗ ██║██║╚══██╔══╝${c.reset}
135
+ ${rgb(255, 180, 80)} ██║██╔██╗ ██║██║ ██║ ${c.reset}
136
+ ${rgb(255, 160, 60)} ██║██║╚██╗██║██║ ██║ ${c.reset}
137
+ ${rgb(255, 140, 40)} ██║██║ ╚████║██║ ██║ ${c.reset}
138
+ ${rgb(255, 120, 20)} ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ ${c.reset}
139
+ `;
140
+
141
+ const BANNER_FULL = `
142
+ ${rgb(255, 220, 120)} ██╗ ██╗██╗██████╗ ███████╗ ██████╗██╗ ██╗███████╗ ██████╗██╗ ██╗${c.reset}
143
+ ${rgb(255, 200, 100)} ██║ ██║██║██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔════╝██║ ██╔╝${c.reset}
144
+ ${rgb(255, 180, 80)} ██║ ██║██║██████╔╝█████╗ ██║ ███████║█████╗ ██║ █████╔╝ ${c.reset}
145
+ ${rgb(255, 160, 60)} ╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██║ ██╔══██║██╔══╝ ██║ ██╔═██╗ ${c.reset}
146
+ ${rgb(255, 140, 40)} ╚████╔╝ ██║██████╔╝███████╗╚██████╗██║ ██║███████╗╚██████╗██║ ██╗${c.reset}
147
+ ${rgb(255, 120, 20)} ╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝${c.reset}
148
+
149
+ ${c.dim} ┌─────────────────────────────────────────────────────────────────────┐${c.reset}
150
+ ${c.dim} │${c.reset} ${rgb(255, 200, 100)}⚡${c.reset} ${c.bold}INIT${c.reset} ${c.dim}•${c.reset} ${rgb(200, 200, 200)}Project Setup${c.reset} ${c.dim}•${c.reset} ${rgb(150, 150, 150)}Enterprise Ready${c.reset} ${c.dim}│${c.reset}
151
+ ${c.dim} └─────────────────────────────────────────────────────────────────────┘${c.reset}
152
+ `;
153
+
154
+ // ═══════════════════════════════════════════════════════════════════════════════
155
+ // ICONS & SYMBOLS
156
+ // ═══════════════════════════════════════════════════════════════════════════════
157
+
158
+ const ICONS = {
159
+ // Main
160
+ init: '⚡',
161
+ setup: '🔧',
162
+ config: '⚙️',
163
+ wizard: '🧙',
164
+
165
+ // Status
166
+ check: '✓',
167
+ cross: '✗',
168
+ warning: '⚠',
169
+ info: 'ℹ',
170
+ arrow: '→',
171
+ bullet: '•',
172
+
173
+ // Categories
174
+ framework: '🏗️',
175
+ database: '🗄️',
176
+ auth: '🔐',
177
+ payment: '💳',
178
+ ci: '🔄',
179
+ deploy: '🚀',
180
+ testing: '🧪',
181
+
182
+ // Actions
183
+ create: '📝',
184
+ update: '✏️',
185
+ skip: '⏭️',
186
+ detect: '🔍',
187
+ repair: '🔧',
188
+ tool: '🛠️',
189
+
190
+ // Objects
191
+ file: '📄',
192
+ folder: '📁',
193
+ git: '🌿',
194
+ lock: '🔒',
195
+ shield: '🛡️',
196
+ team: '👥',
197
+ clock: '⏱',
198
+ lightning: '⚡',
199
+ sparkle: '✨',
200
+ star: '★',
201
+
202
+ // Enterprise
203
+ enterprise: '🏢',
204
+ compliance: '📋',
205
+ mcp: '🤖',
206
+ };
207
+
208
+ // ═══════════════════════════════════════════════════════════════════════════════
209
+ // BOX DRAWING
210
+ // ═══════════════════════════════════════════════════════════════════════════════
211
+
212
+ const BOX = {
213
+ topLeft: '╭', topRight: '╮', bottomLeft: '╰', bottomRight: '╯',
214
+ horizontal: '─', vertical: '│',
215
+ teeRight: '├', teeLeft: '┤', teeDown: '┬', teeUp: '┴',
216
+ cross: '┼',
217
+ // Double line
218
+ dTopLeft: '╔', dTopRight: '╗', dBottomLeft: '╚', dBottomRight: '╝',
219
+ dHorizontal: '═', dVertical: '║',
220
+ // Heavy
221
+ hTopLeft: '┏', hTopRight: '┓', hBottomLeft: '┗', hBottomRight: '┛',
222
+ hHorizontal: '━', hVertical: '┃',
223
+ };
224
+
225
+ // ═══════════════════════════════════════════════════════════════════════════════
226
+ // SPINNER & PROGRESS
227
+ // ═══════════════════════════════════════════════════════════════════════════════
228
+
229
+ const SPINNER_DOTS = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];
230
+ const SPINNER_SETUP = ['⚡', '✨', '⚡', '✨'];
231
+
232
+ let spinnerIndex = 0;
233
+ let spinnerInterval = null;
234
+ let spinnerStartTime = null;
235
+
236
+ function formatDuration(ms) {
237
+ if (ms < 1000) return `${ms}ms`;
238
+ if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
239
+ const mins = Math.floor(ms / 60000);
240
+ const secs = Math.floor((ms % 60000) / 1000);
241
+ return `${mins}m ${secs}s`;
242
+ }
243
+
244
+ function truncate(str, len) {
245
+ if (!str) return '';
246
+ if (str.length <= len) return str;
247
+ return str.slice(0, len - 3) + '...';
248
+ }
249
+
250
+ function padCenter(str, width) {
251
+ const padding = Math.max(0, width - str.length);
252
+ const left = Math.floor(padding / 2);
253
+ const right = padding - left;
254
+ return ' '.repeat(left) + str + ' '.repeat(right);
255
+ }
256
+
257
+ function startSpinner(message, color = colors.accent) {
258
+ spinnerStartTime = Date.now();
259
+ process.stdout.write(c.hideCursor);
260
+
261
+ spinnerInterval = setInterval(() => {
262
+ const elapsed = formatDuration(Date.now() - spinnerStartTime);
263
+ process.stdout.write(`\r${c.clearLine} ${color}${SPINNER_DOTS[spinnerIndex]}${c.reset} ${message} ${c.dim}${elapsed}${c.reset}`);
264
+ spinnerIndex = (spinnerIndex + 1) % SPINNER_DOTS.length;
265
+ }, 80);
266
+ }
267
+
268
+ function stopSpinner(message, success = true) {
269
+ if (spinnerInterval) {
270
+ clearInterval(spinnerInterval);
271
+ spinnerInterval = null;
272
+ }
273
+ const elapsed = spinnerStartTime ? formatDuration(Date.now() - spinnerStartTime) : '';
274
+ const icon = success ? `${colors.success}${ICONS.check}${c.reset}` : `${colors.error}${ICONS.cross}${c.reset}`;
275
+ process.stdout.write(`\r${c.clearLine} ${icon} ${message} ${c.dim}${elapsed}${c.reset}\n`);
276
+ process.stdout.write(c.showCursor);
277
+ spinnerStartTime = null;
278
+ }
279
+
280
+ // ═══════════════════════════════════════════════════════════════════════════════
281
+ // SECTION HEADERS
282
+ // ═══════════════════════════════════════════════════════════════════════════════
283
+
284
+ function printBanner() {
285
+ console.log(BANNER_FULL);
286
+ }
287
+
288
+ function printCompactBanner() {
289
+ console.log(INIT_BANNER);
290
+ }
291
+
292
+ function printDivider(char = '─', width = 69, color = c.dim) {
293
+ console.log(`${color} ${char.repeat(width)}${c.reset}`);
294
+ }
295
+
296
+ function printSection(title, icon = '◆') {
297
+ console.log();
298
+ console.log(` ${colors.accent}${icon}${c.reset} ${c.bold}${title}${c.reset}`);
299
+ printDivider();
300
+ }
301
+
302
+ // ═══════════════════════════════════════════════════════════════════════════════
303
+ // FRAMEWORK-SPECIFIC CONFIGURATION
304
+ // ═══════════════════════════════════════════════════════════════════════════════
305
+
306
+ function getFrameworkConfig(detection) {
307
+ if (!detection || !detection.frameworks) {
308
+ return {
309
+ framework: "node",
310
+ checks: ["routes", "env", "auth", "security"],
311
+ ignorePaths: [],
312
+ extra: {},
313
+ };
314
+ }
315
+
316
+ // Find the primary detected framework
317
+ const detectedFrameworks = Object.entries(detection.frameworks)
318
+ .filter(([key, fw]) => fw.detected)
319
+ .map(([key, fw]) => ({ key, ...fw }));
320
+
321
+ if (detectedFrameworks.length === 0) {
322
+ return {
323
+ framework: "node",
324
+ checks: ["routes", "env", "auth", "security"],
325
+ ignorePaths: [],
326
+ extra: {},
327
+ };
328
+ }
329
+
330
+ // Use the first detected framework (usually the most specific)
331
+ const primary = detectedFrameworks[0];
332
+ const frameworkKey = primary.key;
333
+
334
+ // Framework-specific configurations
335
+ const frameworkConfigs = {
336
+ nextjs: {
337
+ framework: "nextjs",
338
+ checks: ["routes", "auth", "api", "security", "ssr"],
339
+ ignorePaths: [".next/", "out/", ".vercel/"],
340
+ extra: {},
341
+ },
342
+ remix: {
343
+ framework: "remix",
344
+ checks: ["routes", "auth", "api", "security", "loaders"],
345
+ ignorePaths: [".remix/", "build/"],
346
+ extra: {},
347
+ },
348
+ nuxt: {
349
+ framework: "nuxt",
350
+ checks: ["routes", "auth", "api", "security"],
351
+ ignorePaths: [".nuxt/", ".output/"],
352
+ extra: {},
353
+ },
354
+ sveltekit: {
355
+ framework: "sveltekit",
356
+ checks: ["routes", "auth", "api", "security"],
357
+ ignorePaths: [".svelte-kit/", "build/"],
358
+ extra: {},
359
+ },
360
+ react: {
361
+ framework: "react",
362
+ checks: ["components", "api", "security"],
363
+ ignorePaths: ["build/", "dist/"],
364
+ extra: {},
365
+ },
366
+ vue: {
367
+ framework: "vue",
368
+ checks: ["components", "api", "security"],
369
+ ignorePaths: ["dist/"],
370
+ extra: {},
371
+ },
372
+ fastify: {
373
+ framework: "fastify",
374
+ checks: ["routes", "auth", "api", "security"],
375
+ ignorePaths: [],
376
+ extra: {
377
+ fastify: {
378
+ plugins: detection.frameworks?.fastify?.plugins || [],
379
+ },
380
+ },
381
+ },
382
+ express: {
383
+ framework: "express",
384
+ checks: ["routes", "auth", "api", "security"],
385
+ ignorePaths: [],
386
+ extra: {},
387
+ },
388
+ nestjs: {
389
+ framework: "nestjs",
390
+ checks: ["routes", "auth", "api", "security", "modules"],
391
+ ignorePaths: ["dist/"],
392
+ extra: {},
393
+ },
394
+ };
395
+
396
+ // Get framework-specific config or use detected checks
397
+ const config = frameworkConfigs[frameworkKey] || {
398
+ framework: frameworkKey,
399
+ checks: primary.checks || ["routes", "env", "auth", "security"],
400
+ ignorePaths: [],
401
+ extra: {},
402
+ };
403
+
404
+ // Merge detected checks if available
405
+ if (primary.checks && primary.checks.length > 0) {
406
+ config.checks = [...new Set([...config.checks, ...primary.checks])];
407
+ }
408
+
409
+ return config;
410
+ }
411
+
412
+ // ═══════════════════════════════════════════════════════════════════════════════
413
+ // INIT STATE TRACKING
414
+ // ═══════════════════════════════════════════════════════════════════════════════
415
+
416
+ function saveInitState(targetDir, state) {
417
+ try {
418
+ const statePath = path.join(targetDir, ".vibecheck", ".init-state.json");
419
+ fs.writeFileSync(statePath, JSON.stringify(state, null, 2));
420
+ } catch (e) {
421
+ // Non-critical - state tracking is optional
422
+ if (process.env.VIBECHECK_DEBUG) {
423
+ console.error(`Failed to save init state: ${e.message}`);
424
+ }
425
+ }
426
+ }
427
+
428
+ function loadInitState(targetDir) {
429
+ try {
430
+ const statePath = path.join(targetDir, ".vibecheck", ".init-state.json");
431
+ if (fs.existsSync(statePath)) {
432
+ return JSON.parse(fs.readFileSync(statePath, "utf-8"));
433
+ }
434
+ } catch (e) {
435
+ // Non-critical
436
+ }
437
+ return null;
438
+ }
439
+
440
+ // ═══════════════════════════════════════════════════════════════════════════════
441
+ // POST-INIT VALIDATION
442
+ // ═══════════════════════════════════════════════════════════════════════════════
443
+
444
+ async function verifyInitSetup(targetDir, opts) {
445
+ const issues = [];
446
+ const vibecheckDir = path.join(targetDir, ".vibecheck");
447
+
448
+ // Check directory structure
449
+ const requiredDirs = [
450
+ vibecheckDir,
451
+ path.join(vibecheckDir, "results"),
452
+ path.join(vibecheckDir, "contracts"),
453
+ ];
454
+
455
+ for (const dir of requiredDirs) {
456
+ if (!fs.existsSync(dir)) {
457
+ issues.push(`Missing directory: ${path.relative(targetDir, dir)}`);
458
+ }
459
+ }
460
+
461
+ // Check config.json
462
+ const configPath = path.join(vibecheckDir, "config.json");
463
+ if (!fs.existsSync(configPath)) {
464
+ issues.push("Missing: .vibecheck/config.json");
465
+ } else {
466
+ try {
467
+ const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
468
+ if (!config.version || !config.checks) {
469
+ issues.push("Invalid config.json structure");
470
+ }
471
+ } catch (e) {
472
+ issues.push(`Invalid config.json: ${e.message}`);
473
+ }
474
+ }
475
+
476
+ // Check truthpack
477
+ const truthpackPath = path.join(vibecheckDir, "truthpack.json");
478
+ if (!fs.existsSync(truthpackPath)) {
479
+ issues.push("Missing: .vibecheck/truthpack.json (run 'vibecheck ctx build')");
480
+ } else {
481
+ try {
482
+ const truthpack = JSON.parse(fs.readFileSync(truthpackPath, "utf-8"));
483
+ if (!truthpack.version || !truthpack.generatedAt) {
484
+ issues.push("Invalid truthpack.json structure");
485
+ }
486
+ } catch (e) {
487
+ issues.push(`Invalid truthpack.json: ${e.message}`);
488
+ }
489
+ }
490
+
491
+ // Check contracts
492
+ const contractsDir = path.join(vibecheckDir, "contracts");
493
+ const requiredContracts = ["routes.contract.json", "env.contract.json"];
494
+ for (const contract of requiredContracts) {
495
+ const contractPath = path.join(contractsDir, contract);
496
+ if (!fs.existsSync(contractPath)) {
497
+ issues.push(`Missing contract: ${contract}`);
498
+ }
499
+ }
500
+
501
+ if (issues.length === 0 && !opts.json) {
502
+ console.log();
503
+ console.log(` ${colors.success}${ICONS.check}${c.reset} ${c.bold}Setup Verification:${c.reset} All checks passed`);
504
+ }
505
+
506
+ return {
507
+ success: issues.length === 0,
508
+ issues,
509
+ };
510
+ }
511
+
512
+ // ═══════════════════════════════════════════════════════════════════════════════
513
+ // FRAMEWORK-SPECIFIC RECOMMENDATIONS
514
+ // ═══════════════════════════════════════════════════════════════════════════════
515
+
516
+ function printFrameworkRecommendations(detection, opts) {
517
+ const frameworks = Object.keys(detection.frameworks || {}).filter(k => detection.frameworks[k].detected);
518
+ if (frameworks.length === 0) return;
519
+
520
+ const primaryFramework = frameworks[0];
521
+ const framework = detection.frameworks[primaryFramework];
522
+
523
+ const recommendations = [];
524
+
525
+ // Next.js specific
526
+ if (primaryFramework === 'nextjs') {
527
+ recommendations.push({
528
+ icon: ICONS.framework,
529
+ title: "Next.js Route Verification",
530
+ command: "vibecheck scan --routes",
531
+ description: "Verify all Next.js routes are properly configured",
532
+ });
533
+ if (!opts.connect) {
534
+ recommendations.push({
535
+ icon: ICONS.ci,
536
+ title: "Add Vercel Integration",
537
+ command: "vibecheck init --connect",
538
+ description: "Enable GitHub Actions for automatic PR checks",
539
+ });
540
+ }
541
+ }
542
+
543
+ // Fastify specific
544
+ if (primaryFramework === 'fastify') {
545
+ recommendations.push({
546
+ icon: ICONS.framework,
547
+ title: "Fastify Route Extraction",
548
+ command: "vibecheck scan --routes",
549
+ description: "Extract and verify all Fastify routes",
550
+ });
551
+ }
552
+
553
+ // Express specific
554
+ if (primaryFramework === 'express') {
555
+ recommendations.push({
556
+ icon: ICONS.framework,
557
+ title: "Express Route Analysis",
558
+ command: "vibecheck scan --routes",
559
+ description: "Analyze Express route definitions",
560
+ });
561
+ }
562
+
563
+ // Auth providers
564
+ const authProviders = Object.keys(detection.auth || {}).filter(k => detection.auth[k].detected);
565
+ if (authProviders.length > 0) {
566
+ recommendations.push({
567
+ icon: ICONS.auth,
568
+ title: "Auth Coverage Check",
569
+ command: "vibecheck scan --auth",
570
+ description: "Verify authentication coverage across routes",
571
+ });
572
+ }
573
+
574
+ // Payment providers
575
+ const paymentProviders = Object.keys(detection.payments || {}).filter(k => detection.payments[k].detected);
576
+ if (paymentProviders.length > 0) {
577
+ recommendations.push({
578
+ icon: ICONS.payment,
579
+ title: "Payment Flow Verification",
580
+ command: "vibecheck scan --billing",
581
+ description: "Verify payment webhook handlers and idempotency",
582
+ });
583
+ }
584
+
585
+ if (recommendations.length > 0) {
586
+ console.log();
587
+ printSection('RECOMMENDATIONS', ICONS.sparkle);
588
+ console.log();
589
+ for (const rec of recommendations) {
590
+ console.log(` ${rec.icon} ${c.bold}${rec.title}${c.reset}`);
591
+ console.log(` ${c.dim}${rec.description}${c.reset}`);
592
+ console.log(` ${c.cyan}${rec.command}${c.reset}`);
593
+ console.log();
594
+ }
595
+ }
596
+ }
597
+
598
+ // ═══════════════════════════════════════════════════════════════════════════════
599
+ // REPAIR MODE - Fix partial init state
600
+ // ═══════════════════════════════════════════════════════════════════════════════
601
+
602
+ async function runRepairMode(targetDir, projectName, opts) {
603
+ printSection('REPAIR MODE', ICONS.repair);
604
+ console.log();
605
+ console.log(` ${colors.info}${ICONS.info}${c.reset} Scanning for partial initialization state...`);
606
+ console.log();
607
+
608
+ // Load previous init state if available
609
+ const previousState = loadInitState(targetDir);
610
+ if (previousState && !opts.json) {
611
+ console.log(` ${c.dim}Previous init: ${previousState.timestamp} (${previousState.mode} mode)${c.reset}`);
612
+ if (previousState.errors && previousState.errors.length > 0) {
613
+ console.log(` ${colors.warning}${ICONS.warning}${c.reset} ${previousState.errors.length} error(s) from previous attempt`);
614
+ }
615
+ console.log();
616
+ }
617
+
618
+ const vibecheckDir = path.join(targetDir, ".vibecheck");
619
+ const issues = [];
620
+ const fixes = [];
621
+
622
+ // Check for missing directories
623
+ const requiredDirs = [
624
+ vibecheckDir,
625
+ path.join(vibecheckDir, "results"),
626
+ path.join(vibecheckDir, "reports"),
627
+ path.join(vibecheckDir, "contracts"),
628
+ path.join(vibecheckDir, "missions"),
629
+ path.join(vibecheckDir, "checkpoints"),
630
+ path.join(vibecheckDir, "runs"),
631
+ ];
632
+
633
+ for (const dir of requiredDirs) {
634
+ if (!fs.existsSync(dir)) {
635
+ issues.push(`Missing directory: ${path.relative(targetDir, dir)}`);
636
+ if (!opts.dryRun) {
637
+ fs.mkdirSync(dir, { recursive: true });
638
+ fixes.push(`Created: ${path.relative(targetDir, dir)}`);
639
+ } else {
640
+ fixes.push(`Would create: ${path.relative(targetDir, dir)}`);
641
+ }
642
+ }
643
+ }
644
+
645
+ // Check for missing config.json
646
+ const configPath = path.join(vibecheckDir, "config.json");
647
+ if (!fs.existsSync(configPath)) {
648
+ issues.push("Missing: .vibecheck/config.json");
649
+ if (!opts.dryRun) {
650
+ try {
651
+ const { detectAll } = require("./lib/enterprise-detect");
652
+ const detection = detectAll(targetDir);
653
+ const frameworkConfig = getFrameworkConfig(detection);
654
+ const config = {
655
+ version: "2.0.0",
656
+ project: projectName,
657
+ createdAt: new Date().toISOString(),
658
+ framework: frameworkConfig.framework || "node",
659
+ checks: frameworkConfig.checks || ["routes", "env", "auth", "security"],
660
+ output: ".vibecheck",
661
+ policy: {
662
+ allowlist: { domains: [], packages: [] },
663
+ ignore: {
664
+ paths: [
665
+ "node_modules",
666
+ "__tests__",
667
+ "*.test.*",
668
+ "*.spec.*",
669
+ ...(frameworkConfig.ignorePaths || []),
670
+ ],
671
+ },
672
+ },
673
+ thresholds: {
674
+ minScore: 70,
675
+ maxBlockers: 0,
676
+ maxWarnings: 10,
677
+ },
678
+ ...(frameworkConfig.extra || {}),
679
+ };
680
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
681
+ fixes.push("Created: .vibecheck/config.json");
682
+ } catch (e) {
683
+ issues.push(`Failed to create config.json: ${e.message}`);
684
+ }
685
+ } else {
686
+ fixes.push("Would create: .vibecheck/config.json");
687
+ }
688
+ }
689
+
690
+ // Check for missing truthpack
691
+ const truthpackPath = path.join(vibecheckDir, "truthpack.json");
692
+ if (!fs.existsSync(truthpackPath)) {
693
+ issues.push("Missing: .vibecheck/truthpack.json");
694
+ if (!opts.dryRun) {
695
+ startSpinner('Generating truthpack...', colors.accent);
696
+ try {
697
+ const { runContext } = require("./runContext");
698
+ await runContext(["--path", targetDir, "--quiet"]);
699
+ stopSpinner('Truthpack generated', true);
700
+ fixes.push("Generated: .vibecheck/truthpack.json");
701
+ } catch (e) {
702
+ stopSpinner('Truthpack generation failed', false);
703
+ issues.push(`Failed to generate truthpack: ${e.message}`);
704
+ }
705
+ } else {
706
+ fixes.push("Would generate: .vibecheck/truthpack.json");
707
+ }
708
+ }
709
+
710
+ // Check for missing contracts
711
+ const contractsDir = path.join(vibecheckDir, "contracts");
712
+ const routeContractPath = path.join(contractsDir, "routes.contract.json");
713
+ const envContractPath = path.join(contractsDir, "env.contract.json");
714
+
715
+ if (!fs.existsSync(routeContractPath)) {
716
+ issues.push("Missing: .vibecheck/contracts/routes.contract.json");
717
+ if (!opts.dryRun) {
718
+ const routeContract = {
719
+ version: "1.0.0",
720
+ generatedAt: new Date().toISOString(),
721
+ routes: [],
722
+ description: "Route contract - populated by scan",
723
+ };
724
+ fs.writeFileSync(routeContractPath, JSON.stringify(routeContract, null, 2));
725
+ fixes.push("Created: .vibecheck/contracts/routes.contract.json");
726
+ } else {
727
+ fixes.push("Would create: .vibecheck/contracts/routes.contract.json");
728
+ }
729
+ }
730
+
731
+ if (!fs.existsSync(envContractPath)) {
732
+ issues.push("Missing: .vibecheck/contracts/env.contract.json");
733
+ if (!opts.dryRun) {
734
+ const envContract = {
735
+ version: "1.0.0",
736
+ generatedAt: new Date().toISOString(),
737
+ required: [],
738
+ optional: [],
739
+ description: "Environment contract - populated by scan",
740
+ };
741
+ fs.writeFileSync(envContractPath, JSON.stringify(envContract, null, 2));
742
+ fixes.push("Created: .vibecheck/contracts/env.contract.json");
743
+ } else {
744
+ fixes.push("Would create: .vibecheck/contracts/env.contract.json");
745
+ }
746
+ }
747
+
748
+ // Use previous state to prioritize fixes
749
+ if (previousState && previousState.errors && previousState.errors.length > 0) {
750
+ const previousErrors = previousState.errors.map(e => e.step);
751
+ // Prioritize fixing errors from previous attempt
752
+ const prioritizedIssues = [];
753
+ const otherIssues = [];
754
+
755
+ for (const issue of issues) {
756
+ const isPreviousError = previousErrors.some(step => issue.toLowerCase().includes(step));
757
+ if (isPreviousError) {
758
+ prioritizedIssues.push(issue);
759
+ } else {
760
+ otherIssues.push(issue);
761
+ }
762
+ }
763
+
764
+ issues.length = 0;
765
+ issues.push(...prioritizedIssues, ...otherIssues);
766
+ }
767
+
768
+ // Summary
769
+ console.log();
770
+ if (issues.length === 0) {
771
+ console.log(` ${colors.success}${ICONS.check}${c.reset} No issues found - initialization is complete`);
772
+ // Clear previous state on successful repair
773
+ if (!opts.dryRun) {
774
+ const statePath = path.join(targetDir, ".vibecheck", ".init-state.json");
775
+ if (fs.existsSync(statePath)) {
776
+ fs.unlinkSync(statePath);
777
+ }
778
+ }
779
+ return 0;
780
+ }
781
+
782
+ console.log(` ${colors.warning}${ICONS.warning}${c.reset} Found ${issues.length} issue(s)`);
783
+ if (previousState && previousState.errors && previousState.errors.length > 0) {
784
+ console.log(` ${c.dim}(${previousState.errors.length} from previous attempt)${c.reset}`);
785
+ }
786
+ console.log();
787
+ for (const issue of issues) {
788
+ console.log(` ${c.dim}•${c.reset} ${issue}`);
789
+ }
790
+
791
+ if (fixes.length > 0) {
792
+ console.log();
793
+ console.log(` ${colors.success}${ICONS.check}${c.reset} Applied ${fixes.length} fix(es)`);
794
+ for (const fix of fixes) {
795
+ console.log(` ${c.dim}•${c.reset} ${fix}`);
796
+ }
797
+ }
798
+
799
+ console.log();
800
+ return issues.length > 0 ? (opts.dryRun ? 0 : 1) : 0;
801
+ }
802
+
803
+ // ═══════════════════════════════════════════════════════════════════════════════
804
+ // ENHANCED DETECTION DISPLAY
805
+ // ═══════════════════════════════════════════════════════════════════════════════
806
+
807
+ function printEnhancedDetection(detection, verbose = false) {
808
+ const frameworks = Object.keys(detection.frameworks || {}).filter(k => detection.frameworks[k].detected);
809
+ const databases = Object.keys(detection.databases || {}).filter(k => detection.databases[k].detected);
810
+ const authProviders = Object.keys(detection.auth || {}).filter(k => detection.auth[k].detected);
811
+ const paymentProviders = Object.keys(detection.payments || {}).filter(k => detection.payments[k].detected);
812
+
813
+ if (frameworks.length > 0) {
814
+ console.log(` ${colors.info}${ICONS.info}${c.reset} ${c.bold}Detected Stack:${c.reset}`);
815
+ console.log(` ${ICONS.framework} Frameworks: ${frameworks.map(f => detection.frameworks[f].name).join(', ')}`);
816
+
817
+ if (databases.length > 0) {
818
+ console.log(` ${ICONS.database} Databases: ${databases.map(d => detection.databases[d].name).join(', ')}`);
819
+ }
820
+ if (authProviders.length > 0) {
821
+ console.log(` ${ICONS.auth} Auth: ${authProviders.map(a => detection.auth[a].name).join(', ')}`);
822
+ }
823
+ if (paymentProviders.length > 0) {
824
+ console.log(` ${ICONS.payment} Payments: ${paymentProviders.map(p => detection.payments[p].name).join(', ')}`);
825
+ }
826
+
827
+ if (verbose) {
828
+ console.log();
829
+ console.log(` ${c.dim}Detection Details:${c.reset}`);
830
+ if (detection.packageManager) {
831
+ console.log(` Package Manager: ${detection.packageManager}`);
832
+ }
833
+ if (detection.nodeVersion) {
834
+ console.log(` Node Version: ${detection.nodeVersion}`);
835
+ }
836
+ const checks = detection.checks || [];
837
+ if (checks.length > 0) {
838
+ console.log(` Recommended Checks: ${checks.join(', ')}`);
839
+ }
840
+ const invariants = detection.invariants || [];
841
+ if (invariants.length > 0) {
842
+ console.log(` Invariants: ${invariants.join(', ')}`);
843
+ }
844
+ }
845
+ console.log();
846
+ } else {
847
+ console.log(` ${colors.warning}${ICONS.warning}${c.reset} No framework detected - using default Node.js configuration`);
848
+ console.log();
849
+ }
850
+ }
851
+
852
+ // ═══════════════════════════════════════════════════════════════════════════════
853
+ // DETECTION DISPLAY
854
+ // ═══════════════════════════════════════════════════════════════════════════════
855
+
856
+ function printDetectionResults(detection) {
857
+ printSection('PROJECT DETECTION', ICONS.detect);
858
+ console.log();
859
+
860
+ const categories = [
861
+ { key: 'frameworks', label: 'Frameworks', icon: ICONS.framework, color: colors.framework },
862
+ { key: 'databases', label: 'Databases', icon: ICONS.database, color: colors.database },
863
+ { key: 'auth', label: 'Authentication', icon: ICONS.auth, color: colors.auth },
864
+ { key: 'payments', label: 'Payments', icon: ICONS.payment, color: colors.payment },
865
+ { key: 'ci', label: 'CI/CD', icon: ICONS.ci, color: colors.ci },
866
+ { key: 'deploy', label: 'Deployment', icon: ICONS.deploy, color: colors.deploy },
867
+ { key: 'testing', label: 'Testing', icon: ICONS.testing, color: colors.testing },
868
+ ];
869
+
870
+ for (const cat of categories) {
871
+ const itemsObj = detection[cat.key] || {};
872
+ // Handle both object and array formats
873
+ const items = Array.isArray(itemsObj)
874
+ ? itemsObj
875
+ : Object.entries(itemsObj)
876
+ .filter(([key, value]) => value && (value.detected || value === true))
877
+ .map(([key, value]) => typeof value === 'object' ? value.name || key : key);
878
+
879
+ if (items.length === 0) continue;
880
+
881
+ const itemList = items.slice(0, 4).join(', ');
882
+ const more = items.length > 4 ? ` +${items.length - 4} more` : '';
883
+
884
+ console.log(` ${cat.color}${cat.icon}${c.reset} ${c.bold}${cat.label.padEnd(16)}${c.reset} ${itemList}${c.dim}${more}${c.reset}`);
885
+ }
886
+
887
+ // Show detected package manager
888
+ if (detection.packageManager) {
889
+ console.log();
890
+ console.log(` ${c.dim}Package manager:${c.reset} ${colors.info}${detection.packageManager}${c.reset}`);
891
+ }
892
+
893
+ // Show Node version if detected
894
+ if (detection.nodeVersion) {
895
+ console.log(` ${c.dim}Node version:${c.reset} ${colors.info}${detection.nodeVersion}${c.reset}`);
896
+ }
897
+ }
898
+
899
+ // ═══════════════════════════════════════════════════════════════════════════════
900
+ // SETUP PROGRESS DISPLAY
901
+ // ═══════════════════════════════════════════════════════════════════════════════
902
+
903
+ function printSetupStep(step, status, detail = null) {
904
+ let icon, color;
905
+
906
+ switch (status) {
907
+ case 'dry-run':
908
+ icon = ICONS.info;
909
+ color = colors.warning;
910
+ break;
911
+ case 'creating':
912
+ icon = ICONS.create;
913
+ color = colors.accent;
914
+ break;
915
+ case 'updating':
916
+ icon = ICONS.update;
917
+ color = colors.info;
918
+ break;
919
+ case 'success':
920
+ icon = ICONS.check;
921
+ color = colors.success;
922
+ break;
923
+ case 'skipped':
924
+ icon = ICONS.skip;
925
+ color = colors.muted;
926
+ break;
927
+ case 'exists':
928
+ icon = ICONS.warning;
929
+ color = colors.warning;
930
+ break;
931
+ case 'error':
932
+ icon = ICONS.cross;
933
+ color = colors.error;
934
+ break;
935
+ default:
936
+ icon = ICONS.bullet;
937
+ color = colors.muted;
938
+ }
939
+
940
+ let line = ` ${color}${icon}${c.reset} ${step}`;
941
+ if (detail) {
942
+ line += ` ${c.dim}${detail}${c.reset}`;
943
+ }
944
+ console.log(line);
945
+ }
946
+
947
+ // ═══════════════════════════════════════════════════════════════════════════════
948
+ // FILES CREATED DISPLAY
949
+ // ═══════════════════════════════════════════════════════════════════════════════
950
+
951
+ function printFilesCreated(files) {
952
+ printSection('FILES CREATED', ICONS.file);
953
+ console.log();
954
+
955
+ const fileIcons = {
956
+ 'config.json': ICONS.config,
957
+ 'invariants.yml': ICONS.shield,
958
+ 'security-policy.json': ICONS.lock,
959
+ 'team.json': ICONS.team,
960
+ 'mcp.json': ICONS.mcp,
961
+ '.vibecheckrc': ICONS.config,
962
+ 'vibecheck.yml': ICONS.ci,
963
+ };
964
+
965
+ for (const file of files) {
966
+ const basename = path.basename(file);
967
+ const icon = fileIcons[basename] || ICONS.file;
968
+ const displayPath = file.startsWith('.vibecheck/') ? file : `.vibecheck/${file}`;
969
+ console.log(` ${colors.success}${icon}${c.reset} ${c.dim}${displayPath}${c.reset}`);
970
+ }
971
+ }
972
+
973
+ // ═══════════════════════════════════════════════════════════════════════════════
974
+ // SUCCESS CARD
975
+ // ═══════════════════════════════════════════════════════════════════════════════
976
+
977
+ function printSuccessCard(projectName, mode, filesCreated) {
978
+ const w = 68;
979
+
980
+ console.log();
981
+ console.log();
982
+
983
+ // Top border
984
+ console.log(` ${colors.success}${BOX.dTopLeft}${BOX.dHorizontal.repeat(w)}${BOX.dTopRight}${c.reset}`);
985
+
986
+ // Empty line
987
+ console.log(` ${colors.success}${BOX.dVertical}${c.reset}${' '.repeat(w)}${colors.success}${BOX.dVertical}${c.reset}`);
988
+
989
+ // Headline
990
+ const headline = `${ICONS.sparkle} VIBECHECK INITIALIZED`;
991
+ const headlinePadded = padCenter(headline, w);
992
+ console.log(` ${colors.success}${BOX.dVertical}${c.reset}${colors.success}${c.bold}${headlinePadded}${c.reset}${colors.success}${BOX.dVertical}${c.reset}`);
993
+
994
+ // Project name
995
+ const projectLine = `Project: ${projectName}`;
996
+ const projectPadded = padCenter(projectLine, w);
997
+ console.log(` ${colors.success}${BOX.dVertical}${c.reset}${c.dim}${projectPadded}${c.reset}${colors.success}${BOX.dVertical}${c.reset}`);
998
+
999
+ // Mode
1000
+ const modeLine = `Mode: ${mode}`;
1001
+ const modePadded = padCenter(modeLine, w);
1002
+ console.log(` ${colors.success}${BOX.dVertical}${c.reset}${c.dim}${modePadded}${c.reset}${colors.success}${BOX.dVertical}${c.reset}`);
1003
+
1004
+ // Empty line
1005
+ console.log(` ${colors.success}${BOX.dVertical}${c.reset}${' '.repeat(w)}${colors.success}${BOX.dVertical}${c.reset}`);
1006
+
1007
+ // Files created count
1008
+ const filesLine = `${filesCreated} files configured`;
1009
+ const filesPadded = padCenter(filesLine, w);
1010
+ console.log(` ${colors.success}${BOX.dVertical}${c.reset}${colors.accent}${filesPadded}${c.reset}${colors.success}${BOX.dVertical}${c.reset}`);
1011
+
1012
+ // Empty line
1013
+ console.log(` ${colors.success}${BOX.dVertical}${c.reset}${' '.repeat(w)}${colors.success}${BOX.dVertical}${c.reset}`);
1014
+
1015
+ // Bottom border
1016
+ console.log(` ${colors.success}${BOX.dBottomLeft}${BOX.dHorizontal.repeat(w)}${BOX.dBottomRight}${c.reset}`);
1017
+
1018
+ console.log();
1019
+ }
1020
+
1021
+ // ═══════════════════════════════════════════════════════════════════════════════
1022
+ // NEXT STEPS DISPLAY
1023
+ // ═══════════════════════════════════════════════════════════════════════════════
1024
+
1025
+ function printNextSteps(options = {}) {
1026
+ printSection('NEXT STEPS', ICONS.arrow);
1027
+ console.log();
1028
+
1029
+ const steps = [];
1030
+
1031
+ if (options.mode === 'connect') {
1032
+ steps.push(
1033
+ { num: 1, cmd: 'vibecheck scan', desc: 'Run baseline scan' },
1034
+ { num: 2, cmd: 'vibecheck checkpoint --save', desc: 'Save baseline for comparison' },
1035
+ { num: 3, cmd: 'git push', desc: 'CI will run automatically' },
1036
+ );
1037
+ } else {
1038
+ steps.push(
1039
+ { num: 1, cmd: 'vibecheck scan', desc: 'Run your first scan' },
1040
+ { num: 2, cmd: 'vibecheck ship', desc: 'Check if ready to ship' },
1041
+ );
1042
+
1043
+ if (options.hasCI) {
1044
+ steps.push({ num: 3, cmd: 'git push', desc: 'CI will run automatically' });
1045
+ } else {
1046
+ steps.push({ num: 3, cmd: 'vibecheck init --connect', desc: 'Add GitHub integration [STARTER]' });
1047
+ }
1048
+ }
1049
+
1050
+ for (const step of steps) {
1051
+ console.log(` ${colors.accent}${step.num}.${c.reset} ${c.bold}${step.cmd}${c.reset}`);
1052
+ console.log(` ${c.dim}${step.desc}${c.reset}`);
1053
+ }
1054
+
1055
+ console.log();
1056
+ console.log(` ${c.dim}Full docs:${c.reset} ${colors.info}https://docs.vibecheckai.dev${c.reset}`);
1057
+ console.log();
1058
+
1059
+ // Upsell box
1060
+ console.log(` ${c.dim}╭────────────────────────────────────────────────────────────╮${c.reset}`);
1061
+ console.log(` ${c.dim}│${c.reset} ${c.dim}│${c.reset}`);
1062
+ console.log(` ${c.dim}│${c.reset} ${colors.accent}⚡ STARTER${c.reset} ${c.dim}•${c.reset} AI-powered fixes, GitHub CI, MCP tools ${c.dim}│${c.reset}`);
1063
+ console.log(` ${c.dim}│${c.reset} ${colors.accent}🏆 PRO${c.reset} ${c.dim}•${c.reset} Runtime proof, verified badges, AI testing ${c.dim}│${c.reset}`);
1064
+ console.log(` ${c.dim}│${c.reset} ${c.dim}│${c.reset}`);
1065
+ console.log(` ${c.dim}│${c.reset} ${colors.info}vibecheck login${c.reset} ${c.dim}to upgrade • vibecheck.dev/pricing${c.reset} ${c.dim}│${c.reset}`);
1066
+ console.log(` ${c.dim}│${c.reset} ${c.dim}│${c.reset}`);
1067
+ console.log(` ${c.dim}╰────────────────────────────────────────────────────────────╯${c.reset}`);
1068
+ console.log();
1069
+ }
1070
+
1071
+ // ═══════════════════════════════════════════════════════════════════════════════
1072
+ // ENTERPRISE MODE HEADER
1073
+ // ═══════════════════════════════════════════════════════════════════════════════
1074
+
1075
+ function printEnterpriseHeader(options) {
1076
+ console.log();
1077
+ console.log(` ${bgRgb(60, 40, 100)}${c.bold} ${ICONS.enterprise} ENTERPRISE MODE ${c.reset}`);
1078
+ console.log();
1079
+
1080
+ const features = [];
1081
+ if (options.ci) features.push(`${ICONS.ci} CI/CD`);
1082
+ if (options.compliance) features.push(`${ICONS.compliance} Compliance`);
1083
+ if (options.team) features.push(`${ICONS.team} Team`);
1084
+ if (options.mcp) features.push(`${ICONS.mcp} MCP`);
1085
+ if (options.strict) features.push(`${ICONS.shield} Strict`);
1086
+
1087
+ if (features.length > 0) {
1088
+ console.log(` ${c.dim}Features:${c.reset} ${features.join(' ')}`);
1089
+ console.log();
1090
+ }
1091
+ }
1092
+
1093
+ // ═══════════════════════════════════════════════════════════════════════════════
1094
+ // COMPLIANCE DISPLAY
1095
+ // ═══════════════════════════════════════════════════════════════════════════════
1096
+
1097
+ function printComplianceInfo(complianceType) {
1098
+ const complianceInfo = {
1099
+ soc2: { name: 'SOC 2 Type II', icon: '🔐', color: colors.compliance },
1100
+ hipaa: { name: 'HIPAA', icon: '🏥', color: rgb(255, 100, 100) },
1101
+ gdpr: { name: 'GDPR', icon: '🇪🇺', color: rgb(100, 150, 255) },
1102
+ pci: { name: 'PCI-DSS', icon: '💳', color: rgb(255, 200, 100) },
1103
+ };
1104
+
1105
+ const info = complianceInfo[complianceType] || { name: complianceType, icon: ICONS.compliance, color: colors.compliance };
1106
+
1107
+ console.log();
1108
+ console.log(` ${info.color}${info.icon}${c.reset} ${c.bold}${info.name} Compliance${c.reset}`);
1109
+ console.log(` ${c.dim}Generating baseline templates...${c.reset}`);
1110
+ }
1111
+
1112
+ // ═══════════════════════════════════════════════════════════════════════════════
1113
+ // HELP DISPLAY
1114
+ // ═══════════════════════════════════════════════════════════════════════════════
1115
+
1116
+ function printHelp(showBanner = true) {
1117
+ if (showBanner && shouldShowBanner({})) {
1118
+ console.log(BANNER_FULL);
1119
+ }
1120
+ console.log(`
1121
+ ${c.bold}Usage:${c.reset} vibecheck init [mode] [options]
1122
+
1123
+ ${c.bold}MODES${c.reset}
1124
+ ${colors.success}--local${c.reset} ${c.green}[FREE]${c.reset} Full local setup (default)
1125
+ Creates truthpack, contracts, MDC/IDE rules
1126
+ ${colors.accent}--connect${c.reset} ${c.cyan}[STARTER]${c.reset} + GitHub Actions, PR comments, dashboard sync
1127
+
1128
+ ${c.bold}Basic Options:${c.reset}
1129
+ ${colors.accent}--path, -p <dir>${c.reset} Project path ${c.dim}(default: current directory)${c.reset}
1130
+ ${colors.accent}--quick, -q${c.reset} Skip wizard, use defaults
1131
+ ${colors.accent}--wizard, -i${c.reset} Interactive setup wizard
1132
+ ${colors.accent}--dry-run${c.reset} Preview changes without applying
1133
+ ${colors.accent}--repair${c.reset} Fix partial init state
1134
+ ${colors.accent}--verify${c.reset} Verify setup after init
1135
+ ${colors.accent}--verbose, -v${c.reset} Show detailed output
1136
+ ${colors.accent}--git-hooks${c.reset} Install git pre-push hook
1137
+ ${colors.accent}--json${c.reset} Output results as JSON
1138
+ ${colors.accent}--help, -h${c.reset} Show this help
1139
+
1140
+ ${colors.enterprise}${c.bold}Enterprise Options:${c.reset}
1141
+ ${colors.accent}--enterprise, -e${c.reset} Enable enterprise mode
1142
+ ${colors.accent}--full${c.reset} All features: CI + team + MCP
1143
+ ${colors.accent}--detect${c.reset} Detection only (JSON output)
1144
+
1145
+ ${colors.ci}${c.bold}CI/CD Integration:${c.reset}
1146
+ ${colors.accent}--ci [provider]${c.reset} Setup CI/CD (auto-detects)
1147
+ ${colors.accent}--gha${c.reset} GitHub Actions workflow
1148
+ ${colors.accent}--gitlab${c.reset} GitLab CI configuration
1149
+ ${colors.accent}--fail-on-warn${c.reset} CI fails on WARN
1150
+
1151
+ ${colors.compliance}${c.bold}Compliance Templates:${c.reset}
1152
+ ${colors.accent}--compliance [type]${c.reset} Generate compliance templates
1153
+ ${colors.accent}--soc2${c.reset} SOC 2 Type II baseline
1154
+ ${colors.accent}--hipaa${c.reset} HIPAA compliance baseline
1155
+ ${colors.accent}--gdpr${c.reset} GDPR compliance baseline
1156
+ ${colors.accent}--pci${c.reset} PCI-DSS compliance baseline
1157
+
1158
+ ${colors.team}${c.bold}Team & Security:${c.reset}
1159
+ ${colors.accent}--team${c.reset} Generate team config (multi-env)
1160
+ ${colors.accent}--mcp${c.reset} Generate MCP server config
1161
+ ${colors.accent}--strict${c.reset} Enable strict mode
1162
+
1163
+ ${c.bold}Created Files (--local):${c.reset}
1164
+ ${c.dim}.vibecheck/config.json${c.reset} Main configuration
1165
+ ${c.dim}.vibecheck/truthpack.json${c.reset} Routes, env, auth, billing truth
1166
+ ${c.dim}.vibecheck/contracts/${c.reset} Contract definitions
1167
+ ${c.dim}.cursor/rules/*.mdc${c.reset} Cursor IDE rules
1168
+ ${c.dim}.windsurf/rules.md${c.reset} Windsurf IDE rules
1169
+
1170
+ ${c.bold}Additional Files (--connect):${c.reset}
1171
+ ${c.dim}.github/workflows/vibecheck.yml${c.reset} GitHub Actions workflow
1172
+ ${c.dim}.github/workflows/vibecheck-pr.yml${c.reset} PR check workflow
1173
+
1174
+ ${c.bold}Examples:${c.reset}
1175
+ ${c.dim}# Full local setup (default)${c.reset}
1176
+ vibecheck init --local
1177
+
1178
+ ${c.dim}# Local + GitHub integration${c.reset}
1179
+ vibecheck init --connect
1180
+
1181
+ ${c.dim}# Quick setup${c.reset}
1182
+ vibecheck init --quick
1183
+
1184
+ ${c.dim}# Enterprise with compliance${c.reset}
1185
+ vibecheck init --enterprise --soc2
1186
+ `);
1187
+ }
1188
+
1189
+ // ═══════════════════════════════════════════════════════════════════════════════
1190
+ // ARGS PARSER
1191
+ // ═══════════════════════════════════════════════════════════════════════════════
1192
+
1193
+ function parseArgs(args) {
1194
+ // Parse global flags first
1195
+ const { flags: globalFlags, cleanArgs } = parseGlobalFlags(args);
1196
+
1197
+ const out = {
1198
+ path: globalFlags.path || ".",
1199
+ gitHooks: false,
1200
+ help: globalFlags.help || false,
1201
+ quick: false,
1202
+ json: globalFlags.json || false,
1203
+ verbose: globalFlags.verbose || false,
1204
+ noBanner: globalFlags.noBanner || false,
1205
+ ci: globalFlags.ci || false,
1206
+ quiet: globalFlags.quiet || false,
1207
+ // Mode flags (--local is default, --connect requires STARTER)
1208
+ local: false,
1209
+ connect: false,
1210
+ // Enhancement flags
1211
+ wizard: false,
1212
+ interactive: false,
1213
+ dryRun: false,
1214
+ repair: false,
1215
+ verify: false,
1216
+ // Enterprise options
1217
+ enterprise: false,
1218
+ compliance: false,
1219
+ team: false,
1220
+ mcp: false,
1221
+ strict: globalFlags.strict || false,
1222
+ failOnWarn: false,
1223
+ detect: false,
1224
+ };
1225
+
1226
+ for (let i = 0; i < cleanArgs.length; i++) {
1227
+ const a = cleanArgs[i];
1228
+ if (a.startsWith("--path=")) out.path = a.split("=")[1];
1229
+ if (a === "--path" || a === "-p") out.path = cleanArgs[++i];
1230
+ if (a === "--git-hooks") out.gitHooks = true;
1231
+ if (a === "--quick" || a === "-q") out.quick = true;
1232
+ if (a === "--verify") out.verify = true;
1233
+
1234
+ // Enhancement flags
1235
+ if (a === "--wizard" || a === "--interactive" || a === "-i") {
1236
+ out.wizard = true;
1237
+ out.interactive = true;
1238
+ }
1239
+ if (a === "--dry-run" || a === "--dryrun") out.dryRun = true;
1240
+ if (a === "--repair") out.repair = true;
1241
+
1242
+ // Mode flags
1243
+ if (a === "--local" || a === "-l") out.local = true;
1244
+ if (a === "--connect" || a === "-c") out.connect = true;
1245
+
1246
+ // Enterprise flags
1247
+ if (a === "--enterprise" || a === "-e") out.enterprise = true;
1248
+ if (a === "--ci") {
1249
+ const next = args[i + 1];
1250
+ if (next && !next.startsWith("-")) {
1251
+ out.ci = args[++i];
1252
+ } else {
1253
+ out.ci = true;
1254
+ }
1255
+ }
1256
+ if (a === "--gha" || a === "--github-actions") out.ci = "github";
1257
+ if (a === "--gitlab") out.ci = "gitlab";
1258
+ if (a === "--compliance") {
1259
+ const next = args[i + 1];
1260
+ if (next && !next.startsWith("-")) {
1261
+ out.compliance = args[++i];
1262
+ } else {
1263
+ out.compliance = true;
1264
+ }
1265
+ }
1266
+ if (a === "--soc2") out.compliance = "soc2";
1267
+ if (a === "--hipaa") out.compliance = "hipaa";
1268
+ if (a === "--gdpr") out.compliance = "gdpr";
1269
+ if (a === "--pci") out.compliance = "pci";
1270
+ if (a === "--team") out.team = true;
1271
+ if (a === "--mcp") out.mcp = true;
1272
+ if (a === "--strict") out.strict = true;
1273
+ if (a === "--fail-on-warn") out.failOnWarn = true;
1274
+ if (a === "--detect") out.detect = true;
1275
+ if (a === "--full") {
1276
+ out.enterprise = true;
1277
+ out.ci = true;
1278
+ out.team = true;
1279
+ out.mcp = true;
1280
+ out.connect = true;
1281
+ }
1282
+ }
1283
+
1284
+ // Default to --local if neither mode specified
1285
+ if (!out.local && !out.connect) {
1286
+ out.local = true;
1287
+ }
1288
+
1289
+ return out;
1290
+ }
1291
+
1292
+ // ═══════════════════════════════════════════════════════════════════════════════
1293
+ // MAIN INIT FUNCTION
1294
+ // ═══════════════════════════════════════════════════════════════════════════════
1295
+
1296
+ // ═══════════════════════════════════════════════════════════════════════════════
1297
+ // LOCAL MODE SETUP - Full local initialization
1298
+ // ═══════════════════════════════════════════════════════════════════════════════
1299
+
1300
+ async function runLocalSetup(targetDir, projectName, opts, filesCreated) {
1301
+ printSection('LOCAL SETUP', ICONS.setup);
1302
+ console.log();
1303
+
1304
+ const totalSteps = 7; // Approximate number of major steps
1305
+ let currentStep = 0;
1306
+
1307
+ function logStep(stepName) {
1308
+ currentStep++;
1309
+ if (opts.verbose && !opts.json) {
1310
+ console.log(` ${c.dim}[${currentStep}/${totalSteps}]${c.reset} ${stepName}`);
1311
+ }
1312
+ }
1313
+
1314
+ // Detect framework for framework-specific templates
1315
+ let detection = null;
1316
+ if (!opts.dryRun) {
1317
+ try {
1318
+ const { detectAll } = require("./lib/enterprise-detect");
1319
+ detection = detectAll(targetDir);
1320
+ if (!opts.json) {
1321
+ printEnhancedDetection(detection, opts.verbose);
1322
+ }
1323
+ } catch (e) {
1324
+ if (!opts.json) {
1325
+ console.log(` ${colors.warning}${ICONS.warning}${c.reset} Detection failed: ${e.message}`);
1326
+ if (opts.verbose) {
1327
+ console.log(` ${c.dim}Stack: ${e.stack}${c.reset}`);
1328
+ }
1329
+ console.log(` ${c.dim}Using default configuration${c.reset}`);
1330
+ console.log();
1331
+ }
1332
+ }
1333
+ }
1334
+
1335
+ const vibecheckDir = path.join(targetDir, ".vibecheck");
1336
+
1337
+ // 1. Create .vibecheck/ directory structure
1338
+ logStep('Creating directory structure');
1339
+ const dirs = [
1340
+ vibecheckDir,
1341
+ path.join(vibecheckDir, "results"),
1342
+ path.join(vibecheckDir, "reports"),
1343
+ path.join(vibecheckDir, "contracts"),
1344
+ path.join(vibecheckDir, "missions"),
1345
+ path.join(vibecheckDir, "checkpoints"),
1346
+ path.join(vibecheckDir, "runs"),
1347
+ ];
1348
+
1349
+ for (const dir of dirs) {
1350
+ if (!fs.existsSync(dir)) {
1351
+ if (opts.dryRun) {
1352
+ printSetupStep(path.relative(targetDir, dir), 'dry-run', 'would create');
1353
+ } else {
1354
+ fs.mkdirSync(dir, { recursive: true });
1355
+ }
1356
+ }
1357
+ }
1358
+ if (!opts.dryRun) {
1359
+ printSetupStep('.vibecheck/', 'success', 'directory structure created');
1360
+ filesCreated.push('.vibecheck/');
1361
+ }
1362
+
1363
+ // 2. Create config.json with framework-specific settings
1364
+ logStep('Creating configuration');
1365
+ const configPath = path.join(vibecheckDir, "config.json");
1366
+ if (!fs.existsSync(configPath) || opts.dryRun) {
1367
+ const frameworkConfig = getFrameworkConfig(detection);
1368
+ const config = {
1369
+ version: "2.0.0",
1370
+ project: projectName,
1371
+ createdAt: new Date().toISOString(),
1372
+ framework: frameworkConfig.framework || "node",
1373
+ checks: frameworkConfig.checks || ["routes", "env", "auth", "security"],
1374
+ output: ".vibecheck",
1375
+ policy: {
1376
+ allowlist: { domains: [], packages: [] },
1377
+ ignore: {
1378
+ paths: [
1379
+ "node_modules",
1380
+ "__tests__",
1381
+ "*.test.*",
1382
+ "*.spec.*",
1383
+ ...(frameworkConfig.ignorePaths || [])
1384
+ ]
1385
+ },
1386
+ },
1387
+ thresholds: {
1388
+ minScore: 70,
1389
+ maxBlockers: 0,
1390
+ maxWarnings: 10,
1391
+ },
1392
+ ...(frameworkConfig.extra || {}),
1393
+ };
1394
+
1395
+ if (opts.dryRun) {
1396
+ printSetupStep('config.json', 'dry-run', `would create (framework: ${config.framework})`);
1397
+ console.log(` ${c.dim}Config preview:${c.reset}`);
1398
+ console.log(JSON.stringify(config, null, 2));
1399
+ } else {
1400
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
1401
+ printSetupStep('config.json', 'success', `configuration created (framework: ${config.framework})`);
1402
+ filesCreated.push('.vibecheck/config.json');
1403
+ }
1404
+ } else {
1405
+ printSetupStep('config.json', 'exists', 'already exists');
1406
+ }
1407
+
1408
+ // 3. Generate truthpack
1409
+ logStep('Generating truthpack');
1410
+ if (!opts.dryRun) {
1411
+ startSpinner('Building truthpack...', colors.accent);
1412
+ try {
1413
+ const { runContext } = require("./runContext");
1414
+ await runContext(["--path", targetDir, "--quiet"]);
1415
+ stopSpinner('Truthpack generated', true);
1416
+ filesCreated.push('.vibecheck/truthpack.json');
1417
+ } catch (e) {
1418
+ stopSpinner('Truthpack generation failed', false);
1419
+ // Don't throw - truthpack generation is optional for init
1420
+ if (!opts.json) {
1421
+ console.log(` ${colors.warning}${ICONS.warning}${c.reset} ${e.message}`);
1422
+ console.log(` ${c.dim}Run 'vibecheck context' manually to generate truthpack${c.reset}`);
1423
+ }
1424
+ }
1425
+ } else {
1426
+ printSetupStep('truthpack.json', 'dry-run', 'would generate via vibecheck ctx build');
1427
+ }
1428
+
1429
+ // 4. Generate contracts
1430
+ logStep('Creating contracts');
1431
+ const contractsDir = path.join(vibecheckDir, "contracts");
1432
+
1433
+ // Routes contract
1434
+ const routeContractPath = path.join(contractsDir, "routes.contract.json");
1435
+ if (!fs.existsSync(routeContractPath)) {
1436
+ const routeContract = {
1437
+ version: "1.0.0",
1438
+ generatedAt: new Date().toISOString(),
1439
+ routes: [],
1440
+ description: "Route contract - populated by scan",
1441
+ };
1442
+ if (opts.dryRun) {
1443
+ printSetupStep('routes.contract.json', 'dry-run', 'would create');
1444
+ } else {
1445
+ fs.writeFileSync(routeContractPath, JSON.stringify(routeContract, null, 2));
1446
+ printSetupStep('routes.contract.json', 'success', 'route contract created');
1447
+ filesCreated.push('.vibecheck/contracts/routes.contract.json');
1448
+ }
1449
+ }
1450
+
1451
+ // Env contract
1452
+ const envContractPath = path.join(contractsDir, "env.contract.json");
1453
+ if (!fs.existsSync(envContractPath)) {
1454
+ const envContract = {
1455
+ version: "1.0.0",
1456
+ generatedAt: new Date().toISOString(),
1457
+ required: [],
1458
+ optional: [],
1459
+ description: "Environment contract - populated by scan",
1460
+ };
1461
+ if (opts.dryRun) {
1462
+ printSetupStep('env.contract.json', 'dry-run', 'would create');
1463
+ } else {
1464
+ fs.writeFileSync(envContractPath, JSON.stringify(envContract, null, 2));
1465
+ printSetupStep('env.contract.json', 'success', 'env contract created');
1466
+ filesCreated.push('.vibecheck/contracts/env.contract.json');
1467
+ }
1468
+ }
1469
+
1470
+ // 5. Generate IDE rules (MDC for Cursor, rules for others)
1471
+ logStep('Generating IDE rules');
1472
+ if (!opts.dryRun) {
1473
+ startSpinner('Generating IDE rules...', colors.accent);
1474
+ try {
1475
+ const { runContext } = require("./runContext");
1476
+ await runContext(["--path", targetDir, "--quiet"]);
1477
+ stopSpinner('IDE rules generated', true);
1478
+ filesCreated.push('.cursor/rules/', '.windsurf/', '.github/copilot-instructions.md');
1479
+ } catch (e) {
1480
+ stopSpinner('IDE rules generation failed', false);
1481
+ if (!opts.json) {
1482
+ console.log(` ${colors.warning}${ICONS.warning}${c.reset} ${e.message}`);
1483
+ console.log(` ${c.dim}Run 'vibecheck context' manually to generate IDE rules${c.reset}`);
1484
+ }
1485
+ // Don't throw - IDE rules are optional
1486
+ }
1487
+ } else {
1488
+ printSetupStep('IDE rules', 'dry-run', 'would generate via vibecheck context');
1489
+ }
1490
+
1491
+ // 6. Create .vibecheckrc at project root (create both for compatibility)
1492
+ logStep('Creating root config');
1493
+ const rcPathJson = path.join(targetDir, ".vibecheckrc.json");
1494
+ const rcPath = path.join(targetDir, ".vibecheckrc");
1495
+ const rc = {
1496
+ extends: ".vibecheck/config.json",
1497
+ tier: "free",
1498
+ };
1499
+
1500
+ if (!fs.existsSync(rcPathJson) && !fs.existsSync(rcPath)) {
1501
+ if (opts.dryRun) {
1502
+ printSetupStep('.vibecheckrc', 'dry-run', 'would create');
1503
+ printSetupStep('.vibecheckrc.json', 'dry-run', 'would create');
1504
+ } else {
1505
+ // Create .vibecheckrc (without .json) for compatibility with tests/expectations
1506
+ fs.writeFileSync(rcPath, JSON.stringify(rc, null, 2));
1507
+ printSetupStep('.vibecheckrc', 'success', 'root config created');
1508
+ filesCreated.push('.vibecheckrc');
1509
+
1510
+ // Also create .vibecheckrc.json for backward compatibility
1511
+ fs.writeFileSync(rcPathJson, JSON.stringify(rc, null, 2));
1512
+ filesCreated.push('.vibecheckrc.json');
1513
+ }
1514
+ } else if (fs.existsSync(rcPathJson) && !fs.existsSync(rcPath)) {
1515
+ // If only .vibecheckrc.json exists, create .vibecheckrc for compatibility
1516
+ if (!opts.dryRun) {
1517
+ fs.writeFileSync(rcPath, JSON.stringify(rc, null, 2));
1518
+ printSetupStep('.vibecheckrc', 'success', 'root config created (compatibility)');
1519
+ filesCreated.push('.vibecheckrc');
1520
+ }
1521
+ }
1522
+
1523
+ // 7. Update .gitignore
1524
+ logStep('Updating .gitignore');
1525
+ const gitignorePath = path.join(targetDir, ".gitignore");
1526
+ if (fs.existsSync(gitignorePath)) {
1527
+ let gitignore = fs.readFileSync(gitignorePath, "utf-8");
1528
+ const additions = [];
1529
+ if (!gitignore.includes(".vibecheck/results/")) additions.push(".vibecheck/results/");
1530
+ if (!gitignore.includes(".vibecheck/runs/")) additions.push(".vibecheck/runs/");
1531
+ if (!gitignore.includes(".vibecheck/checkpoints/")) additions.push(".vibecheck/checkpoints/");
1532
+
1533
+ if (additions.length > 0) {
1534
+ if (opts.dryRun) {
1535
+ printSetupStep('.gitignore', 'dry-run', `would add: ${additions.join(', ')}`);
1536
+ } else {
1537
+ gitignore += `\n# vibecheck (generated outputs)\n${additions.join("\n")}\n`;
1538
+ fs.writeFileSync(gitignorePath, gitignore);
1539
+ printSetupStep('.gitignore', 'success', 'updated with vibecheck paths');
1540
+ }
1541
+ }
1542
+ }
1543
+
1544
+ // Return both filesCreated and detection for use in main function
1545
+ return { filesCreated, detection };
1546
+ }
1547
+
1548
+ // ═══════════════════════════════════════════════════════════════════════════════
1549
+ // CONNECT MODE SETUP - GitHub integration
1550
+ // ═══════════════════════════════════════════════════════════════════════════════
1551
+
1552
+ async function runConnectSetup(targetDir, projectName, opts, filesCreated) {
1553
+ // Check entitlement
1554
+ const entitlements = require("./lib/entitlements-v2");
1555
+ const access = await entitlements.enforce("init.connect", { silent: true });
1556
+
1557
+ if (!access.allowed) {
1558
+ console.log();
1559
+ console.log(` ${colors.warning}${ICONS.warning}${c.reset} ${c.bold}--connect requires STARTER plan${c.reset}`);
1560
+ console.log(` ${c.dim}Upgrade at: https://vibecheckai.dev/pricing${c.reset}`);
1561
+ console.log();
1562
+ console.log(` ${c.dim}Local setup completed. Run 'vibecheck init --connect' after upgrading.${c.reset}`);
1563
+ return filesCreated;
1564
+ }
1565
+
1566
+ printSection('GITHUB INTEGRATION', ICONS.ci);
1567
+ console.log();
1568
+
1569
+ // 1. Create GitHub workflows directory
1570
+ const workflowsDir = path.join(targetDir, ".github", "workflows");
1571
+ if (!fs.existsSync(workflowsDir)) {
1572
+ fs.mkdirSync(workflowsDir, { recursive: true });
1573
+ }
1574
+
1575
+ // 2. Copy main workflow template
1576
+ const mainWorkflowPath = path.join(workflowsDir, "vibecheck.yml");
1577
+ if (!fs.existsSync(mainWorkflowPath)) {
1578
+ // Read template
1579
+ const templatePath = path.join(__dirname, "..", "..", "templates", "github-actions", "vibecheck.yml");
1580
+ if (fs.existsSync(templatePath)) {
1581
+ fs.copyFileSync(templatePath, mainWorkflowPath);
1582
+ printSetupStep('vibecheck.yml', 'success', 'main workflow created');
1583
+ filesCreated.push('.github/workflows/vibecheck.yml');
1584
+ } else {
1585
+ // Inline template as fallback
1586
+ const workflow = `# Vibecheck CI/CD Workflow
1587
+ name: Vibecheck
1588
+ on:
1589
+ push:
1590
+ branches: [main, master]
1591
+ pull_request:
1592
+
1593
+ jobs:
1594
+ vibecheck:
1595
+ runs-on: ubuntu-latest
1596
+ steps:
1597
+ - uses: actions/checkout@v4
1598
+ - uses: actions/setup-node@v4
1599
+ with:
1600
+ node-version: '20'
1601
+ - run: npm ci
1602
+ - run: npx vibecheck scan --json > .vibecheck/results/scan.json
1603
+ - run: npx vibecheck ship --ci
1604
+ `;
1605
+ fs.writeFileSync(mainWorkflowPath, workflow);
1606
+ printSetupStep('vibecheck.yml', 'success', 'main workflow created');
1607
+ filesCreated.push('.github/workflows/vibecheck.yml');
1608
+ }
1609
+ } else {
1610
+ printSetupStep('vibecheck.yml', 'exists', 'already exists');
1611
+ }
1612
+
1613
+ // 3. Copy PR workflow template
1614
+ const prWorkflowPath = path.join(workflowsDir, "vibecheck-pr.yml");
1615
+ if (!fs.existsSync(prWorkflowPath)) {
1616
+ const templatePath = path.join(__dirname, "..", "..", "templates", "github-actions", "vibecheck-pr.yml");
1617
+ if (fs.existsSync(templatePath)) {
1618
+ fs.copyFileSync(templatePath, prWorkflowPath);
1619
+ printSetupStep('vibecheck-pr.yml', 'success', 'PR workflow created');
1620
+ filesCreated.push('.github/workflows/vibecheck-pr.yml');
1621
+ }
1622
+ }
1623
+
1624
+ // 4. Provide setup instructions
1625
+ console.log();
1626
+ console.log(` ${colors.info}${ICONS.info}${c.reset} ${c.bold}GitHub Setup Required:${c.reset}`);
1627
+ console.log(` 1. Add ${c.cyan}VIBECHECK_API_KEY${c.reset} to repository secrets`);
1628
+ console.log(` 2. Push to trigger first workflow run`);
1629
+ console.log();
1630
+
1631
+ return filesCreated;
1632
+ }
1633
+
1634
+ // ═══════════════════════════════════════════════════════════════════════════════
1635
+ // MAIN INIT FUNCTION
1636
+ // ═══════════════════════════════════════════════════════════════════════════════
1637
+
1638
+ async function runInit(args) {
1639
+ const opts = parseArgs(args);
1640
+
1641
+ if (opts.help) {
1642
+ printHelp(shouldShowBanner(opts));
1643
+ return 0;
1644
+ }
1645
+
1646
+ // --quick mode runs local setup with non-interactive defaults
1647
+ if (opts.quick) {
1648
+ opts.local = true;
1649
+ opts.nonInteractive = true;
1650
+ // Continue with normal init flow below
1651
+ }
1652
+
1653
+ const targetDir = path.resolve(opts.path);
1654
+ const projectName = path.basename(targetDir);
1655
+ let bannerPrinted = false;
1656
+
1657
+ // Enterprise mode - comprehensive setup
1658
+ const useEnterprise = opts.enterprise || opts.ci || opts.compliance ||
1659
+ opts.team || opts.mcp || opts.detect;
1660
+
1661
+ if (EnterpriseInit && useEnterprise && !opts.local && !opts.connect) {
1662
+ if (shouldShowBanner(opts)) {
1663
+ printBanner();
1664
+ bannerPrinted = true;
1665
+ printEnterpriseHeader(opts);
1666
+
1667
+ console.log(` ${c.dim}Project:${c.reset} ${c.bold}${projectName}${c.reset}`);
1668
+ console.log(` ${c.dim}Path:${c.reset} ${targetDir}`);
1669
+ console.log();
1670
+ }
1671
+
1672
+ const enterprise = new EnterpriseInit(targetDir, opts);
1673
+ return await enterprise.run();
1674
+ }
1675
+
1676
+ // Detect-only mode (quick detection report)
1677
+ if (opts.detect) {
1678
+ if (shouldShowBanner(opts)) {
1679
+ printBanner();
1680
+ bannerPrinted = true;
1681
+ console.log(` ${c.dim}Project:${c.reset} ${c.bold}${projectName}${c.reset}`);
1682
+ console.log(` ${c.dim}Path:${c.reset} ${targetDir}`);
1683
+ }
1684
+
1685
+ startSpinner('Detecting project configuration...', colors.accent);
1686
+
1687
+ try {
1688
+ const { detectAll } = require("./lib/enterprise-detect");
1689
+ const detection = detectAll(targetDir);
1690
+ stopSpinner('Detection complete', true);
1691
+ if (!opts.json) {
1692
+ printDetectionResults(detection);
1693
+ console.log();
1694
+ console.log(` ${c.dim}Full JSON output:${c.reset}`);
1695
+ }
1696
+ console.log(JSON.stringify(detection, null, 2));
1697
+ } catch (e) {
1698
+ stopSpinner('Detection failed', false);
1699
+ console.log(` ${colors.error}Error:${c.reset} ${e.message}`);
1700
+ }
1701
+ return 0;
1702
+ }
1703
+
1704
+ // ═══════════════════════════════════════════════════════════════════════════
1705
+ // NEW: --local and --connect modes
1706
+ // ═══════════════════════════════════════════════════════════════════════════
1707
+
1708
+ // Interactive wizard mode
1709
+ if (opts.wizard && InitWizard) {
1710
+ if (shouldShowBanner(opts) && !bannerPrinted) {
1711
+ printBanner();
1712
+ bannerPrinted = true;
1713
+ }
1714
+ const wizard = new InitWizard(targetDir, opts);
1715
+ return await wizard.run();
1716
+ }
1717
+
1718
+ // Repair mode - fix partial state
1719
+ if (opts.repair) {
1720
+ if (shouldShowBanner(opts) && !bannerPrinted) {
1721
+ printBanner();
1722
+ bannerPrinted = true;
1723
+ console.log(` ${c.dim}Project:${c.reset} ${c.bold}${projectName}${c.reset}`);
1724
+ console.log(` ${c.dim}Path:${c.reset} ${targetDir}`);
1725
+ console.log(` ${c.dim}Mode:${c.reset} ${colors.accent}Repair${c.reset}`);
1726
+ console.log();
1727
+ }
1728
+ return await runRepairMode(targetDir, projectName, opts);
1729
+ }
1730
+
1731
+ // Print banner only once (not already printed in enterprise/detect modes)
1732
+ if (shouldShowBanner(opts) && !bannerPrinted) {
1733
+ printBanner();
1734
+ bannerPrinted = true;
1735
+
1736
+ const mode = opts.connect ? 'Local + Connect' : 'Local';
1737
+ const tierBadge = opts.connect ? `${c.cyan}[STARTER]${c.reset}` : `${c.green}[FREE]${c.reset}`;
1738
+
1739
+ console.log(` ${c.dim}Project:${c.reset} ${c.bold}${projectName}${c.reset}`);
1740
+ console.log(` ${c.dim}Path:${c.reset} ${targetDir}`);
1741
+ console.log(` ${c.dim}Mode:${c.reset} ${colors.accent}${mode}${c.reset} ${tierBadge}`);
1742
+ if (opts.dryRun) {
1743
+ console.log(` ${colors.warning}${ICONS.warning}${c.reset} ${c.bold}DRY-RUN MODE${c.reset} - No files will be created`);
1744
+ }
1745
+ }
1746
+
1747
+ let filesCreated = [];
1748
+ let detection = null; // Declare detection in main function scope
1749
+ const result = {
1750
+ success: true,
1751
+ project: projectName,
1752
+ path: targetDir,
1753
+ mode: opts.connect ? 'connect' : 'local',
1754
+ filesCreated: [],
1755
+ errors: [],
1756
+ dryRun: opts.dryRun,
1757
+ };
1758
+
1759
+ // Always run local setup first
1760
+ if (opts.local || opts.connect) {
1761
+ try {
1762
+ // runLocalSetup returns both filesCreated and detection
1763
+ const setupResult = await runLocalSetup(targetDir, projectName, opts, filesCreated);
1764
+ if (setupResult && typeof setupResult === 'object' && 'filesCreated' in setupResult) {
1765
+ filesCreated = setupResult.filesCreated;
1766
+ detection = setupResult.detection || null;
1767
+ } else {
1768
+ // Backward compatibility: if it returns just an array, use it
1769
+ filesCreated = Array.isArray(setupResult) ? setupResult : filesCreated;
1770
+ }
1771
+ } catch (e) {
1772
+ result.errors.push({ step: 'local', error: e.message, stack: e.stack });
1773
+ if (!opts.json) {
1774
+ console.log(` ${colors.error}${ICONS.cross}${c.reset} Local setup error: ${e.message}`);
1775
+ if (opts.verbose) {
1776
+ console.log(` ${c.dim}Stack: ${e.stack}${c.reset}`);
1777
+ }
1778
+ console.log(` ${colors.info}${ICONS.info}${c.reset} Run ${c.cyan}vibecheck init --repair${c.reset} to fix partial state`);
1779
+ }
1780
+ // Don't exit on error - continue and report errors in result
1781
+ // Only exit if critical setup failed AND we're not in dry-run mode
1782
+ if (!opts.dryRun && result.errors.length > 0 && filesCreated.length === 0) {
1783
+ // Only exit if NO files were created at all (complete failure)
1784
+ return EXIT.INTERNAL_ERROR;
1785
+ }
1786
+ }
1787
+ }
1788
+
1789
+ // Run connect setup if requested
1790
+ if (opts.connect) {
1791
+ try {
1792
+ filesCreated = await runConnectSetup(targetDir, projectName, opts, filesCreated);
1793
+ } catch (e) {
1794
+ result.errors.push({ step: 'connect', error: e.message, stack: e.stack });
1795
+ if (!opts.json) {
1796
+ console.log(` ${colors.error}${ICONS.cross}${c.reset} Connect setup error: ${e.message}`);
1797
+ if (opts.verbose) {
1798
+ console.log(` ${c.dim}Stack: ${e.stack}${c.reset}`);
1799
+ }
1800
+ }
1801
+ if (!opts.dryRun) {
1802
+ return EXIT.INTERNAL_ERROR;
1803
+ }
1804
+ }
1805
+ }
1806
+
1807
+ // Git hooks if requested
1808
+ if (opts.gitHooks) {
1809
+ const huskyDir = path.join(targetDir, ".husky");
1810
+ if (!fs.existsSync(huskyDir)) {
1811
+ fs.mkdirSync(huskyDir, { recursive: true });
1812
+ }
1813
+ const prePushHook = `#!/usr/bin/env sh
1814
+ . "$(dirname -- "$0")/_/husky.sh"
1815
+
1816
+ echo "🚦 Running vibecheck gate..."
1817
+ npx vibecheck ship --ci
1818
+
1819
+ if [ $? -ne 0 ]; then
1820
+ echo "❌ Push blocked: Gate failed!"
1821
+ exit 1
1822
+ fi
1823
+ `;
1824
+ fs.writeFileSync(path.join(huskyDir, "pre-push"), prePushHook, { mode: 0o755 });
1825
+ if (!opts.json) {
1826
+ printSetupStep('.husky/pre-push', 'success', 'git hook installed');
1827
+ }
1828
+ filesCreated.push('.husky/pre-push');
1829
+ }
1830
+
1831
+ result.filesCreated = filesCreated;
1832
+
1833
+ // JSON output
1834
+ if (opts.json) {
1835
+ console.log(JSON.stringify(result, null, 2));
1836
+ return result.errors.length > 0 ? 1 : 0;
1837
+ }
1838
+
1839
+ // Success card
1840
+ const mode = opts.connect ? 'Local + Connect' : 'Local Setup';
1841
+ printSuccessCard(projectName, mode, filesCreated.length);
1842
+
1843
+ // Generate dependency graph
1844
+ if (!opts.dryRun) {
1845
+ if (!opts.json) {
1846
+ startSpinner('Generating dependency graph...', colors.accent);
1847
+ }
1848
+ try {
1849
+ const { buildDependencyGraph, generateHtmlVisualization } = require("./context/dependency-graph");
1850
+ const depGraph = buildDependencyGraph(targetDir);
1851
+ const htmlViz = generateHtmlVisualization(depGraph, { maxNodes: 200 });
1852
+ const graphPath = path.join(targetDir, ".vibecheck", "dependency-graph.html");
1853
+ fs.writeFileSync(graphPath, htmlViz);
1854
+ filesCreated.push('.vibecheck/dependency-graph.html');
1855
+ if (!opts.json) {
1856
+ stopSpinner('Dependency graph generated', true);
1857
+ }
1858
+ } catch (e) {
1859
+ if (!opts.json) {
1860
+ stopSpinner('Dependency graph skipped', false);
1861
+ console.log(` ${colors.warning}${ICONS.warning}${c.reset} ${e.message}`);
1862
+ }
1863
+ }
1864
+ } else {
1865
+ printSetupStep('dependency-graph.html', 'dry-run', 'would generate');
1866
+ }
1867
+
1868
+ // Init summary
1869
+ printSection('INIT SUMMARY', ICONS.check);
1870
+ console.log();
1871
+ console.log(` ${colors.success}${ICONS.check}${c.reset} .vibecheck/ structure created`);
1872
+ console.log(` ${colors.success}${ICONS.check}${c.reset} Truthpack generated`);
1873
+ console.log(` ${colors.success}${ICONS.check}${c.reset} Contracts initialized`);
1874
+ console.log(` ${colors.success}${ICONS.check}${c.reset} IDE rules generated`);
1875
+ console.log(` ${colors.success}${ICONS.check}${c.reset} Dependency graph generated`);
1876
+ if (opts.connect) {
1877
+ console.log(` ${colors.success}${ICONS.check}${c.reset} GitHub Actions workflows installed`);
1878
+ }
1879
+ console.log();
1880
+
1881
+ // Show dependency graph location
1882
+ const graphPath = path.join(targetDir, ".vibecheck", "dependency-graph.html");
1883
+ if (fs.existsSync(graphPath)) {
1884
+ console.log(` ${colors.info}${ICONS.info}${c.reset} ${c.bold}Dependency Graph:${c.reset}`);
1885
+ console.log(` ${c.cyan}file://${graphPath.replace(/\\/g, '/')}${c.reset}`);
1886
+ console.log();
1887
+ }
1888
+
1889
+ // Save init state for repair mode
1890
+ if (!opts.dryRun) {
1891
+ saveInitState(targetDir, {
1892
+ timestamp: new Date().toISOString(),
1893
+ mode: opts.connect ? 'connect' : 'local',
1894
+ filesCreated,
1895
+ errors: result.errors,
1896
+ detection: detection ? {
1897
+ frameworks: Object.keys(detection.frameworks || {}).filter(k => detection.frameworks[k].detected),
1898
+ checks: detection.checks || [],
1899
+ } : null,
1900
+ });
1901
+ }
1902
+
1903
+ // Post-init validation
1904
+ if (opts.verify && !opts.dryRun) {
1905
+ const validationResult = await verifyInitSetup(targetDir, opts);
1906
+ if (!validationResult.success && !opts.json) {
1907
+ console.log();
1908
+ console.log(` ${colors.warning}${ICONS.warning}${c.reset} ${c.bold}Validation Issues Found:${c.reset}`);
1909
+ for (const issue of validationResult.issues) {
1910
+ console.log(` ${c.dim}•${c.reset} ${issue}`);
1911
+ }
1912
+ console.log();
1913
+ }
1914
+ }
1915
+
1916
+ // Framework-specific recommendations
1917
+ if (detection && !opts.json && !opts.dryRun) {
1918
+ printFrameworkRecommendations(detection, opts);
1919
+ }
1920
+
1921
+ // Next steps
1922
+ printNextSteps({ hasCI: opts.connect, mode: opts.connect ? 'connect' : 'local' });
1923
+
1924
+ return 0;
1925
+ }
1926
+
1927
+ module.exports = { runInit };