--force is documented as "Allow scaffolding into a non-empty folder" (src/commands/create.js:25), but it never works on the default path. It only works with --from.
Orientation
node bin/brmbh.js create demo --from ../brmbh-agentic-wp-suite # local copy path
node bin/brmbh.js create demo # clone path (default)
create has two ways to get the theme files, both in materializeTheme() (src/registry.js:22):
--from <path> → copyDir() (src/fsutil.js:36), which merges into an existing directory happily
- default →
git clone --depth 1 (src/registry.js:43-47), which refuses a non-empty destination
Repro
mkdir my-site && touch my-site/keep.txt
node bin/brmbh.js create my-site
# → ✗ Folder already exists and is not empty: … / Pass --force to scaffold anyway. (correct)
node bin/brmbh.js create my-site --force
# → ✗ `git clone --depth 1 https://… my-site` exited with code 128 (wrong)
git's own message — fatal: destination path 'my-site' already exists and is not an empty directory — is streamed to the terminal, but the CLI's own error is the opaque command_failed exit code. In --json mode the envelope reports {"ok":false,"code":"command_failed"} with no hint that --force is the thing that failed.
Where it goes wrong
src/commands/create.js:37-42 correctly skips the empty-folder guard when --force is set. Execution then falls through to materializeTheme(), which has no concept of --force at all — the flag is never passed to it (src/registry.js:22 takes { dest, from, ref, ctx }).
Options
- Clone to a temp dir, then merge — clone into
fs.mkdtemp(), delete .git, copyDir() into dest, remove the temp dir. Makes --force behave identically on both paths. Most work, best result.
- Download a tarball instead of cloning — extraction over an existing directory just works, and removes the hard
git dependency. Bigger change than this issue needs; only worth it if wanted for other reasons.
- Make the limitation explicit — if
--force and no --from, fail early with a real message: "--force requires --from (git cannot clone into a non-empty folder)". Cheapest, honest, but leaves the flag half-useful.
Recommend option 1.
Acceptance
mkdir my-site && touch my-site/keep.txt
node bin/brmbh.js create my-site --force --skip-install
ls my-site # → keep.txt AND the theme files
And whichever option is chosen, no path may surface a bare exited with code 128. Use ToolError (src/tool.js:24) with a code and detail so both pretty and --json modes explain the cause.
Note
There is no test suite — package.json declares "test": "node --test test/" but no test/ directory exists. This bug is a good candidate for the first test, if we want one.
--forceis documented as "Allow scaffolding into a non-empty folder" (src/commands/create.js:25), but it never works on the default path. It only works with--from.Orientation
createhas two ways to get the theme files, both inmaterializeTheme()(src/registry.js:22):--from <path>→copyDir()(src/fsutil.js:36), which merges into an existing directory happilygit clone --depth 1(src/registry.js:43-47), which refuses a non-empty destinationRepro
git's own message —
fatal: destination path 'my-site' already exists and is not an empty directory— is streamed to the terminal, but the CLI's own error is the opaquecommand_failedexit code. In--jsonmode the envelope reports{"ok":false,"code":"command_failed"}with no hint that--forceis the thing that failed.Where it goes wrong
src/commands/create.js:37-42correctly skips the empty-folder guard when--forceis set. Execution then falls through tomaterializeTheme(), which has no concept of--forceat all — the flag is never passed to it (src/registry.js:22takes{ dest, from, ref, ctx }).Options
fs.mkdtemp(), delete.git,copyDir()intodest, remove the temp dir. Makes--forcebehave identically on both paths. Most work, best result.gitdependency. Bigger change than this issue needs; only worth it if wanted for other reasons.--forceand no--from, fail early with a real message: "--forcerequires--from(git cannot clone into a non-empty folder)". Cheapest, honest, but leaves the flag half-useful.Recommend option 1.
Acceptance
And whichever option is chosen, no path may surface a bare
exited with code 128. UseToolError(src/tool.js:24) with acodeanddetailso both pretty and--jsonmodes explain the cause.Note
There is no test suite —
package.jsondeclares"test": "node --test test/"but notest/directory exists. This bug is a good candidate for the first test, if we want one.