#!/bin/bash # VFAT AI Agent Installation Script # Interactive installer with multiple modes # # Usage: # curl -fsSL https://ai.vf.at/install.sh | TOKEN=xxx bash # # Environment variables: # TOKEN - Required: Agent authentication token # INSTALL_MODE - Optional: user or isolated (skips interactive prompt) # CONTROL_PLANE_URL - Optional: WebSocket URL (auto-set by server) # # Note: URLs below are replaced dynamically when served via /install.sh endpoint # set -e # If we're being piped (stdin is not a tty and $0 is bash), save to temp file # This allows re-execution with sudo for isolated mode if [ ! -t 0 ] && echo "$0" | grep -q "bash"; then SCRIPT_FILE=$(mktemp /tmp/vfat-ai-install.XXXXXX) cat > "$SCRIPT_FILE" chmod +x "$SCRIPT_FILE" export VFAT_AI_SCRIPT_FILE="$SCRIPT_FILE" exec bash "$SCRIPT_FILE" "$@" fi # Configuration from environment TOKEN="${TOKEN:-}" CONTROL_PLANE_URL="${CONTROL_PLANE_URL:-wss://ai.vf.at/agent/connect}" INSTALL_MODE="${INSTALL_MODE:-}" # Clean up temp file on exit if we created one if [ -n "$VFAT_AI_SCRIPT_FILE" ]; then trap "rm -f '$VFAT_AI_SCRIPT_FILE'" EXIT fi if [ -z "$TOKEN" ]; then echo "TOKEN is required. Get your token from https://ai.vf.at" echo " curl -fsSL https://ai.vf.at/install.sh | TOKEN=your-token bash" exit 1 fi # Derive package URL from control plane URL HTTPS_URL="${CONTROL_PLANE_URL/wss:/https:}" HTTPS_URL="${HTTPS_URL/ws:/http:}" PACKAGE_URL="${HTTPS_URL%/agent/connect}/package/vfat-ai.tar.gz" echo "=== VFAT AI Agent Installation ===" echo # Interactive mode selection (unless pre-selected) if [ -z "$INSTALL_MODE" ]; then echo "Choose installation mode:" echo echo " 1) User mode (recommended for personal dev machines)" echo " - Runs as your current user ($USER)" echo " - Uses ~/.local/vfat-ai/ for installation" echo " - Start manually or add to shell profile" echo echo " 2) Isolated mode (recommended for shared/production servers)" echo " - Creates dedicated 'vfat-ai' system user" echo " - Runs as systemd service (auto-start on boot)" echo " - More secure isolation" echo # Check if we have a tty for interactive input # When piped (curl | bash), stdin is the pipe, so we read from /dev/tty if [ -t 0 ]; then read -p "Enter choice [1/2]: " choice elif [ -e /dev/tty ]; then read -p "Enter choice [1/2]: " choice < /dev/tty else echo "No interactive terminal detected. Defaulting to user mode." echo "Use INSTALL_MODE=isolated for isolated mode." choice="1" fi case "$choice" in 1) INSTALL_MODE="user" ;; 2) INSTALL_MODE="isolated" ;; *) echo "Invalid choice. Defaulting to user mode." INSTALL_MODE="user" ;; esac fi echo echo "Selected mode: $INSTALL_MODE" echo # Function to install the package into a venv install_package() { local VENV_DIR="$1" local RUN_AS_USER="${2:-}" # Optional: run commands as this user echo "Creating virtual environment at $VENV_DIR..." if [ -n "$RUN_AS_USER" ]; then if ! sudo -u "$RUN_AS_USER" python3 -m venv "$VENV_DIR"; then echo "ERROR: Failed to create virtual environment" exit 1 fi else if ! python3 -m venv "$VENV_DIR"; then echo "ERROR: Failed to create virtual environment" exit 1 fi fi # Verify venv was created if [ ! -f "$VENV_DIR/bin/pip" ]; then echo "ERROR: Virtual environment creation failed - pip not found" echo "Make sure python3-venv is installed" exit 1 fi echo "Downloading package from $PACKAGE_URL..." if [ -n "$RUN_AS_USER" ]; then if ! sudo -u "$RUN_AS_USER" "$VENV_DIR/bin/pip" install --quiet "$PACKAGE_URL"; then echo "ERROR: Failed to install package" exit 1 fi else if ! "$VENV_DIR/bin/pip" install --quiet "$PACKAGE_URL"; then echo "ERROR: Failed to install package" exit 1 fi fi # Verify installation if [ ! -f "$VENV_DIR/bin/vfat-ai-agent" ]; then echo "ERROR: vfat-ai-agent not found after installation" echo "Check: $PACKAGE_URL" exit 1 fi echo "Installed: $("$VENV_DIR/bin/vfat-ai-agent" --version 2>/dev/null || echo 'vfat-ai-agent')" } # Function to install in user mode install_user_mode() { echo "--- Installing User Mode ---" VENV_DIR="$HOME/.local/vfat-ai" PROJECTS_DIR="$HOME/projects" ENV_FILE="$HOME/.config/vfat-ai/agent.env" AGENT_BIN="$VENV_DIR/bin/vfat-ai-agent" # Check for python3-venv if ! python3 -c "import ensurepip" 2>/dev/null; then echo "ERROR: python3-venv is required but not installed." echo echo "Install it with:" if command -v apt-get &>/dev/null; then echo " sudo apt install python3-venv" elif command -v dnf &>/dev/null; then echo " sudo dnf install python3-venv" elif command -v pacman &>/dev/null; then echo " sudo pacman -S python" else echo " Install python3-venv using your package manager" fi echo echo "Then re-run this script." exit 1 fi # Create directories echo "Setting up directories..." mkdir -p "$PROJECTS_DIR" mkdir -p "$(dirname "$ENV_FILE")" mkdir -p "$(dirname "$VENV_DIR")" # Install package into venv install_package "$VENV_DIR" # Create environment file with token echo "Configuring agent token..." cat > "$ENV_FILE" << EOF # VFAT AI Agent Configuration (auto-generated) VFAT_AI_AGENT_TOKEN=$TOKEN VFAT_AI_CONTROL_PLANE_URL=$CONTROL_PLANE_URL EOF chmod 600 "$ENV_FILE" echo echo "User mode installed!" echo echo "Start the agent with:" echo " export \$(cat $ENV_FILE | xargs) && $AGENT_BIN" echo echo "Or add to your shell profile for persistence." } # Function to install in isolated mode install_isolated_mode() { echo "--- Installing Isolated Mode ---" # Check for root if [ "$EUID" -ne 0 ]; then echo "Isolated mode requires root privileges." echo "Re-running with sudo..." exec sudo TOKEN="$TOKEN" CONTROL_PLANE_URL="$CONTROL_PLANE_URL" INSTALL_MODE="isolated" bash "$0" fi AGENT_USER="vfat-ai" AGENT_HOME="/var/lib/vfat-ai" VENV_DIR="$AGENT_HOME/venv" PROJECTS_DIR="$AGENT_HOME/projects" ENV_FILE="/etc/vfat-ai-agent.env" AGENT_BIN="$VENV_DIR/bin/vfat-ai-agent" # Create system user if id "vfat-ai" &>/dev/null; then echo "User 'vfat-ai' already exists" else echo "Creating user 'vfat-ai'..." useradd --system \ --home-dir "$AGENT_HOME" \ --shell /bin/bash \ --create-home \ vfat-ai fi # Create directories echo "Setting up directories..." sudo -u vfat-ai mkdir -p "$PROJECTS_DIR" sudo -u vfat-ai mkdir -p "$AGENT_HOME/.ssh" chmod 700 "$AGENT_HOME/.ssh" # Generate SSH key if [ ! -f "$AGENT_HOME/.ssh/id_ed25519" ]; then echo "Generating SSH key..." sudo -u vfat-ai ssh-keygen -t ed25519 \ -f "$AGENT_HOME/.ssh/id_ed25519" \ -N "" \ -C "vfat-ai-agent" fi # Configure git echo "Configuring git..." cd "$AGENT_HOME" sudo -u vfat-ai git config --global user.name "VFAT AI Agent" sudo -u vfat-ai git config --global user.email "agent@vfat-ai.local" # Install system dependencies echo "Installing system dependencies..." apt-get update -qq || true # Ignore update errors (some repos may fail) if ! apt-get install -y -qq python3-venv python3-pip; then echo "ERROR: Failed to install python3-venv" echo "Try running: sudo apt install python3-venv python3-pip" exit 1 fi # Install package into venv install_package "$VENV_DIR" "vfat-ai" # Create environment file with token echo "Configuring agent token..." cat > "$ENV_FILE" << EOF # VFAT AI Agent Configuration (auto-generated) VFAT_AI_AGENT_TOKEN=$TOKEN VFAT_AI_CONTROL_PLANE_URL=$CONTROL_PLANE_URL EOF chmod 600 "$ENV_FILE" # Install systemd service echo "Installing systemd service..." cat > /etc/systemd/system/vfat-ai-agent.service << EOF [Unit] Description=VFAT AI Agent (Isolated) After=network.target [Service] Type=simple User=vfat-ai Group=vfat-ai WorkingDirectory=$AGENT_HOME EnvironmentFile=$ENV_FILE Environment=HOME=$AGENT_HOME ExecStart=$AGENT_BIN Restart=always RestartSec=10 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload # Start the agent echo "Starting agent..." systemctl enable vfat-ai-agent systemctl start vfat-ai-agent echo echo "Isolated mode installed!" echo echo "Agent is running as systemd service." echo echo "Next step - Log in to Claude Code:" echo " sudo -u vfat-ai claude" } # Execute based on mode case "$INSTALL_MODE" in user) install_user_mode ;; isolated) install_isolated_mode ;; *) echo "Unknown mode: $INSTALL_MODE" exit 1 ;; esac echo echo "=== Installation Complete ===" echo echo "Return to the web UI to set up GitHub access."