@vibecheckai/cli 2.8.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (454) hide show
  1. package/README.md +8 -8
  2. package/bin/_deprecations.js +35 -0
  3. package/bin/_router.js +46 -0
  4. package/bin/cli-hygiene.js +241 -0
  5. package/bin/guardrail.js +834 -0
  6. package/bin/runners/cli-utils.js +1070 -0
  7. package/bin/runners/context/ai-task-decomposer.js +337 -0
  8. package/bin/runners/context/analyzer.js +462 -0
  9. package/bin/runners/context/api-contracts.js +427 -0
  10. package/bin/runners/context/context-diff.js +342 -0
  11. package/bin/runners/context/context-pruner.js +291 -0
  12. package/bin/runners/context/dependency-graph.js +414 -0
  13. package/bin/runners/context/generators/claude.js +107 -0
  14. package/bin/runners/context/generators/codex.js +108 -0
  15. package/bin/runners/context/generators/copilot.js +119 -0
  16. package/bin/runners/context/generators/cursor.js +514 -0
  17. package/bin/runners/context/generators/mcp.js +151 -0
  18. package/bin/runners/context/generators/windsurf.js +180 -0
  19. package/bin/runners/context/git-context.js +302 -0
  20. package/bin/runners/context/index.js +1042 -0
  21. package/bin/runners/context/insights.js +173 -0
  22. package/bin/runners/context/mcp-server/generate-rules.js +337 -0
  23. package/bin/runners/context/mcp-server/index.js +1176 -0
  24. package/bin/runners/context/mcp-server/package.json +24 -0
  25. package/bin/runners/context/memory.js +200 -0
  26. package/bin/runners/context/monorepo.js +215 -0
  27. package/bin/runners/context/multi-repo-federation.js +404 -0
  28. package/bin/runners/context/patterns.js +253 -0
  29. package/bin/runners/context/proof-context.js +972 -0
  30. package/bin/runners/context/security-scanner.js +303 -0
  31. package/bin/runners/context/semantic-search.js +350 -0
  32. package/bin/runners/context/shared.js +264 -0
  33. package/bin/runners/context/team-conventions.js +310 -0
  34. package/bin/runners/lib/ai-bridge.js +416 -0
  35. package/bin/runners/lib/analysis-core.js +271 -0
  36. package/bin/runners/lib/analyzers.js +541 -0
  37. package/bin/runners/lib/audit-bridge.js +391 -0
  38. package/bin/runners/lib/auth-truth.js +193 -0
  39. package/bin/runners/lib/auth.js +215 -0
  40. package/bin/runners/lib/backup.js +62 -0
  41. package/bin/runners/lib/billing.js +107 -0
  42. package/bin/runners/lib/claims.js +118 -0
  43. package/bin/runners/lib/cli-ui.js +540 -0
  44. package/bin/runners/lib/compliance-bridge-new.js +0 -0
  45. package/bin/runners/lib/compliance-bridge.js +165 -0
  46. package/bin/runners/lib/contracts/auth-contract.js +194 -0
  47. package/bin/runners/lib/contracts/env-contract.js +178 -0
  48. package/bin/runners/lib/contracts/external-contract.js +198 -0
  49. package/bin/runners/lib/contracts/guard.js +168 -0
  50. package/bin/runners/lib/contracts/index.js +89 -0
  51. package/bin/runners/lib/contracts/plan-validator.js +311 -0
  52. package/bin/runners/lib/contracts/route-contract.js +192 -0
  53. package/bin/runners/lib/detect.js +89 -0
  54. package/bin/runners/lib/doctor/autofix.js +254 -0
  55. package/bin/runners/lib/doctor/index.js +37 -0
  56. package/bin/runners/lib/doctor/modules/dependencies.js +325 -0
  57. package/bin/runners/lib/doctor/modules/index.js +46 -0
  58. package/bin/runners/lib/doctor/modules/network.js +250 -0
  59. package/bin/runners/lib/doctor/modules/project.js +312 -0
  60. package/bin/runners/lib/doctor/modules/runtime.js +224 -0
  61. package/bin/runners/lib/doctor/modules/security.js +348 -0
  62. package/bin/runners/lib/doctor/modules/system.js +213 -0
  63. package/bin/runners/lib/doctor/modules/vibecheck.js +394 -0
  64. package/bin/runners/lib/doctor/reporter.js +262 -0
  65. package/bin/runners/lib/doctor/service.js +262 -0
  66. package/bin/runners/lib/doctor/types.js +113 -0
  67. package/bin/runners/lib/doctor/ui.js +263 -0
  68. package/bin/runners/lib/doctor-enhanced.js +233 -0
  69. package/bin/runners/lib/doctor-v2.js +608 -0
  70. package/bin/runners/lib/enforcement.js +72 -0
  71. package/bin/runners/lib/enterprise-detect.js +603 -0
  72. package/bin/runners/lib/enterprise-init.js +942 -0
  73. package/bin/runners/lib/entitlements-v2.js +381 -0
  74. package/bin/runners/lib/entitlements.generated.js +0 -0
  75. package/bin/runners/lib/entitlements.js +332 -0
  76. package/bin/runners/lib/env-template.js +66 -0
  77. package/bin/runners/lib/env.js +189 -0
  78. package/bin/runners/lib/error-handler.js +320 -0
  79. package/bin/runners/lib/firewall-prompt.js +50 -0
  80. package/bin/runners/lib/graph/graph-builder.js +265 -0
  81. package/bin/runners/lib/graph/html-renderer.js +413 -0
  82. package/bin/runners/lib/graph/index.js +32 -0
  83. package/bin/runners/lib/graph/runtime-collector.js +215 -0
  84. package/bin/runners/lib/graph/static-extractor.js +518 -0
  85. package/bin/runners/lib/init-wizard.js +308 -0
  86. package/bin/runners/lib/json-output.js +76 -0
  87. package/bin/runners/lib/llm.js +75 -0
  88. package/bin/runners/lib/meter.js +61 -0
  89. package/bin/runners/lib/missions/evidence.js +126 -0
  90. package/bin/runners/lib/missions/plan.js +69 -0
  91. package/bin/runners/lib/missions/templates.js +147 -0
  92. package/bin/runners/lib/patch.js +40 -0
  93. package/bin/runners/lib/permissions/auth-model.js +213 -0
  94. package/bin/runners/lib/permissions/idor-prover.js +205 -0
  95. package/bin/runners/lib/permissions/index.js +45 -0
  96. package/bin/runners/lib/permissions/matrix-builder.js +198 -0
  97. package/bin/runners/lib/pkgjson.js +28 -0
  98. package/bin/runners/lib/preflight.js +142 -0
  99. package/bin/runners/lib/reality-findings.js +84 -0
  100. package/bin/runners/lib/redact.js +29 -0
  101. package/bin/runners/lib/replay/capsule-manager.js +154 -0
  102. package/bin/runners/lib/replay/index.js +263 -0
  103. package/bin/runners/lib/replay/player.js +348 -0
  104. package/bin/runners/lib/replay/recorder.js +331 -0
  105. package/bin/runners/lib/report-engine.js +447 -0
  106. package/bin/runners/lib/report-html.js +1117 -0
  107. package/bin/runners/lib/report-templates.js +964 -0
  108. package/bin/runners/lib/route-detection.js +1140 -0
  109. package/bin/runners/lib/route-truth.js +477 -0
  110. package/bin/runners/lib/sandbox/index.js +59 -0
  111. package/bin/runners/lib/sandbox/proof-chain.js +399 -0
  112. package/bin/runners/lib/sandbox/sandbox-runner.js +205 -0
  113. package/bin/runners/lib/sandbox/worktree.js +174 -0
  114. package/bin/runners/lib/scan-cache.js +330 -0
  115. package/bin/runners/lib/scan-output-schema.js +344 -0
  116. package/bin/runners/lib/score-history.js +282 -0
  117. package/bin/runners/lib/security-bridge.js +249 -0
  118. package/bin/runners/lib/server-usage.js +513 -0
  119. package/bin/runners/lib/share-pack.js +239 -0
  120. package/bin/runners/lib/snippets.js +67 -0
  121. package/bin/runners/lib/truth.js +667 -0
  122. package/bin/runners/lib/unified-output.js +189 -0
  123. package/bin/runners/lib/validate-patch.js +156 -0
  124. package/bin/runners/lib/verification.js +345 -0
  125. package/bin/runners/reality/engine.js +917 -0
  126. package/bin/runners/reality/flows.js +122 -0
  127. package/bin/runners/reality/report.js +378 -0
  128. package/bin/runners/reality/session.js +193 -0
  129. package/bin/runners/runAIAgent.js +2 -0
  130. package/bin/runners/runAudit.js +2 -0
  131. package/bin/runners/runAuth.js +106 -0
  132. package/bin/runners/runAutopilot.js +2 -0
  133. package/bin/runners/runBadge.js +2 -0
  134. package/bin/runners/runCertify.js +2 -0
  135. package/bin/runners/runClaimVerifier.js +483 -0
  136. package/bin/runners/runContext.js +56 -0
  137. package/bin/runners/runContextCompiler.js +385 -0
  138. package/bin/runners/runCtx.js +187 -0
  139. package/bin/runners/runCtxGuard.js +176 -0
  140. package/bin/runners/runCtxSync.js +116 -0
  141. package/bin/runners/runDashboard.js +10 -0
  142. package/bin/runners/runDoctor.js +245 -0
  143. package/bin/runners/runEnhancedShip.js +2 -0
  144. package/bin/runners/runFix.js +735 -0
  145. package/bin/runners/runFixPacks.js +2 -0
  146. package/bin/runners/runGate.js +17 -0
  147. package/bin/runners/runGraph.js +283 -0
  148. package/bin/runners/runInit.js +260 -0
  149. package/bin/runners/runInitGha.js +101 -0
  150. package/bin/runners/runInstall.js +76 -0
  151. package/bin/runners/runInteractive.js +388 -0
  152. package/bin/runners/runLaunch.js +2 -0
  153. package/bin/runners/runMcp.js +19 -0
  154. package/bin/runners/runMdc.js +2 -0
  155. package/bin/runners/runMissionGenerator.js +282 -0
  156. package/bin/runners/runNaturalLanguage.js +3 -0
  157. package/bin/runners/runPR.js +96 -0
  158. package/bin/runners/runPermissions.js +290 -0
  159. package/bin/runners/runPromptFirewall.js +211 -0
  160. package/bin/runners/runProof.js +2 -0
  161. package/bin/runners/runProve.js +392 -0
  162. package/bin/runners/runReality.js +489 -0
  163. package/bin/runners/runRealitySniff.js +2 -0
  164. package/bin/runners/runReplay.js +469 -0
  165. package/bin/runners/runReport.js +478 -0
  166. package/bin/runners/runScan.js +835 -0
  167. package/bin/runners/runShare.js +34 -0
  168. package/bin/runners/runShip.js +1062 -0
  169. package/bin/runners/runStatus.js +136 -0
  170. package/bin/runners/runTruthpack.js +634 -0
  171. package/bin/runners/runUpgrade.js +2 -0
  172. package/bin/runners/runValidate.js +2 -0
  173. package/bin/runners/runVerifyAgentOutput.js +2 -0
  174. package/bin/runners/runWatch.js +230 -0
  175. package/bin/runners/utils.js +360 -0
  176. package/bin/scan.js +612 -0
  177. package/bin/vibecheck.js +834 -0
  178. package/package.json +11 -11
  179. package/dist/autopatch/verified-autopatch.d.ts +0 -111
  180. package/dist/autopatch/verified-autopatch.d.ts.map +0 -1
  181. package/dist/autopatch/verified-autopatch.js +0 -503
  182. package/dist/autopatch/verified-autopatch.js.map +0 -1
  183. package/dist/bundles/index.js +0 -8
  184. package/dist/bundles/vibecheck-core.js +0 -25799
  185. package/dist/bundles/vibecheck-security.js +0 -208693
  186. package/dist/bundles/vibecheck-ship.js +0 -2318
  187. package/dist/commands/baseline.d.ts +0 -7
  188. package/dist/commands/baseline.d.ts.map +0 -1
  189. package/dist/commands/baseline.js +0 -79
  190. package/dist/commands/baseline.js.map +0 -1
  191. package/dist/commands/cache.d.ts +0 -13
  192. package/dist/commands/cache.d.ts.map +0 -1
  193. package/dist/commands/cache.js +0 -165
  194. package/dist/commands/cache.js.map +0 -1
  195. package/dist/commands/checkpoint.d.ts +0 -8
  196. package/dist/commands/checkpoint.d.ts.map +0 -1
  197. package/dist/commands/checkpoint.js +0 -35
  198. package/dist/commands/checkpoint.js.map +0 -1
  199. package/dist/commands/doctor.d.ts +0 -17
  200. package/dist/commands/doctor.d.ts.map +0 -1
  201. package/dist/commands/doctor.js +0 -226
  202. package/dist/commands/doctor.js.map +0 -1
  203. package/dist/commands/evidence.d.ts +0 -45
  204. package/dist/commands/evidence.d.ts.map +0 -1
  205. package/dist/commands/evidence.js +0 -197
  206. package/dist/commands/evidence.js.map +0 -1
  207. package/dist/commands/explain.d.ts +0 -8
  208. package/dist/commands/explain.d.ts.map +0 -1
  209. package/dist/commands/explain.js +0 -52
  210. package/dist/commands/explain.js.map +0 -1
  211. package/dist/commands/fix-consolidated.d.ts +0 -19
  212. package/dist/commands/fix-consolidated.d.ts.map +0 -1
  213. package/dist/commands/fix-consolidated.js +0 -165
  214. package/dist/commands/fix-consolidated.js.map +0 -1
  215. package/dist/commands/index.d.ts +0 -8
  216. package/dist/commands/index.d.ts.map +0 -1
  217. package/dist/commands/index.js +0 -15
  218. package/dist/commands/index.js.map +0 -1
  219. package/dist/commands/init.d.ts +0 -8
  220. package/dist/commands/init.d.ts.map +0 -1
  221. package/dist/commands/init.js +0 -125
  222. package/dist/commands/init.js.map +0 -1
  223. package/dist/commands/launcher.d.ts +0 -10
  224. package/dist/commands/launcher.d.ts.map +0 -1
  225. package/dist/commands/launcher.js +0 -174
  226. package/dist/commands/launcher.js.map +0 -1
  227. package/dist/commands/on.d.ts +0 -8
  228. package/dist/commands/on.d.ts.map +0 -1
  229. package/dist/commands/on.js +0 -123
  230. package/dist/commands/on.js.map +0 -1
  231. package/dist/commands/replay.d.ts +0 -8
  232. package/dist/commands/replay.d.ts.map +0 -1
  233. package/dist/commands/replay.js +0 -52
  234. package/dist/commands/replay.js.map +0 -1
  235. package/dist/commands/scan-consolidated.d.ts +0 -61
  236. package/dist/commands/scan-consolidated.d.ts.map +0 -1
  237. package/dist/commands/scan-consolidated.js +0 -243
  238. package/dist/commands/scan-consolidated.js.map +0 -1
  239. package/dist/commands/scan-secrets.d.ts +0 -47
  240. package/dist/commands/scan-secrets.d.ts.map +0 -1
  241. package/dist/commands/scan-secrets.js +0 -225
  242. package/dist/commands/scan-secrets.js.map +0 -1
  243. package/dist/commands/scan-vulnerabilities-enhanced.d.ts +0 -41
  244. package/dist/commands/scan-vulnerabilities-enhanced.d.ts.map +0 -1
  245. package/dist/commands/scan-vulnerabilities-enhanced.js +0 -368
  246. package/dist/commands/scan-vulnerabilities-enhanced.js.map +0 -1
  247. package/dist/commands/scan-vulnerabilities-osv.d.ts +0 -58
  248. package/dist/commands/scan-vulnerabilities-osv.d.ts.map +0 -1
  249. package/dist/commands/scan-vulnerabilities-osv.js +0 -722
  250. package/dist/commands/scan-vulnerabilities-osv.js.map +0 -1
  251. package/dist/commands/scan-vulnerabilities.d.ts +0 -32
  252. package/dist/commands/scan-vulnerabilities.d.ts.map +0 -1
  253. package/dist/commands/scan-vulnerabilities.js +0 -283
  254. package/dist/commands/scan-vulnerabilities.js.map +0 -1
  255. package/dist/commands/secrets-allowlist.d.ts +0 -7
  256. package/dist/commands/secrets-allowlist.d.ts.map +0 -1
  257. package/dist/commands/secrets-allowlist.js +0 -85
  258. package/dist/commands/secrets-allowlist.js.map +0 -1
  259. package/dist/commands/ship-consolidated.d.ts +0 -58
  260. package/dist/commands/ship-consolidated.d.ts.map +0 -1
  261. package/dist/commands/ship-consolidated.js +0 -515
  262. package/dist/commands/ship-consolidated.js.map +0 -1
  263. package/dist/commands/stats.d.ts +0 -8
  264. package/dist/commands/stats.d.ts.map +0 -1
  265. package/dist/commands/stats.js +0 -134
  266. package/dist/commands/stats.js.map +0 -1
  267. package/dist/commands/upgrade.d.ts +0 -8
  268. package/dist/commands/upgrade.d.ts.map +0 -1
  269. package/dist/commands/upgrade.js +0 -30
  270. package/dist/commands/upgrade.js.map +0 -1
  271. package/dist/fix/applicator.d.ts +0 -44
  272. package/dist/fix/applicator.d.ts.map +0 -1
  273. package/dist/fix/applicator.js +0 -144
  274. package/dist/fix/applicator.js.map +0 -1
  275. package/dist/fix/backup.d.ts +0 -38
  276. package/dist/fix/backup.d.ts.map +0 -1
  277. package/dist/fix/backup.js +0 -154
  278. package/dist/fix/backup.js.map +0 -1
  279. package/dist/fix/engine.d.ts +0 -55
  280. package/dist/fix/engine.d.ts.map +0 -1
  281. package/dist/fix/engine.js +0 -285
  282. package/dist/fix/engine.js.map +0 -1
  283. package/dist/fix/index.d.ts +0 -5
  284. package/dist/fix/index.d.ts.map +0 -1
  285. package/dist/fix/index.js +0 -12
  286. package/dist/fix/index.js.map +0 -1
  287. package/dist/fix/interactive.d.ts +0 -22
  288. package/dist/fix/interactive.d.ts.map +0 -1
  289. package/dist/fix/interactive.js +0 -172
  290. package/dist/fix/interactive.js.map +0 -1
  291. package/dist/formatters/index.d.ts +0 -6
  292. package/dist/formatters/index.d.ts.map +0 -1
  293. package/dist/formatters/index.js +0 -11
  294. package/dist/formatters/index.js.map +0 -1
  295. package/dist/formatters/sarif-enhanced.d.ts +0 -78
  296. package/dist/formatters/sarif-enhanced.d.ts.map +0 -1
  297. package/dist/formatters/sarif-enhanced.js +0 -144
  298. package/dist/formatters/sarif-enhanced.js.map +0 -1
  299. package/dist/formatters/sarif-v2.d.ts +0 -121
  300. package/dist/formatters/sarif-v2.d.ts.map +0 -1
  301. package/dist/formatters/sarif-v2.js +0 -356
  302. package/dist/formatters/sarif-v2.js.map +0 -1
  303. package/dist/formatters/sarif.d.ts +0 -72
  304. package/dist/formatters/sarif.d.ts.map +0 -1
  305. package/dist/formatters/sarif.js +0 -146
  306. package/dist/formatters/sarif.js.map +0 -1
  307. package/dist/index.d.ts +0 -61
  308. package/dist/index.d.ts.map +0 -1
  309. package/dist/index.js +0 -4388
  310. package/dist/index.js.map +0 -1
  311. package/dist/init/ci-generator.d.ts +0 -18
  312. package/dist/init/ci-generator.d.ts.map +0 -1
  313. package/dist/init/ci-generator.js +0 -317
  314. package/dist/init/ci-generator.js.map +0 -1
  315. package/dist/init/detect-framework.d.ts +0 -15
  316. package/dist/init/detect-framework.d.ts.map +0 -1
  317. package/dist/init/detect-framework.js +0 -301
  318. package/dist/init/detect-framework.js.map +0 -1
  319. package/dist/init/hooks-installer.d.ts +0 -22
  320. package/dist/init/hooks-installer.d.ts.map +0 -1
  321. package/dist/init/hooks-installer.js +0 -310
  322. package/dist/init/hooks-installer.js.map +0 -1
  323. package/dist/init/index.d.ts +0 -8
  324. package/dist/init/index.d.ts.map +0 -1
  325. package/dist/init/index.js +0 -22
  326. package/dist/init/index.js.map +0 -1
  327. package/dist/init/templates.d.ts +0 -402
  328. package/dist/init/templates.d.ts.map +0 -1
  329. package/dist/init/templates.js +0 -240
  330. package/dist/init/templates.js.map +0 -1
  331. package/dist/mcp/server.d.ts +0 -12
  332. package/dist/mcp/server.d.ts.map +0 -1
  333. package/dist/mcp/server.js +0 -42
  334. package/dist/mcp/server.js.map +0 -1
  335. package/dist/mcp/telemetry.d.ts +0 -40
  336. package/dist/mcp/telemetry.d.ts.map +0 -1
  337. package/dist/mcp/telemetry.js +0 -98
  338. package/dist/mcp/telemetry.js.map +0 -1
  339. package/dist/reality/no-dead-buttons/button-sweep-generator.d.ts +0 -32
  340. package/dist/reality/no-dead-buttons/button-sweep-generator.d.ts.map +0 -1
  341. package/dist/reality/no-dead-buttons/button-sweep-generator.js +0 -236
  342. package/dist/reality/no-dead-buttons/button-sweep-generator.js.map +0 -1
  343. package/dist/reality/no-dead-buttons/index.d.ts +0 -11
  344. package/dist/reality/no-dead-buttons/index.d.ts.map +0 -1
  345. package/dist/reality/no-dead-buttons/index.js +0 -18
  346. package/dist/reality/no-dead-buttons/index.js.map +0 -1
  347. package/dist/reality/no-dead-buttons/static-scanner.d.ts +0 -34
  348. package/dist/reality/no-dead-buttons/static-scanner.d.ts.map +0 -1
  349. package/dist/reality/no-dead-buttons/static-scanner.js +0 -230
  350. package/dist/reality/no-dead-buttons/static-scanner.js.map +0 -1
  351. package/dist/reality/reality-graph.d.ts +0 -192
  352. package/dist/reality/reality-graph.d.ts.map +0 -1
  353. package/dist/reality/reality-graph.js +0 -600
  354. package/dist/reality/reality-graph.js.map +0 -1
  355. package/dist/reality/reality-runner.d.ts +0 -89
  356. package/dist/reality/reality-runner.d.ts.map +0 -1
  357. package/dist/reality/reality-runner.js +0 -540
  358. package/dist/reality/reality-runner.js.map +0 -1
  359. package/dist/reality/receipt-generator.d.ts +0 -152
  360. package/dist/reality/receipt-generator.d.ts.map +0 -1
  361. package/dist/reality/receipt-generator.js +0 -495
  362. package/dist/reality/receipt-generator.js.map +0 -1
  363. package/dist/reality/runtime-tracer.d.ts +0 -75
  364. package/dist/reality/runtime-tracer.d.ts.map +0 -1
  365. package/dist/reality/runtime-tracer.js +0 -109
  366. package/dist/reality/runtime-tracer.js.map +0 -1
  367. package/dist/runtime/auth-utils.d.ts +0 -43
  368. package/dist/runtime/auth-utils.d.ts.map +0 -1
  369. package/dist/runtime/auth-utils.js +0 -130
  370. package/dist/runtime/auth-utils.js.map +0 -1
  371. package/dist/runtime/client.d.ts +0 -74
  372. package/dist/runtime/client.d.ts.map +0 -1
  373. package/dist/runtime/client.js +0 -222
  374. package/dist/runtime/client.js.map +0 -1
  375. package/dist/runtime/creds.d.ts +0 -48
  376. package/dist/runtime/creds.d.ts.map +0 -1
  377. package/dist/runtime/creds.js +0 -245
  378. package/dist/runtime/creds.js.map +0 -1
  379. package/dist/runtime/exit-codes.d.ts +0 -49
  380. package/dist/runtime/exit-codes.d.ts.map +0 -1
  381. package/dist/runtime/exit-codes.js +0 -93
  382. package/dist/runtime/exit-codes.js.map +0 -1
  383. package/dist/runtime/index.d.ts +0 -9
  384. package/dist/runtime/index.d.ts.map +0 -1
  385. package/dist/runtime/index.js +0 -25
  386. package/dist/runtime/index.js.map +0 -1
  387. package/dist/runtime/json-output.d.ts +0 -42
  388. package/dist/runtime/json-output.d.ts.map +0 -1
  389. package/dist/runtime/json-output.js +0 -59
  390. package/dist/runtime/json-output.js.map +0 -1
  391. package/dist/runtime/semver.d.ts +0 -37
  392. package/dist/runtime/semver.d.ts.map +0 -1
  393. package/dist/runtime/semver.js +0 -110
  394. package/dist/runtime/semver.js.map +0 -1
  395. package/dist/scan/dead-ui-detector.d.ts +0 -48
  396. package/dist/scan/dead-ui-detector.d.ts.map +0 -1
  397. package/dist/scan/dead-ui-detector.js +0 -170
  398. package/dist/scan/dead-ui-detector.js.map +0 -1
  399. package/dist/scan/playwright-sweep.d.ts +0 -40
  400. package/dist/scan/playwright-sweep.d.ts.map +0 -1
  401. package/dist/scan/playwright-sweep.js +0 -216
  402. package/dist/scan/playwright-sweep.js.map +0 -1
  403. package/dist/scan/proof-bundle.d.ts +0 -25
  404. package/dist/scan/proof-bundle.d.ts.map +0 -1
  405. package/dist/scan/proof-bundle.js +0 -203
  406. package/dist/scan/proof-bundle.js.map +0 -1
  407. package/dist/scan/proof-graph.d.ts +0 -59
  408. package/dist/scan/proof-graph.d.ts.map +0 -1
  409. package/dist/scan/proof-graph.js +0 -64
  410. package/dist/scan/proof-graph.js.map +0 -1
  411. package/dist/scan/reality-sniff.d.ts +0 -56
  412. package/dist/scan/reality-sniff.d.ts.map +0 -1
  413. package/dist/scan/reality-sniff.js +0 -200
  414. package/dist/scan/reality-sniff.js.map +0 -1
  415. package/dist/scan/structural-verifier.d.ts +0 -20
  416. package/dist/scan/structural-verifier.d.ts.map +0 -1
  417. package/dist/scan/structural-verifier.js +0 -112
  418. package/dist/scan/structural-verifier.js.map +0 -1
  419. package/dist/scan/verification-engine.d.ts +0 -47
  420. package/dist/scan/verification-engine.d.ts.map +0 -1
  421. package/dist/scan/verification-engine.js +0 -141
  422. package/dist/scan/verification-engine.js.map +0 -1
  423. package/dist/scanner/baseline.d.ts +0 -52
  424. package/dist/scanner/baseline.d.ts.map +0 -1
  425. package/dist/scanner/baseline.js +0 -85
  426. package/dist/scanner/baseline.js.map +0 -1
  427. package/dist/scanner/incremental.d.ts +0 -30
  428. package/dist/scanner/incremental.d.ts.map +0 -1
  429. package/dist/scanner/incremental.js +0 -82
  430. package/dist/scanner/incremental.js.map +0 -1
  431. package/dist/scanner/parallel.d.ts +0 -43
  432. package/dist/scanner/parallel.d.ts.map +0 -1
  433. package/dist/scanner/parallel.js +0 -99
  434. package/dist/scanner/parallel.js.map +0 -1
  435. package/dist/standalone.d.ts +0 -1
  436. package/dist/standalone.d.ts.map +0 -1
  437. package/dist/standalone.js +0 -1
  438. package/dist/standalone.js.map +0 -1
  439. package/dist/truth-pack/index.d.ts +0 -102
  440. package/dist/truth-pack/index.d.ts.map +0 -1
  441. package/dist/truth-pack/index.js +0 -694
  442. package/dist/truth-pack/index.js.map +0 -1
  443. package/dist/ui/frame.d.ts +0 -68
  444. package/dist/ui/frame.d.ts.map +0 -1
  445. package/dist/ui/frame.js +0 -165
  446. package/dist/ui/frame.js.map +0 -1
  447. package/dist/ui/index.d.ts +0 -5
  448. package/dist/ui/index.d.ts.map +0 -1
  449. package/dist/ui/index.js +0 -16
  450. package/dist/ui/index.js.map +0 -1
  451. package/dist/ui.d.ts +0 -36
  452. package/dist/ui.d.ts.map +0 -1
  453. package/dist/ui.js +0 -45
  454. package/dist/ui.js.map +0 -1
@@ -0,0 +1,541 @@
1
+ // bin/runners/lib/analyzers.js
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+ const fg = require("fast-glob");
5
+ const crypto = require("crypto");
6
+ const parser = require("@babel/parser");
7
+ const traverse = require("@babel/traverse").default;
8
+ const t = require("@babel/types");
9
+ const { routeMatches } = require("./claims");
10
+ const { matcherCoversPath } = require("./auth-truth");
11
+
12
+ function sha256(text) {
13
+ return "sha256:" + crypto.createHash("sha256").update(text).digest("hex");
14
+ }
15
+
16
+ function parseFile(code) {
17
+ return parser.parse(code, { sourceType: "unambiguous", plugins: ["typescript", "jsx"] });
18
+ }
19
+
20
+ function evidenceFromLoc(fileAbs, repoRoot, loc, reason) {
21
+ if (!loc) return null;
22
+ const fileRel = path.relative(repoRoot, fileAbs).replace(/\\/g, "/");
23
+ const lines = fs.readFileSync(fileAbs, "utf8").split(/\r?\n/);
24
+ const start = Math.max(1, loc.start?.line || 1);
25
+ const end = Math.max(start, loc.end?.line || start);
26
+ const snippet = lines.slice(start - 1, end).join("\n");
27
+ return { id: `ev_${crypto.randomBytes(4).toString("hex")}`, file: fileRel, lines: `${start}-${end}`, snippetHash: sha256(snippet), reason };
28
+ }
29
+
30
+ function findMissingRoutes(truthpack) {
31
+ const findings = [];
32
+ const server = truthpack.routes.server || [];
33
+ const refs = truthpack.routes.clientRefs || [];
34
+ const gaps = truthpack.routes.gaps || [];
35
+
36
+ // If we have route detection gaps, be less aggressive with BLOCKs
37
+ const hasGaps = gaps.length > 0;
38
+
39
+ // Build a set of known route path prefixes for smarter matching
40
+ const knownPrefixes = new Set();
41
+ for (const r of server) {
42
+ const parts = r.path.split('/').filter(Boolean);
43
+ if (parts.length >= 2) {
44
+ knownPrefixes.add('/' + parts[0] + '/' + parts[1]);
45
+ }
46
+ if (parts.length >= 1) {
47
+ knownPrefixes.add('/' + parts[0]);
48
+ }
49
+ }
50
+
51
+ for (const ref of refs) {
52
+ const method = ref.method || "*";
53
+ const p = ref.path;
54
+
55
+ const ok = server.some(r => routeMatches(r, method, p) || routeMatches(r, "*", p));
56
+ if (ok) continue;
57
+
58
+ // Check if route shares a prefix with known routes (might be undetected sibling)
59
+ const refParts = p.split('/').filter(Boolean);
60
+ const refPrefix1 = refParts.length >= 1 ? '/' + refParts[0] : '/';
61
+ const refPrefix2 = refParts.length >= 2 ? '/' + refParts[0] + '/' + refParts[1] : refPrefix1;
62
+ const sharesPrefix = knownPrefixes.has(refPrefix1) || knownPrefixes.has(refPrefix2);
63
+
64
+ // Determine severity based on confidence and context
65
+ // In monorepos with complex routing (plugins, dynamic registration), static analysis has limits
66
+ // Default to WARN unless we're very confident the route is truly invented
67
+ let severity = "WARN";
68
+
69
+ // Only BLOCK if:
70
+ // 1. High confidence client ref
71
+ // 2. No detection gaps
72
+ // 3. Doesn't share prefix with any known route
73
+ // 4. Looks like an invented/hallucinated route (unusual patterns)
74
+ const looksInvented = /\/(fake|test|mock|dummy|example|foo|bar|baz|xxx|yyy|placeholder)/i.test(p);
75
+ if (ref.confidence === "high" && !hasGaps && !sharesPrefix && looksInvented) {
76
+ severity = "BLOCK";
77
+ }
78
+
79
+ // Always WARN for common internal/utility routes
80
+ const isInternalRoute = /^\/(health|metrics|ready|live|version|debug|internal|suggestions|security|analyze|websocket|dashboard)/.test(p);
81
+ if (isInternalRoute) {
82
+ severity = "WARN";
83
+ }
84
+
85
+ findings.push({
86
+ id: `F_MISSING_ROUTE_${String(findings.length + 1).padStart(3, "0")}`,
87
+ severity,
88
+ category: "MissingRoute",
89
+ title: `Client references route that does not exist: ${method} ${p}`,
90
+ why: severity === "BLOCK"
91
+ ? "AI frequently invents endpoints. Shipping this = broken flows (404 / silent failure)."
92
+ : "Route reference found but server route not detected. May be a false positive if route is defined dynamically.",
93
+ confidence: ref.confidence || "low",
94
+ evidence: ref.evidence || [],
95
+ fixHints: [
96
+ "Update the client call to a real server route (see route map).",
97
+ "If the route exists but wasn't detected, it may use dynamic registration.",
98
+ "If truly missing, implement it in your API and re-run ship."
99
+ ]
100
+ });
101
+ }
102
+
103
+ // If route scan had gaps, add a WARN so users know why some routes may be unknown
104
+ if (hasGaps) {
105
+ findings.push({
106
+ id: `F_ROUTE_MAP_GAPS_001`,
107
+ severity: "WARN",
108
+ category: "RouteMapGaps",
109
+ title: `Route map incomplete (${gaps.length} unresolved sources)`,
110
+ why: "Some routes may not be detected due to dynamic registration or unresolved plugins.",
111
+ confidence: "low",
112
+ evidence: [],
113
+ fixHints: [
114
+ "Routes registered dynamically or via unresolved imports may not be detected.",
115
+ "Consider using explicit route registration for better static analysis.",
116
+ "Run with --verbose to see detection gaps."
117
+ ]
118
+ });
119
+ }
120
+
121
+ return findings;
122
+ }
123
+
124
+ // ============================================================================
125
+ // ENV GAPS ANALYZER
126
+ // ============================================================================
127
+
128
+ function findEnvGaps(truthpack) {
129
+ const findings = [];
130
+ const used = truthpack?.env?.vars || [];
131
+ const declared = new Set(truthpack?.env?.declared || []);
132
+ const declaredSources = truthpack?.env?.declaredSources || [];
133
+
134
+ // 1) USED but not declared in templates/examples => WARN (or BLOCK if required)
135
+ for (const v of used) {
136
+ if (declared.has(v.name)) continue;
137
+
138
+ const sev = v.required ? "BLOCK" : "WARN";
139
+ findings.push({
140
+ id: `F_ENV_UNDECLARED_${v.name}`,
141
+ severity: sev,
142
+ category: "EnvContract",
143
+ title: `Env var used but not declared in env templates: ${v.name}`,
144
+ why: v.required
145
+ ? "Required env var is used with no fallback. Vibecoders will ship a broken app if it's not documented."
146
+ : "Env var appears optional but should still be documented to prevent guesswork.",
147
+ confidence: "high",
148
+ evidence: v.references || [],
149
+ fixHints: [
150
+ `Add ${v.name}= to .env.example (or .env.template).`,
151
+ "If it's truly optional, ensure the code has an explicit fallback or guard."
152
+ ]
153
+ });
154
+ }
155
+
156
+ // 2) Declared but never used => WARN (hygiene)
157
+ const usedSet = new Set(used.map(v => v.name));
158
+ for (const name of declared) {
159
+ if (usedSet.has(name)) continue;
160
+
161
+ findings.push({
162
+ id: `F_ENV_UNUSED_${name}`,
163
+ severity: "WARN",
164
+ category: "EnvContract",
165
+ title: `Env var declared but never used: ${name}`,
166
+ why: "Dead config creates confusion and encourages hallucinated wiring.",
167
+ confidence: "med",
168
+ evidence: [],
169
+ fixHints: [
170
+ "Remove it from templates if it's obsolete, or wire it into code intentionally.",
171
+ "If used at runtime only (in infra), document that explicitly."
172
+ ]
173
+ });
174
+ }
175
+
176
+ // 3) If no template sources exist, warn loudly
177
+ if (!declaredSources.length && used.length) {
178
+ findings.push({
179
+ id: "F_ENV_NO_TEMPLATE",
180
+ severity: "WARN",
181
+ category: "EnvContract",
182
+ title: "No .env.example/.env.template found",
183
+ why: "Without an env contract file, AI and humans will guess env vars and ship broken setups.",
184
+ confidence: "high",
185
+ evidence: [],
186
+ fixHints: ["Add a .env.example that lists required/optional vars with comments."]
187
+ });
188
+ }
189
+
190
+ return findings;
191
+ }
192
+
193
+ // ============================================================================
194
+ // FAKE SUCCESS ANALYZER (INV_NO_FAKE_SUCCESS)
195
+ // ============================================================================
196
+
197
+ function isToastSuccessCall(node) {
198
+ return t.isCallExpression(node) &&
199
+ t.isMemberExpression(node.callee) &&
200
+ t.isIdentifier(node.callee.object, { name: "toast" }) &&
201
+ t.isIdentifier(node.callee.property, { name: "success" });
202
+ }
203
+
204
+ function isRouterPushCall(node) {
205
+ return t.isCallExpression(node) && (
206
+ (t.isMemberExpression(node.callee) &&
207
+ t.isIdentifier(node.callee.property, { name: "push" })) ||
208
+ (t.isIdentifier(node.callee) && (node.callee.name === "navigate"))
209
+ );
210
+ }
211
+
212
+ function isFetchCall(node) {
213
+ return t.isCallExpression(node) && t.isIdentifier(node.callee, { name: "fetch" });
214
+ }
215
+
216
+ function isAxiosCall(node) {
217
+ return t.isCallExpression(node) &&
218
+ t.isMemberExpression(node.callee) &&
219
+ t.isIdentifier(node.callee.object, { name: "axios" }) &&
220
+ t.isIdentifier(node.callee.property) &&
221
+ ["get","post","put","patch","delete"].includes(node.callee.property.name);
222
+ }
223
+
224
+ function findFakeSuccess(repoRoot) {
225
+ const findings = [];
226
+ const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
227
+ cwd: repoRoot,
228
+ absolute: true,
229
+ ignore: ["**/node_modules/**","**/.next/**","**/dist/**","**/build/**"]
230
+ });
231
+
232
+ for (const fileAbs of files) {
233
+ const code = fs.readFileSync(fileAbs, "utf8");
234
+ let ast;
235
+ try { ast = parseFile(code); } catch { continue; }
236
+
237
+ traverse(ast, {
238
+ Function(pathFn) {
239
+ let hasSuccess = false;
240
+ let successLoc = null;
241
+ let hasNetwork = false;
242
+ let hasAwaitNetwork = false;
243
+ let hasOkCheck = false;
244
+
245
+ pathFn.traverse({
246
+ CallExpression(p) {
247
+ const n = p.node;
248
+
249
+ if (isToastSuccessCall(n) || isRouterPushCall(n)) {
250
+ hasSuccess = true;
251
+ successLoc = successLoc || n.loc;
252
+ }
253
+
254
+ if (isFetchCall(n) || isAxiosCall(n)) {
255
+ hasNetwork = true;
256
+ if (p.parentPath && p.parentPath.isAwaitExpression()) hasAwaitNetwork = true;
257
+ }
258
+ },
259
+ IfStatement(p) {
260
+ const test = p.node.test;
261
+ const text = code.slice(test.start || 0, test.end || 0);
262
+ if (/\b(ok|status)\b/.test(text) && /(res|response)/.test(text)) {
263
+ hasOkCheck = true;
264
+ }
265
+ }
266
+ });
267
+
268
+ if (!hasSuccess || !hasNetwork) return;
269
+
270
+ const severity = hasAwaitNetwork ? (hasOkCheck ? null : "WARN") : "BLOCK";
271
+ if (!severity) return;
272
+
273
+ const ev = evidenceFromLoc(fileAbs, repoRoot, successLoc, "Success UI call in networked flow");
274
+ findings.push({
275
+ id: `F_FAKE_SUCCESS_${String(findings.length + 1).padStart(3, "0")}`,
276
+ severity,
277
+ category: "FakeSuccess",
278
+ title: severity === "BLOCK"
279
+ ? "Success UI triggered without awaiting network call"
280
+ : "Success UI triggered without verifying network result (res.ok/status)",
281
+ why: severity === "BLOCK"
282
+ ? "This ships lies. Users see success even when the request never completed."
283
+ : "This often ships lies. You're not gating success on a real response.",
284
+ confidence: "med",
285
+ evidence: ev ? [ev] : [],
286
+ fixHints: [
287
+ "Await the network call (await fetch/await axios...).",
288
+ "Gate success UI behind res.ok / status checks; surface errors otherwise."
289
+ ]
290
+ });
291
+ }
292
+ });
293
+ }
294
+
295
+ return findings;
296
+ }
297
+
298
+ // ============================================================================
299
+ // GHOST AUTH ANALYZER (INV_NO_GHOST_AUTH)
300
+ // ============================================================================
301
+
302
+ function looksSensitive(pathStr) {
303
+ const p = String(pathStr || "");
304
+ return (
305
+ p.startsWith("/api/admin") ||
306
+ p.startsWith("/api/billing") ||
307
+ p.startsWith("/api/stripe") ||
308
+ p.startsWith("/api/org") ||
309
+ p.startsWith("/api/team") ||
310
+ p.startsWith("/api/account") ||
311
+ p.startsWith("/api/settings") ||
312
+ p.startsWith("/api/users") ||
313
+ p.startsWith("/api/user")
314
+ );
315
+ }
316
+
317
+ function hasRouteLevelProtection(routeDef) {
318
+ const hooks = routeDef.hooks || [];
319
+ if (hooks.includes("preHandler") || hooks.includes("onRequest") || hooks.includes("preValidation")) return true;
320
+ return false;
321
+ }
322
+
323
+ function handlerHasAuthSignal(repoRoot, handlerRel) {
324
+ const abs = path.join(repoRoot, handlerRel);
325
+ if (!fs.existsSync(abs)) return false;
326
+ const code = fs.readFileSync(abs, "utf8");
327
+
328
+ return (
329
+ /\bgetServerSession\b|\bauth\(\)\b|\bclerk\b|@clerk\/nextjs|\bcreateRouteHandlerClient\b|@supabase/i.test(code) ||
330
+ /\b(jwtVerify|authorization|bearer|verifyToken|verifyJWT)\b/i.test(code) ||
331
+ /\b(isAdmin|adminOnly|permissions|rbac)\b/i.test(code)
332
+ );
333
+ }
334
+
335
+ function isProtectedByNextMiddleware(truthpack, routePath) {
336
+ const patterns = truthpack?.auth?.nextMatcherPatterns || [];
337
+ return matcherCoversPath(patterns, routePath);
338
+ }
339
+
340
+ function findGhostAuth(truthpack, repoRoot) {
341
+ const findings = [];
342
+ const server = truthpack?.routes?.server || [];
343
+
344
+ for (const r of server) {
345
+ if (!looksSensitive(r.path)) continue;
346
+
347
+ const middlewareProtected = isProtectedByNextMiddleware(truthpack, r.path);
348
+ const routeHooksProtected = hasRouteLevelProtection(r);
349
+ const handlerProtected = r.handler ? handlerHasAuthSignal(repoRoot, r.handler) : false;
350
+
351
+ const protectedSomehow = middlewareProtected || routeHooksProtected || handlerProtected;
352
+
353
+ if (!protectedSomehow) {
354
+ findings.push({
355
+ id: `F_GHOST_AUTH_${r.method}_${r.path}`.replace(/[^A-Z0-9_\/:*-]/gi, "_"),
356
+ severity: "BLOCK",
357
+ category: "GhostAuth",
358
+ title: `Sensitive endpoint appears unprotected: ${r.method} ${r.path}`,
359
+ why: "This is how apps get owned. UI gating doesn't matter. If the server doesn't enforce auth, it's public.",
360
+ confidence: "med",
361
+ evidence: (r.evidence || []).slice(0, 2),
362
+ fixHints: [
363
+ "Add server-side auth verification in the handler (session/jwt).",
364
+ "Or protect the path via Next middleware matcher (and verify it actually applies).",
365
+ "If Fastify: add preHandler/onRequest auth hook and ensure it's registered for this route."
366
+ ]
367
+ });
368
+ }
369
+ }
370
+
371
+ // If there IS middleware but it doesn't cover obvious sensitive prefixes, warn
372
+ const patterns = truthpack?.auth?.nextMatcherPatterns || [];
373
+ if (patterns.length) {
374
+ const coversApi = patterns.some(p => String(p).includes("/api"));
375
+ if (!coversApi) {
376
+ findings.push({
377
+ id: "F_MIDDLEWARE_NOT_COVERING_API",
378
+ severity: "WARN",
379
+ category: "GhostAuth",
380
+ title: "Next middleware exists but does not appear to cover /api routes",
381
+ why: "People assume middleware protects APIs. Often it doesn't. Verify matcher patterns.",
382
+ confidence: "high",
383
+ evidence: (truthpack?.auth?.nextMiddleware?.[0]?.evidence || []).slice(0, 3),
384
+ fixHints: ["Add /api/:path* to middleware matcher if your design expects API auth protection."]
385
+ });
386
+ }
387
+ }
388
+
389
+ return findings;
390
+ }
391
+
392
+ // ============================================================================
393
+ // STRIPE WEBHOOK VIOLATIONS (INV_WEBHOOK_VERIFIED + INV_WEBHOOK_IDEMPOTENT)
394
+ // ============================================================================
395
+
396
+ function findStripeWebhookViolations(truthpack) {
397
+ const findings = [];
398
+ const billing = truthpack?.billing;
399
+
400
+ if (!billing?.hasStripe) return findings;
401
+
402
+ const candidates = billing.webhookCandidates || [];
403
+
404
+ if (!candidates.length) {
405
+ findings.push({
406
+ id: "F_STRIPE_NO_WEBHOOK_HANDLER",
407
+ severity: "WARN",
408
+ category: "Billing",
409
+ title: "Stripe appears used but no webhook handler candidate detected",
410
+ why: "If you bill with Stripe, webhooks are usually required. Missing webhooks often means subscription state desync.",
411
+ confidence: "med",
412
+ evidence: [],
413
+ fixHints: ["Add a Stripe webhook handler with signature verification and idempotency."]
414
+ });
415
+ return findings;
416
+ }
417
+
418
+ for (const w of candidates) {
419
+ const verified = w.signals.webhookConstructEvent && w.signals.rawBodySignal && w.signals.readsStripeSignatureHeader;
420
+ const idempotent = !!w.signals.idempotencySignal;
421
+
422
+ if (!verified) {
423
+ findings.push({
424
+ id: `F_STRIPE_WEBHOOK_NOT_VERIFIED_${w.file.replace(/[^a-z0-9]/gi, "_")}`,
425
+ severity: "BLOCK",
426
+ category: "Billing",
427
+ title: `Stripe webhook handler not clearly signature-verified: ${w.file}`,
428
+ why: "Unverified webhooks = spoofable billing state. That's catastrophic.",
429
+ confidence: "high",
430
+ evidence: (w.evidence || []).slice(0, 4),
431
+ fixHints: [
432
+ "Use stripe.webhooks.constructEvent(rawBody, sigHeader, STRIPE_WEBHOOK_SECRET).",
433
+ "Ensure raw body is used (disable bodyParser in pages router; in app router read req.text()/arrayBuffer).",
434
+ "Reject if signature missing/invalid."
435
+ ]
436
+ });
437
+ }
438
+
439
+ if (!idempotent) {
440
+ findings.push({
441
+ id: `F_STRIPE_WEBHOOK_NOT_IDEMPOTENT_${w.file.replace(/[^a-z0-9]/gi, "_")}`,
442
+ severity: "BLOCK",
443
+ category: "Billing",
444
+ title: `Stripe webhook handler not clearly idempotent: ${w.file}`,
445
+ why: "Stripe retries webhooks. Without dedupe, you'll double-grant access, double-send emails, or double-write state.",
446
+ confidence: "med",
447
+ evidence: (w.evidence || []).slice(0, 4),
448
+ fixHints: [
449
+ "Persist event.id as processed (DB/Redis). If seen, return 200 immediately.",
450
+ "Wrap state mutation in a transaction keyed by event.id."
451
+ ]
452
+ });
453
+ }
454
+ }
455
+
456
+ return findings;
457
+ }
458
+
459
+ // ============================================================================
460
+ // PAID SURFACE NOT ENFORCED (INV_PAID_FEATURE_ENFORCED_SERVER_SIDE)
461
+ // ============================================================================
462
+
463
+ function findPaidSurfaceNotEnforced(truthpack) {
464
+ const findings = [];
465
+ const enforcement = truthpack?.enforcement;
466
+
467
+ const checks = enforcement?.checks || [];
468
+ for (const c of checks) {
469
+ if (c.enforced) continue;
470
+
471
+ findings.push({
472
+ id: `F_PAID_SURFACE_NOT_ENFORCED_${c.method}_${c.path}`.replace(/[^a-z0-9]/gi, "_"),
473
+ severity: "BLOCK",
474
+ category: "Entitlements",
475
+ title: `Paid surface appears un-enforced server-side: ${c.method} ${c.path}`,
476
+ why: "If enforcement is only in the CLI/UI, users can call the endpoint directly. That's a free enterprise bypass.",
477
+ confidence: "med",
478
+ evidence: [],
479
+ fixHints: [
480
+ "Add enforceFeature/enforceLimit in the server handler BEFORE doing work.",
481
+ "Return 402/403 with a structured error code.",
482
+ "Make the CLI treat that code as an upgrade prompt."
483
+ ]
484
+ });
485
+ }
486
+ return findings;
487
+ }
488
+
489
+ // ============================================================================
490
+ // OWNER MODE BYPASS (INV_NO_OWNER_MODE_BYPASS)
491
+ // ============================================================================
492
+
493
+ function findOwnerModeBypass(repoRoot) {
494
+ const findings = [];
495
+ const files = fg.sync(["**/*.{ts,tsx,js,jsx}"], {
496
+ cwd: repoRoot,
497
+ absolute: true,
498
+ ignore: ["**/node_modules/**","**/.next/**","**/dist/**","**/build/**"]
499
+ });
500
+
501
+ const patterns = [
502
+ /OWNER_MODE/i,
503
+ /GUARDRAIL_OWNER_MODE/i,
504
+ /VIBECHECK_OWNER_MODE/i,
505
+ /process\.env\.[A-Z0-9_]*OWNER[A-Z0-9_]*/i
506
+ ];
507
+
508
+ for (const fileAbs of files) {
509
+ const code = fs.readFileSync(fileAbs, "utf8");
510
+ const hit = patterns.some(rx => rx.test(code));
511
+ if (!hit) continue;
512
+
513
+ const fileRel = path.relative(repoRoot, fileAbs).replace(/\\/g, "/");
514
+
515
+ findings.push({
516
+ id: `F_OWNER_MODE_BYPASS_${fileRel.replace(/[^a-z0-9]/gi, "_")}`,
517
+ severity: "BLOCK",
518
+ category: "Security",
519
+ title: `Owner mode / env bypass signal detected: ${fileRel}`,
520
+ why: "This is a production backdoor unless it's cryptographically gated. It cannot ship.",
521
+ confidence: "high",
522
+ evidence: [],
523
+ fixHints: [
524
+ "Delete owner mode bypass. If you need dev override, require a signed admin token + non-prod environment.",
525
+ "Add a test that asserts no OWNER_MODE env var grants entitlements."
526
+ ]
527
+ });
528
+ }
529
+
530
+ return findings;
531
+ }
532
+
533
+ module.exports = {
534
+ findMissingRoutes,
535
+ findEnvGaps,
536
+ findFakeSuccess,
537
+ findGhostAuth,
538
+ findStripeWebhookViolations,
539
+ findPaidSurfaceNotEnforced,
540
+ findOwnerModeBypass
541
+ };