@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
@@ -1,111 +1,46 @@
1
- import { renderList, renderMutate, renderShow, serializeList } from "../output/patterns.js";
1
+ import { formatColumns } from "../shell/ui.js";
2
+ import { formatDescriptorLabel } from "../shell/command-meta.js";
3
+ import { renderResolvedProjectContextBlock } from "./verbose-context.js";
2
4
  //#region src/presenters/branch.ts
3
5
  function renderBranchList(context, descriptor, result) {
4
- return renderList({
5
- title: "Listing branches for the resolved project.",
6
- descriptor,
7
- parentContext: {
8
- key: "project",
9
- value: result.projectName ?? "not resolved"
10
- },
11
- items: result.branches.map((branch) => ({
12
- noun: "branch",
13
- label: branch.name,
14
- id: branch.id,
15
- status: branch.active ? "active" : null
16
- })),
17
- emptyMessage: "No branches found."
18
- }, context.ui);
6
+ const ui = context.ui;
7
+ const lines = [`${ui.strong(formatDescriptorLabel(descriptor))} ${ui.dim("→")} ${ui.dim("Listing branches for the resolved project.")}`, ""];
8
+ const rail = ui.dim("│");
9
+ lines.push(`${rail} ${ui.accent("project:")} ${result.projectName}`);
10
+ lines.push(rail);
11
+ if (result.branches.length === 0) {
12
+ lines.push(`${rail} ${ui.dim("No branches found.")}`);
13
+ lines.push(...renderBranchResolvedContextBlock(context, result));
14
+ return lines;
15
+ }
16
+ const widths = [
17
+ Math.max(4, ...result.branches.map((branch) => branch.name.length)),
18
+ Math.max(4, ...result.branches.map((branch) => branch.role.length)),
19
+ Math.max(7, ...result.branches.map((branch) => branch.envMap.length))
20
+ ];
21
+ lines.push(`${rail} ${ui.accent(formatColumns([
22
+ "Name",
23
+ "Role",
24
+ "Env map"
25
+ ], widths))}`);
26
+ for (const branch of result.branches) lines.push(`${rail} ${formatColumns([
27
+ branch.name,
28
+ branch.role,
29
+ branch.envMap
30
+ ], widths)}`);
31
+ lines.push(...renderBranchResolvedContextBlock(context, result));
32
+ return lines;
19
33
  }
20
34
  function serializeBranchList(result) {
21
- return serializeList({
22
- context: { project: result.projectName ?? "not resolved" },
23
- items: result.branches.map((branch) => ({
24
- noun: "branch",
25
- label: branch.name,
26
- id: branch.id,
27
- status: branch.active ? "active" : null
28
- }))
29
- });
30
- }
31
- function serializeBranchShow(result) {
35
+ const { verboseContext: _verboseContext, ...serializable } = result;
32
36
  return {
33
- projectId: result.projectId,
34
- projectName: result.projectName,
35
- branch: {
36
- name: result.branch.name,
37
- kind: result.branch.kind,
38
- active: result.branch.active,
39
- remoteState: result.branch.remoteState,
40
- liveDeployment: result.branch.liveDeployment
41
- }
37
+ projectId: serializable.projectId,
38
+ projectName: serializable.projectName,
39
+ branches: serializable.branches
42
40
  };
43
41
  }
44
- function renderBranchShow(context, descriptor, result) {
45
- const fields = [
46
- {
47
- key: "project",
48
- value: result.projectName ?? "not resolved",
49
- tone: result.projectName ? "default" : "dim"
50
- },
51
- {
52
- key: "branch",
53
- value: result.branch.name,
54
- tone: result.branch.active ? "success" : "default"
55
- },
56
- {
57
- key: "kind",
58
- value: result.branch.kind
59
- }
60
- ];
61
- if (result.branch.liveDeployment) {
62
- fields.push({
63
- key: "status",
64
- value: result.branch.liveDeployment.status,
65
- tone: toneForDeploymentStatus(result.branch.liveDeployment.status)
66
- });
67
- if (result.branch.liveDeployment.url) fields.push({
68
- key: "url",
69
- value: result.branch.liveDeployment.url,
70
- tone: "link"
71
- });
72
- } else if (!result.branch.remoteState) fields.push({
73
- key: "remote state",
74
- value: "not created yet",
75
- tone: "dim"
76
- });
77
- return renderShow({
78
- title: "Showing the current active branch context.",
79
- descriptor,
80
- fields
81
- }, context.ui);
82
- }
83
- function toneForDeploymentStatus(status) {
84
- if (status === "ready" || status === "active" || status === "healthy") return "success";
85
- if (status === "pending" || status === "building" || status === "starting") return "warning";
86
- if (status === "failed" || status === "error") return "error";
87
- return "default";
88
- }
89
- function renderBranchUse(context, descriptor, result) {
90
- return renderMutate({
91
- title: "Changing the local default branch context.",
92
- descriptor,
93
- context: [{
94
- key: "project",
95
- value: result.projectName ?? "not resolved",
96
- tone: result.projectName ? "default" : "dim"
97
- }, {
98
- key: "branch",
99
- value: result.branch.name
100
- }],
101
- operationDescription: "Applying active branch change",
102
- operationCount: 1,
103
- details: ["Active branch updated in local CLI state for this repo."],
104
- alerts: result.branch.kind === "production" ? [{
105
- tone: "warning",
106
- text: "Production is protected and durable. Use with care"
107
- }] : void 0
108
- }, context.ui);
42
+ function renderBranchResolvedContextBlock(context, result) {
43
+ return renderResolvedProjectContextBlock(context.ui, result.verboseContext);
109
44
  }
110
45
  //#endregion
111
- export { renderBranchList, renderBranchShow, renderBranchUse, serializeBranchList, serializeBranchShow };
46
+ export { renderBranchList, serializeBranchList };
@@ -0,0 +1,274 @@
1
+ import { formatColumns, renderSummaryLine } from "../shell/ui.js";
2
+ import { formatDescriptorLabel } from "../shell/command-meta.js";
3
+ import { renderMutate, renderShow, serializeList } from "../output/patterns.js";
4
+ import { renderResolvedProjectContextBlock, stripVerboseContext } from "./verbose-context.js";
5
+ //#region src/presenters/database.ts
6
+ function renderDatabaseList(context, descriptor, result) {
7
+ const ui = context.ui;
8
+ const lines = [`${ui.strong(formatDescriptorLabel(descriptor))} ${ui.dim("→")} ${ui.dim("Listing databases for the resolved project.")}`, ""];
9
+ const rail = ui.dim("│");
10
+ lines.push(`${rail} ${ui.accent("project:")} ${result.projectName}`);
11
+ if (result.branchName) lines.push(`${rail} ${ui.accent("branch:")} ${result.branchName}`);
12
+ lines.push(rail);
13
+ if (result.databases.length === 0) {
14
+ lines.push(`${rail} ${ui.dim("No databases found.")}`);
15
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
16
+ return lines;
17
+ }
18
+ const rows = result.databases.map((database) => [
19
+ database.name,
20
+ database.branchName ?? "unscoped",
21
+ database.region ?? "unknown",
22
+ formatStatus(database),
23
+ database.id
24
+ ]);
25
+ const widths = [
26
+ Math.max(4, ...rows.map((row) => row[0].length)),
27
+ Math.max(6, ...rows.map((row) => row[1].length)),
28
+ Math.max(6, ...rows.map((row) => row[2].length)),
29
+ Math.max(6, ...rows.map((row) => row[3].length)),
30
+ Math.max(2, ...rows.map((row) => row[4].length))
31
+ ];
32
+ lines.push(`${rail} ${ui.accent(formatColumns([
33
+ "Name",
34
+ "Branch",
35
+ "Region",
36
+ "Status",
37
+ "Id"
38
+ ], widths))}`);
39
+ for (const row of rows) lines.push(`${rail} ${formatColumns(row, widths)}`);
40
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
41
+ return lines;
42
+ }
43
+ function serializeDatabaseList(result) {
44
+ return {
45
+ ...serializeList({
46
+ context: {
47
+ project: result.projectName,
48
+ ...result.branchName ? { branch: result.branchName } : {}
49
+ },
50
+ items: result.databases.map((database) => ({
51
+ noun: "database",
52
+ label: database.name,
53
+ id: database.id,
54
+ status: database.isDefault ? "default" : null
55
+ }))
56
+ }),
57
+ projectId: result.projectId,
58
+ branchName: result.branchName,
59
+ databases: result.databases
60
+ };
61
+ }
62
+ function renderDatabaseShow(context, descriptor, result) {
63
+ const lines = renderShow({
64
+ title: "Showing database metadata.",
65
+ descriptor,
66
+ fields: [
67
+ {
68
+ key: "project",
69
+ value: result.projectName
70
+ },
71
+ {
72
+ key: "database",
73
+ value: result.database.name
74
+ },
75
+ {
76
+ key: "id",
77
+ value: result.database.id,
78
+ tone: "dim"
79
+ },
80
+ {
81
+ key: "branch",
82
+ value: result.database.branchName ?? "unscoped",
83
+ tone: result.database.branchName ? "default" : "dim"
84
+ },
85
+ {
86
+ key: "region",
87
+ value: result.database.region ?? "unknown",
88
+ tone: result.database.region ? "default" : "dim"
89
+ },
90
+ {
91
+ key: "status",
92
+ value: formatStatus(result.database)
93
+ },
94
+ {
95
+ key: "connections",
96
+ value: String(result.connections.length)
97
+ }
98
+ ]
99
+ }, context.ui);
100
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
101
+ return lines;
102
+ }
103
+ function serializeDatabaseShow(result) {
104
+ return stripVerboseContext(result);
105
+ }
106
+ function renderDatabaseCreateStdout(_context, _descriptor, result) {
107
+ return [result.connectionString];
108
+ }
109
+ function renderDatabaseCreate(context, _descriptor, result) {
110
+ const ui = context.ui;
111
+ const lines = [
112
+ "Creating database...",
113
+ renderSummaryLine(ui, "success", `Created database "${result.database.name}" in ${formatDatabaseTarget(result.projectName, result.database.branchName)}.`),
114
+ " The connection URL below is shown once, so save it now."
115
+ ];
116
+ if (ui.verbose) {
117
+ lines.push("");
118
+ lines.push(...renderDatabaseCreateVerboseRows(context, result));
119
+ }
120
+ return lines;
121
+ }
122
+ function serializeDatabaseCreate(result) {
123
+ return stripVerboseContext(result);
124
+ }
125
+ function renderDatabaseRemove(context, descriptor, result) {
126
+ const lines = renderMutate({
127
+ title: "Removing database.",
128
+ descriptor,
129
+ context: [
130
+ {
131
+ key: "project",
132
+ value: result.projectName
133
+ },
134
+ {
135
+ key: "database",
136
+ value: result.database.name
137
+ },
138
+ {
139
+ key: "id",
140
+ value: result.database.id,
141
+ tone: "dim"
142
+ }
143
+ ],
144
+ operationDescription: "Removing database",
145
+ operationCount: 1,
146
+ details: ["Database and its connection metadata were removed."]
147
+ }, context.ui);
148
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
149
+ return lines;
150
+ }
151
+ function serializeDatabaseRemove(result) {
152
+ return stripVerboseContext(result);
153
+ }
154
+ function renderDatabaseConnectionList(context, descriptor, result) {
155
+ const ui = context.ui;
156
+ const lines = [`${ui.strong(formatDescriptorLabel(descriptor))} ${ui.dim("→")} ${ui.dim("Listing database connection metadata.")}`, ""];
157
+ const rail = ui.dim("│");
158
+ lines.push(`${rail} ${ui.accent("database:")} ${result.database.name}`);
159
+ lines.push(rail);
160
+ if (result.connections.length === 0) {
161
+ lines.push(`${rail} ${ui.dim("No database connections found.")}`);
162
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
163
+ return lines;
164
+ }
165
+ const rows = result.connections.map((connection) => [
166
+ connection.name,
167
+ connection.id,
168
+ connection.createdAt ?? "unknown"
169
+ ]);
170
+ const widths = [
171
+ Math.max(4, ...rows.map((row) => row[0].length)),
172
+ Math.max(2, ...rows.map((row) => row[1].length)),
173
+ Math.max(7, ...rows.map((row) => row[2].length))
174
+ ];
175
+ lines.push(`${rail} ${ui.accent(formatColumns([
176
+ "Name",
177
+ "Id",
178
+ "Created"
179
+ ], widths))}`);
180
+ for (const row of rows) lines.push(`${rail} ${formatColumns(row, widths)}`);
181
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
182
+ return lines;
183
+ }
184
+ function serializeDatabaseConnectionList(result) {
185
+ return {
186
+ ...serializeList({
187
+ context: {
188
+ project: result.projectName,
189
+ database: result.database.name
190
+ },
191
+ items: result.connections.map((connection) => ({
192
+ noun: "connection",
193
+ label: connection.name,
194
+ id: connection.id,
195
+ status: null
196
+ }))
197
+ }),
198
+ projectId: result.projectId,
199
+ database: result.database,
200
+ connections: result.connections
201
+ };
202
+ }
203
+ function renderDatabaseConnectionCreateStdout(_context, _descriptor, result) {
204
+ return [result.connectionString];
205
+ }
206
+ function renderDatabaseConnectionCreate(context, _descriptor, result) {
207
+ const ui = context.ui;
208
+ const lines = [
209
+ "Creating connection...",
210
+ renderSummaryLine(ui, "success", `Added a connection to "${result.database.name}" in ${formatDatabaseTarget(result.projectName, result.database.branchName)}.`),
211
+ " The connection URL below is shown once, so save it now."
212
+ ];
213
+ if (ui.verbose) {
214
+ lines.push("");
215
+ lines.push(...renderDatabaseConnectionCreateVerboseRows(context, result));
216
+ }
217
+ return lines;
218
+ }
219
+ function serializeDatabaseConnectionCreate(result) {
220
+ return stripVerboseContext(result);
221
+ }
222
+ function renderDatabaseConnectionRemove(context, descriptor, result) {
223
+ return renderMutate({
224
+ title: "Removing database connection.",
225
+ descriptor,
226
+ context: [{
227
+ key: "connection",
228
+ value: result.connection.id,
229
+ tone: "dim"
230
+ }],
231
+ operationDescription: "Removing database connection",
232
+ operationCount: 1,
233
+ details: ["The connection metadata was removed. Existing one-time secrets were not shown."]
234
+ }, context.ui);
235
+ }
236
+ function serializeDatabaseConnectionRemove(result) {
237
+ return result;
238
+ }
239
+ function formatStatus(database) {
240
+ return database.status ?? (database.isDefault ? "default" : "unknown");
241
+ }
242
+ function formatDatabaseTarget(projectName, branchName) {
243
+ return branchName ? `${projectName} / ${branchName}` : projectName;
244
+ }
245
+ function renderDatabaseCreateVerboseRows(context, result) {
246
+ return renderMetadataRows([
247
+ ...renderWorkspaceProjectRows(result),
248
+ ["branch", result.database.branchName ?? "unscoped"],
249
+ ["database", formatResourceWithId(context, result.database.name, result.database.id)],
250
+ ["region", result.database.region ?? "unknown"],
251
+ ["status", formatStatus(result.database)],
252
+ ["connection", formatResourceWithId(context, result.connection.name, result.connection.id)]
253
+ ]);
254
+ }
255
+ function renderDatabaseConnectionCreateVerboseRows(context, result) {
256
+ return renderMetadataRows([
257
+ ...renderWorkspaceProjectRows(result),
258
+ ["branch", result.database.branchName ?? "unscoped"],
259
+ ["database", formatResourceWithId(context, result.database.name, result.database.id)],
260
+ ["connection", formatResourceWithId(context, result.connection.name, result.connection.id)]
261
+ ]);
262
+ }
263
+ function renderWorkspaceProjectRows(result) {
264
+ return [...result.verboseContext ? [["workspace", result.verboseContext.workspace.name]] : [], ["project", result.projectName]];
265
+ }
266
+ function formatResourceWithId(context, name, id) {
267
+ return `${name} ${context.ui.dim(`(${id})`)}`;
268
+ }
269
+ function renderMetadataRows(rows) {
270
+ const widths = [Math.max(...rows.map((row) => row[0].length)), 0];
271
+ return rows.map(([key, value]) => ` ${formatColumns([key, value], widths)}`);
272
+ }
273
+ //#endregion
274
+ export { renderDatabaseConnectionCreate, renderDatabaseConnectionCreateStdout, renderDatabaseConnectionList, renderDatabaseConnectionRemove, renderDatabaseCreate, renderDatabaseCreateStdout, renderDatabaseList, renderDatabaseRemove, renderDatabaseShow, serializeDatabaseConnectionCreate, serializeDatabaseConnectionList, serializeDatabaseConnectionRemove, serializeDatabaseCreate, serializeDatabaseList, serializeDatabaseRemove, serializeDatabaseShow };
@@ -1,56 +1,91 @@
1
- import { renderList, renderMutate, renderShow, serializeList } from "../output/patterns.js";
1
+ import { padDisplay, renderNextSteps, renderSummaryLine, renderVerboseBlock } from "../shell/ui.js";
2
+ import { formatDescriptorLabel } from "../shell/command-meta.js";
3
+ import { formatCommandArgument } from "../shell/command-arguments.js";
4
+ import { renderMutate, renderShow, serializeList } from "../output/patterns.js";
5
+ import { renderResolvedProjectContextBlock } from "./verbose-context.js";
6
+ import path from "node:path";
7
+ import stringWidth from "string-width";
2
8
  //#region src/presenters/project.ts
3
9
  function renderProjectList(context, descriptor, result) {
4
- return renderList({
5
- title: "Listing projects for the authenticated workspace.",
6
- descriptor,
7
- parentContext: {
8
- key: "workspace",
9
- value: result.workspace.name
10
- },
11
- items: result.projects.map((project) => ({
12
- noun: "project",
13
- label: project.name,
14
- id: project.id,
15
- status: null
16
- })),
17
- emptyMessage: "No projects found."
18
- }, context.ui);
10
+ const ui = context.ui;
11
+ const rail = ui.dim("│");
12
+ const lines = [`${ui.strong(formatDescriptorLabel(descriptor))} ${ui.dim("→")} ${ui.dim("Listing projects for the authenticated workspace.")}`, ""];
13
+ lines.push(`${rail} ${ui.accent("workspace:")} ${result.workspace.name}`);
14
+ if (result.projects.length === 0) {
15
+ lines.push(`${rail} ${ui.dim("No projects found.")}`);
16
+ if (result.localBinding?.status === "not-linked" || result.localBinding?.status === "invalid") lines.push(...renderNextSteps(["Link an existing Project you choose: prisma-cli project link <id-or-name>", "Create a new Project: prisma-cli project create <name>"]));
17
+ return lines;
18
+ }
19
+ const nameWidth = Math.max(4, ...result.projects.map((project) => stringWidth(project.name)));
20
+ lines.push(rail);
21
+ lines.push(`${rail} ${ui.accent(padDisplay("name", nameWidth))} ${ui.accent("id")}`);
22
+ for (const project of result.projects) lines.push(`${rail} ${padDisplay(project.name, nameWidth)} ${project.id}`);
23
+ if (result.localBinding?.status === "not-linked" || result.localBinding?.status === "invalid") lines.push(...renderNextSteps(["Link an existing Project you choose: prisma-cli project link <id-or-name>", "Create a new Project: prisma-cli project create <name>"]));
24
+ return lines;
19
25
  }
20
26
  function serializeProjectList(result) {
21
- return serializeList({
22
- context: { workspace: result.workspace.name },
23
- items: result.projects.map((project) => ({
24
- noun: "project",
25
- label: project.name,
26
- id: project.id,
27
- status: null
28
- }))
29
- });
27
+ return {
28
+ ...serializeList({
29
+ context: { workspace: result.workspace.name },
30
+ items: result.projects.map((project) => ({
31
+ noun: "project",
32
+ label: project.name,
33
+ id: project.id,
34
+ status: null
35
+ }))
36
+ }),
37
+ localBinding: result.localBinding ?? null
38
+ };
30
39
  }
31
40
  function renderProjectShow(context, descriptor, result) {
32
- return renderShow({
33
- title: "Showing the project Prisma resolves for this directory.",
34
- descriptor,
35
- fields: [
41
+ if (result.project === null) {
42
+ const lines = renderShow({
43
+ title: "This directory is not linked to a Prisma Project.",
44
+ descriptor,
45
+ fields: [{
46
+ key: "workspace",
47
+ value: result.workspace.name
48
+ }, {
49
+ key: "project",
50
+ value: "Not linked",
51
+ tone: "warning"
52
+ }]
53
+ }, context.ui);
54
+ lines.push(...renderVerboseBlock(context.ui, [
36
55
  {
37
56
  key: "workspace",
38
57
  value: result.workspace.name
39
58
  },
40
59
  {
41
- key: "project",
42
- value: result.project.name
60
+ key: "workspace id",
61
+ value: result.workspace.id,
62
+ tone: "dim"
43
63
  },
44
64
  {
45
- key: "resolution",
46
- value: formatProjectSource(result.resolution.projectSource)
65
+ key: "project source",
66
+ value: "unbound"
67
+ },
68
+ {
69
+ key: "suggested name",
70
+ value: `${result.suggestedProjectName} (${result.suggestedProjectNameSource})`
47
71
  }
48
- ]
49
- }, context.ui);
72
+ ], { title: "Resolved context" }));
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)}`]));
74
+ return lines;
75
+ }
76
+ return renderBoundProjectShow(context, descriptor, result);
50
77
  }
51
78
  function serializeProjectShow(result) {
52
79
  return result;
53
80
  }
81
+ function renderProjectSetup(context, _descriptor, result) {
82
+ const lines = result.action === "created" ? [renderSummaryLine(context.ui, "success", `Created Project "${result.project.name}"`)] : [];
83
+ lines.push(renderSummaryLine(context.ui, "success", `Linked "${result.directory}" to Project "${result.project.name}"`), `Saved ${result.localPin.path}`);
84
+ return lines;
85
+ }
86
+ function serializeProjectSetup(result) {
87
+ return result;
88
+ }
54
89
  function renderGitConnect(context, descriptor, result) {
55
90
  const connection = result.repositoryConnection;
56
91
  return renderMutate({
@@ -102,18 +137,36 @@ function renderGitDisconnect(context, descriptor, result) {
102
137
  details: ["GitHub branch automation is no longer active for this project."]
103
138
  }, context.ui);
104
139
  }
105
- function formatProjectSource(source) {
106
- switch (source) {
107
- case "explicit": return "explicit";
108
- case "env": return "environment";
109
- case "local-pin": return "local pin";
110
- case "platform-mapping": return "platform mapping";
111
- case "remembered-local": return "remembered local context";
112
- case "package-name": return "package name";
113
- case "directory-name": return "directory name";
114
- case "created": return "created";
115
- case "prompt": return "prompt";
140
+ function renderBoundProjectShow(context, descriptor, result) {
141
+ const { ui } = context;
142
+ const rail = ui.dim("");
143
+ const keyWidth = 10;
144
+ const platform = `${result.workspace.name} / ${result.project.name}`;
145
+ const lines = [
146
+ `${ui.strong(formatDescriptorLabel(descriptor))} ${ui.dim("")} ${ui.dim("This directory is linked to the following platform project.")}`,
147
+ "",
148
+ `${rail} ${ui.accent(padDisplay("local repo", keyWidth))} ${formatLocalRepoPath(context.runtime.cwd, context.runtime.env)}`,
149
+ `${rail} ${ui.accent(padDisplay("platform", keyWidth))} ${ui.strong(platform)}`
150
+ ];
151
+ if (result.project.url) {
152
+ lines.push(rail);
153
+ lines.push(`${rail} ${ui.dim("→")} ${ui.link(result.project.url)}`);
154
+ }
155
+ lines.push(...renderResolvedProjectContextBlock(context.ui, {
156
+ workspace: result.workspace,
157
+ project: result.project,
158
+ resolution: result.resolution
159
+ }));
160
+ return lines;
161
+ }
162
+ function formatLocalRepoPath(cwd, env) {
163
+ const resolved = path.resolve(cwd);
164
+ const home = env.HOME ? path.resolve(env.HOME) : null;
165
+ if (home && (resolved === home || resolved.startsWith(`${home}${path.sep}`))) {
166
+ const relative = path.relative(home, resolved);
167
+ return relative ? `~/${relative}` : "~";
116
168
  }
169
+ return resolved;
117
170
  }
118
171
  function formatGitConnectionDetail(status) {
119
172
  switch (status) {
@@ -124,4 +177,4 @@ function formatGitConnectionDetail(status) {
124
177
  }
125
178
  }
126
179
  //#endregion
127
- export { renderGitConnect, renderGitDisconnect, renderProjectList, renderProjectShow, serializeProjectList, serializeProjectShow };
180
+ export { renderGitConnect, renderGitDisconnect, renderProjectList, renderProjectSetup, renderProjectShow, serializeProjectList, serializeProjectSetup, serializeProjectShow };
@@ -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 };
@@ -0,0 +1,6 @@
1
+ //#region src/shell/command-arguments.ts
2
+ function formatCommandArgument(value) {
3
+ return /^[A-Za-z0-9._/-]+$/.test(value) && !value.startsWith("-") ? value : `'${value.replace(/'/g, "'\\''")}'`;
4
+ }
5
+ //#endregion
6
+ export { formatCommandArgument };