fix(cli): classify user-input mistakes instead of reporting unknown-error - #4010
Conversation
…be overwritten `veryfront init app` refused any existing `app/`, including an empty one or a fresh clone holding only `.git`, with "Directory already exists". Every mainstream scaffolder accepts those, and `mkdir app && veryfront init app` is the first thing many developers type. A conflict is now a file the scaffold would write over, not the directory existing. `createProject` is the single authority: the named path uses the same `findExistingPaths` check the current-directory path already used, and both directory-existence checks in `initCommand` are gone. The refusal names the files and points at `--force`: Directory "app" already contains README.md. Use --force to overwrite. `.gitignore` is merged rather than replaced, so it never conflicts. The interactive wizard now runs before a refusal for a taken name; the message it ends on says exactly which files are in the way. The `vf_create_project` MCP tool keeps its own directory check and message; aligning it is a separate change. Tests: empty directory and unrelated-file cases at the `createProject`, `initCommand`, and subprocess levels; the conflict message for a named directory; existing expectations updated from "already exists" to the file-level message. API reference pins regenerated with CI's Deno.
Accepting an existing target directory means the scaffold now meets states
the old "directory already exists" check never let it reach. One of them
wrote outside the project.
`findExistingPaths` asks whether `app/page.tsx` exists. When `app` is a
regular file, that path cannot resolve, so the check reports no conflict.
`writeScaffoldFiles` then writes the root files (`README.md`, `AGENTS.md`)
and fails on `ensureDir("app")` with a raw stat error, leaving a half
scaffold behind. When `app` is a link to another directory, nothing fails
at all: `veryfront init app` exits 0, prints "app ready", and leaves
`page.tsx`, `layout.tsx` and `about/page.mdx` in the link target instead of
the project you named.
`createProject` now checks every directory the scaffold has to create,
before it writes anything, and refuses when one is already a file or a
link:
Directory "app" already contains app as a file or a link, and the
scaffold needs a directory there. Move it aside or use a different name.
The check runs whatever the conflict policy is. `--force` says you accept
your own files being replaced, not the scaffold writing somewhere else.
Every segment is checked, not just the first, so a real `app/` with a file
at `app/about` is caught before `app/page.tsx` is written. A real directory
that is already there is never blocked: it is exactly what the scaffold is
about to create.
The current-directory path had the same hole, so `cd repo && veryfront
init` with a linked `app/` wrote outside the repo too. The check covers
both paths because it sits in `createProject`.
Tests: a file and a link at a scaffold directory, for the named path, the
current-directory path, and under `--force`, plus a block one level down at
`app/about`, each asserting nothing was written through or beside it; and an
existing real `app/` that must still scaffold. Every refusal test fails
without the check.
…h directories Two more places where accepting an existing directory let a write land somewhere it was never asked to go. A link at the scaffold path itself escaped the preflight, which only walked the directories above it. `findExistingPaths` resolves a dangling link to nothing and reports it absent, so `proj/README.md -> ../outside.md` made `veryfront init proj` exit 0, print "proj ready", and write the README to `outside.md` outside the project. The check now walks every segment, including the last, and refuses a link anywhere along the path: Directory "proj" already contains README.md as a file or a link the scaffold cannot write through. Move it aside or use a different name. A real file at a scaffold path is deliberately not refused here. It resolves fine and stays the ordinary conflict pointing at `--force`, pinned by a test so this cannot drift into refusing any directory with a file in it. The named target being a link is still allowed on purpose. `ln -s /mnt/big/app app && veryfront init app` puts the project on another volume and every file is reachable at the path you named. Only a link you did not name can surprise you. The TUI is the second caller of `createProject` with a fail policy, and it relied on the directory check this branch removed. It reserves a new remote slug, then scaffolds into `projects/<slug>`, then writes the link for that slug. With the check gone it would adopt an existing `projects/<slug>` that holds none of the template files, and repoint a directory that is already another project. It now refuses before scaffolding. The constraint belongs in that caller, not in `createProject`: `veryfront init` accepting a directory that exists is the point of this branch, and the TUI wanting a fresh one is the opposite requirement. Tests: a dangling link at a scaffold path, the same under `--force`, a real file at a scaffold path that must stay an overwritable conflict, and a TUI slug whose directory already exists and is linked elsewhere. All fail without these changes.
…rror
A bad flag, an invalid project name, a missing positional, or a target that
already exists all rendered as "[unknown-error] Unknown/unclassified error"
with "Check logs for more details", because those sites threw plain Errors or
`createError({ type: "config" })`, which carry no registry slug. Exit codes
were split between 1 and 2 by a message-prefix heuristic.
Two registered errors now cover them:
- `invalid-argument` (existing, exit 2) for anything the caller typed wrong.
Its title drops "function" - it has always been the CLI's usage error too
(`login` already used it) and the docs catalog describes it that way.
`parseArgsOrThrow` now throws it, which classifies every command's
argument-parse failure at once (`dev --port abc`, ...), as do
`parseRuntime`, project-name validation, invalid integrations, and the
`generate` usage error.
- `already-exists` (new, 409, exit 1) for writing over something that is
there: `init` into a directory holding scaffold files, and `generate` onto
an existing file. Its suggestion is command-agnostic because `generate` has
no --force; `init` keeps the --force hint in its detail.
Exit code 2 is the style guide's "invalid usage" code; the router heuristic
stays as the fallback for sites not yet converted.
Tests pin the slug and exit code at the unit level (registry, parseRuntime,
parseArgsOrThrow, generate, createProject) and at the process level (init
integration: exit 2 with [invalid-argument], exit 1 with [already-exists],
never unknown-error). Error reference and API reference regenerated.
Closes veryfront/veryfront-issue-inbox#740.
|
Warning Review limit reached
Next review available in: 12 minutes Limit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?Wait for the limit to reset, then comment An organization admin can change what happens after included review limits in Billing. How do review limits work?CodeRabbit enforces per-developer PR review limits within each organization. For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (28)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
… titles The RSC client bundles inline the error registry, so renaming `invalid-argument` and adding `already-exists` left `rsc-bundles.generated.ts` holding the old "Invalid function argument" title. `deno task typecheck` runs `generate:manifests:check` first and failed on it, which the required `ci (typecheck)` job would have caught once this PR targets main.
# Conflicts: # cli/commands/init/init-command.ts # cli/commands/init/init.integration.test.ts # cli/shared/project-creation.test.ts # cli/shared/project-creation.ts # docs/api-reference/veryfront/scaffold.md
📦 Client bundle boundary
A server module in a client graph aborts hydration in the browser. New leaks fail CI; known leaks are tracked in |
|
@codex review |
|
Codex Review: Didn't find any major issues. What shall we delve into next? Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
The registry count assertion is an exact number, so two PRs each adding one error are individually correct and wrong together. This branch adds already-exists and main added one more while it waited, giving 122. Caught by the merge queue rather than by either branch's own CI: each passed alone.
|
@codex review |
|
@coderabbitai review |
|
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
…fuses (#4011) * fix(mcp): let vf_create_project refuse exactly what veryfront init refuses The tool kept its own pre-check, "Directory already exists: <path>", so an empty directory or a fresh clone holding only .git was refused here while `veryfront init` (since the current-directory and empty-directory fixes) scaffolds into both, and a real conflict was reported without naming the file. The pre-check is gone: `createProject` is the single authority, and its refusal - `Directory "x" already contains README.md. Use --force to overwrite.` - reaches the caller through the existing failure envelope. Tests: a directory holding a scaffold file is refused with the file named and left intact; an existing empty directory scaffolds. * fix(init): refuse a linked project root instead of scaffolding through it Dropping the `vf_create_project` pre-check handed the target decision to `createProject`, which never looked at the project root itself: `findUnwritablePaths` walks only the paths beneath it. A symlink at the root therefore passed, and the scaffold wrote its files, its `.gitignore` and its installed dependencies into the link target, which can sit outside the requested parent entirely. The tool reported success. The scaffold picks that path itself by joining the name onto the parent, so a link there sends every write somewhere the caller never named. `createProject` now refuses it, for the same reason a link at any other scaffold path is already refused. A parent directory the caller passed in is their own choice, so only the derived path is checked. Fixing it in `createProject` closes the same hole for `veryfront init`, not just the MCP tool. * Refuse linked gitignore before scaffold merge The project creation preflight already rejects symlinks on paths the scaffold writes outright. The generated .gitignore is merged instead of treated as a normal overwrite conflict, but the merge still writes to that path and would follow a symlink outside the project. This keeps regular .gitignore merge behavior while adding it to the write-through protection list, with shared and MCP regression coverage for the outside-target case. Constraint: Preserve existing .gitignore merge behavior for regular files Rejected: Add .gitignore to scaffoldWritePaths | that would turn normal .gitignore merges into overwrite conflicts Confidence: high Scope-risk: narrow Tested: VF_DISABLE_LRU_INTERVAL=1 deno test --no-check --allow-all cli/shared/project-creation.test.ts Tested: VF_DISABLE_LRU_INTERVAL=1 deno test --no-check --allow-all cli/mcp/tools/catalog-tools.test.ts Tested: deno lint cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: deno check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts * Protect scaffold reuse lockfile leaves The project creation preflight now treats installer-generated lockfiles as possible writes when dependency installation is enabled, so fail-policy reuse rejects a user-owned package-lock before npm can replace it. The same protected-leaf check rejects a directory at merge-only leaves such as .gitignore before scaffold files are written, preventing partial project creation. Constraint: Preserve regular .gitignore merge behavior and force-overwrite behavior for ordinary lockfiles Rejected: Disable dependency installation for reused directories | too broad and would remove expected vf_create_project behavior Confidence: high Scope-risk: narrow Tested: VF_DISABLE_LRU_INTERVAL=1 deno test --no-check --allow-all cli/shared/project-creation.test.ts Tested: VF_DISABLE_LRU_INTERVAL=1 deno test --no-check --allow-all cli/mcp/tools/catalog-tools.test.ts Tested: deno lint cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: deno check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts * Close remaining scaffold reuse write-through gaps The reuse preflight now covers npm's hidden lockfile and rejects non-file protected merge leaves before scaffold writes begin. The generated scaffold docs were refreshed so source anchors point at the current declarations. Constraint: Preserve regular .gitignore merge behavior and ordinary lockfile fail-policy semantics. Rejected: Reject any existing node_modules directory | too broad because only npm's hidden lockfile is a deterministic installer write target here. Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep merge-only leaves in protectedLeafPaths out of normal overwrite conflict detection, but preflight every non-regular leaf before writeGitignore runs. Tested: Deno 2.7.7; VF_DISABLE_LRU_INTERVAL=1 deno test --no-check --allow-all cli/shared/project-creation.test.ts Tested: Deno 2.7.7; VF_DISABLE_LRU_INTERVAL=1 deno test --no-check --allow-all cli/mcp/tools/catalog-tools.test.ts Tested: Deno 2.7.7; deno fmt --check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts docs/api-reference/veryfront/scaffold.md Tested: Deno 2.7.7; deno lint cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: Deno 2.7.7; deno check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: Deno 2.7.7; deno task docs:api-reference:check Not-tested: Full repository test suite. * Protect npm shrinkwrap during scaffold reuse npm treats npm-shrinkwrap.json as an installation-owned lockfile and can update it during install. Reused project directories now preflight that path with the rest of the installer write set so conflictPolicy fail refuses it before scaffold writes or dependency installation. Constraint: Keep dependency installation enabled for safe reused directories. Rejected: Disable npm install whenever a reused directory exists | too broad; only deterministic installer-owned write targets need preflight protection. Confidence: high Scope-risk: narrow Reversibility: clean Directive: Add future package-manager-owned write targets to installerWritePaths so conflict detection and write-through protection stay coupled. Tested: Deno 2.7.7; VF_DISABLE_LRU_INTERVAL=1 deno test --no-check --allow-all cli/shared/project-creation.test.ts Tested: Deno 2.7.7; VF_DISABLE_LRU_INTERVAL=1 deno test --no-check --allow-all cli/mcp/tools/catalog-tools.test.ts Tested: Deno 2.7.7; deno fmt --check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts docs/api-reference/veryfront/scaffold.md Tested: Deno 2.7.7; deno lint cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: Deno 2.7.7; deno check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: Deno 2.7.7; deno task docs:api-reference:check Not-tested: Full repository test suite. * Refuse npm node_modules reuse before install npm install can prune existing node_modules content before returning success. Reused project directories now treat node_modules as an npm installer conflict when dependency installation is enabled, so conflictPolicy fail refuses the directory before scaffold writes or install side effects. Constraint: Preserve safe reused-directory scaffolding when dependency installation has no existing npm-owned tree to mutate. Rejected: Treat node_modules as a protected write-through leaf | conflict detection gives the user-facing fail-policy error while existing symlink protection still comes from node_modules/.package-lock.json path traversal. Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep installer conflict paths separate from installer file write paths when the path is a directory-level npm side effect. Tested: Deno 2.7.7; VF_DISABLE_LRU_INTERVAL=1 deno test --no-check --allow-all cli/shared/project-creation.test.ts Tested: Deno 2.7.7; VF_DISABLE_LRU_INTERVAL=1 deno test --no-check --allow-all cli/mcp/tools/catalog-tools.test.ts Tested: Deno 2.7.7; deno fmt --check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts docs/api-reference/veryfront/scaffold.md Tested: Deno 2.7.7; deno lint cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: Deno 2.7.7; deno check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: Deno 2.7.7; deno task docs:api-reference:check Not-tested: Full repository test suite. * Restore project creation style invariants The scaffold creation module now keeps veryfront package imports with the other external imports and keeps the unwritable-paths documentation directly attached to the function it describes. Constraint: Address exact-head standards review without changing runtime behavior. Confidence: high Scope-risk: narrow Reversibility: clean Tested: Deno 2.7.7; VF_DISABLE_LRU_INTERVAL=1 deno test --no-check --allow-all cli/shared/project-creation.test.ts Tested: Deno 2.7.7; deno fmt --check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts docs/api-reference/veryfront/scaffold.md Tested: Deno 2.7.7; deno lint cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: Deno 2.7.7; deno check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: Deno 2.7.7; deno task docs:api-reference:check Not-tested: Full repository test suite. * Replace gitignore atomically before scaffolding Existing .gitignore files are merge-only, but direct writes can mutate hard-linked files and late write failures can leave a partial scaffold. The merge now writes a same-directory temporary file, renames it over .gitignore, and happens before the rest of the scaffold output. Constraint: Preserve regular .gitignore merge semantics while preventing writes through shared inodes or late permission failures. Rejected: Keep direct writeTextFile with more preflight checks | hard links are easier and safer to handle by replacing the path instead of mutating the inode. Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep .gitignore as a merge-only path; do not re-add it to overwrite conflict detection without preserving existing ignore entries. Tested: Deno 2.7.7; VF_DISABLE_LRU_INTERVAL=1 deno test --no-check --allow-all cli/shared/project-creation.test.ts Tested: Deno 2.7.7; VF_DISABLE_LRU_INTERVAL=1 deno test --no-check --allow-all cli/mcp/tools/catalog-tools.test.ts Tested: Deno 2.7.7; deno fmt --check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts docs/api-reference/veryfront/scaffold.md Tested: Deno 2.7.7; deno lint cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: Deno 2.7.7; deno check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: Deno 2.7.7; deno task docs:api-reference:check Not-tested: Full repository test suite. * Fail closed on unreadable gitignore merges Existing .gitignore content is merge input. Treating every read failure as absence could replace unreadable user content and then continue scaffolding. The merge now treats only missing .gitignore as absent; any other read failure happens before scaffold writes. Constraint: Preserve absent .gitignore behavior and atomic replacement semantics. Rejected: Swallow all read errors and rely on rename | replaces unreadable existing content under fail policy. Confidence: high Scope-risk: narrow Reversibility: clean Directive: Do not broaden read-error handling for merge-only files; only NotFound means absent. Tested: deno test --no-check --allow-all cli/shared/project-creation.test.ts Tested: deno test --no-check --allow-all cli/mcp/tools/catalog-tools.test.ts Tested: deno fmt --check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts docs/api-reference/veryfront/scaffold.md Tested: deno lint cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: deno check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: deno task docs:api-reference:check Not-tested: Full repository test suite. * Protect Bun scaffold installs from existing node_modules Bun installs dependencies into node_modules like npm-family package managers. Reused project targets must therefore reject an existing node_modules tree before installation can prune or replace user-owned files. The unsupported atomic-gitignore capability branch now also uses the file-local config error helper so the error stays on the registered VeryfrontError path. Constraint: Keep MCP create-project behavior unchanged; it currently exposes no runtime input and always calls shared creation with runtime node. Rejected: Add a Bun runtime option to vf_create_project | broadens the MCP tool contract beyond this conflict-safety fix. Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep installer conflict paths aligned with NPM_FAMILY_CLIENTS when a package manager writes node_modules. Tested: deno test --no-check --allow-all cli/shared/project-creation.test.ts Tested: deno test --no-check --allow-all cli/mcp/tools/catalog-tools.test.ts Tested: deno fmt --check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts docs/api-reference/veryfront/scaffold.md Tested: deno lint cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: deno check cli/shared/project-creation.ts cli/shared/project-creation.test.ts cli/mcp/tools/catalog-tools.test.ts Tested: deno task docs:api-reference:check Not-tested: Full repository test suite. --------- Co-authored-by: Kentaro Wakayama <kentaro@codersociety.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
Codex Review: Didn't find any major issues. 🎉 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
|
Pushed exact head This fixes the only red hosted gate after merging current main:
Fresh exact-head verification: 44 focused steps passed; semantic unit-boundary audit passed; test-layout passed; production typecheck passed; full @codex review Please review exact head |
Greptile SummaryThe PR classifies several CLI input and target-conflict failures with registered errors while preserving their intended exit-code distinction.
Confidence Score: 5/5The PR appears safe to merge; no concrete blocking or independently actionable non-blocking issue remains. The changed error classifications preserve the intended usage and operational exit codes, while the expanded project-creation preflight rejects reachable conflicts and symlink write-through paths before writing.
|
| Filename | Overview |
|---|---|
| cli/shared/project-creation.ts | Centralizes classified validation and conflict failures, expands installer and symlink preflight checks, and atomically replaces the merged .gitignore. |
| cli/shared/args.ts | Changes shared parser failures from plain errors to registered invalid-argument errors with usage exit code 2. |
| cli/commands/generate/command.ts | Reports scaffold file conflicts through the new already-exists definition while retaining conflict details. |
| cli/commands/generate/handler.ts | Classifies missing or invalid generate operands as registered usage errors. |
| cli/commands/init/runtime.ts | Classifies unsupported runtime values as invalid-argument and records diagnostic context. |
| cli/mcp/tools/catalog-tools.ts | Removes the coarse existing-directory rejection and delegates precise conflict detection to shared project creation. |
| src/errors/error-registry/general.ts | Adds already-exists, assigns its conflict semantics and exit code, and generalizes the invalid-argument title. |
| src/errors/catalog/general-errors.ts | Adds user-facing catalog guidance for the new already-exists slug. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[CLI or MCP project request] --> B[Validate arguments and project name]
B -->|Invalid input| C[invalid-argument, exit 2]
B -->|Valid| D[Assemble scaffold]
D --> E[Preflight scaffold, installer, and symlink conflicts]
E -->|Conflict| F[already-exists, exit 1]
E -->|Clear| G[Atomically merge .gitignore]
G --> H[Write scaffold and metadata]
H --> I[Install dependencies and initialize Git]
Reviews (1): Last reviewed commit: "test(suites): classify CLI filesystem co..." | Re-trigger Greptile
|
Codex Review: Didn't find any major issues. What shall we delve into next? Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
Summary
Addresses veryfront/veryfront-issue-inbox#740 and fixes all seven repros it lists.
That issue stays open on purpose. 31 sites across 8 files still render
[unknown-error]forthe same class of user-input mistake (verified live:
veryfront uploads list --limit abc).They are tracked in veryfront/veryfront-issue-inbox#767, together with the
cli/router.ts:291prefix heuristic they currently depend on for their exit codes.
#4002 has landed, so this now targets
maindirectly.origin/mainwas merged in, not rebased.User-input mistakes rendered as
[unknown-error] Unknown/unclassified error … Check logs for more detailsbecause the sites threw plainErrors orcreateError({ type: "config" }), which carry no registry slug; exit codes were split 1/2 by a message-prefix heuristic in the router. Two registered errors now cover them:invalid-argument(existing)parseArgsOrThrow(so every command's arg-parse failure, e.g.dev --port abc),parseRuntime, project-name validation, invalid integrations,generateusagealready-exists(new, 409)initinto a dir holding scaffold files (incl. #4002's "file or link in the way" refusal),generateonto an existing fileBefore / after (
0.1.1251vs this branch):Decisions:
invalid-argumentis reused rather than adding a CLI-only slug:loginalready returnsregistrySlug: "invalid-argument"for usage errors and the docs catalog already describes it as "Command received invalid argument". Only its registry title changes ("Invalid function argument" → "Invalid argument"; nothing asserted the old title).already-existsgets a command-agnostic suggestion ("choose a different name, or remove the existing target first") becausegeneratehas no--force;init's detail keeps "Use --force to overwrite."startsWith("Invalid ")fallback is left in place for sites not yet converted.Test plan
parseRuntime,parseArgsOrThrow,generateusage + conflict,createProjectname + conflict, and the subprocess-level init integration pinningexit 2 + [invalid-argument]/exit 1 + [already-exists]/ neverunknown-error)src/errors/,cli/commands/init/(incl. all integration files),cli/commands/generate/,cli/shared/,cli/app/operations/,cli/commands/{deploy,merge,dev}/handler.test.ts,cli/auth/exit-code.integration.test.ts,tests/docs/error-docs-links.test.ts— 60+ files passlint:test-typecheck,lint:anti-slop,lint:sanitizer-baseline,docs:errors:check,docs:public:check,docs:api-reference:check(regenerated with CI's Deno 2.7.7) all cleansrc/server/services/rsc/endpoints/rsc-bundles.generated.tsregenerated: the RSC client bundles inline the error registry, so the renamedinvalid-argumenttitle and the newalready-existsentry made the committed bundle stale and failedgenerate:manifests:check, whichdeno task typecheckruns first