feat: Add uninstall script for Fabric AI CLI with logging and OS detection

This commit is contained in:
Peter Wood
2025-11-30 19:39:45 -05:00
parent bb945ebd42
commit 6aa087cf0a
3 changed files with 227 additions and 0 deletions

11
.github/prompts/removefabric.prompt.md vendored Normal file
View File

@@ -0,0 +1,11 @@
Create a portable bash shell script to safely uninstall the Fabric AI CLI and related packages on Debian, Ubuntu, and Fedora systems. The script must:
- Detect the operating system and select the appropriate package manager (`apt`, `dnf`, or `yum`).
- Uninstall Fabric packages installed via system package managers and Python package managers (`pip`, `pip3`).
- Check for errors after each removal step; abort the script if a critical error occurs.
- Prompt the user for confirmation before making any changes.
- Advise the user to reboot the system if required after uninstallation.
- Log all actions and errors to a user-specified log file.
- Be fully self-contained and compatible with bash.
Reference the official [Fabric documentation](https://github.com/danielmiessler/Fabric) and your distributions package manager documentation for implementation details.

2
.gitignore vendored
View File

@@ -23,6 +23,7 @@ _book
# Runtime generated files # Runtime generated files
logs/ logs/
uninstall-fabric.log
immich_backups/*.gz immich_backups/*.gz
# Backup files - ignore most backups but keep current state files # Backup files - ignore most backups but keep current state files
crontab/crontab-backups/*/archive/ crontab/crontab-backups/*/archive/
@@ -36,6 +37,7 @@ crontab/crontab-backups/*/archive/
# can be downloaded from <https://github.com/Backblaze/B2_Command_Line_Tool/releases/latest/download/b2-linux> # can be downloaded from <https://github.com/Backblaze/B2_Command_Line_Tool/releases/latest/download/b2-linux>
immich/b2-linux immich/b2-linux
# Generated dotfiles - these are created dynamically by bootstrap process # Generated dotfiles - these are created dynamically by bootstrap process
dotfiles/my-aliases.zsh dotfiles/my-aliases.zsh

214
uninstall-fabric.sh Executable file
View File

@@ -0,0 +1,214 @@
#!/bin/bash
# uninstall-fabric.sh
#
# Description: Safely uninstalls the Fabric AI CLI (Daniel Miessler) and related configuration.
# Avoids removing the 'fabric' Python deployment library.
# Detects OS and uses appropriate package managers if applicable.
# Logs all actions to a file.
#
# Usage: ./uninstall-fabric.sh
#
# Author: GitHub Copilot
set -u
# Configuration
LOG_FILE="uninstall-fabric.log"
CURRENT_DATE=$(date +'%Y-%m-%d %H:%M:%S')
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Initialize log file
echo "Fabric AI CLI Uninstallation Log - Started at $CURRENT_DATE" > "$LOG_FILE"
# Logging functions
log() {
local message="$1"
echo -e "[$(date +'%H:%M:%S')] $message" | tee -a "$LOG_FILE"
}
info() {
local message="$1"
echo -e "${BLUE}[INFO]${NC} $message" | tee -a "$LOG_FILE"
}
success() {
local message="$1"
echo -e "${GREEN}[SUCCESS]${NC} $message" | tee -a "$LOG_FILE"
}
warning() {
local message="$1"
echo -e "${YELLOW}[WARNING]${NC} $message" | tee -a "$LOG_FILE"
}
error() {
local message="$1"
echo -e "${RED}[ERROR]${NC} $message" | tee -a "$LOG_FILE"
exit 1
}
# Function to detect Operating System
detect_os() {
if [[ -f /etc/os-release ]]; then
# shellcheck source=/dev/null
. /etc/os-release
OS_NAME=$ID
VERSION_ID=$VERSION_ID
info "Detected OS: $NAME ($ID) $VERSION_ID"
else
error "Could not detect operating system. /etc/os-release file not found."
fi
}
# Function to check for root privileges
check_privileges() {
if [[ $EUID -ne 0 ]]; then
warning "This script is not running as root."
warning "System package removal might fail or require sudo password."
else
info "Running with root privileges."
fi
}
# Function to confirm action
confirm_execution() {
echo -e "\n${YELLOW}WARNING: This script will attempt to uninstall the Fabric AI CLI (Daniel Miessler).${NC}"
echo -e "It will NOT remove the 'fabric' Python deployment library."
echo -e "It will remove the 'fabric' binary if identified as the AI tool, and configuration files."
echo -e "Please ensure you have backups if necessary.\n"
read -p "Do you want to proceed? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
info "Operation cancelled by user."
exit 0
fi
}
# Function to check if a binary is the Fabric AI tool
is_fabric_ai_tool() {
local bin_path="$1"
# Check help output for keywords
# The AI tool usually mentions 'patterns', 'context', 'session', 'model'
if "$bin_path" --help 2>&1 | grep -qE "Daniel Miessler|patterns|context|session|model"; then
return 0
fi
return 1
}
# Function to uninstall binary
uninstall_binary() {
local bin_path
bin_path=$(command -v fabric)
if [[ -n "$bin_path" ]]; then
info "Found 'fabric' binary at: $bin_path"
if is_fabric_ai_tool "$bin_path"; then
info "Identified as Fabric AI CLI."
# Check if owned by system package
local pkg_owner=""
if [[ "$OS_NAME" =~ (debian|ubuntu|linuxmint|pop|kali) ]]; then
if dpkg -S "$bin_path" &> /dev/null; then
pkg_owner=$(dpkg -S "$bin_path" | cut -d: -f1)
fi
elif [[ "$OS_NAME" =~ (fedora|centos|rhel|almalinux|rocky) ]]; then
if rpm -qf "$bin_path" &> /dev/null; then
pkg_owner=$(rpm -qf "$bin_path")
fi
fi
if [[ -n "$pkg_owner" ]]; then
info "Binary is owned by system package: $pkg_owner"
info "Removing package $pkg_owner..."
local sudo_prefix=""
[[ $EUID -ne 0 ]] && sudo_prefix="sudo"
if [[ "$OS_NAME" =~ (debian|ubuntu|linuxmint|pop|kali) ]]; then
$sudo_prefix apt-get remove -y "$pkg_owner" >> "$LOG_FILE" 2>&1 || error "Failed to remove package $pkg_owner"
else
$sudo_prefix dnf remove -y "$pkg_owner" >> "$LOG_FILE" 2>&1 || error "Failed to remove package $pkg_owner"
fi
success "Removed system package $pkg_owner."
else
info "Binary is not owned by a system package. Removing manually..."
rm -f "$bin_path" || error "Failed to remove $bin_path"
success "Removed binary $bin_path."
fi
else
warning "The binary at $bin_path does not appear to be the Fabric AI CLI. Skipping removal to be safe."
warning "Run '$bin_path --help' to verify what it is."
fi
else
info "'fabric' binary not found in PATH."
fi
}
# Function to uninstall from pipx
uninstall_pipx() {
if command -v pipx &> /dev/null; then
info "Checking pipx for 'fabric'..."
if pipx list | grep -q "package fabric"; then
info "Found 'fabric' installed via pipx. Uninstalling..."
pipx uninstall fabric >> "$LOG_FILE" 2>&1 || error "Failed to uninstall fabric via pipx"
success "Uninstalled fabric via pipx."
else
info "'fabric' not found in pipx."
fi
fi
}
# Function to remove configuration files
remove_config() {
local config_dirs=(
"$HOME/.config/fabric"
"$HOME/.fabric"
"$HOME/.local/share/fabric"
)
for dir in "${config_dirs[@]}"; do
if [[ -d "$dir" ]]; then
info "Found configuration directory: $dir"
rm -rf "$dir" || error "Failed to remove $dir"
success "Removed $dir."
fi
done
}
# Main execution flow
main() {
detect_os
check_privileges
confirm_execution
info "Starting uninstallation process..."
# Check pipx first as it manages its own binaries
uninstall_pipx
# Check binary
uninstall_binary
# Remove config
remove_config
echo -e "\n----------------------------------------------------------------"
success "Uninstallation steps completed."
info "A log of this operation has been saved to: $LOG_FILE"
echo -e "${YELLOW}Note: If you removed system-level components, a reboot might be recommended.${NC}"
echo -e "----------------------------------------------------------------"
}
# Trap interrupts
trap 'echo -e "\n${RED}Script interrupted by user.${NC}"; exit 1' INT TERM
# Run main
main