@prisma/orm-toolchain 8.0.0-rc.1-dev.38 → 8.0.0-rc.1-dev.40

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 (171) hide show
  1. package/dist/bin__prisma-next.mjs +25 -318
  2. package/dist/bin__prisma-next.mjs.map +1 -1
  3. package/dist/{caught-errors-DLPzfzIW-CQ9BoXD-.mjs → caught-errors-BZo7zcRc-C-pIEasG.mjs} +3 -3
  4. package/dist/{caught-errors-DLPzfzIW-CQ9BoXD-.mjs.map → caught-errors-BZo7zcRc-C-pIEasG.mjs.map} +1 -1
  5. package/dist/{cli-errors-BG6bItjG-DwdKIeGz.mjs → cli-errors-B4zTLaqQ-CXgjO9t4.mjs} +20 -3
  6. package/dist/cli-errors-B4zTLaqQ-CXgjO9t4.mjs.map +1 -0
  7. package/dist/{cli-errors-BiKBrOXc-JPxQqO58.d.mts → cli-errors-iquUoY6O-BFboxglv.d.mts} +17 -9
  8. package/dist/cli-errors-iquUoY6O-BFboxglv.d.mts.map +1 -0
  9. package/dist/cli.mjs +2895 -182
  10. package/dist/cli.mjs.map +1 -1
  11. package/dist/cli__commands__contract-emit.mjs +1 -1
  12. package/dist/cli__commands__contract-infer.mjs +1 -1
  13. package/dist/cli__commands__db-init.mjs +1 -1
  14. package/dist/cli__commands__db-schema.mjs +1 -1
  15. package/dist/cli__commands__db-sign.mjs +1 -1
  16. package/dist/cli__commands__db-update.mjs +1 -1
  17. package/dist/cli__commands__db-verify.mjs +1 -1
  18. package/dist/cli__commands__migrate.d.mts +2 -2
  19. package/dist/cli__commands__migrate.mjs +1 -1
  20. package/dist/cli__commands__migration-check.d.mts +1 -1
  21. package/dist/cli__commands__migration-check.mjs +2 -2
  22. package/dist/cli__commands__migration-graph.d.mts +2 -2
  23. package/dist/cli__commands__migration-graph.mjs +1 -1
  24. package/dist/cli__commands__migration-list.d.mts +2 -2
  25. package/dist/cli__commands__migration-list.mjs +1 -1
  26. package/dist/cli__commands__migration-log.d.mts +2 -2
  27. package/dist/cli__commands__migration-log.mjs +1 -1
  28. package/dist/cli__commands__migration-new.mjs +1 -1
  29. package/dist/cli__commands__migration-plan.d.mts +1 -1
  30. package/dist/cli__commands__migration-plan.mjs +1 -1
  31. package/dist/cli__commands__migration-show.d.mts +1 -1
  32. package/dist/cli__commands__migration-show.mjs +1 -1
  33. package/dist/cli__commands__migration-status.d.mts +2 -2
  34. package/dist/cli__commands__migration-status.mjs +2 -2
  35. package/dist/cli__commands__ref.mjs +1 -1
  36. package/dist/cli__commands__telemetry.mjs +1 -1
  37. package/dist/cli__control-api.d.mts +4 -4
  38. package/dist/cli__control-api.mjs +15 -15
  39. package/dist/cli__control-api__testing.d.mts +1 -1
  40. package/dist/cli__control-api__testing.mjs +2 -1
  41. package/dist/cli__control-api__testing.mjs.map +1 -1
  42. package/dist/cli__init-output.d.mts +1 -1
  43. package/dist/cli__init-output.mjs +1 -1
  44. package/dist/{client-DU9qtBxW-BjVHiKzE.mjs → client-C6Qp5ujC-Dxb7r79B.mjs} +12 -15
  45. package/dist/client-C6Qp5ujC-Dxb7r79B.mjs.map +1 -0
  46. package/dist/code-templates-D73q329L-CSx0Jg-6.mjs +295 -0
  47. package/dist/code-templates-D73q329L-CSx0Jg-6.mjs.map +1 -0
  48. package/dist/combine-verify-results-B87B_pMc-D4l22OqY.mjs +65 -0
  49. package/dist/combine-verify-results-B87B_pMc-D4l22OqY.mjs.map +1 -0
  50. package/dist/{command-helpers-CwLvFwMB-BWwUQhlT.mjs → command-helpers-BCgwcqTe-lNCtppzM.mjs} +3 -3
  51. package/dist/{command-helpers-CwLvFwMB-BWwUQhlT.mjs.map → command-helpers-BCgwcqTe-lNCtppzM.mjs.map} +1 -1
  52. package/dist/{contract-at-errors-Dptf8RE_-B5gr04Sc.mjs → contract-at-errors-BSoDI0Hw-BXeUNE3s.mjs} +3 -3
  53. package/dist/{contract-at-errors-Dptf8RE_-B5gr04Sc.mjs.map → contract-at-errors-BSoDI0Hw-BXeUNE3s.mjs.map} +1 -1
  54. package/dist/contract-emit-DDWBBvF1-BeGZCRrb.mjs +2 -0
  55. package/dist/{contract-emit-CZQZ1i4z-p9LSGmmQ.mjs → contract-emit-DFScp9D6-6H-UJMFv.mjs} +5 -5
  56. package/dist/{contract-emit-CZQZ1i4z-p9LSGmmQ.mjs.map → contract-emit-DFScp9D6-6H-UJMFv.mjs.map} +1 -1
  57. package/dist/{contract-emit-BQFpcb2A-BwT9iVdb.mjs → contract-emit-DsvAx-dY-DQzoDO34.mjs} +5 -5
  58. package/dist/{contract-emit-BQFpcb2A-BwT9iVdb.mjs.map → contract-emit-DsvAx-dY-DQzoDO34.mjs.map} +1 -1
  59. package/dist/{contract-infer-C6cYOihE-CIUCgmw0.mjs → contract-infer-BwIDGl7v-CZrdWXAr.mjs} +4 -4
  60. package/dist/{contract-infer-C6cYOihE-CIUCgmw0.mjs.map → contract-infer-BwIDGl7v-CZrdWXAr.mjs.map} +1 -1
  61. package/dist/{contract-snapshot-resolution-DvZvbNcZ-DHFCWe_k.mjs → contract-snapshot-resolution-De2VvOJn-DqIAV9cr.mjs} +4 -4
  62. package/dist/{contract-snapshot-resolution-DvZvbNcZ-DHFCWe_k.mjs.map → contract-snapshot-resolution-De2VvOJn-DqIAV9cr.mjs.map} +1 -1
  63. package/dist/{contract-space-aggregate-loader-CoLTf3Ce-pQDru2w0.mjs → contract-space-aggregate-loader-fa04OIaL-B7LXHle3.mjs} +4 -4
  64. package/dist/{contract-space-aggregate-loader-CoLTf3Ce-pQDru2w0.mjs.map → contract-space-aggregate-loader-fa04OIaL-B7LXHle3.mjs.map} +1 -1
  65. package/dist/{db-init-DypCy1e3-CBrYfhHF.mjs → db-init-BolXrKAI-CwG-zEDW.mjs} +6 -6
  66. package/dist/{db-init-DypCy1e3-CBrYfhHF.mjs.map → db-init-BolXrKAI-CwG-zEDW.mjs.map} +1 -1
  67. package/dist/{db-init-failure-BmCcHUfc-BqDxyrJE.mjs → db-init-failure-B5cQML4A-5zr-99Ek.mjs} +3 -3
  68. package/dist/{db-init-failure-BmCcHUfc-BqDxyrJE.mjs.map → db-init-failure-B5cQML4A-5zr-99Ek.mjs.map} +1 -1
  69. package/dist/{db-schema-DHfPM-5V-JeCjrQ55.mjs → db-schema-DvdLBdEY-Dl6e1d_Y.mjs} +4 -4
  70. package/dist/{db-schema-DHfPM-5V-JeCjrQ55.mjs.map → db-schema-DvdLBdEY-Dl6e1d_Y.mjs.map} +1 -1
  71. package/dist/{db-sign-DbAxRcZh-C-nT9kcG.mjs → db-sign-DCp4c8CA-B3tun-kh.mjs} +6 -6
  72. package/dist/{db-sign-DbAxRcZh-C-nT9kcG.mjs.map → db-sign-DCp4c8CA-B3tun-kh.mjs.map} +1 -1
  73. package/dist/{db-update-J59yROwL-DCP-_z2W.mjs → db-update-CfayE8WE-CPhQyDaZ.mjs} +6 -6
  74. package/dist/{db-update-J59yROwL-DCP-_z2W.mjs.map → db-update-CfayE8WE-CPhQyDaZ.mjs.map} +1 -1
  75. package/dist/{db-verify-0TpDMziA-CJDKutMN.mjs → db-verify-BN7IrOAL-kEzRNJUl.mjs} +7 -65
  76. package/dist/db-verify-BN7IrOAL-kEzRNJUl.mjs.map +1 -0
  77. package/dist/{exports-DaxzMVtq.mjs → exports-B3xY_FHp.mjs} +304 -18
  78. package/dist/exports-B3xY_FHp.mjs.map +1 -0
  79. package/dist/{format-cbJY7l6v-CjMUDTAs.mjs → format-Ca7dUE6B-BMFqrc6D.mjs} +5 -5
  80. package/dist/{format-cbJY7l6v-CjMUDTAs.mjs.map → format-Ca7dUE6B-BMFqrc6D.mjs.map} +1 -1
  81. package/dist/{framework-components-C3K7SBeC-Bj5gx85-.mjs → framework-components-Bau7o1-J-DTp6AUoq.mjs} +3 -3
  82. package/dist/{framework-components-C3K7SBeC-Bj5gx85-.mjs.map → framework-components-Bau7o1-J-DTp6AUoq.mjs.map} +1 -1
  83. package/dist/init-DJrxDasP-DoQftaPY.mjs +800 -0
  84. package/dist/init-DJrxDasP-DoQftaPY.mjs.map +1 -0
  85. package/dist/{inspect-live-schema-Cf77j9Vd-i5fzNW4T.mjs → inspect-live-schema-BPHXdvqW-DrzL2ZkQ.mjs} +5 -5
  86. package/dist/{inspect-live-schema-Cf77j9Vd-i5fzNW4T.mjs.map → inspect-live-schema-BPHXdvqW-DrzL2ZkQ.mjs.map} +1 -1
  87. package/dist/integrity-violation-to-check-failure-BmWMLAae-DqiC4_3p.mjs +115 -0
  88. package/dist/integrity-violation-to-check-failure-BmWMLAae-DqiC4_3p.mjs.map +1 -0
  89. package/dist/{invariants-1zL5-9Mc-BCeOLxd_.mjs → invariants-Bltd8DyA-Cg_1Lu0q.mjs} +4 -4
  90. package/dist/{invariants-1zL5-9Mc-BCeOLxd_.mjs.map → invariants-Bltd8DyA-Cg_1Lu0q.mjs.map} +1 -1
  91. package/dist/{legend-BQcPKTLe-bn9e4_ZU.mjs → legend-DGv9e2_0-BtetgRz4.mjs} +3 -3
  92. package/dist/{legend-BQcPKTLe-bn9e4_ZU.mjs.map → legend-DGv9e2_0-BtetgRz4.mjs.map} +1 -1
  93. package/dist/{migrate-CgSnzAUm-aGstaO5N.mjs → migrate-BXATUjYE-Do79Imf-.mjs} +12 -12
  94. package/dist/{migrate-CgSnzAUm-aGstaO5N.mjs.map → migrate-BXATUjYE-Do79Imf-.mjs.map} +1 -1
  95. package/dist/{migrate-failure-CnoUcDms-taa9pfd7.mjs → migrate-failure-D4NvkoCk-0bttmQs2.mjs} +5 -5
  96. package/dist/{migrate-failure-CnoUcDms-taa9pfd7.mjs.map → migrate-failure-D4NvkoCk-0bttmQs2.mjs.map} +1 -1
  97. package/dist/{migrate-show-Dlo-YzOk-BXo-DmwI.d.mts → migrate-show-B8UJ9dmb-C4RTPbDk.d.mts} +3 -3
  98. package/dist/{migrate-show-Dlo-YzOk-BXo-DmwI.d.mts.map → migrate-show-B8UJ9dmb-C4RTPbDk.d.mts.map} +1 -1
  99. package/dist/{migrate-show-kVUG1xdo-bVTW8tu4.mjs → migrate-show-C_9xR4Qt-B-Y0PGKw.mjs} +6 -6
  100. package/dist/{migrate-show-kVUG1xdo-bVTW8tu4.mjs.map → migrate-show-C_9xR4Qt-B-Y0PGKw.mjs.map} +1 -1
  101. package/dist/{migration-check-CBMoMDX2-DhSEOGNg.mjs → migration-check-Bbdw7t-r-C2VTMK61.mjs} +6 -6
  102. package/dist/{migration-check-CBMoMDX2-DhSEOGNg.mjs.map → migration-check-Bbdw7t-r-C2VTMK61.mjs.map} +1 -1
  103. package/dist/migration-check-DbHgYK7F-7mtYNVFu.mjs +163 -0
  104. package/dist/migration-check-DbHgYK7F-7mtYNVFu.mjs.map +1 -0
  105. package/dist/{migration-command-scaffold-B1BiWKLI-Bskk5UKX.mjs → migration-command-scaffold-SzjR2naH-Yi3-rNfX.mjs} +5 -5
  106. package/dist/{migration-command-scaffold-B1BiWKLI-Bskk5UKX.mjs.map → migration-command-scaffold-SzjR2naH-Yi3-rNfX.mjs.map} +1 -1
  107. package/dist/{migration-graph-B30X5398-BH3zB9Mn.mjs → migration-graph-B8WxW_tm-qGNf7jQh.mjs} +3 -3
  108. package/dist/{migration-graph-B30X5398-BH3zB9Mn.mjs.map → migration-graph-B8WxW_tm-qGNf7jQh.mjs.map} +1 -1
  109. package/dist/{migration-graph-D2dbLCkl-CCHL0aDA.mjs → migration-graph-BOwu76mF-kOTWFvfV.mjs} +9 -9
  110. package/dist/{migration-graph-D2dbLCkl-CCHL0aDA.mjs.map → migration-graph-BOwu76mF-kOTWFvfV.mjs.map} +1 -1
  111. package/dist/{migration-graph-command-render-BeuEyf2B-BNH9oUB_.mjs → migration-graph-command-render-h0VdTkSM-C3rPZEw1.mjs} +17 -3
  112. package/dist/migration-graph-command-render-h0VdTkSM-C3rPZEw1.mjs.map +1 -0
  113. package/dist/{migration-graph-sections-0lKA5l1b-CTHQquu7.mjs → migration-graph-sections-BBHPOFN--COKyUKQ4.mjs} +4 -4
  114. package/dist/{migration-graph-sections-0lKA5l1b-CTHQquu7.mjs.map → migration-graph-sections-BBHPOFN--COKyUKQ4.mjs.map} +1 -1
  115. package/dist/{migration-list-DCx0KOFp-B3MiGnpa.mjs → migration-list-CKuYcMQq-CubZzE9i.mjs} +7 -7
  116. package/dist/{migration-list-DCx0KOFp-B3MiGnpa.mjs.map → migration-list-CKuYcMQq-CubZzE9i.mjs.map} +1 -1
  117. package/dist/{migration-list-BQTfSGbT-DoNqbNsu.mjs → migration-list-CY08bD8I-PoXuv94c.mjs} +3 -3
  118. package/dist/{migration-list-BQTfSGbT-DoNqbNsu.mjs.map → migration-list-CY08bD8I-PoXuv94c.mjs.map} +1 -1
  119. package/dist/{migration-log-CJ6_9_uj-uWyc3vlC.mjs → migration-log-CUbGla-9-BLIrWjwN.mjs} +8 -8
  120. package/dist/{migration-log-CJ6_9_uj-uWyc3vlC.mjs.map → migration-log-CUbGla-9-BLIrWjwN.mjs.map} +1 -1
  121. package/dist/{migration-log-table-DRiOnvzf-zTQBThqe.mjs → migration-log-table-eES9lPjv-BCFm8qJr.mjs} +3 -3
  122. package/dist/{migration-log-table-DRiOnvzf-zTQBThqe.mjs.map → migration-log-table-eES9lPjv-BCFm8qJr.mjs.map} +1 -1
  123. package/dist/{migration-new-CXLgOLXz-2C5s_q7n.mjs → migration-new-ChvZjf5X-BFhEM0BF.mjs} +4 -4
  124. package/dist/{migration-new-CXLgOLXz-2C5s_q7n.mjs.map → migration-new-ChvZjf5X-BFhEM0BF.mjs.map} +1 -1
  125. package/dist/{migration-new-Bp5dPKnF-D-Fb6vEp.mjs → migration-new-DXMvJdbB-BkrpDfcr.mjs} +7 -7
  126. package/dist/{migration-new-Bp5dPKnF-D-Fb6vEp.mjs.map → migration-new-DXMvJdbB-BkrpDfcr.mjs.map} +1 -1
  127. package/dist/{migration-path-target-BNTSTPAc-D7dQ4K7x.mjs → migration-path-target-JDWqF9kj-B7zoMq6X.mjs} +3 -3
  128. package/dist/{migration-path-target-BNTSTPAc-D7dQ4K7x.mjs.map → migration-path-target-JDWqF9kj-B7zoMq6X.mjs.map} +1 -1
  129. package/dist/{migration-plan-CharRhoN-BIB3WL65.d.mts → migration-plan-BV9f5Xjq-DiyscOMc.d.mts} +3 -3
  130. package/dist/{migration-plan-CharRhoN-BIB3WL65.d.mts.map → migration-plan-BV9f5Xjq-DiyscOMc.d.mts.map} +1 -1
  131. package/dist/{migration-plan-BxfF1Hdo-BKn0xMlY.mjs → migration-plan-Bz1hOTHF-CFCtPuOv.mjs} +4 -4
  132. package/dist/{migration-plan-BxfF1Hdo-BKn0xMlY.mjs.map → migration-plan-Bz1hOTHF-CFCtPuOv.mjs.map} +1 -1
  133. package/dist/{migration-plan-C6KrFHJT-CRkTsE7L.mjs → migration-plan-Cfz0efEL-DMNFq5b2.mjs} +8 -8
  134. package/dist/{migration-plan-C6KrFHJT-CRkTsE7L.mjs.map → migration-plan-Cfz0efEL-DMNFq5b2.mjs.map} +1 -1
  135. package/dist/{migration-show-Dhnlx_GU-DhWLLt3Z.mjs → migration-show-BGdR1xnT-Cg3M0FPh.mjs} +8 -8
  136. package/dist/{migration-show-Dhnlx_GU-DhWLLt3Z.mjs.map → migration-show-BGdR1xnT-Cg3M0FPh.mjs.map} +1 -1
  137. package/dist/{migration-status-S88DjM8c-DLHnCKfW.mjs → migration-status-BIrAJ5af-D-_mMBUA.mjs} +12 -11
  138. package/dist/{migration-status-S88DjM8c-DLHnCKfW.mjs.map → migration-status-BIrAJ5af-D-_mMBUA.mjs.map} +1 -1
  139. package/dist/{output-DWNYqZGc-D2sRgLAm.mjs → output-DP3woAjV-BxCr9nHA.mjs} +21 -11
  140. package/dist/output-DP3woAjV-BxCr9nHA.mjs.map +1 -0
  141. package/dist/{project-import-root-nwdoPWap--5vXe4zp.mjs → project-import-root-B4nM-VWX-D__g0hTb.mjs} +3 -3
  142. package/dist/{project-import-root-nwdoPWap--5vXe4zp.mjs.map → project-import-root-B4nM-VWX-D__g0hTb.mjs.map} +1 -1
  143. package/dist/{init-Bco4QkKJ-DqUZVrBU.mjs → redact-secrets-Cvia6eTB-BE_Pg3k9.mjs} +741 -1517
  144. package/dist/redact-secrets-Cvia6eTB-BE_Pg3k9.mjs.map +1 -0
  145. package/dist/{ref-gZQjdz8I-CW6n9Fc0.mjs → ref-4x6BGSsd-ClaoZIQh.mjs} +4 -4
  146. package/dist/{ref-gZQjdz8I-CW6n9Fc0.mjs.map → ref-4x6BGSsd-ClaoZIQh.mjs.map} +1 -1
  147. package/dist/{ref-C8oaaeky-ColNkWpr.mjs → ref-WXLIR9Xm-12IUtoBU.mjs} +5 -5
  148. package/dist/{ref-C8oaaeky-ColNkWpr.mjs.map → ref-WXLIR9Xm-12IUtoBU.mjs.map} +1 -1
  149. package/dist/{ref-resolution-DAK4OK3x-B-8ZZc0f.mjs → ref-resolution-BSN1amKm-C6-TTM2N.mjs} +3 -3
  150. package/dist/{ref-resolution-DAK4OK3x-B-8ZZc0f.mjs.map → ref-resolution-BSN1amKm-C6-TTM2N.mjs.map} +1 -1
  151. package/dist/{schemas-Bm2e3Hk1-qLKF0B36.d.mts → schemas-BGgjiKV0-Rh8RlMCl.d.mts} +4 -2
  152. package/dist/schemas-BGgjiKV0-Rh8RlMCl.d.mts.map +1 -0
  153. package/dist/{schemas-BMkqaqvM-CLaqlat4.mjs → schemas-CYSD83Cu-Bff4PPoi.mjs} +3 -2
  154. package/dist/schemas-CYSD83Cu-Bff4PPoi.mjs.map +1 -0
  155. package/dist/{telemetry-DPXFYAsz-CPW2USxs.mjs → telemetry-BD52LETE-Cqeb7ebh.mjs} +3 -3
  156. package/dist/{telemetry-DPXFYAsz-CPW2USxs.mjs.map → telemetry-BD52LETE-Cqeb7ebh.mjs.map} +1 -1
  157. package/dist/vite-plugin-contract-emit.mjs +1 -1
  158. package/package.json +13 -13
  159. package/dist/cli-errors-BG6bItjG-DwdKIeGz.mjs.map +0 -1
  160. package/dist/cli-errors-BiKBrOXc-JPxQqO58.d.mts.map +0 -1
  161. package/dist/client-DU9qtBxW-BjVHiKzE.mjs.map +0 -1
  162. package/dist/contract-emit-Bzt11N4v-BQ2Pr8KG.mjs +0 -2
  163. package/dist/db-verify-0TpDMziA-CJDKutMN.mjs.map +0 -1
  164. package/dist/exports-DaxzMVtq.mjs.map +0 -1
  165. package/dist/init-Bco4QkKJ-DqUZVrBU.mjs.map +0 -1
  166. package/dist/migration-check-BVK9vfan-Dfg8lbeB.mjs +0 -272
  167. package/dist/migration-check-BVK9vfan-Dfg8lbeB.mjs.map +0 -1
  168. package/dist/migration-graph-command-render-BeuEyf2B-BNH9oUB_.mjs.map +0 -1
  169. package/dist/output-DWNYqZGc-D2sRgLAm.mjs.map +0 -1
  170. package/dist/schemas-BMkqaqvM-CLaqlat4.mjs.map +0 -1
  171. package/dist/schemas-Bm2e3Hk1-qLKF0B36.d.mts.map +0 -1
package/dist/cli.mjs CHANGED
@@ -1,47 +1,58 @@
1
1
  import { i as loadConfig } from "./exports-BZLNbtkY.mjs";
2
- import { I as requireLiveDatabase, L as runCommandAction, M as errorTargetMigrationNotSupported, O as errorRunnerFailed, P as errorUnexpected, a as errorConfigValidation$1, b as errorMigrationPlanningFailed, c as errorContractValidationFailed, d as errorDriverRequired, f as errorFileNotFound, g as errorLegendHumanOnly, k as errorRuntime$1, l as errorDatabaseConnectionRequired, o as errorConsentPlanMismatch, t as CliStructuredError$1$1, u as errorDestructiveChanges, x as errorNoMigrations, y as errorMigrationPackageNotFound } from "./cli-errors-BG6bItjG-DwdKIeGz.mjs";
2
+ import { A as errorRuntime$1, F as errorUnexpected, L as requireLiveDatabase, N as errorTargetMigrationNotSupported, P as errorTargetMismatch, R as runCommandAction, S as errorNoMigrations, _ as errorLegendHumanOnly, a as errorConfigValidation$1, b as errorMigrationPackageNotFound, d as errorDestructiveChanges, f as errorDriverRequired, k as errorRunnerFailed, l as errorContractValidationFailed, m as errorHashMismatch, o as errorConsentPlanMismatch, p as errorFileNotFound, r as chooseAction, s as errorContractArgConflict, t as CliStructuredError$1$1, u as errorDatabaseConnectionRequired, x as errorMigrationPlanningFailed, y as errorMarkerMissing } from "./cli-errors-B4zTLaqQ-CXgjO9t4.mjs";
3
3
  import { r as getEmittedArtifactPaths } from "./exports-BCLg4CiV-05kuwcb0.mjs";
4
- import { n as executeContractEmit } from "./contract-emit-CZQZ1i4z-p9LSGmmQ.mjs";
4
+ import { n as executeContractEmit } from "./contract-emit-DFScp9D6-6H-UJMFv.mjs";
5
5
  import { h as renderPreviewStatement, m as previewBlockHeader } from "./terminal-ui-Cqz4LVL7-B0mcVdLy.mjs";
6
6
  import { c as spaceMigrationDirectory } from "./verify-contract-spaces-DhJTb0zM-_oh6W6lp.mjs";
7
- import { S as targetSupportsMigrations, f as maskConnectionUrl, n as closeQuietly, v as sanitizeErrorMessage } from "./command-helpers-CwLvFwMB-BWwUQhlT.mjs";
8
- import { t as createContractEmitCommand } from "./contract-emit-BQFpcb2A-BwT9iVdb.mjs";
9
- import { n as executeFormat, t as createFormatCommand } from "./format-cbJY7l6v-CjMUDTAs.mjs";
10
- import { a as loadContractSpaceAggregateForCli, r as buildReadAggregate, s as refuseContractSpaceIntegrity, u as toDeclaredExtensionsFromRaw } from "./contract-space-aggregate-loader-CoLTf3Ce-pQDru2w0.mjs";
11
- import { t as createControlClient } from "./client-DU9qtBxW-BjVHiKzE.mjs";
7
+ import { S as targetSupportsMigrations, f as maskConnectionUrl, h as readContractEnvelope, n as closeQuietly, v as sanitizeErrorMessage } from "./command-helpers-BCgwcqTe-lNCtppzM.mjs";
8
+ import { t as createContractEmitCommand } from "./contract-emit-DsvAx-dY-DQzoDO34.mjs";
9
+ import { n as executeFormat, t as createFormatCommand } from "./format-Ca7dUE6B-BMFqrc6D.mjs";
10
+ import { c as targetLabel, i as scaffoldSpecifierResolverFor, l as targetPackageName, n as dbFile, o as starterSchema, r as defaultSchemaPath, t as configFile } from "./code-templates-D73q329L-CSx0Jg-6.mjs";
11
+ import { a as loadContractSpaceAggregateForCli, i as loadContractRawSafely, l as refusePackageCorruptionOnAggregate, r as buildReadAggregate, s as refuseContractSpaceIntegrity, u as toDeclaredExtensionsFromRaw } from "./contract-space-aggregate-loader-fa04OIaL-B7LXHle3.mjs";
12
+ import { t as createControlClient } from "./client-C6Qp5ujC-Dxb7r79B.mjs";
12
13
  import { a as readContractIR, o as resolveRefAdvancementFields, t as advanceRefSafely } from "./ref-advancement-DaZBzm7m-WoqnFAyr.mjs";
13
- import { t as mapDbInitFailure } from "./db-init-failure-BmCcHUfc-BqDxyrJE.mjs";
14
- import { t as resolveContractRefToSnapshot } from "./contract-snapshot-resolution-DvZvbNcZ-DHFCWe_k.mjs";
15
- import { t as mapCaughtMigrationError } from "./caught-errors-DLPzfzIW-CQ9BoXD-.mjs";
16
- import { t as mapContractAtError } from "./contract-at-errors-Dptf8RE_-B5gr04Sc.mjs";
17
- import { i as refuseUnknownInvariants, n as refuseMarkerOutsideGraph } from "./invariants-1zL5-9Mc-BCeOLxd_.mjs";
18
- import { t as executeMigrateShowPlan } from "./migrate-show-kVUG1xdo-bVTW8tu4.mjs";
19
- import { n as resolveMigrationRef, t as resolveContractRef } from "./ref-resolution-DAK4OK3x-B-8ZZc0f.mjs";
20
- import { n as migrationSpaceListEntriesFromAggregate, r as runMigrationList } from "./migration-list-BQTfSGbT-DoNqbNsu.mjs";
21
- import { S as toneSpans, b as renderMigrationListWithStyle, d as createToneMigrationListStyler, n as TONE_MIGRATION_GRAPH_PALETTE, v as renderMigrationGraphLegend, x as toneDrawing } from "./migration-graph-command-render-BeuEyf2B-BNH9oUB_.mjs";
22
- import { n as migrateShowRunListRows, r as renderMigrateShowGraph, t as mapMigrateFailure } from "./migrate-failure-CnoUcDms-taa9pfd7.mjs";
23
- import { n as looksLikePath, r as resolveAppTargetPath, t as findPackageByDirPath } from "./migration-path-target-BNTSTPAc-D7dQ4K7x.mjs";
24
- import { t as buildMigrationSpaceGraphEntries } from "./migration-graph-B30X5398-BH3zB9Mn.mjs";
25
- import { n as renderMigrationGraphDot, r as renderMigrationGraphSections, t as buildMigrationGraphTreeSections } from "./migration-graph-sections-0lKA5l1b-CTHQquu7.mjs";
26
- import { a as sortLedgerEntries, i as serializeLedgerEntriesForJson, n as formatLedgerAppliedAt, o as styleHashTransition, t as MIGRATION_LOG_EMPTY_MESSAGE } from "./migration-log-table-DRiOnvzf-zTQBThqe.mjs";
27
- import { n as executeRefListCommand, r as executeRefSetCommand, t as executeRefDeleteCommand } from "./ref-C8oaaeky-ColNkWpr.mjs";
14
+ import { t as mapDbInitFailure } from "./db-init-failure-B5cQML4A-5zr-99Ek.mjs";
15
+ import { t as resolveContractRefToSnapshot } from "./contract-snapshot-resolution-De2VvOJn-DqIAV9cr.mjs";
16
+ import { t as combineVerifyResults } from "./combine-verify-results-B87B_pMc-D4l22OqY.mjs";
17
+ import { t as mapCaughtMigrationError } from "./caught-errors-BZo7zcRc-C-pIEasG.mjs";
18
+ import { t as mapContractAtError } from "./contract-at-errors-BSoDI0Hw-BXeUNE3s.mjs";
19
+ import { i as refuseUnknownInvariants, n as refuseMarkerOutsideGraph, r as refuseMissingInvariantPath, t as hasMigrationPath } from "./invariants-Bltd8DyA-Cg_1Lu0q.mjs";
20
+ import { t as executeMigrateShowPlan } from "./migrate-show-C_9xR4Qt-B-Y0PGKw.mjs";
21
+ import { n as resolveMigrationRef, t as resolveContractRef } from "./ref-resolution-BSN1amKm-C6-TTM2N.mjs";
22
+ import { n as migrationSpaceListEntriesFromAggregate, r as runMigrationList, t as listRefsByContractHash } from "./migration-list-CY08bD8I-PoXuv94c.mjs";
23
+ import { C as toneSpans, S as toneDrawing, b as renderMigrationGraphSpaceTrees, d as createToneMigrationListStyler, m as indentMigrationGraphTreeBlock, n as TONE_MIGRATION_GRAPH_PALETTE, v as renderMigrationGraphLegend, x as renderMigrationListWithStyle } from "./migration-graph-command-render-h0VdTkSM-C3rPZEw1.mjs";
24
+ import { n as migrateShowRunListRows, r as renderMigrateShowGraph, t as mapMigrateFailure } from "./migrate-failure-D4NvkoCk-0bttmQs2.mjs";
25
+ import { n as looksLikePath, r as resolveAppTargetPath, t as findPackageByDirPath } from "./migration-path-target-JDWqF9kj-B7zoMq6X.mjs";
26
+ import { i as runMigrationCheck, n as enumerateCheckSpaces, r as loadAggregateIntegrityViolations, t as checkSingleTarget } from "./migration-check-Bbdw7t-r-C2VTMK61.mjs";
27
+ import { t as integrityViolationToCheckFailure } from "./integrity-violation-to-check-failure-BmWMLAae-DqiC4_3p.mjs";
28
+ import { t as buildMigrationSpaceGraphEntries } from "./migration-graph-B8WxW_tm-qGNf7jQh.mjs";
29
+ import { n as renderMigrationGraphDot, r as renderMigrationGraphSections, t as buildMigrationGraphTreeSections } from "./migration-graph-sections-BBHPOFN--COKyUKQ4.mjs";
30
+ import { a as sortLedgerEntries, i as serializeLedgerEntriesForJson, n as formatLedgerAppliedAt, o as styleHashTransition, t as MIGRATION_LOG_EMPTY_MESSAGE } from "./migration-log-table-eES9lPjv-BCFm8qJr.mjs";
31
+ import { t as executeMigrationNewCommand } from "./migration-new-DXMvJdbB-BkrpDfcr.mjs";
32
+ import { t as executeMigrationPlanCommand } from "./migration-plan-Cfz0efEL-DMNFq5b2.mjs";
33
+ import { a as statusForMigrationHash, i as readMigrationRefs, n as deriveStatusEdgeAnnotations, r as originHashForStatus, t as appliedHashesFromLedger } from "./refs-fQLFcMoq-aTBeUU9H.mjs";
34
+ import { n as executeRefListCommand, r as executeRefSetCommand, t as executeRefDeleteCommand } from "./ref-WXLIR9Xm-12IUtoBU.mjs";
35
+ import { A as isRecognisedPnpmResolutionError, B as removeDependency, C as findStaleArtifacts, E as formatRunCommand, F as mergeTsConfig, G as validateSchemaPath, H as resolveAuthoring, I as minimalProjectReadmeMd, L as probeServerVersion, M as mergeGitattributes, N as mergeGitignore, O as formatSkillSourceUrl, P as mergePackageScripts, R as quickReferenceMd, S as errorInitWriteFailed, U as resolveProjectSkillInstallCommands, V as requiredGitattributesLines, W as resolveTarget, _ as errorInitProbeFailed, a as TsConfigParseError, b as errorInitStrictProbeWithoutProbe, d as envFileContent, g as errorInitMissingFlags, h as errorInitInvalidTsconfig, i as REQUIRED_SCRIPTS, j as legacySkillDirs, l as ensureEsmModuleType, m as errorInitInvalidManifest, n as DEFAULT_SKILL_SOURCES, o as buildCatalogWarnings, r as MIN_SERVER_VERSION, s as defaultTsConfig, t as DEFAULT_SKILL_AGENTS, u as envExampleContent, x as errorInitUserAborted, z as redactSecrets } from "./redact-secrets-Cvia6eTB-BE_Pg3k9.mjs";
36
+ import { n as buildNextSteps, t as InitOutputSchema } from "./output-DP3woAjV-BxCr9nHA.mjs";
28
37
  import { CliStructuredError } from "@prisma/orm-framework/errors/control";
29
38
  import { ifDefined } from "@prisma/orm-framework/utils/defined";
30
- import { basename, dirname, join, normalize, relative, resolve } from "pathe";
31
- import { existsSync, unlinkSync, writeFileSync } from "node:fs";
32
- import { DOCS_BASE, isStructuredError } from "@prisma/orm-framework/utils/structured-error";
39
+ import { basename, dirname, isAbsolute, join, normalize, relative, resolve } from "pathe";
40
+ import { existsSync, mkdirSync, readFileSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
41
+ import { DOCS_BASE, docsUrlFor, isStructuredError, isStructuredErrorCode } from "@prisma/orm-framework/utils/structured-error";
33
42
  import { blindCast, castAs } from "@prisma/orm-framework/utils/casts";
34
- import { InternalError, assertNever } from "@prisma/orm-framework/utils/internal-error";
43
+ import { InternalError, assertNever, isInternalError } from "@prisma/orm-framework/utils/internal-error";
35
44
  import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
36
- import { APP_SPACE_ID, createControlStack } from "@prisma/orm-framework/components/control";
45
+ import { APP_SPACE_ID, VERIFY_CODE_HASH_MISMATCH, VERIFY_CODE_MARKER_MISSING, VERIFY_CODE_TARGET_MISMATCH, createControlStack, issueOutcome } from "@prisma/orm-framework/components/control";
46
+ import { type } from "arktype";
37
47
  import { collectConfigIssues } from "@prisma/orm-framework/config/config-validation";
38
48
  import { tmpdir } from "node:os";
49
+ import { detect } from "package-manager-detector/detect";
39
50
  import { printPsl } from "@prisma/orm-framework/psl-printer";
40
- import { defineCommand, defineCommandFamily, defineConfigSection, flag, positional } from "@prisma/cli-engine";
51
+ import { defineCommand, defineCommandFamily, defineConfigSection, defineServerCommand, flag, positional } from "@prisma/cli-engine";
41
52
  import { CliStructuredError as CliStructuredError$1, notOk, ok } from "@prisma/cli-engine/protocol";
42
53
  import { pathToFileURL } from "node:url";
43
54
  import { build } from "esbuild";
44
- //#region ../../../1-framework/3-tooling/cli/dist/load-config-pL46nF5F.mjs
55
+ //#region ../../../1-framework/3-tooling/cli/dist/load-config-CVli79Ro.mjs
45
56
  const MISSING_CONFIG_ACTION = {
46
57
  kind: "run-command",
47
58
  label: "Create a config file",
@@ -251,6 +262,11 @@ function normalizeError(error) {
251
262
  * prisma/prisma's `CliStructuredError` — both classes carry that name — and then settles it
252
263
  * through fields the engine's own class has and this one does not. The envelope that results is
253
264
  * off-protocol. Catching here means every handler settles through the single conversion instead.
265
+ *
266
+ * An `InternalError` is the one thing this boundary does not convert. Its own contract says never
267
+ * to catch it outside the outermost boundary: it means an invariant broke, which is a bug in
268
+ * Prisma Next rather than something the user did. Re-throwing lets the engine settle it as a bug
269
+ * at exit 1, where converting it would report the same number as a bad connection string.
254
270
  */
255
271
  function defineOrmCommand(def) {
256
272
  return defineCommand({
@@ -259,6 +275,7 @@ function defineOrmCommand(def) {
259
275
  try {
260
276
  return await def.handler(args, ctx);
261
277
  } catch (error) {
278
+ if (isInternalError(error)) throw error;
262
279
  return notOk(normalizeError(error));
263
280
  }
264
281
  }
@@ -608,7 +625,7 @@ function perSpaceBlocks(perSpace, mode) {
608
625
  roots: spaceNodes(perSpace, mode)
609
626
  }, ...destructiveWarningBlocks(hasDestructive)];
610
627
  }
611
- function operationBlocks$1(result) {
628
+ function operationBlocks$2(result) {
612
629
  const perSpace = result.perSpace;
613
630
  if (perSpace !== void 0 && perSpace.length > 0) return perSpaceBlocks(perSpace, result.mode);
614
631
  if (result.plan.operations.length === 0) return [];
@@ -619,7 +636,7 @@ function operationBlocks$1(result) {
619
636
  }, ...destructiveWarningBlocks(hasDestructive)];
620
637
  }
621
638
  /** The statements a database would run, printed verbatim rather than laid out. */
622
- function previewBlocks$1(preview) {
639
+ function previewBlocks$2(preview) {
623
640
  if (preview === void 0) return [];
624
641
  const header = {
625
642
  kind: "summary",
@@ -666,7 +683,7 @@ function applySummaryText(result) {
666
683
  if (executed === 0) return `Database already matches contract${across}`;
667
684
  return `Applied ${executed} operation(s)${across}`;
668
685
  }
669
- function planBlocks(result) {
686
+ function planBlocks$1(result) {
670
687
  const planned = result.plannedAdvanceRef;
671
688
  return [
672
689
  {
@@ -675,7 +692,7 @@ function planBlocks(result) {
675
692
  text: planSummaryText(result)
676
693
  },
677
694
  ...plannerWarningBlocks(result),
678
- ...operationBlocks$1(result),
695
+ ...operationBlocks$2(result),
679
696
  {
680
697
  kind: "fields",
681
698
  rows: [{
@@ -694,7 +711,7 @@ function planBlocks(result) {
694
711
  tone: "identifier"
695
712
  }]
696
713
  }],
697
- ...previewBlocks$1(result.plan.preview),
714
+ ...previewBlocks$2(result.plan.preview),
698
715
  {
699
716
  kind: "summary",
700
717
  status: "info",
@@ -736,7 +753,7 @@ function applyBlocks(result) {
736
753
  text: applySummaryText(result)
737
754
  },
738
755
  ...plannerWarningBlocks(result),
739
- ...operationBlocks$1(result),
756
+ ...operationBlocks$2(result),
740
757
  ...fallbackMarkerBlocks(result),
741
758
  ...advanced === null || advanced === void 0 ? [] : [{
742
759
  kind: "summary",
@@ -750,7 +767,7 @@ function applyBlocks(result) {
750
767
  }
751
768
  /** What a `db init` / `db update` result looks like in human mode. */
752
769
  function migrationResultBlocks(result) {
753
- return result.mode === "plan" ? planBlocks(result) : applyBlocks(result);
770
+ return result.mode === "plan" ? planBlocks$1(result) : applyBlocks(result);
754
771
  }
755
772
  /** Where the user goes next, as typed actions rather than trailing prose. */
756
773
  function migrationResultNextActions(result, applyCommand) {
@@ -769,6 +786,16 @@ function appMigrationsDirFor(config, cwd) {
769
786
  return spaceMigrationDirectory(migrationsDirFor(config, cwd), APP_SPACE_ID);
770
787
  }
771
788
  /**
789
+ * The config file an operation should anchor its project paths on. The engine
790
+ * loads the config and hands a handler the value but not the path, and
791
+ * `--config` is an engine flag the handler never sees, so a handler names the
792
+ * invocation directory's file. That equals the loaded file for every
793
+ * invocation whose config sits in the invocation directory.
794
+ */
795
+ function projectConfigPathFor(cwd) {
796
+ return resolve(cwd, "prisma-next.config.ts");
797
+ }
798
+ /**
772
799
  * Where refs live. The framework keeps them under the app subspace rather than
773
800
  * at the migrations root.
774
801
  */
@@ -842,7 +869,7 @@ async function prepareMigrationRun(inputs) {
842
869
  refsDir: appRefsDirFor(config, cwd)
843
870
  });
844
871
  }
845
- function initPresentations(inputs) {
872
+ function initPresentations$1(inputs) {
846
873
  const { document, database, dryRun } = inputs;
847
874
  return {
848
875
  human: () => [{
@@ -974,7 +1001,7 @@ function createDbInitCommand(createClient) {
974
1001
  severity: "verbose",
975
1002
  text: `Total time: ${document.timings.total}ms`
976
1003
  });
977
- return ok(ctx.present({ data: document }, initPresentations({
1004
+ return ok(ctx.present({ data: document }, initPresentations$1({
978
1005
  document,
979
1006
  contractPath: prepared.value.contractDisplayPath,
980
1007
  database: prepared.value.database,
@@ -1090,7 +1117,7 @@ function treeNode(node) {
1090
1117
  ...ifDefined("children", node.children === void 0 || node.children.length === 0 ? void 0 : node.children.map(treeNode))
1091
1118
  };
1092
1119
  }
1093
- function schemaPresentations(inputs) {
1120
+ function schemaPresentations$1(inputs) {
1094
1121
  const { document, schemaView, database } = inputs;
1095
1122
  return {
1096
1123
  human: () => [...database === void 0 ? [] : [{
@@ -1167,7 +1194,7 @@ function createDbSchemaCommand(createClient) {
1167
1194
  meta: { ...ifDefined("dbUrl", database) },
1168
1195
  timings: { total: Date.now() - startedAt }
1169
1196
  };
1170
- return ok(ctx.present({ data: document }, schemaPresentations({
1197
+ return ok(ctx.present({ data: document }, schemaPresentations$1({
1171
1198
  document,
1172
1199
  schemaView,
1173
1200
  database
@@ -1177,6 +1204,372 @@ function createDbSchemaCommand(createClient) {
1177
1204
  }
1178
1205
  const dbSchemaCommand = createDbSchemaCommand(createControlClient);
1179
1206
  /**
1207
+ * Reads the emitted contract and hydrates it through the family's
1208
+ * `deserializeContract` seam, which is where every other on-disk contract read
1209
+ * in this CLI crosses into family types.
1210
+ */
1211
+ async function readEmittedContract(inputs) {
1212
+ const path = contractPathFor(inputs.config, inputs.cwd);
1213
+ if (path === void 0) return notOk(normalizeError(errorConfigValidation$1("contract.output", {
1214
+ why: `${inputs.commandName} reads the emitted contract from config.contract.output; the config has no value to read.`,
1215
+ section: "contract"
1216
+ })));
1217
+ const relativePath = displayPath(path, inputs.cwd);
1218
+ let content;
1219
+ try {
1220
+ content = await readFile(path, "utf-8");
1221
+ } catch (error) {
1222
+ return notOk(normalizeError(Reflect.get(Object(error), "code") === "ENOENT" ? errorFileNotFound(path, {
1223
+ why: `Contract file not found at ${path}`,
1224
+ fix: `Run \`prisma-next contract emit\` to generate ${relativePath}, or update \`contract.output\` in prisma-next.config.ts`
1225
+ }) : errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}` })));
1226
+ }
1227
+ const familyInstance = inputs.config.family.create(createControlStack(inputs.config));
1228
+ try {
1229
+ return ok({
1230
+ contract: familyInstance.deserializeContract(castAs(JSON.parse(content))),
1231
+ path,
1232
+ displayPath: relativePath
1233
+ });
1234
+ } catch (error) {
1235
+ return notOk(normalizeError(errorContractValidationFailed(`Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`, { where: { path } })));
1236
+ }
1237
+ }
1238
+ /**
1239
+ * The connection and driver both verification commands need. Returns the
1240
+ * resolved connection or the precondition failure that stopped the run.
1241
+ */
1242
+ function requireVerifyConnection(inputs) {
1243
+ const dbConnection = inputs.db ?? inputs.config.db?.connection;
1244
+ if (typeof dbConnection !== "string" || dbConnection.length === 0) return notOk(normalizeError(errorDatabaseConnectionRequired({
1245
+ why: `Database connection is required for ${inputs.invocation} (set db.connection in prisma-next.config.ts, or pass --db <url>)`,
1246
+ missingFlags: ["--db"],
1247
+ retryCommand: `prisma-next ${inputs.invocation} --db <url>`
1248
+ })));
1249
+ if (inputs.config.driver === void 0) return notOk(normalizeError(errorDriverRequired({ why: `Config.driver is required for ${inputs.invocation}` })));
1250
+ return ok(dbConnection);
1251
+ }
1252
+ /**
1253
+ * A failure the verification could not recover from — a dropped connection, a
1254
+ * driver throw — as a settlement the user can act on. Connection strings are
1255
+ * stripped from the prose whichever path the value took. A driver error
1256
+ * carrying `ECONNREFUSED`, `ENOTFOUND` or a SQLSTATE has a `code` and takes
1257
+ * the first path, and its message is exactly the one likely to quote the URL.
1258
+ */
1259
+ function verificationThrow(inputs) {
1260
+ const { error } = inputs;
1261
+ const message = error instanceof Error ? error.message : String(error);
1262
+ return withoutConnectionString(typeof error === "object" && error !== null && "code" in error ? normalizeError(error) : normalizeError(errorUnexpected(message, { why: `Unexpected error during ${inputs.invocation}: ${message}` })), inputs.connection);
1263
+ }
1264
+ /**
1265
+ * The same envelope with the connection string stripped from every field the
1266
+ * settlement serializes: the prose, each next action's strings, and every
1267
+ * string reachable through `meta`. A driver error quotes the URL wherever it
1268
+ * pleases, so nothing user-facing passes through unstripped.
1269
+ */
1270
+ function withoutConnectionString(error, connection) {
1271
+ const clean = (text) => sanitizeErrorMessage(text, connection);
1272
+ return new CliStructuredError$1(error.code, clean(error.message), {
1273
+ severity: error.severity,
1274
+ nextActions: error.nextActions.map((action) => cleanNextAction(action, clean)),
1275
+ ...ifDefined("why", error.why === void 0 ? void 0 : clean(error.why)),
1276
+ ...ifDefined("where", error.where),
1277
+ ...ifDefined("meta", error.meta === void 0 ? void 0 : cleanMetaRecord(error.meta, clean)),
1278
+ ...ifDefined("docsUrl", error.docsUrl),
1279
+ cause: error.cause
1280
+ });
1281
+ }
1282
+ function cleanNextAction(action, clean) {
1283
+ return {
1284
+ kind: action.kind,
1285
+ label: clean(action.label),
1286
+ ...ifDefined("command", action.command === void 0 ? void 0 : clean(action.command)),
1287
+ ...ifDefined("commands", action.commands?.map(clean)),
1288
+ ...ifDefined("url", action.url === void 0 ? void 0 : clean(action.url)),
1289
+ ...ifDefined("reason", action.reason === void 0 ? void 0 : clean(action.reason))
1290
+ };
1291
+ }
1292
+ function cleanMetaValue(value, clean) {
1293
+ if (typeof value === "string") return clean(value);
1294
+ if (Array.isArray(value)) return value.map((entry) => cleanMetaValue(entry, clean));
1295
+ if (typeof value === "object" && value !== null) return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, cleanMetaValue(entry, clean)]));
1296
+ return value;
1297
+ }
1298
+ function cleanMetaRecord(meta, clean) {
1299
+ return Object.fromEntries(Object.entries(meta).map(([key, value]) => [key, cleanMetaValue(value, clean)]));
1300
+ }
1301
+ const OUTCOME_LABEL = {
1302
+ "not-found": "missing",
1303
+ "not-expected": "extra",
1304
+ "not-equal": "mismatch"
1305
+ };
1306
+ /** What a diff issue says, in the words the commander shell used. */
1307
+ function issueLabel(issue) {
1308
+ return `${OUTCOME_LABEL[issueOutcome(issue)]}: ${issue.path.join("/")}`;
1309
+ }
1310
+ function issueNodes(issues, status) {
1311
+ return issues.map((issue) => ({
1312
+ label: issueLabel(issue),
1313
+ status
1314
+ }));
1315
+ }
1316
+ /**
1317
+ * The drift, laid out as a tree the engine draws: one root per finding family,
1318
+ * one child per element. The engine owns the connectors and the status glyphs,
1319
+ * so nothing here carries an escape sequence.
1320
+ */
1321
+ function schemaFindingBlocks(inputs) {
1322
+ const roots = [];
1323
+ const issues = inputs.result.schema.issues;
1324
+ if (issues.length > 0) roots.push({
1325
+ label: "Schema issues",
1326
+ status: "error",
1327
+ children: issueNodes(issues, "error")
1328
+ });
1329
+ const warnings = inputs.result.schema.warnings?.issues ?? [];
1330
+ if (warnings.length > 0) roots.push({
1331
+ label: "Schema warnings",
1332
+ status: "warn",
1333
+ children: issueNodes(warnings, "warn")
1334
+ });
1335
+ if (inputs.unclaimed.length > 0) {
1336
+ const status = inputs.strict ? "error" : "warn";
1337
+ roots.push({
1338
+ label: "Unclaimed elements (declared by no contract)",
1339
+ status,
1340
+ children: inputs.unclaimed.map((name) => ({
1341
+ label: name,
1342
+ status
1343
+ }))
1344
+ });
1345
+ }
1346
+ return roots.length === 0 ? [] : [{
1347
+ kind: "tree",
1348
+ roots
1349
+ }];
1350
+ }
1351
+ /**
1352
+ * A failed schema-verification verdict as one envelope diagnostic. `error` is
1353
+ * the honest severity: the database does not satisfy the contract. It is legal
1354
+ * because both commands settle at exit 4 — the engine refuses a
1355
+ * severity-`error` diagnostic only on a run that exits 0.
1356
+ */
1357
+ function schemaVerdictDiagnostic(inputs) {
1358
+ const code = inputs.result.code;
1359
+ const dotted = code !== void 0 && isStructuredErrorCode(code);
1360
+ const issues = inputs.result.schema.issues.map(issueLabel);
1361
+ return {
1362
+ code: dotted ? code : "CONTRACT.VERIFY_FAILED",
1363
+ severity: "error",
1364
+ summary: inputs.result.summary,
1365
+ ...issues.length === 0 ? {} : { why: `The live schema differs: ${issues.join("; ")}.` },
1366
+ nextActions: inputs.nextActions,
1367
+ meta: {
1368
+ ...inputs.space === void 0 ? {} : { space: inputs.space },
1369
+ issues,
1370
+ ...dotted || code === void 0 ? {} : { code }
1371
+ }
1372
+ };
1373
+ }
1374
+ /**
1375
+ * Verification ran and refused the signature. The command completed — it
1376
+ * answered the question "may this database be signed?" — so the refusal is a
1377
+ * diagnostic on a completed envelope rather than an error.
1378
+ */
1379
+ const FINDINGS_EXIT_CODE$2 = 4;
1380
+ /** The config file this bin reads; the handler is not told which one was loaded. */
1381
+ const CONFIG_DISPLAY_PATH = "prisma-next.config.ts";
1382
+ function headerBlock$1(inputs) {
1383
+ return {
1384
+ kind: "fields",
1385
+ rail: true,
1386
+ rows: [{
1387
+ label: "contract",
1388
+ value: inputs.contract
1389
+ }, {
1390
+ label: "database",
1391
+ value: inputs.database
1392
+ }]
1393
+ };
1394
+ }
1395
+ function signPresentations(inputs) {
1396
+ const marker = inputs.document.marker;
1397
+ return {
1398
+ human: () => [
1399
+ inputs.header,
1400
+ {
1401
+ kind: "summary",
1402
+ status: "ok",
1403
+ text: "Database signed"
1404
+ },
1405
+ {
1406
+ kind: "fields",
1407
+ rows: [{
1408
+ label: "from",
1409
+ value: marker.previous?.storageHash === void 0 ? [{
1410
+ text: "none",
1411
+ tone: "muted"
1412
+ }] : [{
1413
+ text: marker.previous.storageHash,
1414
+ tone: "identifier"
1415
+ }]
1416
+ }, {
1417
+ label: "to",
1418
+ value: [{
1419
+ text: inputs.document.contract.storageHash,
1420
+ tone: "identifier"
1421
+ }]
1422
+ }]
1423
+ }
1424
+ ],
1425
+ json: () => inputs.document
1426
+ };
1427
+ }
1428
+ function refusedPresentations(inputs) {
1429
+ return {
1430
+ human: () => [
1431
+ inputs.header,
1432
+ ...schemaFindingBlocks({
1433
+ result: inputs.document,
1434
+ unclaimed: [],
1435
+ strict: false
1436
+ }),
1437
+ {
1438
+ kind: "summary",
1439
+ status: "error",
1440
+ text: inputs.document.summary
1441
+ }
1442
+ ],
1443
+ json: () => inputs.document
1444
+ };
1445
+ }
1446
+ /**
1447
+ * Builds the command with its control-client factory injected, so tests mount
1448
+ * the same tree over a fake client instead of mocking the client module.
1449
+ */
1450
+ function createDbSignCommand(createClient = createControlClient) {
1451
+ return defineOrmCommand({
1452
+ help: {
1453
+ summary: "Sign the database with your contract so you can safely run queries",
1454
+ description: "Verifies that your database schema satisfies the emitted contract, and if\nso, writes or updates the database signature. Idempotent and safe to run\nin CI or a deployment pipeline. The signature records that this database\ninstance is aligned with a specific contract version.\nExit codes: 0 = signed, 2 = the command could not run (unresolvable\ncontract reference, no emitted contract, unreachable database),\n4 = schema verification failed and no signature was written.",
1455
+ examples: [
1456
+ "db sign",
1457
+ "db sign --db $DATABASE_URL",
1458
+ "db sign production --db $DATABASE_URL",
1459
+ "db sign --contract production --db $DATABASE_URL"
1460
+ ]
1461
+ },
1462
+ args: {
1463
+ positionals: { contract: positional.optionalString({
1464
+ brief: "Contract reference (hash, prefix, ref name, or migration dir name)",
1465
+ placeholder: "contract"
1466
+ }) },
1467
+ flags: {
1468
+ db: dbFlag,
1469
+ contract: flag.string({
1470
+ brief: "Contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)",
1471
+ placeholder: "contract"
1472
+ })
1473
+ }
1474
+ },
1475
+ needs: { config: ormConfigSection },
1476
+ exitCodes: { 4: "schema verification failed; no signature was written" },
1477
+ handler: async (args, ctx) => {
1478
+ const positionalContract = args.positionals.contract;
1479
+ const flagContract = args.flags.contract;
1480
+ if (positionalContract !== void 0 && flagContract !== void 0) return notOk(normalizeError(errorContractArgConflict({
1481
+ positional: positionalContract,
1482
+ flag: flagContract
1483
+ })));
1484
+ const contractRef = positionalContract ?? flagContract;
1485
+ const emitted = await readEmittedContract({
1486
+ config: ctx.config,
1487
+ cwd: ctx.cwd,
1488
+ commandName: "db sign"
1489
+ });
1490
+ if (!emitted.ok) return notOk(emitted.failure);
1491
+ let contractInput = emitted.value.contract;
1492
+ if (contractRef !== void 0) {
1493
+ const resolvedRef = await resolveContractRefToSnapshot({
1494
+ config: ctx.config,
1495
+ migrationsDir: migrationsDirFor(ctx.config, ctx.cwd),
1496
+ refInput: contractRef,
1497
+ contractPathAbsolute: emitted.value.path,
1498
+ fallbackToEmitted: true
1499
+ });
1500
+ if (!resolvedRef.ok) return notOk(normalizeError(resolvedRef.failure));
1501
+ contractInput = resolvedRef.value.contractJson;
1502
+ }
1503
+ const connection = requireVerifyConnection({
1504
+ config: ctx.config,
1505
+ db: args.flags.db,
1506
+ invocation: "db sign"
1507
+ });
1508
+ if (!connection.ok) return notOk(connection.failure);
1509
+ const dbConnection = connection.value;
1510
+ const header = headerBlock$1({
1511
+ contract: contractRef ?? emitted.value.displayPath,
1512
+ database: maskConnectionUrl(dbConnection)
1513
+ });
1514
+ const client = createClient({
1515
+ family: ctx.config.family,
1516
+ target: ctx.config.target,
1517
+ adapter: ctx.config.adapter,
1518
+ ...ifDefined("driver", ctx.config.driver),
1519
+ extensions: ctx.config.extensions ?? []
1520
+ });
1521
+ const onProgress = controlProgressReporter(ctx.report);
1522
+ try {
1523
+ const verified = await client.schemaVerify({
1524
+ contract: contractInput,
1525
+ strict: false,
1526
+ connection: dbConnection,
1527
+ onProgress
1528
+ });
1529
+ if (!verified.ok) {
1530
+ const document = verified;
1531
+ return ok(ctx.present({
1532
+ data: document,
1533
+ exitCode: FINDINGS_EXIT_CODE$2,
1534
+ diagnostics: [schemaVerdictDiagnostic({
1535
+ result: verified,
1536
+ space: void 0,
1537
+ nextActions: [runCommandAction("Bring the database up to the contract, then sign again", "prisma-next db update")]
1538
+ })]
1539
+ }, refusedPresentations({
1540
+ document,
1541
+ header
1542
+ })));
1543
+ }
1544
+ const signed = await client.sign({
1545
+ contract: contractInput,
1546
+ contractPath: displayPath(emitted.value.path, ctx.cwd),
1547
+ configPath: CONFIG_DISPLAY_PATH,
1548
+ onProgress
1549
+ });
1550
+ if (!signed.ok) throw new InternalError(`The family returned a sign result that did not sign: ${signed.summary}`);
1551
+ return ok(ctx.present({
1552
+ data: signed,
1553
+ exitCode: 0
1554
+ }, signPresentations({
1555
+ document: signed,
1556
+ header
1557
+ })));
1558
+ } catch (error) {
1559
+ if (isInternalError(error)) throw error;
1560
+ return notOk(verificationThrow({
1561
+ error,
1562
+ invocation: "db sign",
1563
+ connection: dbConnection
1564
+ }));
1565
+ } finally {
1566
+ await closeQuietly(client);
1567
+ }
1568
+ }
1569
+ });
1570
+ }
1571
+ const dbSignCommand = createDbSignCommand();
1572
+ /**
1180
1573
  * A `db update` failure as the CLI's structured error.
1181
1574
  *
1182
1575
  * `DESTRUCTIVE_CHANGES` is handled by the command, which asks for consent and
@@ -1440,85 +1833,1503 @@ function createDbUpdateCommand(createClient) {
1440
1833
  });
1441
1834
  }
1442
1835
  const dbUpdateCommand = createDbUpdateCommand(createControlClient);
1443
- const NOTHING_TO_FORMAT = "Nothing to format (contract source is not PSL).";
1444
- function formatPresentations(document, cwd) {
1445
- const path = document.path;
1446
- return {
1447
- human: () => document.formatted && path !== void 0 ? [{
1448
- kind: "summary",
1449
- status: "ok",
1450
- text: [{ text: "Formatted " }, {
1451
- text: relative(cwd, path),
1452
- tone: "identifier"
1453
- }]
1454
- }] : [{
1455
- kind: "summary",
1456
- status: "info",
1457
- text: NOTHING_TO_FORMAT
1836
+ /**
1837
+ * Verification ran and the database does not match the contract. The run did
1838
+ * the job it was asked to do, so this is a completed settlement carrying
1839
+ * diagnostics rather than an error.
1840
+ */
1841
+ const FINDINGS_EXIT_CODE$1 = 4;
1842
+ const PUSH_THE_CONTRACT = runCommandAction("Push the contract to the database", "prisma-next db update");
1843
+ const RECONCILE_BY_HAND = {
1844
+ kind: "user-choice",
1845
+ label: "Or reconcile the differences by hand and verify again"
1846
+ };
1847
+ function errorInvalidVerifyMode(options) {
1848
+ return new CliStructuredError$1("CLI.INVALID_VERIFY_MODE", "Invalid verify mode", {
1849
+ why: options.why,
1850
+ nextActions: [{
1851
+ kind: "user-choice",
1852
+ label: options.choose
1458
1853
  }],
1459
- json: () => document
1460
- };
1461
- }
1462
- function createFormatCommand$1(execute = executeFormat) {
1463
- return defineOrmCommand({
1464
- help: {
1465
- summary: "Format your PSL contract source",
1466
- description: "Formats the Prisma schema (PSL) contract source declared in your config\n(contract.source.inputs[0]) in place. Only runs when contract.source.format\nis 'psl'; a TypeScript or unset source is left untouched. Indent and newline\nare read from the optional formatter config section, defaulting to two\nspaces and the system newline.",
1467
- examples: ["format", "format --json"]
1468
- },
1469
- needs: { config: ormConfigSection },
1470
- handler: async (_args, ctx) => {
1471
- const result = await execute({
1472
- config: ctx.config,
1473
- cwd: ctx.cwd
1474
- });
1475
- if (!result.ok) return notOk(normalizeError(result.failure));
1476
- return ok(ctx.present({ data: result.value }, formatPresentations(result.value, ctx.cwd)));
1477
- }
1854
+ docsUrl: "https://pris.ly/db-verify"
1478
1855
  });
1479
1856
  }
1480
- const formatCommand = createFormatCommand$1();
1481
- const STATUS_ACTION = runCommandAction("Check every space against the database", "prisma-next migration status");
1857
+ function resolveMode(flags) {
1858
+ if (flags.markerOnly && flags.schemaOnly) return notOk(errorInvalidVerifyMode({
1859
+ why: "`--marker-only` and `--schema-only` cannot be used together",
1860
+ choose: "Choose one mode: omit both to check the marker and schema, use `--marker-only` to check only the marker, or use `--schema-only` to check only the live schema."
1861
+ }));
1862
+ if (flags.markerOnly && flags.strict) return notOk(errorInvalidVerifyMode({
1863
+ why: "`--strict` requires schema verification, but `--marker-only` skips it",
1864
+ choose: "Remove `--strict`, or use `db verify` / `db verify --schema-only` when you want to check the live schema in strict mode."
1865
+ }));
1866
+ if (flags.schemaOnly) return ok("schema-only");
1867
+ return ok(flags.markerOnly ? "marker-only" : "full");
1868
+ }
1869
+ function modeLabel(mode, strict) {
1870
+ if (mode === "marker-only") return "marker only";
1871
+ const strictness = strict ? "strict" : "tolerant";
1872
+ return mode === "schema-only" ? `schema only (${strictness})` : `full (marker + schema, ${strictness})`;
1873
+ }
1874
+ function invocation(mode, strict) {
1875
+ return [
1876
+ "db verify",
1877
+ ...mode === "marker-only" ? ["--marker-only"] : [],
1878
+ ...mode === "schema-only" ? ["--schema-only"] : [],
1879
+ ...strict ? ["--strict"] : []
1880
+ ].join(" ");
1881
+ }
1882
+ /** The marker verdict as a finding, keeping the code the commander raised. */
1883
+ function markerFindingDiagnostic(result) {
1884
+ const { ok: _ok, ...diagnostic } = normalizeError(markerFindingError(result)).toEnvelope();
1885
+ return diagnostic;
1886
+ }
1482
1887
  /**
1483
- * The route the migration will take. The graph is a drawing the engine cannot
1484
- * derive a lane gutter — and the ordered list under it is drawn with the same
1485
- * widths so every arrow lands in one column.
1888
+ * The aggregate verifier's per-space marker drift as a finding on a completed
1889
+ * run, keeping the `MIGRATION.CONTRACT_SPACE_VIOLATION` envelope it was
1890
+ * raised with.
1486
1891
  */
1487
- function showPresentations$1(inputs) {
1488
- const { document, graph, runList } = inputs;
1489
- const count = document.migrations.length;
1892
+ function markerDriftDiagnostic(drift) {
1893
+ const { ok: _ok, ...diagnostic } = normalizeError(drift).toEnvelope();
1894
+ return diagnostic;
1895
+ }
1896
+ function markerFindingError(result) {
1897
+ if (result.code === VERIFY_CODE_MARKER_MISSING) return errorMarkerMissing();
1898
+ if (result.code === VERIFY_CODE_HASH_MISMATCH) {
1899
+ if (!(result.marker?.storageHash === result.contract.storageHash)) return errorHashMismatch({
1900
+ why: "Contract storageHash does not match database marker",
1901
+ expected: result.contract.storageHash,
1902
+ ...ifDefined("actual", result.marker?.storageHash)
1903
+ });
1904
+ return errorHashMismatch({
1905
+ why: !result.contract.profileHash || result.marker?.profileHash === result.contract.profileHash ? "Contract hash does not match database marker" : "Contract profileHash does not match database marker",
1906
+ ...ifDefined("expected", result.contract.profileHash),
1907
+ ...ifDefined("actual", result.marker?.profileHash)
1908
+ });
1909
+ }
1910
+ if (result.code === VERIFY_CODE_TARGET_MISMATCH) return errorTargetMismatch(result.target.expected, result.target.actual ?? "unknown");
1911
+ return errorRuntime$1("CONTRACT.VERIFY_FAILED", result.summary, {
1912
+ why: "Verification failed",
1913
+ fix: "Check contract and database state"
1914
+ });
1915
+ }
1916
+ function verifyDocument(inputs) {
1917
+ return {
1918
+ ok: inputs.ok,
1919
+ summary: inputs.summary,
1920
+ mode: inputs.mode,
1921
+ contract: inputs.verified.contract,
1922
+ ...ifDefined("marker", inputs.verified.marker),
1923
+ target: inputs.verified.target,
1924
+ ...ifDefined("missingCodecs", inputs.verified.missingCodecs),
1925
+ ...ifDefined("codecCoverageSkipped", inputs.verified.codecCoverageSkipped),
1926
+ ...ifDefined("schema", inputs.schema),
1927
+ ...ifDefined("unclaimed", inputs.unclaimed),
1928
+ ...ifDefined("warning", inputs.warning),
1929
+ meta: {
1930
+ ...inputs.verified.meta ?? {},
1931
+ schemaVerification: inputs.schemaVerification
1932
+ },
1933
+ timings: { total: inputs.elapsed }
1934
+ };
1935
+ }
1936
+ function schemaSummary(combined) {
1937
+ return {
1938
+ summary: combined.result.summary,
1939
+ strict: combined.result.meta?.strict ?? false,
1940
+ warnings: (combined.result.schema.warnings?.issues ?? []).map((issue) => issue.path.join("/"))
1941
+ };
1942
+ }
1943
+ function headerBlock(inputs) {
1944
+ return {
1945
+ kind: "fields",
1946
+ rail: true,
1947
+ rows: [
1948
+ {
1949
+ label: "contract",
1950
+ value: inputs.contractPath
1951
+ },
1952
+ {
1953
+ label: "mode",
1954
+ value: modeLabel(inputs.mode, inputs.strict)
1955
+ },
1956
+ {
1957
+ label: "database",
1958
+ value: inputs.database
1959
+ }
1960
+ ]
1961
+ };
1962
+ }
1963
+ function verifyPresentations(inputs) {
1964
+ const document = inputs.document;
1965
+ const warnings = document.schema?.warnings ?? [];
1966
+ const unclaimed = document.unclaimed ?? [];
1490
1967
  return {
1491
1968
  human: () => [
1969
+ inputs.header,
1492
1970
  {
1493
- kind: "fields",
1494
- rail: true,
1495
- rows: [
1496
- {
1497
- label: "migrations",
1498
- value: inputs.migrationsDir
1499
- },
1500
- ...inputs.database === void 0 ? [] : [{
1501
- label: "database",
1502
- value: inputs.database
1503
- }],
1504
- ...inputs.from === void 0 ? [] : [{
1505
- label: "from",
1506
- value: inputs.from
1507
- }],
1508
- ...inputs.to === void 0 ? [] : [{
1509
- label: "to",
1510
- value: inputs.to
1511
- }]
1512
- ]
1971
+ kind: "summary",
1972
+ status: document.ok ? "ok" : "error",
1973
+ text: document.summary
1513
1974
  },
1514
- ...graph.length === 0 ? [] : [{
1515
- kind: "drawing",
1516
- lines: toneDrawing(graph)
1975
+ ...document.ok ? [{
1976
+ kind: "fields",
1977
+ rows: [{
1978
+ label: "storageHash",
1979
+ value: document.contract.storageHash
1980
+ }, ...document.contract.profileHash === void 0 ? [] : [{
1981
+ label: "profileHash",
1982
+ value: document.contract.profileHash
1983
+ }]]
1984
+ }] : [],
1985
+ ...warnings.length === 0 && unclaimed.length === 0 ? [] : [{
1986
+ kind: "tree",
1987
+ roots: [...warnings.length === 0 ? [] : [{
1988
+ label: "Schema warnings",
1989
+ status: "warn",
1990
+ children: warnings.map((message) => ({
1991
+ label: message,
1992
+ status: "warn"
1993
+ }))
1994
+ }], ...unclaimed.length === 0 ? [] : [{
1995
+ label: "Unclaimed elements (declared by no contract)",
1996
+ status: "warn",
1997
+ children: unclaimed.map((name) => ({
1998
+ label: name,
1999
+ status: "warn"
2000
+ }))
2001
+ }]]
1517
2002
  }],
1518
- ...count === 0 ? [{
2003
+ ...document.warning === void 0 ? [] : [{
1519
2004
  kind: "summary",
1520
- status: "info",
1521
- text: document.summary
2005
+ status: "warn",
2006
+ text: document.warning
2007
+ }]
2008
+ ],
2009
+ json: () => document
2010
+ };
2011
+ }
2012
+ function schemaPresentations(inputs) {
2013
+ return {
2014
+ human: () => [
2015
+ inputs.header,
2016
+ ...schemaFindingBlocks({
2017
+ result: inputs.document,
2018
+ unclaimed: inputs.document.unclaimed,
2019
+ strict: inputs.strict
2020
+ }),
2021
+ {
2022
+ kind: "summary",
2023
+ status: inputs.document.ok ? "ok" : "error",
2024
+ text: inputs.document.summary
2025
+ }
2026
+ ],
2027
+ json: () => inputs.document
2028
+ };
2029
+ }
2030
+ /**
2031
+ * One diagnostic per contract space whose live schema does not satisfy its
2032
+ * contract, plus the combined verdict when only the unclaimed list failed it.
2033
+ */
2034
+ function driftDiagnostics(inputs) {
2035
+ const perSpace = [...inputs.perSpace].filter(([, result]) => !result.ok).map(([space, result]) => schemaVerdictDiagnostic({
2036
+ result,
2037
+ space,
2038
+ nextActions: [PUSH_THE_CONTRACT, RECONCILE_BY_HAND]
2039
+ }));
2040
+ if (perSpace.length > 0) return perSpace;
2041
+ return [schemaVerdictDiagnostic({
2042
+ result: inputs.combined.result,
2043
+ space: void 0,
2044
+ nextActions: [{
2045
+ kind: "user-choice",
2046
+ label: "Declare the unclaimed elements in a contract, or drop them from the database"
2047
+ }]
2048
+ })];
2049
+ }
2050
+ /**
2051
+ * Builds the command with its control-client factory injected, so tests mount
2052
+ * the same tree over a fake client instead of mocking the client module.
2053
+ */
2054
+ function createDbVerifyCommand(createClient = createControlClient) {
2055
+ return defineOrmCommand({
2056
+ help: {
2057
+ summary: "Check whether the database marker and live schema match your contract",
2058
+ description: "Verifies the database marker first, then checks the database schema\nmatches your contract. Use `--marker-only` for marker-only verification,\n`--schema-only` to skip marker checks and inspect only the live schema,\nand `--strict` to fail if the database includes elements not present in\nthe contract.\nExit codes: 0 = the database matches the contract, 2 = the check could\nnot run (conflicting mode flags, no emitted contract, unreachable\ndatabase), 4 = drift or a marker finding.",
2059
+ examples: [
2060
+ "db verify",
2061
+ "db verify --db $DATABASE_URL",
2062
+ "db verify --strict",
2063
+ "db verify --schema-only",
2064
+ "db verify --marker-only",
2065
+ "db verify --json"
2066
+ ]
2067
+ },
2068
+ args: { flags: {
2069
+ db: dbFlag,
2070
+ markerOnly: flag.boolean({ brief: "Skip schema verification and only check the database marker" }),
2071
+ schemaOnly: flag.boolean({ brief: "Skip marker verification and only check whether the live schema satisfies the contract" }),
2072
+ strict: flag.boolean({ brief: "Treat schema elements not present in the contract as an error" })
2073
+ } },
2074
+ needs: { config: ormConfigSection },
2075
+ exitCodes: { 4: "verification found drift or marker findings" },
2076
+ handler: async (args, ctx) => {
2077
+ const strict = args.flags.strict;
2078
+ const resolved = resolveMode({
2079
+ markerOnly: args.flags.markerOnly,
2080
+ schemaOnly: args.flags.schemaOnly,
2081
+ strict
2082
+ });
2083
+ if (!resolved.ok) return notOk(resolved.failure);
2084
+ const mode = resolved.value;
2085
+ const commandInvocation = invocation(mode, strict);
2086
+ const emitted = await readEmittedContract({
2087
+ config: ctx.config,
2088
+ cwd: ctx.cwd,
2089
+ commandName: commandInvocation
2090
+ });
2091
+ if (!emitted.ok) return notOk(emitted.failure);
2092
+ const connection = requireVerifyConnection({
2093
+ config: ctx.config,
2094
+ db: args.flags.db,
2095
+ invocation: commandInvocation
2096
+ });
2097
+ if (!connection.ok) return notOk(connection.failure);
2098
+ const dbConnection = connection.value;
2099
+ const header = headerBlock({
2100
+ contractPath: emitted.value.displayPath,
2101
+ mode,
2102
+ strict,
2103
+ database: maskConnectionUrl(dbConnection)
2104
+ });
2105
+ const migrationsDir = migrationsDirFor(ctx.config, ctx.cwd);
2106
+ const client = createClient({
2107
+ family: ctx.config.family,
2108
+ target: ctx.config.target,
2109
+ adapter: ctx.config.adapter,
2110
+ ...ifDefined("driver", ctx.config.driver),
2111
+ extensions: ctx.config.extensions ?? []
2112
+ });
2113
+ const onProgress = controlProgressReporter(ctx.report);
2114
+ const startedAt = Date.now();
2115
+ try {
2116
+ if (mode === "schema-only") {
2117
+ await client.connect(dbConnection);
2118
+ const aggregate = await client.dbVerify({
2119
+ contract: emitted.value.contract,
2120
+ migrationsDir,
2121
+ strict,
2122
+ skipSchema: false,
2123
+ skipMarker: true,
2124
+ onProgress
2125
+ });
2126
+ if (!aggregate.ok) return notOk(normalizeError(aggregate.failure));
2127
+ const combined = combineVerifyResults(aggregate.value.schemaResults, aggregate.value.appSpaceId, strict, aggregate.value.unclaimed);
2128
+ const document = {
2129
+ ...combined.result,
2130
+ unclaimed: combined.unclaimed
2131
+ };
2132
+ return ok(ctx.present({
2133
+ data: document,
2134
+ exitCode: combined.result.ok ? 0 : FINDINGS_EXIT_CODE$1,
2135
+ diagnostics: combined.result.ok ? [] : driftDiagnostics({
2136
+ perSpace: aggregate.value.schemaResults,
2137
+ combined
2138
+ })
2139
+ }, schemaPresentations({
2140
+ document,
2141
+ header,
2142
+ strict
2143
+ })));
2144
+ }
2145
+ const verified = await client.verify({
2146
+ contract: emitted.value.contract,
2147
+ connection: dbConnection,
2148
+ onProgress
2149
+ });
2150
+ if (!verified.ok) {
2151
+ const document = verifyDocument({
2152
+ ok: false,
2153
+ mode,
2154
+ summary: verified.summary,
2155
+ verified,
2156
+ schema: void 0,
2157
+ schemaVerification: "skipped",
2158
+ unclaimed: void 0,
2159
+ warning: void 0,
2160
+ elapsed: Date.now() - startedAt
2161
+ });
2162
+ return ok(ctx.present({
2163
+ data: document,
2164
+ exitCode: FINDINGS_EXIT_CODE$1,
2165
+ diagnostics: [markerFindingDiagnostic(verified)]
2166
+ }, verifyPresentations({
2167
+ document,
2168
+ header
2169
+ })));
2170
+ }
2171
+ const aggregate = await client.dbVerify({
2172
+ contract: emitted.value.contract,
2173
+ migrationsDir,
2174
+ strict,
2175
+ skipSchema: mode === "marker-only",
2176
+ skipMarker: false,
2177
+ onProgress
2178
+ });
2179
+ if (!aggregate.ok) return notOk(normalizeError(aggregate.failure));
2180
+ const drift = aggregate.value.markerDrift;
2181
+ if (drift !== null) {
2182
+ const driftCombined = mode === "marker-only" ? void 0 : combineVerifyResults(aggregate.value.schemaResults, aggregate.value.appSpaceId, strict, aggregate.value.unclaimed);
2183
+ const document = verifyDocument({
2184
+ ok: false,
2185
+ mode,
2186
+ summary: normalizeError(drift).message,
2187
+ verified,
2188
+ schema: driftCombined === void 0 ? void 0 : schemaSummary(driftCombined),
2189
+ schemaVerification: driftCombined === void 0 ? "skipped" : "performed",
2190
+ unclaimed: driftCombined?.unclaimed,
2191
+ warning: void 0,
2192
+ elapsed: Date.now() - startedAt
2193
+ });
2194
+ return ok(ctx.present({
2195
+ data: document,
2196
+ exitCode: FINDINGS_EXIT_CODE$1,
2197
+ diagnostics: [markerDriftDiagnostic(drift), ...driftCombined !== void 0 && !driftCombined.result.ok ? driftDiagnostics({
2198
+ perSpace: aggregate.value.schemaResults,
2199
+ combined: driftCombined
2200
+ }) : []]
2201
+ }, verifyPresentations({
2202
+ document,
2203
+ header
2204
+ })));
2205
+ }
2206
+ if (mode === "marker-only") {
2207
+ const document = verifyDocument({
2208
+ ok: true,
2209
+ mode,
2210
+ summary: "Database marker matches contract",
2211
+ verified,
2212
+ schema: void 0,
2213
+ schemaVerification: "skipped",
2214
+ unclaimed: void 0,
2215
+ warning: "Schema verification skipped because --marker-only was provided",
2216
+ elapsed: Date.now() - startedAt
2217
+ });
2218
+ return ok(ctx.present({
2219
+ data: document,
2220
+ exitCode: 0
2221
+ }, verifyPresentations({
2222
+ document,
2223
+ header
2224
+ })));
2225
+ }
2226
+ const combined = combineVerifyResults(aggregate.value.schemaResults, aggregate.value.appSpaceId, strict, aggregate.value.unclaimed);
2227
+ if (!combined.result.ok) {
2228
+ const document = {
2229
+ ...combined.result,
2230
+ unclaimed: combined.unclaimed
2231
+ };
2232
+ return ok(ctx.present({
2233
+ data: document,
2234
+ exitCode: FINDINGS_EXIT_CODE$1,
2235
+ diagnostics: driftDiagnostics({
2236
+ perSpace: aggregate.value.schemaResults,
2237
+ combined
2238
+ })
2239
+ }, schemaPresentations({
2240
+ document,
2241
+ header,
2242
+ strict
2243
+ })));
2244
+ }
2245
+ const document = verifyDocument({
2246
+ ok: true,
2247
+ mode,
2248
+ summary: "Database marker and schema match contract",
2249
+ verified,
2250
+ schema: schemaSummary(combined),
2251
+ schemaVerification: "performed",
2252
+ unclaimed: combined.unclaimed,
2253
+ warning: void 0,
2254
+ elapsed: Date.now() - startedAt
2255
+ });
2256
+ return ok(ctx.present({
2257
+ data: document,
2258
+ exitCode: 0
2259
+ }, verifyPresentations({
2260
+ document,
2261
+ header
2262
+ })));
2263
+ } catch (error) {
2264
+ if (isInternalError(error)) throw error;
2265
+ return notOk(verificationThrow({
2266
+ error,
2267
+ invocation: commandInvocation,
2268
+ connection: dbConnection
2269
+ }));
2270
+ } finally {
2271
+ await closeQuietly(client);
2272
+ }
2273
+ }
2274
+ });
2275
+ }
2276
+ const dbVerifyCommand = createDbVerifyCommand();
2277
+ const NOTHING_TO_FORMAT = "Nothing to format (contract source is not PSL).";
2278
+ function formatPresentations(document, cwd) {
2279
+ const path = document.path;
2280
+ return {
2281
+ human: () => document.formatted && path !== void 0 ? [{
2282
+ kind: "summary",
2283
+ status: "ok",
2284
+ text: [{ text: "Formatted " }, {
2285
+ text: relative(cwd, path),
2286
+ tone: "identifier"
2287
+ }]
2288
+ }] : [{
2289
+ kind: "summary",
2290
+ status: "info",
2291
+ text: NOTHING_TO_FORMAT
2292
+ }],
2293
+ json: () => document
2294
+ };
2295
+ }
2296
+ function createFormatCommand$1(execute = executeFormat) {
2297
+ return defineOrmCommand({
2298
+ help: {
2299
+ summary: "Format your PSL contract source",
2300
+ description: "Formats the Prisma schema (PSL) contract source declared in your config\n(contract.source.inputs[0]) in place. Only runs when contract.source.format\nis 'psl'; a TypeScript or unset source is left untouched. Indent and newline\nare read from the optional formatter config section, defaulting to two\nspaces and the system newline.",
2301
+ examples: ["format", "format --json"]
2302
+ },
2303
+ needs: { config: ormConfigSection },
2304
+ handler: async (_args, ctx) => {
2305
+ const result = await execute({
2306
+ config: ctx.config,
2307
+ cwd: ctx.cwd
2308
+ });
2309
+ if (!result.ok) return notOk(normalizeError(result.failure));
2310
+ return ok(ctx.present({ data: result.value }, formatPresentations(result.value, ctx.cwd)));
2311
+ }
2312
+ });
2313
+ }
2314
+ const formatCommand = createFormatCommand$1();
2315
+ /** The invocation that finishes what a failed `init` phase started. */
2316
+ const EMIT_COMMAND = "prisma-next contract emit";
2317
+ /**
2318
+ * The command's own record of a phase that failed after the scaffold was
2319
+ * written. The scaffold is on disk and the run has a result to report, so each
2320
+ * of these rides a completed envelope as a finding rather than replacing it.
2321
+ */
2322
+ function initFinding(code, summary, parts) {
2323
+ return {
2324
+ code,
2325
+ severity: "error",
2326
+ summary,
2327
+ why: parts.why,
2328
+ nextActions: parts.nextActions,
2329
+ meta: parts.meta,
2330
+ docsUrl: docsUrlFor(code)
2331
+ };
2332
+ }
2333
+ /**
2334
+ * The dependency install failed. The engine composed and announced the command
2335
+ * line, so its own next action — which carries the redacted spelling — is the
2336
+ * one that tells the user what to run; `init` adds the emit that was waiting
2337
+ * on it.
2338
+ */
2339
+ function installFailedFinding(failure, filesWritten) {
2340
+ return initFinding("CLI.INIT_INSTALL_FAILED", "Failed to install dependencies", {
2341
+ why: failure.why ?? failure.message,
2342
+ nextActions: [...failure.nextActions, runCommandAction("Emit the contract once the dependencies are installed", EMIT_COMMAND)],
2343
+ meta: {
2344
+ filesWritten,
2345
+ install: failure.meta ?? {}
2346
+ }
2347
+ });
2348
+ }
2349
+ /** The first emit failed against the freshly written scaffold. */
2350
+ function emitFailedFinding(cause, filesWritten) {
2351
+ return initFinding("CLI.INIT_EMIT_FAILED", "Failed to emit contract", {
2352
+ why: `\`${EMIT_COMMAND}\` failed: ${cause}`,
2353
+ nextActions: [chooseAction("Fix the problem the contract source reports, then emit again"), runCommandAction("Emit the contract", EMIT_COMMAND)],
2354
+ meta: {
2355
+ filesWritten,
2356
+ cause
2357
+ }
2358
+ });
2359
+ }
2360
+ /**
2361
+ * An agent-skill install failed; the project itself is complete without it.
2362
+ * The remedy is the skill-install commands themselves, which run against any
2363
+ * directory — advising a re-run of `init` would put the user's schema at risk
2364
+ * to fix something `init` no longer needs to be involved in.
2365
+ */
2366
+ function skillInstallFailedFinding(failure, filesWritten, skillCommands) {
2367
+ return initFinding("CLI.INIT_SKILL_INSTALL_FAILED", "Failed to install Prisma Next skills", {
2368
+ why: failure.why ?? failure.message,
2369
+ nextActions: [...failure.nextActions, ...skillCommands.map((command) => runCommandAction("Install the Prisma Next skills", command))],
2370
+ meta: {
2371
+ filesWritten,
2372
+ skillInstall: failure.meta ?? {}
2373
+ }
2374
+ });
2375
+ }
2376
+ function fileNodes(paths) {
2377
+ return paths.map((path) => ({
2378
+ label: path,
2379
+ tone: "identifier"
2380
+ }));
2381
+ }
2382
+ function scaffoldTree(document) {
2383
+ const roots = [{
2384
+ label: "written",
2385
+ tone: "heading",
2386
+ children: fileNodes(document.filesWritten)
2387
+ }];
2388
+ if (document.filesDeleted.length > 0) roots.push({
2389
+ label: "removed (stale artifacts and retired skill directories)",
2390
+ tone: "heading",
2391
+ children: fileNodes(document.filesDeleted)
2392
+ });
2393
+ const installed = document.packagesInstalled;
2394
+ if (installed.status === "installed") roots.push({
2395
+ label: "installed",
2396
+ tone: "heading",
2397
+ children: [...fileNodes(installed.deps), ...installed.devDeps.map((dep) => ({
2398
+ label: `${dep} (dev)`,
2399
+ tone: "identifier"
2400
+ }))]
2401
+ });
2402
+ return {
2403
+ kind: "tree",
2404
+ roots
2405
+ };
2406
+ }
2407
+ /**
2408
+ * The scaffold's follow-up steps, typed. `nextSteps` in the result document
2409
+ * keeps its numbered prose for consumers that already read it; these are the
2410
+ * same advice in the shape an agent can act on.
2411
+ */
2412
+ function buildInitNextActions(inputs) {
2413
+ const actions = [chooseAction("Set DATABASE_URL in your environment (export it or add it to .env)")];
2414
+ if (!inputs.contractEmitted) actions.push(runCommandAction("Emit the contract", EMIT_COMMAND));
2415
+ actions.push({
2416
+ kind: "edit-file",
2417
+ label: `Edit your schema at ${inputs.schemaPath}, then emit again`
2418
+ });
2419
+ actions.push(chooseAction("Open prisma-next.md for a quick reference on writing your first typed query"));
2420
+ if (inputs.skillRegistered) actions.push(chooseAction("Prisma Next skills are registered with your agent runtime — ask it to add a model, run a query, or plan a migration"));
2421
+ return actions;
2422
+ }
2423
+ const DONE_TEXT = "Done. Open prisma-next.md to get started.";
2424
+ const INCOMPLETE_TEXT = "Scaffold written. Finish the steps above to complete setup.";
2425
+ /**
2426
+ * `init` writes files rather than data another program reads, so it supplies
2427
+ * no `stdout` payload: human mode writes nothing to stdout.
2428
+ */
2429
+ function initPresentations(inputs) {
2430
+ const { document } = inputs;
2431
+ return {
2432
+ human: () => [
2433
+ {
2434
+ kind: "fields",
2435
+ rail: true,
2436
+ rows: [
2437
+ {
2438
+ label: "target",
2439
+ value: document.target
2440
+ },
2441
+ {
2442
+ label: "authoring",
2443
+ value: document.authoring
2444
+ },
2445
+ {
2446
+ label: "schema",
2447
+ value: document.schemaPath
2448
+ }
2449
+ ]
2450
+ },
2451
+ scaffoldTree(document),
2452
+ inputs.complete ? {
2453
+ kind: "summary",
2454
+ status: "ok",
2455
+ text: DONE_TEXT
2456
+ } : {
2457
+ kind: "summary",
2458
+ status: "warn",
2459
+ text: INCOMPLETE_TEXT
2460
+ }
2461
+ ],
2462
+ json: () => document,
2463
+ next: () => inputs.nextActions
2464
+ };
2465
+ }
2466
+ /**
2467
+ * Emits the contract for the project `init` has just scaffolded.
2468
+ *
2469
+ * The config file is the one this run wrote, so it is read here rather than
2470
+ * through `needs.config`: `init` runs where no config exists yet, and the
2471
+ * engine loads a section before the handler starts. The emitter and the config
2472
+ * loader are imported at execution time so a run that skips the install — and
2473
+ * therefore skips the emit — never pays for either.
2474
+ */
2475
+ async function emitScaffoldedContract(ctx) {
2476
+ const { executeContractEmit } = await import("./contract-emit-DDWBBvF1-BeGZCRrb.mjs");
2477
+ const { loadConfigForSections } = await import("./exports-BZLNbtkY.mjs").then((n) => n.t);
2478
+ const configPath = join(ctx.cwd, "prisma-next.config.ts");
2479
+ const loaded = await loadConfigForSections(configPath, [
2480
+ "contract",
2481
+ "family",
2482
+ "target",
2483
+ "adapter",
2484
+ "extensions"
2485
+ ]);
2486
+ if (!loaded.ok) throw loaded.failure;
2487
+ await executeContractEmit({
2488
+ config: loaded.value,
2489
+ cwd: ctx.cwd,
2490
+ configPath
2491
+ });
2492
+ }
2493
+ const CONFIG_FILE = "prisma-next.config.ts";
2494
+ const QUICK_REFERENCE_FILE = "prisma-next.md";
2495
+ const ENV_EXAMPLE_FILE = ".env.example";
2496
+ /**
2497
+ * The generated files a run replaces outright, in the order it writes them.
2498
+ * Everything else the scaffold touches it merges (`tsconfig.json`,
2499
+ * `package.json`, the git files) or keeps (`.env`, `README.md`), so replacing
2500
+ * one of these is the destructive act consent is asked for.
2501
+ *
2502
+ * `.env.example` is written the same way but deliberately left out: it is a
2503
+ * conventional filename in projects that have never seen Prisma Next, and a
2504
+ * consent token demanded for it would fire on first runs. The scaffold warns
2505
+ * when it replaces one instead.
2506
+ */
2507
+ function generatedFilesInitReplaces(schemaPath) {
2508
+ return [
2509
+ schemaPath,
2510
+ CONFIG_FILE,
2511
+ join(dirname(schemaPath), "db.ts"),
2512
+ QUICK_REFERENCE_FILE
2513
+ ];
2514
+ }
2515
+ const MANAGERS = /* @__PURE__ */ new Set([
2516
+ "pnpm",
2517
+ "npm",
2518
+ "yarn",
2519
+ "bun",
2520
+ "deno"
2521
+ ]);
2522
+ function isPackageManager(name) {
2523
+ return MANAGERS.has(name);
2524
+ }
2525
+ /**
2526
+ * The manager the scaffolded quick reference and README name in their example
2527
+ * commands. It resolves the way the engine's package operations resolve theirs
2528
+ * — the project at `cwd` first, then the manager that invoked this process —
2529
+ * so the documentation `init` writes names the manager `init` drove. The
2530
+ * capability itself reports no manager back on success, which is why this is
2531
+ * worked out a second time here.
2532
+ */
2533
+ async function resolveScaffoldPackageManager(ctx) {
2534
+ const detected = await detect({ cwd: ctx.cwd });
2535
+ if (detected !== null && isPackageManager(detected.name)) return detected.name;
2536
+ const invoking = ctx.env["npm_config_user_agent"]?.split("/")[0];
2537
+ return invoking !== void 0 && isPackageManager(invoking) ? invoking : "npm";
2538
+ }
2539
+ /**
2540
+ * True when the parsed manifest declares `name` directly in `dependencies` or
2541
+ * `devDependencies`. Transitive presence is deliberately ignored: detecting it
2542
+ * needs the lockfile, and the realistic risk is a direct pin being clobbered.
2543
+ */
2544
+ function hasDirectDep(parsed, name) {
2545
+ for (const field of ["dependencies", "devDependencies"]) {
2546
+ const value = parsed[field];
2547
+ if (value !== null && typeof value === "object" && name in value) return true;
2548
+ }
2549
+ return false;
2550
+ }
2551
+ /**
2552
+ * npm package names are lowercase and URL-safe; `basename(cwd)` happily
2553
+ * returns "My Project" or ".hidden", both of which npm refuses to read.
2554
+ */
2555
+ function sanitisePackageName(raw) {
2556
+ const trimmed = raw.toLowerCase().replace(/[^a-z0-9._~-]/g, "-").replace(/^[._-]+/, "").replace(/-+/g, "-");
2557
+ return trimmed.length > 0 ? trimmed : "my-app";
2558
+ }
2559
+ /**
2560
+ * The manifest `init` writes for a directory that has none. Private, so a
2561
+ * stray publish cannot leak the placeholder, and ESM so the scaffolded import
2562
+ * attributes load under Node's loader.
2563
+ */
2564
+ function defaultPackageJsonContent(rawName) {
2565
+ return `${JSON.stringify({
2566
+ name: sanitisePackageName(rawName),
2567
+ version: "0.0.0",
2568
+ private: true,
2569
+ type: "module"
2570
+ }, null, 2)}\n`;
2571
+ }
2572
+ function hasProjectManifest(cwd) {
2573
+ return existsSync(join(cwd, "package.json")) || existsSync(join(cwd, "deno.json")) || existsSync(join(cwd, "deno.jsonc"));
2574
+ }
2575
+ /**
2576
+ * Computes every write before touching disk: reads and parses each file the
2577
+ * scaffold merges with, so a malformed manifest or tsconfig fails with the
2578
+ * user's project byte-identical to how it started.
2579
+ */
2580
+ function planScaffold(ctx) {
2581
+ const { cwd, inputs, packageManager, resolveImportSpecifier } = ctx;
2582
+ const warnings = [];
2583
+ const schemaDir = dirname(inputs.schemaPath);
2584
+ const configContractPath = isAbsolute(inputs.schemaPath) ? inputs.schemaPath : `./${inputs.schemaPath}`;
2585
+ const runPrefix = formatRunCommand(packageManager, "prisma-next", "").trimEnd();
2586
+ const files = [
2587
+ {
2588
+ path: inputs.schemaPath,
2589
+ content: starterSchema(inputs.target, inputs.authoring, resolveImportSpecifier)
2590
+ },
2591
+ {
2592
+ path: CONFIG_FILE,
2593
+ content: configFile(inputs.target, configContractPath, resolveImportSpecifier)
2594
+ },
2595
+ {
2596
+ path: join(schemaDir, "db.ts"),
2597
+ content: dbFile(inputs.target, resolveImportSpecifier)
2598
+ },
2599
+ {
2600
+ path: QUICK_REFERENCE_FILE,
2601
+ content: quickReferenceMd(inputs.target, inputs.authoring, inputs.schemaPath, runPrefix, resolveImportSpecifier)
2602
+ },
2603
+ {
2604
+ path: ENV_EXAMPLE_FILE,
2605
+ content: envExampleContent(inputs.target)
2606
+ }
2607
+ ];
2608
+ if (existsSync(join(cwd, ENV_EXAMPLE_FILE))) warnings.push(`${ENV_EXAMPLE_FILE} already existed and was replaced with the Prisma Next template.`);
2609
+ const filesToDelete = inputs.reinit ? [...findStaleArtifacts(cwd, schemaDir)] : [];
2610
+ const dirsToDelete = legacySkillDirs().filter((rel) => existsSync(join(cwd, rel)));
2611
+ if (inputs.writeEnv) if (existsSync(join(cwd, ".env"))) warnings.push(".env already exists; leaving it untouched. Compare with .env.example for any new keys.");
2612
+ else files.push({
2613
+ path: ".env",
2614
+ content: envFileContent(inputs.target)
2615
+ });
2616
+ const tsconfigPath = join(cwd, "tsconfig.json");
2617
+ if (existsSync(tsconfigPath)) {
2618
+ const existing = readFileSync(tsconfigPath, "utf-8");
2619
+ let merged;
2620
+ try {
2621
+ merged = mergeTsConfig(existing);
2622
+ } catch (error) {
2623
+ if (error instanceof TsConfigParseError) throw errorInitInvalidTsconfig({
2624
+ path: "tsconfig.json",
2625
+ cause: error.message
2626
+ });
2627
+ throw error;
2628
+ }
2629
+ files.push({
2630
+ path: "tsconfig.json",
2631
+ content: merged,
2632
+ note: "Updated tsconfig.json with required compiler options."
2633
+ });
2634
+ } else files.push({
2635
+ path: "tsconfig.json",
2636
+ content: defaultTsConfig()
2637
+ });
2638
+ const gitignorePath = join(cwd, ".gitignore");
2639
+ const nextGitignore = mergeGitignore(existsSync(gitignorePath) ? readFileSync(gitignorePath, "utf-8") : void 0);
2640
+ if (nextGitignore !== null) files.push({
2641
+ path: ".gitignore",
2642
+ content: nextGitignore
2643
+ });
2644
+ const gitattributesPath = join(cwd, ".gitattributes");
2645
+ const nextGitattributes = mergeGitattributes(existsSync(gitattributesPath) ? readFileSync(gitattributesPath, "utf-8") : void 0, requiredGitattributesLines(schemaDir, inputs.target));
2646
+ if (nextGitattributes !== null) files.push({
2647
+ path: ".gitattributes",
2648
+ content: nextGitattributes
2649
+ });
2650
+ const manifestPath = join(cwd, "package.json");
2651
+ const manifestExisted = existsSync(manifestPath);
2652
+ const synthesiseManifest = !manifestExisted && !hasProjectManifest(cwd);
2653
+ let parsedManifest = null;
2654
+ if (manifestExisted || synthesiseManifest) {
2655
+ const raw = manifestExisted ? readFileSync(manifestPath, "utf-8") : defaultPackageJsonContent(basename(cwd));
2656
+ try {
2657
+ parsedManifest = JSON.parse(raw);
2658
+ } catch (error) {
2659
+ if (error instanceof SyntaxError) throw errorInitInvalidManifest({
2660
+ path: "package.json",
2661
+ cause: error.message
2662
+ });
2663
+ throw error;
2664
+ }
2665
+ let working = raw;
2666
+ let changed = synthesiseManifest;
2667
+ if (inputs.removePreviousFacade !== null) {
2668
+ const next = removeDependency(working, inputs.removePreviousFacade);
2669
+ if (next !== null) {
2670
+ working = next;
2671
+ changed = true;
2672
+ }
2673
+ }
2674
+ const { content: withScripts, warnings: scriptWarnings } = mergePackageScripts(working, REQUIRED_SCRIPTS);
2675
+ if (withScripts !== null) {
2676
+ working = withScripts;
2677
+ changed = true;
2678
+ }
2679
+ const { content: withType, warning: typeWarning } = ensureEsmModuleType(working);
2680
+ if (withType !== null) {
2681
+ working = withType;
2682
+ changed = true;
2683
+ }
2684
+ if (changed) files.push({
2685
+ path: "package.json",
2686
+ content: working
2687
+ });
2688
+ warnings.push(...scriptWarnings);
2689
+ if (typeWarning !== null) warnings.push(typeWarning);
2690
+ if (synthesiseManifest) warnings.push("No package.json found in the target directory; created a minimal one. Edit `name` / `version` to taste.");
2691
+ }
2692
+ if (existsSync(join(cwd, "src/index.ts"))) if (existsSync(join(cwd, "README.md"))) warnings.push("README.md already exists; leaving it untouched.");
2693
+ else {
2694
+ const declaredName = parsedManifest !== null && typeof parsedManifest["name"] === "string" ? parsedManifest["name"] : basename(cwd);
2695
+ files.push({
2696
+ path: "README.md",
2697
+ content: minimalProjectReadmeMd(inputs.target, inputs.schemaPath, sanitisePackageName(declaredName), packageManager)
2698
+ });
2699
+ }
2700
+ return {
2701
+ files,
2702
+ filesToDelete,
2703
+ dirsToDelete,
2704
+ warnings,
2705
+ hasTypesNode: parsedManifest !== null && hasDirectDep(parsedManifest, "@types/node")
2706
+ };
2707
+ }
2708
+ /**
2709
+ * Plans every write, then performs them. Everything that can fail on the
2710
+ * user's existing files fails during planning, so a failure leaves the project
2711
+ * as it was; after the first write, the scaffold is on disk to keep, and a
2712
+ * write that fails partway names the files that already landed.
2713
+ */
2714
+ function scaffoldProject(ctx) {
2715
+ const resolveImportSpecifier = scaffoldSpecifierResolverFor(ctx.inputs.target);
2716
+ const plan = planScaffold({
2717
+ ...ctx,
2718
+ resolveImportSpecifier
2719
+ });
2720
+ const filesWritten = [];
2721
+ const filesDeleted = [];
2722
+ const notes = [];
2723
+ for (const file of plan.files) {
2724
+ const target = join(ctx.cwd, file.path);
2725
+ try {
2726
+ mkdirSync(dirname(target), { recursive: true });
2727
+ writeFileSync(target, file.content, "utf-8");
2728
+ } catch (error) {
2729
+ throw errorInitWriteFailed({
2730
+ path: file.path,
2731
+ cause: error instanceof Error ? error.message : String(error),
2732
+ filesWritten
2733
+ });
2734
+ }
2735
+ filesWritten.push(file.path);
2736
+ if (file.note !== void 0) notes.push(file.note);
2737
+ }
2738
+ for (const rel of plan.filesToDelete) {
2739
+ const target = join(ctx.cwd, rel);
2740
+ if (!existsSync(target)) continue;
2741
+ try {
2742
+ unlinkSync(target);
2743
+ filesDeleted.push(rel);
2744
+ } catch (error) {
2745
+ if (!(error instanceof Error && Reflect.get(error, "code") === "ENOENT")) throw error;
2746
+ }
2747
+ }
2748
+ for (const rel of plan.dirsToDelete) {
2749
+ rmSync(join(ctx.cwd, rel), {
2750
+ recursive: true,
2751
+ force: true
2752
+ });
2753
+ filesDeleted.push(rel);
2754
+ }
2755
+ return {
2756
+ filesWritten,
2757
+ filesDeleted,
2758
+ warnings: plan.warnings,
2759
+ notes,
2760
+ hasTypesNode: plan.hasTypesNode,
2761
+ resolveImportSpecifier
2762
+ };
2763
+ }
2764
+ const REQUIRED_FLAG_PROMPTS = /* @__PURE__ */ new Set(["target", "authoring"]);
2765
+ function formatFileList(files) {
2766
+ const last = files.at(-1) ?? "";
2767
+ return files.length <= 1 ? last : `${files.slice(0, -1).join(", ")} and ${last}`;
2768
+ }
2769
+ /**
2770
+ * Names the files at stake rather than the category they belong to: the user
2771
+ * knows `contract.prisma`, not "every generated file".
2772
+ */
2773
+ function consentQuestion(replaced) {
2774
+ const written = replaced.length === 1 ? "it" : "them";
2775
+ return `Re-initializing replaces ${formatFileList(replaced)} with a fresh scaffold, losing anything you wrote in ${written}.`;
2776
+ }
2777
+ /**
2778
+ * The engine raises this when a prompt has no default and the session cannot
2779
+ * show it. For the two prompts that stand in for a required flag, that is the
2780
+ * same condition `init` has always reported as a missing flag.
2781
+ */
2782
+ function isPromptRequired(error) {
2783
+ return error instanceof Error && Reflect.get(error, "code") === "CLI.PROMPT_REQUIRED";
2784
+ }
2785
+ /**
2786
+ * `--confirm` matches a token, so the token has to be something the user can
2787
+ * see and type. The working directory's name is it; a directory with no name
2788
+ * of its own (the filesystem root) falls back to its path.
2789
+ *
2790
+ * Trimmed, because the engine compares the typed answer trimmed: an untrimmed
2791
+ * token from a directory named `my app ` is one no keystroke sequence matches.
2792
+ */
2793
+ function consentToken(cwd) {
2794
+ const name = basename(cwd).trim();
2795
+ return name.length > 0 ? name : cwd.trim();
2796
+ }
2797
+ async function askTarget(prompt) {
2798
+ return prompt.select("What database are you using?", [{
2799
+ value: "postgres",
2800
+ label: "PostgreSQL"
2801
+ }, {
2802
+ value: "mongo",
2803
+ label: "MongoDB"
2804
+ }]);
2805
+ }
2806
+ async function askAuthoring(prompt) {
2807
+ return prompt.select("How do you want to write your schema?", [{
2808
+ value: "psl",
2809
+ label: "Prisma Schema Language (.prisma)"
2810
+ }, {
2811
+ value: "typescript",
2812
+ label: "TypeScript (.ts)"
2813
+ }]);
2814
+ }
2815
+ /**
2816
+ * The schema path the user typed goes through the same validator the flag
2817
+ * does, so an answer the engine accepted still has to agree with the authoring
2818
+ * style.
2819
+ */
2820
+ async function askSchemaPath(prompt, authoring) {
2821
+ return validateSchemaPath(await prompt.text("Where should the schema file go?", { default: defaultSchemaPath(authoring) }), authoring);
2822
+ }
2823
+ /**
2824
+ * The facade a previous `init` installed for the other target, when this run
2825
+ * switches targets and one is still declared. Reads every name a previous run
2826
+ * could have written, because older versions scaffolded the workspace name.
2827
+ */
2828
+ function previousFacade(cwd, target) {
2829
+ const manifestPath = join(cwd, "package.json");
2830
+ if (!existsSync(manifestPath)) return;
2831
+ const otherTarget = target === "postgres" ? "mongo" : "postgres";
2832
+ const candidates = [targetPackageName(otherTarget, scaffoldSpecifierResolverFor(otherTarget)), targetPackageName(otherTarget)];
2833
+ let parsed;
2834
+ try {
2835
+ parsed = JSON.parse(readFileSync(manifestPath, "utf-8"));
2836
+ } catch {
2837
+ return;
2838
+ }
2839
+ const deps = parsed["dependencies"];
2840
+ if (deps === null || typeof deps !== "object" || Array.isArray(deps)) return;
2841
+ const declared = deps;
2842
+ return candidates.find((name) => Object.hasOwn(declared, name));
2843
+ }
2844
+ async function resolveRemovePreviousFacade(ctx) {
2845
+ if (!ctx.reinit || ctx.keepPreviousFacade) return null;
2846
+ const facade = previousFacade(ctx.cwd, ctx.target);
2847
+ if (facade === void 0) return null;
2848
+ const otherTarget = ctx.target === "postgres" ? "mongo" : "postgres";
2849
+ return await ctx.prompt.confirm(`Switching from ${targetLabel(otherTarget)} to ${targetLabel(ctx.target)} — remove ${facade} from package.json dependencies?`, { default: true }) ? facade : null;
2850
+ }
2851
+ /**
2852
+ * Resolves every input from the flags and, where a flag is absent, from the
2853
+ * engine's prompt surface.
2854
+ *
2855
+ * Order matters twice. Every flag value is validated before anything is asked,
2856
+ * so a typo costs a typo rather than a typed consent token. And consent comes
2857
+ * as soon as the schema path is known, because that is the point at which the
2858
+ * question can name the files it is about — and before any question whose
2859
+ * answer only matters if the run proceeds.
2860
+ */
2861
+ async function resolveInitInputs(ctx) {
2862
+ const { cwd, flags, prompt } = ctx;
2863
+ if (flags.strictProbe && !flags.probeDb) throw errorInitStrictProbeWithoutProbe();
2864
+ const flagTarget = resolveTarget(flags.target);
2865
+ const flagAuthoring = resolveAuthoring(flags.authoring);
2866
+ let target;
2867
+ let authoring;
2868
+ try {
2869
+ target = flagTarget ?? await askTarget(prompt);
2870
+ authoring = flagAuthoring ?? await askAuthoring(prompt);
2871
+ } catch (error) {
2872
+ if (!isPromptRequired(error)) throw error;
2873
+ throw errorInitMissingFlags({
2874
+ missing: [...flagTarget === void 0 ? ["target"] : [], ...flagAuthoring === void 0 ? ["authoring"] : []].filter((flag) => REQUIRED_FLAG_PROMPTS.has(flag)),
2875
+ why: "This session cannot prompt, so the answers have to arrive as flags."
2876
+ });
2877
+ }
2878
+ const schemaPath = flags.schemaPath !== void 0 ? validateSchemaPath(flags.schemaPath, authoring) : await askSchemaPath(prompt, authoring);
2879
+ const replaced = generatedFilesInitReplaces(schemaPath).filter((relative) => existsSync(join(cwd, relative)));
2880
+ const reinit = replaced.length > 0;
2881
+ if (reinit) {
2882
+ if (!await prompt.consent(consentQuestion(replaced), { token: consentToken(cwd) })) throw errorInitUserAborted();
2883
+ }
2884
+ const writeEnv = flags.writeEnv || await prompt.confirm("Also write a .env file from .env.example? (gitignored)", { default: false });
2885
+ const removePreviousFacade = await resolveRemovePreviousFacade({
2886
+ cwd,
2887
+ target,
2888
+ reinit,
2889
+ keepPreviousFacade: flags.keepPreviousFacade,
2890
+ prompt
2891
+ });
2892
+ return {
2893
+ target,
2894
+ authoring,
2895
+ schemaPath,
2896
+ install: !flags.skipInstall,
2897
+ writeEnv,
2898
+ probeDb: flags.probeDb,
2899
+ strictProbe: flags.strictProbe,
2900
+ reinit,
2901
+ removePreviousFacade,
2902
+ installProjectSkill: !flags.skipSkills
2903
+ };
2904
+ }
2905
+ function metaString(failure, key) {
2906
+ const value = failure.meta?.[key];
2907
+ return typeof value === "string" ? value : "";
2908
+ }
2909
+ /**
2910
+ * pnpm reported a specifier the published artifact leaked, which npm installs
2911
+ * happily. The engine redacts credentials out of the stderr it returns but
2912
+ * leaves error codes alone, which is what this reads.
2913
+ */
2914
+ function pnpmLeakedASpecifier(failure) {
2915
+ return metaString(failure, "manager") === "pnpm" && isRecognisedPnpmResolutionError(metaString(failure, "stderrTail"));
2916
+ }
2917
+ /**
2918
+ * The engine redacts the stderr it hands back, and this redacts it again
2919
+ * before quoting it: what the engine strips is its own business, and registry
2920
+ * auth material is not all URL-shaped.
2921
+ */
2922
+ function fallbackWarning(failure) {
2923
+ const firstLine = redactSecrets(metaString(failure, "stderrTail")).trim().split("\n")[0] ?? "";
2924
+ return [
2925
+ "pnpm could not install: a published Prisma Next dependency leaked a `workspace:*` or `catalog:` specifier.",
2926
+ "Falling back to npm so init can complete.",
2927
+ firstLine === "" ? "" : ` pnpm error: ${firstLine}`,
2928
+ "Both installs ran under npm, which writes a package-lock.json beside the pnpm lockfile — delete whichever of the two you do not want to keep.",
2929
+ "Once the offending package republishes a clean version, re-run `pnpm install` to switch back."
2930
+ ].filter((line) => line !== "").join("\n");
2931
+ }
2932
+ /** The pnpm failure the npm retry was meant to recover from, kept alongside the npm one. */
2933
+ function retriedWarning(failure) {
2934
+ const firstLine = redactSecrets(metaString(failure, "stderrTail")).trim().split("\n")[0] ?? "";
2935
+ return ["pnpm failed first with a leaked `workspace:*` or `catalog:` specifier, so init retried with npm.", firstLine === "" ? "" : ` pnpm error: ${firstLine}`].filter((line) => line !== "").join("\n");
2936
+ }
2937
+ /**
2938
+ * Adds the runtime and development dependencies through the engine's package
2939
+ * manager. The retry is `init`'s alone: the engine spells and runs the
2940
+ * command, and this decides — from the stderr it returned — that another
2941
+ * manager is worth a try.
2942
+ */
2943
+ async function installProjectDependencies(ctx) {
2944
+ const pair = async (manager) => {
2945
+ const runtimeDeps = await ctx.packages.install({
2946
+ packages: ctx.deps,
2947
+ cwd: ctx.cwd,
2948
+ ...ifDefined("manager", manager)
2949
+ });
2950
+ if (!runtimeDeps.ok) return runtimeDeps.failure;
2951
+ const developmentDeps = await ctx.packages.install({
2952
+ packages: ctx.devDeps,
2953
+ dev: true,
2954
+ cwd: ctx.cwd,
2955
+ ...ifDefined("manager", manager)
2956
+ });
2957
+ return developmentDeps.ok ? void 0 : developmentDeps.failure;
2958
+ };
2959
+ const failure = await pair();
2960
+ if (failure === void 0) return {
2961
+ failure: void 0,
2962
+ manager: void 0,
2963
+ warnings: ctx.catalogWarnings
2964
+ };
2965
+ if (!pnpmLeakedASpecifier(failure)) return {
2966
+ failure,
2967
+ manager: void 0,
2968
+ warnings: []
2969
+ };
2970
+ const retryFailure = await pair("npm");
2971
+ if (retryFailure !== void 0) return {
2972
+ failure: retryFailure,
2973
+ manager: void 0,
2974
+ warnings: [retriedWarning(failure)]
2975
+ };
2976
+ return {
2977
+ failure: void 0,
2978
+ manager: "npm",
2979
+ warnings: [fallbackWarning(failure)]
2980
+ };
2981
+ }
2982
+ function skillArgs(url, skill) {
2983
+ return [
2984
+ "add",
2985
+ url,
2986
+ "--agent",
2987
+ ...DEFAULT_SKILL_AGENTS,
2988
+ "--skill",
2989
+ skill,
2990
+ "-y"
2991
+ ];
2992
+ }
2993
+ /**
2994
+ * Registers every Prisma Next skill with the agent runtimes, in order. The
2995
+ * first failure stops the loop: the user opted into Prisma Next by running
2996
+ * `init`, and a half-installed skill set leaves the project ambiguous.
2997
+ */
2998
+ async function installAgentSkills(ctx) {
2999
+ for (const source of DEFAULT_SKILL_SOURCES) {
3000
+ const result = await ctx.packages.run({
3001
+ package: "skills@latest",
3002
+ args: skillArgs(formatSkillSourceUrl(source, ctx.env), source.skill),
3003
+ cwd: ctx.cwd,
3004
+ ...ifDefined("manager", ctx.manager)
3005
+ });
3006
+ if (!result.ok) return result.failure;
3007
+ }
3008
+ }
3009
+ /** The scaffold is on disk from here on, so each of these is a finding. */
3010
+ const INIT_EXIT_CODES = {
3011
+ 4: "scaffold written; dependency install failed",
3012
+ 5: "scaffold written and installed; contract emit failed",
3013
+ 6: "scaffold complete; agent-skill install failed"
3014
+ };
3015
+ function probeWarning(outcome, strictProbe) {
3016
+ switch (outcome.kind) {
3017
+ case "ok": return {
3018
+ warning: void 0,
3019
+ fatal: void 0
3020
+ };
3021
+ case "below-minimum": return {
3022
+ warning: outcome.message,
3023
+ fatal: void 0
3024
+ };
3025
+ case "no-database-url":
3026
+ case "connection-failed":
3027
+ case "driver-missing": return strictProbe ? {
3028
+ warning: void 0,
3029
+ fatal: outcome.message
3030
+ } : {
3031
+ warning: outcome.message,
3032
+ fatal: void 0
3033
+ };
3034
+ }
3035
+ }
3036
+ function causeMessage(error) {
3037
+ return error instanceof Error ? error.message : String(error);
3038
+ }
3039
+ const createInitCommand = (injected) => defineOrmCommand({
3040
+ help: {
3041
+ summary: "Initialize a new Prisma Next project",
3042
+ description: "Scaffolds config, schema, and runtime files, installs dependencies,\nand emits the contract. Gets you from zero to typed queries in one step.\n\nRun it interactively for a guided setup, or supply --target and --authoring\nfor a fully scriptable run (CI, AI coding agents, automation).",
3043
+ examples: [
3044
+ "init",
3045
+ "init --target postgres --authoring psl",
3046
+ "init --target mongodb --authoring typescript --json",
3047
+ "init --skip-install",
3048
+ "init --skip-skills",
3049
+ "init --target postgres --keep-previous-facade"
3050
+ ]
3051
+ },
3052
+ args: { flags: {
3053
+ target: flag.string({
3054
+ brief: "Database target: postgres or mongodb",
3055
+ placeholder: "db"
3056
+ }),
3057
+ authoring: flag.string({
3058
+ brief: "Schema authoring style: psl or typescript",
3059
+ placeholder: "style"
3060
+ }),
3061
+ schemaPath: flag.string({
3062
+ brief: "Where to write the starter schema",
3063
+ placeholder: "path"
3064
+ }),
3065
+ writeEnv: flag.boolean({ brief: "Write a .env file from .env.example (gitignored)" }),
3066
+ probeDb: flag.boolean({ brief: "Connect to DATABASE_URL once and check the server version" }),
3067
+ strictProbe: flag.boolean({ brief: "Treat a failed --probe-db as fatal" }),
3068
+ skipInstall: flag.boolean({ brief: "Skip dependency installation and contract emission" }),
3069
+ skipSkills: flag.boolean({ brief: "Skip the Prisma Next agent-skill install" }),
3070
+ keepPreviousFacade: flag.boolean({ brief: "Keep the previous target package in package.json when switching targets" })
3071
+ } },
3072
+ exitCodes: INIT_EXIT_CODES,
3073
+ installsPackages: true,
3074
+ handler: async (args, ctx) => {
3075
+ const warnings = [];
3076
+ const warn = (text) => {
3077
+ warnings.push(text);
3078
+ ctx.report({
3079
+ kind: "message",
3080
+ severity: "warn",
3081
+ text
3082
+ });
3083
+ };
3084
+ const inputs = await resolveInitInputs({
3085
+ cwd: ctx.cwd,
3086
+ flags: args.flags,
3087
+ prompt: ctx.prompt
3088
+ });
3089
+ const packageManager = await resolveScaffoldPackageManager({
3090
+ cwd: ctx.cwd,
3091
+ env: ctx.env
3092
+ });
3093
+ const scaffold = scaffoldProject({
3094
+ cwd: ctx.cwd,
3095
+ inputs,
3096
+ packageManager
3097
+ });
3098
+ for (const warning of scaffold.warnings) warn(warning);
3099
+ for (const note of scaffold.notes) ctx.report({
3100
+ kind: "message",
3101
+ severity: "info",
3102
+ text: note
3103
+ });
3104
+ const deps = [targetPackageName(inputs.target, scaffold.resolveImportSpecifier), "dotenv"];
3105
+ const devDeps = scaffold.hasTypesNode ? ["prisma-next"] : ["prisma-next", "@types/node"];
3106
+ const findings = [];
3107
+ const extraActions = [];
3108
+ let installedManager;
3109
+ let packagesInstalled = "skipped";
3110
+ let contractEmitted = false;
3111
+ let skillRegistered = false;
3112
+ const settle = (exitCode) => {
3113
+ const installed = packagesInstalled === "installed";
3114
+ const document = {
3115
+ ok: true,
3116
+ target: inputs.target === "mongo" ? "mongodb" : "postgres",
3117
+ authoring: inputs.authoring,
3118
+ schemaPath: inputs.schemaPath,
3119
+ filesWritten: scaffold.filesWritten,
3120
+ filesDeleted: scaffold.filesDeleted,
3121
+ packagesInstalled: {
3122
+ status: packagesInstalled,
3123
+ deps: installed ? deps : [],
3124
+ devDeps: installed ? devDeps : []
3125
+ },
3126
+ contractEmitted,
3127
+ nextSteps: buildNextSteps({
3128
+ target: inputs.target === "mongo" ? "mongodb" : "postgres",
3129
+ packagesInstalled,
3130
+ contractEmitted,
3131
+ emitCommand: EMIT_COMMAND,
3132
+ schemaPath: inputs.schemaPath,
3133
+ skillRegistered
3134
+ }),
3135
+ warnings
3136
+ };
3137
+ const validated = InitOutputSchema(document);
3138
+ if (validated instanceof type.errors) return notOk(new CliStructuredError$1("CLI.INIT_INVALID_OUTPUT_DOCUMENT", "Init produced an invalid output document", {
3139
+ why: `The success document failed schema validation: ${String(validated)}`,
3140
+ nextActions: [chooseAction("This is a bug in prisma-next. Please report it with `-v` output.")],
3141
+ docsUrl: docsUrlFor("CLI.INIT_INVALID_OUTPUT_DOCUMENT")
3142
+ }));
3143
+ return ok(ctx.present({
3144
+ data: document,
3145
+ exitCode,
3146
+ diagnostics: findings
3147
+ }, initPresentations({
3148
+ document,
3149
+ complete: exitCode === 0,
3150
+ nextActions: [...extraActions, ...buildInitNextActions({
3151
+ contractEmitted,
3152
+ schemaPath: inputs.schemaPath,
3153
+ skillRegistered
3154
+ })]
3155
+ })));
3156
+ };
3157
+ if (inputs.install) {
3158
+ const outcome = await installProjectDependencies({
3159
+ packages: ctx.packages,
3160
+ cwd: ctx.cwd,
3161
+ deps,
3162
+ devDeps,
3163
+ catalogWarnings: packageManager === "pnpm" ? buildCatalogWarnings(ctx.cwd, [...deps, ...devDeps]) : []
3164
+ });
3165
+ for (const warning of outcome.warnings) warn(warning);
3166
+ if (outcome.failure !== void 0) {
3167
+ packagesInstalled = "failed";
3168
+ findings.push(installFailedFinding(outcome.failure, scaffold.filesWritten));
3169
+ return settle(4);
3170
+ }
3171
+ packagesInstalled = "installed";
3172
+ installedManager = outcome.manager;
3173
+ const emitStep = "Emit the contract";
3174
+ ctx.report({
3175
+ kind: "step-started",
3176
+ step: emitStep
3177
+ });
3178
+ try {
3179
+ await injected.emitScaffoldedContract({ cwd: ctx.cwd });
3180
+ contractEmitted = true;
3181
+ ctx.report({
3182
+ kind: "step-finished",
3183
+ step: emitStep,
3184
+ outcome: "ok"
3185
+ });
3186
+ } catch (error) {
3187
+ ctx.report({
3188
+ kind: "step-finished",
3189
+ step: emitStep,
3190
+ outcome: "failed"
3191
+ });
3192
+ findings.push(emitFailedFinding(causeMessage(error), scaffold.filesWritten));
3193
+ return settle(5);
3194
+ }
3195
+ } else extraActions.push(chooseAction(`Install the project dependencies with your package manager: ${deps.join(", ")} (and ${devDeps.join(", ")} as development dependencies)`));
3196
+ if (inputs.probeDb) {
3197
+ const probe = probeWarning(await probeServerVersion({
3198
+ baseDir: ctx.cwd,
3199
+ target: inputs.target,
3200
+ databaseUrl: ctx.env["DATABASE_URL"],
3201
+ minVersion: MIN_SERVER_VERSION[inputs.target]
3202
+ }, {}), inputs.strictProbe);
3203
+ if (probe.warning !== void 0) warn(probe.warning);
3204
+ if (probe.fatal !== void 0) return notOk(normalizeError(errorInitProbeFailed({
3205
+ cause: probe.fatal,
3206
+ filesWritten: scaffold.filesWritten
3207
+ })));
3208
+ }
3209
+ const skillCommands = resolveProjectSkillInstallCommands(installedManager ?? packageManager, ctx.env);
3210
+ if (inputs.installProjectSkill) {
3211
+ const failure = await installAgentSkills({
3212
+ packages: ctx.packages,
3213
+ cwd: ctx.cwd,
3214
+ env: ctx.env,
3215
+ manager: installedManager
3216
+ });
3217
+ if (failure !== void 0) {
3218
+ findings.push(skillInstallFailedFinding(failure, scaffold.filesWritten, skillCommands));
3219
+ return settle(6);
3220
+ }
3221
+ skillRegistered = true;
3222
+ } else warn(`Skipped the Prisma Next agent-skill install (--skip-skills). To install them later, run: ${skillCommands.map((command) => `\`${command}\``).join(" && ")}`);
3223
+ return settle(0);
3224
+ }
3225
+ });
3226
+ const initCommand = createInitCommand({ emitScaffoldedContract });
3227
+ /**
3228
+ * R-S5-12 asks every command to end at 143 for SIGTERM and 130 otherwise, and
3229
+ * a server command is the one kind the engine leaves to do it: it settles the
3230
+ * handler's code verbatim, on the reasoning that a protocol conclusion was
3231
+ * never the CLI's to author. The two readings are in tension — this one wins
3232
+ * here, and the tension is recorded for the engine's owners, because it means
3233
+ * a SIGTERM landing after a clean `shutdown` reports 143 for a conversation
3234
+ * that ended correctly at 0.
3235
+ */
3236
+ function signalExitCode(reason) {
3237
+ return reason === "SIGTERM" ? 143 : 130;
3238
+ }
3239
+ const lspCommand = defineServerCommand({
3240
+ help: {
3241
+ summary: "Start the Prisma Next language server",
3242
+ description: "Launches a Language Server Protocol server that publishes PSL parse diagnostics\nand handles whole-document PSL formatting for the schema inputs declared in\nyour config (contract.source.inputs). Formatting uses the Prisma Next PSL\nformatter and the formatter block from the project config.\nCommunicates over stdio; intended to be spawned by an\neditor, not run interactively. The server keeps running until the editor client\ndisconnects.",
3243
+ examples: ["lsp"]
3244
+ },
3245
+ args: { flags: {
3246
+ stdio: flag.boolean({ brief: "Communicate with the editor over stdio (the default and only transport)" }),
3247
+ clientProcessId: flag.number({
3248
+ brief: "Process id of the editor that spawned the server; the server ends when it dies",
3249
+ placeholder: "pid"
3250
+ })
3251
+ } },
3252
+ handler: async (args, io) => {
3253
+ const exitCode = await withoutClientProcessIdInArgv(async () => {
3254
+ const { startServer } = await import("./exports-B3xY_FHp.mjs");
3255
+ return startServer({
3256
+ stdin: io.stdin,
3257
+ stdout: io.stdout,
3258
+ stderr: io.stderr,
3259
+ signal: io.signal,
3260
+ ...ifDefined("clientProcessId", args.flags.clientProcessId)
3261
+ });
3262
+ });
3263
+ return io.signal.aborted ? signalExitCode(io.signal.reason) : exitCode;
3264
+ }
3265
+ });
3266
+ /**
3267
+ * Importing `vscode-languageserver/node` reads `--clientProcessId` off
3268
+ * `process.argv` and arms a parent-watch interval that is never unref'd, so a
3269
+ * settled run would leave the process hanging. The server watches the client
3270
+ * process itself (from the parsed flag), so the argument is hidden for the
3271
+ * import and restored after.
3272
+ */
3273
+ async function withoutClientProcessIdInArgv(run) {
3274
+ const original = process.argv;
3275
+ const scrubbed = [];
3276
+ for (let index = 0; index < original.length; index += 1) {
3277
+ const token = original[index];
3278
+ if (token === "--clientProcessId") {
3279
+ index += 1;
3280
+ continue;
3281
+ }
3282
+ if (token === void 0 || token.startsWith("--clientProcessId=")) continue;
3283
+ scrubbed.push(token);
3284
+ }
3285
+ process.argv = scrubbed;
3286
+ try {
3287
+ return await run();
3288
+ } finally {
3289
+ process.argv = original;
3290
+ }
3291
+ }
3292
+ const STATUS_ACTION = runCommandAction("Check every space against the database", "prisma-next migration status");
3293
+ /**
3294
+ * The route the migration will take. The graph is a drawing — the engine cannot
3295
+ * derive a lane gutter — and the ordered list under it is drawn with the same
3296
+ * widths so every arrow lands in one column.
3297
+ */
3298
+ function showPresentations$1(inputs) {
3299
+ const { document, graph, runList } = inputs;
3300
+ const count = document.migrations.length;
3301
+ return {
3302
+ human: () => [
3303
+ {
3304
+ kind: "fields",
3305
+ rail: true,
3306
+ rows: [
3307
+ {
3308
+ label: "migrations",
3309
+ value: inputs.migrationsDir
3310
+ },
3311
+ ...inputs.database === void 0 ? [] : [{
3312
+ label: "database",
3313
+ value: inputs.database
3314
+ }],
3315
+ ...inputs.from === void 0 ? [] : [{
3316
+ label: "from",
3317
+ value: inputs.from
3318
+ }],
3319
+ ...inputs.to === void 0 ? [] : [{
3320
+ label: "to",
3321
+ value: inputs.to
3322
+ }]
3323
+ ]
3324
+ },
3325
+ ...graph.length === 0 ? [] : [{
3326
+ kind: "drawing",
3327
+ lines: toneDrawing(graph)
3328
+ }],
3329
+ ...count === 0 ? [{
3330
+ kind: "summary",
3331
+ status: "info",
3332
+ text: document.summary
1522
3333
  }] : [{
1523
3334
  kind: "summary",
1524
3335
  status: "info",
@@ -1799,6 +3610,146 @@ function createMigrateCommand(createClient) {
1799
3610
  }
1800
3611
  const migrateCommand = createMigrateCommand(createControlClient);
1801
3612
  /**
3613
+ * The check completed and the artifacts it read are not internally consistent.
3614
+ * The findings ride the envelope as diagnostics; the run itself did its job,
3615
+ * which is why this is not an errored settlement.
3616
+ */
3617
+ const FINDINGS_EXIT_CODE = 4;
3618
+ /**
3619
+ * One integrity failure as an envelope diagnostic. `error` is the honest
3620
+ * severity: nothing about the artifacts is merely worth a look, and exit 4
3621
+ * makes it legal — the engine refuses a severity-`error` diagnostic only on a
3622
+ * run that exits 0.
3623
+ *
3624
+ * The summary leads with the path because the engine's diagnostic renderer
3625
+ * prints `code`, `summary`, `why` and the next actions and never prints
3626
+ * `where`. Several failure texts name no package on their own — a hash
3627
+ * mismatch reads "Stored hash X does not match recomputed hash Y" — so
3628
+ * without the path a project with fifty migrations cannot be told which one
3629
+ * is broken. `where` still carries the path on its own for a `--json`
3630
+ * consumer.
3631
+ */
3632
+ function failureDiagnostic(failure) {
3633
+ if (!isStructuredErrorCode(failure.code)) throw new InternalError(`migration check produced the failure code "${failure.code}", which is not a dotted NAMESPACE.SUBCODE.`);
3634
+ return {
3635
+ code: failure.code,
3636
+ severity: "error",
3637
+ summary: `${failure.where}: ${failure.why}`,
3638
+ nextActions: failure.nextActions,
3639
+ where: { path: failure.where },
3640
+ meta: { space: failure.space }
3641
+ };
3642
+ }
3643
+ function checkPresentations(inputs) {
3644
+ const summary = inputs.resolvedSpaceId === void 0 ? inputs.document.summary : `${inputs.document.summary} (space: ${inputs.resolvedSpaceId})`;
3645
+ return {
3646
+ human: () => [{
3647
+ kind: "fields",
3648
+ rail: true,
3649
+ rows: [
3650
+ {
3651
+ label: "migrations",
3652
+ value: inputs.migrationsRelative
3653
+ },
3654
+ ...inputs.target === void 0 ? [] : [{
3655
+ label: "target",
3656
+ value: inputs.target
3657
+ }],
3658
+ ...inputs.space === void 0 ? [] : [{
3659
+ label: "space",
3660
+ value: inputs.space
3661
+ }]
3662
+ ]
3663
+ }, {
3664
+ kind: "summary",
3665
+ status: inputs.document.ok ? "ok" : "error",
3666
+ text: summary
3667
+ }],
3668
+ json: () => inputs.document
3669
+ };
3670
+ }
3671
+ const migrationCheckCommand = defineOrmCommand({
3672
+ help: {
3673
+ summary: "Verify artifact and graph integrity",
3674
+ description: "Validates that on-disk migration packages are internally consistent\n(hashes match, manifests are complete) and that the graph is well-formed\n(edges connect, refs point at valid nodes). The whole-graph check spans\nevery contract space by default; pass --space <id> to narrow to one. A\nmigration reference checks a single package, resolved across all contract\nspaces (narrow with --space; an ambiguous reference cannot be checked).\nOffline — does not consult the database.\nExit codes: 0 = all checks passed, 2 = precondition failed (unresolved\ntarget or unknown --space), 4 = integrity failure(s) found.",
3675
+ examples: [
3676
+ "migration check",
3677
+ "migration check --space app",
3678
+ "migration check 20260101-add-users",
3679
+ "migration check 20260101-add-users --space app",
3680
+ "migration check --json"
3681
+ ]
3682
+ },
3683
+ args: {
3684
+ positionals: { target: positional.optionalString({
3685
+ brief: "Migration reference: directory name, hash/prefix, ref, or path",
3686
+ placeholder: "target"
3687
+ }) },
3688
+ flags: { space: flag.string({
3689
+ brief: "Narrow output to a single contract space",
3690
+ placeholder: "id"
3691
+ }) }
3692
+ },
3693
+ needs: { config: ormConfigSection },
3694
+ exitCodes: { 4: "integrity check found failures" },
3695
+ handler: async (args, ctx) => {
3696
+ const { target } = args.positionals;
3697
+ const spaceFilter = args.flags.space;
3698
+ const migrationsDir = migrationsDirFor(ctx.config, ctx.cwd);
3699
+ const appMigrationsDir = appMigrationsDirFor(ctx.config, ctx.cwd);
3700
+ const appMigrationsRelative = displayPath(appMigrationsDir, ctx.cwd);
3701
+ const loaded = await buildReadAggregate(ctx.config, { migrationsDir });
3702
+ if (!loaded.ok) return notOk(normalizeError(loaded.failure));
3703
+ const spaces = await enumerateCheckSpaces(loaded.value.aggregate, migrationsDir, ctx.cwd);
3704
+ let document;
3705
+ let resolvedSpaceId;
3706
+ if (target !== void 0) {
3707
+ const outcome = await checkSingleTarget(target, {
3708
+ spaces,
3709
+ ...ifDefined("spaceFilter", spaceFilter),
3710
+ appMigrationsDir,
3711
+ appMigrationsRelative,
3712
+ cwd: ctx.cwd
3713
+ });
3714
+ if (outcome.error !== void 0) return notOk(normalizeError(outcome.error));
3715
+ const result = outcome.result;
3716
+ if (result === void 0 || outcome.exitCode === 2) return notOk(normalizeError(errorMigrationPackageNotFound(result?.summary ?? `Migration package for "${target}" not found on disk`)));
3717
+ document = result;
3718
+ resolvedSpaceId = outcome.resolvedSpaceId;
3719
+ } else {
3720
+ const checked = await runMigrationCheck({
3721
+ spaces,
3722
+ ...ifDefined("spaceFilter", spaceFilter)
3723
+ });
3724
+ if (!checked.ok) return notOk(normalizeError(checked.failure));
3725
+ const violations = await loadAggregateIntegrityViolations(ctx.config, migrationsDir);
3726
+ const scoped = spaceFilter === void 0 ? violations : violations.filter((violation) => violation.kind !== "disjointness" && violation.spaceId === spaceFilter);
3727
+ const failures = [...checked.value.failures, ...scoped.map((violation) => integrityViolationToCheckFailure(violation, migrationsDir))];
3728
+ document = failures.length === 0 ? {
3729
+ ok: true,
3730
+ failures: [],
3731
+ summary: "All checks passed"
3732
+ } : {
3733
+ ok: false,
3734
+ failures: [...failures],
3735
+ summary: `${failures.length} integrity failure(s)`
3736
+ };
3737
+ }
3738
+ const diagnostics = document.failures.map(failureDiagnostic);
3739
+ return ok(ctx.present({
3740
+ data: document,
3741
+ exitCode: diagnostics.length === 0 ? 0 : FINDINGS_EXIT_CODE,
3742
+ diagnostics
3743
+ }, checkPresentations({
3744
+ document,
3745
+ migrationsRelative: appMigrationsRelative,
3746
+ target,
3747
+ space: spaceFilter,
3748
+ resolvedSpaceId
3749
+ })));
3750
+ }
3751
+ });
3752
+ /**
1802
3753
  * The tree is a drawing for a reader; the DOT document is a graph description
1803
3754
  * for another program, so it is the one thing here that belongs on stdout.
1804
3755
  */
@@ -2020,85 +3971,392 @@ function ledgerGrid(entries, options) {
2020
3971
  })
2021
3972
  };
2022
3973
  }
2023
- function logPresentations(inputs) {
2024
- const grid = inputs.grid;
3974
+ function logPresentations(inputs) {
3975
+ const grid = inputs.grid;
3976
+ return {
3977
+ human: () => [...inputs.database === void 0 ? [] : [{
3978
+ kind: "fields",
3979
+ rail: true,
3980
+ rows: [{
3981
+ label: "database",
3982
+ value: inputs.database
3983
+ }]
3984
+ }], ...grid === void 0 ? [{
3985
+ kind: "summary",
3986
+ status: "info",
3987
+ text: MIGRATION_LOG_EMPTY_MESSAGE
3988
+ }] : [{
3989
+ kind: "table",
3990
+ columns: grid.headings,
3991
+ rows: grid.rows
3992
+ }]],
3993
+ json: () => inputs.document
3994
+ };
3995
+ }
3996
+ const migrationLogCommand = defineOrmCommand({
3997
+ help: {
3998
+ summary: "Show executed migration history",
3999
+ description: "Reads the database ledger and displays every applied migration edge in\nchronological order, including rollbacks and re-applies, merged across\nall contract spaces. Requires a database connection.",
4000
+ examples: [
4001
+ "migration log",
4002
+ "migration log --db $DATABASE_URL",
4003
+ "migration log --utc",
4004
+ "migration log --json"
4005
+ ]
4006
+ },
4007
+ args: { flags: {
4008
+ db: dbFlag,
4009
+ utc: flag.boolean({ brief: "Render human timestamps in UTC instead of local time" }),
4010
+ ascii: flag.boolean({ brief: "Use ASCII glyphs (pipe-friendly)" })
4011
+ } },
4012
+ needs: { config: ormConfigSection },
4013
+ handler: async (args, ctx) => {
4014
+ const dbConnection = args.flags.db ?? ctx.config.db?.connection;
4015
+ const missingDb = requireLiveDatabase({
4016
+ dbConnection,
4017
+ hasDriver: ctx.config.driver !== void 0,
4018
+ why: "migration log needs a database connection and driver to read the ledger (set db.connection in prisma-next.config.ts, or pass --db <url>)",
4019
+ commandName: "migration log"
4020
+ });
4021
+ if (missingDb !== null) return notOk(normalizeError(missingDb));
4022
+ if (!targetSupportsMigrations(ctx.config.target)) return notOk(normalizeError(errorTargetMigrationNotSupported({ why: "migration log reads the ledger a migration runner writes, and the configured target provides no runner." })));
4023
+ const client = createControlClient({
4024
+ family: ctx.config.family,
4025
+ target: ctx.config.target,
4026
+ adapter: ctx.config.adapter,
4027
+ ...ifDefined("driver", ctx.config.driver),
4028
+ extensions: ctx.config.extensions ?? []
4029
+ });
4030
+ let entries;
4031
+ try {
4032
+ await client.connect(dbConnection);
4033
+ entries = await client.readLedger();
4034
+ } catch (error) {
4035
+ return notOk(normalizeError(mapCaughtMigrationError(error) ?? errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read migration log: ${error instanceof Error ? error.message : String(error)}` })));
4036
+ } finally {
4037
+ await closeQuietly(client);
4038
+ }
4039
+ const records = serializeLedgerEntriesForJson(entries);
4040
+ const document = {
4041
+ ok: true,
4042
+ records,
4043
+ summary: `${records.length} migration(s) applied`
4044
+ };
4045
+ const glyphMode = args.flags.ascii ? "ascii" : "unicode";
4046
+ return ok(ctx.present({ data: document }, logPresentations({
4047
+ document,
4048
+ grid: entries.length === 0 ? void 0 : ledgerGrid(entries, {
4049
+ utc: args.flags.utc,
4050
+ glyphMode
4051
+ }),
4052
+ database: typeof dbConnection === "string" ? maskConnectionUrl(dbConnection) : void 0
4053
+ })));
4054
+ }
4055
+ });
4056
+ function newPresentations(inputs) {
4057
+ const { document } = inputs;
4058
+ const migrationTs = join(document.dir, "migration.ts");
4059
+ return {
4060
+ human: () => [
4061
+ {
4062
+ kind: "fields",
4063
+ rail: true,
4064
+ rows: [{
4065
+ label: "contract",
4066
+ value: inputs.contractPath
4067
+ }, {
4068
+ label: "migrations",
4069
+ value: inputs.appMigrationsRelative
4070
+ }]
4071
+ },
4072
+ {
4073
+ kind: "summary",
4074
+ status: "ok",
4075
+ text: document.summary
4076
+ },
4077
+ {
4078
+ kind: "fields",
4079
+ rows: [{
4080
+ label: "from",
4081
+ value: document.from === null ? [{
4082
+ text: "(baseline)",
4083
+ tone: "muted"
4084
+ }] : [{
4085
+ text: document.from,
4086
+ tone: "identifier"
4087
+ }]
4088
+ }, {
4089
+ label: "to",
4090
+ value: [{
4091
+ text: document.to,
4092
+ tone: "identifier"
4093
+ }]
4094
+ }]
4095
+ }
4096
+ ],
4097
+ json: () => document,
4098
+ next: () => [{
4099
+ kind: "edit-file",
4100
+ label: `Write the migration body in ${migrationTs}`
4101
+ }, runCommandAction("Run it to self-emit ops.json and attest the package", `node "${migrationTs}"`)]
4102
+ };
4103
+ }
4104
+ const migrationNewCommand = defineOrmCommand({
4105
+ help: {
4106
+ summary: "Scaffold a new migration for manual authoring",
4107
+ description: "Creates a migration package with a migration.ts file for manual authoring.\nWrite the migration body in migration.ts, then run the file with Node\n(`node migration.ts`) to self-emit ops.json and attest the package.\nOffline — does not consult the database.",
4108
+ examples: [
4109
+ "migration new --name split-name",
4110
+ "migration new --name custom-fk --from abc123",
4111
+ "migration new --json"
4112
+ ]
4113
+ },
4114
+ args: { flags: {
4115
+ name: flag.string({
4116
+ brief: "Migration name (used in directory name)",
4117
+ placeholder: "slug"
4118
+ }),
4119
+ from: flag.string({
4120
+ brief: "Starting contract hash (default: latest migration target)",
4121
+ placeholder: "hash"
4122
+ })
4123
+ } },
4124
+ needs: { config: ormConfigSection },
4125
+ handler: async (args, ctx) => {
4126
+ const scaffolded = await executeMigrationNewCommand({
4127
+ config: ctx.config,
4128
+ cwd: ctx.cwd,
4129
+ configPath: projectConfigPathFor(ctx.cwd),
4130
+ ...ifDefined("name", args.flags.name),
4131
+ ...ifDefined("from", args.flags.from)
4132
+ });
4133
+ if (!scaffolded.ok) return notOk(normalizeError(scaffolded.failure));
4134
+ const contractPath = contractPathFor(ctx.config, ctx.cwd);
4135
+ return ok(ctx.present({ data: scaffolded.value }, newPresentations({
4136
+ document: scaffolded.value,
4137
+ contractPath: contractPath === void 0 ? "(unset)" : displayPath(contractPath, ctx.cwd),
4138
+ appMigrationsRelative: displayPath(appMigrationsDirFor(ctx.config, ctx.cwd), ctx.cwd)
4139
+ })));
4140
+ }
4141
+ });
4142
+ function hashRow(label, hash) {
4143
+ return {
4144
+ label,
4145
+ value: hash === null ? [{
4146
+ text: "(baseline)",
4147
+ tone: "muted"
4148
+ }] : [{
4149
+ text: hash,
4150
+ tone: "identifier"
4151
+ }]
4152
+ };
4153
+ }
4154
+ /**
4155
+ * Where the run put things: the contract edge it planned, then every directory
4156
+ * it wrote — the app-space package, the auto-baseline package that precedes it,
4157
+ * and any extension-space package the seed phase materialised.
4158
+ */
4159
+ function outcomeFields(result, migrationsRelative) {
4160
+ return {
4161
+ kind: "fields",
4162
+ rows: [
4163
+ hashRow("from", result.from),
4164
+ hashRow("to", result.to),
4165
+ ...result.baselineDir === void 0 ? [] : [{
4166
+ label: "baseline",
4167
+ value: result.baselineDir
4168
+ }],
4169
+ ...result.dir === void 0 ? [] : [{
4170
+ label: "app space",
4171
+ value: result.dir
4172
+ }],
4173
+ ...result.emittedExtensionDirs.map((entry) => ({
4174
+ label: `space ${entry.spaceId}`,
4175
+ value: join(migrationsRelative, entry.spaceId, entry.dirName)
4176
+ }))
4177
+ ]
4178
+ };
4179
+ }
4180
+ function operationNodes$1(result) {
4181
+ return result.operations.map((operation) => operation.operationClass === "destructive" ? {
4182
+ label: operation.label,
4183
+ status: "warn"
4184
+ } : { label: operation.label });
4185
+ }
4186
+ function operationBlocks$1(result) {
4187
+ if (result.operations.length === 0) return [];
4188
+ const destructive = result.operations.some((operation) => operation.operationClass === "destructive");
4189
+ return [{
4190
+ kind: "tree",
4191
+ roots: [{
4192
+ label: result.dir ?? "operations",
4193
+ children: operationNodes$1(result)
4194
+ }]
4195
+ }, ...destructive ? [{
4196
+ kind: "summary",
4197
+ status: "warn",
4198
+ text: "This migration contains destructive operations that may cause data loss."
4199
+ }] : []];
4200
+ }
4201
+ /** Statements a database would run, printed verbatim rather than laid out. */
4202
+ function previewBlocks$1(result) {
4203
+ const preview = result.preview;
4204
+ if (preview === void 0) return [];
4205
+ const statements = preview.statements.map((statement) => statement.text.trim()).filter((text) => text.length > 0).map((text) => text.endsWith(";") ? text : `${text};`);
4206
+ if (statements.length === 0) return [];
4207
+ return [{
4208
+ kind: "summary",
4209
+ status: "info",
4210
+ tone: "muted",
4211
+ text: previewBlockHeader(preview)
4212
+ }, {
4213
+ kind: "drawing",
4214
+ lines: statements
4215
+ }];
4216
+ }
4217
+ function planBlocks(result, migrationsRelative) {
4218
+ const outcome = outcomeFields(result, migrationsRelative);
4219
+ if (result.noOp) return [{
4220
+ kind: "summary",
4221
+ status: "ok",
4222
+ text: "No changes detected"
4223
+ }, outcome];
4224
+ if (result.pendingPlaceholders === true) return [{
4225
+ kind: "summary",
4226
+ status: "warn",
4227
+ text: result.summary
4228
+ }, outcome];
4229
+ return [
4230
+ {
4231
+ kind: "summary",
4232
+ status: "ok",
4233
+ text: result.summary
4234
+ },
4235
+ ...operationBlocks$1(result),
4236
+ outcome,
4237
+ ...previewBlocks$1(result)
4238
+ ];
4239
+ }
4240
+ function planNextActions(result, migrationsRelative) {
4241
+ if (result.pendingPlaceholders === true) {
4242
+ const migrationTs = join(result.dir ?? "<dir>", "migration.ts");
4243
+ return [{
4244
+ kind: "edit-file",
4245
+ label: `Replace each placeholder(...) call in ${migrationTs} with your query`
4246
+ }, runCommandAction("Run it to self-emit ops.json and attest the package", `node "${migrationTs}"`)];
4247
+ }
4248
+ const written = [
4249
+ ...result.baselineDir === void 0 ? [] : [result.baselineDir],
4250
+ ...result.dir === void 0 ? [] : [result.dir],
4251
+ ...result.emittedExtensionDirs.map((entry) => join(migrationsRelative, entry.spaceId, entry.dirName))
4252
+ ];
4253
+ if (written.length === 0) return [];
4254
+ return [{
4255
+ kind: "edit-file",
4256
+ label: `Review ${written.join(" and ")}`
4257
+ }, runCommandAction("Apply the migration", "prisma-next migrate")];
4258
+ }
4259
+ function planPresentations(inputs) {
2025
4260
  return {
2026
- human: () => [...inputs.database === void 0 ? [] : [{
4261
+ human: () => [{
2027
4262
  kind: "fields",
2028
4263
  rail: true,
2029
- rows: [{
2030
- label: "database",
2031
- value: inputs.database
2032
- }]
2033
- }], ...grid === void 0 ? [{
2034
- kind: "summary",
2035
- status: "info",
2036
- text: MIGRATION_LOG_EMPTY_MESSAGE
2037
- }] : [{
2038
- kind: "table",
2039
- columns: grid.headings,
2040
- rows: grid.rows
2041
- }]],
2042
- json: () => inputs.document
4264
+ rows: [
4265
+ {
4266
+ label: "contract",
4267
+ value: inputs.contractPath
4268
+ },
4269
+ {
4270
+ label: "migrations",
4271
+ value: inputs.appMigrationsRelative
4272
+ },
4273
+ ...inputs.from === void 0 ? [] : [{
4274
+ label: "from",
4275
+ value: inputs.from
4276
+ }],
4277
+ ...inputs.to === void 0 ? [] : [{
4278
+ label: "to",
4279
+ value: inputs.to
4280
+ }],
4281
+ ...inputs.name === void 0 ? [] : [{
4282
+ label: "name",
4283
+ value: inputs.name
4284
+ }]
4285
+ ]
4286
+ }, ...planBlocks(inputs.document, inputs.migrationsRelative)],
4287
+ json: () => inputs.document,
4288
+ next: () => planNextActions(inputs.document, inputs.migrationsRelative)
2043
4289
  };
2044
4290
  }
2045
- const migrationLogCommand = defineOrmCommand({
4291
+ const migrationPlanCommand = defineOrmCommand({
2046
4292
  help: {
2047
- summary: "Show executed migration history",
2048
- description: "Reads the database ledger and displays every applied migration edge in\nchronological order, including rollbacks and re-applies, merged across\nall contract spaces. Requires a database connection.",
4293
+ summary: "Plan a migration from contract changes",
4294
+ description: "Compares the emitted contract against the latest on-disk migration state\nand produces a new migration package with the required operations.\nOffline does not consult the database.",
2049
4295
  examples: [
2050
- "migration log",
2051
- "migration log --db $DATABASE_URL",
2052
- "migration log --utc",
2053
- "migration log --json"
4296
+ "migration plan",
4297
+ "migration plan --name add-users-table",
4298
+ "migration plan --to <migration-dir>^ --name rollback",
4299
+ "migration plan --json"
2054
4300
  ]
2055
4301
  },
2056
4302
  args: { flags: {
2057
- db: dbFlag,
2058
- utc: flag.boolean({ brief: "Render human timestamps in UTC instead of local time" }),
2059
- ascii: flag.boolean({ brief: "Use ASCII glyphs (pipe-friendly)" })
4303
+ name: flag.string({
4304
+ brief: "Name slug for the migration directory",
4305
+ placeholder: "slug"
4306
+ }),
4307
+ from: flag.string({
4308
+ brief: "Starting contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)",
4309
+ placeholder: "contract"
4310
+ }),
4311
+ to: flag.string({
4312
+ brief: "Destination contract reference; defaults to the emitted contract. Same grammar as --from",
4313
+ placeholder: "contract"
4314
+ })
2060
4315
  } },
2061
4316
  needs: { config: ormConfigSection },
2062
4317
  handler: async (args, ctx) => {
2063
- const dbConnection = args.flags.db ?? ctx.config.db?.connection;
2064
- const missingDb = requireLiveDatabase({
2065
- dbConnection,
2066
- hasDriver: ctx.config.driver !== void 0,
2067
- why: "migration log needs a database connection and driver to read the ledger (set db.connection in prisma-next.config.ts, or pass --db <url>)",
2068
- commandName: "migration log"
2069
- });
2070
- if (missingDb !== null) return notOk(normalizeError(missingDb));
2071
- if (!targetSupportsMigrations(ctx.config.target)) return notOk(normalizeError(errorTargetMigrationNotSupported({ why: "migration log reads the ledger a migration runner writes, and the configured target provides no runner." })));
2072
- const client = createControlClient({
2073
- family: ctx.config.family,
2074
- target: ctx.config.target,
2075
- adapter: ctx.config.adapter,
2076
- ...ifDefined("driver", ctx.config.driver),
2077
- extensions: ctx.config.extensions ?? []
2078
- });
2079
- let entries;
2080
- try {
2081
- await client.connect(dbConnection);
2082
- entries = await client.readLedger();
2083
- } catch (error) {
2084
- return notOk(normalizeError(mapCaughtMigrationError(error) ?? errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read migration log: ${error instanceof Error ? error.message : String(error)}` })));
2085
- } finally {
2086
- await closeQuietly(client);
2087
- }
2088
- const records = serializeLedgerEntriesForJson(entries);
2089
- const document = {
2090
- ok: true,
2091
- records,
2092
- summary: `${records.length} migration(s) applied`
4318
+ const seeded = (record) => {
4319
+ if (record.action !== "updated") return;
4320
+ const step = `Seed contract space ${record.spaceId}`;
4321
+ ctx.report({
4322
+ kind: "step-started",
4323
+ step,
4324
+ id: record.spaceId
4325
+ });
4326
+ ctx.report({
4327
+ kind: "step-finished",
4328
+ step,
4329
+ id: record.spaceId,
4330
+ outcome: "ok",
4331
+ data: {
4332
+ newHash: record.newHash,
4333
+ newMigrationDirs: record.newMigrationDirs
4334
+ }
4335
+ });
2093
4336
  };
2094
- const glyphMode = args.flags.ascii ? "ascii" : "unicode";
2095
- return ok(ctx.present({ data: document }, logPresentations({
2096
- document,
2097
- grid: entries.length === 0 ? void 0 : ledgerGrid(entries, {
2098
- utc: args.flags.utc,
2099
- glyphMode
2100
- }),
2101
- database: typeof dbConnection === "string" ? maskConnectionUrl(dbConnection) : void 0
4337
+ const planned = await executeMigrationPlanCommand({
4338
+ config: ctx.config,
4339
+ cwd: ctx.cwd,
4340
+ configPath: projectConfigPathFor(ctx.cwd),
4341
+ ...ifDefined("name", args.flags.name),
4342
+ ...ifDefined("from", args.flags.from),
4343
+ ...ifDefined("to", args.flags.to)
4344
+ }, Date.now(), { onSeeded: seeded });
4345
+ if (!planned.ok) return notOk(normalizeError(planned.failure));
4346
+ ctx.report({
4347
+ kind: "message",
4348
+ severity: "verbose",
4349
+ text: `Total time: ${planned.value.timings.total}ms`
4350
+ });
4351
+ const contractPath = contractPathFor(ctx.config, ctx.cwd);
4352
+ return ok(ctx.present({ data: planned.value }, planPresentations({
4353
+ document: planned.value,
4354
+ contractPath: contractPath === void 0 ? "(unset)" : displayPath(contractPath, ctx.cwd),
4355
+ appMigrationsRelative: displayPath(appMigrationsDirFor(ctx.config, ctx.cwd), ctx.cwd),
4356
+ migrationsRelative: displayPath(migrationsDirFor(ctx.config, ctx.cwd), ctx.cwd),
4357
+ from: args.flags.from,
4358
+ to: args.flags.to,
4359
+ name: args.flags.name
2102
4360
  })));
2103
4361
  }
2104
4362
  });
@@ -2336,6 +4594,426 @@ const migrationShowCommand = defineOrmCommand({
2336
4594
  })));
2337
4595
  }
2338
4596
  });
4597
+ const EMIT_CONTRACT = runCommandAction("Regenerate the contract", "prisma-next contract emit");
4598
+ function contractUnreadableFinding(reason) {
4599
+ const message = `Could not read contract: ${reason}`;
4600
+ return {
4601
+ document: {
4602
+ code: "CONTRACT.UNREADABLE",
4603
+ severity: "warn",
4604
+ message,
4605
+ hints: ["Run 'prisma-next contract emit' to generate a valid contract"]
4606
+ },
4607
+ diagnostic: {
4608
+ code: "CONTRACT.UNREADABLE",
4609
+ severity: "warn",
4610
+ summary: message,
4611
+ why: "The status tree falls back to the on-disk migration graph when the emitted contract cannot be read.",
4612
+ nextActions: [EMIT_CONTRACT]
4613
+ }
4614
+ };
4615
+ }
4616
+ function markerNotInHistoryFinding(space) {
4617
+ const message = `Database was updated outside the migration system (marker for space "${space}" does not match any migration)`;
4618
+ return {
4619
+ document: {
4620
+ code: "MIGRATION.MARKER_NOT_IN_HISTORY",
4621
+ severity: "warn",
4622
+ message,
4623
+ hints: ["Run 'prisma-next db sign' to overwrite the marker if the database already matches the contract", "Run 'prisma-next db update' to push the current contract to the database"]
4624
+ },
4625
+ diagnostic: {
4626
+ code: "MIGRATION.MARKER_NOT_IN_HISTORY",
4627
+ severity: "warn",
4628
+ summary: message,
4629
+ why: "The marker the database carries names no contract in the on-disk migration graph.",
4630
+ meta: { space },
4631
+ nextActions: [runCommandAction("Overwrite the marker if the database already matches the contract", "prisma-next db sign"), runCommandAction("Or push the current contract to the database", "prisma-next db update")]
4632
+ }
4633
+ };
4634
+ }
4635
+ function missingInvariantsFinding(inputs) {
4636
+ const message = `missing invariant(s): ${inputs.missing.join(", ")}`;
4637
+ return {
4638
+ document: {
4639
+ code: "MIGRATION.MISSING_INVARIANTS",
4640
+ severity: "warn",
4641
+ ...ifDefined("ref", inputs.refName),
4642
+ invariants: [...inputs.missing],
4643
+ message
4644
+ },
4645
+ diagnostic: {
4646
+ code: "MIGRATION.MISSING_INVARIANTS",
4647
+ severity: "warn",
4648
+ summary: message,
4649
+ why: inputs.refName === void 0 ? "The database marker does not carry every invariant the target requires." : `The database marker does not carry every invariant \`${inputs.refName}\` requires.`,
4650
+ nextActions: [runCommandAction("Apply the migrations that provide them", "prisma-next migrate")],
4651
+ meta: {
4652
+ invariants: [...inputs.missing],
4653
+ ...ifDefined("ref", inputs.refName)
4654
+ }
4655
+ }
4656
+ };
4657
+ }
4658
+ const SHORT_HASH_LENGTH = 12;
4659
+ function shortDisplayHash(hash) {
4660
+ return hash.slice(0, SHORT_HASH_LENGTH);
4661
+ }
4662
+ const NO_DATABASE_STATE = {
4663
+ markersBySpace: /* @__PURE__ */ new Map(),
4664
+ ledgersBySpace: /* @__PURE__ */ new Map()
4665
+ };
4666
+ async function readDatabaseState(inputs) {
4667
+ const { client } = inputs;
4668
+ try {
4669
+ await client.connect(inputs.connection);
4670
+ const markersBySpace = new Map(await client.readAllMarkers());
4671
+ const ledgersBySpace = /* @__PURE__ */ new Map();
4672
+ for (const spaceId of inputs.spaceIds) ledgersBySpace.set(spaceId, await client.readLedger(spaceId));
4673
+ return ok({
4674
+ markersBySpace,
4675
+ ledgersBySpace
4676
+ });
4677
+ } catch (error) {
4678
+ return notOk(normalizeError(CliStructuredError$1.is(error) ? error : errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read database state: ${error instanceof Error ? error.message : String(error)}` })));
4679
+ } finally {
4680
+ await closeQuietly(client);
4681
+ }
4682
+ }
4683
+ function buildNoPathSummary(args) {
4684
+ const markerPart = args.markerHash !== void 0 ? `the database state (${shortDisplayHash(args.markerHash)})` : "the database state";
4685
+ const targetShort = shortDisplayHash(args.targetHash);
4686
+ if (!args.explicitTarget) return `No migration path from ${markerPart} to the application's contract (${targetShort}). Run \`prisma-next migration plan --name <name>\` to author one.`;
4687
+ return `No migration path from ${markerPart} to ${args.refName !== void 0 ? `the target (${targetShort} via \`${args.refName}\`)` : `the target (${targetShort})`}. Run \`prisma-next migration plan --name <name>\` to author one, or pass \`--to <contract>\` to pick a reachable target.`;
4688
+ }
4689
+ function buildStatusHeadline(args) {
4690
+ if (args.markerDiverged && args.markerHash !== void 0) return `Database marker ${shortDisplayHash(args.markerHash)} is not in the on-disk migration graph`;
4691
+ if (args.pendingCount === 0) return "Up to date";
4692
+ return `${args.pendingCount} pending — run \`prisma-next migrate --to ${shortDisplayHash(args.targetHash)}\``;
4693
+ }
4694
+ /**
4695
+ * One space's section: its heading, where more than one space is in scope, on
4696
+ * top of its tree. Heading and tree are one drawing so the heading stays a
4697
+ * bare label — a `summary` would put a status glyph in front of it.
4698
+ */
4699
+ function sectionBlock(section) {
4700
+ const heading = section.showHeading ? [[{
4701
+ text: `${section.space}:`,
4702
+ tone: "heading"
4703
+ }]] : [];
4704
+ const body = section.tree.length === 0 ? [[{
4705
+ text: "(no migrations)",
4706
+ tone: "muted"
4707
+ }]] : toneDrawing(section.tree);
4708
+ return {
4709
+ kind: "drawing",
4710
+ lines: [...heading, ...body]
4711
+ };
4712
+ }
4713
+ function statusPresentations(inputs) {
4714
+ const legend = inputs.legend;
4715
+ return {
4716
+ human: () => [
4717
+ {
4718
+ kind: "fields",
4719
+ rail: true,
4720
+ rows: [
4721
+ {
4722
+ label: "migrations",
4723
+ value: inputs.migrationsDir
4724
+ },
4725
+ ...inputs.database === void 0 ? [] : [{
4726
+ label: "database",
4727
+ value: inputs.database
4728
+ }],
4729
+ ...inputs.ref === void 0 ? [] : [{
4730
+ label: "ref",
4731
+ value: inputs.ref
4732
+ }],
4733
+ ...inputs.from === void 0 ? [] : [{
4734
+ label: "from",
4735
+ value: inputs.from
4736
+ }],
4737
+ ...inputs.space === void 0 ? [] : [{
4738
+ label: "space",
4739
+ value: inputs.space
4740
+ }]
4741
+ ]
4742
+ },
4743
+ ...legend === void 0 ? [] : [{
4744
+ kind: "drawing",
4745
+ lines: toneDrawing(legend)
4746
+ }],
4747
+ ...inputs.sections.map(sectionBlock),
4748
+ inputs.headline
4749
+ ],
4750
+ json: () => inputs.document
4751
+ };
4752
+ }
4753
+ const migrationStatusCommand = defineOrmCommand({
4754
+ help: {
4755
+ summary: "Show migration path and pending status",
4756
+ description: "Shows which migrations are pending between the database marker and the\ntarget contract. Requires a database connection. Pass --from for an\noffline path preview without a database. Use `migration graph` for\ntopology, `migration log` for history, and `migration list` for on-disk\nenumeration.",
4757
+ examples: [
4758
+ "migration status",
4759
+ "migration status --db $DATABASE_URL",
4760
+ "migration status --to production",
4761
+ "migration status --from abc123 --to production",
4762
+ "migration status --ascii",
4763
+ "migration status --legend"
4764
+ ]
4765
+ },
4766
+ args: { flags: {
4767
+ db: dbFlag,
4768
+ space: flag.string({
4769
+ brief: "Narrow output to a single contract space",
4770
+ placeholder: "id"
4771
+ }),
4772
+ to: flag.string({
4773
+ brief: "Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)",
4774
+ placeholder: "contract"
4775
+ }),
4776
+ from: flag.string({
4777
+ brief: "Origin contract reference; same grammar as --to. Supplying it switches to offline path computation",
4778
+ placeholder: "contract"
4779
+ }),
4780
+ legend: flag.boolean({ brief: "Print a key for the tree glyphs and lane colors" }),
4781
+ ascii: flag.boolean({ brief: "Use ASCII glyphs (pipe-friendly)" })
4782
+ } },
4783
+ needs: { config: ormConfigSection },
4784
+ handler: async (args, ctx) => {
4785
+ const migrationsDir = migrationsDirFor(ctx.config, ctx.cwd);
4786
+ const dbConnection = args.flags.db ?? ctx.config.db?.connection;
4787
+ const hasDriver = ctx.config.driver !== void 0;
4788
+ const usingFromOverride = args.flags.from !== void 0;
4789
+ if (!usingFromOverride) {
4790
+ const missingDb = requireLiveDatabase({
4791
+ dbConnection,
4792
+ hasDriver,
4793
+ why: "migration status needs a database connection to read the marker and ledger (or pass --from for an offline path preview)",
4794
+ retryCommand: "prisma-next migration status --from <contract>"
4795
+ });
4796
+ if (missingDb !== null) return notOk(normalizeError(missingDb));
4797
+ }
4798
+ const refsResult = await readMigrationRefs(appRefsDirFor(ctx.config, ctx.cwd));
4799
+ if (!refsResult.ok) return notOk(normalizeError(refsResult.failure));
4800
+ const refs = refsResult.value;
4801
+ const findings = [];
4802
+ const loaded = await buildReadAggregate(ctx.config, { migrationsDir });
4803
+ if (!loaded.ok) return notOk(normalizeError(loaded.failure));
4804
+ const { aggregate, contractHash } = loaded.value;
4805
+ const contractConfig = { contract: ifDefined("output", contractPathFor(ctx.config, ctx.cwd)) };
4806
+ try {
4807
+ await readContractEnvelope(contractConfig);
4808
+ } catch (error) {
4809
+ findings.push(contractUnreadableFinding(error instanceof Error ? error.message : "unknown error"));
4810
+ }
4811
+ if (await loadContractRawSafely(contractConfig) !== null) {
4812
+ const corruption = refusePackageCorruptionOnAggregate(aggregate);
4813
+ if (corruption) return notOk(normalizeError(corruption));
4814
+ }
4815
+ const appGraph = aggregate.app.graph();
4816
+ let activeRefHash;
4817
+ let activeRefName;
4818
+ let activeRefEntry;
4819
+ if (args.flags.to !== void 0) {
4820
+ const resolved = resolveContractRef(args.flags.to, {
4821
+ graph: appGraph,
4822
+ refs
4823
+ });
4824
+ if (!resolved.ok) return notOk(normalizeError(resolved.failure));
4825
+ activeRefHash = resolved.value.hash;
4826
+ if (resolved.value.provenance.kind === "ref") {
4827
+ activeRefName = resolved.value.provenance.refName;
4828
+ activeRefEntry = refs[activeRefName];
4829
+ }
4830
+ }
4831
+ let fromOverrideHash;
4832
+ if (args.flags.from !== void 0) {
4833
+ const resolved = resolveContractRef(args.flags.from, {
4834
+ graph: appGraph,
4835
+ refs
4836
+ });
4837
+ if (!resolved.ok) return notOk(normalizeError(resolved.failure));
4838
+ fromOverrideHash = resolved.value.hash;
4839
+ }
4840
+ const listed = runMigrationList({
4841
+ spaces: await migrationSpaceListEntriesFromAggregate(aggregate, migrationsDir),
4842
+ ...ifDefined("spaceFilter", args.flags.space)
4843
+ });
4844
+ if (!listed.ok) return notOk(normalizeError(listed.failure));
4845
+ const scopedSpaces = listed.value.spaces;
4846
+ const connects = dbConnection !== void 0 && hasDriver && !usingFromOverride;
4847
+ let database = NO_DATABASE_STATE;
4848
+ if (connects) {
4849
+ const read = await readDatabaseState({
4850
+ client: createControlClient({
4851
+ family: ctx.config.family,
4852
+ target: ctx.config.target,
4853
+ adapter: ctx.config.adapter,
4854
+ ...ifDefined("driver", ctx.config.driver),
4855
+ extensions: ctx.config.extensions ?? []
4856
+ }),
4857
+ connection: dbConnection,
4858
+ spaceIds: scopedSpaces.map((entry) => entry.space)
4859
+ });
4860
+ if (!read.ok) return notOk(read.failure);
4861
+ database = read.value;
4862
+ }
4863
+ const appMarker = database.markersBySpace.get(aggregate.app.spaceId);
4864
+ if (activeRefEntry !== void 0 && activeRefEntry.invariants.length > 0 && connects) {
4865
+ const unknown = refuseUnknownInvariants({
4866
+ graph: appGraph,
4867
+ markerInvariants: appMarker?.invariants ?? [],
4868
+ refInvariants: activeRefEntry.invariants,
4869
+ ...ifDefined("refName", activeRefName)
4870
+ });
4871
+ if (unknown) return notOk(normalizeError(unknown));
4872
+ }
4873
+ const glyphMode = args.flags.ascii ? "ascii" : "unicode";
4874
+ const styler = createToneMigrationListStyler();
4875
+ const showSpaceHeadings = scopedSpaces.length > 1;
4876
+ const statusSpaces = [];
4877
+ const renderInputs = [];
4878
+ const emptySpaces = [];
4879
+ let divergedMarker;
4880
+ let noPath;
4881
+ let headlineTargetHash = activeRefHash ?? contractHash;
4882
+ let totalPending = 0;
4883
+ for (const entry of scopedSpaces) {
4884
+ const space = aggregate.space(entry.space);
4885
+ if (space === void 0) continue;
4886
+ const graph = space.graph();
4887
+ const spaceContractHash = space.contract().storage.storageHash;
4888
+ const targetHash = activeRefHash ?? spaceContractHash;
4889
+ if (entry.space === aggregate.app.spaceId) headlineTargetHash = targetHash;
4890
+ const markerHash = usingFromOverride ? fromOverrideHash : database.markersBySpace.get(entry.space)?.storageHash;
4891
+ const originHash = originHashForStatus(markerHash);
4892
+ const markerInGraph = markerHash === void 0 || graph.nodes.has(markerHash) || markerHash === spaceContractHash;
4893
+ if (connects && markerInGraph && originHash !== targetHash && noPath === void 0 && !hasMigrationPath(graph, originHash, targetHash)) noPath = {
4894
+ markerHash,
4895
+ targetHash
4896
+ };
4897
+ if (connects && markerHash !== void 0 && !markerInGraph) {
4898
+ divergedMarker ??= {
4899
+ space: entry.space,
4900
+ markerHash
4901
+ };
4902
+ findings.push(markerNotInHistoryFinding(entry.space));
4903
+ }
4904
+ const ledger = database.ledgersBySpace.get(entry.space) ?? [];
4905
+ const annotations = deriveStatusEdgeAnnotations({
4906
+ graph,
4907
+ targetHash,
4908
+ originHash,
4909
+ appliedMigrationHashes: connects ? appliedHashesFromLedger(ledger) : /* @__PURE__ */ new Set(),
4910
+ showAppliedOverlay: connects
4911
+ });
4912
+ const migrations = entry.migrations.map((migration) => ({
4913
+ ...migration,
4914
+ status: statusForMigrationHash(migration.hash, annotations)
4915
+ }));
4916
+ totalPending += migrations.filter((migration) => migration.status === "pending").length;
4917
+ statusSpaces.push({
4918
+ space: entry.space,
4919
+ currentContract: markerHash ?? null,
4920
+ targetContract: targetHash,
4921
+ migrations
4922
+ });
4923
+ if (graph.nodes.size === 0) {
4924
+ emptySpaces.push(entry.space);
4925
+ continue;
4926
+ }
4927
+ renderInputs.push({
4928
+ spaceId: entry.space,
4929
+ graph,
4930
+ migrations: entry.migrations,
4931
+ liveContractHash: contractHash,
4932
+ refsByHash: listRefsByContractHash(space),
4933
+ statusOverlayByHash: annotations,
4934
+ colorize: true,
4935
+ glyphMode,
4936
+ styler,
4937
+ palette: TONE_MIGRATION_GRAPH_PALETTE,
4938
+ isAppSpace: entry.space === aggregate.app.spaceId,
4939
+ ...connects && markerHash !== void 0 ? { dbHash: markerHash } : {}
4940
+ });
4941
+ }
4942
+ const requiredInvariants = [...activeRefEntry?.invariants ?? []].sort();
4943
+ if (connects && requiredInvariants.length > 0) {
4944
+ const held = new Set(appMarker?.invariants ?? []);
4945
+ const missing = requiredInvariants.filter((id) => !held.has(id));
4946
+ if (missing.length > 0) {
4947
+ findings.push(missingInvariantsFinding({
4948
+ missing,
4949
+ refName: activeRefName
4950
+ }));
4951
+ if (activeRefHash !== void 0) {
4952
+ const unreachable = refuseMissingInvariantPath({
4953
+ graph: appGraph,
4954
+ originHash: originHashForStatus(appMarker?.storageHash),
4955
+ targetHash: activeRefHash,
4956
+ missing,
4957
+ ...ifDefined("refName", activeRefName)
4958
+ });
4959
+ if (unreachable) return notOk(normalizeError(unreachable));
4960
+ }
4961
+ }
4962
+ }
4963
+ const rendered = renderMigrationGraphSpaceTrees(renderInputs);
4964
+ const treesBySpace = new Map(renderInputs.map((input, index) => [input.spaceId, rendered[index] ?? ""]));
4965
+ const sections = scopedSpaces.map((entry) => {
4966
+ const tree = treesBySpace.get(entry.space) ?? "";
4967
+ return {
4968
+ space: entry.space,
4969
+ tree: showSpaceHeadings && tree.length > 0 ? indentMigrationGraphTreeBlock(tree, " ") : tree,
4970
+ showHeading: showSpaceHeadings
4971
+ };
4972
+ });
4973
+ const summary = scopedSpaces.every((entry) => entry.migrations.length === 0) ? "No migrations found" : noPath !== void 0 ? buildNoPathSummary({
4974
+ markerHash: noPath.markerHash,
4975
+ targetHash: noPath.targetHash,
4976
+ explicitTarget: args.flags.to !== void 0,
4977
+ refName: activeRefName
4978
+ }) : buildStatusHeadline({
4979
+ pendingCount: totalPending,
4980
+ targetHash: headlineTargetHash,
4981
+ markerDiverged: divergedMarker !== void 0,
4982
+ markerHash: divergedMarker?.markerHash
4983
+ });
4984
+ const diagnostics = findings.map((finding) => finding.diagnostic);
4985
+ const document = {
4986
+ ok: true,
4987
+ spaces: statusSpaces,
4988
+ summary,
4989
+ diagnostics: findings.map((finding) => finding.document)
4990
+ };
4991
+ const alarming = divergedMarker !== void 0 || totalPending > 0 || noPath !== void 0;
4992
+ return ok(ctx.present({
4993
+ data: document,
4994
+ diagnostics
4995
+ }, statusPresentations({
4996
+ document,
4997
+ sections,
4998
+ headline: {
4999
+ kind: "summary",
5000
+ status: alarming ? "warn" : "ok",
5001
+ text: summary
5002
+ },
5003
+ migrationsDir: displayPath(migrationsDir, ctx.cwd),
5004
+ database: connects && typeof dbConnection === "string" ? maskConnectionUrl(dbConnection) : void 0,
5005
+ ref: activeRefName,
5006
+ from: args.flags.from,
5007
+ space: args.flags.space,
5008
+ legend: args.flags.legend ? renderMigrationGraphLegend({
5009
+ colorize: true,
5010
+ glyphMode,
5011
+ styler,
5012
+ palette: TONE_MIGRATION_GRAPH_PALETTE
5013
+ }) : void 0
5014
+ })));
5015
+ }
5016
+ });
2339
5017
  function deletePresentations(document) {
2340
5018
  return {
2341
5019
  human: () => [{
@@ -2507,27 +5185,62 @@ const ormCommandFamily = defineCommandFamily({
2507
5185
  "contract infer": contractInferCommand,
2508
5186
  "db init": dbInitCommand,
2509
5187
  "db schema": dbSchemaCommand,
5188
+ "db sign": dbSignCommand,
2510
5189
  "db update": dbUpdateCommand,
5190
+ "db verify": dbVerifyCommand,
2511
5191
  format: formatCommand,
5192
+ init: initCommand,
5193
+ lsp: lspCommand,
2512
5194
  migrate: migrateCommand,
5195
+ "migration check": migrationCheckCommand,
2513
5196
  "migration graph": migrationGraphCommand,
2514
5197
  "migration list": migrationListCommand,
2515
5198
  "migration log": migrationLogCommand,
5199
+ "migration new": migrationNewCommand,
5200
+ "migration plan": migrationPlanCommand,
2516
5201
  "migration show": migrationShowCommand,
5202
+ "migration status": migrationStatusCommand,
2517
5203
  "ref delete": refDeleteCommand,
2518
5204
  "ref list": refListCommand,
2519
5205
  "ref set": refSetCommand
2520
5206
  },
2521
5207
  docsBaseUrl: DOCS_BASE_URL,
2522
- redirects: [{
2523
- from: "migration apply",
2524
- replacement: "{bin} migrate --to <contract>",
2525
- reason: "Applying a migration is a move to a target contract, not a verb of its own."
2526
- }, {
2527
- from: "migration ref",
2528
- replacement: "{bin} ref set|list|delete",
2529
- reason: "Refs are managed by their own command, for every space rather than migrations alone."
2530
- }]
5208
+ redirects: [
5209
+ {
5210
+ from: "migration apply",
5211
+ replacement: "{bin} migrate --to <contract>",
5212
+ reason: "Applying a migration is a move to a target contract, not a verb of its own."
5213
+ },
5214
+ {
5215
+ from: "migration ref",
5216
+ replacement: "{bin} ref set|list|delete",
5217
+ reason: "Refs are managed by their own command, for every space rather than migrations alone."
5218
+ },
5219
+ {
5220
+ from: "migration status",
5221
+ flag: "graph",
5222
+ replacement: "{bin} migration graph",
5223
+ reason: "Topology is its own command rather than a mode of the status report."
5224
+ },
5225
+ {
5226
+ from: "migration status",
5227
+ flag: "all",
5228
+ replacement: "{bin} migration log --db <url>",
5229
+ reason: "Execution history is read from the database ledger, which is what migration log does."
5230
+ },
5231
+ {
5232
+ from: "migration status",
5233
+ flag: "limit",
5234
+ replacement: "{bin} migration log --db <url>",
5235
+ reason: "Execution history is read from the database ledger, which is what migration log does."
5236
+ },
5237
+ {
5238
+ from: "migration status",
5239
+ flag: "ref",
5240
+ replacement: "{bin} migration status --to <contract>",
5241
+ reason: "One flag names the target contract, whether it is a ref, a hash or a migration."
5242
+ }
5243
+ ]
2531
5244
  });
2532
5245
  /** The file the ORM's loader reads when `--config` names none. */
2533
5246
  const ORM_CONFIG_FILENAME = "prisma-next.config.ts";