@prisma/orm-toolchain 8.0.0-rc.1-dev.28 → 8.0.0-rc.1-dev.30

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 (160) hide show
  1. package/dist/{aggregate-BKbHUHLA.mjs → aggregate-BBsCbXgJ.mjs} +8 -8
  2. package/dist/{aggregate-BKbHUHLA.mjs.map → aggregate-BBsCbXgJ.mjs.map} +1 -1
  3. package/dist/bin__prisma-next.mjs +25 -25
  4. package/dist/bin__prisma-next.mjs.map +1 -1
  5. package/dist/cli.d.mts +2 -2
  6. package/dist/cli.mjs +257 -93
  7. package/dist/cli.mjs.map +1 -1
  8. package/dist/cli__commands__contract-emit.mjs +1 -1
  9. package/dist/cli__commands__contract-infer.mjs +1 -1
  10. package/dist/cli__commands__db-init.mjs +1 -1
  11. package/dist/cli__commands__db-schema.mjs +1 -1
  12. package/dist/cli__commands__db-sign.mjs +1 -1
  13. package/dist/cli__commands__db-update.mjs +1 -1
  14. package/dist/cli__commands__db-verify.mjs +1 -1
  15. package/dist/cli__commands__migrate.mjs +1 -1
  16. package/dist/cli__commands__migration-check.mjs +1 -1
  17. package/dist/cli__commands__migration-graph.d.mts.map +1 -1
  18. package/dist/cli__commands__migration-graph.mjs +1 -1
  19. package/dist/cli__commands__migration-list.mjs +1 -1
  20. package/dist/cli__commands__migration-log.mjs +1 -1
  21. package/dist/cli__commands__migration-new.mjs +1 -1
  22. package/dist/cli__commands__migration-plan.mjs +1 -1
  23. package/dist/cli__commands__migration-show.mjs +1 -1
  24. package/dist/cli__commands__migration-status.mjs +1 -1
  25. package/dist/cli__commands__ref.mjs +1 -1
  26. package/dist/cli__commands__telemetry.mjs +1 -1
  27. package/dist/cli__control-api.d.mts +14 -13
  28. package/dist/cli__control-api.d.mts.map +1 -1
  29. package/dist/cli__control-api.mjs +15 -15
  30. package/dist/cli__migration-cli.mjs +2 -2
  31. package/dist/{client-CaIWFVnh-PVaTEvdx.mjs → client-C4Gh4PBz-BMUlBcuE.mjs} +6 -6
  32. package/dist/{client-CaIWFVnh-PVaTEvdx.mjs.map → client-C4Gh4PBz-BMUlBcuE.mjs.map} +1 -1
  33. package/dist/{command-helpers-DutQjYgy-CDfFwtAa.mjs → command-helpers-Dw3LDEu_-B4AETH4D.mjs} +4 -4
  34. package/dist/{command-helpers-DutQjYgy-CDfFwtAa.mjs.map → command-helpers-Dw3LDEu_-B4AETH4D.mjs.map} +1 -1
  35. package/dist/{contract-at-errors-BsQiGdZC-BY8u2is4.mjs → contract-at-errors-BsQiGdZC-D8l9-WWt.mjs} +2 -2
  36. package/dist/{contract-at-errors-BsQiGdZC-BY8u2is4.mjs.map → contract-at-errors-BsQiGdZC-D8l9-WWt.mjs.map} +1 -1
  37. package/dist/{contract-emit-BJDLPMxp-qaGmQUQr.mjs → contract-emit-CIdgw3Kq-BcfYaUfn.mjs} +4 -4
  38. package/dist/{contract-emit-BJDLPMxp-qaGmQUQr.mjs.map → contract-emit-CIdgw3Kq-BcfYaUfn.mjs.map} +1 -1
  39. package/dist/{contract-infer-B929dnCJ-KkT9frLY.mjs → contract-infer-xOEwVWds-CE5gw1PF.mjs} +5 -5
  40. package/dist/{contract-infer-B929dnCJ-KkT9frLY.mjs.map → contract-infer-xOEwVWds-CE5gw1PF.mjs.map} +1 -1
  41. package/dist/{contract-snapshot-resolution-D2f9kGs0-BenF4tbi.mjs → contract-snapshot-resolution-BnH6_mw7-BrzAsS93.mjs} +6 -6
  42. package/dist/{contract-snapshot-resolution-D2f9kGs0-BenF4tbi.mjs.map → contract-snapshot-resolution-BnH6_mw7-BrzAsS93.mjs.map} +1 -1
  43. package/dist/{contract-snapshot-store-C9-J6OBn-kpuB2oCK.mjs → contract-snapshot-store-B0G1Fw_F-C4JjmWEA.mjs} +3 -3
  44. package/dist/{contract-snapshot-store-C9-J6OBn-kpuB2oCK.mjs.map → contract-snapshot-store-B0G1Fw_F-C4JjmWEA.mjs.map} +1 -1
  45. package/dist/{contract-space-aggregate-loader-sF0OJ6oz-jRjdZoyZ.mjs → contract-space-aggregate-loader-1wG1OiDk-D75luh5-.mjs} +5 -5
  46. package/dist/{contract-space-aggregate-loader-sF0OJ6oz-jRjdZoyZ.mjs.map → contract-space-aggregate-loader-1wG1OiDk-D75luh5-.mjs.map} +1 -1
  47. package/dist/{db-init-CU_x-p2M-_6oEFLiG.mjs → db-init-CEk9Utl4-vGmJajwZ.mjs} +6 -6
  48. package/dist/{db-init-CU_x-p2M-_6oEFLiG.mjs.map → db-init-CEk9Utl4-vGmJajwZ.mjs.map} +1 -1
  49. package/dist/{db-schema-BKAn8UrM-DP4k7BAB.mjs → db-schema-D_PJvBI3-BTnfCqbX.mjs} +6 -6
  50. package/dist/{db-schema-BKAn8UrM-DP4k7BAB.mjs.map → db-schema-D_PJvBI3-BTnfCqbX.mjs.map} +1 -1
  51. package/dist/{db-sign-BQF-jVXg-D467Bhpj.mjs → db-sign-Bparnnii-Yd5pb4VF.mjs} +7 -7
  52. package/dist/{db-sign-BQF-jVXg-D467Bhpj.mjs.map → db-sign-Bparnnii-Yd5pb4VF.mjs.map} +1 -1
  53. package/dist/{db-update-B0_Q4ykE-CT9vcaMu.mjs → db-update-CsKZyDYp-B8Zl7W4k.mjs} +7 -7
  54. package/dist/{db-update-B0_Q4ykE-CT9vcaMu.mjs.map → db-update-CsKZyDYp-B8Zl7W4k.mjs.map} +1 -1
  55. package/dist/{db-verify-C0DJc8z6-f3gZeEMD.mjs → db-verify-B33E7HXH-D87fiNt3.mjs} +6 -6
  56. package/dist/{db-verify-C0DJc8z6-f3gZeEMD.mjs.map → db-verify-B33E7HXH-D87fiNt3.mjs.map} +1 -1
  57. package/dist/{errors-Co-8oaiB-CB-6Uqki.mjs → errors-CXbGUWGu-BQi6YS-H.mjs} +51 -2
  58. package/dist/errors-CXbGUWGu-BQi6YS-H.mjs.map +1 -0
  59. package/dist/{errors-NRmFpwR1.d.mts → errors-KWM8yBAL.d.mts} +3 -1
  60. package/dist/errors-KWM8yBAL.d.mts.map +1 -0
  61. package/dist/{format-SYdHyutg-IqXk-tDV.mjs → format-CYdgHub4-Cs6VcFje.mjs} +4 -4
  62. package/dist/{format-SYdHyutg-IqXk-tDV.mjs.map → format-CYdgHub4-Cs6VcFje.mjs.map} +1 -1
  63. package/dist/{graph-membership-BEmNEMtP-rz61CLM5.mjs → graph-membership-BViWUMpP-Cgu4Z2ox.mjs} +3 -3
  64. package/dist/{graph-membership-BEmNEMtP-rz61CLM5.mjs.map → graph-membership-BViWUMpP-Cgu4Z2ox.mjs.map} +1 -1
  65. package/dist/{init-DXx66xTA-BkK1aEw0.mjs → init-CrypFQwk-XiyERkdi.mjs} +3 -3
  66. package/dist/{init-DXx66xTA-BkK1aEw0.mjs.map → init-CrypFQwk-XiyERkdi.mjs.map} +1 -1
  67. package/dist/{inspect-live-schema-D8d7aI6a-_Q_4S5wm.mjs → inspect-live-schema-BAiaX0n9-DBQFEsMC.mjs} +4 -4
  68. package/dist/{inspect-live-schema-D8d7aI6a-_Q_4S5wm.mjs.map → inspect-live-schema-BAiaX0n9-DBQFEsMC.mjs.map} +1 -1
  69. package/dist/{invariants-C1WVUAH7-DlOBTTkM.mjs → invariants-CTHy88OP-DJ-i5yTz.mjs} +3 -3
  70. package/dist/{invariants-C1WVUAH7-DlOBTTkM.mjs.map → invariants-CTHy88OP-DJ-i5yTz.mjs.map} +1 -1
  71. package/dist/{invariants-TW5CizTS-BsIpi4h4.mjs → invariants-CsxL0lbZ-B9Hfpj2R.mjs} +6 -6
  72. package/dist/{invariants-TW5CizTS-BsIpi4h4.mjs.map → invariants-CsxL0lbZ-B9Hfpj2R.mjs.map} +1 -1
  73. package/dist/{io-CHUUeHh0-CbyTkKP6.mjs → io-635GlNx1-D94PxRc-.mjs} +5 -5
  74. package/dist/{io-CHUUeHh0-CbyTkKP6.mjs.map → io-635GlNx1-D94PxRc-.mjs.map} +1 -1
  75. package/dist/{migrate-vNMZJk7M-DKogRyOh.mjs → migrate-DYx_CSbN-BuQ0lk-0.mjs} +13 -13
  76. package/dist/{migrate-vNMZJk7M-DKogRyOh.mjs.map → migrate-DYx_CSbN-BuQ0lk-0.mjs.map} +1 -1
  77. package/dist/{migrate-show-C-fdCznr-BH88FGVn.mjs → migrate-show-CPZEq35I-DeL3WVjs.mjs} +9 -9
  78. package/dist/{migrate-show-C-fdCznr-BH88FGVn.mjs.map → migrate-show-CPZEq35I-DeL3WVjs.mjs.map} +1 -1
  79. package/dist/{migration-check-C-2GTAGq-Duc0P6Uo.mjs → migration-check-BUAcSrvA-DSS5Yvco.mjs} +9 -9
  80. package/dist/{migration-check-C-2GTAGq-Duc0P6Uo.mjs.map → migration-check-BUAcSrvA-DSS5Yvco.mjs.map} +1 -1
  81. package/dist/{migration-check-DATj3HSn-Del6ZSln.mjs → migration-check-D0ABv6pO-BCJRf3lE.mjs} +6 -6
  82. package/dist/{migration-check-DATj3HSn-Del6ZSln.mjs.map → migration-check-D0ABv6pO-BCJRf3lE.mjs.map} +1 -1
  83. package/dist/{migration-command-scaffold-BezR8GWB-BZFB2PC-.mjs → migration-command-scaffold-CIMPoR6f-Ba-S9gXa.mjs} +4 -4
  84. package/dist/{migration-command-scaffold-BezR8GWB-BZFB2PC-.mjs.map → migration-command-scaffold-CIMPoR6f-Ba-S9gXa.mjs.map} +1 -1
  85. package/dist/{migration-graph-B1mg_jel-HVG6FLD0.mjs → migration-graph-BsGstA5L-BQiNbrkP.mjs} +9 -9
  86. package/dist/{migration-graph-B1mg_jel-HVG6FLD0.mjs.map → migration-graph-BsGstA5L-BQiNbrkP.mjs.map} +1 -1
  87. package/dist/{migration-graph-BtP1Va3T-CMOZgqVW.mjs → migration-graph-BtP1Va3T-C8PpuaYw.mjs} +2 -2
  88. package/dist/{migration-graph-BtP1Va3T-CMOZgqVW.mjs.map → migration-graph-BtP1Va3T-C8PpuaYw.mjs.map} +1 -1
  89. package/dist/{migration-graph-DDaOHo10-yJFAbKCu.mjs → migration-graph-_SJImD5V-D5RCc651.mjs} +3 -3
  90. package/dist/{migration-graph-DDaOHo10-yJFAbKCu.mjs.map → migration-graph-_SJImD5V-D5RCc651.mjs.map} +1 -1
  91. package/dist/{migration-graph-command-render-BKrg6BPv-BP8Pfj4J.mjs → migration-graph-command-render-CgdHruiZ-B6V4gmUe.mjs} +321 -153
  92. package/dist/migration-graph-command-render-CgdHruiZ-B6V4gmUe.mjs.map +1 -0
  93. package/dist/{migration-graph-sections-BVqyqBHg-DAwWjIIf.mjs → migration-graph-sections-CceYWPCP-LqImOaK1.mjs} +6 -4
  94. package/dist/migration-graph-sections-CceYWPCP-LqImOaK1.mjs.map +1 -0
  95. package/dist/{migration-_C5W2uXF.mjs → migration-gubSSeMk.mjs} +3 -3
  96. package/dist/{migration-_C5W2uXF.mjs.map → migration-gubSSeMk.mjs.map} +1 -1
  97. package/dist/{migration-list-AKRIIovW-Cr39jOaI.mjs → migration-list-AKRIIovW-BN-Zrwk0.mjs} +3 -3
  98. package/dist/{migration-list-AKRIIovW-Cr39jOaI.mjs.map → migration-list-AKRIIovW-BN-Zrwk0.mjs.map} +1 -1
  99. package/dist/{migration-list-RSlyGyvD-KKmZtdY1.mjs → migration-list-BiVyonwG-CdMbBV5Z.mjs} +7 -7
  100. package/dist/{migration-list-RSlyGyvD-KKmZtdY1.mjs.map → migration-list-BiVyonwG-CdMbBV5Z.mjs.map} +1 -1
  101. package/dist/{migration-log-CBfOcyPC-DTqCL1cs.mjs → migration-log-Z3-L172x-CvQTNJvI.mjs} +7 -7
  102. package/dist/{migration-log-CBfOcyPC-DTqCL1cs.mjs.map → migration-log-Z3-L172x-CvQTNJvI.mjs.map} +1 -1
  103. package/dist/{migration-log-table-C0dSMG9T-BhBYrdka.mjs → migration-log-table-JR7fFVbE-DR2mom6h.mjs} +4 -4
  104. package/dist/{migration-log-table-C0dSMG9T-BhBYrdka.mjs.map → migration-log-table-JR7fFVbE-DR2mom6h.mjs.map} +1 -1
  105. package/dist/{migration-new-1LYliIXy-BK_Xz0Z6.mjs → migration-new-DDnQd7Ql-1WT_J_zf.mjs} +5 -5
  106. package/dist/{migration-new-1LYliIXy-BK_Xz0Z6.mjs.map → migration-new-DDnQd7Ql-1WT_J_zf.mjs.map} +1 -1
  107. package/dist/{migration-new-DcPO4tiw-Bew7S-bj.mjs → migration-new-ZlgxFcbH-CxlZs2hr.mjs} +8 -8
  108. package/dist/{migration-new-DcPO4tiw-Bew7S-bj.mjs.map → migration-new-ZlgxFcbH-CxlZs2hr.mjs.map} +1 -1
  109. package/dist/{migration-plan-B0z2Qpa5-6b1SJSsb.mjs → migration-plan-CROSunPS-B66Rh_6T.mjs} +5 -5
  110. package/dist/{migration-plan-B0z2Qpa5-6b1SJSsb.mjs.map → migration-plan-CROSunPS-B66Rh_6T.mjs.map} +1 -1
  111. package/dist/{migration-plan-Cb7s5Ifx-Bwa2O0Ov.mjs → migration-plan-DiLJTAep-2B463CwW.mjs} +14 -14
  112. package/dist/{migration-plan-Cb7s5Ifx-Bwa2O0Ov.mjs.map → migration-plan-DiLJTAep-2B463CwW.mjs.map} +1 -1
  113. package/dist/{migration-show-BRy1GVBE-NuwoczhZ.mjs → migration-show-mJD52S2d-DiD-rCBB.mjs} +7 -7
  114. package/dist/{migration-show-BRy1GVBE-NuwoczhZ.mjs.map → migration-show-mJD52S2d-DiD-rCBB.mjs.map} +1 -1
  115. package/dist/{migration-status-Dob4onB1-0YkQF25g.mjs → migration-status-Df6EwEun-CbrQHa3S.mjs} +11 -11
  116. package/dist/{migration-status-Dob4onB1-0YkQF25g.mjs.map → migration-status-Df6EwEun-CbrQHa3S.mjs.map} +1 -1
  117. package/dist/migration-tools.d.mts +1 -1
  118. package/dist/migration-tools.mjs +12 -12
  119. package/dist/migration-tools__aggregate.mjs +1 -1
  120. package/dist/migration-tools__contract-snapshot-store.mjs +1 -1
  121. package/dist/migration-tools__errors.d.mts +1 -1
  122. package/dist/migration-tools__errors.mjs +1 -1
  123. package/dist/migration-tools__invariants.mjs +1 -1
  124. package/dist/migration-tools__io.mjs +1 -1
  125. package/dist/migration-tools__migration-graph.mjs +2 -2
  126. package/dist/migration-tools__migration.mjs +1 -1
  127. package/dist/migration-tools__ref-resolution.mjs +1 -1
  128. package/dist/migration-tools__refs.mjs +1 -1
  129. package/dist/migration-tools__spaces.mjs +2 -2
  130. package/dist/{ref-B643Z0CS-CoJgdv7h.mjs → ref-Cycefq_T-DQE5AM66.mjs} +5 -5
  131. package/dist/{ref-B643Z0CS-CoJgdv7h.mjs.map → ref-Cycefq_T-DQE5AM66.mjs.map} +1 -1
  132. package/dist/{ref-D9J4TNYz-Dk7HCAoq.mjs → ref-DftuSibc-CasZ6LgA.mjs} +10 -10
  133. package/dist/{ref-D9J4TNYz-Dk7HCAoq.mjs.map → ref-DftuSibc-CasZ6LgA.mjs.map} +1 -1
  134. package/dist/{ref-advancement-DaZBzm7m-Deq5Cs7O.mjs → ref-advancement-DaZBzm7m-WoqnFAyr.mjs} +4 -4
  135. package/dist/{ref-advancement-DaZBzm7m-Deq5Cs7O.mjs.map → ref-advancement-DaZBzm7m-WoqnFAyr.mjs.map} +1 -1
  136. package/dist/{ref-resolution-Bi4lpxM8-BX-7sl0f.mjs → ref-resolution-Bi4lpxM8-BbfL_yv8.mjs} +2 -2
  137. package/dist/{ref-resolution-Bi4lpxM8-BX-7sl0f.mjs.map → ref-resolution-Bi4lpxM8-BbfL_yv8.mjs.map} +1 -1
  138. package/dist/{ref-resolution-Ct2GMcNB.mjs → ref-resolution-sGcINe7o.mjs} +2 -2
  139. package/dist/{ref-resolution-Ct2GMcNB.mjs.map → ref-resolution-sGcINe7o.mjs.map} +1 -1
  140. package/dist/{refs-B2BL8z3i-DGGFB7Mj.mjs → refs-WK86uYYp-B6EZkmmT.mjs} +19 -3
  141. package/dist/refs-WK86uYYp-B6EZkmmT.mjs.map +1 -0
  142. package/dist/{refs-fQLFcMoq-UTlvnijY.mjs → refs-fQLFcMoq-aTBeUU9H.mjs} +4 -4
  143. package/dist/{refs-fQLFcMoq-UTlvnijY.mjs.map → refs-fQLFcMoq-aTBeUU9H.mjs.map} +1 -1
  144. package/dist/{spaces-DBTCE3Js.mjs → spaces-BG2w0P8d.mjs} +6 -6
  145. package/dist/{spaces-DBTCE3Js.mjs.map → spaces-BG2w0P8d.mjs.map} +1 -1
  146. package/dist/{telemetry-DFEbk6sD-BYEW2bCJ.mjs → telemetry-LP1Suxsf-CY1l7lD0.mjs} +4 -4
  147. package/dist/{telemetry-DFEbk6sD-BYEW2bCJ.mjs.map → telemetry-LP1Suxsf-CY1l7lD0.mjs.map} +1 -1
  148. package/dist/{terminal-ui-DQNCDg2u-B3PFqjB8.mjs → terminal-ui-JJKxvT0q-CPDEJqqU.mjs} +35 -11
  149. package/dist/terminal-ui-JJKxvT0q-CPDEJqqU.mjs.map +1 -0
  150. package/dist/{verify-contract-spaces-WvjSiWcB-DZPPCwWO.mjs → verify-contract-spaces-DhJTb0zM-_oh6W6lp.mjs} +4 -4
  151. package/dist/{verify-contract-spaces-WvjSiWcB-DZPPCwWO.mjs.map → verify-contract-spaces-DhJTb0zM-_oh6W6lp.mjs.map} +1 -1
  152. package/dist/{verify-TphNCyMu-h8vrnbud.mjs → verify-wUSBDQwh-Bv3NV9WG.mjs} +3 -3
  153. package/dist/{verify-TphNCyMu-h8vrnbud.mjs.map → verify-wUSBDQwh-Bv3NV9WG.mjs.map} +1 -1
  154. package/package.json +13 -13
  155. package/dist/errors-Co-8oaiB-CB-6Uqki.mjs.map +0 -1
  156. package/dist/errors-NRmFpwR1.d.mts.map +0 -1
  157. package/dist/migration-graph-command-render-BKrg6BPv-BP8Pfj4J.mjs.map +0 -1
  158. package/dist/migration-graph-sections-BVqyqBHg-DAwWjIIf.mjs.map +0 -1
  159. package/dist/refs-B2BL8z3i-DGGFB7Mj.mjs.map +0 -1
  160. package/dist/terminal-ui-DQNCDg2u-B3PFqjB8.mjs.map +0 -1
@@ -3,125 +3,152 @@ import { ifDefined } from "@prisma/orm-framework/utils/defined";
3
3
  import { InternalError } from "@prisma/orm-framework/utils/internal-error";
4
4
  import { bold, createColors, cyan, cyanBright, dim, green, yellow } from "colorette";
5
5
  import stringWidth from "string-width";
6
- //#region ../../../1-framework/3-tooling/cli/dist/migration-graph-command-render-BKrg6BPv.mjs
6
+ //#region ../../../1-framework/3-tooling/cli/dist/migration-graph-command-render-CgdHruiZ.mjs
7
7
  /**
8
- * Occlusion renderer for the line/plane/occlusion migration-graph.
8
+ * The drawing formatters compose one string per line, measuring display widths
9
+ * with `string-width` as they go. To carry colour through that pipeline without
10
+ * disturbing a single width, a tone is marked with an SGR escape sequence:
11
+ * `string-width` and `strip-ansi` already treat those as zero-width, so every
12
+ * existing width calculation keeps its answer.
9
13
  *
10
- * Per cell: pick the topmost-plane line (lowest plane number = drawn on top),
11
- * look up its glyph, apply colour from the line's lane or role. Lower-plane
12
- * lines are occluded (not drawn).
13
- *
14
- * Colour is forced via createColors({ useColor: true }) regardless of NO_COLOR.
14
+ * The marks are a transport, not output. {@link toneDrawing} turns a marked
15
+ * string into the engine's spans, and it drops every escape sequence it sees
16
+ * so no escape sequence can reach the engine, which does the painting itself.
17
+ */
18
+ const TONE_MARK_BASE = 900;
19
+ /** The escape character every SGR sequence opens with. */
20
+ const ESCAPE = String.fromCharCode(27);
21
+ /** Ends the innermost open mark. */
22
+ const TONE_MARK_END = `${ESCAPE}[${TONE_MARK_BASE}m`;
23
+ /**
24
+ * Every tone, in the order their marks are numbered. Exported so a test can
25
+ * hold it against a compiler-checked list of the engine's tones: a tone
26
+ * missing from here would silently lose its colour.
15
27
  */
16
- const palette = createColors({ useColor: true });
17
- const LANE_COLORIZERS = [
18
- palette.white,
19
- palette.cyan,
20
- palette.yellow,
21
- palette.blueBright,
22
- palette.magenta,
23
- palette.green
28
+ const TONE_ORDER = [
29
+ "ok",
30
+ "warn",
31
+ "error",
32
+ "info",
33
+ "heading",
34
+ "identifier",
35
+ "ref",
36
+ "placeholder",
37
+ "link",
38
+ "emphasis",
39
+ "muted",
40
+ "structure",
41
+ "highlight",
42
+ "color-1",
43
+ "color-2",
44
+ "color-3",
45
+ "color-4",
46
+ "color-5",
47
+ "color-6"
24
48
  ];
25
- function laneColor(lane) {
26
- return LANE_COLORIZERS[lane % LANE_COLORIZERS.length] ?? ((t) => t);
49
+ const MARK_BY_TONE = new Map(TONE_ORDER.map((tone, index) => [tone, TONE_MARK_BASE + index + 1]));
50
+ const TONE_BY_MARK = new Map(TONE_ORDER.map((tone, index) => [TONE_MARK_BASE + index + 1, tone]));
51
+ /** Marks `text` as carrying `tone`. Marks nest; the innermost one wins. */
52
+ function toned(tone, text) {
53
+ return `${ESCAPE}[${MARK_BY_TONE.get(tone)}m${text}${TONE_MARK_END}`;
54
+ }
55
+ /** The painter shape the formatters take, bound to one tone. */
56
+ function tonePainter(tone) {
57
+ return (text) => toned(tone, text);
58
+ }
59
+ const SGR_SEQUENCE = new RegExp(`${ESCAPE}\\[([\\d;]*)m`, "g");
60
+ function pushSpan(spans, text, tone) {
61
+ if (text.length === 0) return;
62
+ const previous = spans.at(-1);
63
+ if (previous !== void 0 && previous.tone === tone) {
64
+ spans[spans.length - 1] = {
65
+ text: previous.text + text,
66
+ ...tone === void 0 ? {} : { tone }
67
+ };
68
+ return;
69
+ }
70
+ spans.push({
71
+ text,
72
+ ...tone === void 0 ? {} : { tone }
73
+ });
74
+ }
75
+ /** One marked line as spans. Text carrying no mark becomes an untoned span. */
76
+ function toneSpans(line) {
77
+ const spans = [];
78
+ const open = [];
79
+ let cursor = 0;
80
+ SGR_SEQUENCE.lastIndex = 0;
81
+ for (let match = SGR_SEQUENCE.exec(line); match !== null; match = SGR_SEQUENCE.exec(line)) {
82
+ pushSpan(spans, line.slice(cursor, match.index), open.at(-1));
83
+ cursor = match.index + match[0].length;
84
+ for (const parameter of (match[1] ?? "").split(";")) {
85
+ const code = Number(parameter);
86
+ if (code === TONE_MARK_BASE) {
87
+ open.pop();
88
+ continue;
89
+ }
90
+ const tone = TONE_BY_MARK.get(code);
91
+ if (tone !== void 0) open.push(tone);
92
+ }
93
+ }
94
+ pushSpan(spans, line.slice(cursor), open.at(-1));
95
+ return spans;
27
96
  }
28
97
  /**
29
- * The colourizer for a lane's hue (lane0 = white, lane1 = cyan, …). Exported
30
- * so the per-row LABEL renderer can tint a migration name in its lane's colour,
31
- * matching the node `○`, the edges, and the arrows drawn in the gutter — one
32
- * colour per lane across glyph and text.
98
+ * A marked block as the lines of a `drawing` block. A line with no marks stays
99
+ * a plain string, which is what the engine's `Text` wants for untoned text.
33
100
  */
34
- function laneColorizer(lane) {
35
- return laneColor(lane);
36
- }
37
- function roleColor(role) {
38
- return role === "on-path" ? palette.greenBright : palette.dim;
101
+ function toneDrawing(block) {
102
+ return block.split("\n").map((line) => {
103
+ const spans = toneSpans(line);
104
+ if (spans.length === 0) return "";
105
+ const only = spans.length === 1 ? spans[0] : void 0;
106
+ return only !== void 0 && only.tone === void 0 ? only.text : spans;
107
+ });
39
108
  }
40
- const UNICODE_ALPHABET = {
41
- vertical: "│",
42
- horizontal: "─",
43
- cornerUpRight: "╰",
44
- cornerDownRight: "╭",
45
- cornerUpLeft: "╯",
46
- cornerDownLeft: "╮",
47
- arrowUp: "↑",
48
- arrowDown: "↓",
49
- node: "○",
50
- selfLoop: "⟲",
51
- landingArrow: "◂",
52
- fallback: "?"
53
- };
54
- const ASCII_ALPHABET = {
55
- vertical: "|",
56
- horizontal: "-",
57
- cornerUpRight: "\\",
58
- cornerDownRight: "/",
59
- cornerUpLeft: "/",
60
- cornerDownLeft: "\\",
61
- arrowUp: "^",
62
- arrowDown: "v",
63
- node: "*",
64
- selfLoop: "@",
65
- landingArrow: "<",
66
- fallback: "?"
109
+ const LANE_COUNT = 6;
110
+ const forced = createColors({ useColor: true });
111
+ const ANSI_LANES = [
112
+ forced.white,
113
+ forced.cyan,
114
+ forced.yellow,
115
+ forced.blueBright,
116
+ forced.magenta,
117
+ forced.green
118
+ ];
119
+ /** The palette the commander CLI paints with: ANSI SGR straight into the line. */
120
+ const ANSI_MIGRATION_GRAPH_PALETTE = {
121
+ lane: (lane, text) => (ANSI_LANES[lane % LANE_COUNT] ?? ((value) => value))(text),
122
+ role: (role, text) => role === "on-path" ? forced.greenBright(text) : forced.dim(text),
123
+ emphasis: (text) => bold(text),
124
+ status: (status, text) => status === "applied" ? green(text) : yellow(text)
67
125
  };
68
- function alphabetFor(mode) {
69
- return mode === "ascii" ? ASCII_ALPHABET : UNICODE_ALPHABET;
70
- }
71
- function glyphFor(dirs, alphabet) {
72
- const has = (d) => dirs.has(d);
73
- if (has("up") && has("down") && !has("left") && !has("right")) return alphabet.vertical;
74
- if (has("left") && has("right") && !has("up") && !has("down")) return alphabet.horizontal;
75
- if (has("up") && has("right") && !has("down") && !has("left")) return alphabet.cornerUpRight;
76
- if (has("down") && has("right") && !has("up") && !has("left")) return alphabet.cornerDownRight;
77
- if (has("up") && has("left") && !has("down") && !has("right")) return alphabet.cornerUpLeft;
78
- if (has("down") && has("left") && !has("up") && !has("right")) return alphabet.cornerDownLeft;
79
- if (has("up") && !has("down") && !has("left") && !has("right")) return alphabet.arrowUp;
80
- if (has("down") && !has("up") && !has("left") && !has("right")) return alphabet.arrowDown;
81
- return alphabet.fallback;
82
- }
83
- const NO_COLOR = (t) => t;
84
- function renderCell(cell, colorEnabled, alphabet) {
85
- if (cell.node !== void 0) return (!colorEnabled ? NO_COLOR : cell.node.role !== void 0 ? roleColor(cell.node.role) : laneColor(cell.node.lane))(alphabet.node);
86
- if (cell.lines.length === 0) return " ";
87
- const topLine = cell.lines.reduce((best, current) => {
88
- if (current.plane < best.plane) return current;
89
- if (current.plane > best.plane) return best;
90
- if (current.line.role === "on-path" && best.line.role !== "on-path") return current;
91
- return best;
92
- }, cell.lines[0]);
93
- const glyph = topLine.selfLoop === true ? alphabet.selfLoop : topLine.landingArrow === true ? alphabet.landingArrow : glyphFor(topLine.directions, alphabet);
94
- return (!colorEnabled ? NO_COLOR : topLine.line.role !== void 0 ? roleColor(topLine.line.role) : laneColor(topLine.line.lane))(glyph);
95
- }
126
+ const TONE_LANES = [
127
+ "color-1",
128
+ "color-2",
129
+ "color-3",
130
+ "color-4",
131
+ "color-5",
132
+ "color-6"
133
+ ];
96
134
  /**
97
- * Render a single grid row to a coloured string. A completely empty row returns
98
- * the empty string (the row is NOT dropped) so callers that pair grid rows with
99
- * an external per-row label list keep a 1:1 index correspondence. `renderGrid`
100
- * itself drops empty rows for its standalone output (but preserves separator rows).
135
+ * The palette the engine shell marks with: each run of text carries the tone
136
+ * it means, and the engine chooses the bytes. The lane series maps onto the
137
+ * engine's indexed colours in order, which is the same rotation.
101
138
  */
102
- function renderGridRow(row, opts = {}) {
103
- if (row[0]?.separator === true) return "";
104
- let lastNonEmpty = -1;
105
- for (let i = row.length - 1; i >= 0; i--) {
106
- const cell = row[i];
107
- if (cell !== void 0 && (cell.lines.length > 0 || cell.node !== void 0)) {
108
- lastNonEmpty = i;
109
- break;
110
- }
111
- }
112
- if (lastNonEmpty < 0) return "";
113
- const colsPerLane = opts.colsPerLane ?? 2;
114
- const colorEnabled = opts.colorize ?? true;
115
- const alphabet = alphabetFor(opts.glyphMode ?? "unicode");
116
- const lastConnectorCol = Math.floor(lastNonEmpty / colsPerLane) * colsPerLane + (colsPerLane - 1);
117
- const renderThrough = Math.max(lastNonEmpty, lastConnectorCol);
118
- let line = "";
119
- for (let col = 0; col <= Math.min(renderThrough, row.length - 1); col++) {
120
- const cell = row[col];
121
- line += cell === void 0 ? " " : renderCell(cell, colorEnabled, alphabet);
122
- }
123
- return line;
124
- }
139
+ const TONE_MIGRATION_GRAPH_PALETTE = {
140
+ lane: (lane, text) => tonePainter(TONE_LANES[lane % LANE_COUNT] ?? "color-1")(text),
141
+ role: (role, text) => tonePainter(role === "on-path" ? "highlight" : "muted")(text),
142
+ emphasis: tonePainter("emphasis"),
143
+ status: (status, text) => tonePainter(status === "applied" ? "ok" : "warn")(text)
144
+ };
145
+ /** The palette a plain, uncoloured render uses: none of it. */
146
+ const PLAIN_MIGRATION_GRAPH_PALETTE = {
147
+ lane: (_lane, text) => text,
148
+ role: (_role, text) => text,
149
+ emphasis: (text) => text,
150
+ status: (_status, text) => text
151
+ };
125
152
  function migrationListForwardArrow(glyphMode) {
126
153
  return glyphMode === "ascii" ? "->" : "→";
127
154
  }
@@ -1332,6 +1359,7 @@ function renderMigrationGraphSpaceTreeInternal(input) {
1332
1359
  refsByHash: input.refsByHash ?? buildRefsByHashFromListEntries(input.migrations),
1333
1360
  ...input.dbHash !== void 0 ? { dbHash: input.dbHash } : {},
1334
1361
  ...input.styler !== void 0 ? { styler: input.styler } : {},
1362
+ ...input.palette !== void 0 ? { palette: input.palette } : {},
1335
1363
  ...input.globalMaxEdgeTreePrefixWidth !== void 0 ? { globalLabelColumn: input.globalMaxEdgeTreePrefixWidth } : {},
1336
1364
  ...input.globalMaxDirNameWidth !== void 0 ? { globalMaxDirNameWidth: input.globalMaxDirNameWidth } : {}
1337
1365
  });
@@ -1407,7 +1435,8 @@ function buildRefsByHashFromListEntries(entries) {
1407
1435
  function formatEmptyStateLine(spaceId, style) {
1408
1436
  return style.emptyState(`There are no migrations in migrations/${spaceId}/ yet`);
1409
1437
  }
1410
- function renderSpaceTreeBlock(spaceId, migrations, multiSpace, glyphMode, style, colorize, liveContractHash, graphForSpace, appSpaceId, globalMaxEdgeTreePrefixWidth, globalMaxDirNameWidth) {
1438
+ function renderSpaceTreeBlock(input) {
1439
+ const { spaceId, migrations, multiSpace, glyphMode, style, colorize, liveContractHash, graphForSpace, appSpaceId, palette, globalMaxEdgeTreePrefixWidth, globalMaxDirNameWidth } = input;
1411
1440
  if (migrations.length === 0) {
1412
1441
  const emptyLine = formatEmptyStateLine(spaceId, style);
1413
1442
  if (!multiSpace) return [emptyLine];
@@ -1423,6 +1452,7 @@ function renderSpaceTreeBlock(spaceId, migrations, multiSpace, glyphMode, style,
1423
1452
  colorize,
1424
1453
  refsByHash: buildRefsByHashFromListEntries(migrations),
1425
1454
  styler: style,
1455
+ ...palette !== void 0 ? { palette } : {},
1426
1456
  ...isAppSpace !== void 0 ? { isAppSpace } : {},
1427
1457
  ...globalMaxEdgeTreePrefixWidth !== void 0 ? { globalMaxEdgeTreePrefixWidth } : {},
1428
1458
  ...globalMaxDirNameWidth !== void 0 ? { globalMaxDirNameWidth } : {}
@@ -1455,7 +1485,20 @@ function renderMigrationListWithStyle(result, style, glyphMode = "unicode", opti
1455
1485
  for (let index = 0; index < result.spaces.length; index++) {
1456
1486
  const space = result.spaces[index];
1457
1487
  if (index > 0) lines.push("");
1458
- lines.push(...renderSpaceTreeBlock(space.space, space.migrations, multiSpace, glyphMode, style, colorize, liveContractHash, graphForSpace, appSpaceId, globalMaxEdgeTreePrefixWidth, globalMaxDirNameWidth));
1488
+ lines.push(...renderSpaceTreeBlock({
1489
+ spaceId: space.space,
1490
+ migrations: space.migrations,
1491
+ multiSpace,
1492
+ glyphMode,
1493
+ style,
1494
+ colorize,
1495
+ liveContractHash,
1496
+ graphForSpace,
1497
+ appSpaceId,
1498
+ palette: options.palette,
1499
+ globalMaxEdgeTreePrefixWidth,
1500
+ globalMaxDirNameWidth
1501
+ }));
1459
1502
  }
1460
1503
  if (result.spaces.reduce((count, space) => count + space.migrations.length, 0) > 0) {
1461
1504
  lines.push("");
@@ -1540,6 +1583,32 @@ function createAnsiMigrationListStyler(opts) {
1540
1583
  };
1541
1584
  }
1542
1585
  /**
1586
+ * The same vocabulary, said as meaning rather than as colour: each token is
1587
+ * marked with the tone it carries and the CLI engine chooses the bytes.
1588
+ *
1589
+ * Two distinctions the ANSI styler draws by shade do not survive, because a
1590
+ * span carries exactly one tone: the source and destination hashes are both
1591
+ * `identifier` (the ANSI styler dims the source and brightens the
1592
+ * destination), and the `contract` marker is `emphasis` rather than bold
1593
+ * green, which is what tells it apart from a plain marker such as `db`.
1594
+ */
1595
+ function createToneMigrationListStyler() {
1596
+ return {
1597
+ kind: (text) => text,
1598
+ dirName: (text) => toned("emphasis", text),
1599
+ sourceHash: (text) => toned("identifier", text),
1600
+ destHash: (text) => toned("identifier", text),
1601
+ glyph: (text) => toned("structure", text),
1602
+ lane: (text) => toned("structure", text),
1603
+ invariants: (ids) => toned("warn", `{${ids.join(", ")}}`),
1604
+ markers: (names) => names.map((name) => toned("ref", "@") + (name === "contract" ? toned("emphasis", name) : toned("ref", name))).join(" "),
1605
+ refs: (names) => toned("ref", `(${names.join(", ")})`),
1606
+ spaceHeading: (text) => toned("heading", text),
1607
+ summary: (text) => toned("muted", text),
1608
+ emptyState: (text) => toned("muted", text)
1609
+ };
1610
+ }
1611
+ /**
1543
1612
  * Per-row label formatting for the command graph renderer.
1544
1613
  *
1545
1614
  * The command graph renderer ({@link renderMigrationGraphCommand}) derives the
@@ -1559,34 +1628,35 @@ function createAnsiMigrationListStyler(opts) {
1559
1628
  * desired-state marker (see {@link CONTRACT_MARKER_NAME}).
1560
1629
  */
1561
1630
  const DB_MARKER_NAME = "db";
1562
- /**
1563
- * Forced-color functions that always emit ANSI regardless of the ambient TTY
1564
- * environment (NO_COLOR, piped output). Used so on-path green / off-path dim are
1565
- * deterministically emitted in tests that request colour while NO_COLOR is set.
1566
- */
1567
- const { dim: forcedDim } = createColors({ useColor: true });
1568
- const { greenBright: forcedGreen } = createColors({ useColor: true });
1631
+ function paletteFor(opts) {
1632
+ return opts.palette ?? ANSI_MIGRATION_GRAPH_PALETTE;
1633
+ }
1634
+ const identity = (text) => text;
1635
+ /** A palette painter bound to a path role, or a no-op when colour is off. */
1636
+ function rolePainter(palette, colorize, role) {
1637
+ return colorize ? (text) => palette.role(role, text) : identity;
1638
+ }
1569
1639
  /**
1570
1640
  * The two label styles used in `migrate --show` path-highlight mode.
1571
1641
  *
1572
- * - `onPath`: bold name, neutral hashes (the on-path lane glyphs are coloured
1573
- * green by the grid renderer, not here).
1574
- * - `offPath`: uniform dim grey on the name and the whole hash column.
1642
+ * - `onPath`: emphasized name, neutral hashes (the on-path lane glyphs are
1643
+ * coloured by the grid renderer, not here).
1644
+ * - `offPath`: the off-path role reaches the name and the whole hash field.
1575
1645
  *
1576
1646
  * To change the on-path / off-path label colour in future, edit this object.
1577
1647
  */
1578
1648
  const PATH_HIGHLIGHT_STYLES = {
1579
- onPath: (_style, colorize) => ({
1580
- lane: colorize ? forcedGreen : (text) => text,
1581
- arrow: (text) => text,
1582
- dirName: (text) => bold(text),
1649
+ onPath: (_style, colorize, palette = ANSI_MIGRATION_GRAPH_PALETTE) => ({
1650
+ lane: rolePainter(palette, colorize, "on-path"),
1651
+ arrow: identity,
1652
+ dirName: colorize ? (text) => palette.emphasis(text) : identity,
1583
1653
  hashOverride: void 0
1584
1654
  }),
1585
- offPath: (colorize) => ({
1586
- lane: colorize ? forcedDim : (text) => text,
1587
- arrow: colorize ? forcedDim : (text) => text,
1588
- dirName: colorize ? forcedDim : (text) => text,
1589
- hashOverride: colorize ? forcedDim : void 0
1655
+ offPath: (colorize, palette = ANSI_MIGRATION_GRAPH_PALETTE) => ({
1656
+ lane: rolePainter(palette, colorize, "off-path"),
1657
+ arrow: rolePainter(palette, colorize, "off-path"),
1658
+ dirName: rolePainter(palette, colorize, "off-path"),
1659
+ hashOverride: colorize ? rolePainter(palette, colorize, "off-path") : void 0
1590
1660
  })
1591
1661
  };
1592
1662
  function abbreviateHash(hash, hashLength, emptySource) {
@@ -1614,10 +1684,11 @@ function createLabelStyler(opts) {
1614
1684
  const base = opts.styler ?? createAnsiMigrationListStyler({ useColor: opts.colorize });
1615
1685
  const activeRefName = opts.activeRefName;
1616
1686
  if (!opts.colorize || activeRefName === void 0) return base;
1687
+ const palette = paletteFor(opts);
1617
1688
  return {
1618
1689
  ...base,
1619
1690
  refs: (names) => {
1620
- const styledNames = names.map((name) => name === activeRefName ? bold(name) : name);
1691
+ const styledNames = names.map((name) => name === activeRefName ? palette.emphasis(name) : name);
1621
1692
  return base.refs(styledNames);
1622
1693
  }
1623
1694
  };
@@ -1644,10 +1715,7 @@ function formatEdgeAnnotationSuffix(migrationHash, opts, style) {
1644
1715
  const glyph = status === "applied" ? glyphs.applied : glyphs.pending;
1645
1716
  const label = status === "applied" ? "applied" : "pending";
1646
1717
  if (!opts.colorize) segments.push(`${glyph} ${label}`);
1647
- else {
1648
- const styler = status === "applied" ? green : yellow;
1649
- segments.push(styler(`${glyph} ${label}`));
1650
- }
1718
+ else segments.push(paletteFor(opts).status(status, `${glyph} ${label}`));
1651
1719
  }
1652
1720
  if (annotation.pathHighlight === "on-path") {
1653
1721
  const glyph = opts.glyphMode === "ascii" ? ">" : "↑";
@@ -1655,7 +1723,7 @@ function formatEdgeAnnotationSuffix(migrationHash, opts, style) {
1655
1723
  }
1656
1724
  if (segments.length === 0) return "";
1657
1725
  const suffix = ` ${segments.join(" ")}`;
1658
- return opts.colorize && isOffPath ? forcedDim(suffix) : suffix;
1726
+ return opts.colorize && isOffPath ? paletteFor(opts).role("off-path", suffix) : suffix;
1659
1727
  }
1660
1728
  /**
1661
1729
  * Format the `from → to` hash data column for an edge row.
@@ -1687,7 +1755,8 @@ function formatNodeLabel(contractHash, opts, nodeHighlight) {
1687
1755
  const overlays = overlayNamesForContract(contractHash, opts);
1688
1756
  const hasOverlays = overlays.markers.length > 0 || overlays.refs.length > 0;
1689
1757
  const offPath = nodeHighlight === "off-path" && opts.colorize;
1690
- const hashText = contractHash === "empty" ? (offPath ? forcedDim : style.glyph)(emptySource) : (offPath ? forcedDim : style.sourceHash)(abbreviateHash(contractHash, hashLength, emptySource));
1758
+ const dimmed = (text) => paletteFor(opts).role("off-path", text);
1759
+ const hashText = contractHash === "empty" ? (offPath ? dimmed : style.glyph)(emptySource) : (offPath ? dimmed : style.sourceHash)(abbreviateHash(contractHash, hashLength, emptySource));
1691
1760
  if (!hasOverlays) return hashText;
1692
1761
  return `${hashText} ${formatContractNodeOverlays(style, overlays.markers, overlays.refs)}`;
1693
1762
  }
@@ -1705,16 +1774,17 @@ function formatMigrationLabel(edge, dirNameWidth, opts, lane) {
1705
1774
  const hashLength = opts.hashLength ?? 7;
1706
1775
  const glyphMode = opts.glyphMode ?? "unicode";
1707
1776
  const highlight = opts.edgeAnnotationsByHash?.get(edge.migrationHash)?.pathHighlight;
1777
+ const palette = paletteFor(opts);
1708
1778
  let dirNameStyler;
1709
1779
  let hashOverride;
1710
1780
  if (highlight === "on-path") {
1711
- dirNameStyler = opts.colorize ? forcedGreen : (text) => text;
1781
+ dirNameStyler = rolePainter(palette, opts.colorize, "on-path");
1712
1782
  hashOverride = void 0;
1713
1783
  } else if (highlight === "off-path") {
1714
- dirNameStyler = opts.colorize ? forcedDim : style.dirName;
1715
- hashOverride = opts.colorize ? forcedDim : void 0;
1784
+ dirNameStyler = opts.colorize ? rolePainter(palette, true, "off-path") : style.dirName;
1785
+ hashOverride = opts.colorize ? rolePainter(palette, true, "off-path") : void 0;
1716
1786
  } else if (opts.colorize && lane !== void 0) {
1717
- dirNameStyler = (text) => laneColorizer(lane)(text);
1787
+ dirNameStyler = (text) => palette.lane(lane, text);
1718
1788
  hashOverride = void 0;
1719
1789
  } else {
1720
1790
  dirNameStyler = style.dirName;
@@ -1751,11 +1821,6 @@ function legendGlyphs(mode) {
1751
1821
  self: "⟲"
1752
1822
  };
1753
1823
  }
1754
- function formatLegendExampleMarkers(colorize) {
1755
- if (!colorize) return "@contract @db";
1756
- const sigil = green("@");
1757
- return `${sigil + bold(green("contract"))} ${sigil}${green("db")}`;
1758
- }
1759
1824
  /**
1760
1825
  * A compact key for the tree visual language: the contract node glyph, the
1761
1826
  * in-lane direction arrows, the empty baseline, the system-marker `@…` and
@@ -1763,15 +1828,18 @@ function formatLegendExampleMarkers(colorize) {
1763
1828
  */
1764
1829
  function renderMigrationGraphLegend(opts) {
1765
1830
  const glyphMode = opts.glyphMode ?? "unicode";
1766
- const style = createAnsiMigrationListStyler({ useColor: opts.colorize });
1831
+ const style = opts.styler ?? createAnsiMigrationListStyler({ useColor: opts.colorize });
1832
+ const palette = opts.palette ?? ANSI_MIGRATION_GRAPH_PALETTE;
1767
1833
  const glyphs = legendGlyphs(glyphMode);
1768
1834
  const emptySource = migrationListEmptySource(glyphMode);
1769
1835
  const forwardArrow = migrationListForwardArrow(glyphMode);
1770
1836
  const sampleArrow = `${style.sourceHash("aaaaaa")} ${style.glyph(forwardArrow)} ${style.destHash("bbbbbb")}`;
1771
1837
  const statusGlyphs = overlayStatusGlyphs(glyphMode);
1772
- const appliedPending = opts.colorize ? ` ${green(statusGlyphs.applied)} ${style.summary("applied")} ${yellow(statusGlyphs.pending)} ${style.summary("pending")}` : ` ${statusGlyphs.applied} ${style.summary("applied")} ${statusGlyphs.pending} ${style.summary("pending")}`;
1773
- const exampleMarkers = formatLegendExampleMarkers(opts.colorize);
1774
- const exampleRefs = opts.colorize ? style.refs(["prod", "staging"]) : "(prod, staging)";
1838
+ const appliedGlyph = opts.colorize ? palette.status("applied", statusGlyphs.applied) : statusGlyphs.applied;
1839
+ const pendingGlyph = opts.colorize ? palette.status("pending", statusGlyphs.pending) : statusGlyphs.pending;
1840
+ const appliedPending = ` ${appliedGlyph} ${style.summary("applied")} ${pendingGlyph} ${style.summary("pending")}`;
1841
+ const exampleMarkers = style.markers([CONTRACT_MARKER_NAME, DB_MARKER_NAME]);
1842
+ const exampleRefs = style.refs(["prod", "staging"]);
1775
1843
  return [
1776
1844
  "Legend:",
1777
1845
  ` ${style.kind(glyphs.node)} ${style.summary("contract")} ${style.kind(glyphs.forward)} ${style.summary("forward")} ${style.kind(glyphs.rollback)} ${style.summary("rollback")}`,
@@ -1784,6 +1852,104 @@ function renderMigrationGraphLegend(opts) {
1784
1852
  ].join("\n");
1785
1853
  }
1786
1854
  /**
1855
+ * Occlusion renderer for the line/plane/occlusion migration-graph.
1856
+ *
1857
+ * Per cell: pick the topmost-plane line (lowest plane number = drawn on top),
1858
+ * look up its glyph, apply colour from the line's lane or role. Lower-plane
1859
+ * lines are occluded (not drawn).
1860
+ *
1861
+ * Colour comes from the palette the caller hands in; see migration-graph-palette.
1862
+ */
1863
+ const UNICODE_ALPHABET = {
1864
+ vertical: "│",
1865
+ horizontal: "─",
1866
+ cornerUpRight: "╰",
1867
+ cornerDownRight: "╭",
1868
+ cornerUpLeft: "╯",
1869
+ cornerDownLeft: "╮",
1870
+ arrowUp: "↑",
1871
+ arrowDown: "↓",
1872
+ node: "○",
1873
+ selfLoop: "⟲",
1874
+ landingArrow: "◂",
1875
+ fallback: "?"
1876
+ };
1877
+ const ASCII_ALPHABET = {
1878
+ vertical: "|",
1879
+ horizontal: "-",
1880
+ cornerUpRight: "\\",
1881
+ cornerDownRight: "/",
1882
+ cornerUpLeft: "/",
1883
+ cornerDownLeft: "\\",
1884
+ arrowUp: "^",
1885
+ arrowDown: "v",
1886
+ node: "*",
1887
+ selfLoop: "@",
1888
+ landingArrow: "<",
1889
+ fallback: "?"
1890
+ };
1891
+ function alphabetFor(mode) {
1892
+ return mode === "ascii" ? ASCII_ALPHABET : UNICODE_ALPHABET;
1893
+ }
1894
+ function glyphFor(dirs, alphabet) {
1895
+ const has = (d) => dirs.has(d);
1896
+ if (has("up") && has("down") && !has("left") && !has("right")) return alphabet.vertical;
1897
+ if (has("left") && has("right") && !has("up") && !has("down")) return alphabet.horizontal;
1898
+ if (has("up") && has("right") && !has("down") && !has("left")) return alphabet.cornerUpRight;
1899
+ if (has("down") && has("right") && !has("up") && !has("left")) return alphabet.cornerDownRight;
1900
+ if (has("up") && has("left") && !has("down") && !has("right")) return alphabet.cornerUpLeft;
1901
+ if (has("down") && has("left") && !has("up") && !has("right")) return alphabet.cornerDownLeft;
1902
+ if (has("up") && !has("down") && !has("left") && !has("right")) return alphabet.arrowUp;
1903
+ if (has("down") && !has("up") && !has("left") && !has("right")) return alphabet.arrowDown;
1904
+ return alphabet.fallback;
1905
+ }
1906
+ /** A line or node is painted by its path role when it has one, else by its lane. */
1907
+ function paintByRoleOrLane(palette, role, lane) {
1908
+ return role === void 0 ? (text) => palette.lane(lane, text) : (text) => palette.role(role, text);
1909
+ }
1910
+ function renderCell(cell, palette, alphabet) {
1911
+ const node = cell.node;
1912
+ if (node !== void 0) return paintByRoleOrLane(palette, node.role, node.lane)(alphabet.node);
1913
+ if (cell.lines.length === 0) return " ";
1914
+ const topLine = cell.lines.reduce((best, current) => {
1915
+ if (current.plane < best.plane) return current;
1916
+ if (current.plane > best.plane) return best;
1917
+ if (current.line.role === "on-path" && best.line.role !== "on-path") return current;
1918
+ return best;
1919
+ }, cell.lines[0]);
1920
+ const glyph = topLine.selfLoop === true ? alphabet.selfLoop : topLine.landingArrow === true ? alphabet.landingArrow : glyphFor(topLine.directions, alphabet);
1921
+ return paintByRoleOrLane(palette, topLine.line.role, topLine.line.lane)(glyph);
1922
+ }
1923
+ /**
1924
+ * Render a single grid row to a coloured string. A completely empty row returns
1925
+ * the empty string (the row is NOT dropped) so callers that pair grid rows with
1926
+ * an external per-row label list keep a 1:1 index correspondence. `renderGrid`
1927
+ * itself drops empty rows for its standalone output (but preserves separator rows).
1928
+ */
1929
+ function renderGridRow(row, opts = {}) {
1930
+ if (row[0]?.separator === true) return "";
1931
+ let lastNonEmpty = -1;
1932
+ for (let i = row.length - 1; i >= 0; i--) {
1933
+ const cell = row[i];
1934
+ if (cell !== void 0 && (cell.lines.length > 0 || cell.node !== void 0)) {
1935
+ lastNonEmpty = i;
1936
+ break;
1937
+ }
1938
+ }
1939
+ if (lastNonEmpty < 0) return "";
1940
+ const colsPerLane = opts.colsPerLane ?? 2;
1941
+ const palette = opts.colorize ?? true ? opts.palette ?? ANSI_MIGRATION_GRAPH_PALETTE : PLAIN_MIGRATION_GRAPH_PALETTE;
1942
+ const alphabet = alphabetFor(opts.glyphMode ?? "unicode");
1943
+ const lastConnectorCol = Math.floor(lastNonEmpty / colsPerLane) * colsPerLane + (colsPerLane - 1);
1944
+ const renderThrough = Math.max(lastNonEmpty, lastConnectorCol);
1945
+ let line = "";
1946
+ for (let col = 0; col <= Math.min(renderThrough, row.length - 1); col++) {
1947
+ const cell = row[col];
1948
+ line += cell === void 0 ? " " : renderCell(cell, palette, alphabet);
1949
+ }
1950
+ return line;
1951
+ }
1952
+ /**
1787
1953
  * Command graph renderer: composes the gutter (from the grid) with per-row labels.
1788
1954
  *
1789
1955
  * Pipeline: buildMigrationGraphRows → buildGrid → renderMigrationGraphCommand
@@ -1911,7 +2077,8 @@ function renderMigrationGraphCommand(input) {
1911
2077
  ...ifDefined("contractHash", input.contractHash),
1912
2078
  ...ifDefined("isAppSpace", input.isAppSpace),
1913
2079
  ...ifDefined("activeRefName", input.activeRefName),
1914
- ...ifDefined("styler", input.styler)
2080
+ ...ifDefined("styler", input.styler),
2081
+ ...ifDefined("palette", input.palette)
1915
2082
  };
1916
2083
  const nodeHighlights = resolveNodeHighlights(rowModel, input.edgeAnnotationsByHash);
1917
2084
  const labelColumn = input.globalLabelColumn ?? computeLabelColumn(grid, glyphMode);
@@ -1921,7 +2088,8 @@ function renderMigrationGraphCommand(input) {
1921
2088
  for (const row of grid) {
1922
2089
  const gutter = renderGridRow(row, {
1923
2090
  colorize: input.colorize,
1924
- glyphMode
2091
+ glyphMode,
2092
+ ...ifDefined("palette", input.palette)
1925
2093
  });
1926
2094
  const identity = classifyRow(row, edgesByHash);
1927
2095
  if (identity.kind === "none") {
@@ -1940,6 +2108,6 @@ function renderMigrationGraphCommand(input) {
1940
2108
  return lines.join("\n");
1941
2109
  }
1942
2110
  //#endregion
1943
- export { renderMigrationGraphSpaceTree as _, computeGlobalMaxDirNameWidth as a, computeMaxDirNameWidth as c, highlightFromEdgeAnnotations as d, indentMigrationGraphTreeBlock as f, renderMigrationGraphLegend as g, renderMigrationGraphCommand as h, buildMigrationGraphRows as i, createAnsiMigrationListStyler as l, migrationListForwardArrow as m, abbreviateContractHash as n, computeGlobalMaxEdgeTreePrefixWidth as o, migrationListEmptySource as p, buildGrid as r, computeLabelColumn as s, IDENTITY_MIGRATION_LIST_STYLER as t, formatOnPathMigrationRow as u, renderMigrationListWithStyle as v };
2111
+ export { toneSpans as S, renderMigrationGraphCommand as _, buildMigrationGraphRows as a, renderMigrationListWithStyle as b, computeLabelColumn as c, createToneMigrationListStyler as d, formatOnPathMigrationRow as f, migrationListForwardArrow as g, migrationListEmptySource as h, buildGrid as i, computeMaxDirNameWidth as l, indentMigrationGraphTreeBlock as m, TONE_MIGRATION_GRAPH_PALETTE as n, computeGlobalMaxDirNameWidth as o, highlightFromEdgeAnnotations as p, abbreviateContractHash as r, computeGlobalMaxEdgeTreePrefixWidth as s, IDENTITY_MIGRATION_LIST_STYLER as t, createAnsiMigrationListStyler as u, renderMigrationGraphLegend as v, toneDrawing as x, renderMigrationGraphSpaceTree as y };
1944
2112
 
1945
- //# sourceMappingURL=migration-graph-command-render-BKrg6BPv-BP8Pfj4J.mjs.map
2113
+ //# sourceMappingURL=migration-graph-command-render-CgdHruiZ-B6V4gmUe.mjs.map