Skip to content

Conversation

@swhsiang
Copy link

@swhsiang swhsiang commented Aug 12, 2025

Summary

  • Adds a comprehensive uninstall script for ClaudeBox
  • Provides clean removal of all ClaudeBox components
  • Includes user-friendly colored output and clear feedback

Details

This PR introduces uninstall.sh, a complete uninstallation script that:

Features

  • Symlink removal: Removes the claudebox command from ~/.local/bin/
  • Directory cleanup: Removes the main installation directory ~/.claudebox
  • Project cleanup: Finds and removes all project-specific directories (.claudebox-*)
  • Docker cleanup: Removes all ClaudeBox-related Docker containers and images
  • PATH guidance: Provides instructions for cleaning up PATH configuration if needed
  • Optional installer removal: Offers to remove the installer file if present

User Experience

  • Colored output for better readability (green ✓, yellow ⚠, red ✗)
  • Safe handling of already-removed components
  • Clear summary of what was removed
  • No errors if components are already missing

Safety

  • Uses set -e for error handling
  • Safely checks for existence before removal
  • Handles Docker not being installed/running gracefully
  • Confirms before removing the installer file

Test Plan

  • Run on a system with full ClaudeBox installation

🤖 Generated with Claude Code

Summary by Sourcery

Introduce a comprehensive uninstall.sh script to fully remove ClaudeBox components, including symlink, installation and project-specific directories, Docker containers and images, and optionally the installer file, with user-friendly colored output and safety checks

New Features:

  • Add uninstall.sh script to remove ClaudeBox symlink, installation directory, project-specific folders, and related Docker resources
  • Prompt optionally to delete the installer file if present

Enhancements:

  • Display colored status messages and icons for improved readability
  • Perform existence checks and handle missing components or Docker gracefully

This script provides a complete uninstallation process for ClaudeBox:
- Removes symlink from ~/.local/bin/claudebox
- Removes installation directory ~/.claudebox
- Cleans up project-specific directories (.claudebox-*)
- Removes Docker containers and images related to ClaudeBox
- Provides user guidance on PATH configuration cleanup
- Optionally removes the installer file

The script uses colored output for better user experience and
safely handles cases where components may already be removed.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@sourcery-ai
Copy link

sourcery-ai bot commented Aug 12, 2025

Reviewer's Guide

Introduces a comprehensive uninstall.sh script for ClaudeBox that guides users through removal of all components with safety checks, colored output, and optional cleanup prompts.

File-Level Changes

Change Details Files
Add uninstall.sh with structured error handling and output functions
  • Create uninstall.sh with shebang and set -e for strict mode
  • Define color variables and modular print functions for success, warning, error, and info
uninstall.sh
Implement removal logic for ClaudeBox artifacts
  • Remove ~/.local/bin/claudebox symlink if present
  • Delete main installation directory ~/.claudebox
  • Locate and delete project-specific .claudebox-* directories
uninstall.sh
Integrate Docker resource cleanup
  • Check for Docker availability and skip if not installed or running
  • Remove any ClaudeBox-related Docker containers
  • Remove any ClaudeBox-related Docker images
uninstall.sh
Provide PATH guidance, final summary, and installer prompt
  • Inspect PATH for ~/.local/bin and suggest rc file edits
  • Summarize uninstallation outcome based on removed items
  • Prompt user to optionally remove the claudebox.run installer file
uninstall.sh

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @swhsiang - I've reviewed your changes - here's some feedback:

  • Consider adding noninteractive flags like --force or --dry-run so users can preview or automate the uninstall without prompts.
  • Rather than using set -e globally, wrap optional cleanup steps in their own error handlers so a single failure won’t abort the entire summary.
  • Grep-matching Docker names/images may remove unrelated items—use specific Docker labels or more precise filters to target only ClaudeBox resources.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider adding noninteractive flags like --force or --dry-run so users can preview or automate the uninstall without prompts.
- Rather than using set -e globally, wrap optional cleanup steps in their own error handlers so a single failure won’t abort the entire summary.
- Grep-matching Docker names/images may remove unrelated items—use specific Docker labels or more precise filters to target only ClaudeBox resources.

## Individual Comments

### Comment 1
<location> `uninstall.sh:64` </location>
<code_context>
+# 3. Check for project-specific directories
+echo ""
+echo "Checking for project-specific ClaudeBox directories..."
+PROJECT_DIRS=$(find "$HOME" -maxdepth 1 -type d -name ".claudebox-*" 2>/dev/null || true)
+if [ -n "$PROJECT_DIRS" ]; then
+    echo "$PROJECT_DIRS" | while read -r dir; do
+        rm -rf "$dir"
+        print_success "Removed project directory: $dir"
</code_context>

<issue_to_address>
Using a pipeline with 'while read' can cause issues with variable scope in bash.

Because the 'while read' loop runs in a subshell, any changes to variables like 'REMOVED_SOMETHING' inside the loop won't affect the parent shell. Switching to a 'for' loop will ensure variable updates are retained.
</issue_to_address>

### Comment 2
<location> `uninstall.sh:82` </location>
<code_context>
+# Check if Docker is installed and running
+if command -v docker &> /dev/null && docker info &> /dev/null; then
+    # Check for containers
+    CONTAINERS=$(docker ps -a --format "{{.ID}} {{.Names}}" | grep -i claudebox | awk '{print $1}' 2>/dev/null || true)
+    if [ -n "$CONTAINERS" ]; then
+        print_warning "Found ClaudeBox Docker containers. Removing..."
+        echo "$CONTAINERS" | while read -r container; do
+            docker rm -f "$container" &>/dev/null
+            print_success "Removed container: $container"
</code_context>

<issue_to_address>
Subshell in 'while read' may prevent 'REMOVED_SOMETHING' from updating as expected.

Because the loop runs in a subshell, updates to 'REMOVED_SOMETHING' inside it won't persist. Switching to a 'for' loop will ensure variable changes are retained.
</issue_to_address>

### Comment 3
<location> `uninstall.sh:95` </location>
<code_context>
+    fi
+    
+    # Check for images
+    IMAGES=$(docker images --format "{{.ID}} {{.Repository}}" | grep -i claudebox | awk '{print $1}' 2>/dev/null || true)
+    if [ -n "$IMAGES" ]; then
+        print_warning "Found ClaudeBox Docker images. Removing..."
+        echo "$IMAGES" | while read -r image; do
+            docker rmi -f "$image" &>/dev/null
+            print_success "Removed image: $image"
</code_context>

<issue_to_address>
Subshell in 'while read' may prevent 'REMOVED_SOMETHING' from updating as expected.

Consider replacing the pipeline with a 'for' loop to ensure 'REMOVED_SOMETHING' is updated in the parent shell.
</issue_to_address>

### Comment 4
<location> `uninstall.sh:113` </location>
<code_context>
+# 5. Check PATH configuration
+echo ""
+echo "Checking PATH configuration..."
+if echo "$PATH" | grep -q "$HOME/.local/bin"; then
+    print_warning "~/.local/bin is in your PATH"
+    print_info "If you added this only for ClaudeBox, you may want to remove it from:"
</code_context>

<issue_to_address>
PATH check may produce false positives if $HOME/.local/bin is a substring of another path entry.

Consider splitting PATH by ':' and comparing each entry directly to avoid matching substrings.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
echo ""
echo "Checking PATH configuration..."
if echo "$PATH" | grep -q "$HOME/.local/bin"; then
    print_warning "~/.local/bin is in your PATH"
    print_info "If you added this only for ClaudeBox, you may want to remove it from:"
    print_info "  ~/.bashrc, ~/.zshrc, or ~/.bash_profile"
else
    print_info "~/.local/bin is not in your PATH"
fi
=======
echo ""
echo "Checking PATH configuration..."
PATH_HAS_LOCAL_BIN=false
IFS=':' read -ra PATH_ENTRIES <<< "$PATH"
for entry in "${PATH_ENTRIES[@]}"; do
    if [ "$entry" = "$HOME/.local/bin" ]; then
        PATH_HAS_LOCAL_BIN=true
        break
    fi
done
if [ "$PATH_HAS_LOCAL_BIN" = true ]; then
    print_warning "~/.local/bin is in your PATH"
    print_info "If you added this only for ClaudeBox, you may want to remove it from:"
    print_info "  ~/.bashrc, ~/.zshrc, or ~/.bash_profile"
else
    print_info "~/.local/bin is not in your PATH"
fi
>>>>>>> REPLACE

</suggested_fix>

### Comment 5
<location> `uninstall.sh:132` </location>
<code_context>
+echo "========================================="
+
+# Optional: Ask about removing the installer file
+if [ -f "claudebox.run" ]; then
+    echo ""
+    read -p "Remove the claudebox.run installer file? (y/N): " -n 1 -r
</code_context>

<issue_to_address>
Installer file removal prompt assumes script is run from the directory containing 'claudebox.run'.

If users run the script from another directory, 'claudebox.run' may not be detected. Consider clarifying usage instructions or allowing the installer path to be specified.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
# Optional: Ask about removing the installer file
if [ -f "claudebox.run" ]; then
    echo ""
    read -p "Remove the claudebox.run installer file? (y/N): " -n 1 -r
    echo ""
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        rm -f claudebox.run
        print_success "Removed claudebox.run installer"
    fi
fi
=======
# Optional: Ask about removing the installer file
INSTALLER_PATH="${CLAUDEBOX_INSTALLER_PATH:-claudebox.run}"

echo ""
print_info "If you wish to remove the installer file, it will be searched at: $INSTALLER_PATH"
print_info "You can specify a custom path by setting the CLAUDEBOX_INSTALLER_PATH environment variable before running this script."

if [ -f "$INSTALLER_PATH" ]; then
    echo ""
    read -p "Remove the installer file at '$INSTALLER_PATH'? (y/N): " -n 1 -r
    echo ""
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        rm -f "$INSTALLER_PATH"
        print_success "Removed installer file at $INSTALLER_PATH"
    fi
fi
>>>>>>> REPLACE

</suggested_fix>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +64 to +66
PROJECT_DIRS=$(find "$HOME" -maxdepth 1 -type d -name ".claudebox-*" 2>/dev/null || true)
if [ -n "$PROJECT_DIRS" ]; then
echo "$PROJECT_DIRS" | while read -r dir; do
Copy link

Choose a reason for hiding this comment

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

issue (bug_risk): Using a pipeline with 'while read' can cause issues with variable scope in bash.

Because the 'while read' loop runs in a subshell, any changes to variables like 'REMOVED_SOMETHING' inside the loop won't affect the parent shell. Switching to a 'for' loop will ensure variable updates are retained.

Comment on lines +82 to +85
CONTAINERS=$(docker ps -a --format "{{.ID}} {{.Names}}" | grep -i claudebox | awk '{print $1}' 2>/dev/null || true)
if [ -n "$CONTAINERS" ]; then
print_warning "Found ClaudeBox Docker containers. Removing..."
echo "$CONTAINERS" | while read -r container; do
Copy link

Choose a reason for hiding this comment

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

issue (bug_risk): Subshell in 'while read' may prevent 'REMOVED_SOMETHING' from updating as expected.

Because the loop runs in a subshell, updates to 'REMOVED_SOMETHING' inside it won't persist. Switching to a 'for' loop will ensure variable changes are retained.

Comment on lines +95 to +98
IMAGES=$(docker images --format "{{.ID}} {{.Repository}}" | grep -i claudebox | awk '{print $1}' 2>/dev/null || true)
if [ -n "$IMAGES" ]; then
print_warning "Found ClaudeBox Docker images. Removing..."
echo "$IMAGES" | while read -r image; do
Copy link

Choose a reason for hiding this comment

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

issue (bug_risk): Subshell in 'while read' may prevent 'REMOVED_SOMETHING' from updating as expected.

Consider replacing the pipeline with a 'for' loop to ensure 'REMOVED_SOMETHING' is updated in the parent shell.

Comment on lines +111 to +119
echo ""
echo "Checking PATH configuration..."
if echo "$PATH" | grep -q "$HOME/.local/bin"; then
print_warning "~/.local/bin is in your PATH"
print_info "If you added this only for ClaudeBox, you may want to remove it from:"
print_info " ~/.bashrc, ~/.zshrc, or ~/.bash_profile"
else
print_info "~/.local/bin is not in your PATH"
fi
Copy link

Choose a reason for hiding this comment

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

suggestion (bug_risk): PATH check may produce false positives if $HOME/.local/bin is a substring of another path entry.

Consider splitting PATH by ':' and comparing each entry directly to avoid matching substrings.

Suggested change
echo ""
echo "Checking PATH configuration..."
if echo "$PATH" | grep -q "$HOME/.local/bin"; then
print_warning "~/.local/bin is in your PATH"
print_info "If you added this only for ClaudeBox, you may want to remove it from:"
print_info " ~/.bashrc, ~/.zshrc, or ~/.bash_profile"
else
print_info "~/.local/bin is not in your PATH"
fi
echo ""
echo "Checking PATH configuration..."
PATH_HAS_LOCAL_BIN=false
IFS=':' read -ra PATH_ENTRIES <<< "$PATH"
for entry in "${PATH_ENTRIES[@]}"; do
if [ "$entry" = "$HOME/.local/bin" ]; then
PATH_HAS_LOCAL_BIN=true
break
fi
done
if [ "$PATH_HAS_LOCAL_BIN" = true ]; then
print_warning "~/.local/bin is in your PATH"
print_info "If you added this only for ClaudeBox, you may want to remove it from:"
print_info " ~/.bashrc, ~/.zshrc, or ~/.bash_profile"
else
print_info "~/.local/bin is not in your PATH"
fi

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