Move the resource commands onto the CLI engine, and rename database to postgres - #133
Conversation
…atch plan S2 ships as four area PRs (>=1k LOC floor). S2a: engine publish metadata + production dependency, ctx.api on the command context, auth module extraction, the auth family port, update check, cli-telemetry package move with the RunHooks.onSettled amendment, and the clack prompt renderer from the spike. Contracts pin every design decision; dispatches stop rather than improvise. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…ction dependency Give @prisma/cli-engine everything npm publish needs: version 0.1.0, the one-line description, Apache-2.0 license file, files list (dist, README, LICENSE), repository/homepage/bugs pointing at prisma/prisma-cli, publishConfig access public, engines.node >=22.12.0, and a prepack build script, all shaped like packages/cli's package.json. Drop private: true so the package can actually be published, and add a terse README covering the package and its three entry points. Move @prisma/cli-engine from the cli's devDependencies to dependencies (still workspace:*) and settle the lockfile. npm pack --dry-run ships exactly dist + README.md + LICENSE + package.json. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Move token-storage, auth-ops (now operations), and the auth client into src/auth/, extract the real-mode workspace helpers out of the auth controller into src/auth/workspaces.ts, and relocate makeGetCredentials from the v8 runtime into src/auth/credentials.ts. src/auth/index.ts is the module's only public face; controllers, the legacy shell, and the v8 code import through it. No behavior change: both suites pass with only import and mock path updates. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…2 question ledger The 60-command inventory grounds the S2b (resources), S2c (services), and S2d (init + shell retirement) contracts. The overview gains the operator question ledger (Q1 auto-login, Q2 service-run passthrough, Q3 rm alias, Q4 config evaluation for the shipped bin, Q5 exit-code unification) with the defaults the contracts build to. S2a contract errata from D2/D6 grounding: auth logout --workspace, the auth index export list, the white-box test exception. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Contract s2a-foundations §2 (dispatch D3).
- @prisma/management-api-sdk pinned exact (1.55.0) in the engine and
the cli
- Runtime gains managementApi.baseUrl; the v8 bin derives it via
getApiBaseUrl(env)
- CommandContext.api: lazy, once per run, constructed on first access
by copying the shell's createManagementApiSdk call site with the
token source backed by ctx.getCredentials, so refresh is picked up
per request; the client is proxied to rethrow structured errors the
SDK's onError middleware would otherwise wrap in FetchError
- Unauthenticated use throws CLI.CREDENTIALS_REQUIRED via the single
constructor now exported from execution/needs.ts
- Harness spec gains managementApi { baseUrl?, client? }; an injected
client IS ctx.api; baseUrl defaults to https://test.invalid
- Draft amendments: §4 CommandContext, §10 Runtime, §11 harness spec
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Prompt rendering is now two-tier. Real TTYs — isTty.stdin AND
stdin.setRawMode present, no scripted answers — render through
@clack/prompts (exact-pinned 1.5.0, loaded by dynamic import only on
that path); scripted answers, piped stdin, and the test harness stay
on the plain line renderer. --yes resolution and structural failures
are decided before the tier branch, so both tiers share identical
semantics.
clack-renderer.ts adapts Runtime streams for clack: Readable.from over
Runtime.stdin presenting isTTY with setRawMode forwarded, a Writable
over the stderr OutputStream, and { input, output } injected per
prompt, so all prompt UI stays on stderr. Clack's cancel symbol
(including the \x03 byte path) maps to the existing
CLI.PROMPT_CANCELLED exit-3 settlement. consent maps to clack confirm
starting on No: Enter-through returns false, only explicit Yes grants.
Clack's spinner/log helpers are never used (process-global handlers);
progress remains engine events.
Draft notes: §4a two-tier rendering, select's Enter-picks-highlighted
behavior, and the accepted quirk that clack reads
process.stdout.columns for wrap width.
Tests: a fake raw-mode stdin fixture drives confirm/consent/select/
text through the clack tier, asserting resolved values, stderr-only
UI bytes, setRawMode forwarding, and \x03 -> exit 3; a module-load
spy (with a canary validating the spy) proves the scripted and
non-TTY paths never load @clack/prompts. Dist .d.ts stays clack-free.
Reimplements spike/clack-prompts (903b25a) on the current module
layout.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…elemetry Ports packages/1-framework/3-tooling/cli-telemetry from prisma/prisma into this repo as a private workspace package, per the S2a contract (§6). Preserved unchanged: the shared prisma-next user-config path and format (one installation id with the ORM CLI), gating resolution with the exact env var names and precedence (PRISMA_NEXT_DISABLE_TELEMETRY truthy, DO_NOT_TRACK=1, stored consent, opt-out default-on), the detached fork/IPC/unref sender mechanism with its silence and exit-0 contract, the production endpoint and wire protocol, and the sanitizer's value-free discipline. Adapted for this repo: the Commander snapshot is replaced by the engine shape EngineCommandSnapshot (command path, flag names with value source, positional count — no values, ever) and the sanitizer projects it to the same wire fields; the arktype payload schema is spelled out as a hand-rolled guard with identical semantics (no arktype dependency here); the ORM's @internal/config validator is replaced by a structural extraction of target.targetId and extensions[].id with the same empty-on-invalid outcome; pathe and @internal/utils are replaced by node:path and an inline spread. The DB-backed integration harness is replaced by a local mock HTTP backend driven through the same endpoint override the reference suite used; the production endpoint is never contacted from tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…nt commands
Engine amendment (draft §10): RunHooks gains onSettled(summary) with
RunSummary { commandId, exitCode, durationMs, snapshot } and the
value-free EngineCommandSnapshot { commandPath, flags (name + source),
positionalCount }. The snapshot is captured at parse time when a
command mounts: flags explicitly present on argv are source 'cli'
(long, =-form, kebab or camel spelling, --no- negation, and aliases);
the engine reads no flags from the environment today, so everything
else is 'default'. The hook fires exactly once per run after
settlement, never for --help/--version or pre-mount usage errors,
with durationMs from the injectable clock; a throwing hook is
swallowed. RunHooks stays internal — the public growth is the minimal
hooks parameter on Cli.run (CliRunHooks, onSettled only), and the
test harness gains a matching onSettled tap.
Bin wiring (v8 main): the CI/env/consent decision resolves before the
run; when enabled an onSettled hook fires runTelemetry (detached
fork + IPC send + disconnect + unref, reference spawn semantics),
performing the first-run stderr disclosure + shared-id mint when no
installation id is stored; the telemetry command family is exempt;
when disabled no hook is attached. CI detection ports the ORM CLI's
ci-info wrapper.
Commands telemetry status|enable|disable port the ORM consent surface
as engine result commands, mounted shell-owned under the new
telemetry group, with the reference copy, cards per the S1 whoami
pattern, and json serializers. status is a pure read.
The cli bundles @repo/cli-telemetry (workspace devDependency, never a
published dep): a second tsdown config emits dist/v8/cli.js with the
telemetry source inlined plus the forkable dist/v8/sender.js; the
sender's third-party deps (c12, @vercel/detect-agent) move onto the
cli's own dependencies. Smoke-verified against a local mock backend:
a force-enabled run POSTs exactly one wire-shape event with the
stored installation id; CI=1 spawns nothing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Mounts all six auth commands (login, logout [--workspace], whoami, workspace list/use/logout) as engine result commands in the platform command family, backed by the extracted auth module. - login runs the real OAuth flow via performLogin, emitting step-started/finished events around it and an 'endpoint' event for the verification URL (new optional onVerificationUrl hook on performLogin; legacy callers unaffected), then reads the auth state and appends the ported agent-setup tip (CI-suppressed; tip line is human-mode only). Fixture-only --provider/--user/--workspace flags do not port. - logout --workspace calls the shared workspace-logout operation directly instead of the legacy argv re-dispatch. - workspace use resolves by id/case-insensitive name, auto-selects a single workspace, prompts via ctx.prompt.select otherwise, and lets the engine's structural prompt failure cover non-interactive runs. - Legacy flat error codes map mechanically to dotted AUTH.* codes (fix prose -> one user-choice nextAction, meta preserved), matching the S1 whoami precedent. - The workspace operations' context parameter narrows to a structural type both shells satisfy; whoami now shares the state-card and config-invalid helpers. - Semantic tests stub the auth module at the src/auth/index.ts seam; fixture-mode auth.test.ts cases covering ported commands are deleted (real-mode and shell-presentation cases stay until S2d). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
packages/cli/src/shell/update-check.ts moves to packages/cli/src/update-check.ts; its CliRuntime parameter narrows to the structural UpdateCheckRuntime (env/argv/stderr) both shells satisfy. The legacy shell keeps its call sites; the v8 bin copies their sequencing exactly: main() awaits the cached notification (and detached refresh spawn) before dispatch, and the v8 bin entry gains the PRISMA_CLI_RUN_UPDATE_CHECK_WORKER branch. Suppression rules are copied as-is, including silence when argv contains --json/--quiet/-q, recorded in the S2 divergence list. Tests cover the v8 wiring: cached-newer notify, interval silence, json-mode silence, non-TTY silence, and the detached refresh spawn's arguments and worker env contract. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…oxes Creates the S2 cumulative parity divergence list (seeded with a pointer to the S1 whoami-scoped record) covering the auth family's AUTH.* error-code mapping, login's fixture-flag removal and event surface, the logout --workspace commandId change, prompt-path behavior for workspace use, and the update-check json-mode finding. Marks the whoami record as whoami-scoped and updates its stale update-notification note. Checks every S2a acceptance box except the operator publish and the operator's divergence-list review. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
… load
Review-round fixes for slice s2a-foundations (B1, C4, A3, A7, C7):
- Attach a swallowing 'error' listener on the forked sender child so an
async fork failure can neither crash the parent CLI nor flip its exit
code (B1), with a regression test driving a fake child's error event.
- Drop the detached child's prisma-next.config.* c12 load entirely: the
config does not exist in this product and the load evaluated arbitrary
user TS in a detached process. databaseTarget now ships null (payload
override kept for wire compatibility) and extensions ships []; the c12
and magicast dependencies are removed (C4). Recorded as an S2a parity
divergence.
- resolveGating now takes { env, config, inCI } and returns a total
reason union (ci | env-opt-out | stored-opt-out | stored-opt-in |
default-on); CI is part of the resolution itself (A3).
- Public-surface tightening: the duplicated EngineCommandSnapshot type
is no longer re-exported (the structural declaration stays internal)
and SanitisedCommand is normalized to SanitizedCommand (A7).
- Pin @clack/prompts to exact 1.5.0 in packages/cli (C7).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…odule
Review-round fixes for slice s2a-foundations (C1, A10, A11, A8):
- restoreStructuredThrows maps the SDK's AuthError (the 401 /
refresh-unavailable path) to the shared CLI.CREDENTIALS_REQUIRED
structured error, matched structurally by name so a duplicate module
instance cannot defeat it (C1).
- The cause-chain walk tracks visited errors with a depth cap so a
cyclic cause chain terminates (C1), with a settlement test.
- The @prisma/management-api-sdk module now loads via dynamic import on
the first actual request: ctx.api is a Proxy whose async method
wrappers await the lazy construction, mirroring the clack renderer's
lazy-import pattern; the structured-throw restoration merged into the
same wrapper (A10).
- The engine's OAuth client id / redirect URI are inert empty-string
placeholders — no refresh token is ever supplied, so the SDK's OAuth
flow is unreachable (A11).
- RunSummary.commandId documents its derivation from
snapshot.commandPath (always equals commandPath.join('.')); draft §10
carries the same note (A8).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…e homes
Review-round fixes for slice s2a-foundations (A1, A2, A5, A6, C8, C6):
- src/lib/auth/{login,guard,recipient}.ts move into src/auth/; the
index gains requireComputeAuth and the recipient exports, and every
controller imports via src/auth/index.ts only (A1). src/auth is now a
leaf cluster: its one remaining legacy import is the CliError base
class (named as an S2d survivor).
- The auth-specific error constructors move from shell/errors into
src/auth/errors.ts (shell re-exports for legacy imports), and
resolveStateDir moves to src/state-dir.ts with shell/runtime
re-exporting (A2).
- WorkspaceOperationContext flattens to { env, signal }; the v8 adapter
shape is gone and legacy controller call sites build the flat context
(A5).
- listRealAuthWorkspaces/useRealAuthWorkspace/logoutRealAuthWorkspace
rename to listAuthWorkspaces/useAuthWorkspace/logoutAuthWorkspace —
there is no fixture-mode counterpart to distinguish from (A6).
- The onVerificationUrl observer hook is invoked inside try/catch so an
observer bug cannot break the login flow (C8).
- New src/cli-name.ts owns the user-facing binary name and docs URL;
getCliName and the update-check fallback URL consume it (C6).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…g semantics Review-round fixes for slice s2a-foundations (A4, A9, C2, C3, C5, C6, C9, C10, A13): - v8/auth/workspace-commands.ts splits into workspace-list.ts, workspace-use.ts, workspace-logout.ts with a workspace-shared.ts helper module; the shared runWorkspaceLogout operation gets its own module. v8/telemetry/commands.ts splits into status.ts (merged with the status resolution), enable.ts, disable.ts, and a shared consent presentation (A4). - v8/telemetry/wiring.ts renames to reporting.ts; options type renamed to TelemetryReportingOptions (A9). - auth workspace list now maps an empty PRISMA_SERVICE_TOKEN to AUTH.CONFIG_INVALID (exit 2), matching whoami/login/logout, with a divergence row (C2). - The first-run telemetry disclosure prints at gating time — pre-run, before the command's output — while the event still fires at settlement; the installation-id mint stays at first settlement so 'telemetry status' keeps reporting 'not stored' (C5). Status projects the gating resolver's total reason union directly (A3). - The disclosure and the telemetry group help now use the real docs page (the update-check fallback URL) and the CLI_NAME constant in every user-facing command string (C6). - New packages/cli/vitest.config.ts sets PRISMA_NEXT_DISABLE_TELEMETRY=1 suite-wide, mirroring the cli-telemetry package's own guard, so no test reaches the developer's real user config or the endpoint (C3); the bin/update-check test processes opt out explicitly. - Tests: AUTH.CONFIG_INVALID on login and logout, the json login tip envelope (agentSetupTip + tip nextAction), and the tip-suppression branch when Prisma skills are already installed (C9); update-check notify-before-dispatch ordering via a marker-writing stub CLI and the '--format json is NOT suppressed' literal-argv quirk (C10). - v8-auth.test.ts byte assertions convert to semantic assertions (envelope / presented / events / exit code); the sanctioned golden suite v8-golden-rendering.test.ts pins one representative card, table, and error rendering byte-exactly; the S1 whoami byte pins remain (A13). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Operator-process-sanctioned S2 doc amendments from the review round: - parity-divergences.md: workspace list joins the AUTH_CONFIG_INVALID mapping row; new sections for the empty-service-token structuring and the two telemetry divergences (config enrichment dropped; onSettled emission timing with pre-run disclosure — crashed/killed/process.exit runs emit nothing). - s2a-foundations.md §3: the workspace operation exports are the *AuthWorkspaces names, with a one-line erratum; §6: CI is part of the gating resolution, and the wording separates spawn semantics (copied) from timing (onSettled by design, pre-run disclosure). - s2d-init-and-retirement.md R-S2d-4: known survivors named — src/state-dir.ts and the CliError base class residue behind src/auth/errors.ts and the v8 error mapping. - s2b-resources.md D1: build-time test requirement that the family maps and the mount map cover the same command set. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Telemetry docs URL, config-enrichment drop, disclosure timing — each built to a stated default awaiting ratification. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
… line Operator ruling 2026-08-10: this repo takes over prisma@8.0.0-rcX, so it adopts prisma/prisma's versioning scripts AND its version number. Ports determine-version / set-version / bump-version (+ pure-helper tests, run via the new root test:scripts) from wip/repos/prisma, adapted to node:path and this repo's package set. Stamps 8.0.0-rc.1 in lockstep across the root, cli, cli-engine, cli-telemetry, and tsconfig manifests with workspace:8.0.0-rc.1 internal pins (the reference's convention). @prisma/compute is hard-excluded from the lockstep (second ruling: it versions independently pending extraction); its manifest moves to its honest npm state 0.1.0-beta.0 and resolve-package-version.mjs survives trimmed to the dev/next-beta commands publish-compute.yml still uses, with its test moved into the script test suite (the cli-package copy is deleted). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…ion workflow Ports publish.yml from the reference verbatim per the operator ruling (2026-08-10): a push to main with the root version unchanged publishes <base>-dev.N under the dev dist-tag; a push that changes the root version (a merged bump PR) publishes the committed base under latest for BOTH @prisma/cli-engine and @prisma/cli (engine first — the cli depends on it) plus a GitHub Release marked pre-release on the rc line. The operator's words: merging a version bump PR counts as a deliberate explicit action to alter latest. workflow_dispatch keeps the chosen dist-tag + dry-run escape hatch. publish-cli.yml is deleted whole — both its jobs are superseded. The PR preview drops version stamping and copies the reference's pkg.pr.new model (the committed rc base ships as-is at per-commit URLs); the engine is published alongside the cli so its workspace pin resolves to the preview build. pr-quality's test job now runs the ported script tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Adapts prisma/prisma's docs/oss/versioning.md to this repo (package names, the verbatim latest model, the @prisma/compute exclusion pending extraction — operator rulings 2026-08-10). README/CONTRIBUTING publish sections and ADR 0001's status now point at the committed-version model; the S2a contract carries a one-line erratum (engine version 0.1.0 -> 8.0.0-rc.1); the rollout plan's step 2 and its latest invariant are reworded per the ruling — latest moves only through a deliberately merged version-bump PR (or manual dispatch), superseding the earlier next-tag interim. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The v8 telemetry suites pointed only XDG_CONFIG_HOME at their temp dir, but on win32 userConfigPath() resolves from APPDATA first, so every read and write on the Windows runner hit the real %APPDATA%\prisma-next\config.json. That file is never cleaned between tests, so earlier cases leaked stored ids and consent choices into later ones — the six Windows-only failures. Point APPDATA at the same temp dir alongside XDG_CONFIG_HOME and restore both afterwards; expected paths already derive from userConfigPath(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Operator ruling 2026-08-10: a version change alone must not move latest — merging PR #130 jumps the lockstep to 8.0.0-rc.1 but only a deliberately merged 'chore(release): ...' bump PR publishes a release. Any other version-changing merge publishes a dev build, loudly. pkg.pr.new previews are unaffected and already cover both packages. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The release procedure's step 1 is now the ported skill, not a bare script invocation: fresh worktree off origin/main, pnpm bump-version, lockfile refresh, diff sanity check, and the release PR. Adapted for this repo: the PR title must carry the chore(release) marker because squash merges make the PR title the commit subject the publish workflow checks; compute exclusion and generated release notes noted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
… prisma/prisma Operator ruling: the publish machinery must match prisma/prisma exactly so it never needs remembering. The transient problem the gate solved (the lockstep-adoption merge changing the root version without being a release) is handled by sequencing instead: a root-version pre-PR lands on main under the old workflows first, so this branch's merge shows no version change to the new workflow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The use- prefix read as a React hook. The operation switches the active workspace session — its own presenter already says so. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…iClient The name was wrong twice: 'Compute' is branding residue that now collides with the unrelated @prisma/compute package, and 'require' implied a throw where the function returns null. It resolves an authenticated management API client (service token, else stored OAuth with refresh) or null. Legacy-shell-only; dies with it in S2d. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Import ordering and line reflow from the longer identifier. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The engine-modeled credential manager: Identity/Credential/Session/ Scope entities, the scalar session invariant, the manager API, engine integration replacing Runtime.getCredentials, the ruled auth command tree, runtime flows, and the open ends for the design review. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Operator question answered in the doc: workspace switch = re-login (replace); service token = env override; no multi-account registry; the parallel-terminals trade-off stated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
There was a problem hiding this comment.
Actionable comments posted: 19
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.drive/projects/prisma-cli-v8/specs/s2b-design/conventions.md:
- Around line 263-279: Update the “Tests” harness guidance around createTestCli
and the v8-auth.test.ts reference to remove the required ../src/auth mock and
specify the current ctx.activeCredential() seeding or mocking contract, ensuring
resource-command tests provide the workspace credential source they require.
In @.drive/projects/prisma-cli-v8/specs/s2b-design/d1-project.md:
- Around line 286-291: Remove command-owned confirm flag declarations from
project remove in .drive/projects/prisma-cli-v8/specs/s2b-design/d1-project.md
lines 286-291 and project transfer lines 313-319; remove the declarations from
postgres restore in
.drive/projects/prisma-cli-v8/specs/s2b-design/d2-postgres.md lines 343-345,
postgres remove lines 387-388, postgres connection rotate lines 486-487, and
postgres connection remove lines 520-521. In d2-postgres.md lines 104-122,
replace the obsolete helper, mapper error-code, metadata, and
requirePostgresConfirmation requirements with the parent engine-owned shared
--confirm consent contract.
In @.drive/projects/prisma-cli-v8/specs/s2b-design/d3-bucket-branch-git.md:
- Around line 386-391: Update the test-list bullet in the D3 bucket-branch Git
design document to remove the three-event “endpoint → status waiting → status
connected” assertion and describe the single endpoint event instead, matching
the pinned rule and shipped test behavior. Leave the other listed test cases
unchanged.
In @.drive/projects/prisma-cli-v8/specs/s2b-design/facts/facts-d2-postgres.md:
- Line 44: Correct the statement describing resolveProjectTarget in the Postgres
facts so it no longer claims that PRISMA_PROJECT_ID is allowed or affects these
commands. Document that requireDatabaseContext invokes resolveProjectTarget
without envProjectId, while preserving the listed resolution order and error
mappings.
In
@.drive/projects/prisma-cli-v8/specs/s2b-design/facts/facts-d3-bucket-branch-git.md:
- Around line 1-3: Remove developer-specific absolute workstation and worktree
paths from the facts metadata. In
.drive/projects/prisma-cli-v8/specs/s2b-design/facts/facts-d3-bucket-branch-git.md
lines 1-3, replace the source path with a repository-relative path; make the
same replacement in
.drive/projects/prisma-cli-v8/specs/s2b-design/facts/facts-v8-patterns.md lines
1-3, preserving the surrounding branch and provenance details.
In `@packages/cli/src/v8/bucket/delete.ts`:
- Line 44: Replace the hardcoded binary names in
packages/cli/src/v8/bucket/delete.ts#L44-L44 and both occurrences in
packages/cli/src/v8/git/connect.ts#L181-L182 with CLI_NAME-derived command
strings, following the existing naming pattern so user-facing guidance remains
correct if the published binary name changes.
In `@packages/cli/src/v8/bucket/key-delete.ts`:
- Around line 35-52: Add an exact confirmation gate in the handler before
calling deleteKey, using keyId as the consent token via ctx.prompt.consent;
retain the existing validation and credential requirement. Document the
--confirm <key-id> option for this command and add tests covering successful
matching consent and rejection of missing or mismatched confirmation.
In `@packages/cli/src/v8/bucket/list.ts`:
- Line 40: Sanitize tab and newline characters in every cell before emitting
tab-joined rows. Update the stdout mapping in
packages/cli/src/v8/bucket/list.ts#L40-L40 for bucketRows(result.buckets) and
packages/cli/src/v8/bucket/key-list.ts#L33-L33 for bucketKeyRows(result.keys),
using an identical shared helper in packages/cli/src/v8/bucket/presentation.ts
so downstream pipe consumers receive one stable row per bucket or key.
In `@packages/cli/src/v8/git/connect.ts`:
- Around line 65-97: Initialize inspectableInstallationCount from the first
inspect(ctx.signal) result before handling first.match, while preserving the
existing immediate return for a match. Keep the poll callback updating the count
from later inspections so timeout handling passes the latest known value to
installWaitFailedError and selects the correct error outcome.
In `@packages/cli/src/v8/git/context.ts`:
- Line 34: Document the intentional cast in the return statement of the
surrounding context function: explain that the SDK client supports the required
source-repository paths and request shapes, and that the cast adapts it to the
local narrowed SourceRepositoryApiClient contract. Keep the existing cast and
behavior unchanged.
In `@packages/cli/src/v8/project/context.ts`:
- Around line 38-50: Update refuseUnknownReads so the Proxy get trap allows the
string key "then" to pass through via Reflect.get, alongside existing allowed
keys and symbols. Continue throwing the adapter error for all other unknown
string properties.
In `@packages/cli/src/v8/project/create.ts`:
- Around line 49-60: Update the catch handler around createProject to check
ctx.signal.aborted first and rethrow the original cancellation error when true;
only construct projectCreateFailedError for non-cancellation failures.
In `@packages/cli/src/v8/project/env-list.ts`:
- Line 54: The stdout presentation currently reuses decorated variableRows,
producing keys with source labels that break piping. Add and export a raw-row
builder named variableStdoutRows in env-shared.ts, update listPresentations to
use it for stdout while retaining variableRows for the human table, and include
the new symbol in the import.
In `@packages/cli/src/v8/project/link.ts`:
- Around line 104-112: In the CREATE_CHOICE branch, trim the value returned by
ctx.prompt.text before using it. Validate the trimmed name with
isValidProjectSetupName, return projectSetupNameRequiredError("project link")
for invalid input, and pass the trimmed value to createProjectForLink.
In `@packages/cli/src/v8/project/transfer.ts`:
- Around line 203-224: Normalize both recipient flag values with trim before the
validation block, then use those normalized values for the mutually exclusive
and missing-recipient checks. Update the subsequent transferPresentations call
to receive the normalized workspace value so whitespace-only --to-workspace
behaves as absent and a valid --recipient-token is used.
In `@packages/cli/src/v8/resources-shared/workspace.ts`:
- Around line 31-38: Update the workspace ID validation in the activeCredential
handling to reject blank or whitespace-only values using a trimmed non-blank
check. Preserve the existing workspaceRequiredError behavior for invalid IDs,
and use the validated workspace ID when constructing the returned object.
In `@packages/cli/tests/v8-bucket.test.ts`:
- Around line 57-178: Extract the duplicated v8 command-test scaffolding into
one shared test helper module. In packages/cli/tests/v8-bucket.test.ts lines
57-178, move Call, Responder, apiFailure, pinnedCwd, unpinnedCwd, resultFrame,
and blocks into the helper, parameterizing the temporary-directory prefix, and
retain only bucket-specific routes and fixtures. In
packages/cli/tests/v8-branch.test.ts lines 34-131 and
packages/cli/tests/v8-git.test.ts lines 76-235, import the shared helpers and
remove local copies while retaining branchClient routes, or errorOf,
tickingClock, and git-specific fixtures and routes respectively.
In `@packages/cli/tests/v8-git.test.ts`:
- Around line 829-856: Align the git authentication error contract with design
§2.1: remove the 401/403-to-GIT.AUTH_REQUIRED mapping from the git error mapper
and update this test to expect CLI.CREDENTIALS_REQUIRED with its corresponding
envelope, unless the design and divergence documentation are explicitly amended
to preserve GIT.AUTH_REQUIRED.
In `@packages/cli/tests/v8-legacy-context.test.ts`:
- Around line 64-78: Add a test in the legacy context adapter suite that
accesses a symbol property on the context and verifies it passes through the
proxy without throwing the adapter error. Use a symbol key and assert the
resulting value or access behavior, covering the typeof key !== "string" guard
in legacyOperationContext while preserving the existing runtime and top-level
rejection tests.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 260b82f0-c91e-414b-83a4-1f830df78bd1
📒 Files selected for processing (83)
.drive/projects/prisma-cli-v8/assets/briefs/s2b-engine-requests.md.drive/projects/prisma-cli-v8/assets/briefs/s2b-midslice-handover.md.drive/projects/prisma-cli-v8/assets/briefs/windows-ci-credential-manager.md.drive/projects/prisma-cli-v8/assets/s2/parity-divergences-s2b.md.drive/projects/prisma-cli-v8/reviews/code-review.md.drive/projects/prisma-cli-v8/specs/s2b-design/conventions.md.drive/projects/prisma-cli-v8/specs/s2b-design/d1-project.md.drive/projects/prisma-cli-v8/specs/s2b-design/d2-postgres.md.drive/projects/prisma-cli-v8/specs/s2b-design/d3-bucket-branch-git.md.drive/projects/prisma-cli-v8/specs/s2b-design/facts/facts-d1-project.md.drive/projects/prisma-cli-v8/specs/s2b-design/facts/facts-d2-postgres.md.drive/projects/prisma-cli-v8/specs/s2b-design/facts/facts-d3-bucket-branch-git.md.drive/projects/prisma-cli-v8/specs/s2b-design/facts/facts-v8-patterns.md.drive/projects/prisma-cli-v8/specs/s2b-resources.mdpackages/cli/src/controllers/app-env.tspackages/cli/src/controllers/branch.tspackages/cli/src/controllers/database.tspackages/cli/src/controllers/project.tspackages/cli/src/presenters/app-env.tspackages/cli/src/presenters/project.tspackages/cli/src/v8/branch/errors.tspackages/cli/src/v8/branch/list.tspackages/cli/src/v8/bucket/context.tspackages/cli/src/v8/bucket/create.tspackages/cli/src/v8/bucket/delete.tspackages/cli/src/v8/bucket/errors.tspackages/cli/src/v8/bucket/key-create.tspackages/cli/src/v8/bucket/key-delete.tspackages/cli/src/v8/bucket/key-list.tspackages/cli/src/v8/bucket/list.tspackages/cli/src/v8/bucket/presentation.tspackages/cli/src/v8/cli.tspackages/cli/src/v8/git/connect.tspackages/cli/src/v8/git/context.tspackages/cli/src/v8/git/disconnect.tspackages/cli/src/v8/git/errors.tspackages/cli/src/v8/postgres/backup-list.tspackages/cli/src/v8/postgres/connection-create.tspackages/cli/src/v8/postgres/connection-list.tspackages/cli/src/v8/postgres/connection-remove.tspackages/cli/src/v8/postgres/connection-rotate.tspackages/cli/src/v8/postgres/context.tspackages/cli/src/v8/postgres/create.tspackages/cli/src/v8/postgres/errors.tspackages/cli/src/v8/postgres/list.tspackages/cli/src/v8/postgres/presentation.tspackages/cli/src/v8/postgres/remove.tspackages/cli/src/v8/postgres/restore.tspackages/cli/src/v8/postgres/show.tspackages/cli/src/v8/postgres/usage.tspackages/cli/src/v8/project/context.tspackages/cli/src/v8/project/create.tspackages/cli/src/v8/project/env-add.tspackages/cli/src/v8/project/env-list.tspackages/cli/src/v8/project/env-remove.tspackages/cli/src/v8/project/env-shared.tspackages/cli/src/v8/project/env-update.tspackages/cli/src/v8/project/errors.tspackages/cli/src/v8/project/link.tspackages/cli/src/v8/project/list.tspackages/cli/src/v8/project/presentation.tspackages/cli/src/v8/project/remove.tspackages/cli/src/v8/project/rename.tspackages/cli/src/v8/project/show.tspackages/cli/src/v8/project/transfer.tspackages/cli/src/v8/resources-shared/workspace.tspackages/cli/tests/branch.test.tspackages/cli/tests/bucket.test.tspackages/cli/tests/database-plan-limit.test.tspackages/cli/tests/database.test.tspackages/cli/tests/project-controller.test.tspackages/cli/tests/project-mutations.test.tspackages/cli/tests/project-real-mode.test.tspackages/cli/tests/project.test.tspackages/cli/tests/v8-branch.test.tspackages/cli/tests/v8-bucket.test.tspackages/cli/tests/v8-git.test.tspackages/cli/tests/v8-golden-rendering.test.tspackages/cli/tests/v8-legacy-context.test.tspackages/cli/tests/v8-mount-coverage.test.tspackages/cli/tests/v8-postgres.test.tspackages/cli/tests/v8-project.test.tspackages/cli/tests/v8-update-check.test.ts
💤 Files with no reviewable changes (7)
- packages/cli/tests/bucket.test.ts
- packages/cli/tests/project-controller.test.ts
- packages/cli/tests/project-mutations.test.ts
- packages/cli/tests/project-real-mode.test.ts
- packages/cli/tests/project.test.ts
- packages/cli/tests/branch.test.ts
- packages/cli/tests/database.test.ts
The stdout lane carries data, not decoration. "Table data rows go to
stdout" was read as "the cells the human table renders", so project env
list piped STRIPE_KEY (project) and a consumer would have to split on
" (" to get the key back — which defeats the reason the lane exists.
stdout takes the bare key; --json still carries the source.
And cancellation is never remapped: a handler wrapping a rejected
operation must rethrow first when the signal aborted, so a cancelled run
settles as cancelled instead of as a failure of whatever it was doing.
Two sites do this, project create and project link.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…ments CodeRabbit flagged absolute paths from a contributor's machine committed to a public repository. Every one is replaced with a repository-relative path and the branch name, which is what the reader actually needs. The review named two fact sheets; a sweep of `.drive/` found six files with the same header. All six are fixed: the four s2b-design fact sheets, `assets/s2/command-inventory.md`, and `assets/briefs/credential-manager-handover.md`. The last two are outside this slice's usual scope — the inventory is a shared S2 asset and the handover brief belongs to the auth stream — but the defect and the remedy are identical and leaving a known leak in place was not worth the tidiness. `grep -rn "/Users/" .drive/` is now empty. Verification: docs only, no code touched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The two real defects CodeRabbit found on PR #133, both amended into conventions §8, plus two smaller items. Cancellation is no longer remapped. `project create` and `project link` both `.catch` a rejected `createProject` and wrap it in PROJECT.CREATE_FAILED, so an aborted run reported that creating the project had failed. Both sites now check `ctx.signal.aborted` first. They rethrow `ctx.signal.reason` rather than the caught error: the app provider flattens the underlying AbortError into a plain Error, which the engine would settle as a bug at exit 1, so handing back the signal's own reason is what lets it settle the run as cancelled at exit 130. A case for each proves it. `project env list`'s stdout no longer carries a decorated key. The human table's first cell is `${key} (${source})` and stdout reused it, so a piped line read `STRIPE_KEY (project)` and a consumer had to split on `" ("` to recover the key. stdout gets its own rows carrying the bare key; the table keeps the decoration and `--json` keeps the source. Per the amendment I checked every other list command's stdout rows rather than only the one that was caught. `branch list`, `bucket list`, `bucket key list`, `postgres connection list` and `project list` are clean. Two are borderline and I left them alone rather than change a pinned stdout format on my own judgement — they are in the report for a ruling: `postgres list` substitutes isDefault into the status column when status is null, and `postgres backup list` renders a byte count as "2.0 KiB", which a consumer cannot reverse. The proxy added last night refused the string key `then`, which the runtime reads on anything it resolves through a promise — the same failure mode it exists to remove. `then` now passes through like symbols, with a test that probes the adapter and awaits it. `bucket delete` and `git connect` build their user-facing command strings from CLI_NAME instead of a hardcoded `prisma-cli`. Verification, all green: pnpm build, @prisma/cli-engine test, @prisma/cli test, @repo/cli-telemetry test, typecheck, lint. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
… code
Five places where a design document still described something the code
no longer does. Doc-only; no behaviour changes.
conventions §10's test-harness bullet still seeded `credentials: { token }`
and required mocking the auth module for the workspace read. Neither
survives the credential-manager merge-down — the workspace comes from
`ctx.activeCredential()`, which the harness serves from seeded sessions —
so a test following the old instruction would leave resource commands
with no workspace at all.
d1 and d2 still declared per-command `confirm` flags and the obsolete
`*.CONFIRMATION_REQUIRED` mapper rows. Both now carry the same
document-level supersession block d3 has, and the declarations and mapper
rows are struck at their own sites rather than deleted, so the sections
stay usable as the copy source. The per-section notes they already had
were not enough: the review read the surviving declarations as binding.
d3's `git connect` test bullet still prescribed the three-event sequence
struck in §3.8, and it sat outside the block marked superseded. It now
names the single endpoint event the shipped test asserts.
d3 §2.1 said the legacy 401/403 to AUTH_REQUIRED mapping "does not port",
which contradicted divergence 40 and the shipped test. It now says what
happens: the engine settles a genuine sign-in failure before the handler
runs, and the 403 permission residue that still arrives maps mechanically
to GIT.AUTH_REQUIRED.
facts-d2-postgres.md claimed resolution honours PRISMA_PROJECT_ID. I
checked the source rather than the sheets: the variable is read only in
controllers/app.ts, for app deploy and app run, and
`requireDatabaseContext` passes no `envProjectId`, so the option is inert
for these commands. The d2 sheet was wrong and the d1 sheet right; d2 is
corrected and now cites d1.
Verification, all green: pnpm build, @prisma/cli-engine test,
@prisma/cli test, @repo/cli-telemetry test, typecheck, lint.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
The stdout sweep found two values a pipe consumer cannot use that the amendment does not actually reach: a backup size printed as 2.0 KiB, which will not turn back into 2048, and a status column that holds isDefault when the status is null, so it means different things on different rows. Neither glues two facts into one cell, which is what the amendment is about. Both are left as they are and recorded for the operator. Making stdout carry machine-readable values everywhere is a bigger decision than the one already taken: it reaches sizes, timestamps and status columns across every group, and --json is already the lossless lane. That is a call to make deliberately, not one to slip into a closure pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
S2a landed on main as a squash (#130), so main carries its content without its commits. This branch already had those commits from the earlier merge, which is why the overlap resolved cleanly on content. Eight conflicts, all resolved toward the state this branch already holds, checked one at a time rather than by taking a side wholesale: - v8/cli.ts: kept the exported spec constants and all 40 mounted commands; main's inline version is the pre-slice shape. - The three .drive documents: kept this branch's, which are newer and carry the removal of the committed workstation paths. - v8-golden-rendering.test.ts: this branch has main's three entries plus the masked-secret one; the only text main had that this branch lacked was the file header, which was deliberately rewritten to list four surfaces. - v8-update-check.test.ts: this branch's version spreads the original module before overriding, a superset of main's. - project-controller.test.ts: deleted here, import-path updated there. Deletion stands; the change was mechanical. - project-real-mode.test.ts: main still holds three git cases this branch deleted once their v8 equivalents existed. Kept the deletions and main's mock-path updates in the five surviving cases. Verified on the merge: build, cli-engine test, cli test at 62 files and 1006 tests, cli-telemetry test, typecheck and lint all green.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/cli/src/v8/project/create.ts (1)
58-67: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUse the shared
CLI_NAMEfor project recovery commands.Both handlers hard-code
prisma-cliin recovery guidance. This violates theCLI_NAMEcontract and can produce invalid commands when the executable name differs.
packages/cli/src/v8/project/create.ts#L58-L67: InterpolateCLI_NAMEinnextStepsandfallbackFix.packages/cli/src/v8/project/link.ts#L82-L91: InterpolateCLI_NAMEinnextStepsandfallbackFix.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/src/v8/project/create.ts` around lines 58 - 67, Replace hard-coded prisma-cli prefixes with the shared CLI_NAME in recovery guidance: update nextSteps and fallbackFix in projectCreateFailedError within packages/cli/src/v8/project/create.ts (lines 58-67), and apply the same change to the corresponding project-link error handler in packages/cli/src/v8/project/link.ts (lines 82-91). Preserve the existing command arguments and guidance text.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.drive/projects/prisma-cli-v8/specs/s2b-resources.md:
- Around line 133-138: Update the list stdout contract in specs/s2b-resources.md
so backup sizes use stable raw numeric values and null statuses use an explicit
machine-readable representation instead of localized text or isDefault;
alternatively, remove these commands from the pipe-safe contract and its
acceptance criteria.
In `@packages/cli/src/v8/project/context.ts`:
- Around line 45-46: Update the proxy get logic around the key check in the
context adapter to use an own-property check on target instead of key in target,
so inherited Object.prototype keys reach the adapter error path while exposed
own properties still pass through. Preserve the PROBE_KEYS then allowlist, and
add a regression test covering an inherited key such as toString or constructor.
---
Outside diff comments:
In `@packages/cli/src/v8/project/create.ts`:
- Around line 58-67: Replace hard-coded prisma-cli prefixes with the shared
CLI_NAME in recovery guidance: update nextSteps and fallbackFix in
projectCreateFailedError within packages/cli/src/v8/project/create.ts (lines
58-67), and apply the same change to the corresponding project-link error
handler in packages/cli/src/v8/project/link.ts (lines 82-91). Preserve the
existing command arguments and guidance text.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: f9fe6799-f1cc-494d-9f4b-2a64abcbfb59
📒 Files selected for processing (20)
.drive/projects/prisma-cli-v8/assets/briefs/credential-manager-handover.md.drive/projects/prisma-cli-v8/assets/s2/command-inventory.md.drive/projects/prisma-cli-v8/specs/s2b-design/conventions.md.drive/projects/prisma-cli-v8/specs/s2b-design/d1-project.md.drive/projects/prisma-cli-v8/specs/s2b-design/d2-postgres.md.drive/projects/prisma-cli-v8/specs/s2b-design/d3-bucket-branch-git.md.drive/projects/prisma-cli-v8/specs/s2b-design/facts/facts-d1-project.md.drive/projects/prisma-cli-v8/specs/s2b-design/facts/facts-d2-postgres.md.drive/projects/prisma-cli-v8/specs/s2b-design/facts/facts-d3-bucket-branch-git.md.drive/projects/prisma-cli-v8/specs/s2b-design/facts/facts-v8-patterns.md.drive/projects/prisma-cli-v8/specs/s2b-resources.mdpackages/cli/src/v8/bucket/delete.tspackages/cli/src/v8/git/connect.tspackages/cli/src/v8/project/context.tspackages/cli/src/v8/project/create.tspackages/cli/src/v8/project/env-list.tspackages/cli/src/v8/project/env-shared.tspackages/cli/src/v8/project/link.tspackages/cli/tests/v8-legacy-context.test.tspackages/cli/tests/v8-project.test.ts
database to postgres
… name Two inconsistencies the review loop turned up, both where the same value was treated differently by two pieces of the same command. project transfer read --to-workspace raw for the mutual-exclusion check and trimmed for the missing-recipient check, so `--to-workspace " " --recipient-token <token>` was rejected as passing both when the user had passed one. Both flags are now normalized once, before either check. project link's interactive path passed the prompted name straight to creation, while project create validates and trims the same value first. A name is no more valid for having been typed at a prompt, so link now applies the same rule. Also documents the double cast in the git context: the legacy source-repository helpers take a structurally compatible but separately declared client type, which is why the compiler needs it spelled out. Verified: cli test 1006 passed, typecheck and lint green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
code-review.md is a review workspace — scoreboards, findings, round notes — not a document the repository should carry. It was already tracked when this branch started and I added to it instead of asking whether it belonged there. Removed from the index and left on disk, and .gitignore now covers both review directories and wip/, so neither this file nor the closure-pass artifacts nor anything under wip/ can be committed again. wip/ also means biome stops linting scratch files, which failed a build earlier tonight. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…pace listRealWorkspaceProjects read only `data` from the SDK response and threw away `error` and `response`, so any non-2xx became an empty list. `project list` printed "No projects found." and exited 0 while the API was refusing the request — indistinguishable from a workspace that genuinely has no projects. Because resolveProjectTarget resolves names through the same function, every command that resolves a project by name reported "Choose a Project" or a not-found for the same reason. Reproduced before fixing, by pointing the CLI at an API where every request 404s: "No projects found.", exit 0. After: PROJECT.API_ERROR, exit 2, "The Management API returned status 404." This is a legacy body change, which this slice otherwise avoids, and it changes the old shell's behaviour too. Both are intended: reporting a refusal as a success is not a behaviour anyone chose, and the database, branch, bucket, app and env controllers read through the same function. The case that previously pinned the defect now proves the fix. Divergence 46 is restated as a divergence in the other direction, and the slice contract's open-items list drops from three to two. Verified: cli test 1006 passed including the legacy suite, typecheck and lint green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
Inserting projectApiError put the import block out of sort order, which biome treats as an error, and dropped an already-unused FileTokenStorage import in passing. I pushed the previous commit without noticing because the verification chained off an echo rather than off lint's exit code, so a red lint reported as green. Verified properly this time: lint, typecheck and cli test at 1006 all exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The Option A channel ruling of 2026-08-09 makes the human Blocks presentation prose on stderr and the `Presentations.stdout` lines the machine-usable payload. So no human formatting and no placeholder may reach a stdout row: an absent value is an empty field, and where the two lanes differ the command builds two sets of rows, as `project env list` already did. The human tables and cards are untouched and `--json` remains the lossless record. What changed on stdout. `project list`: an absent default region is empty, not `none`. `project show`: the local repo path is raw rather than shortened to `~`, the single `platform: <workspace> / <project>` line becomes a `workspace` line and a `project` line, and an unlinked directory leaves the project field empty instead of saying `Not linked`. `postgres list`: absent branch and region are empty, and the status field carries the raw status — `isDefault` is a different fact and does not belong in that column, so an absent status is empty there too. `postgres show`: the same three. `postgres usage`: the period becomes `period start` and `period end` instead of one glued sentence, each metric carries its number without its unit, and an absent bound or timestamp is empty. `postgres backup list`: the size is the byte count, not `2.0 KiB`. `postgres connection list` and `bucket list`: absent timestamp and branch are empty. The sweep covered every stdout producer in the slice, not just the listed ones. `branch list` and `bucket key list` needed no change — every cell was already a raw required field — and the four one-line secret payloads were already raw. Two placeholders survive and this slice cannot remove them: `postgres backup list`'s `backupType` and `status` are the literal string `unknown` when the API omits them, because `normalizeBackupList` in `lib/database/provider.ts` substitutes that word in the operation layer, before any presentation runs. Removing it is a legacy body change. Divergence 47 records the whole change and that gap. `postgres show`, `postgres usage`, `postgres backup list` and `project show` had no stdout assertion at all, so their existing success cases gained one rather than leaving four changed surfaces unproven. Verification, each judged on its own exit code, all 0: pnpm build, @prisma/cli-engine test, @prisma/cli test, @repo/cli-telemetry test, typecheck, lint. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
…own" The last two placeholders the stdout sweep could not remove, because they were not in the presentation layer at all. normalizeBackupList substituted "unknown" for a missing backupType or status, so the word reached the json envelope as though the API had said it — the machine lane, where a consumer cannot tell it from a backup whose type really is that word. The same function already carried an absent size as null and an absent timestamp as empty, so it was inconsistent with itself. Absence is now carried, and the human table supplies the word, which is where a placeholder belongs. The rendered table is unchanged. Also records the two design corrections behind this pass: conventions §8 now quotes the Option A channel ruling of 2026-08-09 rather than the weaker rule I invented from it, and the slice contract no longer lists the stdout format as an open decision, because it never was one. Verified separately: build, cli-engine test, cli test at 1006, cli-telemetry test, typecheck and lint all 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
It declared needs.interaction, so the engine failed any non-interactive invocation before the handler ran — including the ones the legacy command completed happily, where the repository was already connected or the GitHub app already installed. That declaration was ruled when the engine had no interaction error of its own and the only alternative was a command reading TTY state, which is banned. prompt.browserWait now refuses a non-interactive session itself and names the install URL, so the need bought nothing and cost every scripted run that never reaches the wait. A non-interactive run that does need the wait settles the engine's CLI.INTERACTION_REQUIRED, whose summary carries the install URL. That is a divergence from the legacy REPO_INSTALLATION_REQUIRED, recorded as entry 38, and the two cases now prove both halves: a scripted run that needs nothing connects, and one that needs the wait fails there rather than up front. Operator ruling 2026-08-11. The slice contract now has nothing recorded but unfixed. Verified separately: build, cli-engine test, cli test at 1007, cli-telemetry test, typecheck and lint all 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
S2b (#133) moved the resource commands onto the engine and renamed database to postgres. The one conflict is packages/cli/tests/bucket.test.ts, deleted there with the ported command and touched here only by the repo-wide lint pass; the deletion wins. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
The CLI is moving onto
@prisma/cli-engine, the library that owns a run from argv to exit code. This PR moves 31 resource commands across and renames thedatabasegroup topostgres.Here is what "on the engine" means, shown as one command in both of its output lanes:
The identical run with
--json:{ "ok": true, "commandId": "project.list", "result": { "context": { "workspace": "Will's Prisma Workspace" }, "items": [], "count": 0, "localBinding": { "status": "not-linked" } }, "exitCode": 0, "diagnostics": [], "nextActions": [ { "kind": "run-command", "label": "Link the chosen Project", "command": "prisma-cli project link <id-or-name>", "reason": "Linking writes the durable local Project binding for this directory." } ] }Every command here produces that shape. The human lane and the machine lane are two renderings of one result, not two code paths — so a follow-up step is a typed action with a reason attached rather than a sentence a caller has to parse, and the exit code is part of the result rather than something set on the way out.
Nothing changes for users yet
This is worth saying before anything else, because it sets how much risk is in the diff: the published CLI is unchanged. The package still declares exactly one binary,
prisma-cli, still pointing at the old shell. The ported commands run through a second entry point that only exists inside this repo, reached bypnpm prisma-v8 …. Swapping the binary over is a separate, later change.So this PR adds a parallel implementation and its tests. It does not switch anyone onto it.
What a command looks like now
One file per command, holding both its definition and its handler. The handler does not reimplement any API flow — it calls the same controller and provider functions the old shell calls, through a client the engine constructs and owns.
That is the single most useful thing to know when reading the diff: it is large, but almost none of it is new behaviour. It is command definitions, presentation, and tests, sitting on top of operations that already existed and are unchanged.
What the engine takes over
Errors. Flat codes become dotted ones scoped to their group —
PROJECT_NOT_FOUNDbecomesPROJECT.NOT_FOUND,DATABASE_BACKUP_NOT_FOUNDbecomesPOSTGRES.BACKUP_NOT_FOUND. The wording is carried over as it stands. Two phrases are rewritten because they describe machinery the new runtime does not have:--tracebecomes--log-level verbose, and the offer to "rerun the command in a TTY to sign in interactively" is dropped, since there is no auto-login to rerun into.Exit codes. Every failure now exits 2. Most of these paths exited 1, and a few exited 0 while reporting a problem.
Consent. Seven destructive commands — removing a project or a database, transferring a project, restoring a database, rotating or removing a connection, deleting a bucket — ask you to type the exact resource id. Scripts pass
--confirm <id>exactly as before. The difference is that the prompt, the scripted grant and the refusal are now one implementation the engine injects, rather than seven flags each command declared and could drift on.--yesdeliberately does not satisfy it.Waiting.
git connectstill waits for you to approve a GitHub App installation, but it hands the engine the URL, the question to poll and the cadence, instead of running its own loop. The announcement, the browser open and the clock all live in one place.Secrets. One-time connection URLs and bucket access keys are the only thing on stdout, so
prisma-cli postgres create db | pbcopygives you the bare URL, while the card printed beside it shows the value masked.The rename
databasebecomespostgresthroughout: every path, command id, help string, example, and every command reference inside error text. There is no alias to the old name.The word "database" survives where it is the noun rather than the group — these are still Prisma Postgres databases, and
postgres show <database>still takes one.What is and is not in scope
In:
projectincludingproject env,postgresincludingbackupandconnection,bucketincludingbucket key,branch list, andgit connect|disconnect.Not in: the
service,app,build,agentandfeedbackgroups,init, deleting the old shell, and the binary cutover. The old shell is untouched and still serves everything this PR does not cover.Reviewing this
Every behavioural difference from the old commands is recorded — one entry per change, one row per command — in
parity-divergences-s2b.md. The three most worth arguing with: auto-login is gone, so an unauthenticated run reports it rather than opening a browser;project env removeloses itsrmalias; andgit connectnow refuses to run non-interactively at all, where before it sometimes succeeded.Three known problems are recorded rather than fixed, because each needs a decision rather than a patch.
project listreports an empty workspace at exit 0 when the API actually rejects the request — inherited from the old shell, and it reaches every command that resolves a project by name.git connectrefuses non-interactive runs even when no waiting would have been needed. And two stdout values are still formatted for humans, so a pipe consumer cannot use them: a size printed as2.0 KiB, and a status column that holds a different fact when the status is null.Changes to existing files: 43
exportkeywords, no changed function bodiesSo the new commands can call code that already exists:
controllers/app-env.ts—resolveEnvWriteSource,resolveEnvWriteInput,resolveScopeToApi,resolveListScopeToApi,formatScopeFlag,listVariables,listOverviewVariablescontrollers/branch.ts—RawBranchRecord,sortBranches,listBranches,toBranchSummarycontrollers/database.ts—parseUsageDate,parseBackupLimit,resolveDatabase,ensureProjectId,sortDatabases,defaultConnectionNamecontrollers/project.ts—GITHUB_INSTALL_POLL_INTERVAL_MS,GITHUB_INSTALL_POLL_TIMEOUT_MS,readProjectListLocalBinding,transferRecipientRequiredError,transferRecipientUnavailableError,cleanupLocalPinForProject,rewriteOrClearLocalPinForProject,InstalledRepositoryMatch,SourceRepositoryApiError,SourceRepositoryApiClient,findRepositoryInInstallations,readPositiveIntegerEnv,listScmInstallations,createGitHubInstallIntent,readFirstSourceRepository,toRepositoryConnection,unsupportedRepositoryProviderError,repoNotConnectedError,repoInstallationRequiredError,repoNotAccessibleError,repoAlreadyConnectedError,repositoryFullNamesMatch,repoConnectionApiErrorpresenters/app-env.ts—scopeLabel,listTargetLabelpresenters/project.ts—formatGitConnectionDetailThe old shell's fixture tests for the ported commands are deleted. Unit tests for helpers and providers the new commands still call are kept.
Alternatives considered
Keeping a
databasealias. Rejected. The point of the rename is one name per concept, and an alias keeps the old one alive in help, in documentation and in muscle memory indefinitely.Leaving
--confirmon each command. Rejected. That is seven implementations of one prompt, each free to drift, and scripted callers get one consistent behaviour out of the engine version.Hand-rolling the installation poll in
git connect. Rejected. It would duplicate the announcement, the browser open and the clock, and this would have been the third copy of that pattern.Rewriting the operations onto the engine instead of calling them. Rejected for this PR, and worth explaining because it is the biggest judgement call here. Doing both at once would mix a runtime migration with a behavioural rewrite, and make the parity record above impossible to check — every difference would be attributable to either change. It is also the wrong order: the tests this PR adds are what make a later rewrite safe to attempt, because they pin the behaviour from outside. That rewrite is planned as its own change, before the next group of commands is ported.