Created
January 30, 2026 16:45
-
-
Save rcalsaverini/9352416abcfd5519a1f9d86d711c60f3 to your computer and use it in GitHub Desktop.
Uninstall clawdbot / moltbot / openclaw
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| set -euo pipefail | |
| # OpenClaw/Clawdbot/Moltbot/Moldbot Uninstaller for macOS and Linux | |
| # Reverses everything done by the installer (handles all name variants) | |
| BOLD='\033[1m' | |
| ACCENT='\033[38;2;255;90;45m' | |
| SUCCESS='\033[38;2;47;191;113m' | |
| WARN='\033[38;2;255;176;32m' | |
| ERROR='\033[38;2;226;61;45m' | |
| INFO='\033[38;2;255;138;91m' | |
| MUTED='\033[38;2;139;127;119m' | |
| NC='\033[0m' | |
| DRY_RUN=0 | |
| KEEP_CONFIG=0 | |
| REMOVE_NODE=0 | |
| SCAN_ONLY=0 | |
| HELP=0 | |
| # All known package/binary names | |
| PACKAGE_NAMES=("openclaw" "clawdbot" "moltbot" "moldbot") | |
| # All known config directory names | |
| CONFIG_DIRS=(".openclaw" ".clawdbot" ".moltbot" ".moldbot") | |
| # All known git checkout locations | |
| GIT_DIRS=("openclaw" "clawdbot" "moltbot" "moldbot") | |
| # Store our own PID to avoid killing ourselves | |
| SELF_PID=$$ | |
| print_usage() { | |
| cat <<EOF | |
| OpenClaw/Clawdbot/Moltbot Uninstaller (macOS + Linux) | |
| Handles all name variants: openclaw, clawdbot, moltbot, moldbot | |
| Usage: | |
| ./uninstall-openclaw.sh [options] | |
| Options: | |
| --scan Scan and show what's installed without removing anything | |
| --dry-run Show what would be removed without making changes | |
| --keep-config Keep configuration files (~/.openclaw, ~/.clawdbot, etc.) | |
| --remove-node Also remove Node.js (if installed by the installer) | |
| --help, -h Show this help | |
| Examples: | |
| ./uninstall-openclaw.sh --scan | |
| ./uninstall-openclaw.sh --dry-run | |
| ./uninstall-openclaw.sh | |
| ./uninstall-openclaw.sh --keep-config | |
| EOF | |
| } | |
| parse_args() { | |
| while [[ $# -gt 0 ]]; do | |
| case "$1" in | |
| --scan) | |
| SCAN_ONLY=1 | |
| shift | |
| ;; | |
| --dry-run) | |
| DRY_RUN=1 | |
| shift | |
| ;; | |
| --keep-config) | |
| KEEP_CONFIG=1 | |
| shift | |
| ;; | |
| --remove-node) | |
| REMOVE_NODE=1 | |
| shift | |
| ;; | |
| --help|-h) | |
| HELP=1 | |
| shift | |
| ;; | |
| *) | |
| shift | |
| ;; | |
| esac | |
| done | |
| } | |
| log_action() { | |
| if [[ "$DRY_RUN" == "1" ]]; then | |
| echo -e "${MUTED}[DRY-RUN]${NC} $1" | |
| else | |
| echo -e "${WARN}→${NC} $1" | |
| fi | |
| } | |
| log_success() { | |
| echo -e "${SUCCESS}✓${NC} $1" | |
| } | |
| log_skip() { | |
| echo -e "${MUTED}○${NC} $1" | |
| } | |
| log_found() { | |
| echo -e "${INFO}●${NC} $1" | |
| } | |
| log_not_found() { | |
| echo -e "${MUTED}○${NC} $1" | |
| } | |
| is_root() { | |
| [[ "$(id -u)" -eq 0 ]] | |
| } | |
| maybe_sudo() { | |
| if is_root; then | |
| if [[ "${1:-}" == "-E" ]]; then | |
| shift | |
| fi | |
| "$@" | |
| else | |
| sudo "$@" | |
| fi | |
| } | |
| remove_file() { | |
| local path="$1" | |
| if [[ -e "$path" || -L "$path" ]]; then | |
| log_action "Removing: ${INFO}${path}${NC}" | |
| if [[ "$DRY_RUN" != "1" ]]; then | |
| rm -f "$path" | |
| fi | |
| return 0 | |
| fi | |
| return 1 | |
| } | |
| remove_dir() { | |
| local path="$1" | |
| if [[ -d "$path" ]]; then | |
| log_action "Removing directory: ${INFO}${path}${NC}" | |
| if [[ "$DRY_RUN" != "1" ]]; then | |
| rm -rf "$path" | |
| fi | |
| return 0 | |
| fi | |
| return 1 | |
| } | |
| remove_line_from_file() { | |
| local file="$1" | |
| local pattern="$2" | |
| local description="$3" | |
| if [[ -f "$file" ]] && grep -q "$pattern" "$file" 2>/dev/null; then | |
| log_action "Removing ${description} from ${INFO}${file}${NC}" | |
| if [[ "$DRY_RUN" != "1" ]]; then | |
| # Create backup | |
| cp "$file" "${file}.bak-uninstall" | |
| grep -v "$pattern" "$file" > "${file}.tmp" || true | |
| mv "${file}.tmp" "$file" | |
| fi | |
| return 0 | |
| fi | |
| return 1 | |
| } | |
| # ============================================================================ | |
| # SCAN FUNCTIONS - Show what's installed | |
| # ============================================================================ | |
| scan_installation() { | |
| echo -e "${ACCENT}${BOLD}" | |
| echo " 🔍 Scanning for OpenClaw/Clawdbot/Moltbot installation..." | |
| echo -e "${NC}" | |
| echo -e "${MUTED}Looking for: ${PACKAGE_NAMES[*]}${NC}" | |
| echo "" | |
| local found_anything=0 | |
| # --- npm packages --- | |
| echo -e "${BOLD}npm global packages:${NC}" | |
| for name in "${PACKAGE_NAMES[@]}"; do | |
| local version="" | |
| version=$(npm list -g "$name" 2>/dev/null | grep "$name@" | head -1 || true) | |
| if [[ -n "$version" ]]; then | |
| log_found "$version" | |
| found_anything=1 | |
| fi | |
| done | |
| if [[ "$found_anything" == "0" ]]; then | |
| log_not_found "No npm packages found" | |
| fi | |
| echo "" | |
| # --- npm global location --- | |
| echo -e "${BOLD}npm global install location:${NC}" | |
| local npm_root="" | |
| npm_root="$(npm root -g 2>/dev/null || true)" | |
| if [[ -n "$npm_root" ]]; then | |
| for name in "${PACKAGE_NAMES[@]}"; do | |
| if [[ -d "$npm_root/$name" ]]; then | |
| log_found "$npm_root/$name" | |
| fi | |
| done | |
| fi | |
| local npm_bin="" | |
| npm_bin="$(npm bin -g 2>/dev/null || true)" | |
| if [[ -n "$npm_bin" ]]; then | |
| for name in "${PACKAGE_NAMES[@]}"; do | |
| if [[ -e "$npm_bin/$name" ]]; then | |
| log_found "$npm_bin/$name" | |
| fi | |
| done | |
| fi | |
| echo "" | |
| # --- Config directories --- | |
| echo -e "${BOLD}Configuration directories:${NC}" | |
| local found_config=0 | |
| for dir in "${CONFIG_DIRS[@]}"; do | |
| if [[ -d "$HOME/$dir" ]]; then | |
| log_found "$HOME/$dir" | |
| ls -la "$HOME/$dir" 2>/dev/null | head -10 | while read -r line; do | |
| echo -e " ${MUTED}$line${NC}" | |
| done | |
| found_config=1 | |
| fi | |
| done | |
| if [[ "$found_config" == "0" ]]; then | |
| log_not_found "No config directories found" | |
| fi | |
| echo "" | |
| # --- Git checkouts --- | |
| echo -e "${BOLD}Git checkouts:${NC}" | |
| local found_git=0 | |
| for name in "${GIT_DIRS[@]}"; do | |
| if [[ -d "$HOME/$name" && -f "$HOME/$name/package.json" ]]; then | |
| if grep -q '"name".*"openclaw\|clawdbot\|moltbot\|moldbot"' "$HOME/$name/package.json" 2>/dev/null; then | |
| log_found "$HOME/$name" | |
| found_git=1 | |
| fi | |
| fi | |
| done | |
| if [[ "$found_git" == "0" ]]; then | |
| log_not_found "No git checkouts found" | |
| fi | |
| echo "" | |
| # --- Wrapper scripts --- | |
| echo -e "${BOLD}Wrapper scripts in ~/.local/bin:${NC}" | |
| local found_wrapper=0 | |
| for name in "${PACKAGE_NAMES[@]}"; do | |
| if [[ -e "$HOME/.local/bin/$name" ]]; then | |
| log_found "$HOME/.local/bin/$name" | |
| found_wrapper=1 | |
| fi | |
| done | |
| if [[ "$found_wrapper" == "0" ]]; then | |
| log_not_found "No wrapper scripts found" | |
| fi | |
| echo "" | |
| # --- systemd services --- | |
| echo -e "${BOLD}systemd user services:${NC}" | |
| local systemd_dir="$HOME/.config/systemd/user" | |
| local found_systemd=0 | |
| if [[ -d "$systemd_dir" ]]; then | |
| for name in "${PACKAGE_NAMES[@]}"; do | |
| for service in "$systemd_dir/${name}"*.service "$systemd_dir/${name}"*.timer; do | |
| if [[ -f "$service" ]]; then | |
| local status="" | |
| status=$(systemctl --user is-active "$(basename "$service")" 2>/dev/null || echo "inactive") | |
| log_found "$service (${status})" | |
| found_systemd=1 | |
| fi | |
| done | |
| done | |
| fi | |
| if [[ "$found_systemd" == "0" ]]; then | |
| log_not_found "No systemd services found" | |
| fi | |
| echo "" | |
| # --- Running processes --- | |
| echo -e "${BOLD}Running processes:${NC}" | |
| local found_proc=0 | |
| for name in "${PACKAGE_NAMES[@]}"; do | |
| local procs="" | |
| # Exclude uninstall script from matches | |
| procs=$(pgrep -fa "$name" 2>/dev/null | grep -v "uninstall" | grep -v "grep" || true) | |
| if [[ -n "$procs" ]]; then | |
| echo "$procs" | while read -r line; do | |
| log_found "$line" | |
| done | |
| found_proc=1 | |
| fi | |
| done | |
| if [[ "$found_proc" == "0" ]]; then | |
| log_not_found "No running processes found" | |
| fi | |
| echo "" | |
| # --- Shell RC files --- | |
| echo -e "${BOLD}Shell RC files with PATH modifications:${NC}" | |
| local found_rc=0 | |
| for rc in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.profile"; do | |
| if [[ -f "$rc" ]] && grep -q "openclaw\|clawdbot\|moltbot\|moldbot\|npm-global" "$rc" 2>/dev/null; then | |
| log_found "$rc" | |
| grep "openclaw\|clawdbot\|moltbot\|moldbot\|npm-global" "$rc" 2>/dev/null | while read -r line; do | |
| echo -e " ${MUTED}$line${NC}" | |
| done | |
| found_rc=1 | |
| fi | |
| done | |
| if [[ "$found_rc" == "0" ]]; then | |
| log_not_found "No PATH modifications found" | |
| fi | |
| echo "" | |
| # --- Symlinks in bin directories --- | |
| echo -e "${BOLD}Symlinks in system bin directories:${NC}" | |
| local found_symlink=0 | |
| for bin_dir in "/usr/local/bin" "/opt/homebrew/bin"; do | |
| for name in "${PACKAGE_NAMES[@]}"; do | |
| if [[ -e "$bin_dir/$name" ]]; then | |
| local target="" | |
| target=$(readlink "$bin_dir/$name" 2>/dev/null || echo "(not a symlink)") | |
| log_found "$bin_dir/$name -> $target" | |
| found_symlink=1 | |
| fi | |
| done | |
| done | |
| if [[ "$found_symlink" == "0" ]]; then | |
| log_not_found "No symlinks found" | |
| fi | |
| echo "" | |
| # --- Deep find --- | |
| echo -e "${BOLD}All related files (find):${NC}" | |
| find "$HOME" -maxdepth 4 \( -name "*openclaw*" -o -name "*clawdbot*" -o -name "*moltbot*" -o -name "*moldbot*" \) 2>/dev/null | grep -v "uninstall" | head -30 | while read -r f; do | |
| log_found "$f" | |
| done | |
| echo "" | |
| echo -e "${SUCCESS}${BOLD}Scan complete${NC}" | |
| echo -e "${MUTED}Run with --dry-run to see what would be removed, or without flags to uninstall.${NC}" | |
| } | |
| # ============================================================================ | |
| # UNINSTALL FUNCTIONS | |
| # ============================================================================ | |
| # Stop daemon if running (using systemctl and pkill directly, not clawdbot command) | |
| stop_daemon() { | |
| local found=0 | |
| local systemd_user_dir="$HOME/.config/systemd/user" | |
| # First, stop and disable any systemd services | |
| if [[ -d "$systemd_user_dir" ]]; then | |
| for name in "${PACKAGE_NAMES[@]}"; do | |
| for service in "$systemd_user_dir/${name}"*.service; do | |
| if [[ -f "$service" ]]; then | |
| local service_name | |
| service_name="$(basename "$service")" | |
| log_action "Stopping and disabling systemd service: ${INFO}${service_name}${NC}" | |
| if [[ "$DRY_RUN" != "1" ]]; then | |
| # Use timeout to prevent hanging | |
| timeout 5 systemctl --user disable --now "$service_name" 2>/dev/null || true | |
| fi | |
| found=1 | |
| fi | |
| done | |
| done | |
| fi | |
| # Kill any remaining processes by name (EXCLUDING this script!) | |
| for name in "${PACKAGE_NAMES[@]}"; do | |
| # Get PIDs matching the name, but exclude our own script | |
| local pids="" | |
| pids=$(pgrep -f "$name" 2>/dev/null | grep -v "^${SELF_PID}$" || true) | |
| # Also filter out any process that contains "uninstall" in its command line | |
| if [[ -n "$pids" ]]; then | |
| for pid in $pids; do | |
| local cmdline="" | |
| cmdline=$(ps -p "$pid" -o args= 2>/dev/null || true) | |
| if [[ -n "$cmdline" && ! "$cmdline" =~ uninstall ]]; then | |
| log_action "Killing process $pid: ${INFO}${cmdline}${NC}" | |
| if [[ "$DRY_RUN" != "1" ]]; then | |
| kill "$pid" 2>/dev/null || true | |
| fi | |
| found=1 | |
| fi | |
| done | |
| # Wait and force kill if needed | |
| if [[ "$DRY_RUN" != "1" ]]; then | |
| sleep 1 | |
| for pid in $pids; do | |
| local cmdline="" | |
| cmdline=$(ps -p "$pid" -o args= 2>/dev/null || true) | |
| if [[ -n "$cmdline" && ! "$cmdline" =~ uninstall ]]; then | |
| kill -9 "$pid" 2>/dev/null || true | |
| fi | |
| done | |
| fi | |
| fi | |
| done | |
| if [[ "$found" == "1" ]]; then | |
| log_success "Daemon stopped" | |
| else | |
| log_skip "No running daemon found" | |
| fi | |
| } | |
| # Remove systemd user service files (already stopped/disabled by stop_daemon) | |
| remove_systemd_services() { | |
| local systemd_user_dir="$HOME/.config/systemd/user" | |
| local found=0 | |
| if [[ -d "$systemd_user_dir" ]]; then | |
| for name in "${PACKAGE_NAMES[@]}"; do | |
| for service in "$systemd_user_dir/${name}"*.service "$systemd_user_dir/${name}"*.timer; do | |
| if [[ -f "$service" ]]; then | |
| if remove_file "$service"; then | |
| found=1 | |
| fi | |
| fi | |
| done | |
| done | |
| # Reload systemd after removing services | |
| if [[ "$found" == "1" && "$DRY_RUN" != "1" ]]; then | |
| systemctl --user daemon-reload 2>/dev/null || true | |
| fi | |
| fi | |
| if [[ "$found" == "1" ]]; then | |
| log_success "systemd service files removed" | |
| else | |
| log_skip "No systemd user services found" | |
| fi | |
| } | |
| # Remove npm global packages (all variants) | |
| remove_npm_packages() { | |
| local found=0 | |
| for name in "${PACKAGE_NAMES[@]}"; do | |
| if npm list -g "$name" &>/dev/null 2>&1; then | |
| log_action "Uninstalling npm global package: ${INFO}${name}${NC}" | |
| if [[ "$DRY_RUN" != "1" ]]; then | |
| npm uninstall -g "$name" 2>/dev/null || true | |
| fi | |
| found=1 | |
| fi | |
| done | |
| if [[ "$found" == "1" ]]; then | |
| log_success "npm package(s) removed" | |
| else | |
| log_skip "No npm packages installed (checked: ${PACKAGE_NAMES[*]})" | |
| fi | |
| # Clean up any leftover npm paths | |
| local npm_root="" | |
| npm_root="$(npm root -g 2>/dev/null || true)" | |
| if [[ -n "$npm_root" && -d "$npm_root" ]]; then | |
| for name in "${PACKAGE_NAMES[@]}"; do | |
| for leftover in "$npm_root"/."${name}"-* "$npm_root"/"$name"; do | |
| if [[ -e "$leftover" ]]; then | |
| remove_dir "$leftover" | |
| fi | |
| done | |
| done | |
| fi | |
| } | |
| # Remove git checkout wrapper and source (all variants) | |
| remove_git_install() { | |
| local found_wrapper=0 | |
| local found_checkout=0 | |
| # Remove wrapper scripts from ~/.local/bin | |
| for name in "${PACKAGE_NAMES[@]}"; do | |
| if remove_file "$HOME/.local/bin/$name"; then | |
| found_wrapper=1 | |
| fi | |
| done | |
| if [[ "$found_wrapper" == "1" ]]; then | |
| log_success "Git wrapper(s) removed" | |
| fi | |
| # Remove git checkouts from home directory | |
| for name in "${GIT_DIRS[@]}"; do | |
| local checkout_dir="$HOME/$name" | |
| if [[ -d "$checkout_dir" ]]; then | |
| # Verify it's actually the bot checkout | |
| if [[ -f "$checkout_dir/package.json" ]]; then | |
| local is_match=0 | |
| for pkg_name in "${PACKAGE_NAMES[@]}"; do | |
| if grep -q "\"name\".*\"$pkg_name\"" "$checkout_dir/package.json" 2>/dev/null; then | |
| is_match=1 | |
| break | |
| fi | |
| done | |
| if [[ "$is_match" == "1" ]]; then | |
| log_action "Removing git checkout: ${INFO}${checkout_dir}${NC}" | |
| if [[ "$DRY_RUN" != "1" ]]; then | |
| rm -rf "$checkout_dir" | |
| fi | |
| found_checkout=1 | |
| fi | |
| fi | |
| fi | |
| done | |
| if [[ "$found_checkout" == "1" ]]; then | |
| log_success "Git checkout(s) removed" | |
| else | |
| log_skip "No git checkouts found" | |
| fi | |
| } | |
| # Remove configuration directories (all variants) | |
| remove_config() { | |
| if [[ "$KEEP_CONFIG" == "1" ]]; then | |
| log_skip "Keeping configuration files (--keep-config specified)" | |
| return | |
| fi | |
| local found=0 | |
| for dir_name in "${CONFIG_DIRS[@]}"; do | |
| local full_path="$HOME/$dir_name" | |
| if remove_dir "$full_path"; then | |
| found=1 | |
| fi | |
| done | |
| if [[ "$found" == "1" ]]; then | |
| log_success "Configuration directories removed" | |
| else | |
| log_skip "No configuration directories found" | |
| fi | |
| } | |
| # Remove PATH modifications from shell rc files | |
| clean_shell_rc() { | |
| local modified=0 | |
| for rc in "$HOME/.bashrc" "$HOME/.zshrc"; do | |
| if [[ -f "$rc" ]]; then | |
| # Remove .npm-global/bin PATH addition | |
| if remove_line_from_file "$rc" '.npm-global' "npm-global PATH"; then | |
| modified=1 | |
| fi | |
| # Remove .local/bin PATH additions with any of the bot names | |
| for name in "${PACKAGE_NAMES[@]}"; do | |
| if grep -q ".local/bin.*# ${name}\|# Added by ${name}" "$rc" 2>/dev/null; then | |
| remove_line_from_file "$rc" "# ${name}\|# Added by ${name}" "${name} PATH entries" | |
| modified=1 | |
| fi | |
| done | |
| fi | |
| done | |
| if [[ "$modified" == "1" ]]; then | |
| log_success "Shell rc files cleaned" | |
| echo -e "${INFO}i${NC} Backups created with .bak-uninstall suffix" | |
| else | |
| log_skip "No PATH modifications found in shell rc files" | |
| fi | |
| } | |
| # Remove npm prefix configuration if set to ~/.npm-global | |
| clean_npm_config() { | |
| local npm_prefix="" | |
| npm_prefix="$(npm config get prefix 2>/dev/null || true)" | |
| if [[ "$npm_prefix" == "$HOME/.npm-global" ]]; then | |
| log_action "Resetting npm prefix configuration" | |
| if [[ "$DRY_RUN" != "1" ]]; then | |
| npm config delete prefix 2>/dev/null || true | |
| fi | |
| log_success "npm prefix reset" | |
| # Optionally remove the .npm-global directory if empty | |
| if [[ -d "$HOME/.npm-global" ]]; then | |
| if [[ -z "$(ls -A "$HOME/.npm-global" 2>/dev/null)" ]]; then | |
| remove_dir "$HOME/.npm-global" | |
| else | |
| log_skip "~/.npm-global not empty, keeping it" | |
| fi | |
| fi | |
| else | |
| log_skip "npm prefix not set to ~/.npm-global" | |
| fi | |
| } | |
| # Remove pnpm if it was installed | |
| remove_pnpm() { | |
| if command -v pnpm &> /dev/null; then | |
| log_action "Removing pnpm..." | |
| if [[ "$DRY_RUN" != "1" ]]; then | |
| npm uninstall -g pnpm 2>/dev/null || true | |
| # Also try corepack | |
| if command -v corepack &> /dev/null; then | |
| corepack disable pnpm 2>/dev/null || true | |
| fi | |
| fi | |
| log_success "pnpm removed" | |
| else | |
| log_skip "pnpm not installed" | |
| fi | |
| } | |
| # Remove stale symlinks from common bin directories | |
| clean_stale_symlinks() { | |
| local bin_dirs=( | |
| "/usr/local/bin" | |
| "/opt/homebrew/bin" | |
| "$HOME/.local/bin" | |
| ) | |
| local found=0 | |
| for bin_dir in "${bin_dirs[@]}"; do | |
| if [[ -d "$bin_dir" ]]; then | |
| for name in "${PACKAGE_NAMES[@]}"; do | |
| local symlink="$bin_dir/$name" | |
| if [[ -L "$symlink" ]]; then | |
| local target="" | |
| target="$(readlink "$symlink" 2>/dev/null || true)" | |
| # Check if it points to node_modules for any of our packages | |
| for pkg in "${PACKAGE_NAMES[@]}"; do | |
| if [[ "$target" == *"/node_modules/${pkg}/"* ]]; then | |
| log_action "Removing stale symlink: ${INFO}${symlink}${NC}" | |
| if [[ "$DRY_RUN" != "1" ]]; then | |
| rm -f "$symlink" 2>/dev/null || maybe_sudo rm -f "$symlink" 2>/dev/null || true | |
| fi | |
| found=1 | |
| break | |
| fi | |
| done | |
| fi | |
| done | |
| fi | |
| done | |
| if [[ "$found" == "1" ]]; then | |
| log_success "Stale symlinks removed" | |
| fi | |
| } | |
| # Optionally remove Node.js | |
| remove_node() { | |
| if [[ "$REMOVE_NODE" != "1" ]]; then | |
| return | |
| fi | |
| echo "" | |
| echo -e "${WARN}WARNING: Removing Node.js${NC}" | |
| echo "This will remove Node.js system-wide. Other applications may depend on it." | |
| echo "" | |
| local os="unknown" | |
| if [[ "$OSTYPE" == "darwin"* ]]; then | |
| os="macos" | |
| elif [[ "$OSTYPE" == "linux-gnu"* ]]; then | |
| os="linux" | |
| fi | |
| if [[ "$os" == "macos" ]]; then | |
| if command -v brew &> /dev/null; then | |
| log_action "Removing Node.js via Homebrew..." | |
| if [[ "$DRY_RUN" != "1" ]]; then | |
| brew uninstall node@22 2>/dev/null || brew uninstall node 2>/dev/null || true | |
| fi | |
| log_success "Node.js removed" | |
| fi | |
| elif [[ "$os" == "linux" ]]; then | |
| log_action "Removing Node.js..." | |
| if [[ "$DRY_RUN" != "1" ]]; then | |
| if command -v apt-get &> /dev/null; then | |
| maybe_sudo apt-get remove -y nodejs 2>/dev/null || true | |
| elif command -v dnf &> /dev/null; then | |
| maybe_sudo dnf remove -y nodejs 2>/dev/null || true | |
| elif command -v yum &> /dev/null; then | |
| maybe_sudo yum remove -y nodejs 2>/dev/null || true | |
| fi | |
| fi | |
| log_success "Node.js removed" | |
| fi | |
| } | |
| main() { | |
| echo -e "${ACCENT}${BOLD}" | |
| echo " 🦞 OpenClaw/Clawdbot/Moltbot Uninstaller" | |
| echo -e "${NC}${MUTED} Goodbye, and thanks for all the fish.${NC}" | |
| echo "" | |
| echo -e "${MUTED} Checking for: ${PACKAGE_NAMES[*]}${NC}" | |
| echo "" | |
| if [[ "$DRY_RUN" == "1" ]]; then | |
| echo -e "${WARN}Running in dry-run mode - no changes will be made${NC}" | |
| echo "" | |
| fi | |
| # Stop daemon first | |
| stop_daemon | |
| # Remove systemd services | |
| remove_systemd_services | |
| # Remove npm packages | |
| remove_npm_packages | |
| # Remove git installations | |
| remove_git_install | |
| # Clean stale symlinks | |
| clean_stale_symlinks | |
| # Remove pnpm | |
| remove_pnpm | |
| # Clean npm config | |
| clean_npm_config | |
| # Clean shell rc files | |
| clean_shell_rc | |
| # Remove config directories | |
| remove_config | |
| # Optionally remove Node.js | |
| remove_node | |
| echo "" | |
| if [[ "$DRY_RUN" == "1" ]]; then | |
| echo -e "${SUCCESS}${BOLD}Dry run complete${NC}" | |
| echo -e "${MUTED}Run without --dry-run to apply changes${NC}" | |
| else | |
| echo -e "${SUCCESS}${BOLD}🦞 Uninstall complete${NC}" | |
| echo "" | |
| echo -e "${MUTED}You may need to restart your terminal or run:${NC}" | |
| echo -e " ${INFO}source ~/.bashrc${NC} ${MUTED}or${NC} ${INFO}source ~/.zshrc${NC}" | |
| if [[ "$KEEP_CONFIG" == "1" ]]; then | |
| echo "" | |
| echo -e "${MUTED}Configuration files were kept. Remove manually if desired:${NC}" | |
| echo -e " ${INFO}rm -rf ~/.openclaw ~/.clawdbot ~/.moltbot ~/.moldbot${NC}" | |
| fi | |
| fi | |
| } | |
| parse_args "$@" | |
| if [[ "$HELP" == "1" ]]; then | |
| print_usage | |
| exit 0 | |
| fi | |
| if [[ "$SCAN_ONLY" == "1" ]]; then | |
| scan_installation | |
| exit 0 | |
| fi | |
| main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment