@prisma/cli 3.0.0-dev.95.1 → 3.0.0-dev.99.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.
package/README.md CHANGED
@@ -98,19 +98,6 @@ npx prisma-cli app promote <deployment-id>
98
98
  - Stable command groups, flags, and error codes for scripts and agents.
99
99
  - Environment variable values are not printed back to the terminal.
100
100
 
101
- ### Agent skills
102
-
103
- For agent-guided Next.js deploys, install the Prisma CLI skill cluster at the
104
- project level. Match the skill ref to the installed CLI version:
105
-
106
- ```bash
107
- npx prisma-cli version
108
- pnpm dlx skills@latest add prisma/prisma-cli/skills#cli-v<cli-version> --all
109
- ```
110
-
111
- The skills teach agents how to prepare a Next.js app, run `app deploy`, verify
112
- the result, and route CLI / Compute feedback to the right Prisma channel.
113
-
114
101
  ---
115
102
 
116
103
  ## Beta notes
@@ -11,6 +11,7 @@ const EMPTY_AUTH_CONTEXT = {
11
11
  activeWorkspaceId: null,
12
12
  workspaces: {}
13
13
  };
14
+ const UNKNOWN_WORKSPACE_NAME = "Unknown workspace";
14
15
  function getAuthContextFilePath(authFilePath) {
15
16
  const extension = path.extname(authFilePath);
16
17
  if (!extension) return `${authFilePath}.context.json`;
@@ -140,7 +141,7 @@ var FileTokenStorage = class {
140
141
  return credentials.map((credential) => storedCredentialToTokens(credential)).filter((tokens) => tokens !== null).map((tokens) => {
141
142
  const cached = context.state.workspaces[tokens.workspaceId];
142
143
  const id = typeof cached?.id === "string" && cached.id.trim().length > 0 ? cached.id.trim() : tokens.workspaceId;
143
- const name = typeof cached?.name === "string" && cached.name.trim().length > 0 ? cached.name.trim() : id;
144
+ const name = typeof cached?.name === "string" && cached.name.trim().length > 0 ? workspaceDisplayName(cached.name.trim(), tokens.workspaceId) : UNKNOWN_WORKSPACE_NAME;
144
145
  const lastSeenAt = typeof cached?.lastSeenAt === "string" && cached.lastSeenAt.trim().length > 0 ? cached.lastSeenAt.trim() : null;
145
146
  return {
146
147
  id,
@@ -151,6 +152,10 @@ var FileTokenStorage = class {
151
152
  };
152
153
  });
153
154
  }
155
+ async listWorkspaceTokens() {
156
+ this.signal?.throwIfAborted();
157
+ return (await this.readCredentialsFromDisk()).map((credential) => storedCredentialToTokens(credential)).filter((tokens) => tokens !== null);
158
+ }
154
159
  async useWorkspace(workspaceRef) {
155
160
  return this.withRefreshLock(() => this.useWorkspaceUnlocked(workspaceRef));
156
161
  }
@@ -406,5 +411,8 @@ function workspaceMatchesRef(workspace, ref) {
406
411
  function stripWorkspacePrefix(value) {
407
412
  return value.startsWith("wksp_") ? value.slice(5) : value;
408
413
  }
414
+ function workspaceDisplayName(name, credentialWorkspaceId) {
415
+ return name === credentialWorkspaceId ? UNKNOWN_WORKSPACE_NAME : name;
416
+ }
409
417
  //#endregion
410
418
  export { FileTokenStorage, WorkspaceSelectionError };
@@ -1,4 +1,4 @@
1
- import { SERVICE_TOKEN_ENV_VAR } from "../lib/auth/client.js";
1
+ import { CLIENT_ID, SERVICE_TOKEN_ENV_VAR, getApiBaseUrl } from "../lib/auth/client.js";
2
2
  import { FileTokenStorage, WorkspaceSelectionError } from "../adapters/token-storage.js";
3
3
  import { authRequiredError, usageError, workspaceAmbiguousError, workspaceNotAuthenticatedError, workspaceSwitchUnavailableError } from "../shell/errors.js";
4
4
  import { canPrompt } from "../shell/runtime.js";
@@ -6,6 +6,7 @@ import { performLogin, performLogout, readAuthState } from "../lib/auth/auth-ops
6
6
  import { createAuthUseCases } from "../use-cases/auth.js";
7
7
  import { createCliUseCaseGateways } from "../use-cases/create-cli-gateways.js";
8
8
  import { createSelectPromptPort } from "./select-prompt-port.js";
9
+ import { createManagementApiSdk } from "@prisma/management-api-sdk";
9
10
  //#region src/controllers/auth.ts
10
11
  function isRealMode(context) {
11
12
  return !context.runtime.fixturePath && !context.runtime.env.PRISMA_CLI_MOCK_FIXTURE_PATH;
@@ -77,7 +78,8 @@ async function requireAuthenticatedAuthState(context) {
77
78
  }
78
79
  async function listRealAuthWorkspaces(context) {
79
80
  const rawServiceToken = context.runtime.env[SERVICE_TOKEN_ENV_VAR];
80
- const localWorkspaces = await new FileTokenStorage(context.runtime.env, context.runtime.signal).listWorkspaces();
81
+ const storage = new FileTokenStorage(context.runtime.env, context.runtime.signal);
82
+ const localWorkspaces = await hydrateLocalAuthWorkspaces(context, storage, await storage.listWorkspaces());
81
83
  if (rawServiceToken !== void 0) {
82
84
  const authState = await readAuthState(context.runtime.env, context.runtime.signal);
83
85
  return {
@@ -117,6 +119,7 @@ async function listRealAuthWorkspaces(context) {
117
119
  async function useRealAuthWorkspace(context, workspaceRef) {
118
120
  if (context.runtime.env["PRISMA_SERVICE_TOKEN"] !== void 0) throw workspaceSwitchUnavailableError();
119
121
  const storage = new FileTokenStorage(context.runtime.env, context.runtime.signal);
122
+ await hydrateLocalAuthWorkspaces(context, storage, await storage.listWorkspaces());
120
123
  try {
121
124
  const result = await storage.useWorkspace(workspaceRef);
122
125
  return {
@@ -137,6 +140,7 @@ async function useRealAuthWorkspace(context, workspaceRef) {
137
140
  }
138
141
  async function logoutRealAuthWorkspace(context, workspaceRef) {
139
142
  const storage = new FileTokenStorage(context.runtime.env, context.runtime.signal);
143
+ await hydrateLocalAuthWorkspaces(context, storage, await storage.listWorkspaces());
140
144
  try {
141
145
  const result = await storage.logoutWorkspace(workspaceRef);
142
146
  return {
@@ -171,6 +175,78 @@ async function selectWorkspaceSession(context) {
171
175
  }))
172
176
  })).id;
173
177
  }
178
+ async function hydrateLocalAuthWorkspaces(context, storage, workspaces) {
179
+ const candidates = workspaces.filter(needsWorkspaceMetadataHydration);
180
+ if (candidates.length === 0) return workspaces;
181
+ const tokensByCredentialWorkspaceId = new Map((await storage.listWorkspaceTokens()).map((tokens) => [tokens.workspaceId, tokens]));
182
+ let nextWorkspaces = workspaces;
183
+ for (const workspace of candidates) {
184
+ const tokens = tokensByCredentialWorkspaceId.get(workspace.credentialWorkspaceId);
185
+ if (!tokens) continue;
186
+ const resolved = await resolveOAuthWorkspaceMetadata(context, tokens);
187
+ if (!resolved) continue;
188
+ await rememberResolvedWorkspaceMetadata(context, storage, tokens, resolved);
189
+ nextWorkspaces = nextWorkspaces.map((candidate) => candidate.credentialWorkspaceId === workspace.credentialWorkspaceId ? {
190
+ ...candidate,
191
+ id: resolved.id,
192
+ name: resolved.name,
193
+ lastSeenAt: (/* @__PURE__ */ new Date()).toISOString()
194
+ } : candidate);
195
+ }
196
+ return nextWorkspaces;
197
+ }
198
+ async function rememberResolvedWorkspaceMetadata(context, storage, tokens, resolved) {
199
+ try {
200
+ await storage.rememberWorkspace(tokens.workspaceId, resolved);
201
+ } catch {
202
+ context.runtime.signal?.throwIfAborted();
203
+ }
204
+ }
205
+ function needsWorkspaceMetadataHydration(workspace) {
206
+ return workspace.id === workspace.credentialWorkspaceId || workspace.name === "Unknown workspace" || workspace.name === workspace.credentialWorkspaceId;
207
+ }
208
+ async function resolveOAuthWorkspaceMetadata(context, tokens) {
209
+ const sdk = createManagementApiSdk({
210
+ clientId: CLIENT_ID,
211
+ redirectUri: "http://localhost:0/auth/callback",
212
+ tokenStorage: createSingleWorkspaceTokenStorage(new FileTokenStorage(context.runtime.env, context.runtime.signal, { activateOnSetTokens: false }), tokens),
213
+ apiBaseUrl: getApiBaseUrl(context.runtime.env)
214
+ });
215
+ try {
216
+ const { data } = await sdk.client.GET("/v1/workspaces/{id}", {
217
+ params: { path: { id: tokens.workspaceId } },
218
+ signal: context.runtime.signal
219
+ });
220
+ const id = stringOrNull(data?.data?.id) ?? tokens.workspaceId;
221
+ const name = stringOrNull(data?.data?.name) ?? id;
222
+ if (id === tokens.workspaceId && name === tokens.workspaceId) return null;
223
+ return {
224
+ id,
225
+ name
226
+ };
227
+ } catch {
228
+ context.runtime.signal?.throwIfAborted();
229
+ return null;
230
+ }
231
+ }
232
+ function createSingleWorkspaceTokenStorage(storage, initialTokens) {
233
+ let currentTokens = initialTokens;
234
+ return {
235
+ getTokens: async () => currentTokens,
236
+ setTokens: async (tokens) => {
237
+ currentTokens = tokens;
238
+ await storage.setTokens(tokens);
239
+ },
240
+ clearTokens: async () => {
241
+ const tokens = currentTokens;
242
+ currentTokens = null;
243
+ if (tokens) await storage.clearTokensIfCurrent(tokens);
244
+ }
245
+ };
246
+ }
247
+ function stringOrNull(value) {
248
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
249
+ }
174
250
  function toAuthWorkspace(workspace) {
175
251
  return {
176
252
  id: workspace.id,
@@ -341,7 +341,6 @@ const DESCRIPTORS = [
341
341
  "deploy"
342
342
  ],
343
343
  description: "Creates a new deployment for the app",
344
- longDescription: "Agent skills for guided Next.js deploys are available from the Prisma CLI skill cluster.",
345
344
  examples: [
346
345
  "prisma-cli app deploy",
347
346
  "prisma-cli app deploy --project proj_123",
@@ -353,7 +352,6 @@ const DESCRIPTORS = [
353
352
  "prisma-cli app deploy --app my-app --framework nextjs --http-port 3000",
354
353
  "prisma-cli app deploy --branch feat-login --framework hono",
355
354
  "prisma-cli app deploy --prod --yes",
356
- "pnpm dlx skills@latest add prisma/prisma-cli/skills#cli-v<cli-version> --all",
357
355
  "prisma-cli app deploy --framework bun --entry src/server.ts"
358
356
  ]
359
357
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/cli",
3
- "version": "3.0.0-dev.95.1",
3
+ "version": "3.0.0-dev.99.1",
4
4
  "description": "Command-line interface for the Prisma Developer Platform.",
5
5
  "type": "module",
6
6
  "bin": {