@prisma/cli 3.0.0-dev.63.1 → 3.0.0-dev.67.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -141,4 +141,4 @@ var LocalStateStore = class {
141
141
  }
142
142
  };
143
143
  //#endregion
144
- export { LocalStateStore };
144
+ export { LocalStateStore, resolveLocalStateFilePath };
package/dist/cli2.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { CliError } from "./shell/errors.js";
2
2
  import { createShellUi } from "./shell/ui.js";
3
- import { writeHumanError, writeJsonError, writeJsonSuccess } from "./shell/output.js";
3
+ import { formatUnexpectedError, writeHumanError, writeJsonError, writeJsonSuccess } from "./shell/output.js";
4
4
  import { attachCommandDescriptor } from "./shell/command-meta.js";
5
5
  import { addCompactGlobalFlags } from "./shell/global-flags.js";
6
6
  import { configureRuntimeCommand, createCommandContext } from "./shell/runtime.js";
@@ -33,8 +33,7 @@ async function runCli(options = {}) {
33
33
  return process.exitCode ?? 0;
34
34
  } catch (error) {
35
35
  if (error instanceof CommanderError) return error.code === "commander.helpDisplayed" ? 0 : 2;
36
- const message = error instanceof Error ? error.stack ?? error.message : String(error);
37
- runtime.stderr.write(`${message}\n`);
36
+ runtime.stderr.write(formatUnexpectedError(error, runtime.argv.includes("--trace")));
38
37
  return 1;
39
38
  } finally {
40
39
  runtime.stdin;
@@ -2,7 +2,7 @@ import { CliError } from "../shell/errors.js";
2
2
  import { formatScopeLabel } from "../lib/app/env-config.js";
3
3
  import { apiCallError, findVariableByNaturalKey, toMetadata } from "./app-env-api.js";
4
4
  //#region src/controllers/app-env-file.ts
5
- async function runEnvAddFile(context, client, projectId, resolved, filePath, assignments) {
5
+ async function runEnvAddFile(context, client, projectId, resolved, filePath, assignments, verboseContext) {
6
6
  const existing = await findVariablesByNaturalKey(client, projectId, assignments.map((assignment) => assignment.key), resolved, context.runtime.signal);
7
7
  const existingKeys = assignments.map((assignment) => assignment.key).filter((key) => existing.has(key));
8
8
  if (existingKeys.length > 0) throw new CliError({
@@ -40,6 +40,7 @@ async function runEnvAddFile(context, client, projectId, resolved, filePath, ass
40
40
  command: "project.env.add",
41
41
  result: {
42
42
  projectId,
43
+ verboseContext,
43
44
  scope: resolved.descriptor,
44
45
  variables,
45
46
  file: {
@@ -51,7 +52,7 @@ async function runEnvAddFile(context, client, projectId, resolved, filePath, ass
51
52
  nextSteps: []
52
53
  };
53
54
  }
54
- async function runEnvUpdateFile(context, client, projectId, resolved, filePath, assignments) {
55
+ async function runEnvUpdateFile(context, client, projectId, resolved, filePath, assignments, verboseContext) {
55
56
  const existing = await findVariablesByNaturalKey(client, projectId, assignments.map((assignment) => assignment.key), resolved, context.runtime.signal);
56
57
  const missingKeys = assignments.map((assignment) => assignment.key).filter((key) => !existing.has(key));
57
58
  if (missingKeys.length > 0) throw new CliError({
@@ -87,6 +88,7 @@ async function runEnvUpdateFile(context, client, projectId, resolved, filePath,
87
88
  command: "project.env.update",
88
89
  result: {
89
90
  projectId,
91
+ verboseContext,
90
92
  scope: resolved.descriptor,
91
93
  variables,
92
94
  file: {
@@ -17,12 +17,12 @@ async function runEnvAdd(context, rawAssignment, flags) {
17
17
  });
18
18
  if (!scope) throw usageError(`prisma-cli project env add requires --role or --branch`, "Writing without an explicit scope is rejected.", "Pass --role production, --role preview, or --branch <git-name>.", ["prisma-cli project env add KEY=value --role production"], "app");
19
19
  const input = await resolveEnvWriteInput(context, source, "add");
20
- const { client, projectId } = await requireClientAndProject(context, flags.projectRef, "project env add");
20
+ const { client, projectId, verboseContext } = await requireClientAndProject(context, flags.projectRef, "project env add");
21
21
  const resolved = await resolveScopeToApi(client, projectId, scope, {
22
22
  createBranchIfMissing: true,
23
23
  signal: context.runtime.signal
24
24
  });
25
- if (input.kind === "file") return runEnvAddFile(context, client, projectId, resolved, input.filePath, input.assignments);
25
+ if (input.kind === "file") return runEnvAddFile(context, client, projectId, resolved, input.filePath, input.assignments, verboseContext);
26
26
  if (await findVariableByNaturalKey(client, projectId, input.key, resolved, context.runtime.signal)) throw new CliError({
27
27
  code: "ENV_VARIABLE_ALREADY_EXISTS",
28
28
  domain: "app",
@@ -33,10 +33,6 @@ async function runEnvAdd(context, rawAssignment, flags) {
33
33
  nextSteps: [`prisma-cli project env update ${input.key}=<new-value> ${formatScopeFlag(scope)}`]
34
34
  });
35
35
  const warnings = scope.kind === "branch" && !await findVariableByNaturalKey(client, projectId, input.key, {
36
- scope: {
37
- kind: "role",
38
- role: "preview"
39
- },
40
36
  descriptor: {
41
37
  kind: "role",
42
38
  role: "preview"
@@ -61,6 +57,7 @@ async function runEnvAdd(context, rawAssignment, flags) {
61
57
  command: "project.env.add",
62
58
  result: {
63
59
  projectId,
60
+ verboseContext,
64
61
  scope: resolved.descriptor,
65
62
  variable: toMetadata(data.data, resolved.descriptor)
66
63
  },
@@ -76,12 +73,12 @@ async function runEnvUpdate(context, rawAssignment, flags) {
76
73
  });
77
74
  if (!scope) throw usageError(`prisma-cli project env update requires --role or --branch`, "Writing without an explicit scope is rejected.", "Pass --role production, --role preview, or --branch <git-name>.", ["prisma-cli project env update KEY=value --role production"], "app");
78
75
  const input = await resolveEnvWriteInput(context, source, "update");
79
- const { client, projectId } = await requireClientAndProject(context, flags.projectRef, "project env update");
76
+ const { client, projectId, verboseContext } = await requireClientAndProject(context, flags.projectRef, "project env update");
80
77
  const resolved = await resolveScopeToApi(client, projectId, scope, {
81
78
  createBranchIfMissing: false,
82
79
  signal: context.runtime.signal
83
80
  });
84
- if (input.kind === "file") return runEnvUpdateFile(context, client, projectId, resolved, input.filePath, input.assignments);
81
+ if (input.kind === "file") return runEnvUpdateFile(context, client, projectId, resolved, input.filePath, input.assignments, verboseContext);
85
82
  const existing = await findVariableByNaturalKey(client, projectId, input.key, resolved, context.runtime.signal);
86
83
  if (!existing) throw new CliError({
87
84
  code: "ENV_VARIABLE_NOT_FOUND",
@@ -102,6 +99,7 @@ async function runEnvUpdate(context, rawAssignment, flags) {
102
99
  command: "project.env.update",
103
100
  result: {
104
101
  projectId,
102
+ verboseContext,
105
103
  scope: resolved.descriptor,
106
104
  variable: toMetadata(data.data, resolved.descriptor)
107
105
  },
@@ -140,8 +138,8 @@ async function runEnvList(context, flags) {
140
138
  requireExplicit: false,
141
139
  command: "list"
142
140
  });
143
- const { client, projectId } = await requireClientAndProject(context, flags.projectRef, "project env list");
144
- const resolved = await resolveListScopeToApi(client, projectId, explicit, {
141
+ const { client, projectId, verboseContext } = await requireClientAndProject(context, flags.projectRef, "project env list");
142
+ const resolved = await resolveListScopeToApi(client, projectId, explicit ?? void 0, {
145
143
  cwd: context.runtime.cwd,
146
144
  signal: context.runtime.signal
147
145
  });
@@ -154,6 +152,7 @@ async function runEnvList(context, flags) {
154
152
  command: "project.env.list",
155
153
  result: {
156
154
  projectId,
155
+ verboseContext,
157
156
  scope: resolved.descriptor,
158
157
  target: resolved.target,
159
158
  variables: variables.map((row) => toMetadata(row, resolved.descriptor))
@@ -169,7 +168,7 @@ async function runEnvRemove(context, key, flags) {
169
168
  command: "remove"
170
169
  });
171
170
  if (!scope) throw usageError("prisma-cli project env remove requires --role or --branch", "Writing without an explicit scope is rejected.", "Pass --role production, --role preview, or --branch <git-name>.", [`prisma-cli project env remove ${key} --role production`], "app");
172
- const { client, projectId } = await requireClientAndProject(context, flags.projectRef, "project env remove");
171
+ const { client, projectId, verboseContext } = await requireClientAndProject(context, flags.projectRef, "project env remove");
173
172
  const resolved = await resolveScopeToApi(client, projectId, scope, {
174
173
  createBranchIfMissing: false,
175
174
  signal: context.runtime.signal
@@ -193,6 +192,7 @@ async function runEnvRemove(context, key, flags) {
193
192
  command: "project.env.remove",
194
193
  result: {
195
194
  projectId,
195
+ verboseContext,
196
196
  scope: resolved.descriptor,
197
197
  key
198
198
  },
@@ -205,15 +205,21 @@ async function requireClientAndProject(context, explicitProject, commandName) {
205
205
  const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
206
206
  if (!client) throw authRequiredError(["prisma-cli auth login"]);
207
207
  if (!authState.workspace) throw workspaceRequiredError();
208
+ const target = await resolveProjectTarget({
209
+ context,
210
+ workspace: authState.workspace,
211
+ explicitProject,
212
+ listProjects: () => listRealWorkspaceProjects(client, authState.workspace, context.runtime.signal),
213
+ commandName
214
+ });
208
215
  return {
209
216
  client,
210
- projectId: (await resolveProjectTarget({
211
- context,
217
+ projectId: target.project.id,
218
+ verboseContext: {
212
219
  workspace: authState.workspace,
213
- explicitProject,
214
- listProjects: () => listRealWorkspaceProjects(client, authState.workspace, context.runtime.signal),
215
- commandName
216
- })).project.id
220
+ project: target.project,
221
+ resolution: target.resolution
222
+ }
217
223
  };
218
224
  }
219
225
  async function resolveScopeToApi(client, projectId, scope, options) {
@@ -7,7 +7,7 @@ import { canPrompt } from "../shell/runtime.js";
7
7
  import { confirmPrompt, selectPrompt, textPrompt } from "../shell/prompt.js";
8
8
  import { requireComputeAuth } from "../lib/auth/guard.js";
9
9
  import { readAuthState } from "../lib/auth/auth-ops.js";
10
- import { parseEnvAssignments } from "../lib/app/env-vars.js";
10
+ import { envVarNames, parseEnvAssignments } from "../lib/app/env-vars.js";
11
11
  import { renderDeployOutputRows, renderDeploySettingsPreview } from "../lib/app/deploy-output.js";
12
12
  import { readBunPackageEntrypoint, readBunPackageJson } from "../lib/app/bun-project.js";
13
13
  import { DEFAULT_LOCAL_DEV_PORT, resolveLocalBuildType, runLocalApp } from "../lib/app/local-dev.js";
@@ -213,6 +213,18 @@ async function runAppDeploy(context, appName, options) {
213
213
  name: deployResult.app.name
214
214
  },
215
215
  deployment: deployResult.deployment,
216
+ deploySettings: {
217
+ framework: {
218
+ key: framework.key,
219
+ buildType,
220
+ name: framework.displayName,
221
+ source: framework.annotation
222
+ },
223
+ entrypoint: entrypoint ?? null,
224
+ httpPort: runtime.port,
225
+ region: selectedApp.region ?? null,
226
+ envVars: envVarNames(envVars)
227
+ },
216
228
  durationMs: deployDurationMs,
217
229
  localPin: localPinResult
218
230
  },
@@ -228,6 +240,7 @@ async function runAppListDeploys(context, appName, projectRef) {
228
240
  command: "app.list-deploys",
229
241
  result: {
230
242
  projectId,
243
+ verboseContext: toAppVerboseContext(target),
231
244
  app: null,
232
245
  deployments: []
233
246
  },
@@ -247,6 +260,7 @@ async function runAppListDeploys(context, appName, projectRef) {
247
260
  command: "app.list-deploys",
248
261
  result: {
249
262
  projectId,
263
+ verboseContext: toAppVerboseContext(target),
250
264
  app: {
251
265
  id: deploymentsResult.app.id,
252
266
  name: deploymentsResult.app.name
@@ -265,6 +279,7 @@ async function runAppShow(context, appName, projectRef) {
265
279
  command: "app.show",
266
280
  result: {
267
281
  projectId,
282
+ verboseContext: toAppVerboseContext(target),
268
283
  app: null,
269
284
  liveDeployment: null,
270
285
  liveUrl: null,
@@ -287,6 +302,7 @@ async function runAppShow(context, appName, projectRef) {
287
302
  command: "app.show",
288
303
  result: {
289
304
  projectId,
305
+ verboseContext: toAppVerboseContext(target),
290
306
  app: {
291
307
  id: deploymentsResult.app.id,
292
308
  name: deploymentsResult.app.name
@@ -360,6 +376,7 @@ async function runAppOpen(context, appName, projectRef) {
360
376
  command: "app.open",
361
377
  result: {
362
378
  projectId,
379
+ verboseContext: toAppVerboseContext(target),
363
380
  app: {
364
381
  id: deploymentsResult.app.id,
365
382
  name: deploymentsResult.app.name
@@ -650,6 +667,7 @@ async function runAppPromote(context, deploymentId, appName, projectRef) {
650
667
  command: "app.promote",
651
668
  result: {
652
669
  projectId,
670
+ verboseContext: toAppVerboseContext(target),
653
671
  app: {
654
672
  id: deploymentsResult.app.id,
655
673
  name: deploymentsResult.app.name
@@ -692,6 +710,7 @@ async function runAppRollback(context, appName, deploymentId, projectRef) {
692
710
  command: "app.rollback",
693
711
  result: {
694
712
  projectId,
713
+ verboseContext: toAppVerboseContext(target),
695
714
  app: {
696
715
  id: deploymentsResult.app.id,
697
716
  name: deploymentsResult.app.name
@@ -720,6 +739,7 @@ async function runAppRemove(context, appName, projectRef) {
720
739
  command: "app.remove",
721
740
  result: {
722
741
  projectId,
742
+ verboseContext: toAppVerboseContext(target),
723
743
  app: {
724
744
  id: removedApp.id,
725
745
  name: removedApp.name
@@ -1464,10 +1484,19 @@ function toBranchKind(name) {
1464
1484
  }
1465
1485
  function toResultBranch(branch) {
1466
1486
  return {
1487
+ id: branch.id,
1467
1488
  name: branch.name,
1468
1489
  kind: branch.kind
1469
1490
  };
1470
1491
  }
1492
+ function toAppVerboseContext(target) {
1493
+ return {
1494
+ workspace: target.workspace,
1495
+ project: target.project,
1496
+ branch: target.branch,
1497
+ resolution: target.resolution
1498
+ };
1499
+ }
1471
1500
  function toBranchDatabaseDeployBranch(branch) {
1472
1501
  if (!branch.id) throw new Error(`Deploy branch "${branch.name}" was not resolved remotely.`);
1473
1502
  return {
@@ -41,6 +41,11 @@ async function listRealBranches(context) {
41
41
  return {
42
42
  projectId: target.project.id,
43
43
  projectName: target.project.name,
44
+ verboseContext: {
45
+ workspace,
46
+ project: target.project,
47
+ resolution: target.resolution
48
+ },
44
49
  branches: sortBranches(branches.map(toBranchSummary))
45
50
  };
46
51
  }
@@ -0,0 +1,15 @@
1
+ import { resolveLocalStateFilePath } from "../adapters/local-state.js";
2
+ import { resolveStateDir } from "../shell/runtime.js";
3
+ import { readLocalGitState } from "./git/local-status.js";
4
+ //#region src/lib/diagnostics.ts
5
+ async function collectCommandDiagnostics(context, options = {}) {
6
+ const stateDir = resolveStateDir(context.runtime);
7
+ return {
8
+ cwd: context.runtime.cwd,
9
+ stateFilePath: resolveLocalStateFilePath(stateDir),
10
+ git: await readLocalGitState(context.runtime.cwd, context.runtime.signal),
11
+ durationMs: options.durationMs
12
+ };
13
+ }
14
+ //#endregion
15
+ export { collectCommandDiagnostics };
@@ -0,0 +1,57 @@
1
+ import { execFile } from "node:child_process";
2
+ //#region src/lib/git/local-status.ts
3
+ async function readLocalGitState(cwd, signal) {
4
+ signal.throwIfAborted();
5
+ if ((await runGit(cwd, ["rev-parse", "--is-inside-work-tree"], signal))?.trim() !== "true") return null;
6
+ const [ref, sha, status] = await Promise.all([
7
+ runGit(cwd, [
8
+ "symbolic-ref",
9
+ "--quiet",
10
+ "--short",
11
+ "HEAD"
12
+ ], signal),
13
+ runGit(cwd, [
14
+ "rev-parse",
15
+ "--short",
16
+ "HEAD"
17
+ ], signal),
18
+ runGit(cwd, ["status", "--porcelain"], signal)
19
+ ]);
20
+ return {
21
+ ref: cleanGitValue(ref),
22
+ sha: cleanGitValue(sha),
23
+ dirty: status === null ? null : status.trim().length > 0
24
+ };
25
+ }
26
+ function runGit(cwd, args, signal) {
27
+ return new Promise((resolve, reject) => {
28
+ signal.throwIfAborted();
29
+ execFile("git", args, {
30
+ cwd,
31
+ signal,
32
+ timeout: 2e3
33
+ }, (error, stdout) => {
34
+ if (signal.aborted) {
35
+ reject(error);
36
+ return;
37
+ }
38
+ if (error) {
39
+ resolve(null);
40
+ return;
41
+ }
42
+ resolve(stdout);
43
+ }).on("error", (error) => {
44
+ if (signal.aborted) {
45
+ reject(error);
46
+ return;
47
+ }
48
+ resolve(null);
49
+ });
50
+ });
51
+ }
52
+ function cleanGitValue(value) {
53
+ const cleaned = value?.trim();
54
+ return cleaned ? cleaned : null;
55
+ }
56
+ //#endregion
57
+ export { readLocalGitState };
@@ -1,4 +1,6 @@
1
+ import { renderVerboseBlock } from "../shell/ui.js";
1
2
  import { renderList, renderShow, serializeList } from "../output/patterns.js";
3
+ import { renderResolvedProjectContextBlock, stripVerboseContext } from "./verbose-context.js";
2
4
  //#region src/presenters/app-env.ts
3
5
  function scopeLabel(scope) {
4
6
  if (scope.kind === "role") return scope.role ?? "unknown";
@@ -14,23 +16,102 @@ function listTargetLabel(result) {
14
16
  }
15
17
  return scopeLabel(result.scope);
16
18
  }
17
- function renderEnvAdd(context, descriptor, result) {
18
- if (result.variables !== void 0) return renderList({
19
- title: "Setting new environment variables from file.",
20
- descriptor,
21
- parentContext: {
22
- key: "target",
23
- value: `${scopeLabel(result.scope)} from ${result.file.path}`
19
+ function renderEnvVerboseBlocks(context, result) {
20
+ return [...renderEnvResolvedContextBlock(context, result.verboseContext), ...renderEnvTargetBlock(context, result)];
21
+ }
22
+ function renderEnvResolvedContextBlock(context, verboseContext) {
23
+ return renderResolvedProjectContextBlock(context.ui, verboseContext);
24
+ }
25
+ function renderEnvTargetBlock(context, result) {
26
+ return renderVerboseBlock(context.ui, envTargetRows(result), { title: "Env target" });
27
+ }
28
+ function envTargetRows(result) {
29
+ return [
30
+ {
31
+ key: "project id",
32
+ value: result.projectId,
33
+ tone: "dim"
24
34
  },
25
- items: result.variables.map((variable) => ({
26
- noun: "variable",
27
- label: `${variable.key} (${variable.source})`,
28
- id: variable.id,
29
- status: variable.isManagedBySystem ? "default" : null
30
- })),
31
- emptyMessage: "No environment variables imported."
32
- }, context.ui);
33
- return renderShow({
35
+ {
36
+ key: "scope",
37
+ value: scopeLabel(result.scope)
38
+ },
39
+ ...envListTargetRows(result),
40
+ ...envFileRows(result),
41
+ {
42
+ key: "keys",
43
+ value: formatKeyNames(envResultKeys(result)),
44
+ tone: envResultKeys(result).length > 0 ? "default" : "dim"
45
+ }
46
+ ];
47
+ }
48
+ function envListTargetRows(result) {
49
+ if (!("target" in result)) return [];
50
+ return [
51
+ {
52
+ key: "target source",
53
+ value: result.target.source
54
+ },
55
+ {
56
+ key: "env map",
57
+ value: result.target.envMap
58
+ },
59
+ ...result.target.branchName ? [{
60
+ key: "branch",
61
+ value: result.target.branchName
62
+ }] : [],
63
+ ...result.target.branchId ? [{
64
+ key: "branch id",
65
+ value: result.target.branchId,
66
+ tone: "dim"
67
+ }] : [],
68
+ ...result.target.branchExists === false ? [{
69
+ key: "branch state",
70
+ value: "not created yet",
71
+ tone: "warning"
72
+ }] : []
73
+ ];
74
+ }
75
+ function envFileRows(result) {
76
+ if (!("file" in result) || !result.file) return [];
77
+ return [{
78
+ key: "file",
79
+ value: result.file.path
80
+ }, {
81
+ key: "file count",
82
+ value: String(result.file.count)
83
+ }];
84
+ }
85
+ function envResultKeys(result) {
86
+ if ("variables" in result && result.variables) return result.variables.map((variable) => variable.key).sort((left, right) => left.localeCompare(right));
87
+ if ("variable" in result && result.variable) return [result.variable.key];
88
+ if ("key" in result) return [result.key];
89
+ return [];
90
+ }
91
+ function formatKeyNames(keys) {
92
+ return keys.length > 0 ? keys.join(", ") : "none";
93
+ }
94
+ function renderEnvAdd(context, descriptor, result) {
95
+ if (result.variables !== void 0) {
96
+ const lines = renderList({
97
+ title: "Setting new environment variables from file.",
98
+ descriptor,
99
+ parentContext: {
100
+ key: "target",
101
+ value: `${scopeLabel(result.scope)} from ${result.file.path}`
102
+ },
103
+ items: result.variables.map((variable) => ({
104
+ noun: "variable",
105
+ label: `${variable.key} (${variable.source})`,
106
+ id: variable.id,
107
+ status: variable.isManagedBySystem ? "default" : null
108
+ })),
109
+ emptyMessage: "No environment variables imported."
110
+ }, context.ui);
111
+ lines.push(...renderEnvVerboseBlocks(context, result));
112
+ return lines;
113
+ }
114
+ const lines = renderShow({
34
115
  title: "Setting a new environment variable.",
35
116
  descriptor,
36
117
  fields: [
@@ -58,27 +139,33 @@ function renderEnvAdd(context, descriptor, result) {
58
139
  }
59
140
  ]
60
141
  }, context.ui);
142
+ lines.push(...renderEnvVerboseBlocks(context, result));
143
+ return lines;
61
144
  }
62
145
  function serializeEnvAdd(result) {
63
- return result;
146
+ return stripVerboseContext(result);
64
147
  }
65
148
  function renderEnvUpdate(context, descriptor, result) {
66
- if (result.variables !== void 0) return renderList({
67
- title: "Replacing environment variable values from file.",
68
- descriptor,
69
- parentContext: {
70
- key: "target",
71
- value: `${scopeLabel(result.scope)} from ${result.file.path}`
72
- },
73
- items: result.variables.map((variable) => ({
74
- noun: "variable",
75
- label: `${variable.key} (${variable.source})`,
76
- id: variable.id,
77
- status: variable.isManagedBySystem ? "default" : null
78
- })),
79
- emptyMessage: "No environment variables updated."
80
- }, context.ui);
81
- return renderShow({
149
+ if (result.variables !== void 0) {
150
+ const lines = renderList({
151
+ title: "Replacing environment variable values from file.",
152
+ descriptor,
153
+ parentContext: {
154
+ key: "target",
155
+ value: `${scopeLabel(result.scope)} from ${result.file.path}`
156
+ },
157
+ items: result.variables.map((variable) => ({
158
+ noun: "variable",
159
+ label: `${variable.key} (${variable.source})`,
160
+ id: variable.id,
161
+ status: variable.isManagedBySystem ? "default" : null
162
+ })),
163
+ emptyMessage: "No environment variables updated."
164
+ }, context.ui);
165
+ lines.push(...renderEnvVerboseBlocks(context, result));
166
+ return lines;
167
+ }
168
+ const lines = renderShow({
82
169
  title: "Replacing the environment variable's value.",
83
170
  descriptor,
84
171
  fields: [
@@ -106,12 +193,14 @@ function renderEnvUpdate(context, descriptor, result) {
106
193
  }
107
194
  ]
108
195
  }, context.ui);
196
+ lines.push(...renderEnvVerboseBlocks(context, result));
197
+ return lines;
109
198
  }
110
199
  function serializeEnvUpdate(result) {
111
- return result;
200
+ return stripVerboseContext(result);
112
201
  }
113
202
  function renderEnvList(context, descriptor, result) {
114
- return renderList({
203
+ const lines = renderList({
115
204
  title: "Listing environment variables for the selected scope.",
116
205
  descriptor,
117
206
  parentContext: {
@@ -126,26 +215,29 @@ function renderEnvList(context, descriptor, result) {
126
215
  })),
127
216
  emptyMessage: "No environment variables defined in this scope."
128
217
  }, context.ui);
218
+ lines.push(...renderEnvVerboseBlocks(context, result));
219
+ return lines;
129
220
  }
130
221
  function serializeEnvList(result) {
222
+ const serializable = stripVerboseContext(result);
131
223
  return {
132
- projectId: result.projectId,
133
- scope: result.scope,
134
- target: result.target,
224
+ projectId: serializable.projectId,
225
+ scope: serializable.scope,
226
+ target: serializable.target,
135
227
  ...serializeList({
136
- context: { target: listTargetLabel(result) },
137
- items: result.variables.map((variable) => ({
228
+ context: { target: listTargetLabel(serializable) },
229
+ items: serializable.variables.map((variable) => ({
138
230
  noun: "variable",
139
231
  label: `${variable.key} (${variable.source})`,
140
232
  id: variable.id,
141
233
  status: variable.isManagedBySystem ? "default" : null
142
234
  }))
143
235
  }),
144
- variables: result.variables
236
+ variables: serializable.variables
145
237
  };
146
238
  }
147
239
  function renderEnvRm(context, descriptor, result) {
148
- return renderShow({
240
+ const lines = renderShow({
149
241
  title: "Removing the environment variable from the scope.",
150
242
  descriptor,
151
243
  fields: [
@@ -163,9 +255,11 @@ function renderEnvRm(context, descriptor, result) {
163
255
  }
164
256
  ]
165
257
  }, context.ui);
258
+ lines.push(...renderEnvVerboseBlocks(context, result));
259
+ return lines;
166
260
  }
167
261
  function serializeEnvRm(result) {
168
- return result;
262
+ return stripVerboseContext(result);
169
263
  }
170
264
  //#endregion
171
265
  export { renderEnvAdd, renderEnvList, renderEnvRm, renderEnvUpdate, serializeEnvAdd, serializeEnvList, serializeEnvRm, serializeEnvUpdate };
@@ -1,6 +1,8 @@
1
+ import { renderVerboseBlock } from "../shell/ui.js";
1
2
  import { renderDeployOutputRows } from "../lib/app/deploy-output.js";
2
3
  import { formatDomainFailureFix } from "../lib/app/domain-guidance.js";
3
4
  import { renderList, renderShow, serializeList } from "../output/patterns.js";
5
+ import { renderResolvedProjectContextBlock, stripVerboseContext } from "./verbose-context.js";
4
6
  //#region src/presenters/app.ts
5
7
  function renderAppBuild(context, descriptor, result) {
6
8
  return renderShow({
@@ -35,12 +37,18 @@ function renderAppDeploy(context, descriptor, result) {
35
37
  ...renderDeployOutputRows(context.ui, [{
36
38
  label: "Logs",
37
39
  value: "prisma-cli app logs"
38
- }])
40
+ }]),
41
+ ...renderDeployResolvedContextBlock(context, result),
42
+ ...renderDeploySettingsBlock(context, result)
39
43
  ];
40
44
  }
41
45
  function serializeAppDeploy(result) {
42
- const { localPin: _localPin, ...serialized } = result;
43
- return serialized;
46
+ const { deploySettings: _deploySettings, localPin: _localPin, ...serialized } = result;
47
+ const { id: _branchId, ...branch } = serialized.branch;
48
+ return {
49
+ ...serialized,
50
+ branch
51
+ };
44
52
  }
45
53
  function renderBranchDatabaseDeploySummary(context, result) {
46
54
  if (!result.branchDatabase || result.branchDatabase.status !== "created") return [];
@@ -70,8 +78,107 @@ function formatDuration(durationMs) {
70
78
  if (durationMs < 1e3) return `${durationMs}ms`;
71
79
  return `${(durationMs / 1e3).toFixed(1)}s`;
72
80
  }
81
+ function renderDeployResolvedContextBlock(context, result) {
82
+ return renderResolvedProjectContextBlock(context.ui, {
83
+ workspace: result.workspace,
84
+ project: result.project,
85
+ resolution: result.resolution,
86
+ branch: {
87
+ id: result.branch.id,
88
+ name: result.branch.name,
89
+ kind: result.branch.kind
90
+ }
91
+ }, { extraRows: [
92
+ {
93
+ key: "app",
94
+ value: result.app.name
95
+ },
96
+ {
97
+ key: "app id",
98
+ value: result.app.id,
99
+ tone: "dim"
100
+ },
101
+ {
102
+ key: "deployment id",
103
+ value: result.deployment.id,
104
+ tone: "dim"
105
+ },
106
+ {
107
+ key: "deployment status",
108
+ value: result.deployment.status
109
+ },
110
+ ...result.localPin ? [{
111
+ key: "local pin",
112
+ value: result.localPin.path
113
+ }] : [],
114
+ {
115
+ key: "deploy duration",
116
+ value: formatDuration(result.durationMs)
117
+ }
118
+ ] });
119
+ }
120
+ function renderDeploySettingsBlock(context, result) {
121
+ return renderVerboseBlock(context.ui, [...deploySettingsRows(result.deploySettings), ...branchDatabaseRows(result.branchDatabase)], { title: "Deploy settings" });
122
+ }
123
+ function deploySettingsRows(settings) {
124
+ return [
125
+ {
126
+ key: "framework",
127
+ value: `${settings.framework.name} (${settings.framework.buildType})`
128
+ },
129
+ {
130
+ key: "framework source",
131
+ value: settings.framework.source,
132
+ tone: "dim"
133
+ },
134
+ {
135
+ key: "entrypoint",
136
+ value: settings.entrypoint ?? "derived from build output",
137
+ tone: settings.entrypoint ? "default" : "dim"
138
+ },
139
+ {
140
+ key: "http port",
141
+ value: String(settings.httpPort)
142
+ },
143
+ {
144
+ key: "region",
145
+ value: settings.region ?? "existing app region",
146
+ tone: settings.region ? "default" : "dim"
147
+ },
148
+ {
149
+ key: "env vars",
150
+ value: formatEnvVarNames(settings.envVars),
151
+ tone: settings.envVars.length > 0 ? "default" : "dim"
152
+ }
153
+ ];
154
+ }
155
+ function branchDatabaseRows(branchDatabase) {
156
+ if (!branchDatabase) return [{
157
+ key: "branch db",
158
+ value: "not configured",
159
+ tone: "dim"
160
+ }];
161
+ return [
162
+ {
163
+ key: "branch db",
164
+ value: branchDatabase.status === "created" ? `created${branchDatabase.database ? ` (${branchDatabase.database.name})` : ""}` : `skipped${branchDatabase.reason ? ` (${branchDatabase.reason})` : ""}`,
165
+ tone: branchDatabase.status === "created" ? "success" : "dim"
166
+ },
167
+ ...branchDatabase.envVars.length > 0 ? [{
168
+ key: "branch db env",
169
+ value: branchDatabase.envVars.join(", ")
170
+ }] : [],
171
+ ...branchDatabase.schema ? [{
172
+ key: "branch db schema",
173
+ value: `${formatBranchDatabaseSchemaCommand(branchDatabase.schema.command)} (${branchDatabase.schema.source}, ${branchDatabase.schema.path})`
174
+ }] : []
175
+ ];
176
+ }
177
+ function formatEnvVarNames(envVars) {
178
+ return envVars.length > 0 ? envVars.join(", ") : "none";
179
+ }
73
180
  function renderAppListDeploys(context, descriptor, result) {
74
- return renderList({
181
+ const lines = renderList({
75
182
  title: "Listing deployments for the selected app.",
76
183
  descriptor,
77
184
  parentContext: {
@@ -86,20 +193,23 @@ function renderAppListDeploys(context, descriptor, result) {
86
193
  })),
87
194
  emptyMessage: result.app ? "No deployments found." : "No apps found."
88
195
  }, context.ui);
196
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
197
+ return lines;
89
198
  }
90
199
  function serializeAppListDeploys(result) {
91
- if (!result.app) return {
92
- projectId: result.projectId,
200
+ const { verboseContext: _verboseContext, ...serializable } = result;
201
+ if (!serializable.app) return {
202
+ projectId: serializable.projectId,
93
203
  app: null,
94
204
  items: [],
95
205
  count: 0
96
206
  };
97
207
  return {
98
- projectId: result.projectId,
99
- app: result.app,
208
+ projectId: serializable.projectId,
209
+ app: serializable.app,
100
210
  ...serializeList({
101
- context: { app: result.app.name },
102
- items: result.deployments.map((deployment) => ({
211
+ context: { app: serializable.app.name },
212
+ items: serializable.deployments.map((deployment) => ({
103
213
  noun: "deployment",
104
214
  label: deployment.id,
105
215
  id: deployment.id,
@@ -109,7 +219,7 @@ function serializeAppListDeploys(result) {
109
219
  };
110
220
  }
111
221
  function renderAppShow(context, descriptor, result) {
112
- return renderShow({
222
+ const lines = renderShow({
113
223
  title: "Showing the selected app state.",
114
224
  descriptor,
115
225
  fields: [
@@ -139,9 +249,11 @@ function renderAppShow(context, descriptor, result) {
139
249
  }
140
250
  ]
141
251
  }, context.ui);
252
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
253
+ return lines;
142
254
  }
143
255
  function serializeAppShow(result) {
144
- return result;
256
+ return stripVerboseContext(result);
145
257
  }
146
258
  function renderAppShowDeploy(context, descriptor, result) {
147
259
  return renderShow({
@@ -183,7 +295,7 @@ function serializeAppShowDeploy(result) {
183
295
  return result;
184
296
  }
185
297
  function renderAppOpen(context, descriptor, result) {
186
- return renderShow({
298
+ const lines = renderShow({
187
299
  title: result.opened ? "Opening the live URL for the selected app." : "Resolving the live URL for the selected app.",
188
300
  descriptor,
189
301
  fields: [
@@ -207,9 +319,11 @@ function renderAppOpen(context, descriptor, result) {
207
319
  }
208
320
  ]
209
321
  }, context.ui);
322
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
323
+ return lines;
210
324
  }
211
325
  function serializeAppOpen(result) {
212
- return result;
326
+ return stripVerboseContext(result);
213
327
  }
214
328
  function renderAppDomainAdd(context, descriptor, result) {
215
329
  return renderShow({
@@ -311,7 +425,7 @@ function serializeAppDomainRetry(result) {
311
425
  return result;
312
426
  }
313
427
  function renderAppPromote(context, descriptor, result) {
314
- return renderShow({
428
+ const lines = renderShow({
315
429
  title: "Switching the live deployment for the selected app.",
316
430
  descriptor,
317
431
  fields: [
@@ -349,12 +463,14 @@ function renderAppPromote(context, descriptor, result) {
349
463
  }
350
464
  ]
351
465
  }, context.ui);
466
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
467
+ return lines;
352
468
  }
353
469
  function serializeAppPromote(result) {
354
- return result;
470
+ return stripVerboseContext(result);
355
471
  }
356
472
  function renderAppRollback(context, descriptor, result) {
357
- return renderShow({
473
+ const lines = renderShow({
358
474
  title: "Restoring the selected app to an earlier deployment.",
359
475
  descriptor,
360
476
  fields: [
@@ -397,9 +513,11 @@ function renderAppRollback(context, descriptor, result) {
397
513
  }] : []
398
514
  ]
399
515
  }, context.ui);
516
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
517
+ return lines;
400
518
  }
401
519
  function serializeAppRollback(result) {
402
- return result;
520
+ return stripVerboseContext(result);
403
521
  }
404
522
  function renderAppRun(_context, _descriptor, _result) {
405
523
  return [];
@@ -408,7 +526,7 @@ function serializeAppRun(result) {
408
526
  return result;
409
527
  }
410
528
  function renderAppRemove(context, descriptor, result) {
411
- return renderShow({
529
+ const lines = renderShow({
412
530
  title: "Removing the selected app.",
413
531
  descriptor,
414
532
  fields: [
@@ -427,9 +545,11 @@ function renderAppRemove(context, descriptor, result) {
427
545
  }
428
546
  ]
429
547
  }, context.ui);
548
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
549
+ return lines;
430
550
  }
431
551
  function serializeAppRemove(result) {
432
- return result;
552
+ return stripVerboseContext(result);
433
553
  }
434
554
  function toneForStatus(status) {
435
555
  if (status === "running" || status === "ready" || status === "healthy") return "success";
@@ -1,5 +1,6 @@
1
1
  import { formatColumns } from "../shell/ui.js";
2
2
  import { formatDescriptorLabel } from "../shell/command-meta.js";
3
+ import { renderResolvedProjectContextBlock } from "./verbose-context.js";
3
4
  //#region src/presenters/branch.ts
4
5
  function renderBranchList(context, descriptor, result) {
5
6
  const ui = context.ui;
@@ -9,6 +10,7 @@ function renderBranchList(context, descriptor, result) {
9
10
  lines.push(rail);
10
11
  if (result.branches.length === 0) {
11
12
  lines.push(`${rail} ${ui.dim("No branches found.")}`);
13
+ lines.push(...renderBranchResolvedContextBlock(context, result));
12
14
  return lines;
13
15
  }
14
16
  const widths = [
@@ -26,14 +28,19 @@ function renderBranchList(context, descriptor, result) {
26
28
  branch.role,
27
29
  branch.envMap
28
30
  ], widths)}`);
31
+ lines.push(...renderBranchResolvedContextBlock(context, result));
29
32
  return lines;
30
33
  }
31
34
  function serializeBranchList(result) {
35
+ const { verboseContext: _verboseContext, ...serializable } = result;
32
36
  return {
33
- projectId: result.projectId,
34
- projectName: result.projectName,
35
- branches: result.branches
37
+ projectId: serializable.projectId,
38
+ projectName: serializable.projectName,
39
+ branches: serializable.branches
36
40
  };
37
41
  }
42
+ function renderBranchResolvedContextBlock(context, result) {
43
+ return renderResolvedProjectContextBlock(context.ui, result.verboseContext);
44
+ }
38
45
  //#endregion
39
46
  export { renderBranchList, serializeBranchList };
@@ -1,7 +1,8 @@
1
- import { padDisplay, renderNextSteps, renderSummaryLine } from "../shell/ui.js";
1
+ import { padDisplay, renderNextSteps, renderSummaryLine, renderVerboseBlock } from "../shell/ui.js";
2
2
  import { formatDescriptorLabel } from "../shell/command-meta.js";
3
3
  import { formatCommandArgument } from "../shell/command-arguments.js";
4
4
  import { renderMutate, renderShow, serializeList } from "../output/patterns.js";
5
+ import { renderResolvedProjectContextBlock } from "./verbose-context.js";
5
6
  import path from "node:path";
6
7
  import stringWidth from "string-width";
7
8
  //#region src/presenters/project.ts
@@ -50,6 +51,25 @@ function renderProjectShow(context, descriptor, result) {
50
51
  tone: "warning"
51
52
  }]
52
53
  }, context.ui);
54
+ lines.push(...renderVerboseBlock(context.ui, [
55
+ {
56
+ key: "workspace",
57
+ value: result.workspace.name
58
+ },
59
+ {
60
+ key: "workspace id",
61
+ value: result.workspace.id,
62
+ tone: "dim"
63
+ },
64
+ {
65
+ key: "project source",
66
+ value: "unbound"
67
+ },
68
+ {
69
+ key: "suggested name",
70
+ value: `${result.suggestedProjectName} (${result.suggestedProjectNameSource})`
71
+ }
72
+ ], { title: "Resolved context" }));
53
73
  lines.push(...renderNextSteps(["Link an existing Project you choose: prisma-cli project link <id-or-name>", `Create a new Project: prisma-cli project create ${formatCommandArgument(result.suggestedProjectName)}`]));
54
74
  return lines;
55
75
  }
@@ -132,6 +152,11 @@ function renderBoundProjectShow(context, descriptor, result) {
132
152
  lines.push(rail);
133
153
  lines.push(`${rail} ${ui.dim("→")} ${ui.link(result.project.url)}`);
134
154
  }
155
+ lines.push(...renderResolvedProjectContextBlock(context.ui, {
156
+ workspace: result.workspace,
157
+ project: result.project,
158
+ resolution: result.resolution
159
+ }));
135
160
  return lines;
136
161
  }
137
162
  function formatLocalRepoPath(cwd, env) {
@@ -0,0 +1,64 @@
1
+ import { renderVerboseBlock } from "../shell/ui.js";
2
+ //#region src/presenters/verbose-context.ts
3
+ function renderResolvedProjectContextBlock(ui, context, options = {}) {
4
+ if (!context) return [];
5
+ return renderVerboseBlock(ui, [...projectResolutionRows(context), ...options.extraRows ?? []], { title: options.title ?? "Resolved context" });
6
+ }
7
+ function projectResolutionRows(context) {
8
+ return [
9
+ {
10
+ key: "workspace",
11
+ value: context.workspace.name
12
+ },
13
+ {
14
+ key: "workspace id",
15
+ value: context.workspace.id,
16
+ tone: "dim"
17
+ },
18
+ {
19
+ key: "project",
20
+ value: context.project.name
21
+ },
22
+ {
23
+ key: "project id",
24
+ value: context.project.id,
25
+ tone: "dim"
26
+ },
27
+ {
28
+ key: "project source",
29
+ value: formatProjectSource(context.resolution.projectSource)
30
+ },
31
+ ...context.resolution.targetName ? [{
32
+ key: "target name",
33
+ value: formatTargetName(context.resolution)
34
+ }] : [],
35
+ ...context.branch ? [{
36
+ key: "branch",
37
+ value: `${context.branch.name} (${context.branch.kind})`
38
+ }, ...context.branch.id ? [{
39
+ key: "branch id",
40
+ value: context.branch.id,
41
+ tone: "dim"
42
+ }] : []] : []
43
+ ];
44
+ }
45
+ function stripVerboseContext(result) {
46
+ const { verboseContext: _verboseContext, ...serialized } = result;
47
+ return serialized;
48
+ }
49
+ function formatProjectSource(source) {
50
+ switch (source) {
51
+ case "explicit": return "--project";
52
+ case "env": return "environment";
53
+ case "local-pin": return ".prisma/local.json";
54
+ case "platform-mapping": return "platform mapping";
55
+ case "created": return "created";
56
+ case "prompt": return "prompt";
57
+ case "unbound": return "unbound";
58
+ }
59
+ }
60
+ function formatTargetName(resolution) {
61
+ return resolution.targetNameSource ? `${resolution.targetName} (${resolution.targetNameSource})` : String(resolution.targetName);
62
+ }
63
+ //#endregion
64
+ export { renderResolvedProjectContextBlock, stripVerboseContext };
@@ -3,6 +3,8 @@ import { cliErrorToJson, writeHumanError, writeHumanLines, writeJsonError, write
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
10
  function toCliError(error, runtime) {
@@ -19,6 +21,7 @@ async function runCommand(runtime, commandName, options, handler, presenter) {
19
21
  const flags = resolveGlobalFlags(runtime.argv, options);
20
22
  const context = await createCommandContext(runtime, flags);
21
23
  const descriptor = getCommandDescriptor(commandName);
24
+ const startedAt = Date.now();
22
25
  try {
23
26
  const success = await handler(context);
24
27
  if (flags.json) {
@@ -29,7 +32,12 @@ async function runCommand(runtime, commandName, options, handler, presenter) {
29
32
  return;
30
33
  }
31
34
  if (flags.quiet) return;
32
- writeHumanLines(context.output, presenter.renderHuman(context, descriptor, success.result));
35
+ const rendered = presenter.renderHuman(context, descriptor, success.result);
36
+ const diagnostics = await renderBestEffortCommandDiagnostics(context, {
37
+ enabled: flags.verbose && rendered.length > 0,
38
+ durationMs: Date.now() - startedAt
39
+ });
40
+ writeHumanLines(context.output, [...rendered, ...diagnostics]);
33
41
  } catch (error) {
34
42
  const cliError = toCliError(error, runtime);
35
43
  if (cliError) {
@@ -41,6 +49,14 @@ async function runCommand(runtime, commandName, options, handler, presenter) {
41
49
  throw error;
42
50
  }
43
51
  }
52
+ async function renderBestEffortCommandDiagnostics(context, options) {
53
+ if (!options.enabled) return [];
54
+ try {
55
+ return renderCommandDiagnostics(context, await collectCommandDiagnostics(context, { durationMs: options.durationMs }));
56
+ } catch {
57
+ return [];
58
+ }
59
+ }
44
60
  async function runStreamingCommand(runtime, commandName, options, handler) {
45
61
  const flags = resolveGlobalFlags(runtime.argv, options);
46
62
  const context = await createCommandContext(runtime, flags);
@@ -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 };
@@ -23,6 +23,15 @@ function cliErrorToJson(error) {
23
23
  docsUrl: error.docsUrl
24
24
  };
25
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
+ }
26
35
  function writeJsonError(output, command, error) {
27
36
  output.stdout.write(`${JSON.stringify({
28
37
  ok: false,
@@ -70,4 +79,4 @@ function writeHumanError(output, ui, error, options) {
70
79
  writeHumanLines(output, lines);
71
80
  }
72
81
  //#endregion
73
- export { cliErrorToJson, writeHumanError, writeHumanLines, writeJsonError, writeJsonEvent, writeJsonSuccess };
82
+ export { cliErrorToJson, formatUnexpectedError, writeHumanError, writeHumanLines, writeJsonError, writeJsonEvent, writeJsonSuccess };
@@ -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,17 @@ 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
+ }
51
62
  function formatColumns(columns, widths) {
52
63
  return columns.map((value, index) => padDisplay(value, widths[index])).join(" ").trimEnd();
53
64
  }
@@ -76,5 +87,13 @@ function formatHeaderValue(ui, row) {
76
87
  if (row.tone === "link") return ui.link(value);
77
88
  return value;
78
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
+ }
79
98
  //#endregion
80
- export { createShellUi, formatColumns, maskValue, padDisplay, renderCommandHeader, renderNextSteps, renderSummaryLine, wrapText };
99
+ export { createShellUi, formatColumns, maskValue, padDisplay, renderCommandHeader, renderNextSteps, renderSummaryLine, renderVerboseBlock, wrapText };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/cli",
3
- "version": "3.0.0-dev.63.1",
3
+ "version": "3.0.0-dev.67.1",
4
4
  "description": "Command-line interface for the Prisma Developer Platform.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -36,9 +36,9 @@
36
36
  "license": "Apache-2.0",
37
37
  "dependencies": {
38
38
  "@clack/prompts": "^1.5.0",
39
- "@prisma/compute-sdk": "^0.20.0",
39
+ "@prisma/compute-sdk": "^0.22.0",
40
40
  "@prisma/credentials-store": "^7.8.0",
41
- "@prisma/management-api-sdk": "^1.35.0",
41
+ "@prisma/management-api-sdk": "^1.37.0",
42
42
  "c12": "4.0.0-beta.5",
43
43
  "colorette": "^2.0.20",
44
44
  "commander": "^14.0.3",