Skip to content

feat(cli): add a project delete command so cloud projects can be torn down - #3618

Merged
kojiwakayama merged 3 commits into
mainfrom
fix/dx-20260811-r2-29
Aug 11, 2026
Merged

feat(cli): add a project delete command so cloud projects can be torn down#3618
kojiwakayama merged 3 commits into
mainfrom
fix/dx-20260811-r2-29

Conversation

@kojiwakayama

@kojiwakayama kojiwakayama commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Problem

Dogfooding round 2, finding [29] (new, confirmed against published 0.1.1229).

veryfront push creates a real cloud project on first run ("Creating project..."), and
veryfront deploy then creates environments and releases. The CLI exposed no way to remove any
of it:

$ veryfront help --all | grep -iE 'delete|destroy|remove'
    uninstall         Remove AI assistant integrations
    uploads           List, pull, upload, and delete project uploads
    files             List, read, write, and delete project files

Only uploads and files had delete verbs. Tearing a project down meant driving Studio
(project -> Settings -> Danger Zone -> Delete Project -> retype the slug), which makes scripted
cleanup after CI, dogfooding, or e2e runs impossible without browser automation.

Root cause

Not a bug in the delete path — the path was never wired up. The REST API already serves
DELETE /projects/{project_reference} (204 on success, see
veryfront-api/src/api/http/rest/projects/delete-project/index.ts), and the token returned from
project creation already carries the project.delete capability. The gap was purely the CLI
surface: no command in cli/router.ts, no entry in cli/help/command-definitions.ts.

Change

Adds veryfront project delete [slug]:

  • cli/commands/project/ — help definition, arg schema, command, handler, barrel.
  • Registered as project (alias projects) in cli/router.ts and in the COMMANDS help
    registry, so it also flows into veryfront schema --json, shell completions, and the generated
    CLI reference.
  • Slug resolution: positional argument, then --project/-p, then the project this directory is
    linked to.
  • Confirms before deleting. --force/-f skips the prompt, --yes/-y auto-answers it (CI),
    --json/-j emits the standard envelope
    {"success": true, "command": "project", "data": {"project": "<slug>", "deleted": true}}
    through outputJson, so --output <path> writes the result file too.
  • delete and rm are both accepted as the subcommand. An unrecognised subcommand raises a
    usage error and exits 2 rather than printing usage and exiting 0 — a cleanup script must not
    read veryfront project delet app as a completed teardown.

Docs: docs/guides/deploying.md gains a short "Tear a project down" section, and the generated
docs/api-reference/veryfront/cli.md picks up the new row (regenerated with deno task docs on
Deno 2.7.7).

Tests

Written before the fix, confirmed red for the right reason:

  • cli/router.test.tsproject added to the expected-commands list. Before the fix:
    AssertionError: Values are not equal: Missing command: project.
  • cli/commands/project/command.test.ts — slug parsing (positional and --project), the
    request URL and its encoding, that deleteRemoteProject issues exactly one
    DELETE /projects/<slug>, and that a blank project reference is rejected before any request
    goes out (so an empty slug can never widen into a delete-everything call), and that a
    misspelled subcommand rejects with exit code 2.
  • tests/docs/guide-content.test.ts — the deploy guide documents a CLI teardown path.

Verified against the published repro

Not "tests pass" — the original symptom, re-run end to end.

  1. Published 0.1.1229 (installed into a scratch dir outside the monorepo):
    veryfront project delete foo --force --json -> {"success": false, ..., "message": "Unknown command: project"}.
  2. Created a real cloud project through the same endpoint veryfront push uses:
    POST https://api.veryfront.com/projects {"slug":"dx-r2-29-teardown"} -> 201.
  3. Deleted it with this build, from a directory outside the monorepo:
    veryfront project delete dx-r2-29-teardown --force --json -> {"success": true, ...}.
  4. GET https://api.veryfront.com/projects/dx-r2-29-teardown -> 404.
    (Repeated end to end after the review fixes with dx-r2-29-teardown-2: 201 on create,
    the standard envelope on delete, the same envelope written to --output, then 404.)
  5. The finding's own command against this build:
    veryfront help --all | grep -iE 'delete|destroy|remove' now lists
    project (projects) Delete a cloud project and everything it owns.

No browser automation involved at any step.

Live doc page to check after merge

The CLI reference is synced into veryfront-docs by the Update Code Docs workflow, so no PR is
needed there — but the sync has silently not landed before. After merge, this page must list
veryfront project:

https://veryfront.com/docs/code/api-reference/veryfront/cli

Notes

  • Deleting does not clear the local project link in .veryfront/; a follow-up run of push
    against a deleted slug re-creates the project. Out of scope here.
  • Local full-suite run showed 4 pre-existing environmental failures unrelated to this change
    (cli/utils/git.test.ts ambient-repo, veryfront dev output, schedule command,
    start production MCP boundary) plus one src/cache/backends/disk.test.ts flake that passes
    in isolation and passed on the pre-push re-run.
  • The first CI run hit error: Promise resolution is still pending but the event loop has already resolved in coverage shard 1/8 after 0 failed. That is a pre-existing flake, not
    this branch: main run 31526576753 failed identically in shard 4/8 with the same text and the
    same 0 failed summary. It passed on re-run here.

… down

`veryfront push` and `veryfront up` create a real cloud project on first run,
but the CLI exposed no way to remove one. Teardown required driving Studio
(project -> Settings -> Danger Zone -> Delete Project -> retype the slug), so
scripted cleanup after CI, dogfooding, or e2e runs needed browser automation.

The REST API already serves `DELETE /projects/{project_reference}`; only the
CLI surface was missing. Add `veryfront project delete [slug]` (alias
`veryfront projects`, subcommand alias `rm`) that resolves the slug from the
positional argument, `--project`, or the linked project in the current
directory, confirms before deleting, and supports `--force`, `--yes`, and
`--json`.
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@kojiwakayama, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 1 minute

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e93b3904-f30a-4fe8-9bf3-eea905405b65

📥 Commits

Reviewing files that changed from the base of the PR and between 64d6850 and 7920128.

📒 Files selected for processing (11)
  • cli/commands/project/command-help.ts
  • cli/commands/project/command.test.ts
  • cli/commands/project/command.ts
  • cli/commands/project/handler.ts
  • cli/commands/project/index.ts
  • cli/help/command-definitions.ts
  • cli/router.test.ts
  • cli/router.ts
  • docs/api-reference/veryfront/cli.md
  • docs/guides/deploying.md
  • tests/docs/guide-content.test.ts

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 71ea29579e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cli/commands/project/command.ts Outdated
Comment on lines +109 to +110
if (options.json) {
printJson({ success: true, project: projectSlug });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Route JSON results through the standard output helper

When automation invokes this command with --json, this emits {success, project} instead of the standard {success, command, data} envelope. Because printJson also bypasses outputJson, --output <path> produces no output file even though the router accepts and configures that global flag. Use outputJson(createSuccessEnvelope("project", ...)) here and the corresponding standard envelope for cancellation.

AGENTS.md reference: cli/AGENTS.md:L74-L89

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7920128. project delete --json now goes through outputJson(createSuccessEnvelope("project", ...)) for both the delete and the cancelled-at-prompt case, so --output <path> writes the file the router already configures. Verified against a real project: the command printed {"success":true,"command":"project","data":{"project":"dx-r2-29-teardown-2","deleted":true}} and wrote the same envelope to the --output path.

Comment thread cli/commands/project/command.ts Outdated
Comment on lines +120 to +121
default:
showProjectUsage();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject unknown project subcommands

When the subcommand is misspelled or unsupported, for example veryfront project delet app --force, this default branch only prints usage and returns. cli/main.ts consequently exits with code 0, so a cleanup script can report success while leaving the cloud project and its resources intact; unknown subcommands should raise a usage error and exit with code 2.

AGENTS.md reference: AGENTS.md:L161-L166

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, and it matters most for exactly this command. Fixed in 7920128: an unrecognised subcommand now throws INVALID_ARGUMENT. veryfront project delet app --force exits 2 and, in JSON mode, prints a USAGE_ERROR envelope. Covered by a regression test in cli/commands/project/command.test.ts.

…commands

Review follow-up. `project delete --json` now emits the standard
{success, command, data} envelope through outputJson, so --output writes the
result file the router already accepts. An unrecognised subcommand raises a
usage error (exit 2) instead of printing usage and exiting 0, which a cleanup
script would otherwise read as a completed teardown.
@kojiwakayama
kojiwakayama added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit bb2e5e8 Aug 11, 2026
33 checks passed
@kojiwakayama
kojiwakayama deleted the fix/dx-20260811-r2-29 branch August 11, 2026 23:10
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.

1 participant