feat: add uninstall.sh and sqrbx-uninstall command#78
Conversation
Provide a supported removal path symmetric with sqrbx-rebuild so users can cleanly tear down a squarebox install (container, image, shell integration) without the hand-rolled one-liner. By default ~/squarebox is preserved so the workspace is not lost; --purge removes it with a second confirmation if workspace/ is non-empty. Exposed via sqrbx-uninstall / squarebox-uninstall functions and an `sqrbx uninstall` subcommand on both Bash/Zsh and PowerShell. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a first-class uninstall path for squarebox (Bash/Zsh + PowerShell), wires it into the existing sqrbx UX (including sqrbx uninstall), and updates documentation to replace the manual one-liner removal instructions.
Changes:
- Added
uninstall.shanduninstall.ps1to remove container/image + shell integration, with optional--purge/-Purge. - Updated
install.sh/install.ps1shell integration to exposesqrbx-uninstall/squarebox-uninstalland routesqrbx uninstallto the uninstaller. - Updated README + CONTRIBUTING docs to reference the supported uninstall flow.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| uninstall.sh | New Bash uninstaller handling runtime detection, rc/profile scrubbing, and optional purge. |
| uninstall.ps1 | New PowerShell uninstaller with similar behavior and profile scrubbing. |
| install.sh | Adds uninstall function(s) and sqrbx uninstall dispatch; expands scrub regex to include uninstall names. |
| install.ps1 | Adds uninstall function(s) and sqrbx uninstall dispatch; expands scrub regex to include uninstall names. |
| README.md | Replaces manual uninstall commands with sqrbx-uninstall guidance and purge semantics. |
| CONTRIBUTING.md | Documents the new uninstall scripts in the repo tooling table. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if [ "$PURGE" = 1 ] && [ "$has_install_dir" = 1 ] && [ "$YES" = 0 ]; then | ||
| _workspace_dir="${INSTALL_DIR}/workspace" | ||
| if [ -d "$_workspace_dir" ]; then | ||
| _count=$(find "$_workspace_dir" -mindepth 1 -maxdepth 1 2>/dev/null | wc -l | tr -d ' ') |
There was a problem hiding this comment.
find ... | wc -l is executed inside a command substitution under set -euo pipefail. If find returns non-zero (e.g., permission denied on workspace/—a case this script explicitly anticipates with the uid 1000 ownership note), the whole uninstall will abort before prompting. Consider guarding the pipeline (e.g., make the count computation tolerant of find errors) so --purge doesn’t fail unexpectedly in the very scenario it’s trying to handle.
| _count=$(find "$_workspace_dir" -mindepth 1 -maxdepth 1 2>/dev/null | wc -l | tr -d ' ') | |
| _count=$({ find "$_workspace_dir" -mindepth 1 -maxdepth 1 2>/dev/null || true; } | wc -l | tr -d ' ') |
| if [ -f "$_bash_profile" ] \ | ||
| && grep -qxF '# Source .bashrc for aliases and functions' "$_bash_profile" 2>/dev/null \ | ||
| && grep -qxF '[ -f "$HOME/.bashrc" ] && . "$HOME/.bashrc"' "$_bash_profile" 2>/dev/null; then |
There was a problem hiding this comment.
has_bash_profile_source_line is set based on the two lines existing anywhere in ~/.bash_profile, but the removal awk only deletes them when they are consecutive (it peeks at the next line). This can lead to the summary claiming it “Will remove” / “Scrubbed” the source snippet even when nothing is actually removed. Suggest detecting/removing the snippet using the same consecutive-lines logic (or only setting removed_bash_profile_source when the filter actually drops lines).
| if [ -f "$_bash_profile" ] \ | |
| && grep -qxF '# Source .bashrc for aliases and functions' "$_bash_profile" 2>/dev/null \ | |
| && grep -qxF '[ -f "$HOME/.bashrc" ] && . "$HOME/.bashrc"' "$_bash_profile" 2>/dev/null; then | |
| if [ -f "$_bash_profile" ] && awk ' | |
| BEGIN { | |
| prev = "" | |
| target_prev = "# Source .bashrc for aliases and functions" | |
| target_curr = "[ -f \"$HOME/.bashrc\" ] && . \"$HOME/.bashrc\"" | |
| } | |
| prev == target_prev && $0 == target_curr { found = 1; exit 0 } | |
| { prev = $0 } | |
| END { exit(found ? 0 : 1) } | |
| ' "$_bash_profile" 2>/dev/null; then |
Summary
Adds a supported removal path for squarebox, symmetric with the existing
sqrbx-rebuildcommand. Replaces the hand-rolled one-liner in the README.uninstall.sh(Linux/macOS/Git Bash) anduninstall.ps1(Windows/PowerShell 7+).sqrbx-uninstall/squarebox-uninstallshell functions, and as ansqrbx uninstallsubcommand on both Bash/Zsh and PowerShell.~/squarebox(workspace);--purgeremoves it with a second confirmation ifworkspace/is non-empty.-y/-Yesto skip all prompts for scripting.Design
install.sh:--runtimeflag >SQUAREBOX_RUNTIME> auto-detect by querying which runtime has thesquareboxcontainer/image. If both do (unusual), preferdockerand warn thatpodmanstate also exists so the user can clean it withSQUAREBOX_RUNTIME=podman.install.sh:228-235, extended in all three sites (install.sh,install.ps1, newuninstall.sh) to also matchsqrbx-uninstall/squarebox-uninstallfunction/alias names so reinstall-after-uninstall cleans up properly. Consolidating the duplicated scrub across all four scripts is flagged as a future refactor and intentionally not in this PR.~/squarebox/uninstall.sh(or.ps1) directly when the shell functions aren't available.--purgefalls back tosudo rm -rfif plainrmfails (container'sdevuser may own some files).Test plan
Unit-level (already verified):
bash -n install.shandbash -n uninstall.shparse clean.install.shrenders valid shell (tested with live RUNTIME/INSTALL_DIR substitution).install.sh,install.ps1,uninstall.sh.--help,--runtime=bogus, unknown-flag paths error with the expected exit codes.uninstall.sh -yagainst a fake$HOMEpreserves user content in.bashrcbefore and after the sentinel block.Manual E2E (to run before merge; host-side install/uninstall tests are out of scope for automated CI):
install.sh; verify container, image, sentinel, init file exist.~/squarebox/workspace/.sqrbx-uninstall(default); confirm prompt, accept. Verify container/image/sentinel/init gone;~/squarebox/and marker file still present.sqrbx-uninstall --purge; hit the workspace-non-empty warning; abort.sqrbx-uninstall --purge -y; verify~/squarebox/fully removed.bash -i -c 'type sqrbx'in a new shell returns "not found".install.ps1+sqrbx-uninstall.sqrbx-uninstallagain with nothing installed -> exit 0 with "nothing to do".rm -fstill works..bashrcwith user content above and below the sentinel: only the block is removed.Out of scope
scripts/e2e-test.shruns inside the container; host flow would need a separate effort).🤖 Generated with Claude Code