Files
claude/claude-code-installer.sh
2026-01-10 07:11:28 +00:00

830 lines
33 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
#===============================================================================
#
# Claude Code Installer for Linux
# A colorized, interactive installer with full system detection
#
# Features:
# - Detects Linux distribution and version
# - Checks/removes existing Node.js and npm installations
# - Installs Node.js 20 LTS
# - Installs Claude Code
# - Configures permissions interactively
#
#===============================================================================
# Exit on error
set -e
#-------------------------------------------------------------------------------
# Color Definitions
#-------------------------------------------------------------------------------
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
WHITE='\033[1;37m'
BOLD='\033[1m'
DIM='\033[2m'
RESET='\033[0m'
# Status icons
CHECK="✓"
CROSS="✗"
ARROW="➜"
GEAR="⚙"
PACKAGE="📦"
ROCKET="🚀"
SHIELD="🛡"
WARNING="⚠"
INFO=""
#-------------------------------------------------------------------------------
# Helper Functions
#-------------------------------------------------------------------------------
print_banner() {
clear
echo -e "${CYAN}"
echo "╔═══════════════════════════════════════════════════════════════════════════╗"
echo "║ ║"
echo "║ ██████╗██╗ █████╗ ██╗ ██╗██████╗ ███████╗ ║"
echo "║ ██╔════╝██║ ██╔══██╗██║ ██║██╔══██╗██╔════╝ ║"
echo "║ ██║ ██║ ███████║██║ ██║██║ ██║█████╗ ║"
echo "║ ██║ ██║ ██╔══██║██║ ██║██║ ██║██╔══╝ ║"
echo "║ ╚██████╗███████╗██║ ██║╚██████╔╝██████╔╝███████╗ ║"
echo "║ ╚═════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝ ║"
echo "║ ║"
echo "${WHITE}C O D E I N S T A L L E R${CYAN}"
echo "║ ║"
echo "╚═══════════════════════════════════════════════════════════════════════════╝"
echo -e "${RESET}"
echo ""
}
print_section() {
echo ""
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
echo -e "${BOLD}${WHITE} $1${RESET}"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
echo ""
}
print_step() {
echo -e "${CYAN}${ARROW}${RESET} ${WHITE}$1${RESET}"
}
print_success() {
echo -e "${GREEN}${CHECK}${RESET} ${GREEN}$1${RESET}"
}
print_error() {
echo -e "${RED}${CROSS}${RESET} ${RED}$1${RESET}"
}
print_warning() {
echo -e "${YELLOW}${WARNING}${RESET} ${YELLOW}$1${RESET}"
}
print_info() {
echo -e "${BLUE}${INFO}${RESET} ${DIM}$1${RESET}"
}
print_package() {
echo -e "${MAGENTA}${PACKAGE}${RESET} $1"
}
spinner() {
local pid=$1
local delay=0.1
local spinstr='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
while [ "$(ps a | awk '{print $1}' | grep $pid)" ]; do
local temp=${spinstr#?}
printf " ${CYAN}[%c]${RESET} " "$spinstr"
local spinstr=$temp${spinstr%"$temp"}
sleep $delay
printf "\b\b\b\b\b\b"
done
printf " \b\b\b\b"
}
confirm() {
local prompt="$1"
local default="${2:-y}"
if [[ "$default" == "y" ]]; then
prompt_text="${prompt} [${GREEN}Y${RESET}/${RED}n${RESET}]"
else
prompt_text="${prompt} [${GREEN}y${RESET}/${RED}N${RESET}]"
fi
echo -ne "${YELLOW}?${RESET} ${prompt_text}: "
read -r response
if [[ -z "$response" ]]; then
response="$default"
fi
[[ "$response" =~ ^[Yy]$ ]]
}
wait_for_key() {
echo ""
echo -ne "${DIM}Press any key to continue...${RESET}"
read -n 1 -s
echo ""
}
#-------------------------------------------------------------------------------
# System Detection Functions
#-------------------------------------------------------------------------------
detect_distro() {
print_section "${GEAR} System Detection"
print_step "Identifying your Linux distribution..."
sleep 0.5
# Initialize variables
DISTRO="Unknown"
DISTRO_VERSION="Unknown"
DISTRO_CODENAME="Unknown"
DISTRO_FAMILY="Unknown"
PACKAGE_MANAGER="Unknown"
# Try to detect from /etc/os-release (most modern distros)
if [[ -f /etc/os-release ]]; then
source /etc/os-release
DISTRO="${NAME:-Unknown}"
DISTRO_VERSION="${VERSION_ID:-Unknown}"
DISTRO_CODENAME="${VERSION_CODENAME:-Unknown}"
# Determine distro family and package manager
case "${ID:-}" in
ubuntu|debian|linuxmint|pop|elementary|zorin|kali)
DISTRO_FAMILY="Debian"
PACKAGE_MANAGER="apt"
;;
fedora|rhel|centos|rocky|almalinux|oracle)
DISTRO_FAMILY="RedHat"
if command -v dnf &> /dev/null; then
PACKAGE_MANAGER="dnf"
else
PACKAGE_MANAGER="yum"
fi
;;
arch|manjaro|endeavouros|garuda)
DISTRO_FAMILY="Arch"
PACKAGE_MANAGER="pacman"
;;
opensuse*|sles)
DISTRO_FAMILY="SUSE"
PACKAGE_MANAGER="zypper"
;;
alpine)
DISTRO_FAMILY="Alpine"
PACKAGE_MANAGER="apk"
;;
*)
DISTRO_FAMILY="Unknown"
;;
esac
# Fallback detection methods
elif [[ -f /etc/lsb-release ]]; then
source /etc/lsb-release
DISTRO="${DISTRIB_ID:-Unknown}"
DISTRO_VERSION="${DISTRIB_RELEASE:-Unknown}"
DISTRO_CODENAME="${DISTRIB_CODENAME:-Unknown}"
DISTRO_FAMILY="Debian"
PACKAGE_MANAGER="apt"
elif [[ -f /etc/redhat-release ]]; then
DISTRO=$(cat /etc/redhat-release | cut -d' ' -f1)
DISTRO_VERSION=$(cat /etc/redhat-release | grep -oE '[0-9]+\.[0-9]+' | head -1)
DISTRO_FAMILY="RedHat"
PACKAGE_MANAGER="yum"
fi
# Get kernel and architecture info
KERNEL_VERSION=$(uname -r)
ARCH=$(uname -m)
# Display detected information
echo ""
echo -e " ${WHITE}┌─────────────────────────────────────────────────────────┐${RESET}"
echo -e " ${WHITE}${RESET} ${BOLD}System Information${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}├─────────────────────────────────────────────────────────┤${RESET}"
echo -e " ${WHITE}${RESET} ${CYAN}Distribution:${RESET} ${GREEN}$DISTRO${RESET}"
echo -e " ${WHITE}${RESET} ${CYAN}Version:${RESET} ${GREEN}$DISTRO_VERSION${RESET}"
echo -e " ${WHITE}${RESET} ${CYAN}Codename:${RESET} ${GREEN}$DISTRO_CODENAME${RESET}"
echo -e " ${WHITE}${RESET} ${CYAN}Family:${RESET} ${GREEN}$DISTRO_FAMILY${RESET}"
echo -e " ${WHITE}${RESET} ${CYAN}Package Manager:${RESET} ${GREEN}$PACKAGE_MANAGER${RESET}"
echo -e " ${WHITE}${RESET} ${CYAN}Kernel:${RESET} ${GREEN}$KERNEL_VERSION${RESET}"
echo -e " ${WHITE}${RESET} ${CYAN}Architecture:${RESET} ${GREEN}$ARCH${RESET}"
echo -e " ${WHITE}└─────────────────────────────────────────────────────────┘${RESET}"
echo ""
# Check if distribution is supported
if [[ "$PACKAGE_MANAGER" == "Unknown" ]]; then
print_error "Unsupported Linux distribution detected!"
print_info "This installer supports: Debian/Ubuntu, Fedora/RHEL/CentOS, Arch, openSUSE, Alpine"
exit 1
fi
print_success "Distribution detected successfully!"
sleep 1
}
#-------------------------------------------------------------------------------
# Node.js Detection and Installation
#-------------------------------------------------------------------------------
check_existing_node() {
print_section "${PACKAGE} Node.js & npm Detection"
print_step "Checking for existing Node.js installation..."
sleep 0.5
NODE_INSTALLED=false
NPM_INSTALLED=false
NODE_VERSION=""
NPM_VERSION=""
NEEDS_UPGRADE=false
# Check Node.js
if command -v node &> /dev/null; then
NODE_INSTALLED=true
NODE_VERSION=$(node --version 2>/dev/null || echo "error")
if [[ "$NODE_VERSION" == "error" ]]; then
NODE_VERSION="Broken installation"
NEEDS_UPGRADE=true
fi
fi
# Check npm
if command -v npm &> /dev/null; then
NPM_INSTALLED=true
NPM_VERSION=$(npm --version 2>/dev/null || echo "error")
if [[ "$NPM_VERSION" == "error" ]]; then
NPM_VERSION="Broken installation"
NEEDS_UPGRADE=true
fi
fi
# Display current status
echo ""
echo -e " ${WHITE}┌─────────────────────────────────────────────────────────┐${RESET}"
echo -e " ${WHITE}${RESET} ${BOLD}Current Installation Status${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}├─────────────────────────────────────────────────────────┤${RESET}"
if [[ "$NODE_INSTALLED" == true ]]; then
# Check if version is sufficient (need v18+)
NODE_MAJOR=$(echo "$NODE_VERSION" | sed 's/v//' | cut -d'.' -f1)
if [[ "$NODE_MAJOR" =~ ^[0-9]+$ ]] && [[ "$NODE_MAJOR" -ge 18 ]]; then
echo -e " ${WHITE}${RESET} ${GREEN}${CHECK}${RESET} Node.js: ${GREEN}$NODE_VERSION${RESET} (Compatible)"
else
echo -e " ${WHITE}${RESET} ${YELLOW}${WARNING}${RESET} Node.js: ${YELLOW}$NODE_VERSION${RESET} (Needs upgrade to v18+)"
NEEDS_UPGRADE=true
fi
else
echo -e " ${WHITE}${RESET} ${RED}${CROSS}${RESET} Node.js: ${RED}Not installed${RESET}"
NEEDS_UPGRADE=true
fi
if [[ "$NPM_INSTALLED" == true ]]; then
echo -e " ${WHITE}${RESET} ${GREEN}${CHECK}${RESET} npm: ${GREEN}v$NPM_VERSION${RESET}"
else
echo -e " ${WHITE}${RESET} ${RED}${CROSS}${RESET} npm: ${RED}Not installed${RESET}"
fi
echo -e " ${WHITE}└─────────────────────────────────────────────────────────┘${RESET}"
echo ""
# Determine action needed
if [[ "$NODE_INSTALLED" == true ]] && [[ "$NEEDS_UPGRADE" == true ]]; then
print_warning "Your Node.js version is incompatible with Claude Code."
print_info "Claude Code requires Node.js version 18.0.0 or higher."
echo ""
if confirm "Would you like to remove the existing installation and install Node.js 20 LTS?"; then
remove_existing_node
install_node
else
print_error "Cannot proceed without Node.js 18+. Exiting."
exit 1
fi
elif [[ "$NODE_INSTALLED" == false ]]; then
print_info "Node.js is not installed on your system."
echo ""
if confirm "Would you like to install Node.js 20 LTS?"; then
install_node
else
print_error "Cannot proceed without Node.js. Exiting."
exit 1
fi
else
print_success "Node.js installation is compatible!"
echo ""
if confirm "Would you like to reinstall Node.js anyway (fresh installation)?" "n"; then
remove_existing_node
install_node
fi
fi
}
remove_existing_node() {
print_section "${GEAR} Removing Existing Node.js Installation"
print_step "Removing Node.js, npm, and related packages..."
echo ""
case "$PACKAGE_MANAGER" in
apt)
print_info "Removing Debian/Ubuntu packages..."
# List of packages to remove
PACKAGES_TO_REMOVE="nodejs npm libnode-dev libnode72 nodejs-doc"
for pkg in $PACKAGES_TO_REMOVE; do
if dpkg -l | grep -q "^ii $pkg"; then
echo -ne " ${YELLOW}${RESET} Removing ${CYAN}$pkg${RESET}..."
sudo apt remove -y $pkg > /dev/null 2>&1 || true
echo -e " ${GREEN}done${RESET}"
fi
done
# Remove NodeSource list if exists
if [[ -f /etc/apt/sources.list.d/nodesource.list ]]; then
echo -ne " ${YELLOW}${RESET} Removing old NodeSource repository..."
sudo rm -f /etc/apt/sources.list.d/nodesource.list
echo -e " ${GREEN}done${RESET}"
fi
# Clean up
echo -ne " ${YELLOW}${RESET} Running autoremove..."
sudo apt autoremove -y > /dev/null 2>&1
echo -e " ${GREEN}done${RESET}"
echo -ne " ${YELLOW}${RESET} Cleaning apt cache..."
sudo apt clean > /dev/null 2>&1
echo -e " ${GREEN}done${RESET}"
;;
dnf|yum)
print_info "Removing Fedora/RHEL packages..."
echo -ne " ${YELLOW}${RESET} Removing nodejs and npm..."
sudo $PACKAGE_MANAGER remove -y nodejs npm > /dev/null 2>&1 || true
echo -e " ${GREEN}done${RESET}"
;;
pacman)
print_info "Removing Arch packages..."
echo -ne " ${YELLOW}${RESET} Removing nodejs and npm..."
sudo pacman -Rns --noconfirm nodejs npm > /dev/null 2>&1 || true
echo -e " ${GREEN}done${RESET}"
;;
zypper)
print_info "Removing openSUSE packages..."
echo -ne " ${YELLOW}${RESET} Removing nodejs and npm..."
sudo zypper remove -y nodejs npm > /dev/null 2>&1 || true
echo -e " ${GREEN}done${RESET}"
;;
apk)
print_info "Removing Alpine packages..."
echo -ne " ${YELLOW}${RESET} Removing nodejs and npm..."
sudo apk del nodejs npm > /dev/null 2>&1 || true
echo -e " ${GREEN}done${RESET}"
;;
esac
# Remove global npm packages location
if [[ -d /usr/local/lib/node_modules ]]; then
echo -ne " ${YELLOW}${RESET} Cleaning global node_modules..."
sudo rm -rf /usr/local/lib/node_modules
echo -e " ${GREEN}done${RESET}"
fi
# Remove npm cache
if [[ -d ~/.npm ]]; then
echo -ne " ${YELLOW}${RESET} Cleaning npm cache..."
rm -rf ~/.npm
echo -e " ${GREEN}done${RESET}"
fi
# Remove nvm if exists
if [[ -d ~/.nvm ]]; then
if confirm " Found nvm installation. Remove it too?" "n"; then
rm -rf ~/.nvm
# Remove nvm lines from shell configs
sed -i '/NVM_DIR/d' ~/.bashrc 2>/dev/null || true
sed -i '/nvm.sh/d' ~/.bashrc 2>/dev/null || true
sed -i '/NVM_DIR/d' ~/.zshrc 2>/dev/null || true
sed -i '/nvm.sh/d' ~/.zshrc 2>/dev/null || true
print_success "nvm removed"
fi
fi
echo ""
print_success "Existing Node.js installation removed!"
sleep 1
}
install_node() {
print_section "${PACKAGE} Installing Node.js 20 LTS"
print_step "Preparing to install Node.js 20 LTS..."
echo ""
case "$PACKAGE_MANAGER" in
apt)
print_info "Using NodeSource repository for Debian/Ubuntu..."
echo ""
# Install prerequisites
echo -ne " ${YELLOW}${RESET} Installing prerequisites..."
sudo apt update > /dev/null 2>&1
sudo apt install -y ca-certificates curl gnupg > /dev/null 2>&1
echo -e " ${GREEN}done${RESET}"
# Add NodeSource repository
echo -ne " ${YELLOW}${RESET} Adding NodeSource repository..."
curl -fsSL https://deb.nodesource.com/setup_20.x 2>/dev/null | sudo -E bash - > /dev/null 2>&1
echo -e " ${GREEN}done${RESET}"
# Install Node.js
echo -e " ${YELLOW}${RESET} Installing Node.js 20 LTS..."
sudo apt install -y nodejs 2>&1 | while read line; do
echo -e " ${DIM}$line${RESET}"
done
;;
dnf)
print_info "Using NodeSource repository for Fedora..."
echo ""
echo -ne " ${YELLOW}${RESET} Adding NodeSource repository..."
curl -fsSL https://rpm.nodesource.com/setup_20.x 2>/dev/null | sudo bash - > /dev/null 2>&1
echo -e " ${GREEN}done${RESET}"
echo -e " ${YELLOW}${RESET} Installing Node.js 20 LTS..."
sudo dnf install -y nodejs 2>&1 | while read line; do
echo -e " ${DIM}$line${RESET}"
done
;;
yum)
print_info "Using NodeSource repository for RHEL/CentOS..."
echo ""
echo -ne " ${YELLOW}${RESET} Adding NodeSource repository..."
curl -fsSL https://rpm.nodesource.com/setup_20.x 2>/dev/null | sudo bash - > /dev/null 2>&1
echo -e " ${GREEN}done${RESET}"
echo -e " ${YELLOW}${RESET} Installing Node.js 20 LTS..."
sudo yum install -y nodejs 2>&1 | while read line; do
echo -e " ${DIM}$line${RESET}"
done
;;
pacman)
print_info "Installing from Arch repositories..."
echo ""
echo -ne " ${YELLOW}${RESET} Updating package database..."
sudo pacman -Sy > /dev/null 2>&1
echo -e " ${GREEN}done${RESET}"
echo -e " ${YELLOW}${RESET} Installing Node.js..."
sudo pacman -S --noconfirm nodejs npm 2>&1 | while read line; do
echo -e " ${DIM}$line${RESET}"
done
;;
zypper)
print_info "Installing from openSUSE repositories..."
echo ""
echo -ne " ${YELLOW}${RESET} Refreshing repositories..."
sudo zypper refresh > /dev/null 2>&1
echo -e " ${GREEN}done${RESET}"
echo -e " ${YELLOW}${RESET} Installing Node.js..."
sudo zypper install -y nodejs20 npm20 2>&1 | while read line; do
echo -e " ${DIM}$line${RESET}"
done
;;
apk)
print_info "Installing from Alpine repositories..."
echo ""
echo -ne " ${YELLOW}${RESET} Updating package index..."
sudo apk update > /dev/null 2>&1
echo -e " ${GREEN}done${RESET}"
echo -e " ${YELLOW}${RESET} Installing Node.js..."
sudo apk add nodejs npm 2>&1 | while read line; do
echo -e " ${DIM}$line${RESET}"
done
;;
esac
echo ""
# Rehash command paths
hash -r 2>/dev/null || true
print_success "Node.js installation completed!"
sleep 1
}
verify_node_installation() {
print_section "${CHECK} Verifying Installation"
print_step "Checking Node.js and npm versions..."
echo ""
sleep 0.5
# Rehash to ensure we get fresh paths
hash -r 2>/dev/null || true
# Verify Node.js
if command -v node &> /dev/null; then
NEW_NODE_VERSION=$(node --version)
NODE_MAJOR=$(echo "$NEW_NODE_VERSION" | sed 's/v//' | cut -d'.' -f1)
if [[ "$NODE_MAJOR" -ge 18 ]]; then
echo -e " ${GREEN}${CHECK}${RESET} Node.js: ${GREEN}${BOLD}$NEW_NODE_VERSION${RESET} ${GREEN}(Compatible!)${RESET}"
NODE_OK=true
else
echo -e " ${RED}${CROSS}${RESET} Node.js: ${RED}$NEW_NODE_VERSION (Too old - need v18+)${RESET}"
NODE_OK=false
fi
else
echo -e " ${RED}${CROSS}${RESET} Node.js: ${RED}Not found!${RESET}"
NODE_OK=false
fi
# Verify npm
if command -v npm &> /dev/null; then
NEW_NPM_VERSION=$(npm --version)
echo -e " ${GREEN}${CHECK}${RESET} npm: ${GREEN}${BOLD}v$NEW_NPM_VERSION${RESET}"
NPM_OK=true
else
echo -e " ${RED}${CROSS}${RESET} npm: ${RED}Not found!${RESET}"
NPM_OK=false
fi
# Show paths
echo ""
echo -e " ${DIM}Node path: $(which node 2>/dev/null || echo 'Not found')${RESET}"
echo -e " ${DIM}npm path: $(which npm 2>/dev/null || echo 'Not found')${RESET}"
echo ""
if [[ "$NODE_OK" == true ]] && [[ "$NPM_OK" == true ]]; then
print_success "All requirements verified successfully!"
return 0
else
print_error "Verification failed! Please check the installation."
return 1
fi
}
#-------------------------------------------------------------------------------
# Claude Code Installation
#-------------------------------------------------------------------------------
install_claude_code() {
print_section "${ROCKET} Installing Claude Code"
print_step "Installing Claude Code via npm..."
echo ""
# Create npm global directory in user space to avoid permission issues
if [[ ! -d ~/.npm-global ]]; then
mkdir -p ~/.npm-global
npm config set prefix '~/.npm-global'
# Add to PATH if not already there
if ! grep -q 'npm-global/bin' ~/.bashrc 2>/dev/null; then
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
fi
if [[ -f ~/.zshrc ]] && ! grep -q 'npm-global/bin' ~/.zshrc 2>/dev/null; then
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.zshrc
fi
# Update current session
export PATH=~/.npm-global/bin:$PATH
fi
echo -e " ${YELLOW}${RESET} Downloading and installing Claude Code..."
echo ""
# Install with visible progress
npm install -g @anthropic-ai/claude-code 2>&1 | while IFS= read -r line; do
if [[ "$line" == *"added"* ]] || [[ "$line" == *"packages"* ]]; then
echo -e " ${GREEN}$line${RESET}"
elif [[ "$line" == *"WARN"* ]]; then
echo -e " ${YELLOW}$line${RESET}"
elif [[ "$line" == *"ERR"* ]] || [[ "$line" == *"error"* ]]; then
echo -e " ${RED}$line${RESET}"
else
echo -e " ${DIM}$line${RESET}"
fi
done
# Rehash
hash -r 2>/dev/null || true
echo ""
# Verify installation
if command -v claude &> /dev/null; then
CLAUDE_PATH=$(which claude)
print_success "Claude Code installed successfully!"
echo -e " ${DIM}Location: $CLAUDE_PATH${RESET}"
else
# Try with full path
if [[ -f ~/.npm-global/bin/claude ]]; then
print_success "Claude Code installed successfully!"
echo -e " ${DIM}Location: ~/.npm-global/bin/claude${RESET}"
print_warning "You may need to restart your terminal or run: source ~/.bashrc"
else
print_error "Claude Code installation may have failed!"
print_info "Try running: npm install -g @anthropic-ai/claude-code"
return 1
fi
fi
sleep 1
}
#-------------------------------------------------------------------------------
# Permission Configuration
#-------------------------------------------------------------------------------
configure_permissions() {
print_section "${SHIELD} Permission Configuration"
echo -e " Claude Code can run with different permission levels:"
echo ""
echo -e " ${WHITE}┌─────────────────────────────────────────────────────────────────────┐${RESET}"
echo -e " ${WHITE}${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}${RESET} ${CYAN}1.${RESET} ${BOLD}Normal Mode${RESET} (Recommended for most users) ${WHITE}${RESET}"
echo -e " ${WHITE}${RESET} ${DIM}Claude will ask permission before file edits and commands${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}${RESET} ${GREEN}✓ Safe ✓ Interactive ✓ Full control${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}${RESET} ${CYAN}2.${RESET} ${BOLD}Auto-Accept Edits${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}${RESET} ${DIM}Automatically accept file edits, ask for commands${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}${RESET} ${YELLOW}⚡ Faster editing ✓ Command safety${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}${RESET} ${CYAN}3.${RESET} ${BOLD}Full Auto Mode${RESET} (--dangerously-skip-permissions) ${WHITE}${RESET}"
echo -e " ${WHITE}${RESET} ${DIM}Skip all permission prompts (use with caution!)${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}${RESET} ${RED}⚠ No confirmations ⚠ Full system access${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}${RESET} ${CYAN}4.${RESET} ${BOLD}Don't start Claude${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}${RESET} ${DIM}Exit installer without starting Claude${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}${RESET} ${WHITE}${RESET}"
echo -e " ${WHITE}└─────────────────────────────────────────────────────────────────────┘${RESET}"
echo ""
while true; do
echo -ne "${YELLOW}?${RESET} Select permission mode [${GREEN}1${RESET}/${CYAN}2${RESET}/${RED}3${RESET}/${WHITE}4${RESET}]: "
read -r choice
case "$choice" in
1)
PERMISSION_MODE="normal"
CLAUDE_CMD="claude"
print_success "Selected: Normal Mode"
break
;;
2)
PERMISSION_MODE="auto-edit"
CLAUDE_CMD="claude --auto-accept-edits"
print_success "Selected: Auto-Accept Edits"
break
;;
3)
PERMISSION_MODE="full-auto"
echo ""
print_warning "⚠️ WARNING: Full Auto Mode gives Claude unrestricted access!"
echo -e " ${RED}This mode will:${RESET}"
echo -e " ${RED} • Execute commands without confirmation${RESET}"
echo -e " ${RED} • Modify files without asking${RESET}"
echo -e " ${RED} • Have full access to your system${RESET}"
echo ""
if confirm "Are you sure you want to use Full Auto Mode?" "n"; then
CLAUDE_CMD="claude --dangerously-skip-permissions"
print_success "Selected: Full Auto Mode"
break
else
echo ""
print_info "Please select a different mode."
echo ""
fi
;;
4)
PERMISSION_MODE="exit"
CLAUDE_CMD=""
print_info "Installation complete. You can start Claude anytime with: claude"
break
;;
*)
print_error "Invalid choice. Please enter 1, 2, 3, or 4."
;;
esac
done
}
#-------------------------------------------------------------------------------
# Launch Claude Code
#-------------------------------------------------------------------------------
launch_claude() {
if [[ "$PERMISSION_MODE" == "exit" ]]; then
print_section "${CHECK} Installation Complete!"
echo -e " ${GREEN}Claude Code has been successfully installed!${RESET}"
echo ""
echo -e " ${WHITE}To start Claude Code, run:${RESET}"
echo ""
echo -e " ${CYAN}claude${RESET} ${DIM}# Normal mode${RESET}"
echo -e " ${CYAN}claude --auto-accept-edits${RESET} ${DIM}# Auto-accept file edits${RESET}"
echo -e " ${CYAN}claude --dangerously-skip-permissions${RESET} ${DIM}# Full auto mode${RESET}"
echo ""
echo -e " ${DIM}If 'claude' is not found, restart your terminal or run:${RESET}"
echo -e " ${CYAN}source ~/.bashrc${RESET}"
echo ""
print_success "Thank you for installing Claude Code!"
return
fi
print_section "${ROCKET} Launching Claude Code"
echo -e " ${WHITE}Starting Claude Code with: ${CYAN}$CLAUDE_CMD${RESET}"
echo ""
echo -e " ${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
echo ""
sleep 1
# Ensure PATH includes npm-global
export PATH=~/.npm-global/bin:$PATH
# Launch Claude
exec $CLAUDE_CMD
}
#-------------------------------------------------------------------------------
# Main Script Execution
#-------------------------------------------------------------------------------
main() {
# Check if running as root (not recommended but handle gracefully)
if [[ $EUID -eq 0 ]]; then
print_warning "Running as root. This is not recommended for Claude Code."
print_info "Consider running as a regular user with sudo access."
echo ""
if ! confirm "Continue anyway?"; then
exit 1
fi
fi
# Display banner
print_banner
echo -e " ${WHITE}Welcome to the Claude Code Installer!${RESET}"
echo ""
echo -e " ${DIM}This script will:${RESET}"
echo -e " ${DIM} 1. Detect your Linux distribution${RESET}"
echo -e " ${DIM} 2. Check/install Node.js 20 LTS${RESET}"
echo -e " ${DIM} 3. Install Claude Code${RESET}"
echo -e " ${DIM} 4. Configure permissions${RESET}"
echo ""
if ! confirm "Ready to begin installation?"; then
echo ""
print_info "Installation cancelled. Goodbye!"
exit 0
fi
# Run installation steps
detect_distro
check_existing_node
verify_node_installation || exit 1
install_claude_code || exit 1
configure_permissions
launch_claude
}
# Run main function
main "$@"