@prisma/cli 3.0.0-beta.0 → 3.0.0-beta.10

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 (65) hide show
  1. package/README.md +18 -3
  2. package/dist/adapters/git.js +8 -3
  3. package/dist/adapters/local-state.js +12 -4
  4. package/dist/adapters/mock-api.js +81 -2
  5. package/dist/adapters/token-storage.js +63 -22
  6. package/dist/cli.js +17 -2
  7. package/dist/cli2.js +7 -3
  8. package/dist/commands/app/index.js +26 -13
  9. package/dist/commands/branch/index.js +2 -27
  10. package/dist/commands/database/index.js +159 -0
  11. package/dist/commands/env.js +8 -4
  12. package/dist/commands/project/index.js +28 -2
  13. package/dist/controllers/app-env-api.js +54 -0
  14. package/dist/controllers/app-env-file.js +181 -0
  15. package/dist/controllers/app-env.js +284 -132
  16. package/dist/controllers/app.js +493 -344
  17. package/dist/controllers/auth.js +8 -8
  18. package/dist/controllers/branch.js +78 -48
  19. package/dist/controllers/database.js +318 -0
  20. package/dist/controllers/project.js +302 -75
  21. package/dist/lib/app/branch-database-deploy.js +373 -0
  22. package/dist/lib/app/branch-database.js +316 -0
  23. package/dist/lib/app/bun-project.js +12 -5
  24. package/dist/lib/app/deploy-output.js +10 -1
  25. package/dist/lib/app/env-config.js +1 -1
  26. package/dist/lib/app/env-file.js +82 -0
  27. package/dist/lib/app/env-vars.js +28 -2
  28. package/dist/lib/app/local-dev.js +34 -18
  29. package/dist/lib/app/preview-branch-database.js +102 -0
  30. package/dist/lib/app/preview-build-settings.js +385 -0
  31. package/dist/lib/app/preview-build.js +272 -81
  32. package/dist/lib/app/preview-provider.js +163 -54
  33. package/dist/lib/app/production-deploy-gate.js +161 -0
  34. package/dist/lib/auth/auth-ops.js +69 -19
  35. package/dist/lib/auth/guard.js +3 -2
  36. package/dist/lib/auth/login.js +109 -14
  37. package/dist/lib/database/provider.js +167 -0
  38. package/dist/lib/diagnostics.js +15 -0
  39. package/dist/lib/git/local-branch.js +41 -0
  40. package/dist/lib/git/local-status.js +57 -0
  41. package/dist/lib/project/interactive-setup.js +56 -0
  42. package/dist/lib/project/local-pin.js +182 -33
  43. package/dist/lib/project/resolution.js +287 -105
  44. package/dist/lib/project/setup.js +132 -0
  45. package/dist/presenters/app-env.js +149 -14
  46. package/dist/presenters/app.js +170 -20
  47. package/dist/presenters/auth.js +19 -6
  48. package/dist/presenters/branch.js +37 -102
  49. package/dist/presenters/database.js +274 -0
  50. package/dist/presenters/project.js +100 -47
  51. package/dist/presenters/verbose-context.js +64 -0
  52. package/dist/shell/command-arguments.js +6 -0
  53. package/dist/shell/command-meta.js +139 -16
  54. package/dist/shell/command-runner.js +38 -8
  55. package/dist/shell/diagnostics-output.js +63 -0
  56. package/dist/shell/errors.js +14 -1
  57. package/dist/shell/output.js +13 -2
  58. package/dist/shell/runtime.js +3 -3
  59. package/dist/shell/ui.js +23 -1
  60. package/dist/shell/update-check.js +247 -0
  61. package/dist/use-cases/auth.js +15 -4
  62. package/dist/use-cases/branch.js +20 -68
  63. package/dist/use-cases/create-cli-gateways.js +2 -17
  64. package/dist/use-cases/project.js +2 -1
  65. package/package.json +12 -10
@@ -54,7 +54,11 @@ const DESCRIPTORS = [
54
54
  id: "project",
55
55
  path: ["prisma", "project"],
56
56
  description: "Manage and inspect your Prisma projects",
57
- examples: ["prisma-cli project list", "prisma-cli project show"]
57
+ examples: [
58
+ "prisma-cli project list",
59
+ "prisma-cli project link proj_123",
60
+ "prisma-cli project create my-app"
61
+ ]
58
62
  },
59
63
  {
60
64
  id: "app",
@@ -65,8 +69,18 @@ const DESCRIPTORS = [
65
69
  {
66
70
  id: "branch",
67
71
  path: ["prisma", "branch"],
68
- description: "View your active Platform branches",
69
- examples: ["prisma-cli branch list", "prisma-cli branch show"]
72
+ description: "View your Platform branches",
73
+ examples: ["prisma-cli branch list"]
74
+ },
75
+ {
76
+ id: "database",
77
+ path: ["prisma", "database"],
78
+ description: "Manage Prisma Postgres databases for a project",
79
+ examples: [
80
+ "prisma-cli database list",
81
+ "prisma-cli database create my-db",
82
+ "prisma-cli database connection create db_123"
83
+ ]
70
84
  },
71
85
  {
72
86
  id: "git",
@@ -91,9 +105,33 @@ const DESCRIPTORS = [
91
105
  "project",
92
106
  "show"
93
107
  ],
94
- description: "Show which project is active for this directory",
108
+ description: "Show this directory's Project binding",
95
109
  examples: ["prisma-cli project show", "prisma-cli project show --project proj_123 --json"]
96
110
  },
111
+ {
112
+ id: "project.create",
113
+ path: [
114
+ "prisma",
115
+ "project",
116
+ "create"
117
+ ],
118
+ description: "Create a Project and link this directory",
119
+ examples: ["prisma-cli project create my-app", "prisma-cli project create my-app --json"]
120
+ },
121
+ {
122
+ id: "project.link",
123
+ path: [
124
+ "prisma",
125
+ "project",
126
+ "link"
127
+ ],
128
+ description: "Link this directory to a Project",
129
+ examples: [
130
+ "prisma-cli project link",
131
+ "prisma-cli project link proj_123",
132
+ "prisma-cli project link \"Acme Dashboard\" --json"
133
+ ]
134
+ },
97
135
  {
98
136
  id: "git.connect",
99
137
  path: [
@@ -125,28 +163,99 @@ const DESCRIPTORS = [
125
163
  "branch",
126
164
  "list"
127
165
  ],
128
- description: "List active Platform branches for the resolved project",
166
+ description: "List Platform branches for the resolved project",
129
167
  examples: ["prisma-cli branch list", "prisma-cli branch list --json"]
130
168
  },
131
169
  {
132
- id: "branch.show",
170
+ id: "database.list",
133
171
  path: [
134
172
  "prisma",
135
- "branch",
173
+ "database",
174
+ "list"
175
+ ],
176
+ description: "List Prisma Postgres databases for the resolved project",
177
+ examples: [
178
+ "prisma-cli database list",
179
+ "prisma-cli database list --branch feature/foo",
180
+ "prisma-cli database list --json"
181
+ ]
182
+ },
183
+ {
184
+ id: "database.show",
185
+ path: [
186
+ "prisma",
187
+ "database",
136
188
  "show"
137
189
  ],
138
- description: "Show the Platform branch matching your current Git branch",
139
- examples: ["prisma-cli branch show", "prisma-cli branch show --json"]
190
+ description: "Show database metadata without secret values",
191
+ examples: ["prisma-cli database show db_123", "prisma-cli database show acme-preview --branch preview --json"]
140
192
  },
141
193
  {
142
- id: "branch.use",
194
+ id: "database.create",
143
195
  path: [
144
196
  "prisma",
145
- "branch",
146
- "use"
197
+ "database",
198
+ "create"
147
199
  ],
148
- description: "Change the local default branch context.",
149
- examples: ["prisma-cli branch use", "prisma-cli branch use production"]
200
+ description: "Create a Prisma Postgres database and print its one-time connection URL",
201
+ examples: ["prisma-cli database create my-db", "prisma-cli database create my-db --branch feature/foo --region eu-central-1"]
202
+ },
203
+ {
204
+ id: "database.remove",
205
+ path: [
206
+ "prisma",
207
+ "database",
208
+ "remove"
209
+ ],
210
+ description: "Remove a database after exact id confirmation",
211
+ examples: ["prisma-cli database remove db_123 --confirm db_123"]
212
+ },
213
+ {
214
+ id: "database.connection",
215
+ path: [
216
+ "prisma",
217
+ "database",
218
+ "connection"
219
+ ],
220
+ description: "Manage one-time-view database connection strings",
221
+ examples: [
222
+ "prisma-cli database connection list db_123",
223
+ "prisma-cli database connection create db_123",
224
+ "prisma-cli database connection remove conn_123 --confirm conn_123"
225
+ ]
226
+ },
227
+ {
228
+ id: "database.connection.list",
229
+ path: [
230
+ "prisma",
231
+ "database",
232
+ "connection",
233
+ "list"
234
+ ],
235
+ description: "List database connection metadata without secret values",
236
+ examples: ["prisma-cli database connection list db_123", "prisma-cli database connection list acme-preview --branch preview --json"]
237
+ },
238
+ {
239
+ id: "database.connection.create",
240
+ path: [
241
+ "prisma",
242
+ "database",
243
+ "connection",
244
+ "create"
245
+ ],
246
+ description: "Create a database connection and print its one-time connection URL",
247
+ examples: ["prisma-cli database connection create db_123", "prisma-cli database connection create db_123 --name readonly"]
248
+ },
249
+ {
250
+ id: "database.connection.remove",
251
+ path: [
252
+ "prisma",
253
+ "database",
254
+ "connection",
255
+ "remove"
256
+ ],
257
+ description: "Remove a database connection after exact id confirmation",
258
+ examples: ["prisma-cli database connection remove conn_123 --confirm conn_123"]
150
259
  },
151
260
  {
152
261
  id: "app.build",
@@ -180,11 +289,20 @@ const DESCRIPTORS = [
180
289
  "deploy"
181
290
  ],
182
291
  description: "Creates a new deployment for the app",
292
+ longDescription: "Agent skills for guided Next.js deploys are available from the Prisma CLI skill cluster.",
183
293
  examples: [
184
294
  "prisma-cli app deploy",
295
+ "prisma-cli app deploy --project proj_123",
296
+ "prisma-cli app deploy --create-project my-app --yes",
185
297
  "prisma-cli app deploy --app my-app --env DATABASE_URL=postgresql://example",
298
+ "prisma-cli app deploy --env .env",
299
+ "prisma-cli app deploy --db",
300
+ "prisma-cli app deploy --db --yes",
186
301
  "prisma-cli app deploy --app my-app --framework nextjs --http-port 3000",
187
- "prisma-cli app deploy --branch feat-login --framework hono"
302
+ "prisma-cli app deploy --branch feat-login --framework hono",
303
+ "prisma-cli app deploy --prod --yes",
304
+ "pnpm dlx skills@latest add prisma/prisma-cli/skills#cli-v<cli-version> --all",
305
+ "prisma-cli app deploy --framework bun --entry src/server.ts"
188
306
  ]
189
307
  },
190
308
  {
@@ -345,8 +463,9 @@ const DESCRIPTORS = [
345
463
  ],
346
464
  description: "Manage environment variables for the active project",
347
465
  examples: [
348
- "prisma-cli project env list --role production",
466
+ "prisma-cli project env list",
349
467
  "prisma-cli project env add STRIPE_KEY=sk_test_xxx --role production",
468
+ "prisma-cli project env add --file .env --role preview",
350
469
  "prisma-cli project env add DATABASE_URL=postgresql://branch --branch feature/foo",
351
470
  "prisma-cli project env remove STRIPE_KEY --role preview"
352
471
  ]
@@ -363,7 +482,9 @@ const DESCRIPTORS = [
363
482
  examples: [
364
483
  "prisma-cli project env add STRIPE_KEY=sk_test_xxx --role production",
365
484
  "prisma-cli project env add STRIPE_KEY=sk_test_xxx --role preview",
485
+ "prisma-cli project env add --file .env --role preview",
366
486
  "prisma-cli project env add DATABASE_URL=postgresql://branch --branch feature/foo",
487
+ "prisma-cli project env add --file .env.local --branch feature/foo",
367
488
  "API_URL=https://api.example prisma-cli project env add API_URL --project proj_123 --role preview"
368
489
  ]
369
490
  },
@@ -379,6 +500,7 @@ const DESCRIPTORS = [
379
500
  examples: [
380
501
  "prisma-cli project env update STRIPE_KEY=sk_new_xxx --role production",
381
502
  "prisma-cli project env update STRIPE_KEY=sk_new_xxx --role preview",
503
+ "prisma-cli project env update --file .env --role production",
382
504
  "prisma-cli project env update DATABASE_URL=postgresql://branch --branch feature/foo"
383
505
  ]
384
506
  },
@@ -392,6 +514,7 @@ const DESCRIPTORS = [
392
514
  ],
393
515
  description: "List environment variable metadata for a scope (no values).",
394
516
  examples: [
517
+ "prisma-cli project env list",
395
518
  "prisma-cli project env list --role production",
396
519
  "prisma-cli project env list --role preview",
397
520
  "prisma-cli project env list --branch feature/foo"
@@ -1,19 +1,27 @@
1
- import { CliError, authRequiredError } from "./errors.js";
1
+ import { CliError, authRequiredError, commandCanceledError } from "./errors.js";
2
2
  import { cliErrorToJson, writeHumanError, writeHumanLines, writeJsonError, writeJsonEvent, writeJsonSuccess } from "./output.js";
3
3
  import { getCommandDescriptor } from "./command-meta.js";
4
4
  import { resolveGlobalFlags } from "./global-flags.js";
5
5
  import { createCommandContext } from "./runtime.js";
6
+ import { collectCommandDiagnostics } from "../lib/diagnostics.js";
7
+ import { renderCommandDiagnostics } from "./diagnostics-output.js";
6
8
  import { AuthError } from "@prisma/management-api-sdk";
7
9
  //#region src/shell/command-runner.ts
8
- function toCliError(error) {
10
+ function toCliError(error, runtime) {
11
+ if (isCancellationError(error) || runtime.signal.aborted) return commandCanceledError();
9
12
  if (error instanceof CliError) return error;
10
13
  if (error instanceof AuthError) return authRequiredError(["prisma-cli auth login"], { debug: error.message });
11
14
  return null;
12
15
  }
16
+ function isCancellationError(error) {
17
+ if (!(error instanceof Error)) return false;
18
+ return error.name === "AbortError" || error.name === "CancelledError";
19
+ }
13
20
  async function runCommand(runtime, commandName, options, handler, presenter) {
14
21
  const flags = resolveGlobalFlags(runtime.argv, options);
15
22
  const context = await createCommandContext(runtime, flags);
16
23
  const descriptor = getCommandDescriptor(commandName);
24
+ const startedAt = Date.now();
17
25
  try {
18
26
  const success = await handler(context);
19
27
  if (flags.json) {
@@ -23,10 +31,22 @@ async function runCommand(runtime, commandName, options, handler, presenter) {
23
31
  });
24
32
  return;
25
33
  }
26
- if (flags.quiet) return;
27
- writeHumanLines(context.output, presenter.renderHuman(context, descriptor, success.result));
34
+ const stdout = presenter.renderStdout?.(context, descriptor, success.result) ?? [];
35
+ if (flags.quiet) {
36
+ if (stdout.length > 0) context.output.stdout.write(`${stdout.join("\n")}\n`);
37
+ return;
38
+ }
39
+ const rendered = presenter.renderHuman(context, descriptor, success.result);
40
+ const diagnostics = await renderBestEffortCommandDiagnostics(context, {
41
+ enabled: flags.verbose && rendered.length > 0,
42
+ durationMs: Date.now() - startedAt
43
+ });
44
+ const humanLines = [...rendered, ...diagnostics];
45
+ if (stdout.length > 0 && humanLines.length > 0) humanLines.push("");
46
+ writeHumanLines(context.output, humanLines);
47
+ if (stdout.length > 0) context.output.stdout.write(`${stdout.join("\n")}\n`);
28
48
  } catch (error) {
29
- const cliError = toCliError(error);
49
+ const cliError = toCliError(error, runtime);
30
50
  if (cliError) {
31
51
  if (flags.json) writeJsonError(context.output, commandName, cliError);
32
52
  else writeHumanError(context.output, context.ui, cliError, { trace: flags.trace });
@@ -36,6 +56,14 @@ async function runCommand(runtime, commandName, options, handler, presenter) {
36
56
  throw error;
37
57
  }
38
58
  }
59
+ async function renderBestEffortCommandDiagnostics(context, options) {
60
+ if (!options.enabled) return [];
61
+ try {
62
+ return renderCommandDiagnostics(context, await collectCommandDiagnostics(context, { durationMs: options.durationMs }));
63
+ } catch {
64
+ return [];
65
+ }
66
+ }
39
67
  async function runStreamingCommand(runtime, commandName, options, handler) {
40
68
  const flags = resolveGlobalFlags(runtime.argv, options);
41
69
  const context = await createCommandContext(runtime, flags);
@@ -47,10 +75,11 @@ async function runStreamingCommand(runtime, commandName, options, handler) {
47
75
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
48
76
  result: null,
49
77
  warnings: [],
50
- nextSteps: []
78
+ nextSteps: [],
79
+ nextActions: []
51
80
  });
52
81
  } catch (error) {
53
- const cliError = toCliError(error);
82
+ const cliError = toCliError(error, runtime);
54
83
  if (cliError) {
55
84
  if (flags.json) writeJsonEvent(context.output, {
56
85
  type: "error",
@@ -58,7 +87,8 @@ async function runStreamingCommand(runtime, commandName, options, handler) {
58
87
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
59
88
  error: cliErrorToJson(cliError),
60
89
  warnings: [],
61
- nextSteps: cliError.nextSteps
90
+ nextSteps: cliError.nextSteps,
91
+ nextActions: cliError.nextActions
62
92
  });
63
93
  else writeHumanError(context.output, context.ui, cliError, { trace: flags.trace });
64
94
  process.exitCode = cliError.exitCode;
@@ -0,0 +1,63 @@
1
+ import { renderVerboseBlock } from "./ui.js";
2
+ import path from "node:path";
3
+ //#region src/shell/diagnostics-output.ts
4
+ function renderCommandDiagnostics(context, diagnostics, rows = [], options = {}) {
5
+ if (!diagnostics) return [];
6
+ const { env } = context.runtime;
7
+ const git = diagnostics.git;
8
+ return renderVerboseBlock(context.ui, [
9
+ ...rows,
10
+ ...diagnostics.durationMs === void 0 ? [] : [{
11
+ key: "duration",
12
+ value: formatDuration(diagnostics.durationMs)
13
+ }],
14
+ {
15
+ key: "cwd",
16
+ value: formatLocalPath(diagnostics.cwd, env)
17
+ },
18
+ {
19
+ key: "state file",
20
+ value: formatLocalPath(diagnostics.stateFilePath, env)
21
+ },
22
+ ...git ? [
23
+ {
24
+ key: "git ref",
25
+ value: git.ref ?? "detached",
26
+ tone: git.ref ? "default" : "dim"
27
+ },
28
+ {
29
+ key: "git sha",
30
+ value: git.sha ?? "unknown",
31
+ tone: git.sha ? "default" : "dim"
32
+ },
33
+ {
34
+ key: "git dirty",
35
+ value: formatDirtyState(git.dirty),
36
+ tone: git.dirty ? "warning" : "dim"
37
+ }
38
+ ] : [{
39
+ key: "git",
40
+ value: "not detected",
41
+ tone: "dim"
42
+ }]
43
+ ], { title: options.title ?? "Local context" });
44
+ }
45
+ function formatLocalPath(value, env) {
46
+ const resolved = path.resolve(value);
47
+ const home = env.HOME ? path.resolve(env.HOME) : null;
48
+ if (home && (resolved === home || resolved.startsWith(`${home}${path.sep}`))) {
49
+ const relative = path.relative(home, resolved);
50
+ return relative ? `~/${relative}` : "~";
51
+ }
52
+ return resolved;
53
+ }
54
+ function formatDirtyState(dirty) {
55
+ if (dirty === null) return "unknown";
56
+ return dirty ? "yes" : "no";
57
+ }
58
+ function formatDuration(durationMs) {
59
+ if (durationMs < 1e3) return `${durationMs}ms`;
60
+ return `${(durationMs / 1e3).toFixed(1)}s`;
61
+ }
62
+ //#endregion
63
+ export { renderCommandDiagnostics };
@@ -12,6 +12,7 @@ var CliError = class extends Error {
12
12
  docsUrl;
13
13
  exitCode;
14
14
  nextSteps;
15
+ nextActions;
15
16
  humanLines;
16
17
  constructor(options) {
17
18
  super(options.summary);
@@ -28,6 +29,7 @@ var CliError = class extends Error {
28
29
  this.docsUrl = options.docsUrl ?? null;
29
30
  this.exitCode = options.exitCode ?? 1;
30
31
  this.nextSteps = options.nextSteps ?? [];
32
+ this.nextActions = options.nextActions ?? [];
31
33
  this.humanLines = options.humanLines && options.humanLines.length > 0 ? [...options.humanLines] : null;
32
34
  }
33
35
  };
@@ -54,6 +56,17 @@ function authRequiredError(nextSteps = ["prisma-cli auth login"], options = {})
54
56
  nextSteps
55
57
  });
56
58
  }
59
+ function commandCanceledError() {
60
+ return new CliError({
61
+ code: "COMMAND_CANCELED",
62
+ domain: "cli",
63
+ summary: "Command canceled",
64
+ why: null,
65
+ fix: null,
66
+ exitCode: 130,
67
+ humanLines: ["Command canceled [COMMAND_CANCELED]"]
68
+ });
69
+ }
57
70
  function workspaceRequiredError() {
58
71
  return usageError("Workspace required", "This command needs an active workspace, but the authenticated session does not have one.", "Run prisma-cli auth login and choose a workspace.", ["prisma-cli auth login"], "auth");
59
72
  }
@@ -69,4 +82,4 @@ function featureUnavailableError(summary, why, fix, nextSteps = [], domain = "cl
69
82
  });
70
83
  }
71
84
  //#endregion
72
- export { CliError, authRequiredError, featureUnavailableError, usageError, workspaceRequiredError };
85
+ export { CliError, authRequiredError, commandCanceledError, featureUnavailableError, usageError, workspaceRequiredError };
@@ -3,6 +3,7 @@ import { renderNextSteps, renderSummaryLine } from "./ui.js";
3
3
  function writeJsonSuccess(output, success) {
4
4
  output.stdout.write(`${JSON.stringify({
5
5
  ok: true,
6
+ nextActions: [],
6
7
  ...success
7
8
  }, null, 2)}\n`);
8
9
  }
@@ -22,13 +23,23 @@ function cliErrorToJson(error) {
22
23
  docsUrl: error.docsUrl
23
24
  };
24
25
  }
26
+ function formatUnexpectedError(error, trace) {
27
+ const debug = error instanceof Error ? error.stack ?? error.message : String(error);
28
+ if (trace) return `${debug}\n`;
29
+ return [
30
+ `Unexpected CLI error: ${error instanceof Error && error.message ? error.message : String(error)}`,
31
+ "More: Re-run with --trace for deeper diagnostics",
32
+ ""
33
+ ].join("\n");
34
+ }
25
35
  function writeJsonError(output, command, error) {
26
36
  output.stdout.write(`${JSON.stringify({
27
37
  ok: false,
28
38
  command,
29
39
  error: cliErrorToJson(error),
30
40
  warnings: [],
31
- nextSteps: error.nextSteps
41
+ nextSteps: error.nextSteps,
42
+ nextActions: error.nextActions
32
43
  }, null, 2)}\n`);
33
44
  }
34
45
  function writeHumanLines(output, lines) {
@@ -68,4 +79,4 @@ function writeHumanError(output, ui, error, options) {
68
79
  writeHumanLines(output, lines);
69
80
  }
70
81
  //#endregion
71
- export { cliErrorToJson, writeHumanError, writeHumanLines, writeJsonError, writeJsonEvent, writeJsonSuccess };
82
+ export { cliErrorToJson, formatUnexpectedError, writeHumanError, writeHumanLines, writeJsonError, writeJsonEvent, writeJsonSuccess };
@@ -22,13 +22,13 @@ async function createCommandContext(runtime, flags) {
22
22
  const fixturePath = runtime.fixturePath ?? runtime.env.PRISMA_CLI_MOCK_FIXTURE_PATH;
23
23
  const stateDir = resolveStateDir(runtime);
24
24
  let loadedApi;
25
- if (fixturePath) loadedApi = await MockApi.load(fixturePath);
25
+ if (fixturePath) loadedApi = await MockApi.load(fixturePath, runtime.signal);
26
26
  return {
27
27
  get api() {
28
28
  if (!loadedApi) throw new Error("context.api accessed in real mode. Set runtime.fixturePath or PRISMA_CLI_MOCK_FIXTURE_PATH to use fixture mode.");
29
29
  return loadedApi;
30
30
  },
31
- stateStore: new LocalStateStore(stateDir),
31
+ stateStore: new LocalStateStore(stateDir, runtime.signal),
32
32
  output: {
33
33
  stdout: runtime.stdout,
34
34
  stderr: runtime.stderr
@@ -48,4 +48,4 @@ function canPrompt(context) {
48
48
  return Boolean(context.runtime.stdin.isTTY && context.runtime.stderr.isTTY);
49
49
  }
50
50
  //#endregion
51
- export { canPrompt, configureRuntimeCommand, createCommandContext };
51
+ export { canPrompt, configureRuntimeCommand, createCommandContext, resolveStateDir };
package/dist/shell/ui.js CHANGED
@@ -48,6 +48,20 @@ function renderNextSteps(steps) {
48
48
  ...steps.map((step) => `- ${step}`)
49
49
  ];
50
50
  }
51
+ function renderVerboseBlock(ui, rows, options = {}) {
52
+ if (!ui.verbose || rows.length === 0) return [];
53
+ const title = options.title ?? "Details";
54
+ const keyWidth = Math.max(...rows.map((row) => stringWidth(`${row.key}:`)));
55
+ const rail = ui.dim("│");
56
+ return [
57
+ "",
58
+ `${ui.dim(title)}:`,
59
+ ...rows.map((row) => `${rail} ${ui.accent(padDisplay(`${row.key}:`, keyWidth))} ${formatVerboseValue(ui, row)}`)
60
+ ];
61
+ }
62
+ function formatColumns(columns, widths) {
63
+ return columns.map((value, index) => padDisplay(value, widths[index])).join(" ").trimEnd();
64
+ }
51
65
  function wrapText(text, width, indent = "") {
52
66
  return wrapAnsi(text, width, {
53
67
  hard: false,
@@ -73,5 +87,13 @@ function formatHeaderValue(ui, row) {
73
87
  if (row.tone === "link") return ui.link(value);
74
88
  return value;
75
89
  }
90
+ function formatVerboseValue(ui, row) {
91
+ const value = row.sensitive ? maskValue(row.value) : row.value;
92
+ if (row.tone === "dim") return ui.dim(value);
93
+ if (row.tone === "success") return ui.success(value);
94
+ if (row.tone === "warning") return ui.warning(value);
95
+ if (row.tone === "link") return ui.link(value);
96
+ return value;
97
+ }
76
98
  //#endregion
77
- export { createShellUi, maskValue, padDisplay, renderCommandHeader, renderNextSteps, renderSummaryLine, wrapText };
99
+ export { createShellUi, formatColumns, maskValue, padDisplay, renderCommandHeader, renderNextSteps, renderSummaryLine, renderVerboseBlock, wrapText };