@prisma/cli 3.0.0-beta.2 → 3.0.0-beta.21

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 (87) hide show
  1. package/README.md +5 -16
  2. package/dist/adapters/git.js +8 -3
  3. package/dist/adapters/local-state.js +26 -7
  4. package/dist/adapters/mock-api.js +81 -2
  5. package/dist/adapters/token-storage.js +344 -25
  6. package/dist/cli.js +18 -3
  7. package/dist/cli2.js +12 -4
  8. package/dist/commands/agent/index.js +60 -0
  9. package/dist/commands/app/index.js +90 -61
  10. package/dist/commands/auth/index.js +55 -2
  11. package/dist/commands/branch/index.js +2 -27
  12. package/dist/commands/build/index.js +29 -0
  13. package/dist/commands/database/index.js +159 -0
  14. package/dist/commands/env.js +8 -4
  15. package/dist/commands/git/index.js +1 -1
  16. package/dist/commands/project/index.js +1 -1
  17. package/dist/controllers/agent.js +228 -0
  18. package/dist/controllers/app-env-api.js +55 -0
  19. package/dist/controllers/app-env-file.js +181 -0
  20. package/dist/controllers/app-env.js +286 -131
  21. package/dist/controllers/app.js +849 -309
  22. package/dist/controllers/auth.js +255 -11
  23. package/dist/controllers/branch.js +78 -48
  24. package/dist/controllers/build.js +88 -0
  25. package/dist/controllers/database.js +318 -0
  26. package/dist/controllers/project.js +156 -87
  27. package/dist/controllers/select-prompt-port.js +1 -0
  28. package/dist/lib/agent/cli-command.js +17 -0
  29. package/dist/lib/agent/constants.js +12 -0
  30. package/dist/lib/agent/package-manager.js +99 -0
  31. package/dist/lib/agent/setup-status.js +83 -0
  32. package/dist/lib/app/app-interaction.js +5 -0
  33. package/dist/lib/app/{preview-provider.js → app-provider.js} +220 -104
  34. package/dist/lib/app/branch-database-api.js +102 -0
  35. package/dist/lib/app/branch-database-deploy.js +326 -0
  36. package/dist/lib/app/branch-database.js +216 -0
  37. package/dist/lib/app/build-settings.js +93 -0
  38. package/dist/lib/app/build.js +82 -0
  39. package/dist/lib/app/bun-project.js +15 -9
  40. package/dist/lib/app/compute-config.js +145 -0
  41. package/dist/lib/app/deploy-plan.js +59 -0
  42. package/dist/lib/app/{preview-progress.js → deploy-progress.js} +12 -12
  43. package/dist/lib/app/env-config.js +1 -1
  44. package/dist/lib/app/env-file.js +82 -0
  45. package/dist/lib/app/env-vars.js +28 -2
  46. package/dist/lib/app/local-dev.js +8 -49
  47. package/dist/lib/app/production-deploy-gate.js +162 -0
  48. package/dist/lib/app/read-branch.js +30 -0
  49. package/dist/lib/auth/auth-ops.js +38 -23
  50. package/dist/lib/auth/guard.js +6 -2
  51. package/dist/lib/auth/login.js +117 -15
  52. package/dist/lib/database/provider.js +167 -0
  53. package/dist/lib/diagnostics.js +15 -0
  54. package/dist/lib/fs/home-path.js +24 -0
  55. package/dist/lib/git/local-branch.js +53 -0
  56. package/dist/lib/git/local-status.js +57 -0
  57. package/dist/lib/project/interactive-setup.js +2 -1
  58. package/dist/lib/project/local-pin.js +183 -34
  59. package/dist/lib/project/resolution.js +206 -50
  60. package/dist/lib/project/setup.js +64 -18
  61. package/dist/output/patterns.js +1 -1
  62. package/dist/presenters/agent.js +74 -0
  63. package/dist/presenters/app-env.js +149 -14
  64. package/dist/presenters/app.js +187 -26
  65. package/dist/presenters/auth.js +99 -2
  66. package/dist/presenters/branch.js +37 -102
  67. package/dist/presenters/database.js +274 -0
  68. package/dist/presenters/project.js +44 -26
  69. package/dist/presenters/verbose-context.js +64 -0
  70. package/dist/shell/cli-command.js +12 -0
  71. package/dist/shell/command-arguments.js +7 -1
  72. package/dist/shell/command-meta.js +243 -15
  73. package/dist/shell/command-runner.js +60 -21
  74. package/dist/shell/diagnostics-output.js +57 -0
  75. package/dist/shell/errors.js +61 -1
  76. package/dist/shell/help.js +31 -20
  77. package/dist/shell/output.js +10 -1
  78. package/dist/shell/prompt.js +7 -3
  79. package/dist/shell/runtime.js +10 -6
  80. package/dist/shell/ui.js +42 -3
  81. package/dist/shell/update-check.js +247 -0
  82. package/dist/use-cases/auth.js +68 -1
  83. package/dist/use-cases/branch.js +20 -68
  84. package/dist/use-cases/create-cli-gateways.js +2 -17
  85. package/package.json +27 -10
  86. package/dist/lib/app/preview-build.js +0 -284
  87. package/dist/lib/app/preview-interaction.js +0 -5
@@ -1,11 +1,117 @@
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";
7
+ if (scope.kind === "overview") return "overview";
5
8
  return `branch:${scope.branchName ?? scope.branchId ?? "unknown"}`;
6
9
  }
10
+ function listTargetLabel(result) {
11
+ const target = result.target;
12
+ if (target.source === "overview") return "overview";
13
+ if (target.branchName) {
14
+ const suffix = target.branchExists === false ? " (not created yet)" : "";
15
+ return `branch:${target.branchName} -> ${target.envMap}${suffix}`;
16
+ }
17
+ return scopeLabel(result.scope);
18
+ }
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"
34
+ },
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
+ }
7
94
  function renderEnvAdd(context, descriptor, result) {
8
- return renderShow({
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({
9
115
  title: "Setting a new environment variable.",
10
116
  descriptor,
11
117
  fields: [
@@ -33,12 +139,33 @@ function renderEnvAdd(context, descriptor, result) {
33
139
  }
34
140
  ]
35
141
  }, context.ui);
142
+ lines.push(...renderEnvVerboseBlocks(context, result));
143
+ return lines;
36
144
  }
37
145
  function serializeEnvAdd(result) {
38
- return result;
146
+ return stripVerboseContext(result);
39
147
  }
40
148
  function renderEnvUpdate(context, descriptor, result) {
41
- 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({
42
169
  title: "Replacing the environment variable's value.",
43
170
  descriptor,
44
171
  fields: [
@@ -66,17 +193,19 @@ function renderEnvUpdate(context, descriptor, result) {
66
193
  }
67
194
  ]
68
195
  }, context.ui);
196
+ lines.push(...renderEnvVerboseBlocks(context, result));
197
+ return lines;
69
198
  }
70
199
  function serializeEnvUpdate(result) {
71
- return result;
200
+ return stripVerboseContext(result);
72
201
  }
73
202
  function renderEnvList(context, descriptor, result) {
74
- return renderList({
203
+ const lines = renderList({
75
204
  title: "Listing environment variables for the selected scope.",
76
205
  descriptor,
77
206
  parentContext: {
78
- key: "scope",
79
- value: scopeLabel(result.scope)
207
+ key: "target",
208
+ value: listTargetLabel(result)
80
209
  },
81
210
  items: result.variables.map((variable) => ({
82
211
  noun: "variable",
@@ -86,25 +215,29 @@ function renderEnvList(context, descriptor, result) {
86
215
  })),
87
216
  emptyMessage: "No environment variables defined in this scope."
88
217
  }, context.ui);
218
+ lines.push(...renderEnvVerboseBlocks(context, result));
219
+ return lines;
89
220
  }
90
221
  function serializeEnvList(result) {
222
+ const serializable = stripVerboseContext(result);
91
223
  return {
92
- projectId: result.projectId,
93
- scope: result.scope,
224
+ projectId: serializable.projectId,
225
+ scope: serializable.scope,
226
+ target: serializable.target,
94
227
  ...serializeList({
95
- context: { scope: scopeLabel(result.scope) },
96
- items: result.variables.map((variable) => ({
228
+ context: { target: listTargetLabel(serializable) },
229
+ items: serializable.variables.map((variable) => ({
97
230
  noun: "variable",
98
231
  label: `${variable.key} (${variable.source})`,
99
232
  id: variable.id,
100
233
  status: variable.isManagedBySystem ? "default" : null
101
234
  }))
102
235
  }),
103
- variables: result.variables
236
+ variables: serializable.variables
104
237
  };
105
238
  }
106
239
  function renderEnvRm(context, descriptor, result) {
107
- return renderShow({
240
+ const lines = renderShow({
108
241
  title: "Removing the environment variable from the scope.",
109
242
  descriptor,
110
243
  fields: [
@@ -122,9 +255,11 @@ function renderEnvRm(context, descriptor, result) {
122
255
  }
123
256
  ]
124
257
  }, context.ui);
258
+ lines.push(...renderEnvVerboseBlocks(context, result));
259
+ return lines;
125
260
  }
126
261
  function serializeEnvRm(result) {
127
- return result;
262
+ return stripVerboseContext(result);
128
263
  }
129
264
  //#endregion
130
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({
@@ -26,27 +28,173 @@ function renderAppBuild(context, descriptor, result) {
26
28
  function serializeAppBuild(result) {
27
29
  return result;
28
30
  }
29
- function renderAppDeploy(context, descriptor, result) {
31
+ function renderAppDeploy(context, descriptor, result, options) {
32
+ const logsCommand = options?.logsTarget ? `prisma-cli app logs ${options.logsTarget}` : "prisma-cli app logs";
30
33
  return [
31
- `Live in ${formatDuration(result.durationMs)}`,
32
- ...result.deployment.url ? [context.ui.link(result.deployment.url)] : [],
34
+ ...result.promoted ? [`Live in ${formatDuration(result.durationMs)}`, ...result.deployment.url ? [context.ui.link(result.deployment.url)] : []] : [
35
+ `Built ${result.deployment.id} in ${formatDuration(result.durationMs)} (not promoted)`,
36
+ ...result.deployment.url ? [context.ui.link(result.deployment.url)] : [],
37
+ context.ui.dim("The live deployment is unchanged.")
38
+ ],
39
+ ...renderBranchDatabaseDeploySummary(context, result),
33
40
  "",
34
- ...renderDeployOutputRows(context.ui, [{
41
+ ...renderDeployOutputRows(context.ui, [...result.promoted ? [] : [{
42
+ label: "Promote",
43
+ value: `prisma-cli app promote ${result.deployment.id}`
44
+ }], {
35
45
  label: "Logs",
36
- value: "prisma-cli app logs"
37
- }])
46
+ value: logsCommand
47
+ }]),
48
+ ...renderDeployResolvedContextBlock(context, result),
49
+ ...renderDeploySettingsBlock(context, result)
38
50
  ];
39
51
  }
52
+ function isAppDeployAllResult(result) {
53
+ return "deployments" in result;
54
+ }
55
+ function renderAppDeployAll(context, descriptor, result) {
56
+ const lines = [];
57
+ for (const deployment of result.deployments) {
58
+ lines.push(deployment.target);
59
+ lines.push(...renderAppDeploy(context, descriptor, deployment.result, { logsTarget: deployment.target }).map((line) => line ? ` ${line}` : line));
60
+ lines.push("");
61
+ }
62
+ lines.push(...renderDeployOutputRows(context.ui, result.deployments.map((deployment) => ({
63
+ label: deployment.target,
64
+ value: deployment.result.deployment.url ?? deployment.result.deployment.id
65
+ }))));
66
+ return lines;
67
+ }
68
+ function serializeAppDeployAll(result) {
69
+ return {
70
+ count: result.deployments.length,
71
+ deployments: result.deployments.map((deployment) => ({
72
+ target: deployment.target,
73
+ ...serializeAppDeploy(deployment.result)
74
+ }))
75
+ };
76
+ }
40
77
  function serializeAppDeploy(result) {
41
- const { localPin: _localPin, ...serialized } = result;
42
- return serialized;
78
+ const { deploySettings, localPin: _localPin, ...serialized } = result;
79
+ const { id: _branchId, ...branch } = serialized.branch;
80
+ return {
81
+ ...serialized,
82
+ branch,
83
+ deploySettings: {
84
+ config: deploySettings.config,
85
+ buildCommand: deploySettings.buildCommand,
86
+ outputDirectory: deploySettings.outputDirectory
87
+ }
88
+ };
89
+ }
90
+ function renderBranchDatabaseDeploySummary(context, result) {
91
+ if (!result.branchDatabase || result.branchDatabase.status !== "created") return [];
92
+ return ["", ...renderDeployOutputRows(context.ui, [{
93
+ label: "Database",
94
+ value: result.branchDatabase.database?.name ?? "created"
95
+ }, {
96
+ label: "Env",
97
+ value: result.branchDatabase.envVars.join(", ")
98
+ }])];
43
99
  }
44
100
  function formatDuration(durationMs) {
45
101
  if (durationMs < 1e3) return `${durationMs}ms`;
46
102
  return `${(durationMs / 1e3).toFixed(1)}s`;
47
103
  }
104
+ function renderDeployResolvedContextBlock(context, result) {
105
+ return renderResolvedProjectContextBlock(context.ui, {
106
+ workspace: result.workspace,
107
+ project: result.project,
108
+ resolution: result.resolution,
109
+ branch: {
110
+ id: result.branch.id,
111
+ name: result.branch.name,
112
+ kind: result.branch.kind
113
+ }
114
+ }, { extraRows: [
115
+ {
116
+ key: "app",
117
+ value: result.app.name
118
+ },
119
+ {
120
+ key: "app id",
121
+ value: result.app.id,
122
+ tone: "dim"
123
+ },
124
+ {
125
+ key: "deployment id",
126
+ value: result.deployment.id,
127
+ tone: "dim"
128
+ },
129
+ {
130
+ key: "deployment status",
131
+ value: result.deployment.status
132
+ },
133
+ ...result.localPin ? [{
134
+ key: "local pin",
135
+ value: result.localPin.path
136
+ }] : [],
137
+ {
138
+ key: "deploy duration",
139
+ value: formatDuration(result.durationMs)
140
+ }
141
+ ] });
142
+ }
143
+ function renderDeploySettingsBlock(context, result) {
144
+ return renderVerboseBlock(context.ui, [...deploySettingsRows(result.deploySettings), ...branchDatabaseRows(result.branchDatabase)], { title: "Deploy settings" });
145
+ }
146
+ function deploySettingsRows(settings) {
147
+ return [
148
+ {
149
+ key: "framework",
150
+ value: `${settings.framework.name} (${settings.framework.buildType})`
151
+ },
152
+ {
153
+ key: "framework source",
154
+ value: settings.framework.source,
155
+ tone: "dim"
156
+ },
157
+ {
158
+ key: "entrypoint",
159
+ value: settings.entrypoint ?? "derived from build output",
160
+ tone: settings.entrypoint ? "default" : "dim"
161
+ },
162
+ {
163
+ key: "http port",
164
+ value: String(settings.httpPort)
165
+ },
166
+ {
167
+ key: "region",
168
+ value: settings.region ?? "existing app region",
169
+ tone: settings.region ? "default" : "dim"
170
+ },
171
+ {
172
+ key: "env vars",
173
+ value: formatEnvVarNames(settings.envVars),
174
+ tone: settings.envVars.length > 0 ? "default" : "dim"
175
+ }
176
+ ];
177
+ }
178
+ function branchDatabaseRows(branchDatabase) {
179
+ if (!branchDatabase) return [{
180
+ key: "branch db",
181
+ value: "not configured",
182
+ tone: "dim"
183
+ }];
184
+ return [{
185
+ key: "branch db",
186
+ value: branchDatabase.status === "created" ? `created${branchDatabase.database ? ` (${branchDatabase.database.name})` : ""}` : `skipped${branchDatabase.reason ? ` (${branchDatabase.reason})` : ""}`,
187
+ tone: branchDatabase.status === "created" ? "success" : "dim"
188
+ }, ...branchDatabase.envVars.length > 0 ? [{
189
+ key: "branch db env",
190
+ value: branchDatabase.envVars.join(", ")
191
+ }] : []];
192
+ }
193
+ function formatEnvVarNames(envVars) {
194
+ return envVars.length > 0 ? envVars.join(", ") : "none";
195
+ }
48
196
  function renderAppListDeploys(context, descriptor, result) {
49
- return renderList({
197
+ const lines = renderList({
50
198
  title: "Listing deployments for the selected app.",
51
199
  descriptor,
52
200
  parentContext: {
@@ -61,20 +209,23 @@ function renderAppListDeploys(context, descriptor, result) {
61
209
  })),
62
210
  emptyMessage: result.app ? "No deployments found." : "No apps found."
63
211
  }, context.ui);
212
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
213
+ return lines;
64
214
  }
65
215
  function serializeAppListDeploys(result) {
66
- if (!result.app) return {
67
- projectId: result.projectId,
216
+ const { verboseContext: _verboseContext, ...serializable } = result;
217
+ if (!serializable.app) return {
218
+ projectId: serializable.projectId,
68
219
  app: null,
69
220
  items: [],
70
221
  count: 0
71
222
  };
72
223
  return {
73
- projectId: result.projectId,
74
- app: result.app,
224
+ projectId: serializable.projectId,
225
+ app: serializable.app,
75
226
  ...serializeList({
76
- context: { app: result.app.name },
77
- items: result.deployments.map((deployment) => ({
227
+ context: { app: serializable.app.name },
228
+ items: serializable.deployments.map((deployment) => ({
78
229
  noun: "deployment",
79
230
  label: deployment.id,
80
231
  id: deployment.id,
@@ -84,7 +235,7 @@ function serializeAppListDeploys(result) {
84
235
  };
85
236
  }
86
237
  function renderAppShow(context, descriptor, result) {
87
- return renderShow({
238
+ const lines = renderShow({
88
239
  title: "Showing the selected app state.",
89
240
  descriptor,
90
241
  fields: [
@@ -114,9 +265,11 @@ function renderAppShow(context, descriptor, result) {
114
265
  }
115
266
  ]
116
267
  }, context.ui);
268
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
269
+ return lines;
117
270
  }
118
271
  function serializeAppShow(result) {
119
- return result;
272
+ return stripVerboseContext(result);
120
273
  }
121
274
  function renderAppShowDeploy(context, descriptor, result) {
122
275
  return renderShow({
@@ -158,7 +311,7 @@ function serializeAppShowDeploy(result) {
158
311
  return result;
159
312
  }
160
313
  function renderAppOpen(context, descriptor, result) {
161
- return renderShow({
314
+ const lines = renderShow({
162
315
  title: result.opened ? "Opening the live URL for the selected app." : "Resolving the live URL for the selected app.",
163
316
  descriptor,
164
317
  fields: [
@@ -182,9 +335,11 @@ function renderAppOpen(context, descriptor, result) {
182
335
  }
183
336
  ]
184
337
  }, context.ui);
338
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
339
+ return lines;
185
340
  }
186
341
  function serializeAppOpen(result) {
187
- return result;
342
+ return stripVerboseContext(result);
188
343
  }
189
344
  function renderAppDomainAdd(context, descriptor, result) {
190
345
  return renderShow({
@@ -286,7 +441,7 @@ function serializeAppDomainRetry(result) {
286
441
  return result;
287
442
  }
288
443
  function renderAppPromote(context, descriptor, result) {
289
- return renderShow({
444
+ const lines = renderShow({
290
445
  title: "Switching the live deployment for the selected app.",
291
446
  descriptor,
292
447
  fields: [
@@ -324,12 +479,14 @@ function renderAppPromote(context, descriptor, result) {
324
479
  }
325
480
  ]
326
481
  }, context.ui);
482
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
483
+ return lines;
327
484
  }
328
485
  function serializeAppPromote(result) {
329
- return result;
486
+ return stripVerboseContext(result);
330
487
  }
331
488
  function renderAppRollback(context, descriptor, result) {
332
- return renderShow({
489
+ const lines = renderShow({
333
490
  title: "Restoring the selected app to an earlier deployment.",
334
491
  descriptor,
335
492
  fields: [
@@ -372,9 +529,11 @@ function renderAppRollback(context, descriptor, result) {
372
529
  }] : []
373
530
  ]
374
531
  }, context.ui);
532
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
533
+ return lines;
375
534
  }
376
535
  function serializeAppRollback(result) {
377
- return result;
536
+ return stripVerboseContext(result);
378
537
  }
379
538
  function renderAppRun(_context, _descriptor, _result) {
380
539
  return [];
@@ -383,7 +542,7 @@ function serializeAppRun(result) {
383
542
  return result;
384
543
  }
385
544
  function renderAppRemove(context, descriptor, result) {
386
- return renderShow({
545
+ const lines = renderShow({
387
546
  title: "Removing the selected app.",
388
547
  descriptor,
389
548
  fields: [
@@ -402,9 +561,11 @@ function renderAppRemove(context, descriptor, result) {
402
561
  }
403
562
  ]
404
563
  }, context.ui);
564
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
565
+ return lines;
405
566
  }
406
567
  function serializeAppRemove(result) {
407
- return result;
568
+ return stripVerboseContext(result);
408
569
  }
409
570
  function toneForStatus(status) {
410
571
  if (status === "running" || status === "ready" || status === "healthy") return "success";
@@ -488,4 +649,4 @@ function formatRecentDeployments(deployments) {
488
649
  return deployments.map((deployment) => `${deployment.id}${deployment.live ? " (live)" : ""}`).join(", ");
489
650
  }
490
651
  //#endregion
491
- export { renderAppBuild, renderAppDeploy, renderAppDomainAdd, renderAppDomainRemove, renderAppDomainRetry, renderAppDomainShow, renderAppListDeploys, renderAppOpen, renderAppPromote, renderAppRemove, renderAppRollback, renderAppRun, renderAppShow, renderAppShowDeploy, serializeAppBuild, serializeAppDeploy, serializeAppDomainAdd, serializeAppDomainRemove, serializeAppDomainRetry, serializeAppDomainShow, serializeAppListDeploys, serializeAppOpen, serializeAppPromote, serializeAppRemove, serializeAppRollback, serializeAppRun, serializeAppShow, serializeAppShowDeploy };
652
+ export { isAppDeployAllResult, renderAppBuild, renderAppDeploy, renderAppDeployAll, renderAppDomainAdd, renderAppDomainRemove, renderAppDomainRetry, renderAppDomainShow, renderAppListDeploys, renderAppOpen, renderAppPromote, renderAppRemove, renderAppRollback, renderAppRun, renderAppShow, renderAppShowDeploy, serializeAppBuild, serializeAppDeploy, serializeAppDeployAll, serializeAppDomainAdd, serializeAppDomainRemove, serializeAppDomainRetry, serializeAppDomainShow, serializeAppListDeploys, serializeAppOpen, serializeAppPromote, serializeAppRemove, serializeAppRollback, serializeAppRun, serializeAppShow, serializeAppShowDeploy };
@@ -1,4 +1,7 @@
1
+ import { formatDescriptorLabel } from "../shell/command-meta.js";
2
+ import { padDisplay } from "../shell/ui.js";
1
3
  import { renderMutate, renderShow } from "../output/patterns.js";
4
+ import stringWidth from "string-width";
2
5
  //#region src/presenters/auth.ts
3
6
  function renderAuthSuccess(context, descriptor, command, result) {
4
7
  if (command === "auth.login") {
@@ -22,7 +25,7 @@ function renderAuthSuccess(context, descriptor, command, result) {
22
25
  context: rows,
23
26
  operationDescription: "Applying authentication session changes",
24
27
  operationCount: 1,
25
- details: ["Session stored in local CLI state."]
28
+ details: ["Session stored in local CLI state.", ...result.agentSetupTip ? [`Install Prisma skills for this project with ${result.agentSetupTip.command}.`] : []]
26
29
  }, context.ui);
27
30
  }
28
31
  if (command === "auth.logout") return renderMutate({
@@ -62,11 +65,105 @@ function renderAuthSuccess(context, descriptor, command, result) {
62
65
  }]
63
66
  }, context.ui);
64
67
  }
68
+ function renderAuthWorkspaceList(context, descriptor, result) {
69
+ const ui = context.ui;
70
+ const rail = ui.dim("│");
71
+ const lines = [
72
+ `${ui.strong(formatDescriptorLabel(descriptor))} ${ui.dim("→")} ${ui.dim("Listing authenticated workspaces on this machine.")}`,
73
+ "",
74
+ `${rail} ${ui.accent("auth source:")} ${authSourceLabel(result.authSource)}`
75
+ ];
76
+ const hasMixedSources = new Set(result.workspaces.map((workspace) => workspace.source)).size > 1;
77
+ if (result.workspaces.length === 0) {
78
+ lines.push(`${rail} ${ui.dim("No local OAuth workspaces found.")}`);
79
+ return lines;
80
+ }
81
+ const nameWidth = Math.max(4, ...result.workspaces.map((workspace) => stringWidth(workspace.name)));
82
+ const idWidth = Math.max(2, ...result.workspaces.map((workspace) => stringWidth(workspace.id)));
83
+ const sourceWidth = hasMixedSources ? Math.max(6, ...result.workspaces.map((workspace) => stringWidth(workspaceSourceLabel(workspace.source)))) : 0;
84
+ lines.push(rail);
85
+ lines.push(hasMixedSources ? `${rail} ${ui.accent(padDisplay("name", nameWidth))} ${ui.accent(padDisplay("id", idWidth))} ${ui.accent(padDisplay("source", sourceWidth))} ${ui.accent("status")}` : `${rail} ${ui.accent(padDisplay("name", nameWidth))} ${ui.accent(padDisplay("id", idWidth))} ${ui.accent("status")}`);
86
+ for (const workspace of result.workspaces) {
87
+ const status = workspace.active ? "active" : "";
88
+ const source = workspaceSourceLabel(workspace.source);
89
+ lines.push(hasMixedSources ? `${rail} ${padDisplay(workspace.name, nameWidth)} ${padDisplay(workspace.id, idWidth)} ${padDisplay(source, sourceWidth)} ${status}` : `${rail} ${padDisplay(workspace.name, nameWidth)} ${padDisplay(workspace.id, idWidth)} ${status}`);
90
+ }
91
+ return lines;
92
+ }
93
+ function serializeAuthWorkspaceList(result) {
94
+ return {
95
+ context: {
96
+ authSource: result.authSource,
97
+ activeWorkspaceId: result.activeWorkspace?.id ?? null,
98
+ activeWorkspaceName: result.activeWorkspace?.name ?? null
99
+ },
100
+ items: result.workspaces.map((workspace) => ({
101
+ id: workspace.id,
102
+ name: workspace.name,
103
+ status: workspace.active ? "active" : null,
104
+ source: workspace.source,
105
+ switchable: workspace.switchable,
106
+ credentialWorkspaceId: workspace.credentialWorkspaceId,
107
+ lastSeenAt: workspace.lastSeenAt
108
+ })),
109
+ count: result.workspaces.length
110
+ };
111
+ }
112
+ function renderAuthWorkspaceUse(context, descriptor, result) {
113
+ return renderMutate({
114
+ title: "Switching the local CLI workspace.",
115
+ descriptor,
116
+ context: [...result.previousWorkspace ? [{
117
+ key: "previous",
118
+ value: result.previousWorkspace.name
119
+ }] : [], {
120
+ key: "workspace",
121
+ value: result.workspace.name
122
+ }],
123
+ operationDescription: "Applying workspace selection",
124
+ operationCount: 1,
125
+ details: ["Local OAuth workspace selection updated."]
126
+ }, context.ui);
127
+ }
128
+ function serializeAuthWorkspaceUse(result) {
129
+ return result;
130
+ }
131
+ function renderAuthWorkspaceLogout(context, descriptor, result) {
132
+ return renderMutate({
133
+ title: "Removing a local OAuth workspace session.",
134
+ descriptor,
135
+ context: [{
136
+ key: "workspace",
137
+ value: result.workspace.name
138
+ }, ...result.activeWorkspace ? [{
139
+ key: "active",
140
+ value: result.activeWorkspace.name
141
+ }] : [{
142
+ key: "active",
143
+ value: "none",
144
+ tone: "dim"
145
+ }]],
146
+ operationDescription: "Removing workspace session",
147
+ operationCount: 1,
148
+ details: [result.wasActive ? "Removed active workspace session; no replacement workspace was selected." : "Removed workspace session."]
149
+ }, context.ui);
150
+ }
151
+ function serializeAuthWorkspaceLogout(result) {
152
+ return result;
153
+ }
65
154
  function providerLabel(provider) {
66
155
  if (provider === "github") return "GitHub";
67
156
  if (provider === "google") return "Google";
68
157
  return "";
69
158
  }
159
+ function authSourceLabel(source) {
160
+ if (source === "oauth") return "local OAuth";
161
+ if (source === "service_token") return "PRISMA_SERVICE_TOKEN";
162
+ return "none";
163
+ }
164
+ function workspaceSourceLabel(source) {
165
+ return source === "service_token" ? "service token" : "OAuth";
166
+ }
70
167
  function authUserLabel(result) {
71
168
  return result.user?.email ?? credentialUserLabel(result);
72
169
  }
@@ -83,4 +180,4 @@ function credentialUserLabel(result) {
83
180
  return null;
84
181
  }
85
182
  //#endregion
86
- export { renderAuthSuccess };
183
+ export { renderAuthSuccess, renderAuthWorkspaceList, renderAuthWorkspaceLogout, renderAuthWorkspaceUse, serializeAuthWorkspaceList, serializeAuthWorkspaceLogout, serializeAuthWorkspaceUse };