@prisma-next/cli 0.10.0-dev.22 → 0.10.0-dev.24

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 (130) hide show
  1. package/dist/{cli-errors-CF60g2cG.mjs → cli-errors-Djtz98Vm.mjs} +3 -3
  2. package/dist/cli-errors-Djtz98Vm.mjs.map +1 -0
  3. package/dist/cli.mjs +9 -10
  4. package/dist/cli.mjs.map +1 -1
  5. package/dist/{client-BbsiOKZN.mjs → client-oXO2WCPD.mjs} +4 -4
  6. package/dist/{client-BbsiOKZN.mjs.map → client-oXO2WCPD.mjs.map} +1 -1
  7. package/dist/{command-helpers-Dvgul7UA.mjs → command-helpers-BSb0tRC8.mjs} +103 -9
  8. package/dist/command-helpers-BSb0tRC8.mjs.map +1 -0
  9. package/dist/commands/contract-emit.mjs +1 -1
  10. package/dist/commands/contract-infer.mjs +1 -1
  11. package/dist/commands/db-init.mjs +8 -12
  12. package/dist/commands/db-init.mjs.map +1 -1
  13. package/dist/commands/db-schema.mjs +6 -10
  14. package/dist/commands/db-schema.mjs.map +1 -1
  15. package/dist/commands/db-sign.mjs +7 -11
  16. package/dist/commands/db-sign.mjs.map +1 -1
  17. package/dist/commands/db-update.mjs +8 -12
  18. package/dist/commands/db-update.mjs.map +1 -1
  19. package/dist/commands/db-verify.mjs +1 -1
  20. package/dist/commands/migrate.d.mts +1 -1
  21. package/dist/commands/migrate.mjs +7 -11
  22. package/dist/commands/migrate.mjs.map +1 -1
  23. package/dist/commands/migration-check.mjs +4 -7
  24. package/dist/commands/migration-check.mjs.map +1 -1
  25. package/dist/commands/migration-graph.d.mts +1 -1
  26. package/dist/commands/migration-graph.mjs +6 -10
  27. package/dist/commands/migration-graph.mjs.map +1 -1
  28. package/dist/commands/migration-list.mjs +5 -9
  29. package/dist/commands/migration-list.mjs.map +1 -1
  30. package/dist/commands/migration-log.mjs +6 -10
  31. package/dist/commands/migration-log.mjs.map +1 -1
  32. package/dist/commands/migration-new.mjs +6 -10
  33. package/dist/commands/migration-new.mjs.map +1 -1
  34. package/dist/commands/migration-plan.d.mts +1 -1
  35. package/dist/commands/migration-plan.mjs +1 -1
  36. package/dist/commands/migration-show.d.mts +1 -1
  37. package/dist/commands/migration-show.mjs +8 -12
  38. package/dist/commands/migration-show.mjs.map +1 -1
  39. package/dist/commands/migration-status.d.mts +1 -1
  40. package/dist/commands/migration-status.mjs +9 -13
  41. package/dist/commands/migration-status.mjs.map +1 -1
  42. package/dist/commands/ref.d.mts +1 -1
  43. package/dist/commands/ref.mjs +9 -19
  44. package/dist/commands/ref.mjs.map +1 -1
  45. package/dist/{contract-emit-iynA3BCA.mjs → contract-emit-bcrpT-wD.mjs} +3 -3
  46. package/dist/{contract-emit-iynA3BCA.mjs.map → contract-emit-bcrpT-wD.mjs.map} +1 -1
  47. package/dist/{contract-emit-BDBzHlaC.mjs → contract-emit-r4y8Zhf1.mjs} +7 -12
  48. package/dist/contract-emit-r4y8Zhf1.mjs.map +1 -0
  49. package/dist/{contract-infer-DsgNf-d7.mjs → contract-infer-BmySmqVT.mjs} +8 -13
  50. package/dist/contract-infer-BmySmqVT.mjs.map +1 -0
  51. package/dist/{contract-space-aggregate-loader-pAc8CDfY.mjs → contract-space-aggregate-loader-BmNQwlws.mjs} +2 -2
  52. package/dist/{contract-space-aggregate-loader-pAc8CDfY.mjs.map → contract-space-aggregate-loader-BmNQwlws.mjs.map} +1 -1
  53. package/dist/{db-verify-BfsmBkd4.mjs → db-verify-BClPs3ph.mjs} +8 -12
  54. package/dist/db-verify-BClPs3ph.mjs.map +1 -0
  55. package/dist/exports/control-api.d.mts +1 -1
  56. package/dist/exports/control-api.mjs +2 -2
  57. package/dist/exports/index.mjs +1 -1
  58. package/dist/exports/init-output.mjs +1 -1
  59. package/dist/{framework-components-xFLFpZUO.mjs → framework-components-65gOHkHB.mjs} +2 -2
  60. package/dist/{framework-components-xFLFpZUO.mjs.map → framework-components-65gOHkHB.mjs.map} +1 -1
  61. package/dist/{global-flags-DGmw6Kqg.d.mts → global-flags-CdE7M0d9.d.mts} +4 -1
  62. package/dist/global-flags-CdE7M0d9.d.mts.map +1 -0
  63. package/dist/{graph-render-eJDcLWny.mjs → graph-render-DJVv0_uf.mjs} +1 -1
  64. package/dist/{graph-render-eJDcLWny.mjs.map → graph-render-DJVv0_uf.mjs.map} +1 -1
  65. package/dist/{init-n7JaaCgD.mjs → init-CQ-84_iO.mjs} +70 -11
  66. package/dist/init-CQ-84_iO.mjs.map +1 -0
  67. package/dist/{inspect-live-schema-DyQVuLw6.mjs → inspect-live-schema-DSRbFoOL.mjs} +4 -4
  68. package/dist/{inspect-live-schema-DyQVuLw6.mjs.map → inspect-live-schema-DSRbFoOL.mjs.map} +1 -1
  69. package/dist/{migration-command-scaffold--ZwMgOD_.mjs → migration-command-scaffold-Bzd9La5c.mjs} +4 -4
  70. package/dist/{migration-command-scaffold--ZwMgOD_.mjs.map → migration-command-scaffold-Bzd9La5c.mjs.map} +1 -1
  71. package/dist/{migration-plan-BSzcWsvm.mjs → migration-plan-CFwqw3Gk.mjs} +8 -12
  72. package/dist/migration-plan-CFwqw3Gk.mjs.map +1 -0
  73. package/dist/{migration-types-D2FW63pr.d.mts → migration-types-BXWvz12q.d.mts} +1 -1
  74. package/dist/{migration-types-D2FW63pr.d.mts.map → migration-types-BXWvz12q.d.mts.map} +1 -1
  75. package/dist/{migrations-CgANWI0w.mjs → migrations-CwZMa1Ck.mjs} +2 -2
  76. package/dist/{migrations-CgANWI0w.mjs.map → migrations-CwZMa1Ck.mjs.map} +1 -1
  77. package/dist/{output-B60Gw5fu.mjs → output-BlsrGMEF.mjs} +1 -1
  78. package/dist/{output-B60Gw5fu.mjs.map → output-BlsrGMEF.mjs.map} +1 -1
  79. package/dist/readme-mongo.md +35 -0
  80. package/dist/readme-postgres.md +34 -0
  81. package/dist/{terminal-ui-XtOQsqe9.mjs → terminal-ui-BiB_8KNo.mjs} +131 -24
  82. package/dist/terminal-ui-BiB_8KNo.mjs.map +1 -0
  83. package/dist/{types-0aS865QN.d.mts → types--CqjMdk0.d.mts} +2 -2
  84. package/dist/{types-0aS865QN.d.mts.map → types--CqjMdk0.d.mts.map} +1 -1
  85. package/dist/{verify-nlzO0uIY.mjs → verify-Bom75OYI.mjs} +2 -2
  86. package/dist/{verify-nlzO0uIY.mjs.map → verify-Bom75OYI.mjs.map} +1 -1
  87. package/package.json +18 -18
  88. package/src/commands/contract-emit.ts +4 -4
  89. package/src/commands/contract-infer.ts +6 -6
  90. package/src/commands/db-init.ts +4 -4
  91. package/src/commands/db-schema.ts +4 -4
  92. package/src/commands/db-sign.ts +4 -4
  93. package/src/commands/db-update.ts +4 -4
  94. package/src/commands/db-verify.ts +4 -4
  95. package/src/commands/init/detect-package-manager.ts +15 -0
  96. package/src/commands/init/index.ts +2 -2
  97. package/src/commands/init/init.ts +23 -2
  98. package/src/commands/init/templates/readme-mongo.md +35 -0
  99. package/src/commands/init/templates/readme-postgres.md +34 -0
  100. package/src/commands/init/templates/readme.ts +62 -0
  101. package/src/commands/migrate.ts +4 -7
  102. package/src/commands/migration-check.ts +4 -4
  103. package/src/commands/migration-graph.ts +4 -4
  104. package/src/commands/migration-list.ts +4 -4
  105. package/src/commands/migration-log.ts +4 -4
  106. package/src/commands/migration-new.ts +4 -4
  107. package/src/commands/migration-plan.ts +4 -4
  108. package/src/commands/migration-show.ts +4 -4
  109. package/src/commands/migration-status.ts +4 -4
  110. package/src/commands/ref.ts +8 -8
  111. package/src/utils/cli-errors.ts +4 -0
  112. package/src/utils/command-helpers.ts +6 -2
  113. package/src/utils/global-flags.ts +102 -17
  114. package/src/utils/terminal-ui.ts +44 -23
  115. package/dist/cli-errors-CF60g2cG.mjs.map +0 -1
  116. package/dist/command-helpers-Dvgul7UA.mjs.map +0 -1
  117. package/dist/contract-emit-BDBzHlaC.mjs.map +0 -1
  118. package/dist/contract-infer-DsgNf-d7.mjs.map +0 -1
  119. package/dist/db-verify-BfsmBkd4.mjs.map +0 -1
  120. package/dist/errors-BYAXmyRJ.mjs +0 -56
  121. package/dist/errors-BYAXmyRJ.mjs.map +0 -1
  122. package/dist/global-flags-DGmw6Kqg.d.mts.map +0 -1
  123. package/dist/init-n7JaaCgD.mjs.map +0 -1
  124. package/dist/is-ci-YyvQBBke.mjs +0 -44
  125. package/dist/is-ci-YyvQBBke.mjs.map +0 -1
  126. package/dist/migration-plan-BSzcWsvm.mjs.map +0 -1
  127. package/dist/result-handler-CG3vVoKf.mjs +0 -25
  128. package/dist/result-handler-CG3vVoKf.mjs.map +0 -1
  129. package/dist/terminal-ui-XtOQsqe9.mjs.map +0 -1
  130. /package/dist/{cli-errors-DdcjVLJV.d.mts → cli-errors-Czmx92Zy.d.mts} +0 -0
@@ -0,0 +1,35 @@
1
+ # {{projectName}}
2
+
3
+ Generated by `prisma-next init` with the Minimal template.
4
+
5
+ ## First run
6
+
7
+ 1. `{{runDbUp}}` — start the local MongoDB replica set with `mongodb-memory-server`. Data persists in `.mongo-data/` across restarts.
8
+ 2. `{{runDev}}` — runs `src/index.ts`, which writes one row and reads it back.
9
+
10
+ ## Available scripts
11
+
12
+ - `{{runDev}}` — run the Prisma Next sample script
13
+
14
+ ### Database and migrations
15
+
16
+ - `{{runContractEmit}}` — emit contract artifacts after contract changes
17
+ - `{{runDbUp}}` — start the local MongoDB replica set with `mongodb-memory-server`. Data persists in `.mongo-data/` across restarts.
18
+ - `{{runDbDown}}` — stop the local MongoDB process (data preserved)
19
+ - `{{runDbReset}}` — stop and wipe `.mongo-data/` for a clean slate
20
+ - `{{runMigrationPlan}}` — create a MongoDB migration plan
21
+ - `{{runMigrate}}` — apply the planned MongoDB migration
22
+ - `{{runDbSeed}}` — insert sample users manually
23
+
24
+ ## Prisma Next
25
+
26
+ Prisma Next setup is scaffolded in:
27
+
28
+ - `{{contractPath}}`
29
+ - `prisma-next.config.ts`
30
+ - `prisma/db.ts`
31
+ - `src/lib/prisma.ts`
32
+
33
+ For provider-specific Prisma Next reference docs, see `prisma-next.md`. Prisma Next skills live in the upstream `skills/` directory: https://github.com/prisma/prisma-next/tree/main/skills.
34
+
35
+ Node-based Prisma Next projects expect Node.js 24 LTS or newer.
@@ -0,0 +1,34 @@
1
+ # {{projectName}}
2
+
3
+ Generated by `prisma-next init` with the Minimal template.
4
+
5
+ ## First run
6
+
7
+ 1. `{{runDbInit}}` — applies your contract to the database (creates tables, signs the marker).
8
+ 2. `{{runDev}}` — runs `src/index.ts`, which writes one row and reads it back.
9
+
10
+ ## Available scripts
11
+
12
+ - `{{runDev}}` — run the Prisma Next sample script
13
+
14
+ ### Database and migrations
15
+
16
+ - `{{runContractEmit}}` — emit contract artifacts after contract changes
17
+ - `{{runDbInit}}` — initialize database state manually
18
+ - `{{runDbUpdate}}` — update database state manually
19
+ - `{{runMigrationPlan}}` — create a migration plan
20
+ - `{{runMigrate}}` — apply a planned migration
21
+ - `{{runDbSeed}}` — insert sample users manually (run after `db:init`)
22
+
23
+ ## Prisma Next
24
+
25
+ Prisma Next setup is scaffolded in:
26
+
27
+ - `{{contractPath}}`
28
+ - `prisma-next.config.ts`
29
+ - `prisma/db.ts`
30
+ - `src/lib/prisma.ts`
31
+
32
+ For provider-specific Prisma Next reference docs, see `prisma-next.md`. Prisma Next skills live in the upstream `skills/` directory: https://github.com/prisma/prisma-next/tree/main/skills.
33
+
34
+ Node-based Prisma Next projects expect Node.js 24 LTS or newer.
@@ -0,0 +1,62 @@
1
+ import { formatRunScriptCommand, type PackageManager } from '../detect-package-manager';
2
+ import type { TargetId } from './code-templates';
3
+ import { renderTemplate } from './render';
4
+
5
+ const sharedVariables = ['projectName', 'contractPath', 'runDev', 'runContractEmit'] as const;
6
+
7
+ export const postgresVariables = [
8
+ ...sharedVariables,
9
+ 'runDbInit',
10
+ 'runDbUpdate',
11
+ 'runMigrationPlan',
12
+ 'runMigrate',
13
+ 'runDbSeed',
14
+ ] as const;
15
+
16
+ export const mongoVariables = [
17
+ ...sharedVariables,
18
+ 'runDbUp',
19
+ 'runDbDown',
20
+ 'runDbReset',
21
+ 'runMigrationPlan',
22
+ 'runMigrate',
23
+ 'runDbSeed',
24
+ ] as const;
25
+
26
+ type PostgresVars = Record<(typeof postgresVariables)[number], string>;
27
+ type MongoVars = Record<(typeof mongoVariables)[number], string>;
28
+
29
+ export function minimalProjectReadmeMd(
30
+ target: TargetId,
31
+ schemaPath: string,
32
+ projectName: string,
33
+ pm: PackageManager,
34
+ ): string {
35
+ const run = (script: string): string => formatRunScriptCommand(pm, script);
36
+ const shared = {
37
+ projectName,
38
+ contractPath: schemaPath,
39
+ runDev: run('dev'),
40
+ runContractEmit: run('contract:emit'),
41
+ runMigrationPlan: run('migration:plan'),
42
+ runMigrate: run('migrate'),
43
+ runDbSeed: run('db:seed'),
44
+ };
45
+
46
+ if (target === 'mongo') {
47
+ const vars: MongoVars = {
48
+ ...shared,
49
+ runDbUp: run('db:up'),
50
+ runDbDown: run('db:down'),
51
+ runDbReset: run('db:reset'),
52
+ };
53
+ return renderTemplate('readme-mongo.md', mongoVariables, vars);
54
+ }
55
+
56
+ const vars: PostgresVars = {
57
+ ...shared,
58
+ runDbInit: run('db:init'),
59
+ runDbUpdate: run('db:update'),
60
+ };
61
+ return renderTemplate('readme-postgres.md', postgresVariables, vars);
62
+ }
@@ -43,9 +43,9 @@ import {
43
43
  import { formatMigrationApplyCommandOutput } from '../utils/formatters/migrations';
44
44
  import { formatStyledHeader } from '../utils/formatters/styled';
45
45
  import type { CommonCommandOptions } from '../utils/global-flags';
46
- import { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';
46
+ import { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';
47
47
  import { handleResult } from '../utils/result-handler';
48
- import { TerminalUI } from '../utils/terminal-ui';
48
+ import { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';
49
49
 
50
50
  interface MigrateCommandOptions extends CommonCommandOptions {
51
51
  readonly db?: string;
@@ -319,13 +319,10 @@ export function createMigrateCommand(): Command {
319
319
  'Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',
320
320
  )
321
321
  .action(async (options: MigrateCommandOptions) => {
322
- const flags = parseGlobalFlags(options);
322
+ const flags = parseGlobalFlagsOrExit(options);
323
323
  const startTime = Date.now();
324
324
 
325
- const ui = new TerminalUI({
326
- color: flags.color,
327
- interactive: flags.interactive,
328
- });
325
+ const ui = createTerminalUI(flags);
329
326
 
330
327
  const result = await executeMigrateCommand(options, flags, ui, startTime);
331
328
 
@@ -17,8 +17,8 @@ import {
17
17
  } from '../utils/command-helpers';
18
18
  import { formatStyledHeader } from '../utils/formatters/styled';
19
19
  import type { CommonCommandOptions } from '../utils/global-flags';
20
- import { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';
21
- import { TerminalUI } from '../utils/terminal-ui';
20
+ import { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';
21
+ import { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';
22
22
  import { INTEGRITY_FAILED, OK, PRECONDITION } from './migration-check/exit-codes';
23
23
 
24
24
  interface MigrationCheckOptions extends CommonCommandOptions {
@@ -335,8 +335,8 @@ export function createMigrationCheckCommand(): Command {
335
335
  .argument('[migration]', 'Migration reference (directory name or hash) to check')
336
336
  .option('--config <path>', 'Path to prisma-next.config.ts')
337
337
  .action(async (target: string | undefined, options: MigrationCheckOptions) => {
338
- const flags = parseGlobalFlags(options);
339
- const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
338
+ const flags = parseGlobalFlagsOrExit(options);
339
+ const ui = createTerminalUI(flags);
340
340
 
341
341
  let result: MigrationCheckResult;
342
342
  let exitCode: number;
@@ -23,10 +23,10 @@ import { migrationGraphToRenderInput } from '../utils/formatters/graph-migration
23
23
  import { graphRenderer } from '../utils/formatters/graph-render';
24
24
  import { formatStyledHeader } from '../utils/formatters/styled';
25
25
  import type { CommonCommandOptions } from '../utils/global-flags';
26
- import { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';
26
+ import { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';
27
27
  import type { StatusRef } from '../utils/migration-types';
28
28
  import { handleResult } from '../utils/result-handler';
29
- import { TerminalUI } from '../utils/terminal-ui';
29
+ import { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';
30
30
 
31
31
  interface MigrationGraphOptions extends CommonCommandOptions {
32
32
  readonly config?: string;
@@ -130,8 +130,8 @@ export function createMigrationGraphCommand(): Command {
130
130
  .option('--config <path>', 'Path to prisma-next.config.ts')
131
131
  .option('--dot', 'Output in Graphviz DOT format')
132
132
  .action(async (options: MigrationGraphOptions) => {
133
- const flags = parseGlobalFlags(options);
134
- const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
133
+ const flags = parseGlobalFlagsOrExit(options);
134
+ const ui = createTerminalUI(flags);
135
135
  const result = await executeMigrationGraphCommand(options, flags, ui);
136
136
  const exitCode = handleResult(result, flags, ui, (graphResult) => {
137
137
  // Explicit format flags win over the auto-JSON default. `flags.json`
@@ -20,9 +20,9 @@ import {
20
20
  } from '../utils/command-helpers';
21
21
  import { formatStyledHeader } from '../utils/formatters/styled';
22
22
  import type { CommonCommandOptions } from '../utils/global-flags';
23
- import { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';
23
+ import { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';
24
24
  import { handleResult } from '../utils/result-handler';
25
- import { TerminalUI } from '../utils/terminal-ui';
25
+ import { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';
26
26
 
27
27
  interface MigrationListOptions extends CommonCommandOptions {
28
28
  readonly config?: string;
@@ -130,8 +130,8 @@ export function createMigrationListCommand(): Command {
130
130
  addGlobalOptions(command)
131
131
  .option('--config <path>', 'Path to prisma-next.config.ts')
132
132
  .action(async (options: MigrationListOptions) => {
133
- const flags = parseGlobalFlags(options);
134
- const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
133
+ const flags = parseGlobalFlagsOrExit(options);
134
+ const ui = createTerminalUI(flags);
135
135
  const result = await executeMigrationListCommand(options, flags, ui);
136
136
  const exitCode = handleResult(result, flags, ui, (listResult) => {
137
137
  if (flags.json) {
@@ -26,9 +26,9 @@ import {
26
26
  } from '../utils/command-helpers';
27
27
  import { formatStyledHeader } from '../utils/formatters/styled';
28
28
  import type { CommonCommandOptions } from '../utils/global-flags';
29
- import { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';
29
+ import { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';
30
30
  import { handleResult } from '../utils/result-handler';
31
- import { TerminalUI } from '../utils/terminal-ui';
31
+ import { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';
32
32
 
33
33
  interface MigrationLogOptions extends CommonCommandOptions {
34
34
  readonly db?: string;
@@ -193,8 +193,8 @@ export function createMigrationLogCommand(): Command {
193
193
  .option('--db <url>', 'Database connection string')
194
194
  .option('--config <path>', 'Path to prisma-next.config.ts')
195
195
  .action(async (options: MigrationLogOptions) => {
196
- const flags = parseGlobalFlags(options);
197
- const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
196
+ const flags = parseGlobalFlagsOrExit(options);
197
+ const ui = createTerminalUI(flags);
198
198
  const result = await executeMigrationLogCommand(options, flags, ui);
199
199
  const exitCode = handleResult(result, flags, ui, (logResult) => {
200
200
  if (flags.json) {
@@ -49,9 +49,9 @@ import {
49
49
  import { formatStyledHeader } from '../utils/formatters/styled';
50
50
  import { assertFrameworkComponentsCompatible } from '../utils/framework-components';
51
51
  import type { CommonCommandOptions } from '../utils/global-flags';
52
- import { parseGlobalFlags } from '../utils/global-flags';
52
+ import { parseGlobalFlagsOrExit } from '../utils/global-flags';
53
53
  import { handleResult } from '../utils/result-handler';
54
- import { TerminalUI } from '../utils/terminal-ui';
54
+ import { createTerminalUI } from '../utils/terminal-ui';
55
55
 
56
56
  interface MigrationNewOptions extends CommonCommandOptions {
57
57
  readonly name?: string;
@@ -287,8 +287,8 @@ export function createMigrationNewCommand(): Command {
287
287
  .option('--from <hash>', 'Starting contract hash (default: latest migration target)')
288
288
  .option('--config <path>', 'Path to prisma-next.config.ts')
289
289
  .action(async (options: MigrationNewOptions) => {
290
- const flags = parseGlobalFlags(options);
291
- const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
290
+ const flags = parseGlobalFlagsOrExit(options);
291
+ const ui = createTerminalUI(flags);
292
292
 
293
293
  if (!flags.json && !flags.quiet) {
294
294
  const header = formatStyledHeader({
@@ -51,9 +51,9 @@ import { toExtensionInputs } from '../utils/extension-pack-inputs';
51
51
  import { formatStyledHeader } from '../utils/formatters/styled';
52
52
  import { assertFrameworkComponentsCompatible } from '../utils/framework-components';
53
53
  import type { CommonCommandOptions } from '../utils/global-flags';
54
- import { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';
54
+ import { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';
55
55
  import { handleResult } from '../utils/result-handler';
56
- import { TerminalUI } from '../utils/terminal-ui';
56
+ import { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';
57
57
 
58
58
  interface MigrationPlanOptions extends CommonCommandOptions {
59
59
  readonly config?: string;
@@ -551,10 +551,10 @@ export function createMigrationPlanCommand(): Command {
551
551
  'Starting contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',
552
552
  )
553
553
  .action(async (options: MigrationPlanOptions) => {
554
- const flags = parseGlobalFlags(options);
554
+ const flags = parseGlobalFlagsOrExit(options);
555
555
  const startTime = Date.now();
556
556
 
557
- const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
557
+ const ui = createTerminalUI(flags);
558
558
  const result = await executeMigrationPlanCommand(options, flags, ui, startTime);
559
559
 
560
560
  const exitCode = handleResult(result, flags, ui, (planResult) => {
@@ -43,9 +43,9 @@ import { buildContractSpaceAggregate } from '../utils/contract-space-aggregate-l
43
43
  import { formatMigrationShowOutput } from '../utils/formatters/migrations';
44
44
  import { formatStyledHeader } from '../utils/formatters/styled';
45
45
  import type { CommonCommandOptions } from '../utils/global-flags';
46
- import { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';
46
+ import { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';
47
47
  import { handleResult } from '../utils/result-handler';
48
- import { TerminalUI } from '../utils/terminal-ui';
48
+ import { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';
49
49
 
50
50
  interface MigrationShowOptions extends CommonCommandOptions {
51
51
  readonly config?: string;
@@ -495,9 +495,9 @@ export function createMigrationShowCommand(): Command {
495
495
  )
496
496
  .option('--config <path>', 'Path to prisma-next.config.ts')
497
497
  .action(async (target: string | undefined, options: MigrationShowOptions) => {
498
- const flags = parseGlobalFlags(options);
498
+ const flags = parseGlobalFlagsOrExit(options);
499
499
 
500
- const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
500
+ const ui = createTerminalUI(flags);
501
501
 
502
502
  const result = await executeMigrationShowCommand(target, options, flags, ui);
503
503
 
@@ -65,10 +65,10 @@ import {
65
65
  } from '../utils/formatters/graph-render';
66
66
  import { formatStyledHeader } from '../utils/formatters/styled';
67
67
  import type { CommonCommandOptions } from '../utils/global-flags';
68
- import { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';
68
+ import { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';
69
69
  import type { StatusDiagnostic, StatusRef } from '../utils/migration-types';
70
70
  import { handleResult } from '../utils/result-handler';
71
- import { TerminalUI } from '../utils/terminal-ui';
71
+ import { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';
72
72
 
73
73
  interface MigrationStatusOptions extends CommonCommandOptions {
74
74
  readonly db?: string;
@@ -1140,8 +1140,8 @@ export function createMigrationStatusCommand(): Command {
1140
1140
  'Origin contract reference; same grammar as --to. Supplying --from switches to offline path computation.',
1141
1141
  )
1142
1142
  .action(async (options: MigrationStatusOptions) => {
1143
- const flags = parseGlobalFlags(options);
1144
- const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
1143
+ const flags = parseGlobalFlagsOrExit(options);
1144
+ const ui = createTerminalUI(flags);
1145
1145
 
1146
1146
  const result = await executeMigrationStatusCommand(options, flags, ui);
1147
1147
 
@@ -25,9 +25,9 @@ import {
25
25
  setCommandDescriptions,
26
26
  } from '../utils/command-helpers';
27
27
  import { formatCommandHelp } from '../utils/formatters/help';
28
- import { parseGlobalFlags } from '../utils/global-flags';
28
+ import { parseGlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';
29
29
  import { handleResult } from '../utils/result-handler';
30
- import { TerminalUI } from '../utils/terminal-ui';
30
+ import { createTerminalUI } from '../utils/terminal-ui';
31
31
 
32
32
  interface RefSetResult {
33
33
  readonly ok: true;
@@ -145,8 +145,8 @@ function createRefSetCommand(): Command {
145
145
  hash: string,
146
146
  options: { config?: string; json?: string | boolean; quiet?: boolean },
147
147
  ) => {
148
- const flags = parseGlobalFlags(options);
149
- const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
148
+ const flags = parseGlobalFlagsOrExit(options);
149
+ const ui = createTerminalUI(flags);
150
150
  const result = await executeRefSetCommand(name, hash, options);
151
151
  const exitCode = handleResult(result, flags, ui, (value) => {
152
152
  if (flags.json) {
@@ -172,8 +172,8 @@ function createRefDeleteCommand(): Command {
172
172
  name: string,
173
173
  options: { config?: string; json?: string | boolean; quiet?: boolean },
174
174
  ) => {
175
- const flags = parseGlobalFlags(options);
176
- const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
175
+ const flags = parseGlobalFlagsOrExit(options);
176
+ const ui = createTerminalUI(flags);
177
177
  const result = await executeRefDeleteCommand(name, options);
178
178
  const exitCode = handleResult(result, flags, ui, (value) => {
179
179
  if (flags.json) {
@@ -194,8 +194,8 @@ function createRefListCommand(): Command {
194
194
  addGlobalOptions(command)
195
195
  .option('--config <path>', 'Path to prisma-next.config.ts')
196
196
  .action(async (options: { config?: string; json?: string | boolean; quiet?: boolean }) => {
197
- const flags = parseGlobalFlags(options);
198
- const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
197
+ const flags = parseGlobalFlagsOrExit(options);
198
+ const ui = createTerminalUI(flags);
199
199
  const result = await executeRefListCommand(options);
200
200
  const exitCode = handleResult(result, flags, ui, (value) => {
201
201
  if (flags.json) {
@@ -16,9 +16,11 @@ import {
16
16
  errorDriverRequired,
17
17
  errorFamilyReadMarkerSqlRequired,
18
18
  errorFileNotFound,
19
+ errorInvalidOutputFormat,
19
20
  errorMigrationCliInvalidConfigArg,
20
21
  errorMigrationCliUnknownFlag,
21
22
  errorMigrationPlanningFailed,
23
+ errorOutputFormatMutex,
22
24
  errorQueryRunnerFactoryRequired,
23
25
  errorTargetMigrationNotSupported,
24
26
  errorUnexpected,
@@ -56,9 +58,11 @@ export {
56
58
  errorDriverRequired,
57
59
  errorFamilyReadMarkerSqlRequired,
58
60
  errorFileNotFound,
61
+ errorInvalidOutputFormat,
59
62
  errorMigrationCliInvalidConfigArg,
60
63
  errorMigrationCliUnknownFlag,
61
64
  errorMigrationPlanningFailed,
65
+ errorOutputFormatMutex,
62
66
  errorQueryRunnerFactoryRequired,
63
67
  errorTargetMigrationNotSupported,
64
68
  errorUnexpected,
@@ -365,7 +365,7 @@ export function sanitizeErrorMessage(message: string, connectionUrl?: string): s
365
365
 
366
366
  /**
367
367
  * Registers the global CLI options shared by every command:
368
- * --json, -q/--quiet, -v/--verbose, --trace, --color, --no-color,
368
+ * --format, --json, -q/--quiet, -v/--verbose, --trace, --color, --no-color,
369
369
  * --interactive, --no-interactive, -y/--yes.
370
370
  *
371
371
  * Also sets up the styled help formatter.
@@ -378,7 +378,11 @@ export function addGlobalOptions(command: Command): Command {
378
378
  return formatCommandHelp({ command: cmd, flags });
379
379
  },
380
380
  })
381
- .option('--json', 'Output as JSON')
381
+ .option(
382
+ '--format <pretty|json>',
383
+ 'Output format (default: pretty, or json when stdout is not a TTY)',
384
+ )
385
+ .option('--json', 'Output as JSON (alias for --format json)')
382
386
  .option('-q, --quiet', 'Quiet mode: errors only')
383
387
  .option('-v, --verbose', 'Verbose output: debug info, timings')
384
388
  .option('--trace', 'Trace output: deep internals, stack traces')
@@ -1,9 +1,17 @@
1
+ import { notOk } from '@prisma-next/utils/result';
2
+ import { CliStructuredError, errorInvalidOutputFormat, errorOutputFormatMutex } from './cli-errors';
1
3
  import { isCI } from './is-ci';
4
+ import { handleResult } from './result-handler';
5
+ import { createTerminalUI } from './terminal-ui';
6
+
7
+ export type OutputFormat = 'pretty' | 'json';
2
8
 
3
9
  export interface GlobalFlags {
10
+ readonly format: OutputFormat;
11
+ readonly explicitFormat: boolean;
4
12
  readonly json?: boolean;
5
13
  readonly quiet?: boolean;
6
- readonly verbose?: number; // 0, 1, or 2
14
+ readonly verbose?: number;
7
15
  readonly color?: boolean;
8
16
  readonly interactive?: boolean;
9
17
  readonly yes?: boolean;
@@ -14,6 +22,7 @@ export interface GlobalFlags {
14
22
  * Extend this for command-specific options instead of duplicating these fields.
15
23
  */
16
24
  export interface CommonCommandOptions {
25
+ readonly format?: string;
17
26
  readonly json?: string | boolean;
18
27
  readonly quiet?: boolean;
19
28
  readonly q?: boolean;
@@ -28,33 +37,117 @@ export interface CommonCommandOptions {
28
37
  readonly y?: boolean;
29
38
  }
30
39
 
40
+ function isJsonFlagSet(json: string | boolean | undefined): boolean {
41
+ return json === true;
42
+ }
43
+
44
+ interface ResolvedOutputFormat {
45
+ readonly format: OutputFormat;
46
+ readonly explicitFormat: boolean;
47
+ }
48
+
49
+ function resolveOutputFormat(options: CommonCommandOptions): ResolvedOutputFormat {
50
+ const formatOption = options.format;
51
+ const jsonFlag = isJsonFlagSet(options.json);
52
+
53
+ if (formatOption !== undefined) {
54
+ if (formatOption !== 'pretty' && formatOption !== 'json') {
55
+ throw errorInvalidOutputFormat(formatOption);
56
+ }
57
+ if (jsonFlag && formatOption === 'pretty') {
58
+ throw errorOutputFormatMutex();
59
+ }
60
+ return { format: formatOption, explicitFormat: true };
61
+ }
62
+
63
+ if (jsonFlag) {
64
+ return { format: 'json', explicitFormat: false };
65
+ }
66
+
67
+ if (!process.stdout.isTTY) {
68
+ return { format: 'json', explicitFormat: false };
69
+ }
70
+
71
+ return { format: 'pretty', explicitFormat: false };
72
+ }
73
+
74
+ function inferJsonModeForParseError(options: CommonCommandOptions): boolean {
75
+ if (options.format === 'json') {
76
+ return true;
77
+ }
78
+ if (isJsonFlagSet(options.json) && options.format !== 'pretty') {
79
+ return true;
80
+ }
81
+ if (options.format !== undefined) {
82
+ return false;
83
+ }
84
+ return !process.stdout.isTTY;
85
+ }
86
+
87
+ function emitGlobalFlagParseError(error: CliStructuredError, options: CommonCommandOptions): never {
88
+ const jsonMode = inferJsonModeForParseError(options);
89
+ const flags: GlobalFlags = {
90
+ format: jsonMode ? 'json' : 'pretty',
91
+ explicitFormat: false,
92
+ ...(jsonMode ? { json: true } : {}),
93
+ color: false,
94
+ verbose: 0,
95
+ interactive: false,
96
+ };
97
+ const ui = createTerminalUI(flags);
98
+ const exitCode = handleResult(notOk(error), flags, ui);
99
+ process.exit(exitCode);
100
+ }
101
+
102
+ /**
103
+ * Parses global flags from CLI options.
104
+ * Handles verbosity flags (-v, --trace), output format (--format, --json),
105
+ * quiet mode, color, interactivity (--interactive/--no-interactive), and
106
+ * auto-accept (-y/--yes).
107
+ *
108
+ * On invalid or conflicting format flags, prints a structured CLI error
109
+ * envelope and exits with code 2.
110
+ */
111
+ export function parseGlobalFlagsOrExit(options: CommonCommandOptions): GlobalFlags {
112
+ try {
113
+ return parseGlobalFlags(options);
114
+ } catch (error) {
115
+ if (CliStructuredError.is(error)) {
116
+ emitGlobalFlagParseError(error, options);
117
+ }
118
+ throw error;
119
+ }
120
+ }
121
+
31
122
  /**
32
123
  * Parses global flags from CLI options.
33
- * Handles verbosity flags (-v, --trace), JSON output, quiet mode, color,
34
- * interactivity (--interactive/--no-interactive), and auto-accept (-y/--yes).
124
+ * Handles verbosity flags (-v, --trace), output format (--format, --json),
125
+ * quiet mode, color, interactivity (--interactive/--no-interactive), and
126
+ * auto-accept (-y/--yes).
127
+ *
128
+ * Throws {@link CliStructuredError} for invalid or conflicting format flags.
35
129
  */
36
130
  export function parseGlobalFlags(options: CommonCommandOptions): GlobalFlags {
131
+ const { format, explicitFormat } = resolveOutputFormat(options);
37
132
  const flags: {
133
+ format: OutputFormat;
134
+ explicitFormat: boolean;
38
135
  json?: boolean;
39
136
  quiet?: boolean;
40
137
  verbose?: number;
41
138
  color?: boolean;
42
139
  interactive?: boolean;
43
140
  yes?: boolean;
44
- } = {};
141
+ } = { format, explicitFormat };
45
142
 
46
- // JSON output: explicit --json flag or auto-detect piped stdout (Unix convention)
47
- if (options.json || !process.stdout.isTTY) {
143
+ if (format === 'json') {
48
144
  flags.json = true;
49
145
  }
50
146
 
51
- // Quiet mode
52
147
  if (options.quiet || options.q) {
53
148
  flags.quiet = true;
54
149
  }
55
150
 
56
- // Verbosity: -v = 1, --trace = 2
57
- // Env toggles: PRISMA_NEXT_TRACE=1 ≅ --trace, PRISMA_NEXT_DEBUG=1 ≅ -v
58
151
  if (options.trace || process.env['PRISMA_NEXT_TRACE'] === '1') {
59
152
  flags.verbose = 2;
60
153
  } else if (options.verbose || options.v || process.env['PRISMA_NEXT_DEBUG'] === '1') {
@@ -63,8 +156,6 @@ export function parseGlobalFlags(options: CommonCommandOptions): GlobalFlags {
63
156
  flags.verbose = 0;
64
157
  }
65
158
 
66
- // Color: respect NO_COLOR env var, --color/--no-color flags
67
- // When JSON output is enabled, disable color to ensure clean JSON output
68
159
  if (process.env['NO_COLOR'] || flags.json) {
69
160
  flags.color = false;
70
161
  } else if (options['no-color']) {
@@ -72,14 +163,9 @@ export function parseGlobalFlags(options: CommonCommandOptions): GlobalFlags {
72
163
  } else if (options.color !== undefined) {
73
164
  flags.color = options.color;
74
165
  } else {
75
- // Default: enable color if TTY and not in CI. Uses the consolidated
76
- // `isCI()` helper (`./is-ci.ts`) — the single source of truth shared
77
- // with telemetry-skip detection.
78
166
  flags.color = process.stdout.isTTY && !isCI();
79
167
  }
80
168
 
81
- // Interactivity: --interactive/--no-interactive
82
- // Default: interactive when stdout is a TTY
83
169
  if (options['no-interactive']) {
84
170
  flags.interactive = false;
85
171
  } else if (options.interactive !== undefined) {
@@ -88,7 +174,6 @@ export function parseGlobalFlags(options: CommonCommandOptions): GlobalFlags {
88
174
  flags.interactive = !!process.stdout.isTTY;
89
175
  }
90
176
 
91
- // Auto-accept prompts: -y/--yes
92
177
  if (options.yes || options.y) {
93
178
  flags.yes = true;
94
179
  }