@prisma-next/cli 0.3.0-pr.99.5 → 0.3.0

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 +261 -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 +9 -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 +10 -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 +126 -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 +56 -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 +137 -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 +123 -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 +323 -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 +245 -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 +9 -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-Zm_sd1wQ.mjs +112 -0
  74. package/dist/contract-emit-Zm_sd1wQ.mjs.map +1 -0
  75. package/dist/contract-emit-kN-IkKTE.mjs +6 -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 +8 -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 +142 -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-6Pvm_esG.mjs +430 -0
  96. package/dist/init-6Pvm_esG.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,697 @@
1
+ import { relative, resolve } from "pathe";
2
+ import { hasMigrations } from "@prisma-next/framework-components/control";
3
+ import { ifDefined } from "@prisma-next/utils/defined";
4
+ import { readFile } from "node:fs/promises";
5
+ import { reconstructGraph } from "@prisma-next/migration-tools/dag";
6
+ import { readMigrationsDir } from "@prisma-next/migration-tools/io";
7
+ import { isAttested, isDraft } from "@prisma-next/migration-tools/types";
8
+ import { blue, bold, cyan, dim, green, magenta, red } from "colorette";
9
+ import wrapAnsi from "wrap-ansi";
10
+ import stringWidth from "string-width";
11
+ import stripAnsi from "strip-ansi";
12
+
13
+ //#region src/utils/formatters/helpers.ts
14
+ /**
15
+ * Checks if verbose output is enabled at the specified level.
16
+ */
17
+ function isVerbose(flags, level) {
18
+ return (flags.verbose ?? 0) >= level;
19
+ }
20
+ /**
21
+ * Creates a color-aware formatter function.
22
+ * Returns a function that applies the color only if colors are enabled.
23
+ */
24
+ function createColorFormatter(useColor, colorFn) {
25
+ return useColor ? colorFn : (text) => text;
26
+ }
27
+ /**
28
+ * Formats text with dim styling if colors are enabled.
29
+ */
30
+ function formatDim(useColor, text) {
31
+ return useColor ? dim(text) : text;
32
+ }
33
+
34
+ //#endregion
35
+ //#region src/utils/formatters/styled.ts
36
+ /**
37
+ * Fixed width for left column in help output.
38
+ */
39
+ const LEFT_COLUMN_WIDTH$1 = 20;
40
+ /**
41
+ * Creates an arrow segment badge with green background and white text.
42
+ * Body: green background with white "prisma-next" text
43
+ * Tip: dark grey arrow pointing right (Powerline separator)
44
+ */
45
+ function createPrismaNextBadge$1(useColor) {
46
+ if (!useColor) return "prisma-next";
47
+ return bold("prisma-next");
48
+ }
49
+ /**
50
+ * Creates a padding function.
51
+ */
52
+ function createPadFunction() {
53
+ return (s, w) => s + " ".repeat(Math.max(0, w - s.length));
54
+ }
55
+ /**
56
+ * Formats a header line: brand + operation + intent
57
+ */
58
+ function formatHeaderLine$1(options) {
59
+ if (options.operation) return `${options.brand} ${options.operation} → ${options.intent}`;
60
+ return `${options.brand} ${options.intent}`;
61
+ }
62
+ /**
63
+ * Formats a "Read more" URL line.
64
+ * The "Read more" label is in default color (not cyan), and the URL is blue.
65
+ */
66
+ function formatReadMoreLine$1(options) {
67
+ const labelPadded = createPadFunction()("Read more", options.maxLabelWidth);
68
+ const valueColored = options.useColor ? blue(options.url) : options.url;
69
+ return `${options.formatDimText("│")} ${labelPadded} ${valueColored}`;
70
+ }
71
+ /**
72
+ * Pads text to a fixed width, accounting for ANSI escape codes.
73
+ * Uses string-width to measure the actual display width.
74
+ */
75
+ function padToFixedWidth(text, width) {
76
+ const actualWidth = stringWidth(text);
77
+ const padding = Math.max(0, width - actualWidth);
78
+ return text + " ".repeat(padding);
79
+ }
80
+ /**
81
+ * Renders a command tree structure.
82
+ * Handles both single-level (subcommands of a command) and multi-level (top-level commands with subcommands) trees.
83
+ */
84
+ function renderCommandTree(options) {
85
+ const { commands, useColor, formatDimText, hasItemsAfter, continuationPrefix } = options;
86
+ const lines = [];
87
+ if (commands.length === 0) return lines;
88
+ for (let i = 0; i < commands.length; i++) {
89
+ const cmd = commands[i];
90
+ if (!cmd) continue;
91
+ const subcommands = cmd.commands.filter((subcmd) => !subcmd.name().startsWith("_"));
92
+ const isLastCommand = i === commands.length - 1;
93
+ if (subcommands.length > 0) {
94
+ const treePrefix = `${isLastCommand && !hasItemsAfter ? formatDimText("└") : formatDimText("├")}─ `;
95
+ const remainingWidth = LEFT_COLUMN_WIDTH$1 - stringWidth(stripAnsi(treePrefix));
96
+ const commandNamePadded = padToFixedWidth(cmd.name(), remainingWidth);
97
+ const commandNameColored = useColor ? cyan(commandNamePadded) : commandNamePadded;
98
+ lines.push(`${formatDimText("│")} ${treePrefix}${commandNameColored}`);
99
+ for (let j = 0; j < subcommands.length; j++) {
100
+ const subcmd = subcommands[j];
101
+ if (!subcmd) continue;
102
+ const isLastSubcommand = j === subcommands.length - 1;
103
+ const shortDescription = subcmd.description() || "";
104
+ const treeChar = isLastSubcommand ? "└" : "├";
105
+ const continuation = continuationPrefix ?? (isLastCommand && isLastSubcommand && !hasItemsAfter ? " " : formatDimText("│"));
106
+ const subTreePrefix = `${continuation === " " ? " " : continuation} ${formatDimText(treeChar)}─ `;
107
+ const subRemainingWidth = LEFT_COLUMN_WIDTH$1 - stringWidth(stripAnsi(subTreePrefix));
108
+ const subcommandNamePadded = padToFixedWidth(subcmd.name(), subRemainingWidth);
109
+ const subcommandNameColored = useColor ? cyan(subcommandNamePadded) : subcommandNamePadded;
110
+ lines.push(`${formatDimText("│")} ${subTreePrefix}${subcommandNameColored} ${shortDescription}`);
111
+ }
112
+ } else {
113
+ const treePrefix = `${isLastCommand && !hasItemsAfter ? formatDimText("└") : formatDimText("├")}─ `;
114
+ const remainingWidth = LEFT_COLUMN_WIDTH$1 - stringWidth(stripAnsi(treePrefix));
115
+ const commandNamePadded = padToFixedWidth(cmd.name(), remainingWidth);
116
+ const commandNameColored = useColor ? cyan(commandNamePadded) : commandNamePadded;
117
+ const shortDescription = cmd.description() || "";
118
+ lines.push(`${formatDimText("│")} ${treePrefix}${commandNameColored} ${shortDescription}`);
119
+ }
120
+ }
121
+ return lines;
122
+ }
123
+ /**
124
+ * Formats the header in the new experimental visual style.
125
+ * This header appears at the start of command output, showing the operation,
126
+ * intent, documentation link, and parameters.
127
+ */
128
+ function formatStyledHeader(options) {
129
+ const lines = [];
130
+ const useColor = options.flags.color !== false;
131
+ const formatDimText = (text) => formatDim(useColor, text);
132
+ const brand = createPrismaNextBadge$1(useColor);
133
+ const operation = useColor ? bold(options.command) : options.command;
134
+ const intent = formatDimText(options.description);
135
+ lines.push(formatHeaderLine$1({
136
+ brand,
137
+ operation,
138
+ intent
139
+ }));
140
+ lines.push(formatDimText("│"));
141
+ for (const detail of options.details) {
142
+ const labelPadded = padToFixedWidth(`${detail.label}:`, LEFT_COLUMN_WIDTH$1);
143
+ const labelColored = useColor ? cyan(labelPadded) : labelPadded;
144
+ lines.push(`${formatDimText("│")} ${labelColored} ${detail.value}`);
145
+ }
146
+ if (options.url) {
147
+ lines.push(formatDimText("│"));
148
+ lines.push(formatReadMoreLine$1({
149
+ url: options.url,
150
+ maxLabelWidth: LEFT_COLUMN_WIDTH$1,
151
+ useColor,
152
+ formatDimText
153
+ }));
154
+ }
155
+ lines.push(formatDimText("└"));
156
+ return `${lines.join("\n")}\n`;
157
+ }
158
+ /**
159
+ * Formats a success message in the styled output format.
160
+ */
161
+ function formatSuccessMessage(flags) {
162
+ return `${createColorFormatter(flags.color !== false, green)("✔")} Success`;
163
+ }
164
+
165
+ //#endregion
166
+ //#region src/utils/formatters/help.ts
167
+ /**
168
+ * Fixed width for left column in help output.
169
+ * Must match the value in styled.ts.
170
+ */
171
+ const LEFT_COLUMN_WIDTH = 20;
172
+ /**
173
+ * Minimum width for right column wrapping in help output.
174
+ */
175
+ const RIGHT_COLUMN_MIN_WIDTH = 40;
176
+ /**
177
+ * Maximum width for right column wrapping in help output (when terminal is wide enough).
178
+ */
179
+ const RIGHT_COLUMN_MAX_WIDTH = 90;
180
+ /**
181
+ * Gets the terminal width, or returns a default if not available.
182
+ */
183
+ function getTerminalWidth() {
184
+ const terminalWidth = process.stderr.columns || process.stdout.columns;
185
+ const envWidth = Number.parseInt(process.env["CLI_WIDTH"] || "", 10);
186
+ return terminalWidth || (Number.isFinite(envWidth) ? envWidth : 80);
187
+ }
188
+ /**
189
+ * Calculates the available width for the right column based on terminal width.
190
+ */
191
+ function calculateRightColumnWidth() {
192
+ const availableWidth = getTerminalWidth() - 2 - LEFT_COLUMN_WIDTH - 2;
193
+ return Math.max(RIGHT_COLUMN_MIN_WIDTH, Math.min(availableWidth, RIGHT_COLUMN_MAX_WIDTH));
194
+ }
195
+ /**
196
+ * Creates the CLI brand badge.
197
+ */
198
+ function createPrismaNextBadge(useColor) {
199
+ return useColor ? bold("prisma-next") : "prisma-next";
200
+ }
201
+ /**
202
+ * Formats a header line: brand + operation + intent
203
+ */
204
+ function formatHeaderLine(options) {
205
+ if (options.operation) return `${options.brand} ${options.operation} → ${options.intent}`;
206
+ return `${options.brand} ${options.intent}`;
207
+ }
208
+ /**
209
+ * Wraps text to fit within a specified width using wrap-ansi.
210
+ */
211
+ function wrapTextAnsi(text, width) {
212
+ return wrapAnsi(text, width, {
213
+ hard: false,
214
+ trim: true
215
+ }).split("\n");
216
+ }
217
+ /**
218
+ * Formats a default value as "default: <value>" with dimming.
219
+ */
220
+ function formatDefaultValue(value, useColor) {
221
+ const defaultText = `default: ${String(value)}`;
222
+ return useColor ? dim(defaultText) : defaultText;
223
+ }
224
+ /**
225
+ * Formats a "Read more" URL line.
226
+ */
227
+ function formatReadMoreLine(options) {
228
+ const labelPadded = `Read more${" ".repeat(Math.max(0, options.maxLabelWidth - 9))}`;
229
+ const valueColored = options.useColor ? blue(options.url) : options.url;
230
+ return `${options.formatDimText("│")} ${labelPadded} ${valueColored}`;
231
+ }
232
+ /**
233
+ * Formats multiline description with "Prisma Next" in green.
234
+ */
235
+ function formatMultilineDescription(options) {
236
+ const lines = [];
237
+ const formatGreen = (text) => options.useColor ? green(text) : text;
238
+ const rightColumnWidth = calculateRightColumnWidth();
239
+ const wrapWidth = 2 + LEFT_COLUMN_WIDTH + 2 + rightColumnWidth - 2;
240
+ for (const descLine of options.descriptionLines) {
241
+ const wrappedLines = wrapTextAnsi(descLine.replace(/Prisma Next/g, (match) => formatGreen(match)), wrapWidth);
242
+ for (const wrappedLine of wrappedLines) lines.push(`${options.formatDimText("│")} ${wrappedLine}`);
243
+ }
244
+ return lines;
245
+ }
246
+ /**
247
+ * Maps command paths to their documentation URLs.
248
+ */
249
+ function getCommandDocsUrl(commandPath) {
250
+ return {
251
+ "contract emit": "https://pris.ly/contract-emit",
252
+ "contract infer": "https://pris.ly/contract-infer",
253
+ "db schema": "https://pris.ly/db-schema",
254
+ "db verify": "https://pris.ly/db-verify",
255
+ "db update": "https://pris.ly/db-update",
256
+ "migration plan": "https://pris.ly/migration-plan",
257
+ "migration apply": "https://pris.ly/migration-apply",
258
+ "migration show": "https://pris.ly/migration-show",
259
+ "migration status": "https://pris.ly/migration-status",
260
+ "migration verify": "https://pris.ly/migration-verify"
261
+ }[commandPath];
262
+ }
263
+ /**
264
+ * Builds the full command path from a command and its parents.
265
+ */
266
+ function buildCommandPath(command) {
267
+ const parts = [];
268
+ let current = command;
269
+ while (current && current.name() !== "prisma-next") {
270
+ parts.unshift(current.name());
271
+ current = current.parent ?? void 0;
272
+ }
273
+ return parts.join(" ");
274
+ }
275
+ /**
276
+ * Formats help output for a command using the styled format.
277
+ */
278
+ function formatCommandHelp(options) {
279
+ const { command, flags } = options;
280
+ const lines = [];
281
+ const useColor = flags.color !== false;
282
+ const formatDimText = (text) => formatDim(useColor, text);
283
+ const commandPath = buildCommandPath(command);
284
+ const shortDescription = command.description() || "";
285
+ const longDescription = getLongDescription(command);
286
+ const argsSuffix = command.registeredArguments.map((arg) => arg.required ? `<${arg.name()}>` : `[${arg.name()}]`).join(" ");
287
+ const brand = createPrismaNextBadge(useColor);
288
+ const commandWithArgs = argsSuffix ? `${commandPath} ${argsSuffix}` : commandPath;
289
+ const operation = useColor ? bold(commandWithArgs) : commandWithArgs;
290
+ const intent = formatDimText(shortDescription);
291
+ lines.push(formatHeaderLine({
292
+ brand,
293
+ operation,
294
+ intent
295
+ }));
296
+ lines.push(formatDimText("│"));
297
+ const optionsList = command.options.map((opt) => {
298
+ const description = opt.description || "";
299
+ const defaultValue = opt.defaultValue;
300
+ return {
301
+ flags: opt.flags,
302
+ description,
303
+ defaultValue
304
+ };
305
+ });
306
+ const subcommands = command.commands.filter((cmd) => !cmd.name().startsWith("_"));
307
+ if (subcommands.length > 0) {
308
+ const treeLines = renderCommandTree({
309
+ commands: subcommands,
310
+ useColor,
311
+ formatDimText,
312
+ hasItemsAfter: optionsList.length > 0
313
+ });
314
+ lines.push(...treeLines);
315
+ }
316
+ if (subcommands.length > 0 && optionsList.length > 0) lines.push(formatDimText("│"));
317
+ if (optionsList.length > 0) for (const opt of optionsList) {
318
+ const flagsPadded = padToFixedWidth(opt.flags, LEFT_COLUMN_WIDTH);
319
+ let flagsColored = flagsPadded;
320
+ if (useColor) {
321
+ flagsColored = flagsPadded.replace(/(<[^>]+>)/g, (match) => magenta(match));
322
+ flagsColored = cyan(flagsColored);
323
+ }
324
+ const rightColumnWidth = calculateRightColumnWidth();
325
+ const wrappedDescription = wrapTextAnsi(opt.description, rightColumnWidth);
326
+ lines.push(`${formatDimText("│")} ${flagsColored} ${wrappedDescription[0] || ""}`);
327
+ for (let i = 1; i < wrappedDescription.length; i++) {
328
+ const emptyLabel = " ".repeat(LEFT_COLUMN_WIDTH);
329
+ lines.push(`${formatDimText("│")} ${emptyLabel} ${wrappedDescription[i] || ""}`);
330
+ }
331
+ if (opt.defaultValue !== void 0) {
332
+ const emptyLabel = " ".repeat(LEFT_COLUMN_WIDTH);
333
+ const defaultText = formatDefaultValue(opt.defaultValue, useColor);
334
+ lines.push(`${formatDimText("│")} ${emptyLabel} ${defaultText}`);
335
+ }
336
+ }
337
+ const docsUrl = getCommandDocsUrl(commandPath);
338
+ if (docsUrl) {
339
+ lines.push(formatDimText("│"));
340
+ lines.push(formatReadMoreLine({
341
+ url: docsUrl,
342
+ maxLabelWidth: LEFT_COLUMN_WIDTH,
343
+ useColor,
344
+ formatDimText
345
+ }));
346
+ }
347
+ const examples = getCommandExamples(command);
348
+ if (examples && examples.length > 0) {
349
+ lines.push(formatDimText("│"));
350
+ lines.push(`${formatDimText("│")} ${formatDimText("Examples:")}`);
351
+ for (const example of examples) lines.push(`${formatDimText("│")} ${useColor ? dim("$") : "$"} ${example}`);
352
+ }
353
+ if (longDescription) {
354
+ lines.push(formatDimText("│"));
355
+ const descriptionLines = longDescription.split("\n").filter((line) => line.trim().length > 0);
356
+ lines.push(...formatMultilineDescription({
357
+ descriptionLines,
358
+ useColor,
359
+ formatDimText
360
+ }));
361
+ }
362
+ lines.push(formatDimText("└"));
363
+ return `${lines.join("\n")}\n`;
364
+ }
365
+ /**
366
+ * Formats help output for the root program using the styled format.
367
+ */
368
+ function formatRootHelp(options) {
369
+ const { program, flags } = options;
370
+ const lines = [];
371
+ const useColor = flags.color !== false;
372
+ const formatDimText = (text) => formatDim(useColor, text);
373
+ const brand = createPrismaNextBadge(useColor);
374
+ const intent = formatDimText("Manage your data layer");
375
+ lines.push(formatHeaderLine({
376
+ brand,
377
+ operation: "",
378
+ intent
379
+ }));
380
+ lines.push(formatDimText("│"));
381
+ const topLevelCommands = program.commands.filter((cmd) => !cmd.name().startsWith("_") && cmd.name() !== "help");
382
+ const globalOptions = program.options.map((opt) => {
383
+ const description = opt.description || "";
384
+ const defaultValue = opt.defaultValue;
385
+ return {
386
+ flags: opt.flags,
387
+ description,
388
+ defaultValue
389
+ };
390
+ });
391
+ if (topLevelCommands.length > 0) {
392
+ const treeLines = renderCommandTree({
393
+ commands: topLevelCommands,
394
+ useColor,
395
+ formatDimText,
396
+ hasItemsAfter: globalOptions.length > 0
397
+ });
398
+ lines.push(...treeLines);
399
+ }
400
+ if (topLevelCommands.length > 0 && globalOptions.length > 0) lines.push(formatDimText("│"));
401
+ if (globalOptions.length > 0) for (const opt of globalOptions) {
402
+ const flagsPadded = padToFixedWidth(opt.flags, LEFT_COLUMN_WIDTH);
403
+ let flagsColored = flagsPadded;
404
+ if (useColor) {
405
+ flagsColored = flagsPadded.replace(/(<[^>]+>)/g, (match) => magenta(match));
406
+ flagsColored = cyan(flagsColored);
407
+ }
408
+ const rightColumnWidth = calculateRightColumnWidth();
409
+ const wrappedDescription = wrapTextAnsi(opt.description, rightColumnWidth);
410
+ lines.push(`${formatDimText("│")} ${flagsColored} ${wrappedDescription[0] || ""}`);
411
+ for (let i = 1; i < wrappedDescription.length; i++) {
412
+ const emptyLabel = " ".repeat(LEFT_COLUMN_WIDTH);
413
+ lines.push(`${formatDimText("│")} ${emptyLabel} ${wrappedDescription[i] || ""}`);
414
+ }
415
+ if (opt.defaultValue !== void 0) {
416
+ const emptyLabel = " ".repeat(LEFT_COLUMN_WIDTH);
417
+ const defaultText = formatDefaultValue(opt.defaultValue, useColor);
418
+ lines.push(`${formatDimText("│")} ${emptyLabel} ${defaultText}`);
419
+ }
420
+ }
421
+ const formatGreen = (text) => useColor ? green(text) : text;
422
+ const descriptionLines = [`Use ${formatGreen("Prisma Next")} to define your data layer as a contract. Sign your database and application with the same contract to guarantee compatibility. Plan and apply migrations to safely evolve your schema.`];
423
+ if (descriptionLines.length > 0) {
424
+ lines.push(formatDimText("│"));
425
+ lines.push(...formatMultilineDescription({
426
+ descriptionLines,
427
+ useColor,
428
+ formatDimText
429
+ }));
430
+ }
431
+ lines.push(formatDimText("└"));
432
+ return `${lines.join("\n")}\n`;
433
+ }
434
+
435
+ //#endregion
436
+ //#region src/utils/global-flags.ts
437
+ /**
438
+ * Parses global flags from CLI options.
439
+ * Handles verbosity flags (-v, --trace), JSON output, quiet mode, color,
440
+ * interactivity (--interactive/--no-interactive), and auto-accept (-y/--yes).
441
+ */
442
+ function parseGlobalFlags(options) {
443
+ const flags = {};
444
+ if (options.json || !process.stdout.isTTY) flags.json = true;
445
+ if (options.quiet || options.q) flags.quiet = true;
446
+ if (options.trace || process.env["PRISMA_NEXT_TRACE"] === "1") flags.verbose = 2;
447
+ else if (options.verbose || options.v || process.env["PRISMA_NEXT_DEBUG"] === "1") flags.verbose = 1;
448
+ else flags.verbose = 0;
449
+ if (process.env["NO_COLOR"] || flags.json) flags.color = false;
450
+ else if (options["no-color"]) flags.color = false;
451
+ else if (options.color !== void 0) flags.color = options.color;
452
+ else flags.color = process.stdout.isTTY && !process.env["CI"];
453
+ if (options["no-interactive"]) flags.interactive = false;
454
+ else if (options.interactive !== void 0) flags.interactive = options.interactive;
455
+ else flags.interactive = !!process.stdout.isTTY;
456
+ if (options.yes || options.y) flags.yes = true;
457
+ return flags;
458
+ }
459
+
460
+ //#endregion
461
+ //#region src/utils/command-helpers.ts
462
+ const longDescriptions = /* @__PURE__ */ new WeakMap();
463
+ const commandExamples = /* @__PURE__ */ new WeakMap();
464
+ /**
465
+ * Sets both short and long descriptions for a command.
466
+ * The short description is used in command trees and headers.
467
+ * The long description is shown at the bottom of help output.
468
+ */
469
+ function setCommandDescriptions(command, shortDescription, longDescription) {
470
+ command.description(shortDescription);
471
+ if (longDescription) longDescriptions.set(command, longDescription);
472
+ return command;
473
+ }
474
+ /**
475
+ * Sets copy-pastable examples for a command, shown in help text.
476
+ */
477
+ function setCommandExamples(command, examples) {
478
+ commandExamples.set(command, examples);
479
+ return command;
480
+ }
481
+ /**
482
+ * Gets the long description from a command if it was set via setCommandDescriptions.
483
+ */
484
+ function getLongDescription(command) {
485
+ return longDescriptions.get(command);
486
+ }
487
+ /**
488
+ * Gets examples from a command if set via setCommandExamples.
489
+ */
490
+ function getCommandExamples(command) {
491
+ return commandExamples.get(command);
492
+ }
493
+ /**
494
+ * Resolves the absolute path to contract.json from the config.
495
+ * Centralises the fallback logic shared by every command that reads the contract.
496
+ */
497
+ function resolveContractPath(config) {
498
+ return config.contract?.output ? resolve(config.contract.output) : resolve("src/prisma/contract.json");
499
+ }
500
+ /**
501
+ * Resolves the migrations directory and config path from CLI options.
502
+ * Shared by migration-apply, migration-plan, and migration-status.
503
+ */
504
+ function resolveMigrationPaths(configOption, config) {
505
+ const configPath = configOption ? relative(process.cwd(), resolve(configOption)) : "prisma-next.config.ts";
506
+ const migrationsDir = resolve(configOption ? resolve(configOption, "..") : process.cwd(), config.migrations?.dir ?? "migrations");
507
+ return {
508
+ configPath,
509
+ migrationsDir,
510
+ migrationsRelative: relative(process.cwd(), migrationsDir),
511
+ refsPath: resolve(migrationsDir, "refs.json")
512
+ };
513
+ }
514
+ /**
515
+ * Maps a PathDecision to the slim CLI output representation.
516
+ */
517
+ function toPathDecisionResult(decision) {
518
+ return {
519
+ fromHash: decision.fromHash,
520
+ toHash: decision.toHash,
521
+ alternativeCount: decision.alternativeCount,
522
+ tieBreakReasons: decision.tieBreakReasons,
523
+ ...ifDefined("refName", decision.refName),
524
+ selectedPath: decision.selectedPath.map((entry) => ({
525
+ dirName: entry.dirName,
526
+ migrationId: entry.migrationId,
527
+ from: entry.from,
528
+ to: entry.to
529
+ }))
530
+ };
531
+ }
532
+ function targetSupportsMigrations(target) {
533
+ return hasMigrations(target);
534
+ }
535
+ function getTargetMigrations(target) {
536
+ return hasMigrations(target) ? target.migrations : void 0;
537
+ }
538
+ async function loadAllBundles(migrationsDir) {
539
+ const all = await readMigrationsDir(migrationsDir);
540
+ const attested = all.filter(isAttested);
541
+ return {
542
+ attested,
543
+ drafts: all.filter(isDraft),
544
+ graph: reconstructGraph(attested)
545
+ };
546
+ }
547
+ /**
548
+ * Reads and parses contract.json, validating the framework-level envelope
549
+ * fields (storageHash, schemaVersion, target, targetFamily).
550
+ *
551
+ * Family-specific validation (storage structure, codec mappings, etc.)
552
+ * happens downstream in the control client via the family instance.
553
+ */
554
+ async function readContractEnvelope(config) {
555
+ const contractPath = resolveContractPath(config);
556
+ const content = await readFile(contractPath, "utf-8");
557
+ const json = JSON.parse(content);
558
+ const { schemaVersion, target, targetFamily, profileHash } = json;
559
+ const storageHash = json["storage"]?.["storageHash"];
560
+ if (typeof storageHash !== "string") throw new Error(`Contract at ${relative(process.cwd(), contractPath)} is missing a valid storage.storageHash. Run \`prisma-next contract emit\` to regenerate.`);
561
+ if (typeof schemaVersion !== "string") throw new Error(`Contract at ${relative(process.cwd(), contractPath)} is missing schemaVersion.`);
562
+ if (typeof target !== "string") throw new Error(`Contract at ${relative(process.cwd(), contractPath)} is missing target.`);
563
+ if (typeof targetFamily !== "string") throw new Error(`Contract at ${relative(process.cwd(), contractPath)} is missing targetFamily.`);
564
+ return {
565
+ ...json,
566
+ storageHash,
567
+ schemaVersion,
568
+ target,
569
+ targetFamily,
570
+ ...typeof profileHash === "string" ? { profileHash } : {}
571
+ };
572
+ }
573
+ /**
574
+ * Masks credentials in a database connection URL.
575
+ * Handles standard URLs (username + password + query params) and libpq-style key=value strings.
576
+ */
577
+ function maskConnectionUrl(url) {
578
+ try {
579
+ const parsed = new URL(url);
580
+ if (parsed.username) parsed.username = "****";
581
+ if (parsed.password) parsed.password = "****";
582
+ for (const key of [...parsed.searchParams.keys()]) if (/password/i.test(key)) parsed.searchParams.set(key, "****");
583
+ return parsed.toString();
584
+ } catch {
585
+ return url.replace(/password\s*=\s*\S+/gi, "password=****").replace(/user\s*=\s*\S+/gi, "user=****");
586
+ }
587
+ }
588
+ /**
589
+ * Strips raw connection URL fragments from an error message to prevent credential leakage.
590
+ * Call this before surfacing driver errors to the user.
591
+ */
592
+ function sanitizeErrorMessage(message, connectionUrl) {
593
+ if (!connectionUrl) return message;
594
+ try {
595
+ const parsed = new URL(connectionUrl);
596
+ let sanitized = message;
597
+ sanitized = sanitized.replaceAll(connectionUrl, maskConnectionUrl(connectionUrl));
598
+ if (parsed.password) sanitized = sanitized.replaceAll(parsed.password, "****");
599
+ if (parsed.username) sanitized = sanitized.replaceAll(parsed.username, "****");
600
+ return sanitized;
601
+ } catch {
602
+ return message.replace(/password\s*=\s*\S+/gi, "password=****").replace(/user\s*=\s*\S+/gi, "user=****");
603
+ }
604
+ }
605
+ /**
606
+ * Registers the global CLI options shared by every command:
607
+ * --json, -q/--quiet, -v/--verbose, --trace, --color, --no-color,
608
+ * --interactive, --no-interactive, -y/--yes.
609
+ *
610
+ * Also sets up the styled help formatter.
611
+ */
612
+ function addGlobalOptions(command) {
613
+ return command.configureHelp({ formatHelp: (cmd) => {
614
+ return formatCommandHelp({
615
+ command: cmd,
616
+ flags: parseGlobalFlags({})
617
+ });
618
+ } }).option("--json", "Output as JSON").option("-q, --quiet", "Quiet mode: errors only").option("-v, --verbose", "Verbose output: debug info, timings").option("--trace", "Trace output: deep internals, stack traces").option("--color", "Force color output").option("--no-color", "Disable color output").option("--interactive", "Force interactive mode").option("--no-interactive", "Disable interactive prompts").option("-y, --yes", "Auto-accept prompts");
619
+ }
620
+
621
+ //#endregion
622
+ //#region src/utils/formatters/errors.ts
623
+ /**
624
+ * Formats error output for human-readable display.
625
+ */
626
+ function formatErrorOutput(error, flags) {
627
+ const lines = [];
628
+ const useColor = flags.color !== false;
629
+ const formatRed = createColorFormatter(useColor, red);
630
+ const formatDimText = (text) => formatDim(useColor, text);
631
+ lines.push(`${formatRed("✖")} ${error.summary} (${error.code})`);
632
+ if (error.why) lines.push(`${formatDimText(` Why: ${error.why}`)}`);
633
+ if (error.fix) lines.push(`${formatDimText(` Fix: ${error.fix}`)}`);
634
+ if (error.where?.path) {
635
+ const whereLine = error.where.line ? `${error.where.path}:${error.where.line}` : error.where.path;
636
+ lines.push(`${formatDimText(` Where: ${whereLine}`)}`);
637
+ }
638
+ if (error.meta?.["conflicts"]) {
639
+ const conflicts = error.meta["conflicts"];
640
+ if (conflicts.length > 0) {
641
+ const maxToShow = isVerbose(flags, 1) ? conflicts.length : Math.min(3, conflicts.length);
642
+ const header = isVerbose(flags, 1) ? " Conflicts:" : ` Conflicts (showing ${maxToShow} of ${conflicts.length}):`;
643
+ lines.push(`${formatDimText(header)}`);
644
+ for (const conflict of conflicts.slice(0, maxToShow)) lines.push(`${formatDimText(` - [${conflict.kind}] ${conflict.summary}`)}`);
645
+ if (!isVerbose(flags, 1) && conflicts.length > maxToShow) lines.push(`${formatDimText(" Re-run with -v/--verbose to see all conflicts")}`);
646
+ }
647
+ }
648
+ if (error.meta?.["issues"]) {
649
+ const issues = error.meta["issues"];
650
+ if (issues.length > 0) {
651
+ const maxToShow = isVerbose(flags, 1) ? issues.length : Math.min(3, issues.length);
652
+ const header = isVerbose(flags, 1) ? " Issues:" : ` Issues (showing ${maxToShow} of ${issues.length}):`;
653
+ lines.push(`${formatDimText(header)}`);
654
+ for (const issue of issues.slice(0, maxToShow)) {
655
+ const kind = issue.kind ?? "issue";
656
+ const message = issue.message ?? "";
657
+ lines.push(`${formatDimText(` - [${kind}] ${message}`)}`);
658
+ }
659
+ if (!isVerbose(flags, 1) && issues.length > maxToShow) lines.push(`${formatDimText(" Re-run with -v/--verbose to see all issues")}`);
660
+ }
661
+ }
662
+ if (error.docsUrl && isVerbose(flags, 1)) lines.push(formatDimText(error.docsUrl));
663
+ if (isVerbose(flags, 2) && error.meta) lines.push(`${formatDimText(` Meta: ${JSON.stringify(error.meta, null, 2)}`)}`);
664
+ return lines.join("\n");
665
+ }
666
+ /**
667
+ * Formats error output as JSON.
668
+ */
669
+ function formatErrorJson(error) {
670
+ return JSON.stringify(error, null, 2);
671
+ }
672
+
673
+ //#endregion
674
+ //#region src/utils/result-handler.ts
675
+ /**
676
+ * Processes a CLI command result, handling both success and error cases.
677
+ * Formats output appropriately and returns the exit code.
678
+ * Never throws - returns exit code for commands to use with process.exit().
679
+ *
680
+ * Error output:
681
+ * - JSON mode: JSON error to stdout (piped) via ui.output(), human sees nothing on stderr.
682
+ * - Interactive: human-readable error to stderr.
683
+ */
684
+ function handleResult(result, flags, ui, onSuccess) {
685
+ if (result.ok) {
686
+ if (onSuccess) onSuccess(result.value);
687
+ return 0;
688
+ }
689
+ const envelope = result.failure.toEnvelope();
690
+ if (flags.json) ui.output(formatErrorJson(envelope));
691
+ else ui.error(formatErrorOutput(envelope, flags));
692
+ return result.failure.domain === "CLI" ? 2 : 1;
693
+ }
694
+
695
+ //#endregion
696
+ export { formatStyledHeader as _, maskConnectionUrl as a, formatDim as b, resolveMigrationPaths as c, setCommandExamples as d, targetSupportsMigrations as f, formatRootHelp as g, formatCommandHelp as h, loadAllBundles as i, sanitizeErrorMessage as l, parseGlobalFlags as m, addGlobalOptions as n, readContractEnvelope as o, toPathDecisionResult as p, getTargetMigrations as r, resolveContractPath as s, handleResult as t, setCommandDescriptions as u, formatSuccessMessage as v, isVerbose as x, createColorFormatter as y };
697
+ //# sourceMappingURL=result-handler-oK_vA-Fn.mjs.map