@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
@@ -0,0 +1,276 @@
1
+ import * as clack from '@clack/prompts';
2
+ import { bold, cyan, dim, green, red, yellow } from 'colorette';
3
+ import { shutdownSignal } from './shutdown';
4
+
5
+ /**
6
+ * Composable CLI output abstraction.
7
+ *
8
+ * Follows the Unix convention of separating data from decoration:
9
+ * - **stdout** — data output only (`ui.output()`). This is what scripts and pipes capture.
10
+ * - **stderr** — all decoration (spinners, logs, notes, intro/outro). Visible in terminal, invisible in pipes.
11
+ *
12
+ * Rules:
13
+ * 1. All methods except `output()` and `error()` write to stderr only in interactive mode.
14
+ * 2. `output(data)` always writes to stdout — if a command calls it, there is data to emit.
15
+ * 3. `error()` always writes to stderr — errors matter even when piped.
16
+ * 4. All other decoration is suppressed when piped — `isInteractive` gates every other decoration method.
17
+ * 5. Never write data to stderr — decoration methods are for human context only.
18
+ * 6. Never write decoration to stdout — it breaks pipes, `$(...)` captures, and `> file` redirects.
19
+ */
20
+ export class TerminalUI {
21
+ /**
22
+ * True when stdout is a TTY (interactive terminal).
23
+ * False when piped (e.g., `prisma-next db verify | jq`).
24
+ */
25
+ readonly isInteractive: boolean;
26
+
27
+ /**
28
+ * Whether color output is enabled.
29
+ */
30
+ readonly useColor: boolean;
31
+
32
+ private static readonly stderrOpts = { output: process.stderr } as const;
33
+
34
+ constructor(options?: {
35
+ readonly color?: boolean | undefined;
36
+ readonly interactive?: boolean | undefined;
37
+ }) {
38
+ // --interactive/--no-interactive override TTY detection
39
+ this.isInteractive = options?.interactive ?? !!process.stdout.isTTY;
40
+ this.useColor = options?.color ?? this.isInteractive;
41
+ }
42
+
43
+ // ---------------------------------------------------------------------------
44
+ // Decoration → stderr (only in interactive mode)
45
+ // ---------------------------------------------------------------------------
46
+
47
+ /**
48
+ * Log a message line to stderr. No-op when piped.
49
+ */
50
+ log(message: string): void {
51
+ if (!this.isInteractive) return;
52
+ clack.log.message(message, TerminalUI.stderrOpts);
53
+ }
54
+
55
+ /**
56
+ * Log a success message to stderr. No-op when piped.
57
+ */
58
+ success(message: string): void {
59
+ if (!this.isInteractive) return;
60
+ clack.log.success(message, TerminalUI.stderrOpts);
61
+ }
62
+
63
+ /**
64
+ * Log a warning message to stderr. No-op when piped.
65
+ */
66
+ warn(message: string): void {
67
+ if (!this.isInteractive) return;
68
+ clack.log.warn(message, TerminalUI.stderrOpts);
69
+ }
70
+
71
+ /**
72
+ * Log an error message to stderr. Always writes (errors matter even in pipes).
73
+ */
74
+ error(message: string): void {
75
+ clack.log.error(message, TerminalUI.stderrOpts);
76
+ }
77
+
78
+ /**
79
+ * Log an info message to stderr. No-op when piped.
80
+ */
81
+ info(message: string): void {
82
+ if (!this.isInteractive) return;
83
+ clack.log.info(message, TerminalUI.stderrOpts);
84
+ }
85
+
86
+ /**
87
+ * Log a step message to stderr. No-op when piped.
88
+ */
89
+ step(message: string): void {
90
+ if (!this.isInteractive) return;
91
+ clack.log.step(message, TerminalUI.stderrOpts);
92
+ }
93
+
94
+ /**
95
+ * Display a note box on stderr. No-op when piped.
96
+ */
97
+ note(message: string, title?: string): void {
98
+ if (!this.isInteractive) return;
99
+ clack.note(message, title, TerminalUI.stderrOpts);
100
+ }
101
+
102
+ /**
103
+ * Display intro banner on stderr. No-op when piped.
104
+ */
105
+ intro(title?: string): void {
106
+ if (!this.isInteractive) return;
107
+ clack.intro(title, TerminalUI.stderrOpts);
108
+ }
109
+
110
+ /**
111
+ * Display outro banner on stderr. No-op when piped.
112
+ */
113
+ outro(message?: string): void {
114
+ if (!this.isInteractive) return;
115
+ clack.outro(message, TerminalUI.stderrOpts);
116
+ }
117
+
118
+ /**
119
+ * Create a Clack spinner on stderr with a 100ms delay threshold.
120
+ * The spinner only appears if the operation takes longer than the threshold,
121
+ * avoiding flicker for fast operations. Returns a no-op spinner when not interactive.
122
+ */
123
+ spinner(delayMs = 100): clack.SpinnerResult {
124
+ const noop: clack.SpinnerResult = {
125
+ start: () => {},
126
+ stop: () => {},
127
+ cancel: () => {},
128
+ error: () => {},
129
+ message: () => {},
130
+ clear: () => {},
131
+ get isCancelled() {
132
+ return false;
133
+ },
134
+ };
135
+
136
+ if (!this.isInteractive) {
137
+ return noop;
138
+ }
139
+
140
+ // Wrap the real spinner with a delay: only show it after `delayMs`
141
+ let inner: clack.SpinnerResult | undefined;
142
+ let timer: ReturnType<typeof setTimeout> | undefined;
143
+ let pendingMsg: string | undefined;
144
+ let settled = false;
145
+
146
+ const ensureCleared = () => {
147
+ if (timer !== undefined) {
148
+ clearTimeout(timer);
149
+ timer = undefined;
150
+ }
151
+ };
152
+
153
+ // Cancel the spinner if a shutdown signal fires
154
+ const onAbort = () => {
155
+ if (!settled) {
156
+ settled = true;
157
+ ensureCleared();
158
+ if (inner) {
159
+ inner.cancel('Interrupted');
160
+ }
161
+ }
162
+ };
163
+ if (!shutdownSignal.aborted) {
164
+ shutdownSignal.addEventListener('abort', onAbort, { once: true });
165
+ }
166
+
167
+ return {
168
+ start(msg?: string) {
169
+ pendingMsg = msg;
170
+ timer = setTimeout(() => {
171
+ if (!settled) {
172
+ inner = clack.spinner(TerminalUI.stderrOpts);
173
+ inner.start(pendingMsg);
174
+ }
175
+ }, delayMs);
176
+ },
177
+ stop(msg?: string) {
178
+ settled = true;
179
+ ensureCleared();
180
+ if (inner) {
181
+ inner.stop(msg);
182
+ }
183
+ },
184
+ cancel(msg?: string) {
185
+ settled = true;
186
+ ensureCleared();
187
+ if (inner) {
188
+ inner.cancel(msg);
189
+ }
190
+ },
191
+ error(msg?: string) {
192
+ settled = true;
193
+ ensureCleared();
194
+ if (inner) {
195
+ inner.error(msg);
196
+ }
197
+ },
198
+ message(msg?: string) {
199
+ pendingMsg = msg;
200
+ if (inner) {
201
+ inner.message(msg);
202
+ }
203
+ },
204
+ clear() {
205
+ settled = true;
206
+ ensureCleared();
207
+ if (inner) {
208
+ inner.clear();
209
+ }
210
+ },
211
+ get isCancelled() {
212
+ return inner?.isCancelled ?? false;
213
+ },
214
+ };
215
+ }
216
+
217
+ /**
218
+ * Prompt for yes/no confirmation on stderr. Returns true if confirmed.
219
+ * In non-interactive mode or when cancelled (Ctrl-C), returns false.
220
+ */
221
+ async confirm(message: string): Promise<boolean> {
222
+ if (!this.isInteractive) return false;
223
+ const result = await clack.confirm({
224
+ message,
225
+ ...TerminalUI.stderrOpts,
226
+ });
227
+ if (clack.isCancel(result)) return false;
228
+ return result;
229
+ }
230
+
231
+ /**
232
+ * Write a raw line to stderr. No-op when piped.
233
+ * Use for decoration that doesn't fit Clack's log format (e.g. styled headers).
234
+ */
235
+ stderr(message: string): void {
236
+ if (!this.isInteractive) return;
237
+ process.stderr.write(`${message}\n`);
238
+ }
239
+
240
+ // ---------------------------------------------------------------------------
241
+ // Data → stdout (only when piped)
242
+ // ---------------------------------------------------------------------------
243
+
244
+ /**
245
+ * Write machine-readable data to stdout.
246
+ * Always writes — if a command calls output(), there is data to emit.
247
+ *
248
+ * This is what scripts and pipes capture: `prisma-next db verify --json | jq .ok`
249
+ */
250
+ output(data: string): void {
251
+ process.stdout.write(`${data}\n`);
252
+ }
253
+
254
+ // ---------------------------------------------------------------------------
255
+ // Color helpers
256
+ // ---------------------------------------------------------------------------
257
+
258
+ green(text: string): string {
259
+ return this.useColor ? green(text) : text;
260
+ }
261
+ red(text: string): string {
262
+ return this.useColor ? red(text) : text;
263
+ }
264
+ cyan(text: string): string {
265
+ return this.useColor ? cyan(text) : text;
266
+ }
267
+ dim(text: string): string {
268
+ return this.useColor ? dim(text) : text;
269
+ }
270
+ bold(text: string): string {
271
+ return this.useColor ? bold(text) : text;
272
+ }
273
+ yellow(text: string): string {
274
+ return this.useColor ? yellow(text) : text;
275
+ }
276
+ }
@@ -0,0 +1,49 @@
1
+ import { createRequire } from 'node:module';
2
+
3
+ const IMPORT_PATTERN = /import\s+type\s+.*?\s+from\s+['"](@[^/]+\/[^/'"]+)/g;
4
+
5
+ export function extractPackageSpecifiers(dtsContent: string): string[] {
6
+ const packages = new Set<string>();
7
+ for (const match of dtsContent.matchAll(IMPORT_PATTERN)) {
8
+ const pkg = match[1];
9
+ if (pkg) packages.add(pkg);
10
+ }
11
+ return [...packages];
12
+ }
13
+
14
+ export interface ContractDepsValidation {
15
+ readonly missing: readonly string[];
16
+ readonly warning?: string;
17
+ }
18
+
19
+ export function validateContractDeps(
20
+ dtsContent: string,
21
+ projectRoot: string,
22
+ ): ContractDepsValidation {
23
+ const packages = extractPackageSpecifiers(dtsContent);
24
+ const resolve = createRequire(`${projectRoot}/package.json`);
25
+
26
+ const missing: string[] = [];
27
+ for (const pkg of packages) {
28
+ try {
29
+ resolve.resolve(`${pkg}/package.json`);
30
+ } catch {
31
+ missing.push(pkg);
32
+ }
33
+ }
34
+
35
+ if (missing.length === 0) {
36
+ return { missing };
37
+ }
38
+
39
+ const list = missing.map((p) => ` - ${p}`).join('\n');
40
+ const warning = [
41
+ 'contract.d.ts imports types from packages that are not installed:',
42
+ list,
43
+ '',
44
+ 'Install them with your package manager:',
45
+ ...missing.map((p) => ` ${p}`),
46
+ ].join('\n');
47
+
48
+ return { missing, warning };
49
+ }