Rework the command surface: explicit targeting, delete verbs, workflow-grouped commands - #218
Rework the command surface: explicit targeting, delete verbs, workflow-grouped commands#218wmadden-electric wants to merge 25 commits into
Conversation
The compute config it wrote is unsupported, so the wizard that created it goes with it. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Service commands drop the config-target positional and resolve the project from the invocation directory's link file alone. Agent setup status and the state directory no longer walk up to a config file. The local build-and-deploy path the config fed had no callers left, so app-provider loses deployApp with it. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
pnpm --recursive exec tsc --noEmit fails on packages/tsconfig, which has no typescript dependency. The root typecheck script (turbo run typecheck, per-package tsc --noEmit) already covers every TypeScript package. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Every service command that acts on an existing service now resolves it from --service (by name) or PRISMA_SERVICE_ID (by id, the domain-flow mechanics generalized), with the flag winning. Neither present settles SERVICE.TARGET_REQUIRED at exit 2, interactive terminals included: the interactive picker, the saved selection (rememberSelectedService, LocalStateStore.readSelectedApp/setSelectedApp/clearSelectedApp, the selectedByProject state shape), and service remove's selection cleanup are gone. Branch targeting is --branch only: the git-branch inference is deleted, read flows keep their "main" default and the domain flow keeps "production" with its production-only check. lib/git/local-branch.ts stays: controllers/app-env.ts (project env scope resolution, outside this change's scope) still imports it. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
- project/link.ts: linkDirectoryToProject's doc comment no longer claims init runs it; the export drops to in-file scope, its only use. - cli.ts and mount-coverage note that orm init keeps its path; only the top-level init (the compute config wizard) was removed (2026-08-21 PM review). - service/target.ts: resolveServiceProjectContext loses the projectDir option no caller passed. - state-dir.ts: resolveStateDir is synchronous and takes no signal; it only joins paths. Call sites adjusted. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
project delete, project env delete, postgres delete, postgres connection delete, service delete, and service domain delete replace their remove spellings everywhere: mount paths, source file names, exported symbols, result types (removed: true becomes deleted: true), help, examples, next actions, error copy, consent questions, progress step/status names, unit tests, and e2e describeCommand markers. No aliases or redirects for the old spellings. Error codes tied to these commands follow the verb: SERVICE.REMOVE_FAILED -> SERVICE.DELETE_FAILED, PROJECT_REMOVE_BLOCKED -> PROJECT_DELETE_BLOCKED (PROJECT.DELETE_BLOCKED). The unused legacy AppRemoveResult / AppDomainRemoveResult types are deleted. git disconnect, auth logout, bucket delete, and provider-internal removeApp/removeProject/removeDatabase/removeConnection/removeDomain helpers are untouched. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
- service logs --deployment decides scoped-vs-global on whether any service target was requested: PRISMA_SERVICE_ID now scopes the lookup exactly like --service (D2-1), with tests for the missing-target refusal, the service-scoped path and its not-in-this-service refusal, and the env-var-scoped path (D2-2). - ServiceShowResult.service and ServiceDeploymentListResult.service are non-null; the "not selected" presenter fallbacks are gone (D2-3). - ResolveProjectOptions.projectDir deleted; the invocation directory is the only pin location (D2-4). - User-facing copy no longer says "selected service" — the service is named, not selected (D2-5). - serviceTargetRequiredError keeps why to the cause; the PRISMA_SERVICE_ID alternative is its own nextActions entry so --json consumers see it (D2-6). Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The mounted tree now equals the slice spec's acceptance tree: postgres restore moves under postgres backup, ref list|set|delete move under migration ref, migrate becomes db migrate, format becomes contract format, and composer's dev and deploy mount at the root. The composer group, composer destroy, composer log, and the build group (build logs and its sources and tests) are gone. No aliases or redirects for the old spellings. Both external families are re-wrapped with defineCommandFamily, keeping their configSection and docsBaseUrl. Composer keeps only deploy and dev, so mount-coverage's family-completeness check stays honest about the dropped commands. The ORM family passes its commands through but rewrites its shipped redirects: the migration ref entry is dropped (that spelling is live again, and mounting it with the redirect in place fails buildCli's collision check) and migration apply's replacement is respelled to db migrate. Root help examples end as auth login, project list, deploy. Coverage tables, group briefs (postgres backup now covers restore; migration ref is new), and the bin/orm-mount/postgres tests follow. The cli-engine redirect fixtures are synthetic and stay as they are. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
- Provider-layer failure summaries follow the verb rename: deleting a project, database, database connection, or custom domain now fails as "Failed to delete …", and the env branch-not-found why-text says delete. A postgres delete failure test pins the summary. - validateKey narrows to its reachable commands (add | update); the unreachable remove template branch goes with it. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Command tables and prose in both package READMEs, the root README, packages/cli/AGENTS.md, and the example READMEs now name the live tree: deploy and dev at the root, delete for the destroying commands, postgres backup restore, and the ORM groups without top-level migrate/format/init. command-principles drops init from the stable groups, respells migrate as db, and states the verb rule (delete destroys, remove detaches). The style/output guides use auth login as the first-run banner example; error-conventions drops the removed compute-config and init codes and follows the DELETE_BLOCKED / DELETE_FAILED renames; cli-engine-requirements respells db migrate and orm init; output-conventions loses the compute-config build settings bullet and respells the connection delete rows. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…mand-review Each s2 parity record that documents a renamed or moved command gets a short dated entry (2026-08-21 PM review); command-inventory.md gets a pointer note. command-review.md is recreated in the 76a2c8a format against the new 86-command tree. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
- The wrapped ORM family respells the moved commands' shipped help examples to their mounted paths (contract format, db migrate, migration ref list|set|delete); a rendered-help test pins that no retired spelling survives in any of the five (D4-1). - The composer wrap subtracts destroy and log from the source family instead of selecting deploy and dev, so a command composer adds upstream reaches the wrapped family and mount-coverage flags it until the shell mounts it (D4-2). Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
|
Important Review skippedToo many files! This PR contains 147 files, which is 47 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (147)
You can disable this status message by setting the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
commit: |
Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
- orm init joins the ORM mount respellings: its six shipped help examples now render as orm init, pinned by a sixth row in the rendered-help test and init in the retired-spelling check (D5-1). - The output gallery drops its two init shots (init --help and the hono wizard run) and the wizard's caption panel; both would now capture an unknown-command error (D5-2). Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Review of the grammar-cleanup branch surfaced that removing the git-branch inference left most service commands with no way to reach a service on a non-default branch, and that many help examples and next-action hints named invocations the new parameter-only grammar refuses. - service show/open/logs and every service deployment verb take --branch, threaded into the existing branchName resolution, so preview-branch services and deployments are reachable again. - An empty --branch is refused centrally in the target resolvers instead of only in service delete, and the error's copy no longer describes the deleted git inference. - Every shipped help example and next-action hint that named a service command now carries --service — interpolated where the name is in scope, a <name> placeholder where it is not — and projectDeleteBlockedError suggests the flags-only service delete shape. After service delete, the next action is service list, since nothing service-scoped can run. - The knownLiveDeployment local state had no writers left: the schema, its store methods, and service delete's cleanup pass are gone. - resolveServiceReleaseState had become a passthrough around resolveServiceReadState; the callers use the read state directly. - types/app.ts kept ~18 interfaces nothing produced; the two live domain types moved into service/results.ts as ServiceDomainStatus and ServiceDomainDnsRecord. - New/edited markdown prose is unwrapped to one line per paragraph. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…oyments by id alone Operator ruling on the review round: any command that operates on a subject resource takes that resource's identifier as its first positional argument — the established CLI convention — and flags only scope or qualify. Recorded as "Subjects are positional" in docs/product/command-principles.md and as a dated amendment in the slice spec. - service show/open/logs/delete and service deployment list/rollback take the service name as an optional positional (PRISMA_SERVICE_ID stays as the env fallback; neither present is still the SERVICE.TARGET_REQUIRED refusal, its copy respelled). - service deployment promote/start/stop/delete and service logs --deployment are targeted by the globally-unique deployment id alone, resolved through the same global lookup service deployment show always used (a shared resolveDeploymentSubject). They take no --service, --project, or --branch, and their results drop projectId, matching deployment show. SERVICE.DEPLOYMENT_OUTSIDE_PROJECT is gone with the project check it belonged to. - project show takes the project as an optional positional instead of --project, with a retryCommand override so the shared project-setup hint stops suggesting a flag the command no longer has. - Domain commands keep --service as a scope flag: their positional is the hostname, and the management API has no global hostname lookup. The API's missing deployment-to-service lookup (each id-targeted run pays a project-by-project scan) is recorded in the deferred ledger. - Help examples, error hints, unit tests, and the e2e suite follow the new grammar. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Operator ruling: extend parameters-only targeting to project env. A
bare `project env list` now lists the overview of every scope instead
of resolving the checkout's branch against the platform; --role and
--branch are the only scope selectors, as they already were for
add/update/delete. readLocalGitBranch and lib/git/local-branch.ts are
deleted — nothing else imported them — and the "local-git" target
source is gone from the list result shape.
Also sharpened the deferred-ledger entry on deployment lookups with
what the API actually returns: GET /v1/deployments/{id} omits the
parent appId, which is why the CLI scans for the owner. The fix
belongs in pdp-control-plane's deployment representation.
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Operator ruling: the env var existed for the headless app deploy flow, which this PR already deleted; the domain commands were its only surviving reader, by accident rather than decision. Project targeting is --project and the link file. The envProjectId option and the allowEnvProjectId split between resolveProjectTarget and inspectProjectBinding collapse with it, and the "env" project source leaves the result types. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…ys so pdp-control-plane ADR-012 retires "Deployment" as a noun — a deploy produces a Version — and the CLI adopts it now, pre-rc, before any release teaches users the retired word. - Commands: service deployment list|show|promote|rollback|start|stop| delete mount as service version …; service logs --deployment becomes --version-id (the engine reserves the flag name "version" for the shared --version flag). - JSON contract: deployment→version, deployments→versions, deploymentId→versionId, liveDeployment→liveVersion, recentDeployments→recentVersions, previousLiveDeploymentId→ previousLiveVersionId, and liveDeploymentId→liveVersionId on list entries. Progress steps stop-deployments/delete-deployments become stop-versions/delete-versions. - Error codes: SERVICE.DEPLOYMENT_*→SERVICE.VERSION_*, NO_DEPLOYMENTS→NO_VERSIONS, NO_PREVIOUS_DEPLOYMENT→ NO_PREVIOUS_VERSION, LIVE_DEPLOYMENT_UNKNOWN→LIVE_VERSION_UNKNOWN. - Copy: help and error prose says "service version" (qualified, per the ADR); example ids use the real cpv_ prefix. - The wire layer deliberately keeps platform vocabulary until the platform's own coordinated rename: /v1/deployments paths, compute-sdk names, appId, and the adapter in lib/app/app-provider.ts, which is the seam where the two vocabularies meet. Recorded in the ledger. - docs/product/command-principles.md's noun table now says service and version; READMEs, the slice-spec amendment, tests, and the e2e suite follow. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The create/show e2e asserted liveDeploymentId, liveDeployment, and recentDeployments, which the ADR-012 rename respelled to liveVersionId, liveVersion, and recentVersions — caught by the credentialed CI run, which the local suite cannot reach. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
This PR reshapes the CLI's command surface in one pass. At a glance, what a user types changes like this:
prisma initprisma project link/project create)prisma service removeprisma service delete <name>prisma postgres restoreprisma postgres backup restoreprisma ref set stagingprisma migration ref set stagingprisma migrate/prisma formatprisma db migrate/prisma contract formatprisma composer dev/composer deployprisma dev/prisma deployprisma service show(interactive service picker)prisma service show <name>(no picker)The decision: the CLI is pre-rc, so we owe the old spellings nothing. Every old spelling above now gets the standard unknown-command error — no aliases, no redirects, no deprecation window. That single decision is what keeps this PR mechanical: commands move or rename, and every string that names them (help, examples, error copy, "next action" hints, tests, docs) follows.
Three ideas drive the new shape:
.prisma/local.json). Commands that act on a subject resource take its identifier as the first positional argument (service show <name>, withPRISMA_SERVICE_IDas the env fallback; the argument wins) plus scope flags like--branch <name>; commands targeted by a globally-unique version id (service version promote|start|stop|delete <id>,service logs --version-id <id>) need nothing else at all. Missing target → a structuredSERVICE.TARGET_REQUIREDerror, exit 2, before any network call — even in an interactive terminal. The interactive picker, the remembered per-project selection, and the "use the current git branch" inference are gone. What runs is what was named, which is what makes runs reproducible for humans and scriptable for agents.deletedestroys,removedetaches. Six commands that permanently destroy resources were calledremove; they are nowdeleteend to end — help, consent questions, JSON output (removed→deleted), error codes (…REMOVE_FAILED→…DELETE_FAILED).git disconnectandauth logoutstay: they detach.composerandbuilddisappear as groups:devanddeployare the root-level verbs of the main workflow (this also fixes their shipped help examples, which already readprisma deploy …),composer destroy/logare dropped, and the deprecated platform build runner'sbuild logsgoes with its group.reffolds intomigration ref;restoresits underpostgres backupbecause it acts on a backup.How it's implemented. The shell owns the command tree in
packages/cli/src/cli.ts, so most of the diff is that mount table plus strings. The one structural piece: the composer and ORM command families ship from their own packages, so the shell now wraps both before mounting. The composer wrapper subtractsdestroy/log(by subtraction, so a new upstream command still trips the completeness check). The ORM wrapper rewrites shipped metadata the moves invalidated: it drops the package'smigration ref→refredirect (which would collide with the now-livemigration refmounts at construction time), respells themigration applyredirect's replacement todb migrate, and respells the six commands' help examples whose mount path differs from their family key.Also removed outright: the deprecated
prisma.compute.ts/.jsonconfig and everything that read it — theinitwizard, the config-driven service targeting positional, theSERVICE.COMPUTE_CONFIG_*error codes, and the agent-status config probe (~5k lines).Guard rails. The grammar-completeness test (
packages/cli/tests/mount-coverage.test.ts) asserts the mounted tree equals the agreed 86-command tree, and runs before publish. Docs, both package READMEs, and the product convention docs (including the new delete/remove verb rule) are updated in the same PR. Verified:pnpm typecheck,pnpm lint, unit suites (841 + 11 passed),pnpm check:grammar; e2e runs in CI (local run skipped without credentials).Alternatives considered.
🤖 Generated with Claude Code
ADR-012 vocabulary (added in review). pdp-control-plane ADR-012 retires "Deployment" as a noun — a deploy produces a Version — so this PR also lands that rename on the CLI surface before any rc teaches users the retired word:
service deployment *isservice version *, JSON fields and error codes respell (deployment→version,SERVICE.DEPLOYMENT_*→SERVICE.VERSION_*, …), and prose says "service version". The wire layer (/v1/deployments, compute-sdk names,appId) deliberately keeps platform vocabulary until the platform's own coordinated rename; the adapter inlib/app/app-provider.tsis the seam where the two meet.