#!/usr/bin/env bash # ═══════════════════════════════════════════════════════════════════════════════ # AI Terminal Kickstart - Linux Edition # Supports: Ubuntu 20.04+, Linux Mint 20+, RHEL 8+/9+, Fedora, AlmaLinux # # One script to prep a Linux PC for AI-powered terminal work: # 1. Claude Code (Anthropic) # 2. ChatGPT CLI (OpenAI) # 3. GitHub Copilot CLI (GitHub) # + Netlify CLI for direct site deployment # # Usage: # chmod +x start-ai-terminal-kickstart.sh # sudo ./start-ai-terminal-kickstart.sh # sudo ./start-ai-terminal-kickstart.sh --auto # unattended mode # # Author : AI Terminal ops # Date : 2026-03-25 # ═══════════════════════════════════════════════════════════════════════════════ set -uo pipefail # NOTE: -e (errexit) is intentionally omitted. This script uses manual error # handling with || true and explicit checks. set -e causes false exits on # arithmetic operations returning 0 and optional package installs failing. # ─── Configuration ──────────────────────────────────────────────────────────── SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" TEMP_DIR="/tmp/ai-kickstart-$(date +%Y%m%d)" LOG_FILE="$TEMP_DIR/kickstart.log" AUTO_MODE=false ACTUAL_USER="${SUDO_USER:-$USER}" ACTUAL_HOME=$(eval echo "~$ACTUAL_USER") # Parse arguments for arg in "$@"; do case "$arg" in --auto|-a) AUTO_MODE=true ;; --help|-h) echo "Usage: sudo $0 [--auto]" echo " --auto Install everything without prompts" exit 0 ;; esac done mkdir -p "$TEMP_DIR" touch "$LOG_FILE" # ─── Detect Distro ─────────────────────────────────────────────────────────── DISTRO="unknown" PKG_MGR="unknown" PKG_INSTALL="" PKG_UPDATE="" if [ -f /etc/os-release ]; then . /etc/os-release case "$ID" in ubuntu|linuxmint|pop|elementary|zorin) DISTRO="debian" PKG_MGR="apt" PKG_INSTALL="apt-get install -y" PKG_UPDATE="apt-get update -qq" ;; rhel|centos|rocky|alma|ol) DISTRO="rhel" PKG_MGR="dnf" PKG_INSTALL="dnf install -y" PKG_UPDATE="dnf check-update || true" ;; fedora) DISTRO="rhel" PKG_MGR="dnf" PKG_INSTALL="dnf install -y" PKG_UPDATE="dnf check-update || true" ;; *) # Try to detect by package manager if command -v apt-get &>/dev/null; then DISTRO="debian" PKG_MGR="apt" PKG_INSTALL="apt-get install -y" PKG_UPDATE="apt-get update -qq" elif command -v dnf &>/dev/null; then DISTRO="rhel" PKG_MGR="dnf" PKG_INSTALL="dnf install -y" PKG_UPDATE="dnf check-update || true" elif command -v yum &>/dev/null; then DISTRO="rhel" PKG_MGR="yum" PKG_INSTALL="yum install -y" PKG_UPDATE="yum check-update || true" fi ;; esac fi # ─── Helper Functions ──────────────────────────────────────────────────────── RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' CYAN='\033[0;36m' MAGENTA='\033[0;35m' WHITE='\033[1;37m' GRAY='\033[0;37m' NC='\033[0m' # No Color log() { echo "[$(date +%H:%M:%S)] $*" >> "$LOG_FILE"; } section() { echo -e "\n ${CYAN}=================================================================${NC}"; echo -e " ${CYAN}$1${NC}"; echo -e " ${CYAN}=================================================================${NC}"; log "SECTION: $1"; } step() { echo -e "\n ${CYAN}>> $1${NC}"; log "STEP: $1"; } ok() { echo -e " ${GREEN}[OK]${NC} $1"; log " OK: $1"; } warn() { echo -e " ${YELLOW}[WARN]${NC} $1"; log "WARN: $1"; } fail() { echo -e " ${RED}[FAIL]${NC} $1"; log "FAIL: $1"; } info() { echo -e " ${GRAY}$1${NC}"; } tip() { echo -e " ${YELLOW}[TIP]${NC} $1"; } cmd_exists() { command -v "$1" &>/dev/null; } # ─── Progress bar ──────────────────────────────────────────────────────────── TOTAL_PHASES=6 CURRENT_PHASE=0 show_progress() { local label="$1" CURRENT_PHASE=$((CURRENT_PHASE + 1)) local pct=$((CURRENT_PHASE * 100 / TOTAL_PHASES)) local bar_len=30 local filled=$((bar_len * CURRENT_PHASE / TOTAL_PHASES)) local empty=$((bar_len - filled)) local bar=$(printf '%0.s█' $(seq 1 $filled 2>/dev/null) || true) local space=$(printf '%0.s░' $(seq 1 $empty 2>/dev/null) || true) printf "\r ${CYAN}[%s%s] %3d%% - Phase %d/%d: %s${NC} \n" \ "$bar" "$space" "$pct" "$CURRENT_PHASE" "$TOTAL_PHASES" "$label" } # Spinner for long-running commands run_with_spinner() { local label="$1" shift local cmd="$*" local spin='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏' local i=0 eval "$cmd" & local pid=$! while kill -0 "$pid" 2>/dev/null; do local c="${spin:i++%${#spin}:1}" printf "\r ${CYAN}%s${NC} %s " "$c" "$label" sleep 0.15 done wait "$pid" local rc=$? printf "\r \r" return $rc } # ─── Version Configuration (change these to update targets) ────────────────── NODE_MAJOR="22" # Node.js LTS major version # Python version is auto-detected from system package manager ask_yn() { local prompt="$1" local default="${2:-y}" if $AUTO_MODE; then [[ "$default" == "y" ]] && return 0 || return 1 fi local hint="Y/n" [[ "$default" == "n" ]] && hint="y/N" echo -ne " ${YELLOW}$prompt ($hint): ${NC}" read -r answer answer="${answer:-$default}" [[ "$answer" =~ ^[Yy] ]] } run_as_user() { # Run a command as the actual user (not root) # Uses "$@" quoting pattern via a helper to preserve spaces in arguments if [ "$EUID" -eq 0 ] && [ -n "${SUDO_USER:-}" ]; then sudo -u "$SUDO_USER" -- bash -c "$1" else bash -c "$1" fi } # Track results for final summary declare -a RESULT_NAMES=() declare -a RESULT_STATUS=() declare -a RESULT_DETAIL=() add_result() { RESULT_NAMES+=("$1") RESULT_STATUS+=("$2") RESULT_DETAIL+=("${3:-}") } # ─── Banner ─────────────────────────────────────────────────────────────────── echo -e "${MAGENTA}" cat << 'BANNER' ╔═══════════════════════════════════════════════════════════════════╗ ║ ║ ║ A I T E R M I N A L K I C K S T A R T ║ ║ ───────────────────────────────────────── ║ ║ Linux Edition (Ubuntu / RHEL / Mint) ║ ║ ║ ║ Claude Code | ChatGPT CLI | GitHub Copilot CLI ║ ║ ║ ╚═══════════════════════════════════════════════════════════════════╝ BANNER echo -e "${NC}" # ─── System Info ────────────────────────────────────────────────────────────── echo -e " ${WHITE}System Info:${NC}" echo -e " ${GRAY}OS : $(cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d= -f2 | tr -d '"')${NC}" echo -e " ${GRAY}Kernel : $(uname -r)${NC}" echo -e " ${GRAY}Distro Type : $DISTRO ($PKG_MGR)${NC}" echo -e " ${GRAY}User : $ACTUAL_USER${NC}" echo -e " ${GRAY}Bash : $BASH_VERSION${NC}" echo -e " ${GRAY}Log File : $LOG_FILE${NC}" echo "" if [ "$EUID" -ne 0 ]; then echo -e " ${YELLOW}┌──────────────────────────────────────────────────────────────┐${NC}" echo -e " ${YELLOW}│ WARNING: Not running as root. Re-run with sudo: │${NC}" echo -e " ${YELLOW}│ sudo $0${NC}" echo -e " ${YELLOW}└──────────────────────────────────────────────────────────────┘${NC}" echo "" fi if [ "$DISTRO" = "unknown" ]; then fail "Could not detect your Linux distribution." echo -e " Supported: Ubuntu, Linux Mint, RHEL, CentOS, Rocky, Alma, Fedora" exit 1 fi # ─── Pre-flight: Admin, Network, Disk, Repos, TLS ──────────────────────────── show_progress "Pre-flight Checks" section "PRE-FLIGHT CHECKS" # Log session separator echo "" >> "$LOG_FILE" echo "======================================================================" >> "$LOG_FILE" echo "Session started: $(date '+%Y-%m-%d %H:%M:%S')" >> "$LOG_FILE" echo "OS: $(cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d= -f2 | tr -d '"')" >> "$LOG_FILE" echo "Distro type: $DISTRO ($PKG_MGR) | User: $ACTUAL_USER | EUID: $EUID" >> "$LOG_FILE" echo "======================================================================" >> "$LOG_FILE" # Admin / root access check step "Checking root/sudo privileges" if [ "$EUID" -eq 0 ]; then ok "Running as root - full install capability" add_result "Root Access" "OK" "Elevated" else warn "NOT running as root. Package installs WILL fail." info "Re-run with: sudo $0" info "The following require root: apt/dnf install, repo setup, locale changes" add_result "Root Access" "FAILED" "Not root" fi # TLS / certificates check step "Checking TLS certificates" if [ -f /etc/ssl/certs/ca-certificates.crt ] || [ -d /etc/pki/tls/certs ]; then ok "CA certificate bundle present" else warn "CA certificates may be missing - HTTPS downloads could fail" if [ "$DISTRO" = "debian" ]; then $PKG_INSTALL ca-certificates >> "$LOG_FILE" 2>&1 || true elif [ "$DISTRO" = "rhel" ]; then $PKG_INSTALL ca-certificates >> "$LOG_FILE" 2>&1 || true fi fi # OpenSSL version check if cmd_exists openssl; then SSL_VER=$(openssl version 2>/dev/null || true) ok "OpenSSL: $SSL_VER" else warn "openssl not found - some tools may have TLS issues" fi add_result "TLS/Certs" "OK" "" # Network connectivity - test multiple download sources step "Testing internet connectivity to download sources" REACHABLE=0 UNREACHABLE=0 declare -A NET_ENDPOINTS=( ["GitHub API"]="https://api.github.com" ["NodeSource"]="https://deb.nodesource.com" ["Claude installer"]="https://claude.ai" ["npm registry"]="https://registry.npmjs.org" ["PyPI"]="https://pypi.org" ) for name in "${!NET_ENDPOINTS[@]}"; do url="${NET_ENDPOINTS[$name]}" if curl -sf --connect-timeout 8 --max-time 12 -o /dev/null "$url" 2>/dev/null; then ok "$name reachable" ((REACHABLE++)) || true else warn "$name ($url) - UNREACHABLE" ((UNREACHABLE++)) || true fi done TOTAL_EP=$((REACHABLE + UNREACHABLE)) if [ "$UNREACHABLE" -eq 0 ]; then ok "All $REACHABLE download sources reachable" add_result "Network" "OK" "$REACHABLE/$TOTAL_EP reachable" elif [ "$UNREACHABLE" -lt 3 ]; then warn "$UNREACHABLE of $TOTAL_EP sources unreachable. Some installs may fail." add_result "Network" "PARTIAL" "$REACHABLE/$TOTAL_EP reachable" else fail "Most download sources unreachable. Script will likely fail." info "Check: DNS, proxy, firewall, or VPN settings." add_result "Network" "FAILED" "$REACHABLE/$TOTAL_EP reachable" fi # Disk space check step "Checking available disk space" FREE_GB=$(df -BG / 2>/dev/null | awk 'NR==2{print $4}' | tr -d 'G') TOTAL_GB=$(df -BG / 2>/dev/null | awk 'NR==2{print $2}' | tr -d 'G') if [ "${FREE_GB:-0}" -lt 2 ]; then fail "CRITICAL: Only ${FREE_GB}GB free on / (${TOTAL_GB}GB total). Need at least 2GB." info "Free up disk space before continuing." add_result "Disk Space" "FAILED" "${FREE_GB}GB free" elif [ "${FREE_GB:-0}" -lt 5 ]; then warn "Low: ${FREE_GB}GB free on / (${TOTAL_GB}GB total). Recommend 5+ GB." add_result "Disk Space" "WARN" "${FREE_GB}GB free" else ok "Disk space: ${FREE_GB}GB free on / (${TOTAL_GB}GB total)" add_result "Disk Space" "OK" "${FREE_GB}GB free" fi # Check for package manager lock files step "Checking for package manager locks" if [ "$DISTRO" = "debian" ]; then if fuser /var/lib/dpkg/lock-frontend &>/dev/null 2>&1 || fuser /var/lib/apt/lists/lock &>/dev/null 2>&1; then warn "apt/dpkg is locked by another process. Wait for it to finish." info "Run: sudo lsof /var/lib/dpkg/lock-frontend to see what holds it." add_result "Package Lock" "WARN" "apt locked" else ok "No package manager locks detected" add_result "Package Lock" "OK" "" fi elif [ "$DISTRO" = "rhel" ]; then if [ -f /var/run/yum.pid ] || [ -f /var/run/dnf.pid ]; then warn "dnf/yum lock file found. Another install may be running." add_result "Package Lock" "WARN" "dnf locked" else ok "No package manager locks detected" add_result "Package Lock" "OK" "" fi fi # ═══════════════════════════════════════════════════════════════════════════════ # PHASE 1: SYSTEM UPDATE & CORE PACKAGES # ═══════════════════════════════════════════════════════════════════════════════ show_progress "System Update & Core Packages" section "PHASE 1: System Update & Core Packages" step "Updating package lists" eval "$PKG_UPDATE" >> "$LOG_FILE" 2>&1 || true ok "Package lists updated" # ─── Essential build tools ──────────────────────────────────────────────────── step "Installing essential build tools" if [ "$DISTRO" = "debian" ]; then $PKG_INSTALL build-essential curl wget ca-certificates gnupg lsb-release \ software-properties-common unzip tar >> "$LOG_FILE" 2>&1 || true elif [ "$DISTRO" = "rhel" ]; then $PKG_INSTALL gcc gcc-c++ make curl wget ca-certificates gnupg2 unzip tar \ >> "$LOG_FILE" 2>&1 || true # Enable EPEL for extra packages if ! rpm -q epel-release &>/dev/null; then $PKG_INSTALL epel-release >> "$LOG_FILE" 2>&1 || true fi fi ok "Build tools installed" add_result "Build Tools" "INSTALLED" "" step "Checking locale and UTF-8 support" CURRENT_LANG="${LANG:-}" if [[ "$CURRENT_LANG" == *"UTF-8"* ]] || [[ "$CURRENT_LANG" == *"utf8"* ]]; then ok "Locale is UTF-8: $CURRENT_LANG" else warn "Locale is '$CURRENT_LANG' - may cause display issues with AI terminal output" if [ "$DISTRO" = "debian" ]; then $PKG_INSTALL locales >> "$LOG_FILE" 2>&1 || true locale-gen en_US.UTF-8 >> "$LOG_FILE" 2>&1 || true update-locale LANG=en_US.UTF-8 >> "$LOG_FILE" 2>&1 || true fi tip "Add to ~/.bashrc: export LANG=en_US.UTF-8" if ! grep -q 'LANG=en_US.UTF-8' "$ACTUAL_HOME/.bashrc" 2>/dev/null; then echo 'export LANG=en_US.UTF-8' >> "$ACTUAL_HOME/.bashrc" fi fi # ─── Git ────────────────────────────────────────────────────────────────────── step "Checking Git" if cmd_exists git; then ok "Git already installed ($(git --version))" add_result "Git" "PRESENT" "$(git --version)" else info "Git is REQUIRED for Claude Code and version control." if ask_yn "Install Git?"; then $PKG_INSTALL git >> "$LOG_FILE" 2>&1 || true ok "Git installed ($(git --version))" add_result "Git" "INSTALLED" "$(git --version)" else warn "Skipping Git - Claude Code WILL NOT WORK without it!" add_result "Git" "SKIPPED" "WARNING" fi fi # Git user config check if cmd_exists git; then step "Checking Git configuration" GIT_USER=$(run_as_user "git config --global user.name" 2>/dev/null) GIT_EMAIL=$(run_as_user "git config --global user.email" 2>/dev/null) if [ -z "$GIT_USER" ] || [ -z "$GIT_EMAIL" ]; then warn "Git user.name or user.email not set. Commits will fail without these." tip "Run: git config --global user.name 'Your Name'" tip "Run: git config --global user.email 'you@example.com'" else ok "Git user: $GIT_USER <$GIT_EMAIL>" fi run_as_user "git config --global init.defaultBranch main" 2>/dev/null run_as_user "git config --global core.autocrlf input" 2>/dev/null fi # ─── Node.js (via NodeSource) ──────────────────────────────────────────────── step "Checking Node.js" if cmd_exists node; then ok "Node.js already installed ($(node --version))" cmd_exists npm && ok "npm $(npm --version)" cmd_exists npx && ok "npx available" add_result "Node.js" "PRESENT" "$(node --version)" else info "Node.js is required for Claude Code, npm tools, and MCP servers." if ask_yn "Install Node.js ${NODE_MAJOR} LTS?"; then if [ "$DISTRO" = "debian" ]; then # NodeSource setup for Debian/Ubuntu curl -fsSL https://deb.nodesource.com/setup_${NODE_MAJOR}.x | bash - >> "$LOG_FILE" 2>&1 || true $PKG_INSTALL nodejs >> "$LOG_FILE" 2>&1 || true elif [ "$DISTRO" = "rhel" ]; then curl -fsSL https://rpm.nodesource.com/setup_${NODE_MAJOR}.x | bash - >> "$LOG_FILE" 2>&1 || true $PKG_INSTALL nodejs >> "$LOG_FILE" 2>&1 || true fi if cmd_exists node; then ok "Node.js $(node --version) installed" ok "npm $(npm --version)" add_result "Node.js" "INSTALLED" "$(node --version)" else fail "Node.js installation failed" add_result "Node.js" "FAILED" "" fi else add_result "Node.js" "SKIPPED" "" fi fi # Fix npm global permissions for the actual user if cmd_exists npm; then step "Configuring npm global directory (no-sudo installs)" NPM_GLOBAL="$ACTUAL_HOME/.npm-global" run_as_user "mkdir -p '$NPM_GLOBAL'" run_as_user "npm config set prefix '$NPM_GLOBAL'" # Add to PATH in bashrc if not already there BASHRC="$ACTUAL_HOME/.bashrc" if ! grep -q 'npm-global' "$BASHRC" 2>/dev/null; then echo '' >> "$BASHRC" echo '# npm global packages (no sudo needed)' >> "$BASHRC" echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> "$BASHRC" fi export PATH="$NPM_GLOBAL/bin:$PATH" ok "npm global dir: $NPM_GLOBAL" fi # ─── Python ─────────────────────────────────────────────────────────────────── step "Checking Python" PYTHON_CMD="" if cmd_exists python3; then PYTHON_CMD="python3" elif cmd_exists python; then PYTHON_CMD="python" fi if [ -n "$PYTHON_CMD" ]; then ok "Python already installed ($($PYTHON_CMD --version 2>&1))" add_result "Python" "PRESENT" "$($PYTHON_CMD --version 2>&1)" else info "Python is used for MCP servers, AI SDKs, and data processing." if ask_yn "Install Python 3?"; then if [ "$DISTRO" = "debian" ]; then $PKG_INSTALL python3 python3-pip python3-venv python3-dev >> "$LOG_FILE" 2>&1 || true elif [ "$DISTRO" = "rhel" ]; then $PKG_INSTALL python3 python3-pip python3-devel >> "$LOG_FILE" 2>&1 || true fi PYTHON_CMD="python3" if cmd_exists python3; then ok "Python $(python3 --version 2>&1) installed" add_result "Python" "INSTALLED" "$(python3 --version 2>&1)" else fail "Python installation failed" add_result "Python" "FAILED" "" fi else add_result "Python" "SKIPPED" "" fi fi # Upgrade pip if [ -n "$PYTHON_CMD" ] && cmd_exists "$PYTHON_CMD"; then step "Upgrading pip" run_as_user "$PYTHON_CMD -m pip install --upgrade pip --quiet" 2>/dev/null || true ok "pip upgraded" fi # ─── CLI Utilities ──────────────────────────────────────────────────────────── step "Installing CLI utilities" declare -A CLI_TOOLS if [ "$DISTRO" = "debian" ]; then CLI_TOOLS=( [ripgrep]="ripgrep" [jq]="jq" [fd]="fd-find" [imagemagick]="imagemagick" [p7zip]="p7zip-full" [ghostscript]="ghostscript" [ffmpeg]="ffmpeg" [bat]="bat" [fzf]="fzf" [yq]="yq" [tree]="tree" [delta]="git-delta" [shellcheck]="shellcheck" [tmux]="tmux" [sqlite3]="sqlite3" ) elif [ "$DISTRO" = "rhel" ]; then CLI_TOOLS=( [ripgrep]="ripgrep" [jq]="jq" [fd]="fd-find" [imagemagick]="ImageMagick" [p7zip]="p7zip" [ghostscript]="ghostscript" [ffmpeg]="ffmpeg" [bat]="bat" [fzf]="fzf" [yq]="yq" [tree]="tree" [delta]="git-delta" [shellcheck]="ShellCheck" [tmux]="tmux" [sqlite3]="sqlite" ) fi CLI_CMDS=( [ripgrep]="rg" [jq]="jq" [fd]="fdfind" [imagemagick]="convert" [p7zip]="7z" [ghostscript]="gs" [ffmpeg]="ffmpeg" [bat]="batcat" [fzf]="fzf" [yq]="yq" [tree]="tree" [delta]="delta" [shellcheck]="shellcheck" [tmux]="tmux" [sqlite3]="sqlite3" ) CLI_DESC=( [ripgrep]="Ultra-fast code search (used by Claude Code)" [jq]="JSON processor for API responses" [fd]="Fast file finder" [imagemagick]="Image processing (convert, resize)" [p7zip]="Archive compression" [ghostscript]="PDF/PostScript engine (required by ImageMagick for PDFs)" [ffmpeg]="Video/audio processing and media conversion" [bat]="Syntax-highlighted file viewer (better cat)" [fzf]="Fuzzy finder for files, history, and commands" [yq]="YAML processor (like jq but for YAML)" [tree]="Directory structure viewer" [delta]="Enhanced git diff viewer with syntax highlighting" [shellcheck]="Shell script linter and validator" [tmux]="Terminal multiplexer for persistent sessions" [sqlite3]="Lightweight database engine and client" ) for tool in ripgrep jq fd imagemagick p7zip ghostscript ffmpeg bat fzf yq tree delta shellcheck tmux sqlite3; do pkg="${CLI_TOOLS[$tool]:-}" cmd="${CLI_CMDS[$tool]:-$tool}" desc="${CLI_DESC[$tool]:-}" if cmd_exists "$cmd"; then ok "$tool is installed" add_result "$tool" "PRESENT" "" else info "$tool: $desc" if ask_yn "Install $tool?"; then $PKG_INSTALL "$pkg" >> "$LOG_FILE" 2>&1 || true ok "$tool installed" add_result "$tool" "INSTALLED" "" else add_result "$tool" "SKIPPED" "" fi fi done # ─── Python Packages ───────────────────────────────────────────────────────── if [ -n "$PYTHON_CMD" ] && cmd_exists "$PYTHON_CMD"; then step "Python packages for AI development" info "These packages enhance what Claude Code and AI tools can do:" info " Data: numpy, pandas, polars, matplotlib, openpyxl" info " Web: requests, httpx, beautifulsoup4" info " AI: anthropic, openai, fastmcp, mcp" info " Dev: pydantic, rich, pyyaml, python-dotenv" if ask_yn "Install recommended Python packages?"; then PACKAGES="numpy pandas polars matplotlib openpyxl requests httpx beautifulsoup4 lxml anthropic openai fastmcp mcp pydantic rich pyyaml python-dotenv Pillow chardet tabulate jsonlines" run_as_user "$PYTHON_CMD -m pip install --user $PACKAGES --quiet" >> "$LOG_FILE" 2>&1 || true ok "Python packages installed" add_result "Python Packages" "INSTALLED" "22 packages" else add_result "Python Packages" "SKIPPED" "" fi # uv package manager step "Checking uv (fast Python package manager)" if cmd_exists uv; then ok "uv already installed ($(uv --version 2>/dev/null))" add_result "uv" "PRESENT" "" else if ask_yn "Install uv?"; then run_as_user "curl -LsSf https://astral.sh/uv/install.sh | sh" >> "$LOG_FILE" 2>&1 || true export PATH="$ACTUAL_HOME/.cargo/bin:$PATH" ok "uv installed" add_result "uv" "INSTALLED" "" else add_result "uv" "SKIPPED" "" fi fi fi # ═══════════════════════════════════════════════════════════════════════════════ # PHASE 2: AI TERMINAL INSTALLATIONS # ═══════════════════════════════════════════════════════════════════════════════ show_progress "AI Terminal Solutions" section "PHASE 2: AI Terminal Solutions" echo "" echo -e " ${WHITE}Which AI terminal solutions would you like to set up?${NC}" echo "" echo -e " ${CYAN}┌──────────────────────────────────────────────────────────────┐${NC}" echo -e " ${CYAN}│ 1. Claude Code (Anthropic) │${NC}" echo -e " ${GRAY}│ Best for: Deep code understanding, multi-file edits, │${NC}" echo -e " ${GRAY}│ agentic coding, MCP servers, security research │${NC}" echo -e " ${GRAY}│ Auth: Browser login (OAuth) or ANTHROPIC_API_KEY │${NC}" echo -e " ${CYAN}│ │${NC}" echo -e " ${CYAN}│ 2. ChatGPT CLI (OpenAI) via npx chatgpt │${NC}" echo -e " ${GRAY}│ Best for: Quick questions, brainstorming, general AI │${NC}" echo -e " ${GRAY}│ Auth: OPENAI_API_KEY environment variable │${NC}" echo -e " ${CYAN}│ │${NC}" echo -e " ${CYAN}│ 3. GitHub Copilot CLI (GitHub) │${NC}" echo -e " ${GRAY}│ Best for: Shell command suggestions, git operations │${NC}" echo -e " ${GRAY}│ Auth: gh auth login (browser-based) │${NC}" echo -e " ${CYAN}└──────────────────────────────────────────────────────────────┘${NC}" echo "" INSTALL_CLAUDE=false INSTALL_CHATGPT=false INSTALL_COPILOT=false ask_yn "Install Claude Code?" && INSTALL_CLAUDE=true ask_yn "Install ChatGPT CLI tools?" && INSTALL_CHATGPT=true ask_yn "Install GitHub Copilot CLI?" && INSTALL_COPILOT=true # ─── Claude Code ────────────────────────────────────────────────────────────── if $INSTALL_CLAUDE; then section "Installing Claude Code" if cmd_exists claude; then ok "Claude Code already installed ($(claude --version 2>/dev/null || echo 'installed'))" add_result "Claude Code" "PRESENT" "" else step "Installing Claude Code via official installer..." info "This uses Anthropic's official install script." run_as_user "curl -fsSL https://claude.ai/install.sh | sh" >> "$LOG_FILE" 2>&1 || true # Add to PATH export PATH="$ACTUAL_HOME/.local/bin:$PATH" if ! grep -qF '.local/bin' "$ACTUAL_HOME/.bashrc" 2>/dev/null; then echo '' >> "$ACTUAL_HOME/.bashrc" echo '# Claude Code PATH' >> "$ACTUAL_HOME/.bashrc" echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$ACTUAL_HOME/.bashrc" fi if run_as_user "command -v claude" &>/dev/null; then ok "Claude Code installed!" add_result "Claude Code" "INSTALLED" "" else # Fallback: npm install warn "Official installer may need a new shell. Trying npm fallback..." if cmd_exists npm; then run_as_user "npm install -g @anthropic-ai/claude-code" >> "$LOG_FILE" 2>&1 || true if run_as_user "command -v claude" &>/dev/null; then ok "Claude Code installed via npm" add_result "Claude Code" "INSTALLED" "via npm" else fail "Claude Code install needs a terminal restart" tip "Close this terminal, open a new one, and run: claude" add_result "Claude Code" "INSTALLED" "restart terminal" fi else fail "npm not available for fallback install" add_result "Claude Code" "FAILED" "npm missing" fi fi fi # Claude Code authentication guide echo "" echo -e " ${CYAN}┌──────────────────────────────────────────────────────────────┐${NC}" echo -e " ${CYAN}│ CLAUDE CODE AUTHENTICATION │${NC}" echo -e " ${CYAN}├──────────────────────────────────────────────────────────────┤${NC}" echo -e " ${GRAY}│ │${NC}" echo -e " ${GRAY}│ Option A - Browser Login (easiest): │${NC}" echo -e " ${WHITE}│ 1. Run: claude │${NC}" echo -e " ${WHITE}│ 2. Browser opens -> log in at claude.ai │${NC}" echo -e " ${WHITE}│ 3. Click Authorize -> return to terminal │${NC}" echo -e " ${GRAY}│ │${NC}" echo -e " ${GRAY}│ Option B - API Key: │${NC}" echo -e " ${WHITE}│ 1. Get key from console.anthropic.com/settings/keys │${NC}" echo -e " ${WHITE}│ 2. export ANTHROPIC_API_KEY=\"sk-ant-your-key\" │${NC}" echo -e " ${WHITE}│ 3. Add to ~/.bashrc to persist │${NC}" echo -e " ${GRAY}│ │${NC}" echo -e " ${CYAN}└──────────────────────────────────────────────────────────────┘${NC}" if ask_yn "Set ANTHROPIC_API_KEY now?" "n"; then echo -ne " ${YELLOW}Enter your Anthropic API key (sk-ant-...): ${NC}" read -r ANTHROPIC_KEY if [[ "$ANTHROPIC_KEY" == sk-ant-* ]]; then echo "export ANTHROPIC_API_KEY=\"$ANTHROPIC_KEY\"" >> "$ACTUAL_HOME/.bashrc" export ANTHROPIC_API_KEY="$ANTHROPIC_KEY" ok "ANTHROPIC_API_KEY saved to ~/.bashrc" else warn "Key doesn't start with sk-ant- . Skipped. Use browser login instead." fi fi fi # ─── ChatGPT CLI ───────────────────────────────────────────────────────────── if $INSTALL_CHATGPT; then section "Installing ChatGPT CLI Tools" step "Installing OpenAI-compatible CLI tools..." # Install the Node.js based chatgpt client if cmd_exists npm; then info "Installing chatgpt npm package..." run_as_user "npm install -g chatgpt-cli" >> "$LOG_FILE" 2>&1 || true ok "chatgpt-cli installed (run: chatgpt)" add_result "ChatGPT CLI" "INSTALLED" "chatgpt-cli" else warn "npm not available - cannot install ChatGPT CLI" add_result "ChatGPT CLI" "FAILED" "npm missing" fi # Install the Python openai package for scripting if [ -n "${PYTHON_CMD:-}" ] && cmd_exists "$PYTHON_CMD"; then run_as_user "$PYTHON_CMD -m pip install --user openai --quiet" >> "$LOG_FILE" 2>&1 || true ok "OpenAI Python SDK installed" fi # Authentication guide echo "" echo -e " ${CYAN}┌──────────────────────────────────────────────────────────────┐${NC}" echo -e " ${CYAN}│ CHATGPT AUTHENTICATION │${NC}" echo -e " ${CYAN}├──────────────────────────────────────────────────────────────┤${NC}" echo -e " ${GRAY}│ │${NC}" echo -e " ${WHITE}│ 1. Get API key: https://platform.openai.com/api-keys │${NC}" echo -e " ${WHITE}│ 2. Set it: export OPENAI_API_KEY=\"sk-your-key\" │${NC}" echo -e " ${WHITE}│ 3. Persist: add the export line to ~/.bashrc │${NC}" echo -e " ${WHITE}│ 4. Test: curl https://api.openai.com/v1/models \\ │${NC}" echo -e " ${WHITE}│ -H \"Authorization: Bearer \$OPENAI_API_KEY\" │${NC}" echo -e " ${GRAY}│ │${NC}" echo -e " ${CYAN}└──────────────────────────────────────────────────────────────┘${NC}" if ask_yn "Set OPENAI_API_KEY now?" "n"; then echo -ne " ${YELLOW}Enter your OpenAI API key (sk-...): ${NC}" read -r OPENAI_KEY if [[ "$OPENAI_KEY" == sk-* ]]; then echo "export OPENAI_API_KEY=\"$OPENAI_KEY\"" >> "$ACTUAL_HOME/.bashrc" export OPENAI_API_KEY="$OPENAI_KEY" ok "OPENAI_API_KEY saved to ~/.bashrc" else warn "Key format not recognized. Set it manually later." fi fi fi # ─── GitHub Copilot CLI ────────────────────────────────────────────────────── if $INSTALL_COPILOT; then section "Installing GitHub Copilot CLI" # Install GitHub CLI first step "Checking GitHub CLI (gh)" if cmd_exists gh; then ok "GitHub CLI already installed ($(gh --version 2>/dev/null | head -1))" else info "GitHub CLI is required for Copilot CLI." if ask_yn "Install GitHub CLI?" "y"; then if [ "$DISTRO" = "debian" ]; then curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg 2>/dev/null chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg || true echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list apt-get update -qq >> "$LOG_FILE" 2>&1 || true $PKG_INSTALL gh >> "$LOG_FILE" 2>&1 || true elif [ "$DISTRO" = "rhel" ]; then dnf install -y 'dnf-command(config-manager)' >> "$LOG_FILE" 2>&1 || true dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo >> "$LOG_FILE" 2>&1 || true $PKG_INSTALL gh >> "$LOG_FILE" 2>&1 || true fi fi fi if cmd_exists gh; then ok "GitHub CLI: $(gh --version 2>/dev/null | head -1)" add_result "GitHub CLI" "PRESENT" "" step "Installing Copilot CLI extension..." run_as_user "gh extension install github/gh-copilot" >> "$LOG_FILE" 2>&1 || true ok "Copilot CLI extension installed" add_result "GitHub Copilot CLI" "INSTALLED" "" # Authentication guide echo "" echo -e " ${CYAN}┌──────────────────────────────────────────────────────────────┐${NC}" echo -e " ${CYAN}│ GITHUB COPILOT AUTHENTICATION │${NC}" echo -e " ${CYAN}├──────────────────────────────────────────────────────────────┤${NC}" echo -e " ${GRAY}│ │${NC}" echo -e " ${WHITE}│ 1. Run: gh auth login │${NC}" echo -e " ${WHITE}│ 2. Choose: GitHub.com │${NC}" echo -e " ${WHITE}│ 3. Choose: Login with a web browser │${NC}" echo -e " ${WHITE}│ 4. Copy the one-time code shown │${NC}" echo -e " ${WHITE}│ 5. Browser opens -> paste code -> Authorize │${NC}" echo -e " ${WHITE}│ 6. Return to terminal -> authenticated │${NC}" echo -e " ${GRAY}│ │${NC}" echo -e " ${GRAY}│ Requires: GitHub Copilot subscription (\$10/mo or free │${NC}" echo -e " ${GRAY}│ for students and open source maintainers) │${NC}" echo -e " ${GRAY}│ │${NC}" echo -e " ${CYAN}└──────────────────────────────────────────────────────────────┘${NC}" if ask_yn "Log in to GitHub now?" "n"; then run_as_user "gh auth login" fi else fail "GitHub CLI not available" add_result "GitHub Copilot CLI" "FAILED" "gh CLI missing" fi fi # ═══════════════════════════════════════════════════════════════════════════════ # PHASE 3: NETLIFY CLI & DEPLOYMENT TOOLS # ═══════════════════════════════════════════════════════════════════════════════ show_progress "Deployment & Extras" section "PHASE 3: Netlify CLI & Deployment" step "Checking Netlify CLI" if cmd_exists netlify; then ok "Netlify CLI already installed ($(netlify --version 2>/dev/null))" add_result "Netlify CLI" "PRESENT" "" else info "Netlify CLI lets you deploy websites directly from your terminal." info "Free tier: 100GB bandwidth, 300 build minutes/month, custom domains." if ask_yn "Install Netlify CLI?"; then if cmd_exists npm; then run_as_user "npm install -g netlify-cli" >> "$LOG_FILE" 2>&1 || true export PATH="${NPM_GLOBAL:-$ACTUAL_HOME/.npm-global}/bin:$PATH" if run_as_user "command -v netlify" &>/dev/null || cmd_exists netlify; then ok "Netlify CLI installed" add_result "Netlify CLI" "INSTALLED" "" else warn "Netlify CLI installed but needs terminal restart for PATH" add_result "Netlify CLI" "INSTALLED" "restart terminal" fi else fail "npm not available - install Node.js first" add_result "Netlify CLI" "FAILED" "npm missing" fi else add_result "Netlify CLI" "SKIPPED" "" fi fi # Netlify authentication guide echo "" echo -e " ${CYAN}┌──────────────────────────────────────────────────────────────┐${NC}" echo -e " ${CYAN}│ NETLIFY AUTHENTICATION & DEPLOYMENT │${NC}" echo -e " ${CYAN}├──────────────────────────────────────────────────────────────┤${NC}" echo -e " ${GRAY}│ │${NC}" echo -e " ${WHITE}│ LOGIN: │${NC}" echo -e " ${WHITE}│ netlify login │${NC}" echo -e " ${WHITE}│ (browser opens -> click Authorize -> return to terminal) │${NC}" echo -e " ${GRAY}│ │${NC}" echo -e " ${WHITE}│ FIRST DEPLOY (link a folder to a Netlify site): │${NC}" echo -e " ${WHITE}│ cd /path/to/my-website │${NC}" echo -e " ${WHITE}│ netlify init │${NC}" echo -e " ${WHITE}│ netlify deploy # preview draft │${NC}" echo -e " ${WHITE}│ netlify deploy --prod # push live │${NC}" echo -e " ${GRAY}│ │${NC}" echo -e " ${WHITE}│ AI-POWERED DEPLOY (use Claude to edit then deploy): │${NC}" echo -e " ${WHITE}│ cd /path/to/my-website │${NC}" echo -e " ${WHITE}│ claude │${NC}" echo -e " ${WHITE}│ > fix the broken nav menu and deploy a draft to Netlify │${NC}" echo -e " ${GRAY}│ │${NC}" echo -e " ${WHITE}│ ENVIRONMENT VARIABLES: │${NC}" echo -e " ${WHITE}│ netlify env:set MY_VAR \"value\" │${NC}" echo -e " ${WHITE}│ netlify env:list │${NC}" echo -e " ${GRAY}│ │${NC}" echo -e " ${CYAN}└──────────────────────────────────────────────────────────────┘${NC}" if cmd_exists netlify || run_as_user "command -v netlify" &>/dev/null; then if ask_yn "Log in to Netlify now?" "n"; then run_as_user "netlify login" fi fi # ─── Vercel CLI ─────────────────────────────────────────────────────────────── step "Checking Vercel CLI" if cmd_exists vercel || run_as_user "command -v vercel" &>/dev/null; then ok "Vercel CLI already installed" add_result "Vercel CLI" "PRESENT" "" else info "Vercel is another popular hosting platform (like Netlify)." if ask_yn "Install Vercel CLI?" "n"; then if cmd_exists npm; then run_as_user "npm install -g vercel" >> "$LOG_FILE" 2>&1 || true ok "Vercel CLI installed" add_result "Vercel CLI" "INSTALLED" "" else fail "npm not available" add_result "Vercel CLI" "FAILED" "npm missing" fi else add_result "Vercel CLI" "SKIPPED" "" fi fi # ═══════════════════════════════════════════════════════════════════════════════ # PHASE 4: ENVIRONMENT HEALTH CHECK # ═══════════════════════════════════════════════════════════════════════════════ show_progress "Validation & Health Check" section "PHASE 4: Environment Health Check" echo "" printf " ${WHITE}%-18s %-10s %-35s${NC}\n" "Component" "Status" "Version / Details" printf " %-18s %-10s %-35s\n" "──────────────────" "──────────" "───────────────────────────────────" # ─── Functional Validation (not just version checks) ────────────────────────── step "Running functional validation tests" # Test Node.js can execute JavaScript if cmd_exists node; then NODE_TEST=$(run_as_user "node -e \"console.log('node-ok')\"" 2>/dev/null || true) if [[ "$NODE_TEST" == *"node-ok"* ]]; then ok "Node.js exec: PASS" else warn "Node.js exec: FAIL - node installed but cannot run JS" fi fi # Test Python SSL and package imports if [ -n "${PYTHON_CMD:-}" ] && cmd_exists "$PYTHON_CMD"; then PY_SSL=$(run_as_user "$PYTHON_CMD -c \"import ssl; print('py-ssl-ok:', ssl.OPENSSL_VERSION)\"" 2>/dev/null || true) if [[ "$PY_SSL" == *"py-ssl-ok"* ]]; then ok "Python SSL: PASS (${PY_SSL#*: })" else warn "Python SSL: FAIL - HTTPS requests may not work" fi PY_IMPORT=$(run_as_user "$PYTHON_CMD -c \"import requests, pydantic; print('imports-ok')\"" 2>/dev/null || true) if [[ "$PY_IMPORT" == *"imports-ok"* ]]; then ok "Python packages: PASS" else warn "Python packages: FAIL - some packages not importable" fi fi # Test npm registry connectivity if cmd_exists npm; then NPM_PING=$(run_as_user "npm ping" 2>/dev/null || true) if [ $? -eq 0 ] || [[ "$NPM_PING" != *"ERR"* ]]; then ok "npm registry: PASS" else warn "npm registry: FAIL - npm cannot reach registry" fi fi # Test Git HTTPS connectivity if cmd_exists git; then GIT_LS=$(run_as_user "git ls-remote --heads https://github.com/anthropics/claude-code.git" 2>/dev/null || true) if [ -n "$GIT_LS" ]; then ok "Git HTTPS: PASS" else warn "Git HTTPS: FAIL - git cannot reach GitHub" fi fi echo "" CHECKS=( "Git:git --version" "Node.js:node --version" "npm:npm --version" "npx:npx --version" "Python:python3 --version" "pip:python3 -m pip --version" "uv:uv --version" "Claude Code:claude --version" "GitHub CLI:gh --version" "Netlify CLI:netlify --version" "Vercel CLI:vercel --version" "ripgrep:rg --version" "jq:jq --version" "ImageMagick:convert --version" "GhostScript:gs --version" "FFmpeg:ffmpeg -version" "tmux:tmux -V" "sqlite3:sqlite3 --version" "bat:batcat --version" "fzf:fzf --version" "shellcheck:shellcheck --version" ) PASS_COUNT=0 FAIL_COUNT=0 for check in "${CHECKS[@]}"; do name="${check%%:*}" cmd="${check#*:}" padded_name=$(printf "%-18s" "$name") ver=$(run_as_user "$cmd" 2>/dev/null | head -1 || true) if [ -n "$ver" ]; then truncated="${ver:0:35}" printf " %s ${GREEN}%-10s${NC} ${GRAY}%s${NC}\n" "$padded_name" "PASS" "$truncated" PASS_COUNT=$((PASS_COUNT + 1)) else printf " %s ${RED}%-10s${NC} ${GRAY}%s${NC}\n" "$padded_name" "MISSING" "Not installed" FAIL_COUNT=$((FAIL_COUNT + 1)) fi done echo "" echo -e " ─────────────────────────────────────────────────────────────────" if [ "$FAIL_COUNT" -eq 0 ]; then echo -e " ${GREEN}Total: $PASS_COUNT passed, $FAIL_COUNT missing${NC}" else echo -e " ${YELLOW}Total: $PASS_COUNT passed, $FAIL_COUNT missing${NC}" fi # ═══════════════════════════════════════════════════════════════════════════════ # PHASE 5: QUICK REFERENCE GUIDE # ═══════════════════════════════════════════════════════════════════════════════ show_progress "Complete" section "PHASE 5: Quick Reference Guide" echo -e "${CYAN}" cat << 'GUIDE' ┌─────────────────────────────────────────────────────────────────┐ │ HOW TO USE YOUR AI TERMINALS │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ CLAUDE CODE (Best for coding, files, agents) │ │ ───────────────────────────────────────────── │ │ claude Start interactive session │ │ claude "fix this bug" One-shot command │ │ claude doctor Diagnose configuration │ │ /help In-session help │ │ │ │ First time: run 'claude' -> browser opens -> log in -> │ │ click Authorize -> return to terminal -> start coding! │ │ │ │ CHATGPT CLI (Best for quick Q&A, brainstorming) │ │ ───────────────────────────────────────────── │ │ chatgpt Start interactive chat (if avail) │ │ Set OPENAI_API_KEY first, then use CLI tools │ │ │ │ GITHUB COPILOT CLI (Best for shell commands) │ │ ───────────────────────────────────────────── │ │ gh copilot suggest "..." Get command suggestions │ │ gh copilot explain "..." Explain a command │ │ gh auth login Log in to GitHub first │ │ │ │ NETLIFY DEPLOYMENT │ │ ────────────────── │ │ netlify login Authenticate │ │ cd /path/to/site │ │ netlify init Link folder to Netlify site │ │ netlify deploy Preview deploy │ │ netlify deploy --prod Production deploy │ │ │ │ AI + DEPLOY WORKFLOW (the magic combo) │ │ ───────────────────────────────────── │ │ cd /path/to/site && claude │ │ > make the hero section more engaging, then deploy │ │ a draft to Netlify so I can preview it │ │ │ │ GUI & WEB INTERFACES (when you prefer a visual tool) │ │ ─────────────────────────────────────────────── │ │ Claude web app: https://claude.ai/code │ │ Claude VS Code: Extensions > search "Claude Code" │ │ ChatGPT web: https://chatgpt.com │ │ ChatGPT desktop: https://openai.com/chatgpt/download │ │ Copilot VS Code: Extensions > "GitHub Copilot" │ │ Netlify GUI: https://app.netlify.com │ │ │ │ APP CONNECTORS (via Claude Code MCP Servers) │ │ ──────────────────────────────────────────── │ │ claude mcp add gdrive -- npx @anthropic/gdrive-mcp │ │ claude mcp add slack -- npx @anthropic/slack-mcp │ │ claude mcp add github -- npx @anthropic/github-mcp │ │ claude mcp add playwright -- npx @playwright/mcp@latest │ │ claude mcp list # see all connected services │ │ │ │ COMMON TIPS │ │ ─────────── │ │ - Always cd into your project folder BEFORE starting claude │ │ - Be specific in prompts for better results │ │ - Open a NEW terminal after install for PATH changes │ │ - Run 'claude doctor' if something seems broken │ │ │ └─────────────────────────────────────────────────────────────────┘ GUIDE echo -e "${NC}" # ═══════════════════════════════════════════════════════════════════════════════ # FINAL SUMMARY # ═══════════════════════════════════════════════════════════════════════════════ ELAPSED=$((SECONDS / 60))m$((SECONDS % 60))s echo -e " ${GREEN}╔═══════════════════════════════════════════════════════════════════╗${NC}" echo -e " ${GREEN}║ KICKSTART COMPLETE ║${NC}" echo -e " ${GREEN}╠═══════════════════════════════════════════════════════════════════╣${NC}" echo -e " ${GREEN}║ ║${NC}" printf " ${GREEN}║${NC} ${WHITE}%-22s %-12s %-25s${NC} ${GREEN}║${NC}\n" "Component" "Status" "Detail" printf " ${GREEN}║${NC} %-22s %-12s %-25s ${GREEN}║${NC}\n" "──────────────────────" "────────────" "─────────────────────────" for i in "${!RESULT_NAMES[@]}"; do name="${RESULT_NAMES[$i]}" status="${RESULT_STATUS[$i]}" detail="${RESULT_DETAIL[$i]:0:25}" case "$status" in INSTALLED|PRESENT|RAN|OK) color="$GREEN" ;; SKIPPED|PARTIAL) color="$YELLOW" ;; FAILED|ERROR) color="$RED" ;; *) color="$GRAY" ;; esac printf " ${GREEN}║${NC} ${color}%-22s %-12s${NC} ${GRAY}%-25s${NC} ${GREEN}║${NC}\n" "$name" "$status" "$detail" done echo -e " ${GREEN}║ ║${NC}" echo -e " ${GREEN}║ Time elapsed: $ELAPSED ${GREEN}║${NC}" echo -e " ${GREEN}║ Log file : $LOG_FILE${GREEN}$(printf '%*s' $((35 - ${#LOG_FILE})) '')║${NC}" echo -e " ${GREEN}║ ║${NC}" echo -e " ${GREEN}║ NEXT STEPS: ║${NC}" echo -e " ${GREEN}║ 1. CLOSE this terminal and open a NEW one (PATH refresh) ║${NC}" echo -e " ${GREEN}║ 2. Run 'claude' to start Claude Code (browser auth first time) ║${NC}" echo -e " ${GREEN}║ 3. Run 'gh auth login' for GitHub Copilot ║${NC}" echo -e " ${GREEN}║ 4. Run 'netlify login' to authenticate Netlify ║${NC}" echo -e " ${GREEN}║ 5. cd into your project folder, then 'claude' to start! ║${NC}" echo -e " ${GREEN}║ ║${NC}" echo -e " ${GREEN}╚═══════════════════════════════════════════════════════════════════╝${NC}" echo ""