Skip to content
This repository was archived by the owner on Sep 10, 2026. It is now read-only.

Refuse an occupied destination before asking, not after - #43

Merged
seenu-k merged 1 commit into
mainfrom
fix/occupied-destination
Aug 8, 2026
Merged

seenu-k merged 1 commit into
mainfrom
fix/occupied-destination

Conversation

@seenu-k

@seenu-k seenu-k commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #41, which is merged but not yet released — Release PR #42 is still open, so this amends that changeset rather than adding a second one. Same version, one coherent entry.

The gap

scaffoldGame raised target already exists at index.ts:743, which runs after every question. So the flow was: greeting, Firebase probe, organization prompt (the one you're meant to think about, because Google Play freezes it), git, workflows — and then "target already exists".

That is precisely the failure mode #41 set out to remove. The comment on firebaseReadiness says learning flutterfire is missing "costs nothing here and costs two minutes of Flutter and pub at the far end". Same argument, and I missed this instance of it.

destinationProblem is now asked before the greeting, alongside the slug validation.

The message

create-eigen-game: /tmp/dir-check/my-game already exists, and is not empty — it holds README.md, app, notes.txt.

Scaffold somewhere else, or clear it out yourself. This will not delete a directory you already had.

Three entries named rather than a count. "Not empty" only invites an ls; the three that are actually there usually settle whether this was a mistyped path or a directory already scaffolded once.

No "remove it and continue?"

Several scaffolders in this family offer that. This one writes ninety-odd files and calls flutter create, and the cost of that answer being wrong against a mistyped path has no upper bound. Every other question this CLI asks is reversible; that one would not be, so it stays a refusal and rm -rf stays a command belonging to the person who can see what is in there.

Worth noting this is the one place I did not follow the question-per-flag rule from #41, and the reason is that rule's own logic — a question exists to let someone decide something, not to let a pipe decide it.

Empty directories are now fine

Refusing over nothing was its own papercut: people mkdir my-game out of habit, and cloning a repository that has no first commit yet leaves exactly an empty directory. It is removed and rewritten, because the staging rename publishes itself as that path and cannot do so while anything is standing there.

Verification

  • 71 tests (up from 65). New: empty-directory scaffold succeeds; a non-empty one throws and leaves the contents byte-identical; a destination that is a file is caught; the message names three and counts the rest.
  • Driven with the built CLI: occupied path errors at once with nothing drawn after it, and the directory is untouched. A full scaffold into a pre-existing empty directory completes, installs, commits and summarises.
  • biome check . clean; tsc --noEmit clean.

🤖 Generated with Claude Code

`scaffoldGame` raised `target already exists` at the very end, so the CLI
greeted you, probed for Firebase, and took an organization, a git answer and a
workflows answer before mentioning that the directory was taken. That is the
same insult as learning `flutterfire` is missing after two minutes of Flutter
and pub, which this release just finished fixing.

`destinationProblem` is now asked before the greeting. It names the first three
entries standing in the way rather than saying "not empty", because that
usually settles whether the path was mistyped or already scaffolded once, where
a bare "not empty" only invites an `ls`.

It deliberately does not offer to remove the directory, which is where several
scaffolders in this family go. This one writes ninety-odd files and calls
`flutter create`; the cost of that answer being wrong against a mistyped path
has no upper bound, and every other question here is reversible.

A directory that exists and is empty is no longer refused at all — people make
one out of habit, and cloning a repository with no first commit leaves exactly
that. It is removed and rewritten, since the staging rename publishes itself
*as* that path and cannot do it while something is standing there.

The changeset is amended rather than added to: #41 is merged but the release
PR is still open, so this is the same unreleased change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@seenu-k
seenu-k merged commit 8f6a139 into main Aug 8, 2026
3 checks passed
@seenu-k
seenu-k deleted the fix/occupied-destination branch August 8, 2026 07:21
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant