@prisma-next/cli 0.8.0-dev.1 → 0.8.0-dev.10

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 (152) hide show
  1. package/README.md +7 -8
  2. package/dist/{cli-errors-D3_sMh2K.mjs → cli-errors-CF60g2cG.mjs} +40 -2
  3. package/dist/cli-errors-CF60g2cG.mjs.map +1 -0
  4. package/dist/cli.mjs +67 -19
  5. package/dist/cli.mjs.map +1 -1
  6. package/dist/{client-4d26awB-.mjs → client-XkUw4xD0.mjs} +10 -9
  7. package/dist/client-XkUw4xD0.mjs.map +1 -0
  8. package/dist/{command-helpers-BeZHkxV8.mjs → command-helpers-D3vL5yi8.mjs} +29 -6
  9. package/dist/command-helpers-D3vL5yi8.mjs.map +1 -0
  10. package/dist/commands/contract-emit.mjs +1 -1
  11. package/dist/commands/contract-infer.mjs +1 -1
  12. package/dist/commands/db-init.mjs +7 -7
  13. package/dist/commands/db-schema.mjs +5 -5
  14. package/dist/commands/db-sign.d.mts.map +1 -1
  15. package/dist/commands/db-sign.mjs +67 -25
  16. package/dist/commands/db-sign.mjs.map +1 -1
  17. package/dist/commands/db-update.d.mts.map +1 -1
  18. package/dist/commands/db-update.mjs +37 -9
  19. package/dist/commands/db-update.mjs.map +1 -1
  20. package/dist/commands/db-verify.mjs +1 -1
  21. package/dist/commands/migrate.d.mts +28 -0
  22. package/dist/commands/migrate.d.mts.map +1 -0
  23. package/dist/commands/{migration-apply.mjs → migrate.mjs} +54 -36
  24. package/dist/commands/migrate.mjs.map +1 -0
  25. package/dist/commands/migration-check.d.mts +18 -0
  26. package/dist/commands/migration-check.d.mts.map +1 -0
  27. package/dist/commands/migration-check.mjs +284 -0
  28. package/dist/commands/migration-check.mjs.map +1 -0
  29. package/dist/commands/migration-graph.d.mts +16 -0
  30. package/dist/commands/migration-graph.d.mts.map +1 -0
  31. package/dist/commands/migration-graph.mjs +141 -0
  32. package/dist/commands/migration-graph.mjs.map +1 -0
  33. package/dist/commands/migration-list.d.mts +20 -0
  34. package/dist/commands/migration-list.d.mts.map +1 -0
  35. package/dist/commands/migration-list.mjs +107 -0
  36. package/dist/commands/migration-list.mjs.map +1 -0
  37. package/dist/commands/migration-log.d.mts +21 -0
  38. package/dist/commands/migration-log.d.mts.map +1 -0
  39. package/dist/commands/migration-log.mjs +146 -0
  40. package/dist/commands/migration-log.mjs.map +1 -0
  41. package/dist/commands/migration-new.d.mts.map +1 -1
  42. package/dist/commands/migration-new.mjs +21 -20
  43. package/dist/commands/migration-new.mjs.map +1 -1
  44. package/dist/commands/migration-plan.d.mts +2 -2
  45. package/dist/commands/migration-plan.d.mts.map +1 -1
  46. package/dist/commands/migration-plan.mjs +1 -1
  47. package/dist/commands/migration-show.d.mts +1 -1
  48. package/dist/commands/migration-show.d.mts.map +1 -1
  49. package/dist/commands/migration-show.mjs +85 -47
  50. package/dist/commands/migration-show.mjs.map +1 -1
  51. package/dist/commands/migration-status.d.mts +3 -15
  52. package/dist/commands/migration-status.d.mts.map +1 -1
  53. package/dist/commands/migration-status.mjs +732 -1
  54. package/dist/commands/migration-status.mjs.map +1 -0
  55. package/dist/commands/ref.d.mts +34 -0
  56. package/dist/commands/ref.d.mts.map +1 -0
  57. package/dist/commands/{migration-ref.mjs → ref.mjs} +28 -57
  58. package/dist/commands/ref.mjs.map +1 -0
  59. package/dist/{contract-emit-DLc5GYbr.mjs → contract-emit-CgoFk9AU.mjs} +3 -3
  60. package/dist/{contract-emit-DLc5GYbr.mjs.map → contract-emit-CgoFk9AU.mjs.map} +1 -1
  61. package/dist/{contract-emit-BhKR-D9Y.mjs → contract-emit-GpxW5RLe.mjs} +6 -6
  62. package/dist/{contract-emit-BhKR-D9Y.mjs.map → contract-emit-GpxW5RLe.mjs.map} +1 -1
  63. package/dist/{contract-infer-Bnla2kuK.mjs → contract-infer-D8edZOCi.mjs} +5 -5
  64. package/dist/{contract-infer-Bnla2kuK.mjs.map → contract-infer-D8edZOCi.mjs.map} +1 -1
  65. package/dist/{contract-space-aggregate-loader-BrwKK6Q6.mjs → contract-space-aggregate-loader-D68YpuPR.mjs} +3 -3
  66. package/dist/{contract-space-aggregate-loader-BrwKK6Q6.mjs.map → contract-space-aggregate-loader-D68YpuPR.mjs.map} +1 -1
  67. package/dist/{db-verify-DitNxDiE.mjs → db-verify-DtRB9iHJ.mjs} +7 -7
  68. package/dist/{db-verify-DitNxDiE.mjs.map → db-verify-DtRB9iHJ.mjs.map} +1 -1
  69. package/dist/errors-Cw6kyTyV.mjs +56 -0
  70. package/dist/errors-Cw6kyTyV.mjs.map +1 -0
  71. package/dist/exports/control-api.d.mts +1 -1
  72. package/dist/exports/control-api.mjs +2 -2
  73. package/dist/exports/index.mjs +1 -1
  74. package/dist/exports/init-output.mjs +1 -1
  75. package/dist/{framework-components-ChqVUxR-.mjs → framework-components-xFLFpZUO.mjs} +2 -2
  76. package/dist/{framework-components-ChqVUxR-.mjs.map → framework-components-xFLFpZUO.mjs.map} +1 -1
  77. package/dist/{global-flags-Icqpxk23.d.mts → global-flags-DGmw6Kqg.d.mts} +1 -1
  78. package/dist/{global-flags-Icqpxk23.d.mts.map → global-flags-DGmw6Kqg.d.mts.map} +1 -1
  79. package/dist/{migration-status-Do4Ei0i_.mjs → graph-render-eJDcLWny.mjs} +3 -692
  80. package/dist/graph-render-eJDcLWny.mjs.map +1 -0
  81. package/dist/{init-DW94FRsD.mjs → init-Dm0QZPUA.mjs} +133 -61
  82. package/dist/init-Dm0QZPUA.mjs.map +1 -0
  83. package/dist/{inspect-live-schema-CyzAzPzF.mjs → inspect-live-schema-CPPqCips.mjs} +4 -4
  84. package/dist/{inspect-live-schema-CyzAzPzF.mjs.map → inspect-live-schema-CPPqCips.mjs.map} +1 -1
  85. package/dist/migration-cli.mjs +1 -1
  86. package/dist/migration-cli.mjs.map +1 -1
  87. package/dist/{migration-command-scaffold-Jp1rosw8.mjs → migration-command-scaffold-B_ezTTwX.mjs} +4 -4
  88. package/dist/{migration-command-scaffold-Jp1rosw8.mjs.map → migration-command-scaffold-B_ezTTwX.mjs.map} +1 -1
  89. package/dist/{migration-plan-q1pPoOCf.mjs → migration-plan-DWB-NTxH.mjs} +54 -28
  90. package/dist/migration-plan-DWB-NTxH.mjs.map +1 -0
  91. package/dist/migration-types-D2FW63pr.d.mts +15 -0
  92. package/dist/migration-types-D2FW63pr.d.mts.map +1 -0
  93. package/dist/{migrations-CTsyBXCA.mjs → migrations-DyUf5lTt.mjs} +2 -2
  94. package/dist/migrations-DyUf5lTt.mjs.map +1 -0
  95. package/dist/{output-BVj6a971.mjs → output-B60Gw5fu.mjs} +12 -11
  96. package/dist/{output-BVj6a971.mjs.map → output-B60Gw5fu.mjs.map} +1 -1
  97. package/dist/{result-handler-rmPVKIP2.mjs → result-handler-Bm_6dDYg.mjs} +2 -2
  98. package/dist/{result-handler-rmPVKIP2.mjs.map → result-handler-Bm_6dDYg.mjs.map} +1 -1
  99. package/dist/{terminal-ui-C_hFNbAn.mjs → terminal-ui-XtOQsqe9.mjs} +2 -54
  100. package/dist/terminal-ui-XtOQsqe9.mjs.map +1 -0
  101. package/dist/{types-LItU7E4l.d.mts → types-BS_wpjAY.d.mts} +2 -2
  102. package/dist/{types-LItU7E4l.d.mts.map → types-BS_wpjAY.d.mts.map} +1 -1
  103. package/dist/{verify-CiwNWM9N.mjs → verify-D7ypCCe6.mjs} +1 -1
  104. package/dist/{verify-CiwNWM9N.mjs.map → verify-D7ypCCe6.mjs.map} +1 -1
  105. package/package.json +39 -23
  106. package/src/cli.ts +78 -15
  107. package/src/commands/db-sign.ts +102 -32
  108. package/src/commands/db-update.ts +56 -4
  109. package/src/commands/init/agent-skill-install.ts +145 -43
  110. package/src/commands/init/errors.ts +2 -2
  111. package/src/commands/init/exit-codes.ts +2 -2
  112. package/src/commands/init/index.ts +1 -1
  113. package/src/commands/init/init.ts +15 -6
  114. package/src/commands/init/inputs.ts +1 -1
  115. package/src/commands/init/output.ts +22 -17
  116. package/src/commands/{migration-apply.ts → migrate.ts} +54 -70
  117. package/src/commands/migration-check/exit-codes.ts +3 -0
  118. package/src/commands/migration-check.ts +369 -0
  119. package/src/commands/migration-graph.ts +184 -0
  120. package/src/commands/migration-list.ts +155 -0
  121. package/src/commands/migration-log.ts +218 -0
  122. package/src/commands/migration-new.ts +17 -9
  123. package/src/commands/migration-plan.ts +65 -26
  124. package/src/commands/migration-show.ts +132 -60
  125. package/src/commands/migration-status.ts +77 -64
  126. package/src/commands/{migration-ref.ts → ref.ts} +32 -86
  127. package/src/control-api/operations/apply-aggregate.ts +4 -4
  128. package/src/control-api/operations/db-apply-aggregate.ts +3 -2
  129. package/src/control-api/operations/migration-apply.ts +4 -3
  130. package/src/control-api/types.ts +1 -2
  131. package/src/migration-cli.ts +1 -1
  132. package/src/utils/cli-errors.ts +37 -0
  133. package/src/utils/command-helpers.ts +28 -3
  134. package/src/utils/contract-space-aggregate-loader.ts +2 -2
  135. package/src/utils/contract-space-seed-phase.ts +1 -1
  136. package/src/utils/formatters/help.ts +12 -2
  137. package/src/utils/formatters/migrations.ts +2 -2
  138. package/dist/cli-errors-D3_sMh2K.mjs.map +0 -1
  139. package/dist/client-4d26awB-.mjs.map +0 -1
  140. package/dist/command-helpers-BeZHkxV8.mjs.map +0 -1
  141. package/dist/commands/migration-apply.d.mts +0 -51
  142. package/dist/commands/migration-apply.d.mts.map +0 -1
  143. package/dist/commands/migration-apply.mjs.map +0 -1
  144. package/dist/commands/migration-ref.d.mts +0 -45
  145. package/dist/commands/migration-ref.d.mts.map +0 -1
  146. package/dist/commands/migration-ref.mjs.map +0 -1
  147. package/dist/init-DW94FRsD.mjs.map +0 -1
  148. package/dist/migration-plan-q1pPoOCf.mjs.map +0 -1
  149. package/dist/migration-status-Do4Ei0i_.mjs.map +0 -1
  150. package/dist/migrations-CTsyBXCA.mjs.map +0 -1
  151. package/dist/terminal-ui-C_hFNbAn.mjs.map +0 -1
  152. /package/dist/{cli-errors-B9OBbled.d.mts → cli-errors-DdcjVLJV.d.mts} +0 -0
@@ -19,8 +19,9 @@ import {
19
19
  findReachableLeaves,
20
20
  } from '@prisma-next/migration-tools/migration-graph';
21
21
  import type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';
22
+ import { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';
22
23
  import type { RefEntry, Refs } from '@prisma-next/migration-tools/refs';
23
- import { readRefs, resolveRef } from '@prisma-next/migration-tools/refs';
24
+ import { readRefs } from '@prisma-next/migration-tools/refs';
24
25
  import { ifDefined } from '@prisma-next/utils/defined';
25
26
  import { notOk, ok, type Result } from '@prisma-next/utils/result';
26
27
  import { cyan, dim, magenta, yellow } from 'colorette';
@@ -33,6 +34,7 @@ import {
33
34
  errorRuntime,
34
35
  errorUnexpected,
35
36
  mapMigrationToolsError,
37
+ mapRefResolutionError,
36
38
  } from '../utils/cli-errors';
37
39
  import {
38
40
  addGlobalOptions,
@@ -43,6 +45,7 @@ import {
43
45
  resolveMigrationPaths,
44
46
  setCommandDescriptions,
45
47
  setCommandExamples,
48
+ setCommandSeeAlso,
46
49
  toPathDecisionResult,
47
50
  toStructuralEdge,
48
51
  } from '../utils/command-helpers';
@@ -70,10 +73,8 @@ import { TerminalUI } from '../utils/terminal-ui';
70
73
  interface MigrationStatusOptions extends CommonCommandOptions {
71
74
  readonly db?: string;
72
75
  readonly config?: string;
73
- readonly ref?: string;
74
- readonly graph?: boolean;
75
- readonly limit?: string;
76
- readonly all?: boolean;
76
+ readonly to?: string;
77
+ readonly from?: string;
77
78
  }
78
79
 
79
80
  export interface MigrationStatusEntry {
@@ -94,7 +95,7 @@ export interface MigrationStatusEntry {
94
95
  *
95
96
  * - `headHash`: the on-disk head ref's hash (where the space is going).
96
97
  * - `markerHash`: the live marker hash for the space, or null if no
97
- * marker has been written yet (greenfield, or pre-`migration apply`).
98
+ * marker has been written yet (greenfield, or pre-`migrate`).
98
99
  * - `pendingCount`: number of migration edges between marker and head.
99
100
  * Computed via {@link graphWalkStrategy}; 0 means the space is
100
101
  * already at head.
@@ -420,23 +421,6 @@ function resolveDisplayChain(
420
421
  return toTarget;
421
422
  }
422
423
 
423
- const DEFAULT_LIMIT = 10;
424
-
425
- function determineLimit(opts: MigrationStatusOptions) {
426
- if (opts.all) {
427
- // No limit
428
- return;
429
- }
430
- if (!opts.limit) {
431
- return DEFAULT_LIMIT;
432
- }
433
- const parsed = Number.parseInt(opts.limit, 10);
434
- if (Number.isNaN(parsed)) {
435
- return DEFAULT_LIMIT;
436
- }
437
- return parsed;
438
- }
439
-
440
424
  /**
441
425
  * Build the aggregate enumeration of contract spaces for the status
442
426
  * output. Loads the aggregate from disk (lossy on failure — extension
@@ -581,11 +565,32 @@ async function executeMigrationStatusCommand(
581
565
  throw error;
582
566
  }
583
567
 
584
- if (options.ref) {
585
- activeRefName = options.ref;
568
+ let fromOverrideHash: string | undefined;
569
+
570
+ if (options.to || options.from) {
586
571
  try {
587
- activeRefEntry = resolveRef(allRefs, activeRefName);
588
- activeRefHash = activeRefEntry.hash;
572
+ const { graph: earlyGraph } = await loadMigrationPackages(appMigrationsDir);
573
+
574
+ if (options.to) {
575
+ const refResult = parseContractRef(options.to, { graph: earlyGraph, refs: allRefs });
576
+ if (!refResult.ok) {
577
+ return notOk(mapRefResolutionError(refResult.failure));
578
+ }
579
+ activeRefHash = refResult.value.hash;
580
+ if (refResult.value.provenance.kind === 'ref') {
581
+ const resolvedRefName = refResult.value.provenance.refName;
582
+ activeRefName = resolvedRefName;
583
+ activeRefEntry = allRefs[resolvedRefName];
584
+ }
585
+ }
586
+
587
+ if (options.from) {
588
+ const fromResult = parseContractRef(options.from, { graph: earlyGraph, refs: allRefs });
589
+ if (!fromResult.ok) {
590
+ return notOk(mapRefResolutionError(fromResult.failure));
591
+ }
592
+ fromOverrideHash = fromResult.value.hash;
593
+ }
589
594
  } catch (error) {
590
595
  if (MigrationToolsError.is(error)) {
591
596
  return notOk(mapMigrationToolsError(error));
@@ -613,6 +618,9 @@ async function executeMigrationStatusCommand(
613
618
  if (activeRefName) {
614
619
  details.push({ label: 'ref', value: activeRefName });
615
620
  }
621
+ if (options.from) {
622
+ details.push({ label: 'from', value: options.from });
623
+ }
616
624
  if (activeRefEntry && activeRefEntry.invariants.length > 0) {
617
625
  details.push({
618
626
  label: 'required',
@@ -696,8 +704,8 @@ async function executeMigrationStatusCommand(
696
704
  severity: 'warn',
697
705
  message: 'There are multiple valid migration paths — you must select a target',
698
706
  hints: [
699
- "Use '--ref <name>' to select a target",
700
- "Or 'prisma-next migration ref set <name> <hash>' to create one",
707
+ "Use '--to <contract>' to select a target",
708
+ "Or 'prisma-next ref set <name> <hash>' to create one",
701
709
  ],
702
710
  });
703
711
  }
@@ -751,6 +759,12 @@ async function executeMigrationStatusCommand(
751
759
  }
752
760
  }
753
761
 
762
+ if (fromOverrideHash !== undefined) {
763
+ markerHash = fromOverrideHash;
764
+ mode = 'offline';
765
+ allMarkers = null;
766
+ }
767
+
754
768
  // Build the aggregate enumeration of contract spaces. Lossy on
755
769
  // failure (extensions are simply omitted) so the existing
756
770
  // single-space app pipeline below still runs even if extensions
@@ -863,7 +877,7 @@ async function executeMigrationStatusCommand(
863
877
  code: 'MIGRATION.NO_MARKER',
864
878
  severity: 'warn',
865
879
  message: 'Database has not been initialized — no migration marker found',
866
- hints: ["Run 'prisma-next migration apply' to apply pending migrations"],
880
+ hints: ["Run 'prisma-next migrate' to apply pending migrations"],
867
881
  });
868
882
  }
869
883
 
@@ -923,7 +937,7 @@ async function executeMigrationStatusCommand(
923
937
  let missingInvariants: readonly string[] | undefined;
924
938
  let effectiveRequired = new Set<string>();
925
939
  if (mode === 'online') {
926
- // Mirrors `migration-apply.ts`: compute `effectiveRequired = required −
940
+ // Mirrors `migrate.ts`: compute `effectiveRequired = required −
927
941
  // marker.invariants` directly, then derive the display fields from it.
928
942
  // `appliedInvariants` is the intersection (`required ∩ marker`), which
929
943
  // is what JSON consumers see for the active ref; the unfiltered set
@@ -945,17 +959,17 @@ async function executeMigrationStatusCommand(
945
959
  if (mode === 'online') {
946
960
  if (markerHash !== undefined && !graph.nodes.has(markerHash) && markerHash === contractHash) {
947
961
  summary = `${bundles.length} migration(s) on disk`;
948
- } else if (activeRefHash && markerHash !== undefined) {
949
- const distance = summarizeRefDistance(graph, markerHash, activeRefHash, activeRefName!);
962
+ } else if (activeRefHash && activeRefName && markerHash !== undefined) {
963
+ const distance = summarizeRefDistance(graph, markerHash, activeRefHash, activeRefName);
950
964
  summary = hasInvariantWork ? `${distance} — missing invariant(s): ${missingList}` : distance;
951
965
  } else if (pendingCount === 0 && !hasInvariantWork) {
952
966
  summary = `Database is up to date (${appliedCount} migration${appliedCount !== 1 ? 's' : ''} applied)`;
953
967
  } else if (pendingCount === 0 && hasInvariantWork) {
954
- summary = `Missing invariant(s): ${missingList} — run 'prisma-next migration apply --ref ${activeRefName ?? '<ref>'}' to apply`;
968
+ summary = `Missing invariant(s): ${missingList} — run 'prisma-next migrate --to ${activeRefName ?? '<ref>'}' to apply`;
955
969
  } else if (markerHash === undefined) {
956
970
  summary = `${pendingCount} pending migration(s) — database has no marker`;
957
971
  } else {
958
- summary = `${pendingCount} pending migration(s) — run 'prisma-next migration apply' to apply`;
972
+ summary = `${pendingCount} pending migration(s) — run 'prisma-next migrate' to apply`;
959
973
  }
960
974
  } else {
961
975
  summary = `${entries.length} migration(s) on disk`;
@@ -997,8 +1011,7 @@ async function executeMigrationStatusCommand(
997
1011
  diagnostics.push({
998
1012
  code: 'MIGRATION.MARKER_NOT_IN_HISTORY',
999
1013
  severity: 'warn',
1000
- message:
1001
- 'Database matches the current contract but was updated directly (not via migration apply)',
1014
+ message: 'Database matches the current contract but was updated directly (not via migrate)',
1002
1015
  hints: ["Run 'prisma-next migration plan' to plan a migration to your current contract"],
1003
1016
  });
1004
1017
  } else if (pendingCount > 0) {
@@ -1006,7 +1019,7 @@ async function executeMigrationStatusCommand(
1006
1019
  code: 'MIGRATION.DATABASE_BEHIND',
1007
1020
  severity: 'info',
1008
1021
  message: `${pendingCount} migration(s) pending`,
1009
- hints: ["Run 'prisma-next migration apply' to apply pending migrations"],
1022
+ hints: ["Run 'prisma-next migrate' to apply pending migrations"],
1010
1023
  });
1011
1024
  } else if (hasInvariantWork) {
1012
1025
  diagnostics.push({
@@ -1014,7 +1027,7 @@ async function executeMigrationStatusCommand(
1014
1027
  severity: 'info',
1015
1028
  message: `Missing required invariant(s): ${missingList}`,
1016
1029
  hints: [
1017
- `Run 'prisma-next migration apply --ref ${activeRefName ?? '<ref>'}' to apply a path that covers the required invariants`,
1030
+ `Run 'prisma-next migrate --to ${activeRefName ?? '<ref>'}' to apply a path that covers the required invariants`,
1018
1031
  ],
1019
1032
  });
1020
1033
  } else if (!routingUnreachable) {
@@ -1056,37 +1069,41 @@ export function createMigrationStatusCommand(): Command {
1056
1069
  const command = new Command('status');
1057
1070
  setCommandDescriptions(
1058
1071
  command,
1059
- 'Show migration history and applied status',
1060
- 'Displays the migration history in order. When a database connection\n' +
1061
- 'is available, shows which migrations are applied and which are pending.\n' +
1062
- 'Without a database connection, shows the history from disk only.',
1072
+ 'Show migration path and pending status',
1073
+ 'Shows which migrations are pending between the database marker and\n' +
1074
+ 'the target contract. Requires a database connection for live status.\n' +
1075
+ 'Use `migration graph` for topology, `migration log` for history,\n' +
1076
+ 'and `migration list` for on-disk enumeration.',
1063
1077
  );
1064
1078
  setCommandExamples(command, [
1065
- 'prisma-next migration status',
1066
1079
  'prisma-next migration status --db $DATABASE_URL',
1080
+ 'prisma-next migration status --to production --db $DATABASE_URL',
1081
+ ]);
1082
+ setCommandSeeAlso(command, [
1083
+ { verb: 'migration log', oneLiner: 'Show executed migration history' },
1084
+ { verb: 'migration list', oneLiner: 'List on-disk migrations' },
1085
+ { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },
1086
+ { verb: 'migration show', oneLiner: 'Display migration package contents' },
1067
1087
  ]);
1068
1088
  addGlobalOptions(command)
1069
1089
  .option('--db <url>', 'Database connection string')
1070
1090
  .option('--config <path>', 'Path to prisma-next.config.ts')
1071
- .option('--ref <name>', 'Target ref name from migrations/refs/')
1072
- .option('--graph', 'Show the full migration graph with all branches')
1073
- .option('--limit <n>', 'Maximum number of migrations to display (default: 10)')
1074
- .option('--all', 'Show full history (disables truncation)')
1091
+ .option(
1092
+ '--to <contract>',
1093
+ 'Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',
1094
+ )
1095
+ .option(
1096
+ '--from <contract>',
1097
+ 'Origin contract reference; same grammar as --to. Supplying --from switches to offline path computation.',
1098
+ )
1075
1099
  .action(async (options: MigrationStatusOptions) => {
1076
1100
  const flags = parseGlobalFlags(options);
1077
-
1078
1101
  const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
1079
1102
 
1080
1103
  const result = await executeMigrationStatusCommand(options, flags, ui);
1081
1104
 
1082
1105
  const exitCode = handleResult(result, flags, ui, (statusResult) => {
1083
1106
  if (flags.json) {
1084
- // Strip non-JSON-shape fields before emitting. These belong to
1085
- // the in-memory result so the human renderer can avoid
1086
- // recomputing them, but they would either bloat the wire format
1087
- // (graph, bundles, edgeStatuses) or expose internals
1088
- // (activeRefHash, activeRefName, diverged) that consumers should
1089
- // read off `pathDecision` / `refs` instead.
1090
1107
  const {
1091
1108
  graph: _graph,
1092
1109
  bundles: _bundles,
@@ -1101,7 +1118,6 @@ export function createMigrationStatusCommand(): Command {
1101
1118
  const colorize = flags.color !== false;
1102
1119
 
1103
1120
  if (statusResult.graph) {
1104
- const limit = determineLimit(options);
1105
1121
  const renderInput = migrationGraphToRenderInput({
1106
1122
  graph: statusResult.graph,
1107
1123
  mode: statusResult.mode,
@@ -1113,16 +1129,13 @@ export function createMigrationStatusCommand(): Command {
1113
1129
  edgeStatuses: statusResult.edgeStatuses,
1114
1130
  });
1115
1131
 
1116
- const graphToRender =
1117
- options.graph || statusResult.diverged
1118
- ? renderInput.graph
1119
- : extractRelevantSubgraph(renderInput.graph, renderInput.relevantPaths);
1120
- const dagreOptions =
1121
- !options.graph && isLinearGraph(graphToRender) ? { ranksep: 1 } : undefined;
1132
+ const graphToRender = statusResult.diverged
1133
+ ? renderInput.graph
1134
+ : extractRelevantSubgraph(renderInput.graph, renderInput.relevantPaths);
1135
+ const dagreOptions = isLinearGraph(graphToRender) ? { ranksep: 1 } : undefined;
1122
1136
  const renderOptions = {
1123
1137
  ...renderInput.options,
1124
1138
  colorize,
1125
- ...ifDefined('limit', limit),
1126
1139
  ...ifDefined('dagreOptions', dagreOptions),
1127
1140
  };
1128
1141
  const graphOutput = graphRenderer.render(graphToRender, renderOptions);
@@ -1209,7 +1222,7 @@ export function formatStatusSummary(result: MigrationStatusResult, colorize: boo
1209
1222
  if (total > 0) {
1210
1223
  lines.push('');
1211
1224
  lines.push(
1212
- `${c(yellow, '⧗')} ${total} pending migration(s) across ${result.spaces.length} space(s) — run 'prisma-next migration apply' to apply`,
1225
+ `${c(yellow, '⧗')} ${total} pending migration(s) across ${result.spaces.length} space(s) — run 'prisma-next migrate' to apply`,
1213
1226
  );
1214
1227
  }
1215
1228
  }
@@ -1,8 +1,8 @@
1
1
  import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
2
+ import { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';
2
3
  import type { RefEntry } from '@prisma-next/migration-tools/refs';
3
4
  import {
4
5
  deleteRef,
5
- readRef,
6
6
  readRefs,
7
7
  validateRefName,
8
8
  validateRefValue,
@@ -16,9 +16,11 @@ import {
16
16
  errorRuntime,
17
17
  errorUnexpected,
18
18
  mapMigrationToolsError,
19
+ mapRefResolutionError,
19
20
  } from '../utils/cli-errors';
20
21
  import {
21
22
  addGlobalOptions,
23
+ loadMigrationPackages,
22
24
  resolveMigrationPaths,
23
25
  setCommandDescriptions,
24
26
  } from '../utils/command-helpers';
@@ -34,13 +36,6 @@ interface RefSetResult {
34
36
  readonly invariants: readonly string[];
35
37
  }
36
38
 
37
- interface RefGetResult {
38
- readonly ok: true;
39
- readonly ref: string;
40
- readonly hash: string;
41
- readonly invariants: readonly string[];
42
- }
43
-
44
39
  interface RefDeleteResult {
45
40
  readonly ok: true;
46
41
  readonly ref: string;
@@ -66,53 +61,42 @@ function cliErrorInvalidRefName(name: string): CliStructuredError {
66
61
  });
67
62
  }
68
63
 
69
- function cliErrorInvalidRefValue(hash: string): CliStructuredError {
70
- return errorRuntime(`Invalid contract hash "${hash}"`, {
71
- why: `"${hash}" is not a valid contract hash`,
72
- fix: 'Contract hashes must match the format "sha256:<64 hex chars>". Copy the hash from `prisma-next contract emit` or `migration status --json`.',
73
- });
74
- }
75
-
76
- async function executeRefSetCommand(
64
+ export async function executeRefSetCommand(
77
65
  name: string,
78
- hash: string,
66
+ contractInput: string,
79
67
  options: { config?: string },
80
68
  ): Promise<Result<RefSetResult, CliStructuredError>> {
81
69
  if (!validateRefName(name)) {
82
70
  return notOk(cliErrorInvalidRefName(name));
83
71
  }
84
- if (!validateRefValue(hash)) {
85
- return notOk(cliErrorInvalidRefValue(hash));
86
- }
87
72
 
88
73
  try {
89
74
  const config = await loadConfig(options.config);
90
- const { refsDir } = resolveMigrationPaths(options.config, config);
91
- const entry: RefEntry = { hash, invariants: [] };
75
+ const { appMigrationsDir, refsDir } = resolveMigrationPaths(options.config, config);
76
+
77
+ let resolvedHash: string;
78
+ if (validateRefValue(contractInput)) {
79
+ resolvedHash = contractInput;
80
+ } else {
81
+ const { graph } = await loadMigrationPackages(appMigrationsDir);
82
+ const refs = await readRefs(refsDir);
83
+ const refResult = parseContractRef(contractInput, { graph, refs });
84
+ if (!refResult.ok) {
85
+ return notOk(mapRefResolutionError(refResult.failure));
86
+ }
87
+ resolvedHash = refResult.value.hash;
88
+ }
89
+
90
+ const entry: RefEntry = { hash: resolvedHash, invariants: [] };
92
91
  await writeRef(refsDir, name, entry);
93
- return ok({ ok: true as const, ref: name, hash, invariants: [] });
94
- } catch (error) {
95
- if (error instanceof CliStructuredError) return notOk(error);
96
- return notOk(mapError(error));
97
- }
98
- }
99
-
100
- async function executeRefGetCommand(
101
- name: string,
102
- options: { config?: string },
103
- ): Promise<Result<RefGetResult, CliStructuredError>> {
104
- try {
105
- const config = await loadConfig(options.config);
106
- const { refsDir } = resolveMigrationPaths(options.config, config);
107
- const entry = await readRef(refsDir, name);
108
- return ok({ ok: true as const, ref: name, hash: entry.hash, invariants: entry.invariants });
92
+ return ok({ ok: true as const, ref: name, hash: resolvedHash, invariants: [] });
109
93
  } catch (error) {
110
94
  if (error instanceof CliStructuredError) return notOk(error);
111
95
  return notOk(mapError(error));
112
96
  }
113
97
  }
114
98
 
115
- async function executeRefDeleteCommand(
99
+ export async function executeRefDeleteCommand(
116
100
  name: string,
117
101
  options: { config?: string },
118
102
  ): Promise<Result<RefDeleteResult, CliStructuredError>> {
@@ -127,7 +111,7 @@ async function executeRefDeleteCommand(
127
111
  }
128
112
  }
129
113
 
130
- async function executeRefListCommand(options: {
114
+ export async function executeRefListCommand(options: {
131
115
  config?: string;
132
116
  }): Promise<Result<RefListResult, CliStructuredError>> {
133
117
  try {
@@ -145,12 +129,15 @@ function createRefSetCommand(): Command {
145
129
  const command = new Command('set');
146
130
  setCommandDescriptions(
147
131
  command,
148
- 'Set a ref to a contract hash',
149
- 'Sets a named ref to point to a contract hash in migrations/refs/.',
132
+ 'Set a ref to a contract reference',
133
+ 'Sets a named ref to point to a resolved contract reference (hash, alias, or path) in migrations/refs/.',
150
134
  );
151
135
  addGlobalOptions(command)
152
136
  .argument('<name>', 'Ref name (e.g., staging, production)')
153
- .argument('<hash>', 'Contract hash to point to')
137
+ .argument(
138
+ '<contract>',
139
+ 'Contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',
140
+ )
154
141
  .option('--config <path>', 'Path to prisma-next.config.ts')
155
142
  .action(
156
143
  async (
@@ -174,37 +161,6 @@ function createRefSetCommand(): Command {
174
161
  return command;
175
162
  }
176
163
 
177
- function createRefGetCommand(): Command {
178
- const command = new Command('get');
179
- setCommandDescriptions(
180
- command,
181
- 'Get the hash for a ref',
182
- 'Reads a named ref from migrations/refs/ and prints its contract hash.',
183
- );
184
- addGlobalOptions(command)
185
- .argument('<name>', 'Ref name to look up')
186
- .option('--config <path>', 'Path to prisma-next.config.ts')
187
- .action(
188
- async (
189
- name: string,
190
- options: { config?: string; json?: string | boolean; quiet?: boolean },
191
- ) => {
192
- const flags = parseGlobalFlags(options);
193
- const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
194
- const result = await executeRefGetCommand(name, options);
195
- const exitCode = handleResult(result, flags, ui, (value) => {
196
- if (flags.json) {
197
- ui.output(JSON.stringify(value));
198
- } else {
199
- ui.output(value.hash);
200
- }
201
- });
202
- process.exit(exitCode);
203
- },
204
- );
205
- return command;
206
- }
207
-
208
164
  function createRefDeleteCommand(): Command {
209
165
  const command = new Command('delete');
210
166
  setCommandDescriptions(command, 'Delete a ref', 'Removes a named ref from migrations/refs/.');
@@ -262,20 +218,11 @@ function createRefListCommand(): Command {
262
218
  return command;
263
219
  }
264
220
 
265
- export {
266
- cliErrorInvalidRefName,
267
- cliErrorInvalidRefValue,
268
- executeRefDeleteCommand,
269
- executeRefGetCommand,
270
- executeRefListCommand,
271
- executeRefSetCommand,
272
- };
273
-
274
- export function createMigrationRefCommand(): Command {
221
+ export function createRefCommand(): Command {
275
222
  const command = new Command('ref');
276
223
  setCommandDescriptions(
277
224
  command,
278
- 'Manage migration refs',
225
+ 'Manage contract refs',
279
226
  'Manage named refs in migrations/refs/. Refs map logical environment\n' +
280
227
  'names (e.g., staging, production) to contract hashes.',
281
228
  );
@@ -284,7 +231,6 @@ export function createMigrationRefCommand(): Command {
284
231
  subcommandDescription: () => '',
285
232
  });
286
233
  command.addCommand(createRefSetCommand());
287
- command.addCommand(createRefGetCommand());
288
234
  command.addCommand(createRefDeleteCommand());
289
235
  command.addCommand(createRefListCommand());
290
236
  return command;
@@ -49,7 +49,7 @@ export interface ApplyAggregateInputs<TFamilyId extends string, TTargetId extend
49
49
  * Per-space plans, keyed by `spaceId`. Produced by either the full
50
50
  * {@link planAggregate} pipeline (`db init` / `db update` — synth
51
51
  * for the app, graph-walk for extensions) or by direct
52
- * {@link graphWalkStrategy} calls (`migration apply` — graph-walk
52
+ * {@link graphWalkStrategy} calls (`migrate` — graph-walk
53
53
  * for every member). Either way, the runner consumes the same shape.
54
54
  */
55
55
  readonly perSpacePlans: ReadonlyMap<string, AggregatePerSpacePlan>;
@@ -100,7 +100,7 @@ export type ApplyAggregateResult = Result<ApplyAggregateValue, AggregateApplyRun
100
100
 
101
101
  /**
102
102
  * Runner-driving tail shared by every aggregate apply caller — `db init`,
103
- * `db update`, and `migration apply`. Consumes already-resolved per-space
103
+ * `db update`, and `migrate`. Consumes already-resolved per-space
104
104
  * plans (the planner-vs-replay distinction is owned by the caller) and
105
105
  * dispatches them to the multi-space runner in canonical order.
106
106
  *
@@ -264,7 +264,7 @@ export function collectOrdered(
264
264
  /**
265
265
  * Action-appropriate label for the `spanStart` event the apply
266
266
  * primitive emits. `applyAggregate` is shared by `db init`, `db update`,
267
- * and `migration apply`; the span label tracks the user-visible action
267
+ * and `migrate`; the span label tracks the user-visible action
268
268
  * so structured-progress output reads naturally for each surface.
269
269
  */
270
270
  export function progressLabelForAction(action: AggregateApplyAction): string {
@@ -285,6 +285,6 @@ function labelForAction(action: AggregateApplyAction): string {
285
285
  case 'dbUpdate':
286
286
  return 'db update';
287
287
  case 'migrationApply':
288
- return 'migration apply';
288
+ return 'migrate';
289
289
  }
290
290
  }
@@ -207,9 +207,10 @@ export async function executeAggregateApply<TFamilyId extends string, TTargetId
207
207
 
208
208
  // 5. Apply mode: hand off to the shared `applyAggregate` primitive.
209
209
  // The runner-driving tail is identical for `db init` / `db update` /
210
- // `migration apply` — only how each caller produces `perSpacePlans`
210
+ // `migrate` — only how each caller produces `perSpacePlans`
211
211
  // differs (synth + graph-walk via planAggregate here; graph-walk
212
- // only for migration apply). See M6 sub-spec § Required changes 1.
212
+ // only for migrate). Each caller produces perSpacePlans differently;
213
+ // this helper handles the shared apply tail.
213
214
  const applied = await applyAggregate({
214
215
  aggregate,
215
216
  perSpacePlans: planResult.value.perSpace,
@@ -34,7 +34,7 @@ import type {
34
34
  import { applyAggregate, buildPerSpaceBreakdown } from './apply-aggregate';
35
35
 
36
36
  /**
37
- * Inputs for the aggregate-walking `migration apply` control-api
37
+ * Inputs for the aggregate-walking `migrate` control-api
38
38
  * operation.
39
39
  *
40
40
  * The CLI command resolves the descriptor surface (config, refs,
@@ -110,7 +110,8 @@ export interface ExecuteMigrationApplyOptions<TFamilyId extends string, TTargetI
110
110
  * shared with `db init` / `db update`). Marker advancement is
111
111
  * inside the per-space transaction.
112
112
  *
113
- * Sub-spec § `migration apply` semantics + § Required changes 1.
113
+ * Encodes the replay-only contract: every contract space must have an
114
+ * authored migration graph on disk before this operation can advance it.
114
115
  */
115
116
  export async function executeMigrationApply<TFamilyId extends string, TTargetId extends string>(
116
117
  options: ExecuteMigrationApplyOptions<TFamilyId, TTargetId>,
@@ -461,7 +462,7 @@ function buildNeverPlannedFailure(spaceId: string, targetHash: string): Migratio
461
462
  return {
462
463
  code: 'MIGRATION_PATH_NOT_FOUND',
463
464
  summary: `No on-disk migrations for contract space "${spaceId}"`,
464
- why: `migration apply is replay-only: every contract space must have an authored migration graph on disk. Space "${spaceId}" has no migrations under \`migrations/${spaceId}/\` but its head ref targets "${targetHash}". Run \`prisma-next migration plan\` first to materialise the path.`,
465
+ why: `migrate is replay-only: every contract space must have an authored migration graph on disk. Space "${spaceId}" has no migrations under \`migrations/${spaceId}/\` but its head ref targets "${targetHash}". Run \`prisma-next migration plan\` first to materialise the path.`,
465
466
  meta: { spaceId, target: targetHash, kind: 'neverPlanned' },
466
467
  };
467
468
  }
@@ -2,7 +2,7 @@ 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 { ContractMarkerRecord } from '@prisma-next/contract/types';
6
6
  import type {
7
7
  ControlAdapterDescriptor,
8
8
  ControlDriverDescriptor,
@@ -590,7 +590,6 @@ export interface MigrationApplyStep {
590
590
  readonly dirName: string;
591
591
  readonly from: string | null;
592
592
  readonly to: string;
593
- readonly toContract: Contract;
594
593
  readonly operations: readonly MigrationPlanOperation[];
595
594
  /**
596
595
  * Sorted, deduplicated invariant ids from `migration.json.providedInvariants`.
@@ -3,7 +3,7 @@
3
3
  * `node migration.ts` directly.
4
4
  *
5
5
  * Naming: this is *not* a "migration runner" in the apply-time sense. The
6
- * apply-time runner is the thing `prisma-next migration apply` uses to
6
+ * apply-time runner is the thing `prisma-next migrate` uses to
7
7
  * execute migration JSON ops against a database. `MigrationCLI` is the
8
8
  * tiny CLI surface owned by an authored `migration.ts` file: parse the
9
9
  * file's argv, load the project's `prisma-next.config.ts`, assemble a
@@ -25,6 +25,7 @@ import {
25
25
  } from '@prisma-next/errors/control';
26
26
  import { errorRuntime } from '@prisma-next/errors/execution';
27
27
  import type { MigrationToolsError } from '@prisma-next/migration-tools/errors';
28
+ import type { RefResolutionError } from '@prisma-next/migration-tools/ref-resolution';
28
29
 
29
30
  export {
30
31
  ERROR_CODE_DESTRUCTIVE_CHANGES,
@@ -85,3 +86,39 @@ export function mapMigrationToolsError(error: MigrationToolsError): CliStructure
85
86
  meta: { code: error.code, ...(error.details ?? {}) },
86
87
  });
87
88
  }
89
+
90
+ /**
91
+ * Maps a `RefResolutionError` from the contract/migration reference
92
+ * resolver into a CLI structured error envelope.
93
+ */
94
+ export function mapRefResolutionError(error: RefResolutionError): CliStructuredError {
95
+ switch (error.kind) {
96
+ case 'not-found':
97
+ return errorRuntime(`Not a known ${error.grammar} reference: "${error.input}"`, {
98
+ why: `No ${error.grammar} matching "${error.input}" exists in the migration graph or refs index.`,
99
+ fix:
100
+ error.grammar === 'contract'
101
+ ? 'Provide a valid contract hash, ref name, or migration directory name.'
102
+ : 'Provide a valid migration directory name or migration hash.',
103
+ meta: { input: error.input, grammar: error.grammar },
104
+ });
105
+ case 'ambiguous':
106
+ return errorRuntime(`Ambiguous ${error.grammar} reference: "${error.input}"`, {
107
+ why: `"${error.input}" matches multiple ${error.grammar}s: ${error.candidates.join(', ')}`,
108
+ fix: 'Provide a longer prefix or use the full hash to disambiguate.',
109
+ meta: { input: error.input, candidates: error.candidates, grammar: error.grammar },
110
+ });
111
+ case 'wrong-grammar':
112
+ return errorRuntime(error.message, {
113
+ why: error.message,
114
+ fix: error.fix,
115
+ meta: { input: error.input, expectedGrammar: error.expectedGrammar },
116
+ });
117
+ case 'invalid-format':
118
+ return errorRuntime(`Invalid reference format: "${error.input}"`, {
119
+ why: error.reason,
120
+ fix: 'Provide a valid contract hash, ref name, or migration directory name.',
121
+ meta: { input: error.input },
122
+ });
123
+ }
124
+ }