Skip to content

feat(create): scaffold into a non-empty directory with --force - #2981

Open
kshanxs wants to merge 3 commits into
voidzero-dev:mainfrom
kshanxs:feat/create-keep-existing-files
Open

kshanxs wants to merge 3 commits into
voidzero-dev:mainfrom
kshanxs:feat/create-keep-existing-files

Conversation

@kshanxs

@kshanxs kshanxs commented Oct 10, 2026

Copy link
Copy Markdown
Contributor

Refs #2521

Problem

vp create refuses any target directory that holds more than .git, so it cannot add a project to an existing repository (a repo with a README.md, a LICENSE, or even just a .DS_Store). The only interactive choices are "Cancel" and "Remove existing files".

Change

  • New --force flag: scaffold into a non-empty directory and keep the files already there.
  • The interactive prompt gains a third choice, "Keep existing files and continue".
  • Template files that would replace an existing file are skipped and listed:
● Skipped template files that already exist: .gitignore
◇ Scaffolded . with Vite application

Without --force, non-interactive runs still fail, and the hint now mentions the flag.

How

When existing files must be kept, the template is scaffolded into a staging directory inside the target (.vite-plus-create-<random>), then moved over entry by entry; directories that exist on both sides are merged, and the staging directory is removed afterwards.

Staging is needed because widening the ignore list in the emptiness check is not enough: create-vite and degit run their own emptiness checks (create-vite --overwrite empties the directory), and the bundled/monorepo templates copy with overwrite, which would replace an existing README.md or .gitignore.

It applies to builtin and bundled @org templates, the same set that supports --directory. Remote templates are unchanged and reject --force.

Open question

On a collision this keeps the existing file. The issue suggested overwriting instead; I went with keeping because it cannot lose user work, but I am happy to switch, or to rename the flag if --force reads as "overwrite".

Tests

  • Unit tests for the merge helper and the directory check.
  • Rust parser test for the flag.
  • New snapshot case create_force_keeps_existing_files; command_create_help updated.
  • Ran all create* snapshot cases locally. Two bun cases failed in the parallel run and passed when re-run on their own.

🤖 Generated with Claude Code

`vp create` refused any target directory holding more than `.git`, so it
could not add a project to an existing repository. `--force` (and a
"Keep existing files and continue" choice in the interactive prompt) now
scaffolds into a staging directory inside the target and moves over only
the files that are not already there. Template files that would replace
an existing file are skipped and listed.

Staging is needed because create-vite and degit run their own emptiness
checks, and the bundled templates copy with overwrite.

Refs voidzero-dev#2521

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@fengmk2

fengmk2 commented Oct 10, 2026

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-10T14:55:40.631432Z 31f2b52 Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@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: 31f2b52c68

ℹ️ 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 packages/cli/src/create/bin.ts Outdated
if (result.exitCode !== 0 || !result.projectDir) {
return result;
}
const kept = moveDirKeepingExisting(stagingPath, path.join(workspaceInfo.rootDir, dir));

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 Finish setup before merging into the preserved tree

When --force targets a directory that already contains a project (for example, package.json plus eslint.config.js), this merge exposes the pre-existing files to the rest of the normal create pipeline: detectEslintProject(fullPath) then triggers promptEslintMigration(..., false), which deletes ESLint configs/dependencies, and rewriteStandaloneProject and vp fmt subsequently rewrite the existing package and source tree. Files reported as kept can therefore still be destructively changed without a prompt; perform the generated-project setup in staging, or otherwise exclude all pre-existing paths, before merging.

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.

Valid, fixed in 5850315 with a narrower change than moving the whole setup into staging:

  • A target that already has a package.json is now refused with --force, and the interactive prompt no longer offers "Keep existing files" for it. That is the case where the ESLint/Prettier migration and the package.json rewrite would run against the existing project.
  • The entries that were in the directory before scaffolding are excluded from the final vp fmt, so kept files are not reformatted. The snapshot case now keeps an unformatted README.md and a file in an existing subdirectory to cover this.

Still additive on existing files: .gitignore entries after git init, and agent/editor config writes, which already have their own handling for existing files.

The setup steps that run after scaffolding still saw the files that were
already in the target directory. Refuse a target that already has a
package.json, since those steps would rewrite it, and exclude the
pre-existing entries from the final format.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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