Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions docs/product/cli-style-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,13 @@ Recommended symbols:
Human-oriented command output in TTY mode should usually start with a compact header:

```text
project show → Showing the project resolved for this directory.
project show → No Project linked to this directory.

│ project: Acme Dashboard
│ workspace: Acme Inc
│ source: package-name
│ project: unbound
│ suggested: billing-api (package name)
│ match: Billing API
│ next: prisma-cli project link <id-or-name>
│ Read more docs/product/command-spec.md#prisma-cli-project-show
```
Expand Down
27 changes: 15 additions & 12 deletions docs/product/command-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,8 @@ Commands resolve project context in this order:
2. `PRISMA_PROJECT_ID` when set for headless deploy/domain commands
3. `.prisma/local.json` project pin when present, revalidated against platform data
4. durable platform mapping when available
5. remembered local project context, revalidated against platform data
6. `package.json` name matched exactly against an existing accessible Project for non-mutating resolution
7. explicit setup choice from `project link`, `project create`, an interactive setup picker, `app deploy --project`, or `app deploy --create-project`
8. structured failure in `--json` / `--no-interactive` mode
5. explicit setup choice from `project link`, `project create`, an interactive setup picker, `app deploy --project`, or `app deploy --create-project`
6. structured failure when no explicit or durable Project binding exists

`--project` is an explicit Project choice. When used from an unbound directory
with `app deploy`, it writes `.prisma/local.json` after validation and before
Expand All @@ -93,10 +91,13 @@ suggest setup defaults, but they never authorize Project creation by themselves.
When `PRISMA_PROJECT_ID` is set, `app deploy` and `app domain` commands skip
`.prisma/local.json` reads and do not write a new pin.

`app deploy` is stricter than general inspection commands: it does not use
package-name matching or remembered local context as Project scope. Without a
pin, durable mapping, env var, or explicit Project flag, it enters explicit
setup or fails with `PROJECT_SETUP_REQUIRED`.
Project-scoped commands never use package-name matching, directory-name
matching, or remembered local context as selected Project scope. Local metadata
may suggest setup defaults and candidate Projects, but only explicit input or
durable state may select a Project. Without a pin, durable mapping, supported
env var, or explicit Project flag, Project-scoped commands fail with
`PROJECT_SETUP_REQUIRED`; `app deploy` may enter explicit interactive setup
before failing.

### App Selection

Expand Down Expand Up @@ -376,17 +377,19 @@ prisma-cli project list --json

Purpose:

- show the Prisma project resolved for this directory
- show this directory's Prisma Project binding

Behavior:

- requires auth
- resolves project context without creating projects
- inspects explicit or durable project context without creating projects
- does not prompt for project selection
- does not mutate local state
- `--project <id-or-name>` resolves only the explicit project
- returns Workspace, Project, and `resolution.projectSource`
- fails with `PROJECT_UNRESOLVED`, `PROJECT_NOT_FOUND`, `PROJECT_AMBIGUOUS`, or `LOCAL_STATE_STALE` when resolution cannot continue safely
- when bound, returns Workspace, Project, and `resolution.projectSource`
- when unbound, exits successfully with `project: null`, `resolution.projectSource: "unbound"`, a suggested Project name, matching Project candidates, and recovery commands
- package names and directory names only power unbound suggestions
- fails with `PROJECT_NOT_FOUND`, `PROJECT_AMBIGUOUS`, or `LOCAL_STATE_STALE` when explicit or durable binding validation cannot continue safely

Examples:

Expand Down
6 changes: 2 additions & 4 deletions docs/product/error-conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ These codes are the minimum stable set for the MVP:

- `USAGE_ERROR`
- `AUTH_REQUIRED`
- `PROJECT_UNRESOLVED`
- `PROJECT_SETUP_REQUIRED`
- `PROJECT_CREATE_FAILED`
- `PROJECT_NOT_FOUND`
Expand Down Expand Up @@ -199,13 +198,12 @@ Recommended meanings:

- `USAGE_ERROR`: invalid arguments or invalid command combination
- `AUTH_REQUIRED`: command needs an authenticated session
- `PROJECT_UNRESOLVED`: command needs project context and none could be resolved
- `PROJECT_SETUP_REQUIRED`: `app deploy` needs an explicit Project setup choice before it can continue
- `PROJECT_SETUP_REQUIRED`: command needs explicit or durable Project context before it can continue
- `PROJECT_CREATE_FAILED`: Project creation failed before deployment or linking could continue
- `PROJECT_NOT_FOUND`: requested project does not exist or is not accessible
- `PROJECT_AMBIGUOUS`: multiple safe project candidates matched
- `APP_AMBIGUOUS`: multiple apps matched the inferred or explicit app target
- `LOCAL_STATE_STALE`: local Project pin or remembered context no longer matches platform data and continuing would be ambiguous
- `LOCAL_STATE_STALE`: local Project pin no longer matches platform data and continuing would be ambiguous
- `BRANCH_NOT_DEPLOYABLE`: command tried to deploy to a non-deployable branch context
- `FRAMEWORK_NOT_DETECTED`: app deploy could not detect a supported Beta framework and no explicit framework/build type was provided
- `DEPLOYMENT_NOT_FOUND`: requested deployment id does not exist
Expand Down
8 changes: 5 additions & 3 deletions docs/product/output-conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,13 @@ Human output should:
Recommended header shape:

```text
project show → Showing the project resolved for this directory.
project show → No Project linked to this directory.

│ project: Acme Dashboard
│ workspace: Acme Inc
│ source: package-name
│ project: unbound
│ suggested: billing-api (package name)
│ match: Billing API
│ next: prisma-cli project link <id-or-name>
│ Read more docs/product/command-spec.md#prisma-cli-project-show
```
Expand Down
26 changes: 12 additions & 14 deletions docs/product/resource-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,20 +193,18 @@ Commands resolve project context in this order:
2. `PRISMA_PROJECT_ID` when set for headless deploy/domain commands
3. `.prisma/local.json` project pin when present, revalidated against platform data
4. durable platform mapping when available
5. remembered local project context, revalidated against platform data
6. `package.json` name matched exactly against an existing accessible Project for non-mutating resolution
7. explicit setup choice: `project link`, `project create`, interactive setup picker, `app deploy --project`, or `app deploy --create-project`
8. structured failure in `--json` / `--no-interactive` mode

Remembered local project context is an internal convenience after successful
resolution. It must be revalidated before use and must not be described to users
as durable linking. Package names and directory names may be suggested during
setup, but they do not authorize Project creation by themselves.

`app deploy` is stricter than general inspection commands: if the directory is
not pinned and no explicit Project source is provided, it enters explicit setup
or fails with `PROJECT_SETUP_REQUIRED` instead of using package-name or
remembered-local inference.
5. explicit setup choice: `project link`, `project create`, interactive setup picker, `app deploy --project`, or `app deploy --create-project`
6. structured failure when no explicit or durable Project binding exists

Package names and directory names may suggest setup defaults and matching
Project candidates, but they do not select Project scope. Remembered local
context may help with app/deployment convenience after a Project is explicit,
but it is not a Project binding source.

Project-scoped commands require explicit or durable Project context. If the
directory is not pinned and no explicit Project source is provided, they fail
with `PROJECT_SETUP_REQUIRED`; `app deploy` may enter explicit interactive setup
before failing.

### App Selection Resolution

Expand Down
13 changes: 6 additions & 7 deletions packages/cli/src/controllers/app-env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import type {
EnvVariableMetadata,
} from "../types/app-env";
import { requireAuthenticatedAuthState } from "./auth";
import { createSelectPromptPort } from "./select-prompt-port";
import { listRealWorkspaceProjects } from "./project";

interface ResolvedScope {
Expand Down Expand Up @@ -72,7 +71,7 @@ export async function runEnvAdd(
);
}

const { client, projectId } = await requireClientAndProject(context, flags.projectRef);
const { client, projectId } = await requireClientAndProject(context, flags.projectRef, "project env add");
const resolved = await resolveScopeToApi(client, projectId, scope, {
createBranchIfMissing: true,
});
Expand Down Expand Up @@ -152,7 +151,7 @@ export async function runEnvUpdate(
);
}

const { client, projectId } = await requireClientAndProject(context, flags.projectRef);
const { client, projectId } = await requireClientAndProject(context, flags.projectRef, "project env update");
const resolved = await resolveScopeToApi(client, projectId, scope, {
createBranchIfMissing: false,
});
Expand Down Expand Up @@ -203,7 +202,7 @@ export async function runEnvList(
const explicit = resolveEnvScope(flags, { requireExplicit: false, command: "list" });
const scope = explicit ?? defaultRoleScope();

const { client, projectId } = await requireClientAndProject(context, flags.projectRef);
const { client, projectId } = await requireClientAndProject(context, flags.projectRef, "project env list");
const resolved = await resolveScopeToApi(client, projectId, scope, {
createBranchIfMissing: false,
});
Expand Down Expand Up @@ -249,7 +248,7 @@ export async function runEnvRemove(
);
}

const { client, projectId } = await requireClientAndProject(context, flags.projectRef);
const { client, projectId } = await requireClientAndProject(context, flags.projectRef, "project env remove");
const resolved = await resolveScopeToApi(client, projectId, scope, {
createBranchIfMissing: false,
});
Expand Down Expand Up @@ -293,6 +292,7 @@ export async function runEnvRemove(
async function requireClientAndProject(
context: CommandContext,
explicitProject: string | undefined,
commandName: string,
): Promise<{ client: ManagementApiClient; projectId: string }> {
const authState = await requireAuthenticatedAuthState(context);
const client = await requireComputeAuth(context.runtime.env);
Expand All @@ -308,8 +308,7 @@ async function requireClientAndProject(
workspace: authState.workspace,
explicitProject,
listProjects: () => listRealWorkspaceProjects(client, authState.workspace!),
prompt: createSelectPromptPort(context),
remember: true,
commandName,
});

return { client, projectId: target.project.id };
Expand Down
Loading
Loading