Skip to content

feat: add uninstall.sh and sqrbx-uninstall command#78

Merged
BrettKinny merged 1 commit intomainfrom
claude/kind-moore
Apr 17, 2026
Merged

feat: add uninstall.sh and sqrbx-uninstall command#78
BrettKinny merged 1 commit intomainfrom
claude/kind-moore

Conversation

@BrettKinny
Copy link
Copy Markdown
Collaborator

Summary

Adds a supported removal path for squarebox, symmetric with the existing sqrbx-rebuild command. Replaces the hand-rolled one-liner in the README.

  • New uninstall.sh (Linux/macOS/Git Bash) and uninstall.ps1 (Windows/PowerShell 7+).
  • Exposed via sqrbx-uninstall / squarebox-uninstall shell functions, and as an sqrbx uninstall subcommand on both Bash/Zsh and PowerShell.
  • Default-preserves ~/squarebox (workspace); --purge removes it with a second confirmation if workspace/ is non-empty.
  • -y / -Yes to skip all prompts for scripting.
  • Idempotent: nothing-to-do exit 0 on re-run.

Design

  • Runtime detection mirrors install.sh: --runtime flag > SQUAREBOX_RUNTIME > auto-detect by querying which runtime has the squarebox container/image. If both do (unusual), prefer docker and warn that podman state also exists so the user can clean it with SQUAREBOX_RUNTIME=podman.
  • Scrub logic reuses the exact awk pattern from install.sh:228-235, extended in all three sites (install.sh, install.ps1, new uninstall.sh) to also match sqrbx-uninstall / squarebox-uninstall function/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.
  • Broken-state recovery: README documents running ~/squarebox/uninstall.sh (or .ps1) directly when the shell functions aren't available.
  • uid 1000 fallback: on Linux where the install ran as a non-1000 user, --purge falls back to sudo rm -rf if plain rm fails (container's dev user may own some files).

Test plan

Unit-level (already verified):

  • bash -n install.sh and bash -n uninstall.sh parse clean.
  • Heredoc in install.sh renders valid shell (tested with live RUNTIME/INSTALL_DIR substitution).
  • Scrub regex is consistent across install.sh, install.ps1, uninstall.sh.
  • --help, --runtime=bogus, unknown-flag paths error with the expected exit codes.
  • uninstall.sh -y against a fake $HOME preserves user content in .bashrc before and after the sentinel block.

Manual E2E (to run before merge; host-side install/uninstall tests are out of scope for automated CI):

  • Fresh install via install.sh; verify container, image, sentinel, init file exist.
  • Drop a marker file in ~/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".
  • Repeat on Windows with install.ps1 + sqrbx-uninstall.
  • Idempotency: run sqrbx-uninstall again with nothing installed -> exit 0 with "nothing to do".
  • Podman install path: uninstall picks podman and doesn't error on missing docker.
  • Container in Exited state (not Running): rm -f still works.
  • .bashrc with user content above and below the sentinel: only the block is removed.

Out of scope

  • Automated host-side install/uninstall tests (existing scripts/e2e-test.sh runs inside the container; host flow would need a separate effort).
  • Factoring the scrub logic into a shared helper across all four scripts.

🤖 Generated with Claude Code

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>
Copilot AI review requested due to automatic review settings April 17, 2026 10:42
@BrettKinny BrettKinny merged commit aa7a68e into main Apr 17, 2026
3 checks passed
@BrettKinny BrettKinny deleted the claude/kind-moore branch April 17, 2026 10:43
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.sh and uninstall.ps1 to remove container/image + shell integration, with optional --purge/-Purge.
  • Updated install.sh / install.ps1 shell integration to expose sqrbx-uninstall / squarebox-uninstall and route sqrbx uninstall to 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.

Comment thread uninstall.sh
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 ' ')
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
_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 ' ')

Copilot uses AI. Check for mistakes.
Comment thread uninstall.sh
Comment on lines +169 to +171
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
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Suggested change
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

Copilot uses AI. Check for mistakes.
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