@prisma-next/cli 0.3.0-pr.99.6 → 0.4.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 (257) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +381 -128
  3. package/dist/agent-skill-mongo.md +106 -0
  4. package/dist/agent-skill-postgres.md +106 -0
  5. package/dist/cli-errors-BDCYR5ap.mjs +4 -0
  6. package/dist/cli-errors-DStABy9d.d.mts +3 -0
  7. package/dist/cli.d.mts +1 -0
  8. package/dist/cli.js +1 -2910
  9. package/dist/cli.mjs +254 -0
  10. package/dist/cli.mjs.map +1 -0
  11. package/dist/client-DiUkJAeN.mjs +987 -0
  12. package/dist/client-DiUkJAeN.mjs.map +1 -0
  13. package/dist/commands/contract-emit.d.mts +7 -0
  14. package/dist/commands/contract-emit.d.mts.map +1 -0
  15. package/dist/commands/contract-emit.mjs +4 -0
  16. package/dist/commands/contract-infer.d.mts +7 -0
  17. package/dist/commands/contract-infer.d.mts.map +1 -0
  18. package/dist/commands/contract-infer.mjs +4 -0
  19. package/dist/commands/db-init.d.mts +7 -0
  20. package/dist/commands/db-init.d.mts.map +1 -0
  21. package/dist/commands/db-init.mjs +125 -0
  22. package/dist/commands/db-init.mjs.map +1 -0
  23. package/dist/commands/db-schema.d.mts +7 -0
  24. package/dist/commands/db-schema.d.mts.map +1 -0
  25. package/dist/commands/db-schema.mjs +53 -0
  26. package/dist/commands/db-schema.mjs.map +1 -0
  27. package/dist/commands/db-sign.d.mts +7 -0
  28. package/dist/commands/db-sign.d.mts.map +1 -0
  29. package/dist/commands/db-sign.mjs +136 -0
  30. package/dist/commands/db-sign.mjs.map +1 -0
  31. package/dist/commands/db-update.d.mts +7 -0
  32. package/dist/commands/db-update.d.mts.map +1 -0
  33. package/dist/commands/db-update.mjs +122 -0
  34. package/dist/commands/db-update.mjs.map +1 -0
  35. package/dist/commands/db-verify.d.mts +7 -0
  36. package/dist/commands/db-verify.d.mts.map +1 -0
  37. package/dist/commands/db-verify.mjs +322 -0
  38. package/dist/commands/db-verify.mjs.map +1 -0
  39. package/dist/commands/migration-apply.d.mts +36 -0
  40. package/dist/commands/migration-apply.d.mts.map +1 -0
  41. package/dist/commands/migration-apply.mjs +244 -0
  42. package/dist/commands/migration-apply.mjs.map +1 -0
  43. package/dist/commands/migration-new.d.mts +8 -0
  44. package/dist/commands/migration-new.d.mts.map +1 -0
  45. package/dist/commands/migration-new.mjs +152 -0
  46. package/dist/commands/migration-new.mjs.map +1 -0
  47. package/dist/commands/migration-plan.d.mts +47 -0
  48. package/dist/commands/migration-plan.d.mts.map +1 -0
  49. package/dist/commands/migration-plan.mjs +313 -0
  50. package/dist/commands/migration-plan.mjs.map +1 -0
  51. package/dist/commands/migration-ref.d.mts +43 -0
  52. package/dist/commands/migration-ref.d.mts.map +1 -0
  53. package/dist/commands/migration-ref.mjs +195 -0
  54. package/dist/commands/migration-ref.mjs.map +1 -0
  55. package/dist/commands/migration-show.d.mts +28 -0
  56. package/dist/commands/migration-show.d.mts.map +1 -0
  57. package/dist/commands/migration-show.mjs +140 -0
  58. package/dist/commands/migration-show.mjs.map +1 -0
  59. package/dist/commands/migration-status.d.mts +86 -0
  60. package/dist/commands/migration-status.d.mts.map +1 -0
  61. package/dist/commands/migration-status.mjs +4 -0
  62. package/dist/commands/migration-verify.d.mts +16 -0
  63. package/dist/commands/migration-verify.d.mts.map +1 -0
  64. package/dist/commands/migration-verify.mjs +110 -0
  65. package/dist/commands/migration-verify.mjs.map +1 -0
  66. package/dist/config-loader-C4VXKl8f.mjs +43 -0
  67. package/dist/config-loader-C4VXKl8f.mjs.map +1 -0
  68. package/dist/{config-loader.d.ts → config-loader.d.mts} +8 -3
  69. package/dist/config-loader.d.mts.map +1 -0
  70. package/dist/config-loader.mjs +3 -0
  71. package/dist/contract-emit-D2wDXfyo.mjs +191 -0
  72. package/dist/contract-emit-D2wDXfyo.mjs.map +1 -0
  73. package/dist/contract-emit-D9WOShFz.mjs +4 -0
  74. package/dist/contract-emit-Zm_sd1wQ.mjs +112 -0
  75. package/dist/contract-emit-Zm_sd1wQ.mjs.map +1 -0
  76. package/dist/contract-enrichment-CGW6mm-E.mjs +79 -0
  77. package/dist/contract-enrichment-CGW6mm-E.mjs.map +1 -0
  78. package/dist/contract-infer-DozZT511.mjs +90 -0
  79. package/dist/contract-infer-DozZT511.mjs.map +1 -0
  80. package/dist/exports/config-types.d.mts +2 -0
  81. package/dist/exports/config-types.mjs +3 -0
  82. package/dist/exports/control-api.d.mts +624 -0
  83. package/dist/exports/control-api.d.mts.map +1 -0
  84. package/dist/exports/control-api.mjs +6 -0
  85. package/dist/{load-ts-contract.d.ts → exports/index.d.mts} +12 -7
  86. package/dist/exports/index.d.mts.map +1 -0
  87. package/dist/exports/index.mjs +137 -0
  88. package/dist/exports/index.mjs.map +1 -0
  89. package/dist/extract-operation-statements-DZUJNmL3.mjs +13 -0
  90. package/dist/extract-operation-statements-DZUJNmL3.mjs.map +1 -0
  91. package/dist/extract-sql-ddl-DDMX-9mz.mjs +26 -0
  92. package/dist/extract-sql-ddl-DDMX-9mz.mjs.map +1 -0
  93. package/dist/framework-components-BAsliT4V.mjs +59 -0
  94. package/dist/framework-components-BAsliT4V.mjs.map +1 -0
  95. package/dist/init-DQ8auNB4.mjs +430 -0
  96. package/dist/init-DQ8auNB4.mjs.map +1 -0
  97. package/dist/inspect-live-schema-BYnhztxZ.mjs +91 -0
  98. package/dist/inspect-live-schema-BYnhztxZ.mjs.map +1 -0
  99. package/dist/migration-command-scaffold-CntCcntR.mjs +105 -0
  100. package/dist/migration-command-scaffold-CntCcntR.mjs.map +1 -0
  101. package/dist/migration-status-CJANY4yr.mjs +1583 -0
  102. package/dist/migration-status-CJANY4yr.mjs.map +1 -0
  103. package/dist/migrations-DTZBYXm1.mjs +173 -0
  104. package/dist/migrations-DTZBYXm1.mjs.map +1 -0
  105. package/dist/progress-adapter-B-YvmcDu.mjs +43 -0
  106. package/dist/progress-adapter-B-YvmcDu.mjs.map +1 -0
  107. package/dist/quick-reference-mongo.md +93 -0
  108. package/dist/quick-reference-postgres.md +91 -0
  109. package/dist/result-handler-oK_vA-Fn.mjs +697 -0
  110. package/dist/result-handler-oK_vA-Fn.mjs.map +1 -0
  111. package/dist/terminal-ui-C5k88MmW.mjs +274 -0
  112. package/dist/terminal-ui-C5k88MmW.mjs.map +1 -0
  113. package/dist/validate-contract-deps-esa-VQ0h.mjs +37 -0
  114. package/dist/validate-contract-deps-esa-VQ0h.mjs.map +1 -0
  115. package/dist/verify-DlFQ2FOw.mjs +385 -0
  116. package/dist/verify-DlFQ2FOw.mjs.map +1 -0
  117. package/package.json +87 -40
  118. package/src/cli.ts +118 -58
  119. package/src/commands/contract-emit.ts +101 -78
  120. package/src/commands/contract-infer-paths.ts +32 -0
  121. package/src/commands/contract-infer.ts +143 -0
  122. package/src/commands/db-init.ts +97 -219
  123. package/src/commands/db-schema.ts +77 -0
  124. package/src/commands/db-sign.ts +46 -73
  125. package/src/commands/db-update.ts +236 -0
  126. package/src/commands/db-verify.ts +409 -119
  127. package/src/commands/init/detect-package-manager.ts +47 -0
  128. package/src/commands/init/index.ts +21 -0
  129. package/src/commands/init/init.ts +203 -0
  130. package/src/commands/init/templates/agent-skill-mongo.md +106 -0
  131. package/src/commands/init/templates/agent-skill-postgres.md +106 -0
  132. package/src/commands/init/templates/agent-skill.ts +19 -0
  133. package/src/commands/init/templates/code-templates.ts +168 -0
  134. package/src/commands/init/templates/quick-reference-mongo.md +93 -0
  135. package/src/commands/init/templates/quick-reference-postgres.md +91 -0
  136. package/src/commands/init/templates/quick-reference.ts +19 -0
  137. package/src/commands/init/templates/render.ts +20 -0
  138. package/src/commands/init/templates/tsconfig.ts +35 -0
  139. package/src/commands/inspect-live-schema.ts +170 -0
  140. package/src/commands/migration-apply.ts +427 -0
  141. package/src/commands/migration-new.ts +260 -0
  142. package/src/commands/migration-plan.ts +519 -0
  143. package/src/commands/migration-ref.ts +305 -0
  144. package/src/commands/migration-show.ts +246 -0
  145. package/src/commands/migration-status.ts +864 -0
  146. package/src/commands/migration-verify.ts +180 -0
  147. package/src/config-loader.ts +13 -3
  148. package/src/control-api/client.ts +205 -183
  149. package/src/control-api/contract-enrichment.ts +119 -0
  150. package/src/control-api/errors.ts +9 -0
  151. package/src/control-api/operations/contract-emit.ts +181 -0
  152. package/src/control-api/operations/db-init.ts +53 -49
  153. package/src/control-api/operations/db-update.ts +220 -0
  154. package/src/control-api/operations/extract-operation-statements.ts +14 -0
  155. package/src/control-api/operations/extract-sql-ddl.ts +47 -0
  156. package/src/control-api/operations/migration-apply.ts +191 -0
  157. package/src/control-api/operations/migration-helpers.ts +49 -0
  158. package/src/control-api/types.ts +274 -52
  159. package/src/exports/config-types.ts +4 -3
  160. package/src/exports/control-api.ts +15 -5
  161. package/src/load-ts-contract.ts +30 -19
  162. package/src/utils/cli-errors.ts +14 -8
  163. package/src/utils/command-helpers.ts +302 -3
  164. package/src/utils/formatters/emit.ts +67 -0
  165. package/src/utils/formatters/errors.ts +82 -0
  166. package/src/utils/formatters/graph-migration-mapper.ts +240 -0
  167. package/src/utils/formatters/graph-render.ts +1323 -0
  168. package/src/utils/formatters/graph-types.ts +120 -0
  169. package/src/utils/formatters/help.ts +380 -0
  170. package/src/utils/formatters/helpers.ts +28 -0
  171. package/src/utils/formatters/migrations.ts +346 -0
  172. package/src/utils/formatters/styled.ts +212 -0
  173. package/src/utils/formatters/verify.ts +621 -0
  174. package/src/utils/framework-components.ts +13 -10
  175. package/src/utils/global-flags.ts +41 -23
  176. package/src/utils/migration-command-scaffold.ts +184 -0
  177. package/src/utils/migration-types.ts +12 -0
  178. package/src/utils/progress-adapter.ts +18 -29
  179. package/src/utils/result-handler.ts +12 -13
  180. package/src/utils/shutdown.ts +92 -0
  181. package/src/utils/suggest-command.ts +31 -0
  182. package/src/utils/terminal-ui.ts +276 -0
  183. package/src/utils/validate-contract-deps.ts +49 -0
  184. package/dist/chunk-AGOTG4L3.js +0 -965
  185. package/dist/chunk-AGOTG4L3.js.map +0 -1
  186. package/dist/chunk-HLLI4YL7.js +0 -180
  187. package/dist/chunk-HLLI4YL7.js.map +0 -1
  188. package/dist/chunk-HWYQOCAJ.js +0 -47
  189. package/dist/chunk-HWYQOCAJ.js.map +0 -1
  190. package/dist/chunk-VG2R7DGF.js +0 -735
  191. package/dist/chunk-VG2R7DGF.js.map +0 -1
  192. package/dist/cli.d.ts +0 -2
  193. package/dist/cli.d.ts.map +0 -1
  194. package/dist/cli.js.map +0 -1
  195. package/dist/commands/contract-emit.d.ts +0 -3
  196. package/dist/commands/contract-emit.d.ts.map +0 -1
  197. package/dist/commands/contract-emit.js +0 -10
  198. package/dist/commands/contract-emit.js.map +0 -1
  199. package/dist/commands/db-init.d.ts +0 -3
  200. package/dist/commands/db-init.d.ts.map +0 -1
  201. package/dist/commands/db-init.js +0 -257
  202. package/dist/commands/db-init.js.map +0 -1
  203. package/dist/commands/db-introspect.d.ts +0 -3
  204. package/dist/commands/db-introspect.d.ts.map +0 -1
  205. package/dist/commands/db-introspect.js +0 -155
  206. package/dist/commands/db-introspect.js.map +0 -1
  207. package/dist/commands/db-schema-verify.d.ts +0 -3
  208. package/dist/commands/db-schema-verify.d.ts.map +0 -1
  209. package/dist/commands/db-schema-verify.js +0 -171
  210. package/dist/commands/db-schema-verify.js.map +0 -1
  211. package/dist/commands/db-sign.d.ts +0 -3
  212. package/dist/commands/db-sign.d.ts.map +0 -1
  213. package/dist/commands/db-sign.js +0 -195
  214. package/dist/commands/db-sign.js.map +0 -1
  215. package/dist/commands/db-verify.d.ts +0 -3
  216. package/dist/commands/db-verify.d.ts.map +0 -1
  217. package/dist/commands/db-verify.js +0 -193
  218. package/dist/commands/db-verify.js.map +0 -1
  219. package/dist/config-loader.d.ts.map +0 -1
  220. package/dist/config-loader.js +0 -7
  221. package/dist/config-loader.js.map +0 -1
  222. package/dist/control-api/client.d.ts +0 -13
  223. package/dist/control-api/client.d.ts.map +0 -1
  224. package/dist/control-api/operations/db-init.d.ts +0 -29
  225. package/dist/control-api/operations/db-init.d.ts.map +0 -1
  226. package/dist/control-api/types.d.ts +0 -387
  227. package/dist/control-api/types.d.ts.map +0 -1
  228. package/dist/exports/config-types.d.ts +0 -3
  229. package/dist/exports/config-types.d.ts.map +0 -1
  230. package/dist/exports/config-types.js +0 -6
  231. package/dist/exports/config-types.js.map +0 -1
  232. package/dist/exports/control-api.d.ts +0 -13
  233. package/dist/exports/control-api.d.ts.map +0 -1
  234. package/dist/exports/control-api.js +0 -7
  235. package/dist/exports/control-api.js.map +0 -1
  236. package/dist/exports/index.d.ts +0 -4
  237. package/dist/exports/index.d.ts.map +0 -1
  238. package/dist/exports/index.js +0 -176
  239. package/dist/exports/index.js.map +0 -1
  240. package/dist/load-ts-contract.d.ts.map +0 -1
  241. package/dist/utils/cli-errors.d.ts +0 -7
  242. package/dist/utils/cli-errors.d.ts.map +0 -1
  243. package/dist/utils/command-helpers.d.ts +0 -12
  244. package/dist/utils/command-helpers.d.ts.map +0 -1
  245. package/dist/utils/framework-components.d.ts +0 -70
  246. package/dist/utils/framework-components.d.ts.map +0 -1
  247. package/dist/utils/global-flags.d.ts +0 -25
  248. package/dist/utils/global-flags.d.ts.map +0 -1
  249. package/dist/utils/output.d.ts +0 -142
  250. package/dist/utils/output.d.ts.map +0 -1
  251. package/dist/utils/progress-adapter.d.ts +0 -26
  252. package/dist/utils/progress-adapter.d.ts.map +0 -1
  253. package/dist/utils/result-handler.d.ts +0 -15
  254. package/dist/utils/result-handler.d.ts.map +0 -1
  255. package/src/commands/db-introspect.ts +0 -227
  256. package/src/commands/db-schema-verify.ts +0 -238
  257. package/src/utils/output.ts +0 -1471
package/README.md CHANGED
@@ -22,6 +22,7 @@ Provide a command-line interface that:
22
22
  - **Extension Pack Descriptor Assembly**: Collect adapter and extension descriptors for emission
23
23
  - **Help Output Formatting**: Custom styled help output with command trees and formatted descriptions
24
24
  - **Config Management**: Load and validate `prisma-next.config.ts` files using Arktype validation
25
+ - **CLI Binary Compatibility**: Build emits `dist/cli.mjs` and also writes a compatibility shim at `dist/cli.js`
25
26
 
26
27
  ### Wiring validation
27
28
 
@@ -31,13 +32,13 @@ This prevents runtime mismatches (for example: a contract that declares extensio
31
32
 
32
33
  Commands that enforce wiring validation:
33
34
  - **`db verify`**
34
- - **`db introspect`** (when a contract is provided)
35
35
  - **`db sign`**
36
36
  - **`db init`**
37
+ - **`db update`**
37
38
 
38
39
  If you hit a wiring validation error: add the required descriptors to `config.extensionPacks` (matched by descriptor `id`) and re-run the command.
39
40
 
40
- **Note**: Control plane domain actions (database verification, contract emission) are implemented in `@prisma-next/core-control-plane`. The CLI uses the control plane domain actions programmatically but does not define control plane types itself.
41
+ **Note**: Control plane domain actions (database verification, contract emission) are implemented in `@prisma-next/emitter` and `@prisma-next/framework-components/control`. The CLI uses the control plane domain actions programmatically but does not define control plane types itself.
41
42
 
42
43
  ## Command Descriptions
43
44
 
@@ -56,7 +57,7 @@ Emit `contract.json` and `contract.d.ts` from `config.contract`.
56
57
 
57
58
  **Canonical command:**
58
59
  ```bash
59
- prisma-next contract emit [--config <path>] [--json] [-v] [-q] [--timestamps] [--color/--no-color]
60
+ prisma-next contract emit [--config <path>] [--json] [-v] [-q] [--color/--no-color]
60
61
  ```
61
62
 
62
63
  **Config File Requirements:**
@@ -65,6 +66,7 @@ The `contract emit` command does not require a `driver` in the config since it d
65
66
 
66
67
  ```typescript
67
68
  import { defineConfig } from '@prisma-next/cli/config-types';
69
+ import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
68
70
  import postgresAdapter from '@prisma-next/adapter-postgres/control';
69
71
  import postgres from '@prisma-next/target-postgres/control';
70
72
  import sql from '@prisma-next/family-sql/control';
@@ -75,11 +77,7 @@ export default defineConfig({
75
77
  target: postgres,
76
78
  adapter: postgresAdapter,
77
79
  extensionPacks: [],
78
- contract: {
79
- source: contract,
80
- output: 'src/prisma/contract.json',
81
- types: 'src/prisma/contract.d.ts',
82
- },
80
+ contract: typescriptContract(contract, 'src/prisma/contract.json'),
83
81
  });
84
82
  ```
85
83
 
@@ -89,7 +87,6 @@ Options:
89
87
  - `-q, --quiet`: Quiet mode (errors only)
90
88
  - `-v, --verbose`: Verbose output (debug info, timings)
91
89
  - `-vv, --trace`: Trace output (deep internals, stack traces)
92
- - `--timestamps`: Add timestamps to output
93
90
  - `--color/--no-color`: Force/disable color output
94
91
 
95
92
  Examples:
@@ -100,27 +97,30 @@ prisma-next contract emit
100
97
  # JSON output
101
98
  prisma-next contract emit --json
102
99
 
103
- # Verbose output with timestamps
104
- prisma-next contract emit -v --timestamps
100
+ # Verbose output
101
+ prisma-next contract emit -v
105
102
  ```
106
103
 
107
104
  ### `prisma-next db verify`
108
105
 
109
- Verify that a database instance matches the emitted contract by checking marker presence, hash equality, and target compatibility.
106
+ Verify that a database instance matches the emitted contract by checking the marker first and, by default, the live schema second.
110
107
 
111
108
  **Command:**
112
109
  ```bash
113
- prisma-next db verify [--db <url>] [--config <path>] [--json] [-v] [-q] [--timestamps] [--color/--no-color]
110
+ prisma-next db verify [--db <url>] [--config <path>] [--marker-only | --schema-only] [--strict] [--json] [-v] [-q] [--color/--no-color]
114
111
  ```
115
112
 
116
113
  Options:
117
114
  - `--db <url>`: Database connection string (optional; defaults to `config.db.connection` if set)
118
115
  - `--config <path>`: Optional. Path to `prisma-next.config.ts` (defaults to `./prisma-next.config.ts` if present)
116
+ - `--marker-only`: Skip schema verification and only check the database marker
117
+ - `--schema-only`: Skip marker verification and only check whether the live schema satisfies the contract
118
+ - `--strict`: When schema verification runs, schema elements not present in the contract are considered an error
119
+ - `--marker-only` cannot be combined with `--schema-only` or `--strict` (exit code 2, `PN-CLI-4012`). `--schema-only --strict` is valid.
119
120
  - `--json`: Output as JSON object
120
121
  - `-q, --quiet`: Quiet mode (errors only)
121
122
  - `-v, --verbose`: Verbose output (debug info, timings)
122
123
  - `-vv, --trace`: Trace output (deep internals, stack traces)
123
- - `--timestamps`: Add timestamps to output
124
124
  - `--color/--no-color`: Force/disable color output
125
125
 
126
126
  Examples:
@@ -131,11 +131,20 @@ prisma-next db verify
131
131
  # Specify database URL
132
132
  prisma-next db verify --db postgresql://user:pass@localhost/db
133
133
 
134
+ # Marker-only verification when callers accept the trade-off
135
+ prisma-next db verify --db postgresql://user:pass@localhost/db --marker-only
136
+
137
+ # Schema-only verification without relying on marker state
138
+ prisma-next db verify --db postgresql://user:pass@localhost/db --schema-only
139
+
140
+ # Strict schema verification (extras fail)
141
+ prisma-next db verify --db postgresql://user:pass@localhost/db --strict
142
+
134
143
  # JSON output
135
144
  prisma-next db verify --json
136
145
 
137
- # Verbose output with timestamps
138
- prisma-next db verify -v --timestamps
146
+ # Verbose output
147
+ prisma-next db verify -v
139
148
  ```
140
149
 
141
150
  **Config File Requirements:**
@@ -144,6 +153,7 @@ The `db verify` command requires a `driver` in the config to connect to the data
144
153
 
145
154
  ```typescript
146
155
  import { defineConfig } from '@prisma-next/cli/config-types';
156
+ import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
147
157
  import postgresAdapter from '@prisma-next/adapter-postgres/control';
148
158
  import postgresDriver from '@prisma-next/driver-postgres/control';
149
159
  import postgres from '@prisma-next/target-postgres/control';
@@ -156,11 +166,7 @@ export default defineConfig({
156
166
  adapter: postgresAdapter,
157
167
  driver: postgresDriver,
158
168
  extensionPacks: [],
159
- contract: {
160
- source: contract,
161
- output: 'src/prisma/contract.json',
162
- types: 'src/prisma/contract.d.ts',
163
- },
169
+ contract: typescriptContract(contract, 'src/prisma/contract.json'),
164
170
  db: {
165
171
  connection: process.env.DATABASE_URL, // Optional: can also use --db flag
166
172
  },
@@ -171,52 +177,80 @@ export default defineConfig({
171
177
 
172
178
  1. **Load Contract**: Reads the emitted `contract.json` from `config.contract.output`
173
179
  2. **Connect to Database**: Uses `config.driver.create(url)` to create a driver
174
- 3. **Create Family Instance**: Creates a `ControlPlaneStack` via `createControlPlaneStack()` and passes it to `config.family.create(stack)` to create a family instance
175
- 4. **Verify**: Calls `familyInstance.verify()` which:
180
+ 3. **Create Family Instance**: Creates a `ControlStack` via `createControlStack()` and passes it to `config.family.create(stack)` to create a family instance
181
+ 4. **Verify Marker**: Calls `familyInstance.verify()` which:
176
182
  - Reads the contract marker from the database
177
- - Compares marker presence: Returns `PN-RTM-3001` if marker is missing
178
- - Compares target compatibility: Returns `PN-RTM-3003` if contract target doesn't match config target
179
- - Compares core hash: Returns `PN-RTM-3002` if `coreHash` doesn't match
180
- - Compares profile hash: Returns `PN-RTM-3002` if `profileHash` doesn't match (when present)
183
+ - Compares marker presence: Returns `PN-RUN-3001` if marker is missing
184
+ - Compares target compatibility: Returns `PN-RUN-3003` if contract target doesn't match config target
185
+ - Compares storage hash: Returns `PN-RUN-3002` if `storageHash` doesn't match
186
+ - Compares profile hash: Returns `PN-RUN-3002` if `profileHash` doesn't match (when present)
181
187
  - Checks codec coverage (optional): Compares contract column types against supported codec types and reports missing codecs
188
+ 5. **Verify Schema (default)**: Unless `--marker-only` is provided, calls `familyInstance.schemaVerify()` to catch schema mismatches such as missing tables or columns after manual DDL. By default this runs in tolerant mode; `--strict` treats schema elements not present in the contract as an error.
189
+ 6. **Schema-only mode**: `--schema-only` skips marker verification entirely and runs only `schemaVerify()`. This is useful for brownfield adoption and corrupt-marker diagnosis.
182
190
 
183
191
  **Output Format (TTY):**
184
192
 
185
193
  Success:
186
- ```
187
- ✔ Database matches contract
188
- coreHash: sha256:abc123...
194
+ ```text
195
+ ✔ Database marker and schema match contract
196
+ verification: marker + schema
197
+ storageHash: sha256:abc123...
189
198
  profileHash: sha256:def456...
190
199
  ```
191
200
 
192
- Failure:
201
+ Marker-only success:
202
+ ```text
203
+ ✔ Database marker matches contract
204
+ verification: marker only (--marker-only)
205
+ storageHash: sha256:abc123...
206
+ profileHash: sha256:def456...
207
+
208
+ ⚠ Schema verification skipped because --marker-only was provided
193
209
  ```
194
- ✖ Marker missing (PN-RTM-3001)
210
+
211
+ Marker failure:
212
+ ```text
213
+ ✖ Marker missing (PN-RUN-3001)
195
214
  Why: Contract marker not found in database
196
215
  Fix: Run `prisma-next db sign --db <url>` to create marker
197
216
  ```
198
217
 
218
+ Schema drift failure:
219
+ `db verify` prints the schema verification tree / JSON payload and exits with code 1.
220
+
199
221
  **Output Format (JSON):**
200
222
 
201
223
  ```json
202
224
  {
203
225
  "ok": true,
204
- "summary": "Database matches contract",
226
+ "summary": "Database marker and schema match contract",
227
+ "mode": "full",
205
228
  "contract": {
206
- "coreHash": "sha256:abc123...",
229
+ "storageHash": "sha256:abc123...",
207
230
  "profileHash": "sha256:def456..."
208
231
  },
209
232
  "marker": {
210
- "coreHash": "sha256:abc123...",
233
+ "storageHash": "sha256:abc123...",
211
234
  "profileHash": "sha256:def456..."
212
235
  },
213
236
  "target": {
214
237
  "expected": "postgres"
215
238
  },
216
239
  "missingCodecs": [],
240
+ "schema": {
241
+ "summary": "Database schema satisfies contract",
242
+ "counts": {
243
+ "pass": 12,
244
+ "warn": 0,
245
+ "fail": 0,
246
+ "totalNodes": 12
247
+ },
248
+ "strict": false
249
+ },
217
250
  "meta": {
218
251
  "configPath": "/path/to/prisma-next.config.ts",
219
- "contractPath": "/path/to/src/prisma/contract.json"
252
+ "contractPath": "/path/to/src/prisma/contract.json",
253
+ "schemaVerification": "performed"
220
254
  },
221
255
  "timings": {
222
256
  "total": 42
@@ -227,22 +261,23 @@ Failure:
227
261
  **Error Codes:**
228
262
 
229
263
  - `PN-CLI-4010`: Missing driver in config — provide a driver descriptor
230
- - `PN-RTM-3001`: Marker missing - Contract marker not found in database
231
- - `PN-RTM-3002`: Hash mismatch - Contract hash does not match database marker
232
- - `PN-RTM-3003`: Target mismatch - Contract target does not match config target
264
+ - `PN-RUN-3001`: Marker missing - Contract marker not found in database
265
+ - `PN-RUN-3002`: Hash mismatch - Contract hash does not match database marker
266
+ - `PN-RUN-3003`: Target mismatch - Contract target does not match config target
267
+ - Exit code 1 with schema verification payload: Schema does not match the contract (default mode or `--schema-only`)
233
268
 
234
269
  **Family Requirements:**
235
270
 
236
- The family must provide a `create()` method in the family descriptor that accepts a `ControlPlaneStack` and returns a `ControlFamilyInstance` with a `verify()` method:
271
+ The family must provide a `create()` method in the family descriptor that accepts a `ControlStack` and returns a `ControlFamilyInstance` with a `verify()` method:
237
272
 
238
273
  ```typescript
239
274
  interface ControlFamilyDescriptor<TFamilyId, TFamilyInstance> {
240
275
  create<TTargetId extends string>(
241
- stack: ControlPlaneStack<TFamilyId, TTargetId>,
276
+ stack: ControlStack<TFamilyId, TTargetId>,
242
277
  ): TFamilyInstance;
243
278
  }
244
279
 
245
- interface ControlPlaneStack<TFamilyId, TTargetId> {
280
+ interface ControlStack<TFamilyId, TTargetId> {
246
281
  readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>;
247
282
  readonly adapter: ControlAdapterDescriptor<TFamilyId, TTargetId>;
248
283
  readonly driver: ControlDriverDescriptor<TFamilyId, TTargetId> | undefined;
@@ -252,7 +287,7 @@ interface ControlPlaneStack<TFamilyId, TTargetId> {
252
287
  interface ControlFamilyInstance {
253
288
  verify(options: {
254
289
  driver: ControlDriverInstance;
255
- contractIR: ContractIR;
290
+ contract: Contract;
256
291
  expectedTargetId: string;
257
292
  contractPath: string;
258
293
  configPath?: string;
@@ -260,17 +295,17 @@ interface ControlFamilyInstance {
260
295
  }
261
296
  ```
262
297
 
263
- Use `createControlPlaneStack()` from `@prisma-next/core-control-plane/stack` to create the stack with sensible defaults (`driver` defaults to `undefined`, `extensionPacks` defaults to `[]`).
298
+ Use `createControlStack()` from `@prisma-next/framework-components/control` to create the stack with sensible defaults (`driver` defaults to `undefined`, `extensionPacks` defaults to `[]`).
264
299
 
265
- The SQL family provides this via `@prisma-next/family-sql/control`. The `verify()` method handles reading the marker, comparing hashes, and checking codec coverage internally.
300
+ The SQL family provides this via `@prisma-next/family-sql/control`. The `verify()` method handles marker checks, full `db verify` follows it with `schemaVerify()`, `--marker-only` skips that schema step, and `--schema-only` runs `schemaVerify()` without marker checks.
266
301
 
267
- ### `prisma-next db introspect`
302
+ ### `prisma-next db schema`
268
303
 
269
- Inspect the live database schema and display it as a human-readable tree or machine-consumable JSON.
304
+ Inspect the live database schema and display it as a human-readable tree or machine-consumable JSON. This command is read-only and never writes files.
270
305
 
271
306
  **Command:**
272
307
  ```bash
273
- prisma-next db introspect [--db <url>] [--config <path>] [--json] [-v] [-q] [--timestamps] [--color/--no-color]
308
+ prisma-next db schema [--db <url>] [--config <path>] [--json] [-v] [-q] [--color/--no-color]
274
309
  ```
275
310
 
276
311
  Options:
@@ -280,30 +315,69 @@ Options:
280
315
  - `-q, --quiet`: Quiet mode (errors only)
281
316
  - `-v, --verbose`: Verbose output (debug info, timings)
282
317
  - `-vv, --trace`: Trace output (deep internals, stack traces)
283
- - `--timestamps`: Add timestamps to output
284
318
  - `--color/--no-color`: Force/disable color output
285
319
 
286
320
  Examples:
287
321
  ```bash
288
322
  # Use config defaults
289
- prisma-next db introspect
323
+ prisma-next db schema
290
324
 
291
325
  # Specify database URL
292
- prisma-next db introspect --db postgresql://user:pass@localhost/db
326
+ prisma-next db schema --db postgresql://user:pass@localhost/db
293
327
 
294
328
  # JSON output
295
- prisma-next db introspect --json
329
+ prisma-next db schema --json
330
+
331
+ # Verbose output
332
+ prisma-next db schema -v
333
+ ```
334
+
335
+ ### `prisma-next contract infer`
336
+
337
+ Inspect the live database schema and write an inferred PSL contract to disk. Use this for brownfield adoption when you want a starting `contract.prisma` before running `contract emit` and `db sign`.
338
+
339
+ **Command:**
340
+ ```bash
341
+ prisma-next contract infer [--db <url>] [--config <path>] [--output <path>] [--json] [-v] [-q] [--color/--no-color]
342
+ ```
343
+
344
+ Options:
345
+ - `--db <url>`: Database connection string (optional; defaults to `config.db.connection` if set)
346
+ - `--config <path>`: Optional. Path to `prisma-next.config.ts` (defaults to `./prisma-next.config.ts` if present)
347
+ - `--output <path>`: Write the inferred PSL contract to the specified path
348
+ - `--json`: Output a JSON result envelope (includes `psl.path`)
349
+ - `-q, --quiet`: Quiet mode (errors only)
350
+ - `-v, --verbose`: Verbose output (debug info, timings)
351
+ - `-vv, --trace`: Trace output (deep internals, stack traces)
352
+ - `--color/--no-color`: Force/disable color output
353
+
354
+ Examples:
355
+ ```bash
356
+ # Infer contract.prisma next to the configured contract.json output
357
+ prisma-next contract infer
358
+
359
+ # Specify database URL
360
+ prisma-next contract infer --db postgresql://user:pass@localhost/db
296
361
 
297
- # Verbose output with timestamps
298
- prisma-next db introspect -v --timestamps
362
+ # Override the output path
363
+ prisma-next contract infer --output ./prisma/contract.prisma
364
+
365
+ # JSON output
366
+ prisma-next contract infer --json
299
367
  ```
300
368
 
369
+ By default, `contract infer` writes to:
370
+ 1. `--output <path>`, if provided
371
+ 2. `contract.prisma` next to `config.contract.output`
372
+ 3. `contract.prisma` in the current working directory
373
+
301
374
  **Config File Requirements:**
302
375
 
303
- The `db introspect` command requires a `driver` in the config to connect to the database:
376
+ Both `db schema` and `contract infer` require a `driver` in the config to connect to the database:
304
377
 
305
378
  ```typescript
306
379
  import { defineConfig } from '@prisma-next/cli/config-types';
380
+ import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
307
381
  import postgresAdapter from '@prisma-next/adapter-postgres/control';
308
382
  import postgresDriver from '@prisma-next/driver-postgres/control';
309
383
  import postgres from '@prisma-next/target-postgres/control';
@@ -324,7 +398,7 @@ export default defineConfig({
324
398
  **Introspection Process:**
325
399
 
326
400
  1. **Connect to Database**: Uses `config.driver.create(url)` to create a driver
327
- 2. **Create Family Instance**: Creates a `ControlPlaneStack` via `createControlPlaneStack()` and passes it to `config.family.create(stack)` to create a family instance
401
+ 2. **Create Family Instance**: Creates a `ControlStack` via `createControlStack()` and passes it to `config.family.create(stack)` to create a family instance
328
402
  3. **Introspect**: Calls `familyInstance.introspect()` which:
329
403
  - Queries the database catalog to discover schema structure
330
404
  - Returns a family-specific schema IR (e.g., `SqlSchemaIR` for SQL family)
@@ -403,7 +477,7 @@ The family must provide:
403
477
  interface ControlFamilyInstance {
404
478
  introspect(options: {
405
479
  driver: ControlDriverInstance;
406
- contractIR?: ContractIR;
480
+ contract?: Contract;
407
481
  schema?: string;
408
482
  }): Promise<FamilySchemaIR>;
409
483
 
@@ -421,7 +495,7 @@ Mark the database as matching the emitted contract by writing or updating the co
421
495
 
422
496
  **Command:**
423
497
  ```bash
424
- prisma-next db sign [--db <url>] [--config <path>] [--json] [-v] [-q] [--timestamps] [--color/--no-color]
498
+ prisma-next db sign [--db <url>] [--config <path>] [--json] [-v] [-q] [--color/--no-color]
425
499
  ```
426
500
 
427
501
  Options:
@@ -431,7 +505,6 @@ Options:
431
505
  - `-q, --quiet`: Quiet mode (errors only)
432
506
  - `-v, --verbose`: Verbose output (debug info, timings)
433
507
  - `-vv, --trace`: Trace output (deep internals, stack traces)
434
- - `--timestamps`: Add timestamps to output
435
508
  - `--color/--no-color`: Force/disable color output
436
509
 
437
510
  Examples:
@@ -445,8 +518,8 @@ prisma-next db sign --db postgresql://user:pass@localhost/db
445
518
  # JSON output
446
519
  prisma-next db sign --json
447
520
 
448
- # Verbose output with timestamps
449
- prisma-next db sign -v --timestamps
521
+ # Verbose output
522
+ prisma-next db sign -v
450
523
  ```
451
524
 
452
525
  **Config File Requirements:**
@@ -467,11 +540,7 @@ export default defineConfig({
467
540
  adapter: postgresAdapter,
468
541
  driver: postgresDriver,
469
542
  extensionPacks: [],
470
- contract: {
471
- source: contract,
472
- output: 'src/prisma/contract.json',
473
- types: 'src/prisma/contract.d.ts',
474
- },
543
+ contract: typescriptContract(contract, 'src/prisma/contract.json'),
475
544
  db: {
476
545
  connection: process.env.DATABASE_URL, // Optional: can also use --db flag
477
546
  },
@@ -482,7 +551,7 @@ export default defineConfig({
482
551
 
483
552
  1. **Load Contract**: Reads the emitted `contract.json` from `config.contract.output`
484
553
  2. **Connect to Database**: Uses `config.driver.create(url)` to create a driver
485
- 3. **Create Family Instance**: Creates a `ControlPlaneStack` via `createControlPlaneStack()` and passes it to `config.family.create(stack)` to create a family instance
554
+ 3. **Create Family Instance**: Creates a `ControlStack` via `createControlStack()` and passes it to `config.family.create(stack)` to create a family instance
486
555
  4. **Schema Verification (Precondition)**: Calls `familyInstance.schemaVerify()` to verify the database schema matches the contract:
487
556
  - If verification fails: Prints schema verification output and exits with code 1 (marker is not written)
488
557
  - If verification passes: Proceeds to marker signing
@@ -499,7 +568,7 @@ export default defineConfig({
499
568
  Success (new marker):
500
569
  ```
501
570
  ✔ Database signed (marker created)
502
- coreHash: sha256:abc123...
571
+ storageHash: sha256:abc123...
503
572
  profileHash: sha256:def456...
504
573
  Total time: 42ms
505
574
  ```
@@ -507,16 +576,16 @@ Success (new marker):
507
576
  Success (updated marker):
508
577
  ```
509
578
  ✔ Database signed (marker updated from sha256:old-hash)
510
- coreHash: sha256:abc123...
579
+ storageHash: sha256:abc123...
511
580
  profileHash: sha256:def456...
512
- previous coreHash: sha256:old-hash
581
+ previous storageHash: sha256:old-hash
513
582
  Total time: 42ms
514
583
  ```
515
584
 
516
585
  Success (already up-to-date):
517
586
  ```
518
587
  ✔ Database already signed with this contract
519
- coreHash: sha256:abc123...
588
+ storageHash: sha256:abc123...
520
589
  profileHash: sha256:def456...
521
590
  Total time: 42ms
522
591
  ```
@@ -534,7 +603,7 @@ Failure (schema mismatch):
534
603
  "ok": true,
535
604
  "summary": "Database signed (marker created)",
536
605
  "contract": {
537
- "coreHash": "sha256:abc123...",
606
+ "storageHash": "sha256:abc123...",
538
607
  "profileHash": "sha256:def456..."
539
608
  },
540
609
  "target": {
@@ -561,7 +630,7 @@ For updated markers:
561
630
  "ok": true,
562
631
  "summary": "Database signed (marker updated from sha256:old-hash)",
563
632
  "contract": {
564
- "coreHash": "sha256:abc123...",
633
+ "storageHash": "sha256:abc123...",
565
634
  "profileHash": "sha256:def456..."
566
635
  },
567
636
  "target": {
@@ -572,7 +641,7 @@ For updated markers:
572
641
  "created": false,
573
642
  "updated": true,
574
643
  "previous": {
575
- "coreHash": "sha256:old-hash",
644
+ "storageHash": "sha256:old-hash",
576
645
  "profileHash": "sha256:old-profile-hash"
577
646
  }
578
647
  },
@@ -592,8 +661,7 @@ For updated markers:
592
661
  - Exit code 1: Schema verification failed — database schema does not match contract (marker is not written)
593
662
 
594
663
  **Relationship to Other Commands:**
595
- - **`db schema-verify`**: `db sign` calls `schemaVerify` as a precondition before writing the marker. If schema verification fails, `db sign` exits without writing the marker.
596
- - **`db verify`**: `db verify` checks that the marker exists and matches the contract. `db sign` writes the marker that `db verify` checks.
664
+ - **`db verify`**: `db verify` checks that the marker exists and matches the contract, then runs schema verification by default. `db sign` writes the marker that `db verify` checks. Use `db verify --marker-only` for marker-only verification and `db verify --schema-only` to inspect only the live schema.
597
665
 
598
666
  **Idempotency:**
599
667
  The `db sign` command is idempotent and safe to run multiple times:
@@ -608,7 +676,7 @@ The family must provide a `create()` method in the family descriptor that return
608
676
  interface ControlFamilyInstance {
609
677
  schemaVerify(options: {
610
678
  driver: ControlDriverInstance;
611
- contractIR: ContractIR;
679
+ contract: Contract;
612
680
  strict: boolean;
613
681
  contractPath: string;
614
682
  configPath?: string;
@@ -616,7 +684,7 @@ interface ControlFamilyInstance {
616
684
 
617
685
  sign(options: {
618
686
  driver: ControlDriverInstance;
619
- contractIR: ContractIR;
687
+ contract: Contract;
620
688
  contractPath: string;
621
689
  configPath?: string;
622
690
  }): Promise<SignDatabaseResult>;
@@ -631,18 +699,17 @@ Initialize a database schema from the contract. This command plans and applies *
631
699
 
632
700
  **Command:**
633
701
  ```bash
634
- prisma-next db init [--db <url>] [--config <path>] [--plan] [--json] [-v] [-q] [--timestamps] [--color/--no-color]
702
+ prisma-next db init [--db <url>] [--config <path>] [--dry-run] [--json] [-v] [-q] [--color/--no-color]
635
703
  ```
636
704
 
637
705
  Options:
638
706
  - `--db <url>`: Database connection string (optional; defaults to `config.db.connection` if set)
639
707
  - `--config <path>`: Optional. Path to `prisma-next.config.ts` (defaults to `./prisma-next.config.ts` if present)
640
- - `--plan`: Only show the migration plan, do not apply it
708
+ - `--dry-run`: Only show the migration plan, do not apply it
641
709
  - `--json [format]`: Output as JSON (`object` only; `ndjson` is not supported for this command)
642
710
  - `-q, --quiet`: Quiet mode (errors only)
643
711
  - `-v, --verbose`: Verbose output (debug info, timings)
644
712
  - `-vv, --trace`: Trace output (deep internals, stack traces)
645
- - `--timestamps`: Add timestamps to output
646
713
  - `--color/--no-color`: Force/disable color output
647
714
 
648
715
  Examples:
@@ -651,7 +718,7 @@ Examples:
651
718
  prisma-next db init
652
719
 
653
720
  # Preview migration plan without applying
654
- prisma-next db init --plan
721
+ prisma-next db init --dry-run
655
722
 
656
723
  # Specify database URL
657
724
  prisma-next db init --db postgresql://user:pass@localhost/db
@@ -666,6 +733,7 @@ The `db init` command requires a `driver` in the config to connect to the databa
666
733
 
667
734
  ```typescript
668
735
  import { defineConfig } from '@prisma-next/cli/config-types';
736
+ import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
669
737
  import postgresAdapter from '@prisma-next/adapter-postgres/control';
670
738
  import postgresDriver from '@prisma-next/driver-postgres/control';
671
739
  import postgres from '@prisma-next/target-postgres/control';
@@ -678,11 +746,7 @@ export default defineConfig({
678
746
  adapter: postgresAdapter,
679
747
  driver: postgresDriver,
680
748
  extensionPacks: [],
681
- contract: {
682
- source: contract,
683
- output: 'src/prisma/contract.json',
684
- types: 'src/prisma/contract.d.ts',
685
- },
749
+ contract: typescriptContract(contract, 'src/prisma/contract.json'),
686
750
  db: {
687
751
  connection: process.env.DATABASE_URL, // Optional: can also use --db flag
688
752
  },
@@ -693,17 +757,17 @@ export default defineConfig({
693
757
 
694
758
  1. **Load Contract**: Reads the emitted `contract.json` from `config.contract.output`
695
759
  2. **Connect to Database**: Uses `config.driver.create(url)` to create a driver
696
- 3. **Create Family Instance**: Creates a `ControlPlaneStack` via `createControlPlaneStack()` and passes it to `config.family.create(stack)` to create a family instance
760
+ 3. **Create Family Instance**: Creates a `ControlStack` via `createControlStack()` and passes it to `config.family.create(stack)` to create a family instance
697
761
  4. **Introspect Schema**: Calls `familyInstance.introspect()` to get the current database schema IR
698
762
  5. **Validate wiring**: Ensures the contract is compatible with the CLI config:
699
763
  - `contract.targetFamily` matches `config.family.familyId`
700
764
  - `contract.target` matches `config.target.targetId`
701
765
  - `contract.extensionPacks` (if present) are provided by `config.extensionPacks` (matched by descriptor `id`)
702
766
  6. **Create Planner/Runner**: Uses `config.target.migrations.createPlanner()` and `config.target.migrations.createRunner()`
703
- 7. **Plan Migration**: Calls `planner.plan()` with the contract IR, schema IR, additive-only policy, and `frameworkComponents` (the active target/adapter/extension descriptors)
767
+ 7. **Plan Migration**: Calls `planner.plan()` with the contract, schema IR, additive-only policy, and `frameworkComponents` (the active target/adapter/extension descriptors)
704
768
  - On conflict: Returns a structured failure with conflict list
705
769
  - On success: Returns a migration plan with operations
706
- 8. **Apply Migration** (if not `--plan`):
770
+ 8. **Apply Migration** (if not `--dry-run`):
707
771
  - Calls `runner.execute()` to apply the plan
708
772
  - After execution, verifies schema matches contract
709
773
  - Writes contract marker (and records a ledger entry via the target runner)
@@ -726,7 +790,7 @@ prisma-next db init ➜ Bootstrap a database to match the current contract
726
790
  Destination hash: sha256:abc123...
727
791
 
728
792
  This is a dry run. No changes were applied.
729
- Run without --plan to apply changes.
793
+ Run without --dry-run to apply changes.
730
794
  ```
731
795
 
732
796
  **Output Format (TTY - Apply Mode):**
@@ -754,7 +818,7 @@ Applying migration plan and verifying schema...
754
818
  "plan": {
755
819
  "targetId": "postgres",
756
820
  "destination": {
757
- "coreHash": "sha256:abc123..."
821
+ "storageHash": "sha256:abc123..."
758
822
  },
759
823
  "operations": [
760
824
  {
@@ -769,7 +833,7 @@ Applying migration plan and verifying schema...
769
833
  "operationsExecuted": 4
770
834
  },
771
835
  "marker": {
772
- "coreHash": "sha256:abc123..."
836
+ "storageHash": "sha256:abc123..."
773
837
  }
774
838
  }
775
839
  ```
@@ -781,12 +845,33 @@ Applying migration plan and verifying schema...
781
845
  - `PN-CLI-4010`: Missing driver in config
782
846
  - `PN-CLI-4020`: Migration planning failed (conflicts)
783
847
  - `PN-CLI-4021`: Target does not support migrations
784
- - `PN-RTM-3000`: Runtime error (includes marker mismatch failures)
848
+ - `PN-RUN-3000`: Runtime error (includes marker mismatch failures)
785
849
 
786
850
  **Behavior Notes:**
787
851
 
788
852
  - If the database already has a marker that matches the destination contract, `db init` succeeds as a noop (0 operations planned/executed).
789
- - If the database has a marker that does **not** match the destination contract, `db init` fails (including in `--plan` mode). Use `db init` for bootstrapping; use your migration workflow to reconcile existing databases.
853
+ - If the database has a marker that does **not** match the destination contract, `db init` fails (including in `--dry-run` mode). Use `db init` for bootstrapping; use your migration workflow to reconcile existing databases.
854
+
855
+ ### `prisma-next db update`
856
+
857
+ Update your database schema to match the currently emitted contract.
858
+
859
+ `db update` differs from `db init`:
860
+
861
+ - Works on any database, whether or not it has been initialized with `db init` (creates the signature table if missing)
862
+ - Allows `additive`, `widening`, and `destructive` operation classes where supported by planner/runner
863
+ - Disables per-operation runner execution checks by default (precheck/postcheck/idempotency)
864
+ - In `--dry-run` mode for SQL targets, prints a DDL preview derived from planned operations
865
+ - In interactive mode, destructive plans require confirmation before apply
866
+ - In non-interactive mode, destructive plans fail unless `-y, --yes` is provided
867
+
868
+ **Command:**
869
+ ```bash
870
+ prisma-next db update [--db <url>] [--config <path>] [--dry-run] [-y|--yes] [--interactive|--no-interactive] [--json] [-v] [-q] [--color/--no-color]
871
+ ```
872
+
873
+ **Error codes (additional to shared CLI/runtime codes):**
874
+ - `RUNNER_FAILED`: runner rejected apply (origin mismatch, failed checks, policy failures, or execution errors)
790
875
 
791
876
  **Config File (`prisma-next.config.ts`):**
792
877
 
@@ -801,6 +886,7 @@ The CLI uses a config file to specify the target family, target, adapter, extens
801
886
 
802
887
  ```typescript
803
888
  import { defineConfig } from '@prisma-next/cli/config-types';
889
+ import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
804
890
  import postgresAdapter from '@prisma-next/adapter-postgres/control';
805
891
  import postgres from '@prisma-next/target-postgres/control';
806
892
  import sql from '@prisma-next/family-sql/control';
@@ -811,42 +897,192 @@ export default defineConfig({
811
897
  target: postgres,
812
898
  adapter: postgresAdapter,
813
899
  extensionPacks: [],
814
- contract: {
815
- source: contract, // Can be a value or a function: () => import('./contract').then(m => m.contract)
816
- output: 'src/prisma/contract.json', // Optional: defaults to 'src/prisma/contract.json'
817
- types: 'src/prisma/contract.d.ts', // Optional: defaults to output with .d.ts extension
818
- },
900
+ contract: typescriptContract(contract, 'src/prisma/contract.json'),
819
901
  });
820
902
  ```
821
903
 
822
- The `contract.source` field can be:
823
- - A direct value: `source: contract`
824
- - A synchronous function: `source: () => contract`
825
- - An asynchronous function: `source: () => import('./contract').then(m => m.contract)`
904
+ Prefer helper utilities for authoring mode selection:
905
+ - `typescriptContract(contract, outputPath?)` from `@prisma-next/sql-contract-ts/config-types` for TS-authored contracts
906
+ - `prismaContract(schemaPath, { output?, target? })` from `@prisma-next/sql-contract-psl/provider` for PSL-authored providers
907
+ - Provider failures are returned as structured diagnostics for CLI rendering
826
908
 
827
909
  The `contract.output` field specifies the path to `contract.json`. This is the canonical location where other CLI commands can find the contract JSON artifact. Defaults to `'src/prisma/contract.json'` if not specified.
828
910
 
829
- The `contract.types` field specifies the path to `contract.d.ts`. Defaults to `output` with `.d.ts` extension (replaces `.json` with `.d.ts` if output ends with `.json`, otherwise appends `contract.d.ts` to the directory containing output).
911
+ `contract.d.ts` is always colocated with `contract.json` and derived from `contract.output` (`contract.json` `contract.d.ts`).
830
912
 
831
913
  **Output:**
832
914
  - `contract.json`: Includes `_generated` metadata field indicating it's a generated artifact (excluded from canonicalization/hashing)
833
915
  - `contract.d.ts`: Includes warning header comments indicating it's a generated file
834
916
 
917
+ ### `prisma-next migration plan`
918
+
919
+ Plan a migration from contract changes. Compares the emitted contract against the latest on-disk migration state and produces a new migration package with the required operations. No database connection is needed — fully offline.
920
+
921
+ ```bash
922
+ prisma-next migration plan [--config <path>] [--name <slug>] [--from <hash>] [--json] [-v] [-q] [--color/--no-color]
923
+ ```
924
+
925
+ **Options:**
926
+ - `--config <path>`: Path to `prisma-next.config.ts`
927
+ - `--name <slug>`: Name slug for the migration directory (default: `migration`)
928
+ - `--from <hash>`: Explicit starting contract hash (overrides latest migration target detection)
929
+ - `--json`: Output as JSON object
930
+ - `-q, --quiet`: Quiet mode (errors only)
931
+ - `-v, --verbose`: Verbose output (debug info, timings)
932
+
933
+ **What it does:**
934
+ 1. Loads config and reads `contract.json` (the "to" contract)
935
+ 2. Reads existing migrations from `config.migrations.dir` (default: `migrations/`)
936
+ 3. Determines the starting point: `--from <hash>` if provided, otherwise the latest migration target
937
+ 4. Diffs the starting contract against the new contract using the target's migration planner
938
+ 5. Writes a new migration package (`migration.json` + `ops.json`) and attests the `migrationId`
939
+
940
+ **Branching with `--from`:** Use `--from` to create a migration edge from a specific contract hash instead of the latest migration target. This enables branched migration graphs where multiple environments diverge from a common ancestor.
941
+
942
+ ### `prisma-next migration show`
943
+
944
+ Display a migration package's operations, DDL preview, and metadata. Accepts a directory path, a hash prefix (git-style matching against `migrationId`), or defaults to the latest migration.
945
+
946
+ ```bash
947
+ prisma-next migration show [target] [--config <path>] [--json] [-v] [-q] [--color/--no-color]
948
+ ```
949
+
950
+ **Options:**
951
+ - `[target]`: Migration directory path or migrationId hash prefix (defaults to latest)
952
+ - `--config <path>`: Path to `prisma-next.config.ts`
953
+ - `--json`: Output as JSON object
954
+ - `-q, --quiet`: Quiet mode (errors only)
955
+ - `-v, --verbose`: Verbose output
956
+
957
+ **What it does:**
958
+ 1. If `target` is a path (contains `/` or `\`), reads that directory directly
959
+ 2. If `target` is a hash prefix, scans all attested migrations and matches against `migrationId`
960
+ 3. If no target, defaults to the latest migration
961
+ 4. Displays operations with operation class badges, destructive warnings, and DDL preview
962
+
963
+ **Destructive warnings:** When a migration contains destructive operations (e.g., `DROP TABLE`, `ALTER COLUMN TYPE`), the output includes a prominent `⚠` warning about potential data loss.
964
+
965
+ ### `prisma-next migration status`
966
+
967
+ Show the migration graph and applied status. Adapts based on context:
968
+
969
+ - **With DB connection**: Shows applied/pending markers and "you are here" indicators
970
+ - **Without DB connection**: Shows the graph structure from disk only
971
+ - **With `--ref`**: Targets a specific ref instead of the contract hash; all refs from `refs.json` are rendered on the graph
972
+
973
+ ```bash
974
+ prisma-next migration status [--db <url>] [--ref <name>] [--config <path>] [--json] [-v] [-q] [--color/--no-color]
975
+ ```
976
+
977
+ **Options:**
978
+ - `--db <url>`: Database connection string (enables online mode)
979
+ - `--ref <name>`: Target a named ref from `migrations/refs.json` instead of the current contract hash
980
+ - `--config <path>`: Path to `prisma-next.config.ts`
981
+ - `--json`: Output as JSON object
982
+ - `-q, --quiet`: Quiet mode (errors only)
983
+ - `-v, --verbose`: Verbose output
984
+
985
+ **What it does:**
986
+ 1. Reads migration packages from disk and reconstructs the migration graph
987
+ 2. Loads all refs from `migrations/refs.json` (if present) and renders them on the graph
988
+ 3. If `--ref` is provided, uses the ref's hash as the target instead of the contract hash; the active ref is highlighted in bold, other refs are dimmed
989
+ 4. If a DB connection is available, reads the marker to determine applied/pending status and shows distance from the ref target (e.g., "2 edge(s) behind ref")
990
+ 5. Displays the graph with `◄ DB`, `◄ Contract`, and `◄ ref:<name>` markers
991
+ 6. Shows operation summaries with destructive operation highlighting
992
+ 7. In `--ref` mode, the `CONTRACT.AHEAD` warning is suppressed — contract being ahead of a ref target is expected in multi-environment workflows
993
+
994
+ **Branched graphs:** When the migration graph has multiple branches (divergence), status reports an `AMBIGUOUS_TARGET` error with the divergence point and branch details. Use `--ref` to target a specific branch.
995
+
996
+ ### `prisma-next migration apply`
997
+
998
+ Apply planned migrations to the database. Executes previously planned migrations (created by `migration plan`). Compares the database marker against the migration graph to determine which migrations are pending, then executes them sequentially. Each migration runs in its own transaction. Does not plan new migrations — run `migration plan` first.
999
+
1000
+ ```bash
1001
+ prisma-next migration apply [--db <url>] [--ref <name>] [--config <path>] [--json] [-v] [-q] [--color/--no-color]
1002
+ ```
1003
+
1004
+ **Options:**
1005
+ - `--db <url>`: Database connection string (optional; defaults to `config.db.connection`)
1006
+ - `--ref <name>`: Target a named ref from `migrations/refs.json` instead of the current contract hash
1007
+ - `--config <path>`: Path to `prisma-next.config.ts`
1008
+ - `--json`: Output as JSON object
1009
+ - `-q, --quiet`: Quiet mode (errors only)
1010
+ - `-v, --verbose`: Verbose output (debug info, timings)
1011
+
1012
+ **What it does:**
1013
+ 1. Reads attested migration packages from `config.migrations.dir`
1014
+ 2. Reconstructs the migration graph (skips drafts with `migrationId: null`)
1015
+ 3. Determines the destination hash: from `--ref` (via `refs.json`) or from `contract.json`
1016
+ 4. Connects to the database and reads the current marker hash
1017
+ 5. Finds the shortest path from the marker hash to the destination using graph pathfinding
1018
+ 6. Executes each pending migration in order using the target's `MigrationRunner`
1019
+ 7. Each migration runs in its own transaction with prechecks, postchecks, and idempotency checks enabled
1020
+ 8. After each migration, the runner verifies the schema and updates the marker/ledger
1021
+
1022
+ **Config requirements:** Requires `driver` and `db.connection` (or `--db`). `migrations.dir` is optional and defaults to `migrations/`.
1023
+
1024
+ **Resume semantics:** If a migration fails, previously applied migrations are preserved. Re-running `migration apply` resumes from the last successful migration.
1025
+
1026
+ **Ref-based routing:** With `--ref`, apply targets the ref's hash instead of the contract hash. This enables multi-environment workflows where staging and production track different points in the migration graph.
1027
+
1028
+ ### `prisma-next migration verify`
1029
+
1030
+ Verify a migration package's integrity by recomputing the content-addressed `migrationId`.
1031
+
1032
+ ```bash
1033
+ prisma-next migration verify --dir <path>
1034
+ ```
1035
+
1036
+ - **Verified**: stored `migrationId` matches recomputed value
1037
+ - **Draft**: `migrationId` is null — automatically attests the package
1038
+ - **Mismatch**: package has been modified since attestation (command exits non-zero)
1039
+
1040
+ ### `prisma-next migration ref`
1041
+
1042
+ Manage named refs in `migrations/refs.json`. Refs map logical environment names (e.g., `staging`, `production`) to contract hashes, enabling multi-environment migration workflows where different environments track different points in the migration graph.
1043
+
1044
+ ```bash
1045
+ prisma-next migration ref set <name> <hash> # Set a ref to a contract hash
1046
+ prisma-next migration ref get <name> # Get the hash for a ref
1047
+ prisma-next migration ref delete <name> # Delete a ref
1048
+ prisma-next migration ref list # List all refs
1049
+ ```
1050
+
1051
+ **Options (all subcommands):**
1052
+ - `--config <path>`: Path to `prisma-next.config.ts`
1053
+ - `--json`: Output as JSON object
1054
+ - `-q, --quiet`: Quiet mode (errors only)
1055
+
1056
+ **Ref naming rules:** Lowercase alphanumeric with hyphens or forward slashes (e.g., `staging`, `prod/us-east`). No `.` or `..` segments.
1057
+
1058
+ **Ref values:** Must be valid contract hashes (`sha256:<64 hex chars>` or `sha256:empty`).
1059
+
1060
+ **Atomic writes:** `refs.json` is written atomically via temp file + rename to prevent corruption from concurrent writes.
1061
+
835
1062
  ## Architecture
836
1063
 
837
1064
  ```mermaid
838
1065
  flowchart TD
839
1066
  CLI[CLI Entry Point]
840
- CMD[Emit Command]
1067
+ CMD_EMIT[Emit Command]
1068
+ CMD_DB[DB Commands]
1069
+ CMD_MIG[Migration Commands]
841
1070
  LOAD[TS Contract Loader]
842
1071
  EMIT[Emitter]
1072
+ CTRL[Control Client]
1073
+ MIG_TOOLS["@prisma-next/migration-tools"]
843
1074
  FS[File System]
844
1075
 
845
- CLI --> CMD
846
- CMD --> LOAD
1076
+ CLI --> CMD_EMIT
1077
+ CLI --> CMD_DB
1078
+ CLI --> CMD_MIG
1079
+ CMD_EMIT --> LOAD
847
1080
  LOAD --> EMIT
848
- EMIT --> CMD
849
- CMD --> FS
1081
+ CMD_DB --> CTRL
1082
+ CMD_MIG --> CTRL
1083
+ CMD_MIG --> MIG_TOOLS
1084
+ MIG_TOOLS --> FS
1085
+ CTRL --> FS
850
1086
  ```
851
1087
 
852
1088
  ## Config Validation and Normalization
@@ -868,38 +1104,39 @@ See `.cursor/rules/config-validation-and-normalization.mdc` for detailed pattern
868
1104
  - Exit codes: 0 (success), 1 (runtime error), 2 (usage/config error)
869
1105
  - **Error Handling**: Uses `exitOverride()` to catch unhandled errors (non-structured errors that fail fast) and print stack traces. Commands handle structured errors themselves via `process.exit()`.
870
1106
  - **Command Taxonomy**: Groups commands by domain/plane (e.g., `contract emit`)
871
- - **Help Formatting**: Uses `configureHelp()` to customize help output with styled format matching normal command output. Root help shows "prisma-next" title with command tree; command help shows "prisma-next <command> ➜ <description>" with options and docs URLs. See `utils/output.ts` for help formatters.
1107
+ - **Help Formatting**: Uses `configureHelp()` to customize help output with styled format matching normal command output. Root help shows "prisma-next" title with command tree; command help shows "prisma-next <command> ➜ <description>" with options and docs URLs. See `utils/formatters/help.ts` for help formatters.
872
1108
  - **Command Descriptions**: See the “Command Descriptions” section above for `setCommandDescriptions()` usage.
873
1109
 
874
1110
  ### Contract Emit Command (`commands/contract-emit.ts`)
875
1111
  - Canonical command implementation using commander
876
- - Supports global flags (JSON, verbosity, color, timestamps)
877
- - **Error Handling**: Uses structured errors (`CliStructuredError`), Result pattern (`performAction`), and `process.exit()`. Commands wrap logic in `performAction()`, process results with `handleResult()`, and call `process.exit(exitCode)` directly. See `.cursor/rules/cli-error-handling.mdc` for details.
1112
+ - Supports global flags (JSON, verbosity, color, interactive, yes)
1113
+ - **Error Handling**: Uses structured errors (`CliStructuredError`), Result pattern, and `process.exit()`. Commands return `Result<T, CliStructuredError>`, process results with `handleResult()`, and call `process.exit(exitCode)` directly. See `.cursor/rules/cli-error-handling.mdc` for details.
878
1114
  - Loads the user's config module (`prisma-next.config.ts`)
879
- - Resolves contract from config:
880
- - Uses `config.contract.source` (supports sync and async functions)
881
- - User's config is responsible for loading the contract (can use `loadContractFromTs` or any other method)
1115
+ - Resolves contract from provider:
1116
+ - Calls `config.contract.source()` and expects `Result<Contract, ContractSourceDiagnostics>`
1117
+ - Source-specific parsing/loading stays inside providers
1118
+ - Provider diagnostics are surfaced as actionable CLI failures
882
1119
  - Throws error if `config.contract` is missing
883
- - Uses artifact paths from `config.contract.output/types` (already normalized by `defineConfig()` with defaults applied)
1120
+ - Uses artifact path from `config.contract.output` (already normalized by `defineConfig()` with defaults applied)
884
1121
  - Creates family instance via `config.family.create()` (assembles operation registry, type imports, extension IDs)
885
1122
  - Calls `familyInstance.emitContract()` with raw contract (instance handles stripping mappings and validation internally)
886
1123
  - Outputs human-readable or JSON format based on flags
887
1124
 
888
1125
  ### Programmatic API (`api/emit-contract.ts`)
889
1126
  - **`emitContract(options)`**: Programmatic API for emitting contracts
890
- - Accepts resolved contract IR, output paths, and assembly data
1127
+ - Accepts resolved contract, output paths, and assembly data
891
1128
  - Caller is responsible for loading the contract and resolving paths
892
1129
  - Returns result with hashes, file paths, and timings
893
1130
  - Used by CLI command internally
894
1131
 
895
1132
  ### Error Handling (`utils/errors.ts`, `utils/cli-errors.ts`, `utils/result.ts`, `utils/result-handler.ts`)
896
1133
  - **Structured Errors**: Call sites throw `CliStructuredError` instances with full context (why, fix, docsUrl, etc.)
897
- - **Result Pattern**: Commands wrap logic in `performAction()` which only catches `CliStructuredError` instances
1134
+ - **Result Pattern**: Commands return `Result<T, CliStructuredError>` and use `handleResult()` for output and exit codes
898
1135
  - **Error Conversion**: `CliStructuredError.toEnvelope()` converts errors to envelopes for output formatting
899
1136
  - **Result Processing**: `handleResult()` processes Results, formats output, and returns exit codes
900
1137
  - **Exit Codes**:
901
1138
  - Usage/config errors (PN-CLI-4001-4007) → exit code 2
902
- - Runtime errors (PN-RTM-3xxx) → exit code 1
1139
+ - Runtime errors (PN-RUN-3xxx) → exit code 1
903
1140
  - Success → exit code 0
904
1141
  - **Fail Fast**: Non-structured errors propagate and are caught by Commander.js's `exitOverride()` with stack traces
905
1142
  - See `.cursor/rules/cli-error-handling.mdc` for detailed patterns
@@ -909,7 +1146,7 @@ See `.cursor/rules/config-validation-and-normalization.mdc` for detailed pattern
909
1146
  - **Removed**: `pack-assembly.ts` has been removed. Pack assembly is now handled by family instances. For SQL family, tests can import pack-based helpers directly from `packages/2-sql/3-tooling/family/src/core/assembly.ts` using relative paths.
910
1147
  - Assembly logic is family-specific and owned by each family's instance implementation (e.g., `createSqlFamilyInstance` in `@prisma-next/family-sql`).
911
1148
 
912
- ### Output Formatting (`utils/output.ts`)
1149
+ ### Output Formatting (`utils/formatters/`)
913
1150
  - **Command Output Formatters**: Format human-readable output for commands (emit, verify, etc.)
914
1151
  - Paths are shown as relative paths from current working directory (using `relative(process.cwd(), path)`)
915
1152
  - Success indicators use consistent checkmark (✔) throughout
@@ -934,7 +1171,7 @@ See `.cursor/rules/config-validation-and-normalization.mdc` for detailed pattern
934
1171
  - `create(options)` - Creates a family instance that implements domain actions
935
1172
  - `hook` - Target family hook for contract emission
936
1173
  - Family instances provide:
937
- - `validateContractIR(contractJson)` - Validates and normalizes contract, returns ContractIR without mappings
1174
+ - `validateContract(contractJson)` - Validates and normalizes contract, returns `Contract` without mappings
938
1175
  - `emitContract(options)` - Emits contract (handles stripping mappings and validation internally)
939
1176
  - `verify(options)` - Verifies database marker against contract
940
1177
  - `schemaVerify(options)` - Verifies database schema against contract
@@ -951,7 +1188,7 @@ See `.cursor/rules/config-validation-and-normalization.mdc` for detailed pattern
951
1188
  - `types.storage`: Storage type bindings (`typeId`, `nativeType`, etc.) used in authoring/emission.
952
1189
  - **`operations`**: Operation signatures the component contributes (extensions), used for type generation and (optionally) validation/lowering.
953
1190
  - **Component-specific metadata**:
954
- - Extensions may also include control-plane-only metadata like `databaseDependencies` (used by verify/schema-verify and not required at runtime).
1191
+ - Extensions may also include control-plane-only metadata like `databaseDependencies` (used by verify and schema verification flows and not required at runtime).
955
1192
 
956
1193
  Unlike the older **manifest-based IR** approach (separate JSON manifests + a parsing/validation step to build an IR), descriptors are imported directly from packages (e.g., `@prisma-next/*/control`). This removes a file-format boundary and keeps the data and its types co-located.
957
1194
  - Benefits: fewer moving parts (no JSON parsing), easier refactors (TypeScript catches drift), and clearer ownership (the package exports the canonical descriptor object).
@@ -1003,6 +1240,9 @@ export default defineConfig({
1003
1240
  - **`commander`**: CLI argument parsing and command routing
1004
1241
  - **`esbuild`**: Bundling TypeScript contract files with import allowlisting
1005
1242
  - **`@prisma-next/emitter`**: Contract emission engine (returns strings)
1243
+ - **`@prisma-next/migration-tools`**: On-disk migration I/O, attestation, and history reconstruction
1244
+ - **`@prisma-next/framework-components`**: Control plane types, migration operation types, control stack (via `./control`)
1245
+ - **`@prisma-next/errors`**: Error types and factories (via `./control`)
1006
1246
 
1007
1247
  ## Design Decisions
1008
1248
 
@@ -1094,8 +1334,9 @@ try {
1094
1334
  await client.connect(databaseUrl);
1095
1335
 
1096
1336
  // Run operations
1097
- const verifyResult = await client.verify({ contractIR });
1098
- const initResult = await client.dbInit({ contractIR, mode: 'apply' });
1337
+ const verifyResult = await client.verify({ contract });
1338
+ const initResult = await client.dbInit({ contract, mode: 'apply' });
1339
+ const updateResult = await client.dbUpdate({ contract, mode: 'apply' });
1099
1340
  const introspectResult = await client.introspect();
1100
1341
  } finally {
1101
1342
  // Clean up
@@ -1109,20 +1350,26 @@ try {
1109
1350
  |--------|-------------|
1110
1351
  | `connect(url)` | Establishes database connection |
1111
1352
  | `close()` | Closes connection (idempotent) |
1353
+ | `readMarker()` | Reads contract marker from database (null if none) |
1112
1354
  | `verify(options)` | Verifies database marker matches contract |
1113
1355
  | `schemaVerify(options)` | Verifies database schema satisfies contract |
1114
1356
  | `sign(options)` | Writes contract marker to database |
1115
1357
  | `dbInit(options)` | Initializes database schema from contract |
1358
+ | `dbUpdate(options)` | Updates database schema to match contract |
1359
+ | `migrationApply(options)` | Applies pre-planned migration edges to database |
1116
1360
  | `introspect(options)` | Introspects database schema |
1117
1361
 
1118
1362
  ### Result Types
1119
1363
 
1120
1364
  Operations return structured result types:
1121
1365
 
1366
+ - `readMarker()` → `ContractMarkerRecord | null`
1122
1367
  - `verify()` → `VerifyDatabaseResult`
1123
1368
  - `schemaVerify()` → `VerifyDatabaseSchemaResult`
1124
1369
  - `sign()` → `SignDatabaseResult`
1125
1370
  - `dbInit()` → `Result<DbInitSuccess, DbInitFailure>` (uses Result pattern)
1371
+ - `dbUpdate()` → `Result<DbUpdateSuccess, DbUpdateFailure>` (uses Result pattern)
1372
+ - `migrationApply()` → `Result<MigrationApplySuccess, MigrationApplyFailure>` (uses Result pattern)
1126
1373
  - `introspect()` → Schema IR (family-specific)
1127
1374
 
1128
1375
  ### Error Handling
@@ -1137,7 +1384,7 @@ Operations return structured result types:
1137
1384
  | Aspect | CLI | Control API |
1138
1385
  |--------|-----|-------------|
1139
1386
  | Config | Reads `prisma-next.config.ts` | Accepts descriptors directly |
1140
- | File I/O | Reads contract.json from disk | Accepts contract IR directly |
1387
+ | File I/O | Reads contract.json from disk | Accepts contract directly |
1141
1388
  | Output | Formats for console | Returns structured data |
1142
1389
  | Exit codes | Uses `process.exit()` | Returns results/throws |
1143
1390
 
@@ -1149,11 +1396,17 @@ The CLI package exports several subpaths for different use cases:
1149
1396
  - **`@prisma-next/cli/config-types`**: Exports `defineConfig` and config types
1150
1397
  - **`@prisma-next/cli/control-api`**: Exports `createControlClient` and control API types
1151
1398
  - **`@prisma-next/cli/commands/db-init`**: Exports `createDbInitCommand`
1152
- - **`@prisma-next/cli/commands/db-introspect`**: Exports `createDbIntrospectCommand`
1153
- - **`@prisma-next/cli/commands/db-schema-verify`**: Exports `createDbSchemaVerifyCommand`
1399
+ - **`@prisma-next/cli/commands/db-update`**: Exports `createDbUpdateCommand`
1400
+ - **`@prisma-next/cli/commands/db-schema`**: Exports `createDbSchemaCommand`
1154
1401
  - **`@prisma-next/cli/commands/db-sign`**: Exports `createDbSignCommand`
1155
1402
  - **`@prisma-next/cli/commands/db-verify`**: Exports `createDbVerifyCommand`
1156
1403
  - **`@prisma-next/cli/commands/contract-emit`**: Exports `createContractEmitCommand`
1404
+ - **`@prisma-next/cli/commands/contract-infer`**: Exports `createContractInferCommand`
1405
+ - **`@prisma-next/cli/commands/migration-plan`**: Exports `createMigrationPlanCommand`
1406
+ - **`@prisma-next/cli/commands/migration-show`**: Exports `createMigrationShowCommand`
1407
+ - **`@prisma-next/cli/commands/migration-status`**: Exports `createMigrationStatusCommand`
1408
+ - **`@prisma-next/cli/commands/migration-apply`**: Exports `createMigrationApplyCommand`
1409
+ - **`@prisma-next/cli/commands/migration-verify`**: Exports `createMigrationVerifyCommand`
1157
1410
  - **`@prisma-next/cli/config-loader`**: Exports `loadConfig` function
1158
1411
 
1159
1412
  **Important**: `loadContractFromTs` is exported from the main package (`@prisma-next/cli`). See `.cursor/rules/cli-package-exports.mdc` for import patterns.