@prisma-next/cli 0.12.0-dev.9 → 0.13.0-dev.1

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 (214) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.mjs +180 -163
  3. package/dist/cli.mjs.map +1 -1
  4. package/dist/{client-KgJorIvG.mjs → client-CJzuo5wX.mjs} +222 -107
  5. package/dist/client-CJzuo5wX.mjs.map +1 -0
  6. package/dist/{command-helpers-Bbw1GbwL.mjs → command-helpers-DGMvGBeX.mjs} +318 -25
  7. package/dist/command-helpers-DGMvGBeX.mjs.map +1 -0
  8. package/dist/commands/contract-emit.d.mts.map +1 -1
  9. package/dist/commands/contract-emit.mjs +1 -1
  10. package/dist/commands/contract-infer.d.mts.map +1 -1
  11. package/dist/commands/contract-infer.mjs +1 -1
  12. package/dist/commands/db-init.d.mts.map +1 -1
  13. package/dist/commands/db-init.mjs +4 -5
  14. package/dist/commands/db-init.mjs.map +1 -1
  15. package/dist/commands/db-schema.d.mts.map +1 -1
  16. package/dist/commands/db-schema.mjs +3 -3
  17. package/dist/commands/db-schema.mjs.map +1 -1
  18. package/dist/commands/db-sign.d.mts.map +1 -1
  19. package/dist/commands/db-sign.mjs +6 -6
  20. package/dist/commands/db-sign.mjs.map +1 -1
  21. package/dist/commands/db-update.d.mts.map +1 -1
  22. package/dist/commands/db-update.mjs +10 -7
  23. package/dist/commands/db-update.mjs.map +1 -1
  24. package/dist/commands/db-verify.d.mts.map +1 -1
  25. package/dist/commands/db-verify.mjs +1 -1
  26. package/dist/commands/migrate.d.mts +37 -3
  27. package/dist/commands/migrate.d.mts.map +1 -1
  28. package/dist/commands/migrate.mjs +298 -12
  29. package/dist/commands/migrate.mjs.map +1 -1
  30. package/dist/commands/migration-check.d.mts +55 -13
  31. package/dist/commands/migration-check.d.mts.map +1 -1
  32. package/dist/commands/migration-check.mjs +3 -2
  33. package/dist/commands/migration-graph.d.mts +16 -25
  34. package/dist/commands/migration-graph.d.mts.map +1 -1
  35. package/dist/commands/migration-graph.mjs +185 -2
  36. package/dist/commands/migration-graph.mjs.map +1 -0
  37. package/dist/commands/migration-list.d.mts +26 -27
  38. package/dist/commands/migration-list.d.mts.map +1 -1
  39. package/dist/commands/migration-list.mjs +2 -190
  40. package/dist/commands/migration-log.d.mts +9 -19
  41. package/dist/commands/migration-log.d.mts.map +1 -1
  42. package/dist/commands/migration-log.mjs +1 -137
  43. package/dist/commands/migration-new.d.mts.map +1 -1
  44. package/dist/commands/migration-new.mjs +6 -5
  45. package/dist/commands/migration-new.mjs.map +1 -1
  46. package/dist/commands/migration-plan.d.mts +1 -1
  47. package/dist/commands/migration-plan.d.mts.map +1 -1
  48. package/dist/commands/migration-plan.mjs +1 -1
  49. package/dist/commands/migration-show.d.mts +17 -21
  50. package/dist/commands/migration-show.d.mts.map +1 -1
  51. package/dist/commands/migration-show.mjs +24 -36
  52. package/dist/commands/migration-show.mjs.map +1 -1
  53. package/dist/commands/migration-status.d.mts +42 -144
  54. package/dist/commands/migration-status.d.mts.map +1 -1
  55. package/dist/commands/migration-status.mjs +3 -759
  56. package/dist/commands/ref.d.mts +1 -1
  57. package/dist/commands/ref.d.mts.map +1 -1
  58. package/dist/commands/ref.mjs +4 -4
  59. package/dist/commands/ref.mjs.map +1 -1
  60. package/dist/commands/telemetry/index.d.mts +7 -0
  61. package/dist/commands/telemetry/index.d.mts.map +1 -0
  62. package/dist/commands/telemetry/index.mjs +2 -0
  63. package/dist/{config-loader-B6sJjXTv.mjs → config-loader-p9JMrekQ.mjs} +1 -1
  64. package/dist/{config-loader-B6sJjXTv.mjs.map → config-loader-p9JMrekQ.mjs.map} +1 -1
  65. package/dist/config-loader.mjs +1 -1
  66. package/dist/{contract-at-errors-BxP-TOMl.mjs → contract-at-errors-CFXsstzm.mjs} +2 -2
  67. package/dist/{contract-at-errors-BxP-TOMl.mjs.map → contract-at-errors-CFXsstzm.mjs.map} +1 -1
  68. package/dist/{contract-emit-DxcGl4Uq.mjs → contract-emit-B_qriF8B.mjs} +5 -5
  69. package/dist/{contract-emit-DxcGl4Uq.mjs.map → contract-emit-B_qriF8B.mjs.map} +1 -1
  70. package/dist/{contract-emit-D-4jrNve.mjs → contract-emit-C8HmtboH.mjs} +12 -7
  71. package/dist/contract-emit-C8HmtboH.mjs.map +1 -0
  72. package/dist/{contract-enrichment-a0V5Y_mL.mjs → contract-enrichment-gn9sWbPw.mjs} +1 -1
  73. package/dist/{contract-enrichment-a0V5Y_mL.mjs.map → contract-enrichment-gn9sWbPw.mjs.map} +1 -1
  74. package/dist/{contract-infer-D8uEbJuu.mjs → contract-infer-BYT_ra_U.mjs} +5 -5
  75. package/dist/contract-infer-BYT_ra_U.mjs.map +1 -0
  76. package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs → contract-space-aggregate-loader-ClI1KN6d.mjs} +5 -5
  77. package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs.map → contract-space-aggregate-loader-ClI1KN6d.mjs.map} +1 -1
  78. package/dist/{db-verify-v_vUKXTU.mjs → db-verify-C24FKhb7.mjs} +6 -6
  79. package/dist/{db-verify-v_vUKXTU.mjs.map → db-verify-C24FKhb7.mjs.map} +1 -1
  80. package/dist/exports/control-api.d.mts +5 -3
  81. package/dist/exports/control-api.d.mts.map +1 -1
  82. package/dist/exports/control-api.mjs +3 -3
  83. package/dist/exports/index.mjs +1 -1
  84. package/dist/exports/index.mjs.map +1 -1
  85. package/dist/exports/init-output.d.mts +1 -3
  86. package/dist/exports/init-output.d.mts.map +1 -1
  87. package/dist/exports/init-output.mjs +1 -1
  88. package/dist/{extension-pack-inputs-IDvjRCi3.mjs → extension-pack-inputs-1ySHqxKG.mjs} +1 -1
  89. package/dist/{extension-pack-inputs-IDvjRCi3.mjs.map → extension-pack-inputs-1ySHqxKG.mjs.map} +1 -1
  90. package/dist/{framework-components-fYXjz_in.mjs → framework-components-YVQHhPH7.mjs} +2 -2
  91. package/dist/{framework-components-fYXjz_in.mjs.map → framework-components-YVQHhPH7.mjs.map} +1 -1
  92. package/dist/{global-flags-DEHjV8_s.d.mts → global-flags-BpoOYtNZ.d.mts} +1 -1
  93. package/dist/{global-flags-DEHjV8_s.d.mts.map → global-flags-BpoOYtNZ.d.mts.map} +1 -1
  94. package/dist/{init-Cv9UzWL5.mjs → init-0HwB-Vh8.mjs} +5 -58
  95. package/dist/init-0HwB-Vh8.mjs.map +1 -0
  96. package/dist/{inspect-live-schema-C6ohV_oQ.mjs → inspect-live-schema-DF6IwcDl.mjs} +7 -5
  97. package/dist/inspect-live-schema-DF6IwcDl.mjs.map +1 -0
  98. package/dist/migration-check-soB5uZEQ.mjs +573 -0
  99. package/dist/migration-check-soB5uZEQ.mjs.map +1 -0
  100. package/dist/migration-cli.mjs +1 -1
  101. package/dist/migration-cli.mjs.map +1 -1
  102. package/dist/{migration-command-scaffold-CjvwO6at.mjs → migration-command-scaffold-DA-Lhx6o.mjs} +5 -5
  103. package/dist/{migration-command-scaffold-CjvwO6at.mjs.map → migration-command-scaffold-DA-Lhx6o.mjs.map} +1 -1
  104. package/dist/migration-graph-command-render-CEez7YUK.mjs +1960 -0
  105. package/dist/migration-graph-command-render-CEez7YUK.mjs.map +1 -0
  106. package/dist/migration-list-DlJJ_38Z.mjs +230 -0
  107. package/dist/migration-list-DlJJ_38Z.mjs.map +1 -0
  108. package/dist/migration-log-CG0qQAFm.mjs +222 -0
  109. package/dist/migration-log-CG0qQAFm.mjs.map +1 -0
  110. package/dist/migration-path-target-Ce6OZImp.mjs +38 -0
  111. package/dist/migration-path-target-Ce6OZImp.mjs.map +1 -0
  112. package/dist/{migration-plan-9DJ7q7_z.mjs → migration-plan-z5Ing-TD.mjs} +9 -8
  113. package/dist/migration-plan-z5Ing-TD.mjs.map +1 -0
  114. package/dist/migration-status-CgWSoI_g.mjs +446 -0
  115. package/dist/migration-status-CgWSoI_g.mjs.map +1 -0
  116. package/dist/{output-B60Gw5fu.mjs → output-mEQ74_nd.mjs} +1 -1
  117. package/dist/{output-B60Gw5fu.mjs.map → output-mEQ74_nd.mjs.map} +1 -1
  118. package/dist/{progress-adapter-C644QK8l.mjs → progress-adapter-CjAeTxY_.mjs} +1 -1
  119. package/dist/{progress-adapter-C644QK8l.mjs.map → progress-adapter-CjAeTxY_.mjs.map} +1 -1
  120. package/dist/{ref-advancement-DUZqsue6.mjs → ref-advancement-BkXlikCA.mjs} +1 -1
  121. package/dist/{ref-advancement-DUZqsue6.mjs.map → ref-advancement-BkXlikCA.mjs.map} +1 -1
  122. package/dist/schemas-CeGMYFYX.d.mts +191 -0
  123. package/dist/schemas-CeGMYFYX.d.mts.map +1 -0
  124. package/dist/schemas-KhXMzNA_.mjs +112 -0
  125. package/dist/schemas-KhXMzNA_.mjs.map +1 -0
  126. package/dist/telemetry-BIM4beEO.mjs +122 -0
  127. package/dist/telemetry-BIM4beEO.mjs.map +1 -0
  128. package/dist/{terminal-ui-5Y6mrg93.d.mts → terminal-ui-DGRNFWna.d.mts} +1 -1
  129. package/dist/terminal-ui-DGRNFWna.d.mts.map +1 -0
  130. package/dist/{types-Dt_SfqFm.d.mts → types-C_tYiJYx.d.mts} +53 -31
  131. package/dist/types-C_tYiJYx.d.mts.map +1 -0
  132. package/dist/{verify-DCA9Sldu.mjs → verify-DcOYZ1tH.mjs} +2 -2
  133. package/dist/{verify-DCA9Sldu.mjs.map → verify-DcOYZ1tH.mjs.map} +1 -1
  134. package/package.json +26 -22
  135. package/src/cli.ts +5 -0
  136. package/src/commands/contract-infer.ts +2 -2
  137. package/src/commands/db-update.ts +7 -1
  138. package/src/commands/init/index.ts +6 -35
  139. package/src/commands/init/init.ts +1 -14
  140. package/src/commands/init/inputs.ts +0 -75
  141. package/src/commands/inspect-live-schema.ts +10 -0
  142. package/src/commands/json/schemas.ts +195 -0
  143. package/src/commands/migrate.ts +527 -8
  144. package/src/commands/migration-check.ts +469 -134
  145. package/src/commands/migration-graph.ts +151 -119
  146. package/src/commands/migration-list.ts +72 -39
  147. package/src/commands/migration-log.ts +52 -102
  148. package/src/commands/migration-new.ts +2 -1
  149. package/src/commands/migration-plan.ts +2 -1
  150. package/src/commands/migration-show.ts +31 -66
  151. package/src/commands/migration-status-overlay.ts +61 -0
  152. package/src/commands/migration-status.ts +458 -1066
  153. package/src/commands/telemetry/index.ts +107 -0
  154. package/src/commands/telemetry/status.ts +67 -0
  155. package/src/control-api/client.ts +70 -9
  156. package/src/control-api/operations/contract-emit.ts +22 -2
  157. package/src/control-api/operations/db-init.ts +6 -3
  158. package/src/control-api/operations/{db-apply.ts → db-run.ts} +55 -14
  159. package/src/control-api/operations/db-update.ts +7 -4
  160. package/src/control-api/operations/db-verify.ts +15 -5
  161. package/src/control-api/operations/{migration-apply.ts → migrate.ts} +181 -80
  162. package/src/control-api/operations/{apply.ts → run-migration.ts} +33 -27
  163. package/src/control-api/types.ts +56 -29
  164. package/src/utils/cli-errors.ts +70 -2
  165. package/src/utils/formatters/errors.ts +11 -0
  166. package/src/utils/formatters/migration-graph-command-render.ts +239 -0
  167. package/src/utils/formatters/migration-graph-grid-layout.ts +1134 -0
  168. package/src/utils/formatters/migration-graph-labels.ts +408 -0
  169. package/src/utils/formatters/migration-graph-model.ts +103 -0
  170. package/src/utils/formatters/migration-graph-occlusion-render.ts +258 -0
  171. package/src/utils/formatters/migration-graph-rows.ts +128 -15
  172. package/src/utils/formatters/migration-graph-space-render.ts +188 -0
  173. package/src/utils/formatters/migration-list-data-column.ts +4 -91
  174. package/src/utils/formatters/migration-list-graph-topology.ts +72 -94
  175. package/src/utils/formatters/migration-list-render.ts +135 -71
  176. package/src/utils/formatters/migration-list-styler.ts +46 -5
  177. package/src/utils/formatters/migration-list-types.ts +5 -21
  178. package/src/utils/formatters/migration-log-table.ts +205 -0
  179. package/src/utils/formatters/migrations.ts +33 -11
  180. package/src/utils/global-flags.ts +35 -0
  181. package/src/utils/integrity-violation-to-check-failure.ts +28 -19
  182. package/src/utils/legend.ts +38 -0
  183. package/src/utils/migration-path-target.ts +60 -0
  184. package/src/utils/telemetry.ts +68 -32
  185. package/dist/client-KgJorIvG.mjs.map +0 -1
  186. package/dist/command-helpers-Bbw1GbwL.mjs.map +0 -1
  187. package/dist/commands/migration-list.mjs.map +0 -1
  188. package/dist/commands/migration-log.mjs.map +0 -1
  189. package/dist/commands/migration-status.mjs.map +0 -1
  190. package/dist/contract-emit-D-4jrNve.mjs.map +0 -1
  191. package/dist/contract-infer-D8uEbJuu.mjs.map +0 -1
  192. package/dist/graph-render-rFAqZujX.mjs +0 -1081
  193. package/dist/graph-render-rFAqZujX.mjs.map +0 -1
  194. package/dist/init-Cv9UzWL5.mjs.map +0 -1
  195. package/dist/inspect-live-schema-C6ohV_oQ.mjs.map +0 -1
  196. package/dist/migration-check-BiBJoYYW.mjs +0 -341
  197. package/dist/migration-check-BiBJoYYW.mjs.map +0 -1
  198. package/dist/migration-graph-C9WC-7eO.mjs +0 -1478
  199. package/dist/migration-graph-C9WC-7eO.mjs.map +0 -1
  200. package/dist/migration-list-styler-BRwF4-gy.mjs +0 -399
  201. package/dist/migration-list-styler-BRwF4-gy.mjs.map +0 -1
  202. package/dist/migration-plan-9DJ7q7_z.mjs.map +0 -1
  203. package/dist/migration-types-D2FW63pr.d.mts +0 -15
  204. package/dist/migration-types-D2FW63pr.d.mts.map +0 -1
  205. package/dist/migrations-Cv2jxNNK.mjs +0 -228
  206. package/dist/migrations-Cv2jxNNK.mjs.map +0 -1
  207. package/dist/terminal-ui-5Y6mrg93.d.mts.map +0 -1
  208. package/dist/types-Dt_SfqFm.d.mts.map +0 -1
  209. package/src/utils/formatters/graph-migration-mapper.ts +0 -235
  210. package/src/utils/formatters/graph-render.ts +0 -1323
  211. package/src/utils/formatters/graph-types.ts +0 -120
  212. package/src/utils/formatters/migration-graph-lane-colors.ts +0 -31
  213. package/src/utils/formatters/migration-graph-layout.ts +0 -1141
  214. package/src/utils/formatters/migration-graph-tree-render.ts +0 -768
@@ -2,7 +2,12 @@ import type {
2
2
  ContractSourceDiagnostics,
3
3
  ContractSourceProvider,
4
4
  } from '@prisma-next/config/config-types';
5
- import type { Contract, ContractMarkerRecord } from '@prisma-next/contract/types';
5
+ import type {
6
+ Contract,
7
+ ContractMarkerRecord,
8
+ LedgerEntryRecord,
9
+ } from '@prisma-next/contract/types';
10
+ import type { AuthoringPslBlockDescriptorNamespace } from '@prisma-next/framework-components/authoring';
6
11
  import type {
7
12
  ControlAdapterDescriptor,
8
13
  ControlDriverDescriptor,
@@ -67,7 +72,7 @@ export type ControlActionName =
67
72
  | 'dbInit'
68
73
  | 'dbUpdate'
69
74
  | 'dbVerify'
70
- | 'migrationApply'
75
+ | 'migrate'
71
76
  | 'verify'
72
77
  | 'schemaVerify'
73
78
  | 'sign'
@@ -391,6 +396,7 @@ export interface DbInitSuccess {
391
396
  */
392
397
  readonly perSpace?: ReadonlyArray<PerSpaceExecutionEntry>;
393
398
  readonly summary: string;
399
+ readonly warnings?: ReadonlyArray<MigrationPlannerConflict>;
394
400
  }
395
401
 
396
402
  /**
@@ -406,6 +412,7 @@ export interface DbInitFailure {
406
412
  readonly summary: string;
407
413
  readonly why: string | undefined;
408
414
  readonly conflicts: ReadonlyArray<MigrationPlannerConflict> | undefined;
415
+ readonly warnings?: ReadonlyArray<MigrationPlannerConflict>;
409
416
  readonly meta: Record<string, unknown> | undefined;
410
417
  readonly marker?: {
411
418
  readonly storageHash?: string;
@@ -461,6 +468,7 @@ export interface DbUpdateSuccess {
461
468
  */
462
469
  readonly perSpace?: ReadonlyArray<PerSpaceExecutionEntry>;
463
470
  readonly summary: string;
471
+ readonly warnings?: ReadonlyArray<MigrationPlannerConflict>;
464
472
  }
465
473
 
466
474
  /**
@@ -476,6 +484,7 @@ export interface DbUpdateFailure {
476
484
  readonly summary: string;
477
485
  readonly why: string | undefined;
478
486
  readonly conflicts: ReadonlyArray<MigrationPlannerConflict> | undefined;
487
+ readonly warnings?: ReadonlyArray<MigrationPlannerConflict>;
479
488
  readonly meta: Record<string, unknown> | undefined;
480
489
  }
481
490
 
@@ -532,17 +541,17 @@ export type EmitResult = Result<EmitSuccess, EmitFailure>;
532
541
  // ============================================================================
533
542
 
534
543
  /**
535
- * Options for the aggregate-walking `migrationApply` operation.
544
+ * Options for the aggregate-walking `migrate` operation.
536
545
  *
537
546
  * The control-api operation is responsible for: loading the
538
547
  * contract-space aggregate, reading per-space marker rows from the
539
548
  * live database, plotting per-space paths via `graphWalkStrategy`
540
549
  * (replay-only — no synth, no introspection), and dispatching
541
- * through the shared `applyMigration` primitive. The CLI command
550
+ * through the shared `runMigration` primitive. The CLI command
542
551
  * just resolves the descriptor surface (config, refs, contract
543
552
  * envelope, app-space migration packages) and hands the inputs in.
544
553
  */
545
- export interface MigrationApplyOptions {
554
+ export interface MigrateOptions {
546
555
  /** Already-validated app contract (the canonical "where we are heading" hash). */
547
556
  readonly contract: unknown;
548
557
  /** Migrations root directory (`migrations/` under the project). */
@@ -567,7 +576,7 @@ export interface MigrationApplyOptions {
567
576
  */
568
577
  readonly refName?: string;
569
578
  /**
570
- * Database connection. If provided, migrationApply will connect before executing.
579
+ * Database connection. If provided, migrate will connect before executing.
571
580
  * If omitted, the client must already be connected.
572
581
  */
573
582
  readonly connection?: unknown;
@@ -611,7 +620,7 @@ export interface MigrationApplyStep {
611
620
  * Per-space aggregate detail (markers, ops grouped by space) lives
612
621
  * on `perSpace[]`; this list is the per-edge view.
613
622
  */
614
- export interface MigrationApplyAppliedEntry {
623
+ export interface MigrateRanEntry {
615
624
  readonly spaceId: string;
616
625
  readonly dirName: string;
617
626
  readonly migrationHash: string;
@@ -621,13 +630,13 @@ export interface MigrationApplyAppliedEntry {
621
630
  }
622
631
 
623
632
  /**
624
- * Successful migrationApply result. Carries both the top-level fields
625
- * (`markerHash` is the **app member's** post-apply marker) and the
633
+ * Successful migrate result. Carries both the top-level fields
634
+ * (`markerHash` is the **app member's** post-migrate marker) and the
626
635
  * per-space breakdown (`perSpace` — markers / operations in canonical
627
636
  * schedule order).
628
637
  */
629
638
  /**
630
- * Path-decision summary for the **app member** post-apply. Surfaced
639
+ * Path-decision summary for the **app member** post-migrate. Surfaced
631
640
  * at the top level (and consumed by the cli-journeys suite, which
632
641
  * inspects `requiredInvariants`/`satisfiedInvariants`/
633
642
  * `selectedPath` to validate invariant routing).
@@ -635,7 +644,7 @@ export interface MigrationApplyAppliedEntry {
635
644
  * Per-space path decisions for extension members are not surfaced —
636
645
  * extensions own their own ref/invariant control.
637
646
  */
638
- export interface MigrationApplyPathDecision {
647
+ export interface MigratePathDecision {
639
648
  readonly fromHash: string;
640
649
  readonly toHash: string;
641
650
  readonly alternativeCount: number;
@@ -652,10 +661,10 @@ export interface MigrationApplyPathDecision {
652
661
  }[];
653
662
  }
654
663
 
655
- export interface MigrationApplySuccess {
664
+ export interface MigrateSuccess {
656
665
  readonly migrationsApplied: number;
657
666
  readonly markerHash: string;
658
- readonly applied: readonly MigrationApplyAppliedEntry[];
667
+ readonly applied: readonly MigrateRanEntry[];
659
668
  readonly summary: string;
660
669
  /**
661
670
  * Per-space breakdown in canonical schedule order (extensions
@@ -666,31 +675,31 @@ export interface MigrationApplySuccess {
666
675
  /**
667
676
  * Path-decision data for the app member. Present whenever the
668
677
  * graph-walk strategy ran for the app (i.e. always for the
669
- * aggregate-walking apply path). Absent only for the no-op
678
+ * aggregate-walking migrate path). Absent only for the no-op
670
679
  * "Already up to date" early return when the app has no plan.
671
680
  */
672
- readonly pathDecision?: MigrationApplyPathDecision;
681
+ readonly pathDecision?: MigratePathDecision;
673
682
  }
674
683
 
675
684
  /**
676
- * Failure codes for migrationApply operation.
685
+ * Failure codes for migrate operation.
677
686
  */
678
- export type MigrationApplyFailureCode = 'RUNNER_FAILED' | 'MIGRATION_PATH_NOT_FOUND';
687
+ export type MigrateFailureCode = 'RUNNER_FAILED' | 'MIGRATION_PATH_NOT_FOUND';
679
688
 
680
689
  /**
681
- * Failure details for migrationApply operation.
690
+ * Failure details for migrate operation.
682
691
  */
683
- export interface MigrationApplyFailure {
684
- readonly code: MigrationApplyFailureCode;
692
+ export interface MigrateFailure {
693
+ readonly code: MigrateFailureCode;
685
694
  readonly summary: string;
686
695
  readonly why: string | undefined;
687
696
  readonly meta: Record<string, unknown> | undefined;
688
697
  }
689
698
 
690
699
  /**
691
- * Result type for migrationApply operation.
700
+ * Result type for migrate operation.
692
701
  */
693
- export type MigrationApplyResult = Result<MigrationApplySuccess, MigrationApplyFailure>;
702
+ export type MigrateResult = Result<MigrateSuccess, MigrateFailure>;
694
703
 
695
704
  // ============================================================================
696
705
  // Standalone Contract Emit Types
@@ -877,17 +886,26 @@ export interface ControlClient {
877
886
  readAllMarkers(): Promise<ReadonlyMap<string, ContractMarkerRecord>>;
878
887
 
879
888
  /**
880
- * Applies pre-planned on-disk migrations to the database.
889
+ * Reads the per-migration ledger journal for `space` in apply order.
890
+ * Returns an empty array when the ledger store does not yet exist or
891
+ * has no rows for that space.
892
+ */
893
+ readLedger(space?: string): Promise<readonly LedgerEntryRecord[]>;
894
+
895
+ /**
896
+ * Advances the database along the migration graph to the target contract.
881
897
  * Each migration runs in its own transaction with full execution checks.
882
- * Resume-safe: re-running after failure picks up from the last applied migration.
898
+ * Resume-safe: re-running after failure picks up from the last run migration.
883
899
  *
884
- * @param options.originHash - Explicit source hash for the apply path
885
- * @param options.destinationHash - Explicit destination hash for the apply path
886
- * @param options.pendingMigrations - Ordered migrations to execute
887
- * @returns Result pattern: Ok with applied details, NotOk with failure details
900
+ * @param options.contract - The target contract to migrate to
901
+ * @param options.migrationsDir - Root migrations directory (`migrations/` under the project)
902
+ * @param options.refHash - Optional app-space ref override hash
903
+ * @param options.refInvariants - Required invariants on the user-supplied ref
904
+ * @param options.refName - Resolved name of the user-supplied app-space ref
905
+ * @returns Result pattern: Ok with migration details, NotOk with failure details
888
906
  * @throws If not connected, target doesn't support migrations, or infrastructure failure
889
907
  */
890
- migrationApply(options: MigrationApplyOptions): Promise<MigrationApplyResult>;
908
+ migrate(options: MigrateOptions): Promise<MigrateResult>;
891
909
 
892
910
  /**
893
911
  * Introspects the database schema.
@@ -915,6 +933,15 @@ export interface ControlClient {
915
933
  */
916
934
  inferPslContract(schemaIR: unknown): PslDocumentAst | undefined;
917
935
 
936
+ /**
937
+ * Returns the assembled PSL block descriptors from the control stack — the full
938
+ * set of extension-contributed top-level block descriptors. The CLI's
939
+ * `contract infer` command threads these through to `printPsl` so
940
+ * extension-contributed blocks in the inferred AST round-trip back to PSL
941
+ * source. Forces `init()` so the stack is built before access.
942
+ */
943
+ getPslBlockDescriptors(): AuthoringPslBlockDescriptorNamespace;
944
+
918
945
  /**
919
946
  * Renders a textual preview of a migration plan's operations for the CLI's
920
947
  * "DDL preview" output. Delegates to the family instance's
@@ -28,7 +28,8 @@ import {
28
28
  import { errorRuntime } from '@prisma-next/errors/execution';
29
29
  import type { MigrationToolsError } from '@prisma-next/migration-tools/errors';
30
30
  import type { RefResolutionError } from '@prisma-next/migration-tools/ref-resolution';
31
- import type { MigrationApplyFailure } from '../control-api/types';
31
+ import { ifDefined } from '@prisma-next/utils/defined';
32
+ import type { MigrateFailure } from '../control-api/types';
32
33
 
33
34
  export {
34
35
  ERROR_CODE_DESTRUCTIVE_CHANGES,
@@ -108,6 +109,23 @@ export function errorRefSetEmptySentinel(hash: string): CliStructuredError {
108
109
  });
109
110
  }
110
111
 
112
+ /**
113
+ * `--legend` was combined with a machine-readable or silent output flag.
114
+ * The legend is human-only decoration on stderr.
115
+ */
116
+ export function errorLegendHumanOnly(
117
+ conflictingFlag: '--json' | '--dot' | '--quiet',
118
+ ): CliStructuredError {
119
+ return errorRuntime('`--legend` is only available for human-readable output', {
120
+ why: `\`--legend\` prints a glyph key to stderr and cannot be combined with ${conflictingFlag}.`,
121
+ fix: `Omit ${conflictingFlag} to print the legend alongside the tree, or omit --legend when using ${conflictingFlag}.`,
122
+ meta: {
123
+ code: 'MIGRATION.LEGEND_HUMAN_ONLY',
124
+ conflictingFlag,
125
+ },
126
+ });
127
+ }
128
+
111
129
  /**
112
130
  * `--space <id>` was given a value that doesn't satisfy the contract-space
113
131
  * naming rule (`[a-z][a-z0-9_-]{0,63}` per `isValidSpaceId`). Fires before
@@ -250,7 +268,7 @@ export function errorMarkerMismatch(
250
268
  });
251
269
  }
252
270
 
253
- export function errorPathUnreachable(failure: MigrationApplyFailure): CliStructuredError {
271
+ export function errorPathUnreachable(failure: MigrateFailure): CliStructuredError {
254
272
  const meta = failure.meta ?? {};
255
273
  const fromHashMeta = typeof meta['fromHash'] === 'string' ? meta['fromHash'] : null;
256
274
  // `buildPathNotFoundFailure` uses this sentinel in meta when the live marker is null.
@@ -325,10 +343,60 @@ export function mapMigrationToolsError(error: MigrationToolsError): CliStructure
325
343
  });
326
344
  }
327
345
 
346
+ /**
347
+ * Shared "needs a live database" precondition for read verbs that consult the
348
+ * marker/ledger (`migration log`, `migration status`). A command needs both a
349
+ * connection string and a control-plane driver; either missing yields the same
350
+ * `PN-CLI-4005` envelope with `meta.missingFlags` (canonical long-form flags
351
+ * per CLI Style Guide §Errors) so callers can react programmatically. Returns
352
+ * `null` when both are present.
353
+ */
354
+ export function requireLiveDatabase(args: {
355
+ readonly dbConnection: unknown;
356
+ readonly hasDriver: boolean;
357
+ readonly why: string;
358
+ readonly commandName?: string;
359
+ readonly retryCommand?: string;
360
+ }): CliStructuredError | null {
361
+ if (args.dbConnection && args.hasDriver) {
362
+ return null;
363
+ }
364
+ const missingFlags = args.dbConnection ? [] : ['--db'];
365
+ return errorDatabaseConnectionRequired({
366
+ why: args.why,
367
+ missingFlags,
368
+ ...ifDefined('commandName', args.commandName),
369
+ ...ifDefined('retryCommand', args.retryCommand),
370
+ });
371
+ }
372
+
328
373
  /**
329
374
  * Maps a `RefResolutionError` from the contract/migration reference
330
375
  * resolver into a CLI structured error envelope.
331
376
  */
377
+ /**
378
+ * A migration ref (dirName or hash-prefix) resolves in more than one contract
379
+ * space. The user must qualify with `--space <id>` to disambiguate.
380
+ */
381
+ export function errorAmbiguousMigrationRef(
382
+ ref: string,
383
+ spaceIds: readonly string[],
384
+ ): CliStructuredError {
385
+ const spaceList = spaceIds.join(', ');
386
+ return errorRuntime(
387
+ `Ambiguous migration reference: "${ref}" resolves in multiple spaces — qualify with --space <id>`,
388
+ {
389
+ why: `"${ref}" matches migrations in spaces: ${spaceList}.`,
390
+ fix: `Qualify with --space <id> to select one space. Available matching spaces: ${spaceList}.`,
391
+ meta: {
392
+ code: 'MIGRATION.AMBIGUOUS_MIGRATION_REF',
393
+ ref,
394
+ spaceIds: [...spaceIds],
395
+ },
396
+ },
397
+ );
398
+ }
399
+
332
400
  export function mapRefResolutionError(error: RefResolutionError): CliStructuredError {
333
401
  switch (error.kind) {
334
402
  case 'not-found':
@@ -1,8 +1,11 @@
1
+ import type { MigrationPlannerConflict } from '@prisma-next/framework-components/control';
2
+ import { blindCast } from '@prisma-next/utils/casts';
1
3
  import { red } from 'colorette';
2
4
 
3
5
  import type { CliErrorConflict, CliErrorEnvelope } from '../cli-errors';
4
6
  import type { GlobalFlags } from '../global-flags';
5
7
  import { createColorFormatter, formatDim, isVerbose } from './helpers';
8
+ import { formatPlannerWarningsBlock } from './migrations';
6
9
 
7
10
  /**
8
11
  * Formats error output for human-readable display.
@@ -67,6 +70,14 @@ export function formatErrorOutput(error: CliErrorEnvelope, flags: GlobalFlags):
67
70
  if (error.docsUrl && isVerbose(flags, 1)) {
68
71
  lines.push(formatDimText(error.docsUrl));
69
72
  }
73
+ const plannerWarnings = error.meta?.['plannerWarnings'];
74
+ if (Array.isArray(plannerWarnings) && plannerWarnings.length > 0) {
75
+ const typedWarnings = blindCast<
76
+ readonly MigrationPlannerConflict[],
77
+ 'mapDbUpdateFailure (db-update.ts) writes meta.plannerWarnings as MigrationPlannerConflict[]; meta is typed Record<string, unknown> so the channel erases the element type'
78
+ >(plannerWarnings);
79
+ lines.push(...formatPlannerWarningsBlock(typedWarnings, useColor));
80
+ }
70
81
  if (isVerbose(flags, 2) && error.meta) {
71
82
  lines.push(`${formatDimText(` Meta: ${JSON.stringify(error.meta, null, 2)}`)}`);
72
83
  }
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Command graph renderer: composes the gutter (from the grid) with per-row labels.
3
+ *
4
+ * Pipeline: buildMigrationGraphRows → buildGrid → renderMigrationGraphCommand
5
+ *
6
+ * Each grid row is classified by its cells: a node row gets a contract label;
7
+ * a migration arrow row gets a migration label; connector rows get no label.
8
+ * Label format and styling live in `./migration-graph-labels`.
9
+ */
10
+
11
+ import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
12
+ import { ifDefined } from '@prisma-next/utils/defined';
13
+ import stringWidth from 'string-width';
14
+ import type { GlyphMode } from '../glyph-mode';
15
+ import {
16
+ formatMigrationLabel,
17
+ formatNodeLabel,
18
+ type MigrationEdgeAnnotation,
19
+ type MigrationGraphLabelOptions,
20
+ } from './migration-graph-labels';
21
+ import type { Cell, CellLine, Grid } from './migration-graph-model';
22
+ import { renderGridRow } from './migration-graph-occlusion-render';
23
+ import type { ClassifiedEdge, MigrationGraphRowModel } from './migration-graph-rows';
24
+ import type { MigrationListStyler } from './migration-list-render';
25
+
26
+ const LABEL_GAP = 2;
27
+ const MIN_HASH_DATA_COLUMN = 25;
28
+
29
+ export interface RenderMigrationGraphCommandInput {
30
+ readonly grid: Grid;
31
+ readonly rowModel: MigrationGraphRowModel;
32
+ readonly colorize: boolean;
33
+ readonly glyphMode: GlyphMode;
34
+ readonly refsByHash?: ReadonlyMap<string, readonly string[]>;
35
+ readonly edgeAnnotationsByHash?: ReadonlyMap<string, MigrationEdgeAnnotation>;
36
+ readonly dbHash?: string;
37
+ readonly contractHash?: string;
38
+ readonly isAppSpace?: boolean;
39
+ readonly activeRefName?: string;
40
+ readonly styler?: MigrationListStyler;
41
+ /** Cross-space override for the gutter→label column (max gutter width). */
42
+ readonly globalLabelColumn?: number;
43
+ /** Cross-space override for the migration-name column width. */
44
+ readonly globalMaxDirNameWidth?: number;
45
+ }
46
+
47
+ // ---------------------------------------------------------------------------
48
+ // Row classification — derive each grid row's identity from its own cells.
49
+ // ---------------------------------------------------------------------------
50
+
51
+ type RowIdentity =
52
+ | { readonly kind: 'node'; readonly contractHash: string }
53
+ | { readonly kind: 'migration'; readonly edge: ClassifiedEdge; readonly lane: number }
54
+ | { readonly kind: 'none' };
55
+
56
+ /**
57
+ * Classify a grid row by its own cells:
58
+ * - a cell carrying a NodeRef → node row (contract label);
59
+ * - a cell whose top line is an arrow ({up}/{down}/self-loop) → migration row;
60
+ * - otherwise → no label.
61
+ *
62
+ * A migration's arrow appears in exactly one grid row (the forward `↑` row, the
63
+ * adjacent-rollback `↓` row, or the self-loop `⟲` row), so each migration gets
64
+ * exactly one label, on the row that draws its arrow.
65
+ *
66
+ * Two distinct migrations with identical content (same from/to/ops) hash to the
67
+ * SAME migration hash, so the arrow line is matched on BOTH its hash and its
68
+ * `dirName` (which the LineRef carries per-row) — otherwise both rows would
69
+ * resolve to one edge and the other migration's name would be lost.
70
+ */
71
+ function classifyRow(
72
+ row: readonly Cell[],
73
+ edgesByHash: ReadonlyMap<string, readonly ClassifiedEdge[]>,
74
+ ): RowIdentity {
75
+ for (const cell of row) {
76
+ if (cell.node !== undefined) {
77
+ return { kind: 'node', contractHash: cell.node.contractHash };
78
+ }
79
+ }
80
+ for (const cell of row) {
81
+ const arrow = arrowLine(cell);
82
+ if (arrow === undefined) continue;
83
+ const candidates = edgesByHash.get(arrow.line.migrationHash) ?? [];
84
+ const edge = candidates.find((e) => e.dirName === arrow.line.dirName) ?? candidates[0];
85
+ if (edge !== undefined) return { kind: 'migration', edge, lane: arrow.line.lane };
86
+ }
87
+ return { kind: 'none' };
88
+ }
89
+
90
+ /**
91
+ * Return the cell's arrow line if it carries one — a self-loop, or a line whose
92
+ * directions are exactly `{up}` or `{down}` (the migration-direction arrows).
93
+ * Connector/corner/vertical lines are not arrows and yield `undefined`.
94
+ */
95
+ function arrowLine(cell: Cell): CellLine | undefined {
96
+ for (const line of cell.lines) {
97
+ if (line.selfLoop === true) return line;
98
+ if (line.landingArrow === true) continue;
99
+ const dirs = line.directions;
100
+ if (dirs.size !== 1) continue;
101
+ if (dirs.has('up') || dirs.has('down')) return line;
102
+ }
103
+ return undefined;
104
+ }
105
+
106
+ // ---------------------------------------------------------------------------
107
+ // Node path-highlight resolution (focus mode).
108
+ // ---------------------------------------------------------------------------
109
+
110
+ /**
111
+ * Resolve each contract's path-highlight role from the edges incident on it.
112
+ * On-path wins: a contract touched by any on-path edge is on-path. Empty unless
113
+ * focus-mode annotations are present.
114
+ */
115
+ function resolveNodeHighlights(
116
+ rowModel: MigrationGraphRowModel,
117
+ edgeAnnotationsByHash: ReadonlyMap<string, MigrationEdgeAnnotation> | undefined,
118
+ ): Map<string, 'on-path' | 'off-path'> {
119
+ const result = new Map<string, 'on-path' | 'off-path'>();
120
+ if (edgeAnnotationsByHash === undefined) return result;
121
+ for (const edge of rowModel.edges) {
122
+ const highlight = edgeAnnotationsByHash.get(edge.migrationHash)?.pathHighlight;
123
+ if (highlight === undefined) continue;
124
+ for (const hash of [edge.from, edge.to]) {
125
+ if (hash === EMPTY_CONTRACT_HASH) continue;
126
+ if (result.get(hash) !== 'on-path') result.set(hash, highlight);
127
+ }
128
+ }
129
+ return result;
130
+ }
131
+
132
+ // ---------------------------------------------------------------------------
133
+ // Width helpers
134
+ // ---------------------------------------------------------------------------
135
+
136
+ function maxDirNameLength(edges: readonly ClassifiedEdge[]): number {
137
+ let max = 0;
138
+ for (const edge of edges) max = Math.max(max, edge.dirName.length);
139
+ return max;
140
+ }
141
+
142
+ /**
143
+ * The label column for a render: the widest gutter (visible width) across every
144
+ * row, plus the label gap. Labels begin here so they line up regardless of how
145
+ * deep the lane structure runs on any one row. A cross-space override widens it
146
+ * so sibling space sections share one column.
147
+ */
148
+ export function computeLabelColumn(grid: Grid, glyphMode: GlyphMode): number {
149
+ let maxGutter = 0;
150
+ for (const row of grid) {
151
+ const gutter = renderGridRow(row, { colorize: false, glyphMode });
152
+ maxGutter = Math.max(maxGutter, stringWidth(gutter));
153
+ }
154
+ return maxGutter + LABEL_GAP;
155
+ }
156
+
157
+ export function computeMaxDirNameWidth(rowModel: MigrationGraphRowModel): number {
158
+ return maxDirNameLength(rowModel.edges);
159
+ }
160
+
161
+ function padVisible(text: string, targetWidth: number): string {
162
+ const padding = Math.max(0, targetWidth - stringWidth(text));
163
+ return text + ' '.repeat(padding);
164
+ }
165
+
166
+ const ANSI_ESCAPE = '\x1b';
167
+
168
+ function trimTrailingWhitespace(line: string): string {
169
+ const trailingSpaceBeforeReset = new RegExp(`[\\t ]+((?:${ANSI_ESCAPE}\\[[0-9;]*m)+)$`);
170
+ return line.replace(trailingSpaceBeforeReset, '$1').replace(/\s+$/, '');
171
+ }
172
+
173
+ // ---------------------------------------------------------------------------
174
+ // Render
175
+ // ---------------------------------------------------------------------------
176
+
177
+ export function renderMigrationGraphCommand(input: RenderMigrationGraphCommandInput): string {
178
+ const { grid, rowModel } = input;
179
+ const glyphMode = input.glyphMode;
180
+
181
+ // Edges grouped by hash — a list, not a single entry, because two distinct
182
+ // migrations with identical content collide on one hash. classifyRow then
183
+ // disambiguates by the row's own dirName.
184
+ const edgesByHash = new Map<string, ClassifiedEdge[]>();
185
+ for (const edge of rowModel.edges) {
186
+ const bucket = edgesByHash.get(edge.migrationHash);
187
+ if (bucket) bucket.push(edge);
188
+ else edgesByHash.set(edge.migrationHash, [edge]);
189
+ }
190
+
191
+ const labelOpts: MigrationGraphLabelOptions = {
192
+ colorize: input.colorize,
193
+ glyphMode,
194
+ ...ifDefined('refsByHash', input.refsByHash),
195
+ ...ifDefined('edgeAnnotationsByHash', input.edgeAnnotationsByHash),
196
+ ...ifDefined('dbHash', input.dbHash),
197
+ ...ifDefined('contractHash', input.contractHash),
198
+ ...ifDefined('isAppSpace', input.isAppSpace),
199
+ ...ifDefined('activeRefName', input.activeRefName),
200
+ ...ifDefined('styler', input.styler),
201
+ };
202
+
203
+ const nodeHighlights = resolveNodeHighlights(rowModel, input.edgeAnnotationsByHash);
204
+
205
+ const labelColumn = input.globalLabelColumn ?? computeLabelColumn(grid, glyphMode);
206
+ const maxDirNameLen = input.globalMaxDirNameWidth ?? maxDirNameLength(rowModel.edges);
207
+ // The migration-name column is at least wide enough to push the `from → to`
208
+ // hash column to MIN_HASH_DATA_COLUMN, matching the historical layout.
209
+ const dirNameWidth = Math.max(maxDirNameLen + LABEL_GAP, MIN_HASH_DATA_COLUMN - labelColumn);
210
+
211
+ const lines: string[] = [];
212
+ for (const row of grid) {
213
+ const gutter = renderGridRow(row, { colorize: input.colorize, glyphMode });
214
+ const identity = classifyRow(row, edgesByHash);
215
+
216
+ if (identity.kind === 'none') {
217
+ // Connector / pass-through / back-arc rows carry no label. A wholly empty
218
+ // grid row (the blank line between disjoint components) renders as a blank.
219
+ lines.push(trimTrailingWhitespace(gutter));
220
+ continue;
221
+ }
222
+
223
+ const gutterPad = padVisible(gutter, labelColumn);
224
+ if (identity.kind === 'node') {
225
+ const label = formatNodeLabel(
226
+ identity.contractHash,
227
+ labelOpts,
228
+ nodeHighlights.get(identity.contractHash),
229
+ );
230
+ lines.push(trimTrailingWhitespace(label.length === 0 ? gutter : `${gutterPad}${label}`));
231
+ continue;
232
+ }
233
+
234
+ const label = formatMigrationLabel(identity.edge, dirNameWidth, labelOpts, identity.lane);
235
+ lines.push(trimTrailingWhitespace(`${gutterPad}${label}`));
236
+ }
237
+
238
+ return lines.join('\n');
239
+ }