Skip to content

fix(cli): tolerate safe leftovers in smpy new --dest . (#148) - #150

Merged
antosubash merged 1 commit into
mainfrom
claude/work-on-open-issues-R69p2
May 13, 2026
Merged

fix(cli): tolerate safe leftovers in smpy new --dest . (#148)#150
antosubash merged 1 commit into
mainfrom
claude/work-on-open-issues-R69p2

Conversation

@antosubash

@antosubash antosubash commented May 13, 2026

Copy link
Copy Markdown
Owner

Summary

  • smpy new --dest . was refusing any non-empty destination, which blew up the common gh repo create myapp && cd myapp && smpy new myapp --dest . flow the moment .git/, .gitignore, or README.md was present (closes smpy new --dest . refuses non-empty directories — blocks scaffolding into a fresh git init / worktree #148).
  • Scaffolding now tolerates a small allowlist (SAFE_PRESERVED_NAMES in scaffolding.py) at the target — VCS metadata (.git/, .gitignore, .gitattributes), docs (README*, LICENSE*, COPYING, CHANGELOG.md, CONTRIBUTING.md, CODE_OF_CONDUCT.md), and editor/tooling metadata (.claude/, .vscode/, .idea/, .editorconfig, .DS_Store). Any other pre-existing entry still raises FileExistsError, naming the colliding files so the user knows what to move aside.
  • When the scaffold would write over a tolerated pre-existing file (e.g. user has a .gitignore, scaffold also has one), the scaffold's copy is skipped — the user's file wins. smpy new surfaces a Preserved existing files notice listing what was skipped so users can merge in scaffold content by hand if they care.
  • create_workspace / create_host accept a preserve_existing set and return the list of preserved paths; _require_empty_dest accepts the same set; create_app_project returns (host_dir, preserved).

Test plan

  • uv run pytest framework/cli/tests/ — 121 passed (3 new regression tests in test_cli_new_dest_tolerance.py)
  • uv run ruff check framework/cli/ + uv run ruff format --check framework/cli/ clean
  • uv run ty check framework/cli/simple_module_cli/ clean
  • uv run python scripts/check_file_size.py — no files exceed 300 lines
  • Manual smoke: smpy new myapp --yes --no-install --dest . against a directory with .git/, .gitignore (*.pyc), README.md, and LICENSE succeeds; user files are byte-identical after the run; scaffold's Makefile, pyproject.toml, host/, modules/ land alongside them; CLI prints the preservation notice for .gitignore and README.md.
  • Manual smoke: smpy new myapp --yes --no-install --dest . against a directory with notes.txt still hard-fails (exit=1), names notes.txt in the error, and leaves the file untouched.

https://claude.ai/code/session_01K84RjsX1ToXorMyuaxNBT6

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented May 13, 2026

Copy link
Copy Markdown

Deploying simple-module-python with  Cloudflare Pages  Cloudflare Pages

Latest commit: 7c0fa43
Status: ✅  Deploy successful!
Preview URL: https://f86b666a.simple-module-python.pages.dev
Branch Preview URL: https://claude-work-on-open-issues-r.simple-module-python.pages.dev

View logs

@antosubash
antosubash marked this pull request as ready for review May 13, 2026 16:44
`smpy new --dest .` was refusing any non-empty destination, so the
common `gh repo create myapp && cd myapp && smpy new myapp --dest .`
flow blew up the moment `.git/`, `.gitignore`, or `README.md` was
present. Closes #148.

Scaffolding now tolerates a small allowlist (`SAFE_PRESERVED_NAMES`:
`.git/`, `.gitignore`, `.gitattributes`, `README*`, `LICENSE*`,
`COPYING`, `CHANGELOG.md`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`,
`.claude/`, `.vscode/`, `.idea/`, `.editorconfig`, `.DS_Store`) at the
scaffold target. When the scaffold would write over a tolerated
pre-existing file, the scaffold's copy is skipped — the user's file
wins. Any other pre-existing entry still raises `FileExistsError`,
naming the colliding files so the user knows what to move aside.

`create_workspace` / `create_host` accept a `preserve_existing` set
and return the list of preserved paths; `create_app_project` returns
`(host_dir, preserved)`; `new.py` surfaces a `Preserved existing
files` notice listing what was skipped so users can merge content in
by hand.

Three regression tests in test_cli_new_dest_tolerance.py cover:
workspace mode tolerates a fresh `git init` layout (and user files
survive), flat mode does the same, and unrelated files still
hard-fail without being touched.

https://claude.ai/code/session_01K84RjsX1ToXorMyuaxNBT6
@antosubash
antosubash force-pushed the claude/work-on-open-issues-R69p2 branch from 375db28 to 7c0fa43 Compare May 13, 2026 16:50
@antosubash
antosubash merged commit 8152248 into main May 13, 2026
12 checks passed
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.

smpy new --dest . refuses non-empty directories — blocks scaffolding into a fresh git init / worktree

2 participants