@prisma/cli 3.0.0-beta.3 → 3.0.0-beta.30

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 (99) hide show
  1. package/README.md +6 -15
  2. package/dist/adapters/local-state.js +15 -4
  3. package/dist/adapters/mock-api.js +244 -0
  4. package/dist/adapters/token-storage.js +335 -34
  5. package/dist/cli.js +7 -7
  6. package/dist/cli2.js +24 -5
  7. package/dist/commands/agent/index.js +60 -0
  8. package/dist/commands/app/index.js +91 -61
  9. package/dist/commands/auth/index.js +55 -2
  10. package/dist/commands/branch/index.js +2 -27
  11. package/dist/commands/bucket/index.js +123 -0
  12. package/dist/commands/build/index.js +29 -0
  13. package/dist/commands/database/index.js +249 -0
  14. package/dist/commands/env.js +8 -4
  15. package/dist/commands/feedback/index.js +20 -0
  16. package/dist/commands/git/index.js +1 -1
  17. package/dist/commands/init/index.js +33 -0
  18. package/dist/commands/project/index.js +54 -5
  19. package/dist/controllers/agent-setup.js +52 -0
  20. package/dist/controllers/agent.js +228 -0
  21. package/dist/controllers/app-env-api.js +55 -0
  22. package/dist/controllers/app-env-file.js +181 -0
  23. package/dist/controllers/app-env.js +227 -104
  24. package/dist/controllers/app.js +746 -306
  25. package/dist/controllers/auth.js +247 -3
  26. package/dist/controllers/branch.js +78 -48
  27. package/dist/controllers/bucket.js +278 -0
  28. package/dist/controllers/build.js +88 -0
  29. package/dist/controllers/database.js +567 -0
  30. package/dist/controllers/feedback.js +86 -0
  31. package/dist/controllers/init.js +753 -0
  32. package/dist/controllers/project.js +377 -22
  33. package/dist/controllers/select-prompt-port.js +1 -0
  34. package/dist/lib/agent/cli-command.js +20 -0
  35. package/dist/lib/agent/constants.js +12 -0
  36. package/dist/lib/agent/package-manager.js +99 -0
  37. package/dist/lib/agent/setup-status.js +83 -0
  38. package/dist/lib/app/{preview-provider.js → app-provider.js} +137 -88
  39. package/dist/lib/app/branch-database-api.js +102 -0
  40. package/dist/lib/app/branch-database-deploy.js +326 -0
  41. package/dist/lib/app/branch-database.js +216 -0
  42. package/dist/lib/app/build-settings.js +93 -0
  43. package/dist/lib/app/build.js +83 -0
  44. package/dist/lib/app/bun-project.js +3 -4
  45. package/dist/lib/app/compute-config.js +145 -0
  46. package/dist/lib/app/deploy-plan.js +59 -0
  47. package/dist/lib/app/{preview-progress.js → deploy-progress.js} +12 -12
  48. package/dist/lib/app/env-config.js +1 -1
  49. package/dist/lib/app/env-file.js +82 -0
  50. package/dist/lib/app/env-vars.js +28 -2
  51. package/dist/lib/app/local-dev.js +3 -60
  52. package/dist/lib/app/production-deploy-gate.js +162 -0
  53. package/dist/lib/app/read-branch.js +30 -0
  54. package/dist/lib/auth/auth-ops.js +10 -4
  55. package/dist/lib/auth/guard.js +4 -1
  56. package/dist/lib/auth/login.js +33 -26
  57. package/dist/lib/auth/recipient.js +42 -0
  58. package/dist/lib/bucket/provider.js +139 -0
  59. package/dist/lib/database/provider.js +378 -0
  60. package/dist/lib/diagnostics.js +15 -0
  61. package/dist/lib/fs/home-path.js +24 -0
  62. package/dist/lib/git/local-branch.js +53 -0
  63. package/dist/lib/git/local-status.js +57 -0
  64. package/dist/lib/project/interactive-setup.js +5 -4
  65. package/dist/lib/project/local-pin.js +171 -41
  66. package/dist/lib/project/provider.js +92 -0
  67. package/dist/lib/project/resolution.js +199 -48
  68. package/dist/lib/project/setup.js +67 -20
  69. package/dist/output/patterns.js +1 -1
  70. package/dist/presenters/agent.js +74 -0
  71. package/dist/presenters/app-env.js +149 -14
  72. package/dist/presenters/app.js +208 -27
  73. package/dist/presenters/auth.js +99 -2
  74. package/dist/presenters/branch.js +37 -102
  75. package/dist/presenters/bucket.js +174 -0
  76. package/dist/presenters/database.js +448 -0
  77. package/dist/presenters/feedback.js +26 -0
  78. package/dist/presenters/init.js +30 -0
  79. package/dist/presenters/project.js +139 -27
  80. package/dist/presenters/verbose-context.js +64 -0
  81. package/dist/shell/cli-command.js +12 -0
  82. package/dist/shell/command-arguments.js +7 -1
  83. package/dist/shell/command-meta.js +458 -17
  84. package/dist/shell/command-runner.js +58 -18
  85. package/dist/shell/diagnostics-output.js +57 -0
  86. package/dist/shell/errors.js +56 -1
  87. package/dist/shell/help.js +31 -20
  88. package/dist/shell/output.js +72 -1
  89. package/dist/shell/prompt.js +12 -5
  90. package/dist/shell/runtime.js +8 -4
  91. package/dist/shell/ui.js +42 -3
  92. package/dist/shell/update-check.js +2 -2
  93. package/dist/use-cases/auth.js +68 -1
  94. package/dist/use-cases/branch.js +20 -68
  95. package/dist/use-cases/create-cli-gateways.js +2 -17
  96. package/dist/use-cases/project.js +2 -1
  97. package/package.json +21 -4
  98. package/dist/lib/app/preview-build.js +0 -312
  99. package/dist/lib/app/preview-interaction.js +0 -5
package/README.md CHANGED
@@ -57,6 +57,8 @@ Useful next commands:
57
57
  npx prisma-cli app logs
58
58
  npx prisma-cli app open
59
59
  npx prisma-cli project env add DATABASE_URL=postgresql://example --role preview
60
+ npx prisma-cli project env add --file .env --role preview
61
+ npx prisma-cli project env list
60
62
  npx prisma-cli project env list --role preview
61
63
  ```
62
64
 
@@ -73,7 +75,9 @@ The beta package exposes `prisma-cli` so it can coexist with the existing
73
75
  | `auth` | Log in, log out, and inspect the active Prisma account. |
74
76
  | `project` | List projects, show the resolved project, and manage project environment variables. |
75
77
  | `git` | Connect or disconnect a project from a GitHub repository. |
76
- | `branch` | Inspect the Prisma branch that maps to the current work context. |
78
+ | `branch` | List Prisma branches for the resolved project. |
79
+ | `database` | Create, inspect, and remove Prisma Postgres databases and their connection strings. |
80
+ | `bucket` | Create, list, and delete Tigris object-store buckets and their access keys. |
77
81
  | `app` | Build, run, deploy, inspect, open, stream logs, promote, roll back, and remove apps. |
78
82
 
79
83
  Common examples:
@@ -82,7 +86,7 @@ Common examples:
82
86
  npx prisma-cli version
83
87
  npx prisma-cli auth whoami
84
88
  npx prisma-cli project show
85
- npx prisma-cli branch show
89
+ npx prisma-cli branch list
86
90
  npx prisma-cli app deploy --branch feat-login --framework nextjs
87
91
  npx prisma-cli app promote <deployment-id>
88
92
  ```
@@ -96,19 +100,6 @@ npx prisma-cli app promote <deployment-id>
96
100
  - Stable command groups, flags, and error codes for scripts and agents.
97
101
  - Environment variable values are not printed back to the terminal.
98
102
 
99
- ### Agent skills
100
-
101
- For agent-guided Next.js deploys, install the Prisma CLI skill cluster at the
102
- project level. Match the skill ref to the installed CLI version:
103
-
104
- ```bash
105
- npx prisma-cli version
106
- pnpm dlx skills@latest add prisma/prisma-cli/skills#cli-v<cli-version> --all
107
- ```
108
-
109
- The skills teach agents how to prepare a Next.js app, run `app deploy`, verify
110
- the result, and route CLI / Compute feedback to the right Prisma channel.
111
-
112
103
  ---
113
104
 
114
105
  ## Beta notes
@@ -1,5 +1,5 @@
1
- import { mkdir, readFile, writeFile } from "node:fs/promises";
2
1
  import path from "node:path";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
3
  //#region src/adapters/local-state.ts
4
4
  const DEFAULT_STATE = {
5
5
  auth: null,
@@ -12,7 +12,8 @@ const DEFAULT_STATE = {
12
12
  app: {
13
13
  selectedByProject: {},
14
14
  knownLiveDeploymentByProject: {}
15
- }
15
+ },
16
+ agent: { setupPromptDismissedAt: null }
16
17
  };
17
18
  const DEFAULT_STATE_FILE_NAME = "state.json";
18
19
  function resolveLocalStateFilePath(stateDir) {
@@ -43,7 +44,8 @@ var LocalStateStore = class {
43
44
  app: {
44
45
  selectedByProject: parsed.app?.selectedByProject ?? {},
45
46
  knownLiveDeploymentByProject: parsed.app?.knownLiveDeploymentByProject ?? {}
46
- }
47
+ },
48
+ agent: { setupPromptDismissedAt: parsed.agent?.setupPromptDismissedAt ?? null }
47
49
  };
48
50
  } catch (error) {
49
51
  if (error.code === "ENOENT") return structuredClone(DEFAULT_STATE);
@@ -139,6 +141,15 @@ var LocalStateStore = class {
139
141
  await this.write(state);
140
142
  return state;
141
143
  }
144
+ async readAgentSetupPromptDismissedAt() {
145
+ return (await this.read()).agent.setupPromptDismissedAt;
146
+ }
147
+ async setAgentSetupPromptDismissedAt(dismissedAt) {
148
+ const state = await this.read();
149
+ state.agent.setupPromptDismissedAt = dismissedAt;
150
+ await this.write(state);
151
+ return state;
152
+ }
142
153
  };
143
154
  //#endregion
144
- export { LocalStateStore };
155
+ export { LocalStateStore, resolveLocalStateFilePath };
@@ -32,6 +32,9 @@ var MockApi = class MockApi {
32
32
  const workspaceIds = this.data.memberships.filter((membership) => membership.userId === userId).map((membership) => membership.workspaceId);
33
33
  return this.data.workspaces.filter((workspace) => workspaceIds.includes(workspace.id));
34
34
  }
35
+ listWorkspaces() {
36
+ return this.data.workspaces;
37
+ }
35
38
  getWorkspace(workspaceId) {
36
39
  return this.data.workspaces.find((workspace) => workspace.id === workspaceId);
37
40
  }
@@ -47,6 +50,36 @@ var MockApi = class MockApi {
47
50
  getProjectForWorkspace(workspaceId, projectId) {
48
51
  return this.listProjectsForWorkspace(workspaceId).find((project) => project.id === projectId);
49
52
  }
53
+ renameProject(projectId, name) {
54
+ const project = this.getProject(projectId);
55
+ if (!project) return;
56
+ project.name = name;
57
+ return project;
58
+ }
59
+ removeProject(projectId) {
60
+ const project = this.getProject(projectId);
61
+ if (!project) return { outcome: "not-found" };
62
+ if (this.data.deployments.some((deployment) => deployment.projectId === projectId)) return { outcome: "blocked" };
63
+ const removedDatabaseIds = new Set((this.data.databases ?? []).filter((database) => database.projectId === projectId).map((database) => database.id));
64
+ this.data.projects = this.data.projects.filter((candidate) => candidate.id !== projectId);
65
+ this.data.branches = this.data.branches.filter((branch) => branch.projectId !== projectId);
66
+ this.data.databases = (this.data.databases ?? []).filter((database) => database.projectId !== projectId);
67
+ this.data.databaseConnections = (this.data.databaseConnections ?? []).filter((connection) => !removedDatabaseIds.has(connection.databaseId));
68
+ return {
69
+ outcome: "removed",
70
+ project
71
+ };
72
+ }
73
+ transferProject(projectId, targetWorkspaceId) {
74
+ const project = this.getProject(projectId);
75
+ if (!project) return { outcome: "not-found" };
76
+ if (!this.getWorkspace(targetWorkspaceId)) return { outcome: "workspace-not-found" };
77
+ project.workspaceId = targetWorkspaceId;
78
+ return {
79
+ outcome: "transferred",
80
+ project
81
+ };
82
+ }
50
83
  listBranchesForProject(projectId) {
51
84
  return this.data.branches.filter((branch) => branch.projectId === projectId);
52
85
  }
@@ -56,6 +89,217 @@ var MockApi = class MockApi {
56
89
  getDeployment(deploymentId) {
57
90
  return this.data.deployments.find((deployment) => deployment.id === deploymentId);
58
91
  }
92
+ listDatabasesForProject(projectId, branchName) {
93
+ return (this.data.databases ?? []).filter((database) => database.projectId === projectId && (!branchName || database.branchName === branchName));
94
+ }
95
+ getDatabase(databaseId) {
96
+ return (this.data.databases ?? []).find((database) => database.id === databaseId);
97
+ }
98
+ createDatabase(input) {
99
+ this.data.databases ??= [];
100
+ this.data.databaseConnections ??= [];
101
+ const database = {
102
+ id: `db_${this.data.databases.length + 1e3}`,
103
+ projectId: input.projectId,
104
+ branchId: input.branchName ? this.getBranchForProject(input.projectId, input.branchName)?.id ?? null : null,
105
+ branchName: input.branchName ?? null,
106
+ name: input.name,
107
+ region: input.region ?? null,
108
+ status: "ready",
109
+ isDefault: false,
110
+ createdAt: "2026-06-09T00:00:00.000Z"
111
+ };
112
+ const connectionString = `postgresql://${database.id}.example.prisma.io/postgres`;
113
+ const connection = {
114
+ id: `conn_${this.data.databaseConnections.length + 1e3}`,
115
+ databaseId: database.id,
116
+ name: "primary",
117
+ createdAt: "2026-06-09T00:00:00.000Z",
118
+ connectionString
119
+ };
120
+ this.data.databases.push(database);
121
+ this.data.databaseConnections.push(connection);
122
+ return {
123
+ database,
124
+ connection,
125
+ connectionString
126
+ };
127
+ }
128
+ removeDatabase(databaseId) {
129
+ this.data.databases ??= [];
130
+ this.data.databaseConnections ??= [];
131
+ const database = this.getDatabase(databaseId);
132
+ if (!database) return;
133
+ this.data.databases = this.data.databases.filter((candidate) => candidate.id !== databaseId);
134
+ this.data.databaseConnections = this.data.databaseConnections.filter((connection) => connection.databaseId !== databaseId);
135
+ return database;
136
+ }
137
+ listDatabaseConnections(databaseId) {
138
+ return (this.data.databaseConnections ?? []).filter((connection) => connection.databaseId === databaseId);
139
+ }
140
+ getDatabaseConnection(connectionId) {
141
+ return (this.data.databaseConnections ?? []).find((connection) => connection.id === connectionId);
142
+ }
143
+ createDatabaseConnection(input) {
144
+ if (!this.getDatabase(input.databaseId)) return;
145
+ this.data.databaseConnections ??= [];
146
+ const connectionString = `postgresql://${input.databaseId}-${this.data.databaseConnections.length + 1}.example.prisma.io/postgres`;
147
+ const connection = {
148
+ id: `conn_${this.data.databaseConnections.length + 1e3}`,
149
+ databaseId: input.databaseId,
150
+ name: input.name,
151
+ createdAt: "2026-06-09T00:00:00.000Z",
152
+ connectionString
153
+ };
154
+ this.data.databaseConnections.push(connection);
155
+ return {
156
+ connection,
157
+ connectionString
158
+ };
159
+ }
160
+ removeDatabaseConnection(connectionId) {
161
+ this.data.databaseConnections ??= [];
162
+ const connection = this.getDatabaseConnection(connectionId);
163
+ if (!connection) return;
164
+ this.data.databaseConnections = this.data.databaseConnections.filter((candidate) => candidate.id !== connectionId);
165
+ return connection;
166
+ }
167
+ getDatabaseUsage(databaseId, period) {
168
+ const defaults = (this.data.databaseUsage ?? []).find((record) => record.databaseId === databaseId) ?? {
169
+ databaseId,
170
+ period: {
171
+ start: "2026-06-01T00:00:00.000Z",
172
+ end: "2026-06-30T23:59:59.999Z"
173
+ },
174
+ metrics: {
175
+ operations: {
176
+ used: 0,
177
+ unit: "ops"
178
+ },
179
+ storage: {
180
+ used: 0,
181
+ unit: "GiB"
182
+ }
183
+ },
184
+ generatedAt: "2026-07-01T00:00:00.000Z"
185
+ };
186
+ return {
187
+ period: {
188
+ start: period?.from ?? defaults.period.start,
189
+ end: period?.to ?? defaults.period.end
190
+ },
191
+ metrics: defaults.metrics,
192
+ generatedAt: defaults.generatedAt
193
+ };
194
+ }
195
+ listDatabaseBackups(databaseId, limit) {
196
+ const backups = (this.data.databaseBackups ?? []).filter((backup) => backup.databaseId === databaseId);
197
+ const limited = limit === void 0 ? backups : backups.slice(0, limit);
198
+ return {
199
+ backups: limited.map((backup) => ({
200
+ id: backup.id,
201
+ backupType: backup.backupType,
202
+ status: backup.status,
203
+ size: backup.size ?? null,
204
+ createdAt: backup.createdAt
205
+ })),
206
+ retentionDays: this.data.databaseBackupRetentionDays ?? null,
207
+ hasMore: limited.length < backups.length
208
+ };
209
+ }
210
+ restoreDatabase(input) {
211
+ const target = this.getDatabase(input.targetDatabaseId);
212
+ if (!target) return { outcome: "target-not-found" };
213
+ if (!(this.data.databaseBackups ?? []).find((candidate) => candidate.id === input.backupId && candidate.databaseId === input.sourceDatabaseId)) return { outcome: "backup-not-found" };
214
+ target.status = "recovering";
215
+ return {
216
+ outcome: "restored",
217
+ database: target
218
+ };
219
+ }
220
+ rotateDatabaseConnection(connectionId) {
221
+ const connection = this.getDatabaseConnection(connectionId);
222
+ if (!connection) return;
223
+ const connectionString = `postgresql://rotated-${connection.databaseId}-${connection.id}.example.prisma.io/postgres`;
224
+ connection.connectionString = connectionString;
225
+ return {
226
+ connection,
227
+ connectionString
228
+ };
229
+ }
230
+ listBucketsForProject(projectId, branchName) {
231
+ return (this.data.buckets ?? []).filter((bucket) => bucket.projectId === projectId && (!branchName || this.data.branches.find((branch) => branch.id === bucket.branchId && branch.name === branchName)));
232
+ }
233
+ getBucket(bucketId) {
234
+ return (this.data.buckets ?? []).find((bucket) => bucket.id === bucketId);
235
+ }
236
+ createBucket(input) {
237
+ this.data.buckets ??= [];
238
+ let branchId = null;
239
+ if (input.branchGitName) {
240
+ const branch = this.data.branches.find((b) => b.projectId === input.projectId && b.name === input.branchGitName);
241
+ if (!branch) return;
242
+ branchId = branch.id;
243
+ }
244
+ const bucket = {
245
+ id: `bkt_${this.data.buckets.length + 1e3}`,
246
+ projectId: input.projectId,
247
+ branchId,
248
+ name: input.name ?? `bucket-${this.data.buckets.length + 1e3}`,
249
+ status: "ready",
250
+ createdAt: "2026-06-09T00:00:00.000Z"
251
+ };
252
+ this.data.buckets.push(bucket);
253
+ return bucket;
254
+ }
255
+ deleteBucket(bucketId) {
256
+ this.data.buckets ??= [];
257
+ this.data.bucketKeys ??= [];
258
+ const bucket = this.getBucket(bucketId);
259
+ if (!bucket) return;
260
+ this.data.buckets = this.data.buckets.filter((candidate) => candidate.id !== bucketId);
261
+ this.data.bucketKeys = this.data.bucketKeys.filter((key) => key.bucketId !== bucketId);
262
+ return bucket;
263
+ }
264
+ listBucketKeys(bucketId) {
265
+ return (this.data.bucketKeys ?? []).filter((key) => key.bucketId === bucketId);
266
+ }
267
+ createBucketKey(input) {
268
+ const bucket = this.getBucket(input.bucketId);
269
+ if (!bucket) return;
270
+ this.data.bucketKeys ??= [];
271
+ const secretAccessKey = `secret-${input.bucketId}-${this.data.bucketKeys.length + 1}`;
272
+ const accessKeyId = `AKIA${input.bucketId.toUpperCase().replace(/_/g, "")}${this.data.bucketKeys.length + 1}`;
273
+ const endpoint = `https://fly.storage.tigris.dev`;
274
+ const bucketName = bucket.name;
275
+ const key = {
276
+ id: `bkey_${this.data.bucketKeys.length + 1e3}`,
277
+ bucketId: input.bucketId,
278
+ name: input.name ?? `key-${this.data.bucketKeys.length + 1e3}`,
279
+ role: input.role,
280
+ valueHint: `${accessKeyId.slice(0, 8)}...`,
281
+ createdAt: "2026-06-09T00:00:00.000Z",
282
+ secretAccessKey,
283
+ accessKeyId,
284
+ endpoint,
285
+ bucketName
286
+ };
287
+ this.data.bucketKeys.push(key);
288
+ return {
289
+ key,
290
+ secretAccessKey,
291
+ accessKeyId,
292
+ endpoint,
293
+ bucketName
294
+ };
295
+ }
296
+ deleteBucketKey(bucketId, keyId) {
297
+ this.data.bucketKeys ??= [];
298
+ const key = (this.data.bucketKeys ?? []).find((candidate) => candidate.id === keyId && candidate.bucketId === bucketId);
299
+ if (!key) return;
300
+ this.data.bucketKeys = this.data.bucketKeys.filter((candidate) => candidate.id !== keyId);
301
+ return key;
302
+ }
59
303
  };
60
304
  //#endregion
61
305
  export { MockApi };