@prisma-next/cli 0.3.0-dev.14 → 0.3.0-dev.16

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 (42) hide show
  1. package/dist/chunk-5MPKZYVI.js +47 -0
  2. package/dist/chunk-5MPKZYVI.js.map +1 -0
  3. package/dist/chunk-74IELXRA.js +371 -0
  4. package/dist/chunk-74IELXRA.js.map +1 -0
  5. package/dist/{chunk-MG7PBERL.js → chunk-U6QI3AZ3.js} +7 -5
  6. package/dist/{chunk-MG7PBERL.js.map → chunk-U6QI3AZ3.js.map} +1 -1
  7. package/dist/{chunk-DIJPT5TZ.js → chunk-ZG5T6OB5.js} +2 -46
  8. package/dist/chunk-ZG5T6OB5.js.map +1 -0
  9. package/dist/cli.js +593 -268
  10. package/dist/cli.js.map +1 -1
  11. package/dist/commands/contract-emit.js +3 -2
  12. package/dist/commands/db-init.d.ts.map +1 -1
  13. package/dist/commands/db-init.js +238 -275
  14. package/dist/commands/db-init.js.map +1 -1
  15. package/dist/commands/db-introspect.js +6 -4
  16. package/dist/commands/db-introspect.js.map +1 -1
  17. package/dist/commands/db-schema-verify.js +6 -4
  18. package/dist/commands/db-schema-verify.js.map +1 -1
  19. package/dist/commands/db-sign.js +6 -4
  20. package/dist/commands/db-sign.js.map +1 -1
  21. package/dist/commands/db-verify.js +6 -4
  22. package/dist/commands/db-verify.js.map +1 -1
  23. package/dist/control-api/operations/db-init.d.ts +3 -1
  24. package/dist/control-api/operations/db-init.d.ts.map +1 -1
  25. package/dist/control-api/types.d.ts +54 -1
  26. package/dist/control-api/types.d.ts.map +1 -1
  27. package/dist/exports/control-api.d.ts +1 -1
  28. package/dist/exports/control-api.d.ts.map +1 -1
  29. package/dist/exports/control-api.js +3 -234
  30. package/dist/exports/control-api.js.map +1 -1
  31. package/dist/exports/index.js +3 -2
  32. package/dist/exports/index.js.map +1 -1
  33. package/dist/utils/progress-adapter.d.ts +26 -0
  34. package/dist/utils/progress-adapter.d.ts.map +1 -0
  35. package/package.json +10 -10
  36. package/src/commands/db-init.ts +262 -355
  37. package/src/control-api/client.ts +30 -0
  38. package/src/control-api/operations/db-init.ts +116 -2
  39. package/src/control-api/types.ts +63 -1
  40. package/src/exports/control-api.ts +3 -0
  41. package/src/utils/progress-adapter.ts +86 -0
  42. package/dist/chunk-DIJPT5TZ.js.map +0 -1
@@ -5,11 +5,12 @@ import type {
5
5
  ControlFamilyInstance,
6
6
  MigrationPlan,
7
7
  MigrationPlannerResult,
8
+ MigrationPlanOperation,
8
9
  MigrationRunnerResult,
9
10
  TargetMigrationsCapability,
10
11
  } from '@prisma-next/core-control-plane/types';
11
12
  import { notOk, ok } from '@prisma-next/utils/result';
12
- import type { DbInitResult, DbInitSuccess } from '../types';
13
+ import type { DbInitResult, DbInitSuccess, OnControlProgress } from '../types';
13
14
 
14
15
  /**
15
16
  * Options for executing dbInit operation.
@@ -25,6 +26,8 @@ export interface ExecuteDbInitOptions<TFamilyId extends string, TTargetId extend
25
26
  ControlFamilyInstance<TFamilyId>
26
27
  >;
27
28
  readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;
29
+ /** Optional progress callback for observing operation progress */
30
+ readonly onProgress?: OnControlProgress;
28
31
  }
29
32
 
30
33
  /**
@@ -40,19 +43,40 @@ export interface ExecuteDbInitOptions<TFamilyId extends string, TTargetId extend
40
43
  export async function executeDbInit<TFamilyId extends string, TTargetId extends string>(
41
44
  options: ExecuteDbInitOptions<TFamilyId, TTargetId>,
42
45
  ): Promise<DbInitResult> {
43
- const { driver, familyInstance, contractIR, mode, migrations, frameworkComponents } = options;
46
+ const { driver, familyInstance, contractIR, mode, migrations, frameworkComponents, onProgress } =
47
+ options;
44
48
 
45
49
  // Create planner and runner from target migrations capability
46
50
  const planner = migrations.createPlanner(familyInstance);
47
51
  const runner = migrations.createRunner(familyInstance);
48
52
 
49
53
  // Introspect live schema
54
+ const introspectSpanId = 'introspect';
55
+ onProgress?.({
56
+ action: 'dbInit',
57
+ kind: 'spanStart',
58
+ spanId: introspectSpanId,
59
+ label: 'Introspecting database schema',
60
+ });
50
61
  const schemaIR = await familyInstance.introspect({ driver });
62
+ onProgress?.({
63
+ action: 'dbInit',
64
+ kind: 'spanEnd',
65
+ spanId: introspectSpanId,
66
+ outcome: 'ok',
67
+ });
51
68
 
52
69
  // Policy for init mode (additive only)
53
70
  const policy = { allowedOperationClasses: ['additive'] as const };
54
71
 
55
72
  // Plan migration
73
+ const planSpanId = 'plan';
74
+ onProgress?.({
75
+ action: 'dbInit',
76
+ kind: 'spanStart',
77
+ spanId: planSpanId,
78
+ label: 'Planning migration',
79
+ });
56
80
  const plannerResult: MigrationPlannerResult = await planner.plan({
57
81
  contract: contractIR,
58
82
  schema: schemaIR,
@@ -61,16 +85,37 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
61
85
  });
62
86
 
63
87
  if (plannerResult.kind === 'failure') {
88
+ onProgress?.({
89
+ action: 'dbInit',
90
+ kind: 'spanEnd',
91
+ spanId: planSpanId,
92
+ outcome: 'error',
93
+ });
64
94
  return notOk({
65
95
  code: 'PLANNING_FAILED' as const,
66
96
  summary: 'Migration planning failed due to conflicts',
67
97
  conflicts: plannerResult.conflicts,
98
+ why: undefined,
99
+ meta: undefined,
68
100
  });
69
101
  }
70
102
 
71
103
  const migrationPlan: MigrationPlan = plannerResult.plan;
104
+ onProgress?.({
105
+ action: 'dbInit',
106
+ kind: 'spanEnd',
107
+ spanId: planSpanId,
108
+ outcome: 'ok',
109
+ });
72
110
 
73
111
  // Check for existing marker - handle idempotency and mismatch errors
112
+ const checkMarkerSpanId = 'checkMarker';
113
+ onProgress?.({
114
+ action: 'dbInit',
115
+ kind: 'spanStart',
116
+ spanId: checkMarkerSpanId,
117
+ label: 'Checking contract marker',
118
+ });
74
119
  const existingMarker = await familyInstance.readMarker({ driver });
75
120
  if (existingMarker) {
76
121
  const markerMatchesDestination =
@@ -80,6 +125,12 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
80
125
 
81
126
  if (markerMatchesDestination) {
82
127
  // Already at destination - return success with no operations
128
+ onProgress?.({
129
+ action: 'dbInit',
130
+ kind: 'spanEnd',
131
+ spanId: checkMarkerSpanId,
132
+ outcome: 'skipped',
133
+ });
83
134
  const result: DbInitSuccess = {
84
135
  mode,
85
136
  plan: { operations: [] },
@@ -98,6 +149,12 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
98
149
  }
99
150
 
100
151
  // Marker exists but doesn't match destination - fail
152
+ onProgress?.({
153
+ action: 'dbInit',
154
+ kind: 'spanEnd',
155
+ spanId: checkMarkerSpanId,
156
+ outcome: 'error',
157
+ });
101
158
  return notOk({
102
159
  code: 'MARKER_ORIGIN_MISMATCH' as const,
103
160
  summary: 'Existing contract marker does not match plan destination',
@@ -109,9 +166,19 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
109
166
  coreHash: migrationPlan.destination.coreHash,
110
167
  profileHash: migrationPlan.destination.profileHash,
111
168
  },
169
+ why: undefined,
170
+ conflicts: undefined,
171
+ meta: undefined,
112
172
  });
113
173
  }
114
174
 
175
+ onProgress?.({
176
+ action: 'dbInit',
177
+ kind: 'spanEnd',
178
+ spanId: checkMarkerSpanId,
179
+ outcome: 'ok',
180
+ });
181
+
115
182
  // Plan mode - don't execute
116
183
  if (mode === 'plan') {
117
184
  const result: DbInitSuccess = {
@@ -123,11 +190,42 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
123
190
  }
124
191
 
125
192
  // Apply mode - execute runner
193
+ const applySpanId = 'apply';
194
+ onProgress?.({
195
+ action: 'dbInit',
196
+ kind: 'spanStart',
197
+ spanId: applySpanId,
198
+ label: 'Applying migration plan',
199
+ });
200
+
201
+ const callbacks = onProgress
202
+ ? {
203
+ onOperationStart: (op: MigrationPlanOperation) => {
204
+ onProgress({
205
+ action: 'dbInit',
206
+ kind: 'spanStart',
207
+ spanId: `operation:${op.id}`,
208
+ parentSpanId: applySpanId,
209
+ label: op.label,
210
+ });
211
+ },
212
+ onOperationComplete: (op: MigrationPlanOperation) => {
213
+ onProgress({
214
+ action: 'dbInit',
215
+ kind: 'spanEnd',
216
+ spanId: `operation:${op.id}`,
217
+ outcome: 'ok',
218
+ });
219
+ },
220
+ }
221
+ : undefined;
222
+
126
223
  const runnerResult: MigrationRunnerResult = await runner.execute({
127
224
  plan: migrationPlan,
128
225
  driver,
129
226
  destinationContract: contractIR,
130
227
  policy,
228
+ ...(callbacks ? { callbacks } : {}),
131
229
  // db init plans and applies back-to-back from a fresh introspection, so per-operation
132
230
  // pre/postchecks and the idempotency probe are usually redundant overhead. We still
133
231
  // enforce marker/origin compatibility and a full schema verification after apply.
@@ -140,14 +238,30 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
140
238
  });
141
239
 
142
240
  if (!runnerResult.ok) {
241
+ onProgress?.({
242
+ action: 'dbInit',
243
+ kind: 'spanEnd',
244
+ spanId: applySpanId,
245
+ outcome: 'error',
246
+ });
143
247
  return notOk({
144
248
  code: 'RUNNER_FAILED' as const,
145
249
  summary: runnerResult.failure.summary,
250
+ why: runnerResult.failure.why,
251
+ meta: runnerResult.failure.meta,
252
+ conflicts: undefined,
146
253
  });
147
254
  }
148
255
 
149
256
  const execution = runnerResult.value;
150
257
 
258
+ onProgress?.({
259
+ action: 'dbInit',
260
+ kind: 'spanEnd',
261
+ spanId: applySpanId,
262
+ outcome: 'ok',
263
+ });
264
+
151
265
  const result: DbInitSuccess = {
152
266
  mode: 'apply',
153
267
  plan: { operations: migrationPlan.operations },
@@ -46,6 +46,50 @@ export interface ControlClientOptions {
46
46
  readonly connection?: unknown;
47
47
  }
48
48
 
49
+ // ============================================================================
50
+ // Progress Events
51
+ // ============================================================================
52
+
53
+ /**
54
+ * Action names for control-api operations that can emit progress events.
55
+ */
56
+ export type ControlActionName = 'dbInit' | 'verify' | 'schemaVerify' | 'sign' | 'introspect';
57
+
58
+ /**
59
+ * Progress event emitted during control-api operation execution.
60
+ *
61
+ * Events model operation progress using a span-based model:
62
+ * - `spanStart`: Begin a timed segment (supports nesting via parentSpanId)
63
+ * - `spanEnd`: Complete a timed segment
64
+ *
65
+ * All operation-specific progress (e.g., per-migration-operation) is modeled
66
+ * as nested spans rather than special event types.
67
+ *
68
+ * Events are delivered via an optional `onProgress` callback to avoid polluting
69
+ * return types. If the callback is absent, operations emit no events (zero overhead).
70
+ */
71
+ export type ControlProgressEvent =
72
+ | {
73
+ readonly action: ControlActionName;
74
+ readonly kind: 'spanStart';
75
+ readonly spanId: string;
76
+ readonly parentSpanId?: string;
77
+ readonly label: string;
78
+ }
79
+ | {
80
+ readonly action: ControlActionName;
81
+ readonly kind: 'spanEnd';
82
+ readonly spanId: string;
83
+ readonly outcome: 'ok' | 'skipped' | 'error';
84
+ };
85
+
86
+ /**
87
+ * Callback function for receiving progress events during control-api operations.
88
+ *
89
+ * @param event - The progress event emitted by the operation
90
+ */
91
+ export type OnControlProgress = (event: ControlProgressEvent) => void;
92
+
49
93
  // ============================================================================
50
94
  // Operation Options
51
95
  // ============================================================================
@@ -56,6 +100,8 @@ export interface ControlClientOptions {
56
100
  export interface VerifyOptions {
57
101
  /** Contract IR or unvalidated JSON - validated at runtime via familyInstance.validateContractIR() */
58
102
  readonly contractIR: unknown;
103
+ /** Optional progress callback for observing operation progress */
104
+ readonly onProgress?: OnControlProgress;
59
105
  }
60
106
 
61
107
  /**
@@ -70,6 +116,8 @@ export interface SchemaVerifyOptions {
70
116
  * Default: false (tolerant mode - allows superset)
71
117
  */
72
118
  readonly strict?: boolean;
119
+ /** Optional progress callback for observing operation progress */
120
+ readonly onProgress?: OnControlProgress;
73
121
  }
74
122
 
75
123
  /**
@@ -78,6 +126,8 @@ export interface SchemaVerifyOptions {
78
126
  export interface SignOptions {
79
127
  /** Contract IR or unvalidated JSON - validated at runtime via familyInstance.validateContractIR() */
80
128
  readonly contractIR: unknown;
129
+ /** Optional progress callback for observing operation progress */
130
+ readonly onProgress?: OnControlProgress;
81
131
  }
82
132
 
83
133
  /**
@@ -92,6 +142,14 @@ export interface DbInitOptions {
92
142
  * - 'apply': Applies operations and writes marker
93
143
  */
94
144
  readonly mode: 'plan' | 'apply';
145
+ /**
146
+ * Database connection. If provided, dbInit will connect before executing.
147
+ * If omitted, the client must already be connected.
148
+ * The type is driver-specific (e.g., string URL for Postgres).
149
+ */
150
+ readonly connection?: unknown;
151
+ /** Optional progress callback for observing operation progress */
152
+ readonly onProgress?: OnControlProgress;
95
153
  }
96
154
 
97
155
  /**
@@ -102,6 +160,8 @@ export interface IntrospectOptions {
102
160
  * Optional schema name to introspect.
103
161
  */
104
162
  readonly schema?: string;
163
+ /** Optional progress callback for observing operation progress */
164
+ readonly onProgress?: OnControlProgress;
105
165
  }
106
166
 
107
167
  // ============================================================================
@@ -142,7 +202,9 @@ export type DbInitFailureCode = 'PLANNING_FAILED' | 'MARKER_ORIGIN_MISMATCH' | '
142
202
  export interface DbInitFailure {
143
203
  readonly code: DbInitFailureCode;
144
204
  readonly summary: string;
145
- readonly conflicts?: ReadonlyArray<MigrationPlannerConflict>;
205
+ readonly why: string | undefined;
206
+ readonly conflicts: ReadonlyArray<MigrationPlannerConflict> | undefined;
207
+ readonly meta: Record<string, unknown> | undefined;
146
208
  readonly marker?: {
147
209
  readonly coreHash?: string;
148
210
  readonly profileHash?: string;
@@ -20,14 +20,17 @@ export { createControlClient } from '../control-api/client';
20
20
 
21
21
  // CLI-specific types
22
22
  export type {
23
+ ControlActionName,
23
24
  ControlClient,
24
25
  ControlClientOptions,
26
+ ControlProgressEvent,
25
27
  DbInitFailure,
26
28
  DbInitFailureCode,
27
29
  DbInitOptions,
28
30
  DbInitResult,
29
31
  DbInitSuccess,
30
32
  IntrospectOptions,
33
+ OnControlProgress,
31
34
  SchemaVerifyOptions,
32
35
  SignOptions,
33
36
  VerifyOptions,
@@ -0,0 +1,86 @@
1
+ import ora from 'ora';
2
+ import type { ControlProgressEvent, OnControlProgress } from '../control-api/types';
3
+ import type { GlobalFlags } from './global-flags';
4
+
5
+ /**
6
+ * Options for creating a progress adapter.
7
+ */
8
+ interface ProgressAdapterOptions {
9
+ /**
10
+ * Global flags that control progress output behavior (quiet, json, color).
11
+ */
12
+ readonly flags: GlobalFlags;
13
+ }
14
+
15
+ /**
16
+ * State for tracking active spans in the progress adapter.
17
+ */
18
+ interface SpanState {
19
+ readonly spinner: ReturnType<typeof ora>;
20
+ readonly startTime: number;
21
+ }
22
+
23
+ /**
24
+ * Creates a progress adapter that converts control-api progress events
25
+ * into CLI spinner/progress output.
26
+ *
27
+ * The adapter:
28
+ * - Starts/succeeds spinners for top-level span boundaries
29
+ * - Prints per-operation lines for nested spans (e.g., migration operations under 'apply')
30
+ * - Respects quiet/json/non-TTY flags (no-op in those cases)
31
+ *
32
+ * @param options - Progress adapter configuration
33
+ * @returns An onProgress callback compatible with control-api operations
34
+ */
35
+ export function createProgressAdapter(options: ProgressAdapterOptions): OnControlProgress {
36
+ const { flags } = options;
37
+
38
+ // Skip progress if quiet, JSON output, or non-TTY
39
+ const shouldShowProgress = !flags.quiet && flags.json !== 'object' && process.stdout.isTTY;
40
+
41
+ if (!shouldShowProgress) {
42
+ // Return a no-op callback
43
+ return () => {
44
+ // No-op
45
+ };
46
+ }
47
+
48
+ // Track active spans by spanId
49
+ const activeSpans = new Map<string, SpanState>();
50
+
51
+ return (event: ControlProgressEvent) => {
52
+ if (event.kind === 'spanStart') {
53
+ // Nested spans (with parentSpanId) are printed as lines, not spinners
54
+ if (event.parentSpanId) {
55
+ console.log(` → ${event.label}...`);
56
+ return;
57
+ }
58
+
59
+ // Top-level spans get a spinner
60
+ const spinner = ora({
61
+ text: event.label,
62
+ color: flags.color !== false ? 'cyan' : false,
63
+ }).start();
64
+
65
+ activeSpans.set(event.spanId, {
66
+ spinner,
67
+ startTime: Date.now(),
68
+ });
69
+ } else if (event.kind === 'spanEnd') {
70
+ // Complete the spinner for this span (only top-level spans have spinners)
71
+ const spanState = activeSpans.get(event.spanId);
72
+ if (spanState) {
73
+ const elapsed = Date.now() - spanState.startTime;
74
+ if (event.outcome === 'error') {
75
+ spanState.spinner.fail(`${spanState.spinner.text} (failed)`);
76
+ } else if (event.outcome === 'skipped') {
77
+ spanState.spinner.info(`${spanState.spinner.text} (skipped)`);
78
+ } else {
79
+ spanState.spinner.succeed(`${spanState.spinner.text} (${elapsed}ms)`);
80
+ }
81
+ activeSpans.delete(event.spanId);
82
+ }
83
+ // Nested span ends are no-ops (could log completion if needed)
84
+ }
85
+ };
86
+ }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/action.ts","../src/utils/command-helpers.ts","../src/utils/global-flags.ts","../src/utils/output.ts","../src/utils/result-handler.ts","../src/utils/spinner.ts"],"sourcesContent":["import type { Result } from '@prisma-next/utils/result';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport { CliStructuredError } from './cli-errors';\n\nexport type CliResult<T> = Result<T, CliStructuredError>;\n\n/**\n * Performs an async action and catches structured errors, returning a Result.\n * Only catches CliStructuredError instances - other errors are allowed to propagate (fail fast).\n * If the function throws a CliStructuredError, it's caught and converted to a NotOk result.\n */\nexport async function performAction<T>(fn: () => Promise<T>): Promise<CliResult<T>> {\n try {\n const value = await fn();\n return ok(value);\n } catch (error) {\n // Only catch structured errors - let other errors propagate (fail fast)\n if (error instanceof CliStructuredError) {\n return notOk(error);\n }\n // Re-throw non-structured errors to fail fast\n throw error;\n }\n}\n\n/**\n * Wraps a synchronous function to catch structured errors and return a Result.\n * Only catches CliStructuredError instances - other errors are allowed to propagate (fail fast).\n * If the function throws a CliStructuredError, it's caught and converted to a NotOk result.\n */\nexport function wrapSync<T>(fn: () => T): CliResult<T> {\n try {\n const value = fn();\n return ok(value);\n } catch (error) {\n // Only catch structured errors - let other errors propagate (fail fast)\n if (error instanceof CliStructuredError) {\n return notOk(error);\n }\n // Re-throw non-structured errors to fail fast\n throw error;\n }\n}\n","import type { Command } from 'commander';\n\n/**\n * Sets both short and long descriptions for a command.\n * The short description is used in command trees and headers.\n * The long description is shown at the bottom of help output.\n */\nexport function setCommandDescriptions(\n command: Command,\n shortDescription: string,\n longDescription?: string,\n): Command {\n command.description(shortDescription);\n if (longDescription) {\n // Store long description in a custom property for our formatters to access\n (command as Command & { _longDescription?: string })._longDescription = longDescription;\n }\n return command;\n}\n\n/**\n * Gets the long description from a command if it was set via setCommandDescriptions.\n */\nexport function getLongDescription(command: Command): string | undefined {\n return (command as Command & { _longDescription?: string })._longDescription;\n}\n","export interface GlobalFlags {\n readonly json?: 'object' | 'ndjson';\n readonly quiet?: boolean;\n readonly verbose?: number; // 0, 1, or 2\n readonly timestamps?: boolean;\n readonly color?: boolean;\n}\n\nexport interface CliOptions {\n readonly json?: string | boolean;\n readonly quiet?: boolean;\n readonly q?: boolean;\n readonly verbose?: boolean;\n readonly v?: boolean;\n readonly vv?: boolean;\n readonly trace?: boolean;\n readonly timestamps?: boolean;\n readonly color?: boolean;\n readonly 'no-color'?: boolean;\n}\n\n/**\n * Parses global flags from CLI options.\n * Handles verbosity flags (-v, -vv, --trace), JSON output, quiet mode, timestamps, and color.\n */\nexport function parseGlobalFlags(options: CliOptions): GlobalFlags {\n const flags: {\n json?: 'object' | 'ndjson';\n quiet?: boolean;\n verbose?: number;\n timestamps?: boolean;\n color?: boolean;\n } = {};\n\n // JSON output\n if (options.json === true || options.json === 'object') {\n flags.json = 'object';\n } else if (options.json === 'ndjson') {\n flags.json = 'ndjson';\n }\n\n // Quiet mode\n if (options.quiet || options.q) {\n flags.quiet = true;\n }\n\n // Verbosity: -v = 1, -vv or --trace = 2\n if (options.vv || options.trace) {\n flags.verbose = 2;\n } else if (options.verbose || options.v) {\n flags.verbose = 1;\n } else {\n flags.verbose = 0;\n }\n\n // Timestamps\n if (options.timestamps) {\n flags.timestamps = true;\n }\n\n // Color: respect NO_COLOR env var, --color/--no-color flags\n // When JSON output is enabled (any format), disable color to ensure clean JSON output\n if (process.env['NO_COLOR'] || flags.json) {\n flags.color = false;\n } else if (options['no-color']) {\n flags.color = false;\n } else if (options.color !== undefined) {\n flags.color = options.color;\n } else {\n // Default: enable color if TTY\n flags.color = process.stdout.isTTY && !process.env['CI'];\n }\n\n return flags as GlobalFlags;\n}\n","import { relative } from 'node:path';\nimport { bgGreen, blue, bold, cyan, dim, green, magenta, red, yellow } from 'colorette';\nimport type { Command } from 'commander';\nimport stringWidth from 'string-width';\nimport stripAnsi from 'strip-ansi';\nimport wrapAnsi from 'wrap-ansi';\n// EmitContractResult type for CLI output formatting (includes file paths)\nexport interface EmitContractResult {\n readonly coreHash: string;\n readonly profileHash: string;\n readonly outDir: string;\n readonly files: {\n readonly json: string;\n readonly dts: string;\n };\n readonly timings: {\n readonly total: number;\n };\n}\n\nimport type { CoreSchemaView, SchemaTreeNode } from '@prisma-next/core-control-plane/schema-view';\nimport type {\n IntrospectSchemaResult,\n SchemaVerificationNode,\n SignDatabaseResult,\n VerifyDatabaseResult,\n VerifyDatabaseSchemaResult,\n} from '@prisma-next/core-control-plane/types';\nimport type { CliErrorConflict, CliErrorEnvelope } from './cli-errors';\nimport { getLongDescription } from './command-helpers';\nimport type { GlobalFlags } from './global-flags';\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Formats a timestamp for output.\n */\nfunction formatTimestamp(): string {\n return new Date().toISOString();\n}\n\n/**\n * Creates a prefix string if timestamps are enabled.\n */\nfunction createPrefix(flags: GlobalFlags): string {\n return flags.timestamps ? `[${formatTimestamp()}] ` : '';\n}\n\n/**\n * Checks if verbose output is enabled at the specified level.\n */\nfunction isVerbose(flags: GlobalFlags, level: 1 | 2): boolean {\n return (flags.verbose ?? 0) >= level;\n}\n\n/**\n * Creates a color-aware formatter function.\n * Returns a function that applies the color only if colors are enabled.\n */\nfunction createColorFormatter<T extends (text: string) => string>(\n useColor: boolean,\n colorFn: T,\n): (text: string) => string {\n return useColor ? colorFn : (text: string) => text;\n}\n\n/**\n * Formats text with dim styling if colors are enabled.\n */\nfunction formatDim(useColor: boolean, text: string): string {\n return useColor ? dim(text) : text;\n}\n\n// ============================================================================\n// Emit Output Formatters\n// ============================================================================\n\n/**\n * Formats human-readable output for contract emit.\n */\nexport function formatEmitOutput(result: EmitContractResult, flags: GlobalFlags): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n const prefix = createPrefix(flags);\n\n // Convert absolute paths to relative paths from cwd\n const jsonPath = relative(process.cwd(), result.files.json);\n const dtsPath = relative(process.cwd(), result.files.dts);\n\n lines.push(`${prefix}✔ Emitted contract.json → ${jsonPath}`);\n lines.push(`${prefix}✔ Emitted contract.d.ts → ${dtsPath}`);\n lines.push(`${prefix} coreHash: ${result.coreHash}`);\n if (result.profileHash) {\n lines.push(`${prefix} profileHash: ${result.profileHash}`);\n }\n if (isVerbose(flags, 1)) {\n lines.push(`${prefix} Total time: ${result.timings.total}ms`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Formats JSON output for contract emit.\n */\nexport function formatEmitJson(result: EmitContractResult): string {\n const output = {\n ok: true,\n coreHash: result.coreHash,\n ...(result.profileHash ? { profileHash: result.profileHash } : {}),\n outDir: result.outDir,\n files: result.files,\n timings: result.timings,\n };\n\n return JSON.stringify(output, null, 2);\n}\n\n// ============================================================================\n// Error Output Formatters\n// ============================================================================\n\n/**\n * Formats error output for human-readable display.\n */\nexport function formatErrorOutput(error: CliErrorEnvelope, flags: GlobalFlags): string {\n const lines: string[] = [];\n const prefix = createPrefix(flags);\n const useColor = flags.color !== false;\n const formatRed = createColorFormatter(useColor, red);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n lines.push(`${prefix}${formatRed('✖')} ${error.summary} (${error.code})`);\n\n if (error.why) {\n lines.push(`${prefix}${formatDimText(` Why: ${error.why}`)}`);\n }\n if (error.fix) {\n lines.push(`${prefix}${formatDimText(` Fix: ${error.fix}`)}`);\n }\n if (error.where?.path) {\n const whereLine = error.where.line\n ? `${error.where.path}:${error.where.line}`\n : error.where.path;\n lines.push(`${prefix}${formatDimText(` Where: ${whereLine}`)}`);\n }\n // Show conflicts list if present (always show a short list; show full list when verbose)\n if (error.meta?.['conflicts']) {\n const conflicts = error.meta['conflicts'] as readonly CliErrorConflict[];\n if (conflicts.length > 0) {\n const maxToShow = isVerbose(flags, 1) ? conflicts.length : Math.min(3, conflicts.length);\n const header = isVerbose(flags, 1)\n ? ' Conflicts:'\n : ` Conflicts (showing ${maxToShow} of ${conflicts.length}):`;\n lines.push(`${prefix}${formatDimText(header)}`);\n for (const conflict of conflicts.slice(0, maxToShow)) {\n lines.push(`${prefix}${formatDimText(` - [${conflict.kind}] ${conflict.summary}`)}`);\n }\n if (!isVerbose(flags, 1) && conflicts.length > maxToShow) {\n lines.push(`${prefix}${formatDimText(' Re-run with -v/--verbose to see all conflicts')}`);\n }\n }\n }\n // Show issues list if present (always show a short list; show full list when verbose)\n if (error.meta?.['issues']) {\n const issues = error.meta['issues'] as readonly { kind?: string; message?: string }[];\n if (issues.length > 0) {\n const maxToShow = isVerbose(flags, 1) ? issues.length : Math.min(3, issues.length);\n const header = isVerbose(flags, 1)\n ? ' Issues:'\n : ` Issues (showing ${maxToShow} of ${issues.length}):`;\n lines.push(`${prefix}${formatDimText(header)}`);\n for (const issue of issues.slice(0, maxToShow)) {\n const kind = issue.kind ?? 'issue';\n const message = issue.message ?? '';\n lines.push(`${prefix}${formatDimText(` - [${kind}] ${message}`)}`);\n }\n if (!isVerbose(flags, 1) && issues.length > maxToShow) {\n lines.push(`${prefix}${formatDimText(' Re-run with -v/--verbose to see all issues')}`);\n }\n }\n }\n if (error.docsUrl && isVerbose(flags, 1)) {\n lines.push(formatDimText(error.docsUrl));\n }\n if (isVerbose(flags, 2) && error.meta) {\n lines.push(`${prefix}${formatDimText(` Meta: ${JSON.stringify(error.meta, null, 2)}`)}`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Formats error output as JSON.\n */\nexport function formatErrorJson(error: CliErrorEnvelope): string {\n return JSON.stringify(error, null, 2);\n}\n\n// ============================================================================\n// Verify Output Formatters\n// ============================================================================\n\n/**\n * Formats human-readable output for database verify.\n */\nexport function formatVerifyOutput(result: VerifyDatabaseResult, flags: GlobalFlags): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n const prefix = createPrefix(flags);\n const useColor = flags.color !== false;\n const formatGreen = createColorFormatter(useColor, green);\n const formatRed = createColorFormatter(useColor, red);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n if (result.ok) {\n lines.push(`${prefix}${formatGreen('✔')} ${result.summary}`);\n lines.push(`${prefix}${formatDimText(` coreHash: ${result.contract.coreHash}`)}`);\n if (result.contract.profileHash) {\n lines.push(`${prefix}${formatDimText(` profileHash: ${result.contract.profileHash}`)}`);\n }\n } else {\n lines.push(`${prefix}${formatRed('✖')} ${result.summary} (${result.code})`);\n }\n\n if (isVerbose(flags, 1)) {\n if (result.codecCoverageSkipped) {\n lines.push(\n `${prefix}${formatDimText(' Codec coverage check skipped (helper returned no supported types)')}`,\n );\n }\n lines.push(`${prefix}${formatDimText(` Total time: ${result.timings.total}ms`)}`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Formats JSON output for database verify.\n */\nexport function formatVerifyJson(result: VerifyDatabaseResult): string {\n const output = {\n ok: result.ok,\n ...(result.code ? { code: result.code } : {}),\n summary: result.summary,\n contract: result.contract,\n ...(result.marker ? { marker: result.marker } : {}),\n target: result.target,\n ...(result.missingCodecs ? { missingCodecs: result.missingCodecs } : {}),\n ...(result.meta ? { meta: result.meta } : {}),\n timings: result.timings,\n };\n\n return JSON.stringify(output, null, 2);\n}\n\n/**\n * Formats JSON output for database introspection.\n */\nexport function formatIntrospectJson(result: IntrospectSchemaResult<unknown>): string {\n return JSON.stringify(result, null, 2);\n}\n\n/**\n * Renders a schema tree structure from CoreSchemaView.\n * Matches the style of renderSchemaVerificationTree for consistency.\n */\nfunction renderSchemaTree(\n node: SchemaTreeNode,\n flags: GlobalFlags,\n options: {\n readonly isLast: boolean;\n readonly prefix: string;\n readonly useColor: boolean;\n readonly formatDimText: (text: string) => string;\n readonly isRoot?: boolean;\n },\n): string[] {\n const { isLast, prefix, useColor, formatDimText, isRoot = false } = options;\n const lines: string[] = [];\n\n // Format node label with color based on kind (matching schema-verify style)\n let formattedLabel: string = node.label;\n\n if (useColor) {\n switch (node.kind) {\n case 'root':\n formattedLabel = bold(node.label);\n break;\n case 'entity': {\n // Parse \"table tableName\" format - color \"table\" dim, tableName cyan\n const tableMatch = node.label.match(/^table\\s+(.+)$/);\n if (tableMatch?.[1]) {\n const tableName = tableMatch[1];\n formattedLabel = `${dim('table')} ${cyan(tableName)}`;\n } else {\n // Fallback: color entire label with cyan\n formattedLabel = cyan(node.label);\n }\n break;\n }\n case 'collection': {\n // \"columns\" grouping node - dim the label\n formattedLabel = dim(node.label);\n break;\n }\n case 'field': {\n // Parse column name format: \"columnName: typeDisplay (nullability)\"\n // Color code: column name (cyan), type (default), nullability (dim)\n const columnMatch = node.label.match(/^([^:]+):\\s*(.+)$/);\n if (columnMatch?.[1] && columnMatch[2]) {\n const columnName = columnMatch[1];\n const rest = columnMatch[2];\n // Parse rest: \"typeDisplay (nullability)\"\n const typeMatch = rest.match(/^([^\\s(]+)\\s*(\\([^)]+\\))$/);\n if (typeMatch?.[1] && typeMatch[2]) {\n const typeDisplay = typeMatch[1];\n const nullability = typeMatch[2];\n formattedLabel = `${cyan(columnName)}: ${typeDisplay} ${dim(nullability)}`;\n } else {\n // Fallback if format doesn't match\n formattedLabel = `${cyan(columnName)}: ${rest}`;\n }\n } else {\n formattedLabel = node.label;\n }\n break;\n }\n case 'index': {\n // Parse index/unique constraint/primary key formats\n // \"primary key: columnName\" -> dim \"primary key\", cyan columnName\n const pkMatch = node.label.match(/^primary key:\\s*(.+)$/);\n if (pkMatch?.[1]) {\n const columnNames = pkMatch[1];\n formattedLabel = `${dim('primary key')}: ${cyan(columnNames)}`;\n } else {\n // \"unique name\" -> dim \"unique\", cyan \"name\"\n const uniqueMatch = node.label.match(/^unique\\s+(.+)$/);\n if (uniqueMatch?.[1]) {\n const name = uniqueMatch[1];\n formattedLabel = `${dim('unique')} ${cyan(name)}`;\n } else {\n // \"index name\" or \"unique index name\" -> dim label prefix, cyan name\n const indexMatch = node.label.match(/^(unique\\s+)?index\\s+(.+)$/);\n if (indexMatch?.[2]) {\n const prefix = indexMatch[1] ? `${dim('unique')} ` : '';\n const name = indexMatch[2];\n formattedLabel = `${prefix}${dim('index')} ${cyan(name)}`;\n } else {\n formattedLabel = dim(node.label);\n }\n }\n }\n break;\n }\n case 'extension': {\n // Parse extension message formats similar to schema-verify\n // \"extensionName extension is enabled\" -> cyan extensionName, dim rest\n const extMatch = node.label.match(/^([^\\s]+)\\s+(extension is enabled)$/);\n if (extMatch?.[1] && extMatch[2]) {\n const extName = extMatch[1];\n const rest = extMatch[2];\n formattedLabel = `${cyan(extName)} ${dim(rest)}`;\n } else {\n // Fallback: color entire label with magenta\n formattedLabel = magenta(node.label);\n }\n break;\n }\n default:\n formattedLabel = node.label;\n break;\n }\n }\n\n // Root node renders without tree characters or │ prefix\n if (isRoot) {\n lines.push(formattedLabel);\n } else {\n // Determine tree character for this node\n const treeChar = isLast ? '└' : '├';\n const treePrefix = `${prefix}${formatDimText(treeChar)}─ `;\n // Root's direct children don't have │ prefix, other nodes do\n // But if prefix already contains │ (for nested children), don't add another\n const isRootChild = prefix === '';\n // Check if prefix already contains │ (strip ANSI codes for comparison)\n const prefixWithoutAnsi = stripAnsi(prefix);\n const prefixHasVerticalBar = prefixWithoutAnsi.includes('│');\n if (isRootChild) {\n lines.push(`${treePrefix}${formattedLabel}`);\n } else if (prefixHasVerticalBar) {\n // Prefix already has │, so just use treePrefix directly\n lines.push(`${treePrefix}${formattedLabel}`);\n } else {\n lines.push(`${formatDimText('│')} ${treePrefix}${formattedLabel}`);\n }\n }\n\n // Render children if present\n if (node.children && node.children.length > 0) {\n // For root node, children start with no prefix (they'll add their own tree characters)\n // For other nodes, calculate child prefix based on whether this is last\n const childPrefix = isRoot ? '' : isLast ? `${prefix} ` : `${prefix}${formatDimText('│')} `;\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n if (!child) continue;\n const isLastChild = i === node.children.length - 1;\n const childLines = renderSchemaTree(child, flags, {\n isLast: isLastChild,\n prefix: childPrefix,\n useColor,\n formatDimText,\n isRoot: false,\n });\n lines.push(...childLines);\n }\n }\n\n return lines;\n}\n\n/**\n * Formats human-readable output for database introspection.\n */\nexport function formatIntrospectOutput(\n result: IntrospectSchemaResult<unknown>,\n schemaView: CoreSchemaView | undefined,\n flags: GlobalFlags,\n): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n const prefix = createPrefix(flags);\n const useColor = flags.color !== false;\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n if (schemaView) {\n // Render tree structure - root node is special (no tree characters)\n const treeLines = renderSchemaTree(schemaView.root, flags, {\n isLast: true,\n prefix: '',\n useColor,\n formatDimText,\n isRoot: true,\n });\n // Apply prefix (for timestamps) to each tree line\n const prefixedTreeLines = treeLines.map((line) => `${prefix}${line}`);\n lines.push(...prefixedTreeLines);\n } else {\n // Fallback: print summary when toSchemaView is not available\n lines.push(`${prefix}✔ ${result.summary}`);\n if (isVerbose(flags, 1)) {\n lines.push(`${prefix} Target: ${result.target.familyId}/${result.target.id}`);\n if (result.meta?.dbUrl) {\n lines.push(`${prefix} Database: ${result.meta.dbUrl}`);\n }\n }\n }\n\n // Add timings in verbose mode\n if (isVerbose(flags, 1)) {\n lines.push(`${prefix}${formatDimText(` Total time: ${result.timings.total}ms`)}`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Renders a schema verification tree structure from SchemaVerificationNode.\n * Similar to renderSchemaTree but for verification nodes with status-based colors and glyphs.\n */\nfunction renderSchemaVerificationTree(\n node: SchemaVerificationNode,\n flags: GlobalFlags,\n options: {\n readonly isLast: boolean;\n readonly prefix: string;\n readonly useColor: boolean;\n readonly formatDimText: (text: string) => string;\n readonly isRoot?: boolean;\n },\n): string[] {\n const { isLast, prefix, useColor, formatDimText, isRoot = false } = options;\n const lines: string[] = [];\n\n // Format status glyph and color based on status\n let statusGlyph = '';\n let statusColor: (text: string) => string = (text) => text;\n if (useColor) {\n switch (node.status) {\n case 'pass':\n statusGlyph = '✔';\n statusColor = green;\n break;\n case 'warn':\n statusGlyph = '⚠';\n statusColor = (text) => (useColor ? yellow(text) : text);\n break;\n case 'fail':\n statusGlyph = '✖';\n statusColor = red;\n break;\n }\n } else {\n switch (node.status) {\n case 'pass':\n statusGlyph = '✔';\n break;\n case 'warn':\n statusGlyph = '⚠';\n break;\n case 'fail':\n statusGlyph = '✖';\n break;\n }\n }\n\n // Format node label with color based on kind\n // For column nodes, we need to parse the name to color code different parts\n let labelColor: (text: string) => string = (text) => text;\n let formattedLabel: string = node.name;\n\n if (useColor) {\n switch (node.kind) {\n case 'contract':\n case 'schema':\n labelColor = bold;\n formattedLabel = labelColor(node.name);\n break;\n case 'table': {\n // Parse \"table tableName\" format - color \"table\" dim, tableName cyan\n const tableMatch = node.name.match(/^table\\s+(.+)$/);\n if (tableMatch?.[1]) {\n const tableName = tableMatch[1];\n formattedLabel = `${dim('table')} ${cyan(tableName)}`;\n } else {\n formattedLabel = dim(node.name);\n }\n break;\n }\n case 'columns':\n labelColor = dim;\n formattedLabel = labelColor(node.name);\n break;\n case 'column': {\n // Parse column name format: \"columnName: contractType → nativeType (nullability)\"\n // Color code: column name (cyan), contract type (default), native type (dim), nullability (dim)\n const columnMatch = node.name.match(/^([^:]+):\\s*(.+)$/);\n if (columnMatch?.[1] && columnMatch[2]) {\n const columnName = columnMatch[1];\n const rest = columnMatch[2];\n // Parse rest: \"contractType → nativeType (nullability)\"\n // Match contract type (can contain /, @, etc.), arrow, native type, then nullability in parentheses\n const typeMatch = rest.match(/^([^\\s→]+)\\s*→\\s*([^\\s(]+)\\s*(\\([^)]+\\))$/);\n if (typeMatch?.[1] && typeMatch[2] && typeMatch[3]) {\n const contractType = typeMatch[1];\n const nativeType = typeMatch[2];\n const nullability = typeMatch[3];\n formattedLabel = `${cyan(columnName)}: ${contractType} → ${dim(nativeType)} ${dim(nullability)}`;\n } else {\n // Fallback if format doesn't match (e.g., no native type or no nullability)\n formattedLabel = `${cyan(columnName)}: ${rest}`;\n }\n } else {\n formattedLabel = node.name;\n }\n break;\n }\n case 'type':\n case 'nullability':\n labelColor = (text) => text; // Default color\n formattedLabel = labelColor(node.name);\n break;\n case 'primaryKey': {\n // Parse \"primary key: columnName\" format - color \"primary key\" dim, columnName cyan\n const pkMatch = node.name.match(/^primary key:\\s*(.+)$/);\n if (pkMatch?.[1]) {\n const columnNames = pkMatch[1];\n formattedLabel = `${dim('primary key')}: ${cyan(columnNames)}`;\n } else {\n formattedLabel = dim(node.name);\n }\n break;\n }\n case 'foreignKey':\n case 'unique':\n case 'index':\n labelColor = dim;\n formattedLabel = labelColor(node.name);\n break;\n case 'extension': {\n // Parse specific extension message formats\n // \"database is postgres\" -> dim \"database is\", cyan \"postgres\"\n const dbMatch = node.name.match(/^database is\\s+(.+)$/);\n if (dbMatch?.[1]) {\n const dbName = dbMatch[1];\n formattedLabel = `${dim('database is')} ${cyan(dbName)}`;\n } else {\n // \"vector extension is enabled\" -> dim everything except extension name\n // Match pattern: \"extensionName extension is enabled\"\n const extMatch = node.name.match(/^([^\\s]+)\\s+(extension is enabled)$/);\n if (extMatch?.[1] && extMatch[2]) {\n const extName = extMatch[1];\n const rest = extMatch[2];\n formattedLabel = `${cyan(extName)} ${dim(rest)}`;\n } else {\n // Fallback: color entire name with magenta\n labelColor = magenta;\n formattedLabel = labelColor(node.name);\n }\n }\n break;\n }\n default:\n formattedLabel = node.name;\n break;\n }\n } else {\n formattedLabel = node.name;\n }\n\n const statusGlyphColored = statusColor(statusGlyph);\n\n // Build the label with optional message for failure/warn nodes\n let nodeLabel = formattedLabel;\n if (\n (node.status === 'fail' || node.status === 'warn') &&\n node.message &&\n node.message.length > 0\n ) {\n // Always show message for failure/warn nodes - it provides crucial context\n // For parent nodes, the message summarizes child failures\n // For leaf nodes, the message explains the specific issue\n const messageText = formatDimText(`(${node.message})`);\n nodeLabel = `${formattedLabel} ${messageText}`;\n }\n\n // Root node renders without tree characters or │ prefix\n if (isRoot) {\n lines.push(`${statusGlyphColored} ${nodeLabel}`);\n } else {\n // Determine tree character for this node\n const treeChar = isLast ? '└' : '├';\n const treePrefix = `${prefix}${formatDimText(treeChar)}─ `;\n // Root's direct children don't have │ prefix, other nodes do\n const isRootChild = prefix === '';\n // Check if prefix already contains │ (strip ANSI codes for comparison)\n const prefixWithoutAnsi = stripAnsi(prefix);\n const prefixHasVerticalBar = prefixWithoutAnsi.includes('│');\n if (isRootChild) {\n lines.push(`${treePrefix}${statusGlyphColored} ${nodeLabel}`);\n } else if (prefixHasVerticalBar) {\n // Prefix already has │, so just use treePrefix directly\n lines.push(`${treePrefix}${statusGlyphColored} ${nodeLabel}`);\n } else {\n lines.push(`${formatDimText('│')} ${treePrefix}${statusGlyphColored} ${nodeLabel}`);\n }\n }\n\n // Render children if present\n if (node.children && node.children.length > 0) {\n // For root node, children start with no prefix (they'll add their own tree characters)\n // For other nodes, calculate child prefix based on whether this is last\n const childPrefix = isRoot ? '' : isLast ? `${prefix} ` : `${prefix}${formatDimText('│')} `;\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n if (!child) continue;\n const isLastChild = i === node.children.length - 1;\n const childLines = renderSchemaVerificationTree(child, flags, {\n isLast: isLastChild,\n prefix: childPrefix,\n useColor,\n formatDimText,\n isRoot: false,\n });\n lines.push(...childLines);\n }\n }\n\n return lines;\n}\n\n/**\n * Formats human-readable output for database schema verification.\n */\nexport function formatSchemaVerifyOutput(\n result: VerifyDatabaseSchemaResult,\n flags: GlobalFlags,\n): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n const prefix = createPrefix(flags);\n const useColor = flags.color !== false;\n const formatGreen = createColorFormatter(useColor, green);\n const formatRed = createColorFormatter(useColor, red);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n // Render verification tree first\n const treeLines = renderSchemaVerificationTree(result.schema.root, flags, {\n isLast: true,\n prefix: '',\n useColor,\n formatDimText,\n isRoot: true,\n });\n // Apply prefix (for timestamps) to each tree line\n const prefixedTreeLines = treeLines.map((line) => `${prefix}${line}`);\n lines.push(...prefixedTreeLines);\n\n // Add counts and timings in verbose mode\n if (isVerbose(flags, 1)) {\n lines.push(`${prefix}${formatDimText(` Total time: ${result.timings.total}ms`)}`);\n lines.push(\n `${prefix}${formatDimText(` pass=${result.schema.counts.pass} warn=${result.schema.counts.warn} fail=${result.schema.counts.fail}`)}`,\n );\n }\n\n // Blank line before summary\n lines.push('');\n\n // Summary line at the end: summary with status glyph\n if (result.ok) {\n lines.push(`${prefix}${formatGreen('✔')} ${result.summary}`);\n } else {\n const codeText = result.code ? ` (${result.code})` : '';\n lines.push(`${prefix}${formatRed('✖')} ${result.summary}${codeText}`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Formats JSON output for database schema verification.\n */\nexport function formatSchemaVerifyJson(result: VerifyDatabaseSchemaResult): string {\n return JSON.stringify(result, null, 2);\n}\n\n// ============================================================================\n// Sign Output Formatters\n// ============================================================================\n\n/**\n * Formats human-readable output for database sign.\n */\nexport function formatSignOutput(result: SignDatabaseResult, flags: GlobalFlags): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n const prefix = createPrefix(flags);\n const useColor = flags.color !== false;\n const formatGreen = createColorFormatter(useColor, green);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n if (result.ok) {\n // Main success message in white (not dimmed)\n lines.push(`${prefix}${formatGreen('✔')} Database signed`);\n\n // Show from -> to hashes with clear labels\n const previousHash = result.marker.previous?.coreHash ?? 'none';\n const currentHash = result.contract.coreHash;\n\n lines.push(`${prefix}${formatDimText(` from: ${previousHash}`)}`);\n lines.push(`${prefix}${formatDimText(` to: ${currentHash}`)}`);\n\n if (isVerbose(flags, 1)) {\n if (result.contract.profileHash) {\n lines.push(`${prefix}${formatDimText(` profileHash: ${result.contract.profileHash}`)}`);\n }\n if (result.marker.previous?.profileHash) {\n lines.push(\n `${prefix}${formatDimText(` previous profileHash: ${result.marker.previous.profileHash}`)}`,\n );\n }\n lines.push(`${prefix}${formatDimText(` Total time: ${result.timings.total}ms`)}`);\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Formats JSON output for database sign.\n */\nexport function formatSignJson(result: SignDatabaseResult): string {\n return JSON.stringify(result, null, 2);\n}\n\n// ============================================================================\n// DB Init Output Formatters\n// ============================================================================\n\n/**\n * Result type for db init command.\n */\nexport interface DbInitResult {\n readonly ok: boolean;\n readonly mode: 'plan' | 'apply';\n readonly plan?: {\n readonly targetId: string;\n readonly destination: {\n readonly coreHash: string;\n readonly profileHash?: string;\n };\n readonly operations: readonly {\n readonly id: string;\n readonly label: string;\n readonly operationClass: string;\n }[];\n };\n readonly execution?: {\n readonly operationsPlanned: number;\n readonly operationsExecuted: number;\n };\n readonly marker?: {\n readonly coreHash: string;\n readonly profileHash?: string;\n };\n readonly summary: string;\n readonly timings: {\n readonly total: number;\n };\n}\n\n/**\n * Formats human-readable output for db init plan mode.\n */\nexport function formatDbInitPlanOutput(result: DbInitResult, flags: GlobalFlags): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n const prefix = createPrefix(flags);\n const useColor = flags.color !== false;\n const formatGreen = createColorFormatter(useColor, green);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n // Plan summary\n const operationCount = result.plan?.operations.length ?? 0;\n lines.push(`${prefix}${formatGreen('✔')} Planned ${operationCount} operation(s)`);\n\n // Show operations tree\n if (result.plan?.operations && result.plan.operations.length > 0) {\n lines.push(`${prefix}${formatDimText('│')}`);\n for (let i = 0; i < result.plan.operations.length; i++) {\n const op = result.plan.operations[i];\n if (!op) continue;\n const isLast = i === result.plan.operations.length - 1;\n const treeChar = isLast ? '└' : '├';\n const opClass = formatDimText(`[${op.operationClass}]`);\n lines.push(`${prefix}${formatDimText(treeChar)}─ ${op.label} ${opClass}`);\n }\n }\n\n // Destination hash\n if (result.plan?.destination) {\n lines.push(`${prefix}`);\n lines.push(\n `${prefix}${formatDimText(`Destination hash: ${result.plan.destination.coreHash}`)}`,\n );\n }\n\n // Timings in verbose mode\n if (isVerbose(flags, 1)) {\n lines.push(`${prefix}${formatDimText(`Total time: ${result.timings.total}ms`)}`);\n }\n\n // Note about dry run\n lines.push(`${prefix}`);\n lines.push(`${prefix}${formatDimText('This is a dry run. No changes were applied.')}`);\n lines.push(`${prefix}${formatDimText('Run without --plan to apply changes.')}`);\n\n return lines.join('\\n');\n}\n\n/**\n * Formats human-readable output for db init apply mode.\n */\nexport function formatDbInitApplyOutput(result: DbInitResult, flags: GlobalFlags): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n const prefix = createPrefix(flags);\n const useColor = flags.color !== false;\n const formatGreen = createColorFormatter(useColor, green);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n if (result.ok) {\n // Success summary\n const executed = result.execution?.operationsExecuted ?? 0;\n lines.push(`${prefix}${formatGreen('✔')} Applied ${executed} operation(s)`);\n\n // Marker info\n if (result.marker) {\n lines.push(`${prefix}${formatDimText(` Marker written: ${result.marker.coreHash}`)}`);\n if (result.marker.profileHash) {\n lines.push(`${prefix}${formatDimText(` Profile hash: ${result.marker.profileHash}`)}`);\n }\n }\n\n // Timings in verbose mode\n if (isVerbose(flags, 1)) {\n lines.push(`${prefix}${formatDimText(` Total time: ${result.timings.total}ms`)}`);\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Formats JSON output for db init command.\n */\nexport function formatDbInitJson(result: DbInitResult): string {\n return JSON.stringify(result, null, 2);\n}\n\n// ============================================================================\n// Styled Output Formatters\n// ============================================================================\n\n/**\n * Fixed width for left column in help output.\n */\nconst LEFT_COLUMN_WIDTH = 20;\n\n/**\n * Minimum width for right column wrapping in help output.\n */\nconst RIGHT_COLUMN_MIN_WIDTH = 40;\n\n/**\n * Maximum width for right column wrapping in help output (when terminal is wide enough).\n */\nconst RIGHT_COLUMN_MAX_WIDTH = 90;\n\n/**\n * Gets the terminal width, or returns a default if not available.\n */\nfunction getTerminalWidth(): number {\n // process.stdout.columns may be undefined in non-TTY environments\n const terminalWidth = process.stdout.columns;\n // Default to 80 if terminal width is not available, but allow override via env var\n const defaultWidth = Number.parseInt(process.env['CLI_WIDTH'] || '80', 10);\n return terminalWidth || defaultWidth;\n}\n\n/**\n * Calculates the available width for the right column based on terminal width.\n * Format: \"│ \" (2) + left column (20) + \" \" (2) + right column = total\n * So: right column = terminal width - 2 - 20 - 2 = terminal width - 24\n */\nfunction calculateRightColumnWidth(): number {\n const terminalWidth = getTerminalWidth();\n const availableWidth = terminalWidth - 2 - LEFT_COLUMN_WIDTH - 2; // Subtract separators and left column\n // Ensure minimum width, but don't exceed maximum\n return Math.max(RIGHT_COLUMN_MIN_WIDTH, Math.min(availableWidth, RIGHT_COLUMN_MAX_WIDTH));\n}\n\n/**\n * Creates an arrow segment badge with green background and white text.\n * Body: green background with white \"prisma-next\" text\n * Tip: dark grey arrow pointing right (Powerline separator)\n */\nfunction createPrismaNextBadge(useColor: boolean): string {\n if (!useColor) {\n return 'prisma-next';\n }\n // Body: green background with white text\n const text = ' prisma-next ';\n const body = bgGreen(bold(text));\n\n // Use Powerline separator (U+E0B0) which creates the arrow transition effect\n const separator = '\\u{E0B0}';\n const tip = green(separator); // Dark grey arrow tip\n\n return `${body}${tip}`;\n}\n\n/**\n * Creates a padding function.\n */\nfunction createPadFunction(): (s: string, w: number) => string {\n return (s: string, w: number) => s + ' '.repeat(Math.max(0, w - s.length));\n}\n\n/**\n * Formats a header line: brand + operation + intent\n */\nfunction formatHeaderLine(options: {\n readonly brand: string;\n readonly operation: string;\n readonly intent: string;\n}): string {\n if (options.operation) {\n return `${options.brand} ${options.operation} → ${options.intent}`;\n }\n return `${options.brand} ${options.intent}`;\n}\n\n/**\n * Formats a \"Read more\" URL line.\n * The \"Read more\" label is in default color (not cyan), and the URL is blue.\n */\nfunction formatReadMoreLine(options: {\n readonly url: string;\n readonly maxLabelWidth: number;\n readonly useColor: boolean;\n readonly formatDimText: (text: string) => string;\n}): string {\n const pad = createPadFunction();\n const labelPadded = pad('Read more', options.maxLabelWidth);\n // Label is default color (not cyan)\n const valueColored = options.useColor ? blue(options.url) : options.url;\n return `${options.formatDimText('│')} ${labelPadded} ${valueColored}`;\n}\n\n/**\n * Pads text to a fixed width, accounting for ANSI escape codes.\n * Uses string-width to measure the actual display width.\n */\nfunction padToFixedWidth(text: string, width: number): string {\n const actualWidth = stringWidth(text);\n const padding = Math.max(0, width - actualWidth);\n return text + ' '.repeat(padding);\n}\n\n/**\n * Wraps text to fit within a specified width using wrap-ansi.\n * Preserves ANSI escape codes and breaks at word boundaries.\n */\nfunction wrapTextAnsi(text: string, width: number): string[] {\n const wrapped = wrapAnsi(text, width, { hard: false, trim: true });\n return wrapped.split('\\n');\n}\n\n/**\n * Formats a default value as \"default: <value>\" with dimming.\n */\nfunction formatDefaultValue(value: unknown, useColor: boolean): string {\n const valueStr = String(value);\n const defaultText = `default: ${valueStr}`;\n return useColor ? dim(defaultText) : defaultText;\n}\n\n/**\n * Renders a command tree structure.\n * Handles both single-level (subcommands of a command) and multi-level (top-level commands with subcommands) trees.\n */\nfunction renderCommandTree(options: {\n readonly commands: readonly Command[];\n readonly useColor: boolean;\n readonly formatDimText: (text: string) => string;\n readonly hasItemsAfter: boolean;\n readonly continuationPrefix?: string;\n}): string[] {\n const { commands, useColor, formatDimText, hasItemsAfter, continuationPrefix } = options;\n const lines: string[] = [];\n\n if (commands.length === 0) {\n return lines;\n }\n\n // Format each command\n for (let i = 0; i < commands.length; i++) {\n const cmd = commands[i];\n if (!cmd) continue;\n\n const subcommands = cmd.commands.filter((subcmd) => !subcmd.name().startsWith('_'));\n const isLastCommand = i === commands.length - 1;\n\n if (subcommands.length > 0) {\n // Command with subcommands - show command name, then tree-structured subcommands\n const prefix = isLastCommand && !hasItemsAfter ? formatDimText('└') : formatDimText('├');\n // For top-level command, pad name to fixed width (accounting for \"│ ├─ \" = 5 chars)\n const treePrefix = `${prefix}─ `;\n const treePrefixWidth = stringWidth(stripAnsi(treePrefix));\n const remainingWidth = LEFT_COLUMN_WIDTH - treePrefixWidth;\n const commandNamePadded = padToFixedWidth(cmd.name(), remainingWidth);\n const commandNameColored = useColor ? cyan(commandNamePadded) : commandNamePadded;\n lines.push(`${formatDimText('│')} ${treePrefix}${commandNameColored}`);\n\n for (let j = 0; j < subcommands.length; j++) {\n const subcmd = subcommands[j];\n if (!subcmd) continue;\n\n const isLastSubcommand = j === subcommands.length - 1;\n const shortDescription = subcmd.description() || '';\n\n // Use tree characters: └─ for last subcommand, ├─ for others\n const treeChar = isLastSubcommand ? '└' : '├';\n const continuation =\n continuationPrefix ??\n (isLastCommand && isLastSubcommand && !hasItemsAfter ? ' ' : formatDimText('│'));\n // For subcommands, account for \"│ │ └─ \" = 7 chars (or \"│ └─ \" = 6 chars if continuation is space)\n const continuationStr = continuation === ' ' ? ' ' : continuation;\n const subTreePrefix = `${continuationStr} ${formatDimText(treeChar)}─ `;\n const subTreePrefixWidth = stringWidth(stripAnsi(subTreePrefix));\n const subRemainingWidth = LEFT_COLUMN_WIDTH - subTreePrefixWidth;\n const subcommandNamePadded = padToFixedWidth(subcmd.name(), subRemainingWidth);\n const subcommandNameColored = useColor ? cyan(subcommandNamePadded) : subcommandNamePadded;\n lines.push(\n `${formatDimText('│')} ${subTreePrefix}${subcommandNameColored} ${shortDescription}`,\n );\n }\n } else {\n // Standalone command - show command name and description on same line\n const prefix = isLastCommand && !hasItemsAfter ? formatDimText('└') : formatDimText('├');\n const treePrefix = `${prefix}─ `;\n const treePrefixWidth = stringWidth(stripAnsi(treePrefix));\n const remainingWidth = LEFT_COLUMN_WIDTH - treePrefixWidth;\n const commandNamePadded = padToFixedWidth(cmd.name(), remainingWidth);\n const commandNameColored = useColor ? cyan(commandNamePadded) : commandNamePadded;\n const shortDescription = cmd.description() || '';\n lines.push(`${formatDimText('│')} ${treePrefix}${commandNameColored} ${shortDescription}`);\n }\n }\n\n return lines;\n}\n\n/**\n * Formats multiline description with \"Prisma Next\" in green.\n * Wraps at the same right-hand boundary as the right column.\n * The right edge is defined by: left column (20) + gap (2) + right column (90) = 112 characters total.\n * Since the description line starts with \"│ \" (2 chars), the text wraps at 112 - 2 = 110 characters.\n */\nfunction formatMultilineDescription(options: {\n readonly descriptionLines: readonly string[];\n readonly useColor: boolean;\n readonly formatDimText: (text: string) => string;\n}): string[] {\n const lines: string[] = [];\n const formatGreen = (text: string) => (options.useColor ? green(text) : text);\n\n // Calculate wrap width to align with right edge of right column\n // Format: \"│ \" (2) + left column (20) + \" \" (2) + right column = total\n // Description line has \"│ \" prefix (2 chars), so text wraps at total - 2\n const rightColumnWidth = calculateRightColumnWidth();\n const totalWidth = 2 + LEFT_COLUMN_WIDTH + 2 + rightColumnWidth;\n const wrapWidth = totalWidth - 2; // Subtract \"│ \" prefix\n\n for (const descLine of options.descriptionLines) {\n // Replace \"Prisma Next\" with green version if present\n const formattedLine = descLine.replace(/Prisma Next/g, (match) => formatGreen(match));\n\n // Wrap the line at the same right edge as the right column\n const wrappedLines = wrapTextAnsi(formattedLine, wrapWidth);\n for (const wrappedLine of wrappedLines) {\n lines.push(`${options.formatDimText('│')} ${wrappedLine}`);\n }\n }\n return lines;\n}\n\n/**\n * Formats the header in the new experimental visual style.\n * This header appears at the start of command output, showing the operation,\n * intent, documentation link, and parameters.\n */\nexport function formatStyledHeader(options: {\n readonly command: string;\n readonly description: string;\n readonly url?: string;\n readonly details: ReadonlyArray<{ readonly label: string; readonly value: string }>;\n readonly flags: GlobalFlags;\n}): string {\n const lines: string[] = [];\n const useColor = options.flags.color !== false;\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n // Header: arrow + operation badge + intent\n const brand = createPrismaNextBadge(useColor);\n // Use full command path (e.g., \"contract emit\" not just \"emit\")\n const operation = useColor ? bold(options.command) : options.command;\n const intent = formatDimText(options.description);\n lines.push(formatHeaderLine({ brand, operation, intent }));\n lines.push(formatDimText('│')); // Vertical line separator between command and params\n\n // Format details using fixed left column width (same style as help text options)\n for (const detail of options.details) {\n // Add colon to label, then pad to fixed width using padToFixedWidth for ANSI-aware padding\n const labelWithColon = `${detail.label}:`;\n const labelPadded = padToFixedWidth(labelWithColon, LEFT_COLUMN_WIDTH);\n const labelColored = useColor ? cyan(labelPadded) : labelPadded;\n lines.push(`${formatDimText('│')} ${labelColored} ${detail.value}`);\n }\n\n // Add \"Read more\" URL if present (same style as help text)\n if (options.url) {\n lines.push(formatDimText('│')); // Separator line before \"Read more\"\n lines.push(\n formatReadMoreLine({\n url: options.url,\n maxLabelWidth: LEFT_COLUMN_WIDTH,\n useColor,\n formatDimText,\n }),\n );\n }\n\n lines.push(formatDimText('└'));\n\n return `${lines.join('\\n')}\\n`;\n}\n\n/**\n * Formats a success message in the styled output format.\n */\nexport function formatSuccessMessage(flags: GlobalFlags): string {\n const useColor = flags.color !== false;\n const formatGreen = createColorFormatter(useColor, green);\n return `${formatGreen('✔')} Success`;\n}\n\n// ============================================================================\n// Help Output Formatters\n// ============================================================================\n\n/**\n * Maps command paths to their documentation URLs.\n */\nfunction getCommandDocsUrl(commandPath: string): string | undefined {\n const docsMap: Record<string, string> = {\n 'contract emit': 'https://pris.ly/contract-emit',\n 'db verify': 'https://pris.ly/db-verify',\n };\n return docsMap[commandPath];\n}\n\n/**\n * Builds the full command path from a command and its parents.\n */\nfunction buildCommandPath(command: Command): string {\n const parts: string[] = [];\n let current: Command | undefined = command;\n while (current && current.name() !== 'prisma-next') {\n parts.unshift(current.name());\n current = current.parent ?? undefined;\n }\n return parts.join(' ');\n}\n\n/**\n * Formats help output for a command using the styled format.\n */\nexport function formatCommandHelp(options: {\n readonly command: Command;\n readonly flags: GlobalFlags;\n}): string {\n const { command, flags } = options;\n const lines: string[] = [];\n const useColor = flags.color !== false;\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n // Build full command path (e.g., \"db verify\")\n const commandPath = buildCommandPath(command);\n const shortDescription = command.description() || '';\n const longDescription = getLongDescription(command);\n\n // Header: \"prisma-next <full-command-path> <short-description>\"\n const brand = createPrismaNextBadge(useColor);\n const operation = useColor ? bold(commandPath) : commandPath;\n const intent = formatDimText(shortDescription);\n lines.push(formatHeaderLine({ brand, operation, intent }));\n lines.push(formatDimText('│')); // Vertical line separator between command and params\n\n // Extract options and format them\n const optionsList = command.options.map((opt) => {\n const flags = opt.flags;\n const description = opt.description || '';\n // Commander.js stores default value in defaultValue property\n const defaultValue = (opt as { defaultValue?: unknown }).defaultValue;\n return { flags, description, defaultValue };\n });\n\n // Extract subcommands if any\n const subcommands = command.commands.filter((cmd) => !cmd.name().startsWith('_'));\n\n // Format subcommands as a tree if present\n if (subcommands.length > 0) {\n const hasItemsAfter = optionsList.length > 0;\n const treeLines = renderCommandTree({\n commands: subcommands,\n useColor,\n formatDimText,\n hasItemsAfter,\n });\n lines.push(...treeLines);\n }\n\n // Add separator between subcommands and options if both exist\n if (subcommands.length > 0 && optionsList.length > 0) {\n lines.push(formatDimText('│'));\n }\n\n // Format options with fixed width, wrapping, and default values\n if (optionsList.length > 0) {\n for (const opt of optionsList) {\n // Format flag with fixed 30-char width\n const flagsPadded = padToFixedWidth(opt.flags, LEFT_COLUMN_WIDTH);\n let flagsColored = flagsPadded;\n if (useColor) {\n // Color placeholders in magenta, then wrap in cyan\n flagsColored = flagsPadded.replace(/(<[^>]+>)/g, (match: string) => magenta(match));\n flagsColored = cyan(flagsColored);\n }\n\n // Wrap description based on terminal width\n const rightColumnWidth = calculateRightColumnWidth();\n const wrappedDescription = wrapTextAnsi(opt.description, rightColumnWidth);\n\n // First line: flag + first line of description\n lines.push(`${formatDimText('│')} ${flagsColored} ${wrappedDescription[0] || ''}`);\n\n // Continuation lines: empty label (30 spaces) + wrapped lines\n for (let i = 1; i < wrappedDescription.length; i++) {\n const emptyLabel = ' '.repeat(LEFT_COLUMN_WIDTH);\n lines.push(`${formatDimText('│')} ${emptyLabel} ${wrappedDescription[i] || ''}`);\n }\n\n // Default value line (if present)\n if (opt.defaultValue !== undefined) {\n const emptyLabel = ' '.repeat(LEFT_COLUMN_WIDTH);\n const defaultText = formatDefaultValue(opt.defaultValue, useColor);\n lines.push(`${formatDimText('│')} ${emptyLabel} ${defaultText}`);\n }\n }\n }\n\n // Add docs URL if available (with separator line before it)\n const docsUrl = getCommandDocsUrl(commandPath);\n if (docsUrl) {\n lines.push(formatDimText('│')); // Separator line between params and docs\n lines.push(\n formatReadMoreLine({\n url: docsUrl,\n maxLabelWidth: LEFT_COLUMN_WIDTH,\n useColor,\n formatDimText,\n }),\n );\n }\n\n // Multi-line description (if present) - shown after all other content\n if (longDescription) {\n lines.push(formatDimText('│'));\n const descriptionLines = longDescription.split('\\n').filter((line) => line.trim().length > 0);\n lines.push(...formatMultilineDescription({ descriptionLines, useColor, formatDimText }));\n }\n\n lines.push(formatDimText('└'));\n\n return `${lines.join('\\n')}\\n`;\n}\n\n/**\n * Formats help output for the root program using the styled format.\n */\nexport function formatRootHelp(options: {\n readonly program: Command;\n readonly flags: GlobalFlags;\n}): string {\n const { program, flags } = options;\n const lines: string[] = [];\n const useColor = flags.color !== false;\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n // Header: \"prisma-next → Manage your data layer\"\n const brand = createPrismaNextBadge(useColor);\n const shortDescription = 'Manage your data layer';\n const intent = formatDimText(shortDescription);\n lines.push(formatHeaderLine({ brand, operation: '', intent }));\n lines.push(formatDimText('│')); // Vertical line separator after header\n\n // Extract top-level commands (exclude hidden commands starting with '_' and the 'help' command)\n const topLevelCommands = program.commands.filter(\n (cmd) => !cmd.name().startsWith('_') && cmd.name() !== 'help',\n );\n\n // Extract global options (needed to determine if last command)\n const globalOptions = program.options.map((opt) => {\n const flags = opt.flags;\n const description = opt.description || '';\n // Commander.js stores default value in defaultValue property\n const defaultValue = (opt as { defaultValue?: unknown }).defaultValue;\n return { flags, description, defaultValue };\n });\n\n // Build command tree\n if (topLevelCommands.length > 0) {\n const hasItemsAfter = globalOptions.length > 0;\n const treeLines = renderCommandTree({\n commands: topLevelCommands,\n useColor,\n formatDimText,\n hasItemsAfter,\n });\n lines.push(...treeLines);\n }\n\n // Add separator between commands and options if both exist\n if (topLevelCommands.length > 0 && globalOptions.length > 0) {\n lines.push(formatDimText('│'));\n }\n\n // Format global options with fixed width, wrapping, and default values\n if (globalOptions.length > 0) {\n for (const opt of globalOptions) {\n // Format flag with fixed 30-char width\n const flagsPadded = padToFixedWidth(opt.flags, LEFT_COLUMN_WIDTH);\n let flagsColored = flagsPadded;\n if (useColor) {\n // Color placeholders in magenta, then wrap in cyan\n flagsColored = flagsPadded.replace(/(<[^>]+>)/g, (match: string) => magenta(match));\n flagsColored = cyan(flagsColored);\n }\n\n // Wrap description based on terminal width\n const rightColumnWidth = calculateRightColumnWidth();\n const wrappedDescription = wrapTextAnsi(opt.description, rightColumnWidth);\n\n // First line: flag + first line of description\n lines.push(`${formatDimText('│')} ${flagsColored} ${wrappedDescription[0] || ''}`);\n\n // Continuation lines: empty label (30 spaces) + wrapped lines\n for (let i = 1; i < wrappedDescription.length; i++) {\n const emptyLabel = ' '.repeat(LEFT_COLUMN_WIDTH);\n lines.push(`${formatDimText('│')} ${emptyLabel} ${wrappedDescription[i] || ''}`);\n }\n\n // Default value line (if present)\n if (opt.defaultValue !== undefined) {\n const emptyLabel = ' '.repeat(LEFT_COLUMN_WIDTH);\n const defaultText = formatDefaultValue(opt.defaultValue, useColor);\n lines.push(`${formatDimText('│')} ${emptyLabel} ${defaultText}`);\n }\n }\n }\n\n // Multi-line description (white, not dimmed, with \"Prisma Next\" in green) - shown at bottom\n const formatGreen = (text: string) => (useColor ? green(text) : text);\n const descriptionLines = [\n `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.`,\n ];\n if (descriptionLines.length > 0) {\n lines.push(formatDimText('│')); // Separator line before description\n lines.push(...formatMultilineDescription({ descriptionLines, useColor, formatDimText }));\n }\n\n lines.push(formatDimText('└'));\n\n return `${lines.join('\\n')}\\n`;\n}\n","import type { Result } from '@prisma-next/utils/result';\nimport type { CliStructuredError } from './cli-errors';\nimport type { GlobalFlags } from './global-flags';\nimport { formatErrorJson, formatErrorOutput } from './output';\n\n/**\n * Processes a CLI command result, handling both success and error cases.\n * Formats output appropriately and returns the exit code.\n * Never throws - returns exit code for commands to use with process.exit().\n *\n * @param result - The result from a CLI command\n * @param flags - Global flags for output formatting\n * @param onSuccess - Optional callback for successful results (for custom success output)\n * @returns The exit code that should be used (0 for success, non-zero for errors)\n */\nexport function handleResult<T>(\n result: Result<T, CliStructuredError>,\n flags: GlobalFlags,\n onSuccess?: (value: T) => void,\n): number {\n if (result.ok) {\n // Success case\n if (onSuccess) {\n onSuccess(result.value);\n }\n return 0;\n }\n\n // Error case - convert to CLI envelope\n const envelope = result.failure.toEnvelope();\n\n // Output error based on flags\n if (flags.json) {\n // JSON error to stderr\n console.error(formatErrorJson(envelope));\n } else {\n // Human-readable error to stderr\n console.error(formatErrorOutput(envelope, flags));\n }\n\n // Infer exit code from error domain: CLI errors = 2, RTM errors = 1\n const exitCode = result.failure.domain === 'CLI' ? 2 : 1;\n return exitCode;\n}\n","import ora from 'ora';\nimport type { GlobalFlags } from './global-flags';\n\n/**\n * Options for the withSpinner helper function.\n */\ninterface WithSpinnerOptions {\n /**\n * The message to display in the spinner.\n */\n readonly message: string;\n /**\n * Global flags that control spinner behavior (quiet, json, color).\n */\n readonly flags: GlobalFlags;\n}\n\n/**\n * Wraps an async operation with a spinner.\n *\n * The spinner respects:\n * - `flags.quiet`: No spinner if quiet mode is enabled\n * - `flags.json === 'object'`: No spinner if JSON output is enabled\n * - Non-TTY environments: No spinner if stdout is not a TTY\n *\n * @param operation - The async operation to execute\n * @param options - Spinner configuration options\n * @returns The result of the operation\n */\nexport async function withSpinner<T>(\n operation: () => Promise<T>,\n options: WithSpinnerOptions,\n): Promise<T> {\n const { message, flags } = options;\n\n // Skip spinner if quiet, JSON output, or non-TTY\n const shouldShowSpinner = !flags.quiet && flags.json !== 'object' && process.stdout.isTTY;\n\n if (!shouldShowSpinner) {\n // Just execute the operation without spinner\n return operation();\n }\n\n // Start spinner immediately\n const startTime = Date.now();\n const spinner = ora({\n text: message,\n color: flags.color !== false ? 'cyan' : false,\n }).start();\n\n try {\n // Execute the operation\n const result = await operation();\n\n // Mark spinner as succeeded\n const elapsed = Date.now() - startTime;\n spinner.succeed(`${message} (${elapsed}ms)`);\n\n return result;\n } catch (error) {\n // Mark spinner as failed\n spinner.fail(`${message} failed: ${error instanceof Error ? error.message : String(error)}`);\n\n // Re-throw the error\n throw error;\n }\n}\n"],"mappings":"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","names":["prefix","flags"]}