Skip to content

Port init, delete the Commander shell: the CLI runs entirely on the engine - #139

Merged
wmadden-electric merged 25 commits into
mainfrom
s2d-init-and-retirement
Aug 12, 2026
Merged

Port init, delete the Commander shell: the CLI runs entirely on the engine#139
wmadden-electric merged 25 commits into
mainfrom
s2d-init-and-retirement

Conversation

@wmadden-electric

@wmadden-electric wmadden-electric commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

The last platform slice: init moves onto the engine, and the Commander shell is deleted. When this merges, prisma-cli runs entirely on @prisma/cli-engine.

$ prisma-cli init --config-format ts --name checkout --no-link --no-install
Wrote prisma.compute.ts

$ ./node_modules/.bin/prisma-cli auth whoami --format json     # packed tarball, plain Node
{"kind":"result","envelope":{"ok":true,"commandId":"auth.whoami","result":{"authenticated":false,...},"exitCode":0,"nextActions":[{"kind":"run-command","label":"Sign in","command":"prisma-cli auth login"}]},...}

What is in it

init ported the full prompt matrix, byte-asserted templates
version command removed by ruling — the engine's --version answers
Commander shell deleted 88 files, ~42,000 lines, survivors enumerated
Bin cutover prisma-clidist/cli.js, proven from a tarball on plain Node
Working name retired src/v8/ dissolves into src/; no "v8" remains in code, tests or docs
ctx.host commands stop reading process; flag.optionalBoolean added for init
Divergence record one consolidated document for operator sign-off

init

The hardest command in the product: pick a framework, write a compute config, optionally install types, optionally link the directory to a Project, optionally install the agent skill. Green interactively, under --yes, non-interactively, and when cancelled. The files it writes are asserted byte for byte against what the shipping command produced.

Its link step is literally project link. The legacy wizard called runProjectLink — the same controller that became the v8 project link command. Rather than grow a second picker, project link's handler body is extracted as linkDirectoryToProject and both commands call it. Making that function ignore its explicit ref fails tests in both commands, which is what shows the sharing is real.

--format is renamed --config-format (the engine reserves --format for output). The three optional steps default to no: the engine has one knob where legacy had two — a prompt default under --yes and non-interactive take the same branch — and defaulting to yes would make init --yes in CI install packages, call the API and write skill files. Interactive users press y where they pressed Enter. Flagged for a decision in the divergence document; one line per prompt to flip.

The deletion

Every command already ran on the engine, so the shell that used to run them goes: the commander program, registration tree, renderers, prompt and help machinery, and 27 test files. Four commands disappear with it, each ruled beforehand (app build, app deploy, app run — Composer's; version--version answers). One is a shelve, not a drop: app logs had no v8 successor because the engine lacks the streaming transport service logs needs, and until that lands, streaming service logs is unavailable in any form. That was recorded in the S2c review and is now true.

Survivors are enumerated, not assumed. .drive/projects/prisma-cli-v8/assets/s2/shell-deletion-survivors.md is the transitive import closure of src/v8/** — after this branch nothing outside that closure remains in src/. Two survivors moved: the operation-layer context types (narrowed to the three fields anything still reads), and detectDeployFramework out of the 5,099-line app controller, since init was its only caller.

The CliError knot resolved as the contract preferred: the auth module throws CliStructuredError directly and the auth mapping layer is deleted. Elsewhere CliError stays as the deliberate contract between the surviving operation layer and v8's five per-domain error mappers, all of which rewrite the dead --trace flag to --log-level verbose before any fix text reaches a user.

The init collision, ruled

#164 merged first and mounted the ORM family, whose grammar includes a top-level init — colliding with the platform wizard this branch ports to the same path. Ruled (operator, 2026-08-12): the ORM's project initializer mounts at orm init; top-level init is the platform's compute-config wizard. Users of the old ORM CLI who type prisma init expecting a schema scaffold now get the compute wizard; the divergence document records it.

The merge also exposed a coverage hole: the e2e manifest's scan matched only quoted mount keys, so bare mounts (init, feedback, format, lsp, migrate) were invisible to the every-command-needs-a-happy-path rule. The scan now sees them; init gained a real e2e happy path, run against the live API before committing; the others took reasoned exclusions.

Verification

@prisma/cli-engine 800 tests, exit 0
@prisma/cli 937 passed, 1 skipped, exit 0 (incl. pnpm check:grammar)
@repo/cli-telemetry 49 tests, exit 0
pnpm typecheck, pnpm lint exit 0
Packed tarball on plain Node --version exit 0; auth whoami --format json settles signed-out with a sign-in action

Claims were checked by breaking code and watching the right test fail: renaming an auth error code (caught by the envelope test with no mapper in between), disabling a survivor's API-error check, orphaning the extracted framework detector, hard-coding the feedback runtime, inverting the Windows --copy rule, flipping a prompt default, and unmounting init.

Signed off

.drive/projects/prisma-cli-v8/assets/s2/parity-divergences.md is the one cumulative S2 record, ratified by the operator on 2026-08-12: the init prompt defaults, S2c's four escalated engine gaps (now tracked in deferred.md as ratified-as-shipped follow-ups), and ledger Q1/Q3/Q5–Q8 at their built defaults.

The working name retires

Developed as "v8" beside the shell it replaced; with the shell gone the marker means nothing. src/v8/ dissolves — command groups to src/commands/, the entry files to src/ — the bundle returns to the originally declared dist/cli.js, and forty test files drop their prefix. Two non-mechanical finds: the version read only worked because of the old bundle depth (fixed, nearest-first, proven on the built binary), and the rename would have silently clobbered the update-check module's tests with the bin-wiring tests of the same stripped name (caught by the before/after test count, both files kept). Where "v8" meant Prisma 8 the product, the text now says that. .drive keeps its historical vocabulary.

wmadden-electric and others added 4 commits August 11, 2026 10:31
A self-contained handover for an agent with no context on this project:
port `init` and `version` onto the engine, delete the commander shell
and the fixture machinery, cut the shipped binary over, and close the
platform port.

Written to be actionable rather than a summary. It names the two pull
requests that must land first and why starting early means rebasing a
very large deletion across moving branches; separates the one thing
that is blocked on an operator ruling (how the shipped binary reads a
TypeScript config file, since the loader currently relies on tsx) from
everything that proceeds without it; sizes the deletion; and calls out
the knot where the auth module still constructs the old shell's error
class, so the shell it is meant to outlive cannot simply be deleted
underneath it.

It also flags that the slice contract contradicts itself mid-sentence
on the binary cutover — a previous author catching their own error —
and points at the question ledger as authoritative there.

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>
…tories

Operator ruling, 2026-08-11. The question was how the shipped binary
reads `prisma.config.ts` when it runs on ordinary Node and our loader
does a plain dynamic import that only works under tsx. It was recorded
as an open design choice between jiti, esbuild-register, and requiring
a TypeScript-capable runtime.

It is not a design choice. prisma/prisma and prisma/composer both
solved it already and identically, with `c12`: a dependency, imported
dynamically at the call site, called as
`loadConfig({ name, cwd, configFile? })`, with `typescript` as a peer.
`c12` evaluates TypeScript through `jiti`, which is the part that makes
it work on plain Node, so the dependency declarations are as much of
the answer as the call.

This unblocks the binary cutover in the last platform slice, whose
contract said not to start that work until the question was ruled. The
contract also contradicted itself mid-sentence on this point — a
previous author catching their own error and leaving both halves in —
and that paragraph is replaced.

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>
…s asking it

The brief told the next agent to request a ruling on how the shipped
binary reads a TypeScript config file, and to work around the block
meanwhile. That question is answered: copy prisma/prisma and
prisma/composer, which both use `c12`.

The section now says what to copy — including the dependency
declarations, since `c12` evaluates TypeScript through `jiti` and that
is the part that makes it work on plain Node — and the two discovery
behaviours worth carrying over. Nothing in the slice is blocked now, so
the ordering advice that worked around it is gone too.

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>
…nary can read it at all

The loader did a plain dynamic import of the user's prisma.config.ts.
That works under tsx and nowhere else, so the binary we ship — ordinary
Node — could not read the config file the CLI is built around. On a Node
with type stripping off it fails with `Unknown file extension ".ts"`; on
a current Node it fails on the first piece of syntax stripping cannot
handle, such as an enum.

prisma/prisma and prisma/composer both solved this already and
identically, so this copies them rather than choosing: c12, imported
dynamically at the call site so a run with no config file never pays for
it. jiti, which c12 pulls in and which does the transpiling, is what
makes plain Node work.

Only the evaluation step changes. Discovery is still cwd-only, absence
is still an empty config rather than an error, the $prismaConfig marker
check is unchanged, and failures are still diagnostics rather than
exceptions. Every c12 feature beyond "evaluate this one file" is
switched off explicitly, most importantly `extend: false` — c12 treats a
top-level `extends` key as an instruction to merge another config layer,
where our model says every top-level key is a section name, so a user
with a section called `extends` would have had it silently eaten.
`omit$Keys: false` for the same reason: the default is already correct
but a change to it would strip $prismaConfig and turn every valid config
into a missing-marker error.

The test that matters spawns plain node, with no tsx, against a real
TypeScript config, and asserts both that a direct import fails and that
the config comes back. Two cases, because a current Node can strip
simple annotations: one with stripping disabled, one with an enum.
Reverting the loader fails both.

No existing test changed. One was added to pin `extend: false` and to
record the one observable difference: c12 merges through defu, so the
object we receive is a fresh merge rather than the frozen export.
Arrays, Dates and class instances keep their prototypes; nested plain
objects are new objects. Nothing reads identity, but it is now written
down.

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>
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 320 files, which is 220 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.

Usage-priced reviews support at most 300 files.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4dedee82-4e17-4197-a15c-27631883491e

📥 Commits

Reviewing files that changed from the base of the PR and between c5fe09d and 3f87dd5.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (320)
  • .drive/projects/prisma-cli-v8/assets/briefs/init-and-shell-retirement.md
  • .drive/projects/prisma-cli-v8/assets/engine/engine-interface-draft.ts
  • .drive/projects/prisma-cli-v8/assets/s2/parity-divergences-s2b.md
  • .drive/projects/prisma-cli-v8/assets/s2/parity-divergences-s2c.md
  • .drive/projects/prisma-cli-v8/assets/s2/parity-divergences.md
  • .drive/projects/prisma-cli-v8/assets/s2/shell-deletion-survivors.md
  • .drive/projects/prisma-cli-v8/deferred.md
  • .drive/projects/prisma-cli-v8/plan.md
  • .drive/projects/prisma-cli-v8/specs/s2-overview.md
  • .github/workflows/publish.yml
  • .github/workflows/test-e2e.yml
  • AGENTS.md
  • CONTRIBUTING.md
  • README.md
  • biome.jsonc
  • docs/architecture/overview.md
  • docs/architecture/package-structure.md
  • docs/onboarding/common-tasks.md
  • docs/onboarding/testing.md
  • docs/oss/versioning.md
  • package.json
  • packages/cli-engine/src/args.ts
  • packages/cli-engine/src/context.ts
  • packages/cli-engine/src/execution/command-context.ts
  • packages/cli-engine/src/execution/stricli-adapter.ts
  • packages/cli-engine/src/exports/index.ts
  • packages/cli-engine/src/runtime.ts
  • packages/cli-engine/src/testing.ts
  • packages/cli-engine/tests/clack-isolation.test.ts
  • packages/cli-engine/tests/clack-prompts.test.ts
  • packages/cli-engine/tests/config.test.ts
  • packages/cli-engine/tests/engine.type-test.ts
  • packages/cli-engine/tests/environment-credential-manager.test.ts
  • packages/cli-engine/tests/execution.test.ts
  • packages/cli-engine/tests/lifetimes.test.ts
  • packages/cli-engine/tests/management-api.test.ts
  • packages/cli-engine/tests/prompts.test.ts
  • packages/cli-engine/tests/spawn.test.ts
  • packages/cli/e2e/declared-bin.e2e.ts
  • packages/cli/e2e/harness.ts
  • packages/cli/e2e/init.e2e.ts
  • packages/cli/e2e/postgres.e2e.ts
  • packages/cli/e2e/suite.ts
  • packages/cli/package.json
  • packages/cli/src/auth/errors.ts
  • packages/cli/src/auth/workspaces.ts
  • packages/cli/src/bin.ts
  • packages/cli/src/cli.ts
  • packages/cli/src/commands/agent/errors.ts
  • packages/cli/src/commands/agent/index.ts
  • packages/cli/src/commands/agent/install.ts
  • packages/cli/src/commands/agent/presentation.ts
  • packages/cli/src/commands/agent/results.ts
  • packages/cli/src/commands/agent/skills-cli.ts
  • packages/cli/src/commands/agent/status.ts
  • packages/cli/src/commands/agent/update.ts
  • packages/cli/src/commands/app/index.ts
  • packages/cli/src/commands/auth/agent-setup-tip.ts
  • packages/cli/src/commands/auth/credential-card.ts
  • packages/cli/src/commands/auth/index.ts
  • packages/cli/src/commands/auth/login.ts
  • packages/cli/src/commands/auth/logout.ts
  • packages/cli/src/commands/auth/session-ref.ts
  • packages/cli/src/commands/auth/whoami.ts
  • packages/cli/src/commands/auth/workspace-list.ts
  • packages/cli/src/commands/auth/workspace-logout.ts
  • packages/cli/src/commands/auth/workspace-use.ts
  • packages/cli/src/commands/branch/errors.ts
  • packages/cli/src/commands/branch/index.ts
  • packages/cli/src/commands/branch/list.ts
  • packages/cli/src/commands/bucket/context.ts
  • packages/cli/src/commands/bucket/create.ts
  • packages/cli/src/commands/bucket/delete.ts
  • packages/cli/src/commands/bucket/errors.ts
  • packages/cli/src/commands/bucket/index.ts
  • packages/cli/src/commands/bucket/key-create.ts
  • packages/cli/src/commands/bucket/key-delete.ts
  • packages/cli/src/commands/bucket/key-list.ts
  • packages/cli/src/commands/bucket/list.ts
  • packages/cli/src/commands/bucket/presentation.ts
  • packages/cli/src/commands/build/index.ts
  • packages/cli/src/commands/build/logs.ts
  • packages/cli/src/commands/database/index.ts
  • packages/cli/src/commands/env.ts
  • packages/cli/src/commands/feedback.ts
  • packages/cli/src/commands/feedback/index.ts
  • packages/cli/src/commands/git/connect.ts
  • packages/cli/src/commands/git/context.ts
  • packages/cli/src/commands/git/disconnect.ts
  • packages/cli/src/commands/git/errors.ts
  • packages/cli/src/commands/git/index.ts
  • packages/cli/src/commands/init/agent-setup.ts
  • packages/cli/src/commands/init/config-file.ts
  • packages/cli/src/commands/init/errors.ts
  • packages/cli/src/commands/init/index.ts
  • packages/cli/src/commands/init/init.ts
  • packages/cli/src/commands/init/link.ts
  • packages/cli/src/commands/init/presentation.ts
  • packages/cli/src/commands/init/settings.ts
  • packages/cli/src/commands/init/types-install.ts
  • packages/cli/src/commands/init/types.ts
  • packages/cli/src/commands/postgres/backup-list.ts
  • packages/cli/src/commands/postgres/connection-create.ts
  • packages/cli/src/commands/postgres/connection-list.ts
  • packages/cli/src/commands/postgres/connection-remove.ts
  • packages/cli/src/commands/postgres/connection-rotate.ts
  • packages/cli/src/commands/postgres/context.ts
  • packages/cli/src/commands/postgres/create.ts
  • packages/cli/src/commands/postgres/errors.ts
  • packages/cli/src/commands/postgres/list.ts
  • packages/cli/src/commands/postgres/presentation.ts
  • packages/cli/src/commands/postgres/remove.ts
  • packages/cli/src/commands/postgres/restore.ts
  • packages/cli/src/commands/postgres/show.ts
  • packages/cli/src/commands/postgres/usage.ts
  • packages/cli/src/commands/project/context.ts
  • packages/cli/src/commands/project/create.ts
  • packages/cli/src/commands/project/env-add.ts
  • packages/cli/src/commands/project/env-list.ts
  • packages/cli/src/commands/project/env-remove.ts
  • packages/cli/src/commands/project/env-shared.ts
  • packages/cli/src/commands/project/env-update.ts
  • packages/cli/src/commands/project/errors.ts
  • packages/cli/src/commands/project/index.ts
  • packages/cli/src/commands/project/link.ts
  • packages/cli/src/commands/project/list.ts
  • packages/cli/src/commands/project/presentation.ts
  • packages/cli/src/commands/project/remove.ts
  • packages/cli/src/commands/project/rename.ts
  • packages/cli/src/commands/project/show.ts
  • packages/cli/src/commands/project/transfer.ts
  • packages/cli/src/commands/resources-shared/workspace.ts
  • packages/cli/src/commands/service/create.ts
  • packages/cli/src/commands/service/deployment-delete.ts
  • packages/cli/src/commands/service/deployment-list.ts
  • packages/cli/src/commands/service/deployment-promote.ts
  • packages/cli/src/commands/service/deployment-rollback.ts
  • packages/cli/src/commands/service/deployment-run-state.ts
  • packages/cli/src/commands/service/deployment-show.ts
  • packages/cli/src/commands/service/deployment-start.ts
  • packages/cli/src/commands/service/deployment-stop.ts
  • packages/cli/src/commands/service/domain-add.ts
  • packages/cli/src/commands/service/domain-remove.ts
  • packages/cli/src/commands/service/domain-retry.ts
  • packages/cli/src/commands/service/domain-shared.ts
  • packages/cli/src/commands/service/domain-show.ts
  • packages/cli/src/commands/service/domain-wait.ts
  • packages/cli/src/commands/service/errors.ts
  • packages/cli/src/commands/service/list.ts
  • packages/cli/src/commands/service/open.ts
  • packages/cli/src/commands/service/presentation.ts
  • packages/cli/src/commands/service/release.ts
  • packages/cli/src/commands/service/remove.ts
  • packages/cli/src/commands/service/results.ts
  • packages/cli/src/commands/service/show.ts
  • packages/cli/src/commands/service/target.ts
  • packages/cli/src/commands/telemetry/sender.ts
  • packages/cli/src/commands/version/index.ts
  • packages/cli/src/controllers/agent-setup.ts
  • packages/cli/src/controllers/agent.ts
  • packages/cli/src/controllers/app-env-api.ts
  • packages/cli/src/controllers/app-env-file.ts
  • packages/cli/src/controllers/app-env.ts
  • packages/cli/src/controllers/app.ts
  • packages/cli/src/controllers/auth.ts
  • packages/cli/src/controllers/branch.ts
  • packages/cli/src/controllers/bucket.ts
  • packages/cli/src/controllers/build.ts
  • packages/cli/src/controllers/database.ts
  • packages/cli/src/controllers/feedback.ts
  • packages/cli/src/controllers/init.ts
  • packages/cli/src/controllers/project.ts
  • packages/cli/src/controllers/select-prompt-port.ts
  • packages/cli/src/controllers/version.ts
  • packages/cli/src/legacy/output.ts
  • packages/cli/src/legacy/runtime.ts
  • packages/cli/src/lib/app/app-interaction.ts
  • packages/cli/src/lib/app/branch-database-deploy.ts
  • packages/cli/src/lib/app/branch-database.ts
  • packages/cli/src/lib/app/build.ts
  • packages/cli/src/lib/app/deploy-framework.ts
  • packages/cli/src/lib/app/deploy-output.ts
  • packages/cli/src/lib/app/deploy-plan.ts
  • packages/cli/src/lib/app/deploy-progress.ts
  • packages/cli/src/lib/app/env-vars.ts
  • packages/cli/src/lib/app/local-dev.ts
  • packages/cli/src/lib/app/production-deploy-gate.ts
  • packages/cli/src/lib/bucket/provider.ts
  • packages/cli/src/lib/database/provider.ts
  • packages/cli/src/lib/diagnostics.ts
  • packages/cli/src/lib/git/local-status.ts
  • packages/cli/src/lib/project/interactive-setup.ts
  • packages/cli/src/lib/project/provider.ts
  • packages/cli/src/lib/project/resolution.ts
  • packages/cli/src/lib/project/setup.ts
  • packages/cli/src/lib/version.ts
  • packages/cli/src/main.ts
  • packages/cli/src/output/patterns.ts
  • packages/cli/src/package-manager-runner.ts
  • packages/cli/src/presenters/agent.ts
  • packages/cli/src/presenters/app-env.ts
  • packages/cli/src/presenters/app.ts
  • packages/cli/src/presenters/auth.ts
  • packages/cli/src/presenters/branch.ts
  • packages/cli/src/presenters/bucket.ts
  • packages/cli/src/presenters/database.ts
  • packages/cli/src/presenters/feedback.ts
  • packages/cli/src/presenters/init.ts
  • packages/cli/src/presenters/project.ts
  • packages/cli/src/presenters/verbose-context.ts
  • packages/cli/src/presenters/version.ts
  • packages/cli/src/runtime.ts
  • packages/cli/src/shell-command.ts
  • packages/cli/src/shell/cli-command.ts
  • packages/cli/src/shell/command-arguments.ts
  • packages/cli/src/shell/command-meta.ts
  • packages/cli/src/shell/command-runner.ts
  • packages/cli/src/shell/diagnostics-output.ts
  • packages/cli/src/shell/errors.ts
  • packages/cli/src/shell/global-flags.ts
  • packages/cli/src/shell/help.ts
  • packages/cli/src/shell/next-actions.ts
  • packages/cli/src/shell/output.ts
  • packages/cli/src/shell/prompt.ts
  • packages/cli/src/shell/runtime.ts
  • packages/cli/src/shell/ui.ts
  • packages/cli/src/spawn.ts
  • packages/cli/src/types/agent.ts
  • packages/cli/src/types/diagnostics.ts
  • packages/cli/src/types/feedback.ts
  • packages/cli/src/types/version.ts
  • packages/cli/src/update-check.ts
  • packages/cli/src/v8/bin.ts
  • packages/cli/src/v8/cli.ts
  • packages/cli/tests/agent.test.ts
  • packages/cli/tests/app-branch-database.test.ts
  • packages/cli/tests/app-bun-compat.test.ts
  • packages/cli/tests/app-controller.test.ts
  • packages/cli/tests/app-env-presenter.test.ts
  • packages/cli/tests/app-env-vars.test.ts
  • packages/cli/tests/app-env.test.ts
  • packages/cli/tests/app-local-dev.test.ts
  • packages/cli/tests/app-presenter.test.ts
  • packages/cli/tests/app-state.test.ts
  • packages/cli/tests/app.test.ts
  • packages/cli/tests/auth-presenter.test.ts
  • packages/cli/tests/auth-real-mode.test.ts
  • packages/cli/tests/auth.test.ts
  • packages/cli/tests/bin.test.ts
  • packages/cli/tests/branch-controller.test.ts
  • packages/cli/tests/branch.test.ts
  • packages/cli/tests/bucket.test.ts
  • packages/cli/tests/build-logs.test.ts
  • packages/cli/tests/command-runner-auth.test.ts
  • packages/cli/tests/command-runner.test.ts
  • packages/cli/tests/composer-isolation.test.ts
  • packages/cli/tests/compute-config.test.ts
  • packages/cli/tests/database-plan-limit.test.ts
  • packages/cli/tests/database.test.ts
  • packages/cli/tests/deploy-plan.test.ts
  • packages/cli/tests/e2e-coverage.test.ts
  • packages/cli/tests/feedback.test.ts
  • packages/cli/tests/fixtures/config/composer-section.config.ts
  • packages/cli/tests/fixtures/config/elsewhere.config.ts
  • packages/cli/tests/fixtures/orm-project/migrations/.gitkeep
  • packages/cli/tests/fixtures/startup-probe.mjs
  • packages/cli/tests/git.test.ts
  • packages/cli/tests/golden-rendering.test.ts
  • packages/cli/tests/helpers.ts
  • packages/cli/tests/init-agent-setup.test.ts
  • packages/cli/tests/init.test.ts
  • packages/cli/tests/legacy-context.test.ts
  • packages/cli/tests/mount-coverage.test.ts
  • packages/cli/tests/orm-mount.test.ts
  • packages/cli/tests/output.test.ts
  • packages/cli/tests/package-manager-runner.test.ts
  • packages/cli/tests/postgres.test.ts
  • packages/cli/tests/production-deploy-gate.test.ts
  • packages/cli/tests/project-real-mode.test.ts
  • packages/cli/tests/project.test.ts
  • packages/cli/tests/prompt.test.ts
  • packages/cli/tests/service-compute-config.test.ts
  • packages/cli/tests/service-create.test.ts
  • packages/cli/tests/service-deployment-delete.test.ts
  • packages/cli/tests/service-deployment-list.test.ts
  • packages/cli/tests/service-deployment-promote.test.ts
  • packages/cli/tests/service-deployment-rollback.test.ts
  • packages/cli/tests/service-deployment-show.test.ts
  • packages/cli/tests/service-deployment-start.test.ts
  • packages/cli/tests/service-deployment-stop.test.ts
  • packages/cli/tests/service-domain-wait.test.ts
  • packages/cli/tests/service-domain.test.ts
  • packages/cli/tests/service-list.test.ts
  • packages/cli/tests/service-open.test.ts
  • packages/cli/tests/service-remove.test.ts
  • packages/cli/tests/service-session.test.ts
  • packages/cli/tests/service-show.test.ts
  • packages/cli/tests/service-testkit.ts
  • packages/cli/tests/shell.test.ts
  • packages/cli/tests/spawn-adapter.test.ts
  • packages/cli/tests/telemetry-reporting.test.ts
  • packages/cli/tests/telemetry.test.ts
  • packages/cli/tests/update-check-wiring.test.ts
  • packages/cli/tests/update-check.test.ts
  • packages/cli/tests/v8-agent.test.ts
  • packages/cli/tests/v8-auth.test.ts
  • packages/cli/tests/v8-feedback.test.ts
  • packages/cli/tests/v8-project.test.ts
  • packages/cli/tests/version.test.ts
  • packages/cli/tests/whoami.test.ts
  • packages/cli/tests/workspace-id.test.ts
  • packages/cli/tsdown.config.ts
  • packages/cli/vitest.config.ts
  • scripts/determine-version-utils.test.ts
  • scripts/determine-version-utils.ts
  • scripts/determine-version.ts
  • scripts/smoke-cli-nextjs-artifact.mjs
  • scripts/tarball-smoke-utils.test.mjs
  • skills-contrib/publish-npm-version/SKILL.md
  • turbo.json

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

wmadden-electric and others added 3 commits August 11, 2026 11:14
… not an equivalent one

Compared line by line against prisma/composer's `loadAppConfig` and
prisma/prisma's `config-loader`. Ours had drifted in three ways.

It passed five options neither reference passes — dotenv, envName,
giget, omit$Keys and extend — reasoned out from c12's documentation
rather than copied. Four are now gone. The call is composer's: explicit
configFile, cwd at that file's directory, and the three lookups it turns
off, with prisma/prisma's dynamic import so a run without a config file
never loads c12 or jiti.

It passed the bare cwd where both references pass the config file's own
directory. Now the same.

And it was missing a check both references have: c12 is asked for one
exact path and must not answer with another. prisma/prisma compares the
resolved path, composer compares realpaths. Added.

One deviation remains and it is forced. Both references describe a
config with a fixed set of keys; ours says every top-level key is a
section name. c12 reads `extends` as an instruction to merge another
config layer, so with their options exactly, a user's section called
`extends` is silently consumed. That is demonstrated rather than
argued: with `extend` left at its default the existing test fails,
expecting `['extends','values']` and receiving `['values']`.

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 second of the two commands still on the old shell. It reports the
same three things it always did — the CLI's own version, the Node
version, and the platform — and now does it through the engine, so it
gets the shared flag family, the json envelope and the exit-code
contract for free.

Two changes a user can see.

The invocation kind is gone. The old command reported whether it had
been run via npx, bunx, a global install or a dev checkout, and it
worked that out largely from process.argv[1]. Handlers cannot read argv
on this engine — the runtime owns it and does not pass it through — so
the field has no honest successor. Deriving it from environment
variables alone would still answer for npx and bunx but would quietly
answer "unknown" where it used to say "global", and a field that is
sometimes wrong is worse than one that is absent. The slice contract and
the handover brief both name only version, node and platform, so this
matches what was asked for; it is in the divergence list for sign-off.

Human mode now also writes the fields to stdout, where the old command
wrote only to stderr. That is the engine-wide pattern the ported
commands already follow, and it is what makes the output pipeable.

The version read is split so the new command does not depend on the
shell that is about to be deleted: readCliVersion returns the version or
undefined, getCliVersion keeps throwing the old CliError for the old
shell, and the engine command raises a structured VERSION.UNAVAILABLE
instead.

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>
@wmadden-electric
wmadden-electric force-pushed the s2d-init-and-retirement branch from dda94d8 to b74253c Compare August 11, 2026 09:23
@wmadden-electric
wmadden-electric changed the base branch from main to config-loading-ruling August 11, 2026 09:23
@pkg-pr-new

pkg-pr-new Bot commented Aug 11, 2026

Copy link
Copy Markdown

Open in StackBlitz

npx https://pkg.pr.new/@prisma/cli@139
npx https://pkg.pr.new/@prisma/cli-engine@139

commit: 3f87dd5

@wmadden-electric wmadden-electric changed the title The shipped binary can read prisma.config.ts, and version moves onto the engine Port the last two commands off the old shell: version, and init Aug 11, 2026
wmadden-electric and others added 3 commits August 11, 2026 11:59
`init` has two flags that need three states: `--link`, `--no-link`, and
neither, which means "ask me". The same goes for `--install`. A command
could not express that. `flag.boolean` produces a stricli boolean with a
default of false, so `--no-link` and saying nothing arrive identically,
and the wizard would silently link a directory for someone who asked it
not to.

The engine already uses the right spelling — `optional` with
`withNegated` — for its own `--interactive` and `--color`. It just was
not reachable from a command. `flag.optionalBoolean` exposes it, and
follows the shape `flag.optionalString` already set for strings.

The alternatives both changed a documented flag. Spelling it
`--link <yes|no>` breaks every script and doc line that says
`--no-link`, and adding a separate `--skip-link` leaves `--no-link`
parsing as stricli's negation and quietly meaning "ask me" — a flag that
works and does the wrong thing.

Pinned at both levels: the type test proves all three states reach the
handler and that a plain boolean flag still cannot be undefined, and the
runtime test proves `--flag`, `--no-flag` and absence produce true,
false and undefined. Collapsing the adapter case back to a plain boolean
fails both.

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 last command on the old shell, and the hardest one in the product: a
wizard that picks a framework, writes a compute config, optionally
installs types, optionally links the directory to a Project, and
optionally installs the agent skill. It now runs on the engine's prompt
surface and works interactively, under --yes, non-interactively, and
when cancelled.

Three decisions worth reading.

**init's link step is `project link`.** The legacy wizard called
`runProjectLink`, which is precisely the controller that became the v8
`project link` command. Rather than grow a second project picker, the
handler body of `project link` is extracted as `linkDirectoryToProject`
and both call it. So the picker, the "create a new Project" and "cancel"
choices, the duplicate-name labels, the pin write and the .gitignore
update are one implementation, not two that drift. Making that function
ignore its explicit ref fails tests in both commands, which is what
proves the sharing is real.

**--format becomes --config-format.** Legacy `init --format <ts|json>`
chooses the format of the config file it writes. The engine reserves
--format globally for the output format. The engine's shared flags win,
so the flag is renamed; values and behaviour, including the JSON to
TypeScript conversion path, are unchanged.

**The three optional steps default to no.** The engine has one knob
where the legacy CLI had two: a preselected answer when it asks, and a
separate behaviour when nobody can be asked. `prompt.confirm`'s default
serves both, because --yes and non-interactive take the same branch and
a handler cannot read TTY state. Defaulting them to yes would make
`init --yes` in CI run a package install, call the Management API and
write agent-skill files into the repo, none of which it does today.
Defaulting to no keeps unattended runs behaving exactly as they do now.
The cost is that an interactive user presses y rather than Enter, and
the prompts read (y/N) where they read (Y/n) — a one-line flip per
prompt if the other trade is preferred.

init mounts as shell-owned, beside version and telemetry: it writes a
local compute config and needs neither a config section nor a platform
docs base. When a compute family arrives it should move into it.

Eighteen user-visible differences are recorded for sign-off, including
that a cancelled prompt now ends the run at exit 3 where the legacy
command recorded a decline and exited 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>
…for users

Twenty differences between the shipping commands and their ports, in the
shape S2b's list uses, so the closing dispatch can fold the four lists
into one document.

Two need a decision rather than a nod, and are marked: the version
command loses its invocation field because the engine does not hand a
handler raw argv, and init's three optional steps now default to no
because the engine has one knob where the legacy CLI had two.

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>
@wmadden-electric
wmadden-electric force-pushed the s2d-init-and-retirement branch from b74253c to cc4d2d9 Compare August 11, 2026 10:04
The contract asked for `version` to be ported. It should not be, and
porting it was my mistake.

`--version` is already an engine surface — a pre-parse fast path that
prints the version in human mode and emits a version result frame in
json. The command inventory's own note says the port should unify the
two rather than carry both forward. I read that note and built the
second surface anyway.

Nothing the command added survives scrutiny. The invocation kind
(dev/npx/bunx/global/unknown) had exactly one consumer in the codebase:
the presenter that printed it. It came from process.argv[1] — the
process inspecting how it was launched — which is the thing the engine
withholds argv from handlers to prevent. Keeping it would have meant
piping an environment fact through the runtime into a command, and
commands do not read the environment that way. Node version, platform
and arch are already gathered by the command that needs them: feedback
builds its own context for bug reports.

So `prisma-cli version` goes and `--version` answers instead. This makes
`version` a ruled removal for the grammar completeness check, alongside
`service build`, `service deploy`, `service run` and the mock-only login
flags — the check must exclude it or it will report the command missing
against the inventory.

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>
@wmadden-electric wmadden-electric changed the title Port the last two commands off the old shell: version, and init Port init onto the engine; drop the version command Aug 11, 2026
wmadden-electric and others added 2 commits August 11, 2026 12:57
Three commands across two branches independently reached straight
through to `process` for the same reason: nothing else told them what
they were running on.

  v8/init/agent-setup.ts   process.platform === "win32"
  v8/agent/skills-cli.ts   process.platform === "win32"     (on #132)
  v8/feedback.ts           process.version/platform/arch    (on #132)

Three agents making the same move is a missing surface, not three
oversights. Handlers already take the working directory and the
environment from the context precisely so they never touch process
globals, and there was no equivalent for the machine.

`Runtime.host` carries it and `ctx.host` hands it to commands. It is
deliberately not node-shaped: the field is `runtime: { name, version }`,
so bun and deno describe themselves rather than being flattened into
something called nodeVersion. That naming is what R4 asks for, and it is
what a bug-report payload should be carrying.

This is not a way around the engine's constraints. What a command may
not do is infer its situation from the environment — sniff argv to guess
how it was launched, read process.env behind ctx.env's back. What it
legitimately needs is the odd real platform difference (symlinks want a
privilege on Windows) and the facts a bug report is made of. Those are
supplied, once, by the bin.

The two call sites on #132 cannot be converted from here without
touching that branch. They are recorded for the deletion pass, which
already has to sweep the tree.

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 still owes

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>
Base automatically changed from config-loading-ruling to main August 11, 2026 12:48
wmadden-electric and others added 6 commits August 12, 2026 15:36
… onto the new engine

Main moved substantially while this branch was in flight: S2c's service
and agent families, S3's composer commands and ctx.spawn, S8's service
resource surface, engine-owned CI detection, engine-owned package
manager operations, an on-demand config loader, and the fixture
machinery already deleted by #159.

What this merge decided, beyond taking both sides:

- init's link step keeps calling the shared linkDirectoryToProject,
  updated to main's listWorkspaceProjects signature. Main had inlined
  the handler body this branch extracted; the extraction survives
  because init depends on it.
- The bin-side detectPackageManager this branch carried is deleted in
  favour of main's engine-owned detection — Runtime.packageManager is
  now an optional override, exactly the shape the operator asked for.
- ctx.host joins main's grown context beside ctx.isCI; every Runtime
  literal in the engine tests gains the fixed test host.
- init and its tests adopt main's summary-block field (status, not
  tone) and the mount-coverage test's FAMILYLESS set.

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>
R-S2d-6: the per-slice lists (s2b, s2c, s2d) fold into
parity-divergences.md verbatim, headings demoted, behind a new
preamble that states the shared class rules once and puts everything
needing an actual decision — the init prompt defaults, S2c's four
escalated engine gaps, and the open ledger questions — at the top,
where signing off is meaningful. S3's and S8's lists belong to those
slices and stay separate.

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>
Every command runs on @prisma/cli-engine, so the shell that used to run
them — the commander program, its registration tree, its renderers, its
prompt and help machinery, and the 27 test files that drove them — is
deleted: 88 files, ~42,000 lines. Nothing a user could reach through the
v8 tree is lost; the four commands that do disappear were each ruled
(app build, app deploy, app run — superseded by Composer; version — the
engine's --version answers) or explicitly shelved (app logs, waiting on
the engine transport service logs needs).

What survives is the operation layer the v8 handlers still call, and it
is enumerated, not assumed:
.drive/projects/prisma-cli-v8/assets/s2/shell-deletion-survivors.md is
the transitive import closure of src/v8/** — after this commit nothing
outside that closure remains in src/. Two survivors moved: the
operation-layer context types to src/legacy/runtime.ts, narrowed to the
three fields anything still reads, and detectDeployFramework out of the
5,099-line app controller into its own module, since v8 init was its
only caller.

The CliError knot is resolved the way the contract preferred: the auth
module throws CliStructuredError directly and the auth mapping layer is
gone. Elsewhere CliError remains as the deliberate contract between the
surviving operation layer and v8's five per-domain error mappers, all of
which rewrite the dead --trace flag to --log-level verbose before any
fix text reaches a user.

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 last two commands reading process directly move onto the host
surface. The agent skill installer takes the Windows --copy decision
from ctx.host.platform, and the platform test now sets the engine test
host instead of redefining process.platform — which was itself the
pattern this closes off.

One user-visible change, recorded in the divergence document: the
feedback payload's nodeVersion string becomes a runtime object
({ name, version }), so a bun or deno binary reports itself truthfully
instead of masquerading as a node version. The human summary line reads
the same.

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>
packages/cli's bin points at dist/v8/cli.js — the same value PR #164
writes on its branch, byte for byte, so whichever lands second resolves
a trivial conflict. The tsdown build drops the legacy entry, the root
prisma and prisma-cli scripts point at the v8 bin, the prisma-v8
working name is gone, and six dependencies with no importer left
(commander among them) leave the manifest.

Proven from a packed tarball on plain Node: the declared bin resolves,
--version answers with the lockstep version at exit 0, and auth whoami
--format json settles signed-out with a sign-in next action.

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>
…cument

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>
@wmadden-electric wmadden-electric changed the title Port init onto the engine; drop the version command Port init, delete the Commander shell: the CLI runs entirely on the engine Aug 12, 2026
@wmadden-electric
wmadden-electric marked this pull request as ready for review August 12, 2026 14:17
wmadden-electric and others added 2 commits August 12, 2026 18:50
The S7 merge (#164) mounted the ORM family, whose grammar includes a
top-level init — colliding with the platform's compute-config wizard
this branch ports to the same path. Resolution ruled by the operator
(2026-08-12): the ORM's project initializer mounts at `orm init`, and
top-level `init` is the platform wizard, as the S2d contract wrote it.

The merge also closes a coverage hole it exposed. The e2e coverage
manifest's scan matched only quoted mount keys, so bare identifier
mounts (init, feedback — and after this merge format, lsp, migrate)
were invisible to the every-command-needs-a-happy-path rule. The scan
now sees bare keys; init gains a real e2e happy path against the built
binary (run against the live API before committing); the ORM paths take
the family's existing exclusion reason; feedback is excluded because a
per-CI-run post to the real feedback service is spam, not a test.

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>
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>
wmadden-electric and others added 3 commits August 12, 2026 19:03
The divergence document, its surfaced decisions, and ledger Q1/Q3/Q5-Q8
are ratified at their stated defaults (2026-08-12). The escalated
engine gaps move to deferred.md as ratified-as-shipped follow-ups.

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 engine-based CLI was developed as "v8" beside the shell it replaced.
The shell is gone, so the marker means nothing and goes — from paths,
identifiers, strings, comments, docs and workflows.

src/v8/ dissolves into src/: the command groups land at src/commands/
(the path the old registration tree freed, which also keeps the auth
COMMANDS distinct from the src/auth module), and cli.ts, main.ts,
bin.ts and runtime.ts take the root names the deletion vacated. The
bundle moves from dist/v8/cli.js to dist/cli.js — the path the package
originally declared — and the forty v8-*.test.ts files drop the prefix.

Two things about the move that are not mechanical:

The version read broke and is fixed. lib/version.ts resolved
../../package.json, which only worked because dist/v8/cli.js happened
to sit at the same depth as src/lib/. The flattened bundle is one level
shallower, so the freshly built binary could not find its own version.
The read now tries ../package.json first and ../../package.json second,
and the built binary and the declared-bin end-to-end test prove both
layouts.

One test file was nearly lost. tests/update-check.test.ts (the update
check module's own tests — the module survived the shell deletion) and
tests/v8-update-check.test.ts (the bin's wiring of it) collide under
prefix-stripping, and the rename clobbered the former. Restored; the
wiring tests live at update-check-wiring.test.ts, and the suite is back
to its full count.

Where "v8" meant the Prisma 8 product version rather than the working
name (the release-line docs, the workspace-id format contrast), the
text now says "Prisma 8" — same meaning, no marker. .drive keeps its
historical vocabulary; falsifying records is worse than an old name.

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>
Two expectations in agent.test.ts still conditioned on the machine's
own process.platform, from before the installer read the platform off
ctx.host. The harness pins the host to linux on every machine, so on a
Windows runner the expectation added --copy while the command rightly
did not, and the suite failed only there. The expectations are now
unconditional, and the Windows rule keeps its own dedicated test, which
sets the harness host explicitly.

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants