Files
internalai-setup/install.sh
Jose B fa90c79ee7 chore: automate platform installation by running internalai install after setup
Replace manual next steps display with automatic execution of the platform installation command. The installer now runs `internalai install` immediately after CLI installation, with fallback to direct path execution if the command is not in PATH.
2025-12-11 16:23:34 -05:00

872 lines
29 KiB
Bash
Executable File
Raw 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
set -euo pipefail
# InternalAI Platform Installer
# ============================================================================
# Configuration
# ============================================================================
PLATFORM_NAME="InternalAI Platform"
DEFAULT_INSTALL_DIR="$HOME/internalai"
REPO_URL="https://gitea.app.monadical.io/monadical/internalai.git"
REPO_SSH="git@gitea.app.monadical.io:monadical/internalai.git"
CLI_INSTALL_DIR="/usr/local/bin"
CLI_NAME="internalai"
VERSION="1.0.0"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'
# ============================================================================
# Logging Functions
# ============================================================================
log_info() {
echo -e "${BLUE}${NC} $1"
}
log_success() {
echo -e "${GREEN}${NC} $1"
}
log_warning() {
echo -e "${YELLOW}${NC} $1"
}
log_error() {
echo -e "${RED}${NC} $1"
}
log_header() {
echo ""
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
echo -e "${CYAN} $1${NC}"
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
echo ""
}
print_banner() {
clear
echo -e "${BOLD}${CYAN}"
cat << 'EOF'
╔═════════════════════════════════════════════════════════════════════════════════════════╗
║ ║
║ ██╗███╗ ██╗████████╗███████╗██████╗ ███╗ ██╗ █████╗ ██╗ █████╗ ██╗ ║
║ ██║████╗ ██║╚══██╔══╝██╔════╝██╔══██╗████╗ ██║██╔══██╗██║ ██╔══██╗██║ ║
║ ██║██╔██╗ ██║ ██║ █████╗ ██████╔╝██╔██╗ ██║███████║██║ ███████║██║ ║
║ ██║██║╚██╗██║ ██║ ██╔══╝ ██╔══██╗██║╚██╗██║██╔══██║██║ ██╔══██║██║ ║
║ ██║██║ ╚████║ ██║ ███████╗██║ ██║██║ ╚████║██║ ██║███████╗ ██║ ██║██║ ║
║ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝╚═╝ ║
║ ║
║ Platform Installer v${VERSION} ║
╚═════════════════════════════════════════════════════════════════════════════════════════╝
EOF
echo -e "${NC}"
}
show_welcome() {
print_banner
log_info "This installer will:"
echo " • Check system dependencies"
echo " • Install missing dependencies (Git, Docker, just, uv)"
echo " • Set up Gitea authentication"
echo " • Clone the InternalAI platform repository"
echo " • Install the 'internalai' command-line tool"
echo ""
}
# ============================================================================
# Utility Functions
# ============================================================================
prompt() {
local varname=$1
local prompt_text=$2
local default_value=$3
local is_secret=${4:-false}
if [ -n "$default_value" ]; then
prompt_text="$prompt_text [${default_value}]"
fi
if [ "$is_secret" = true ]; then
echo -ne "${YELLOW}${prompt_text}: ${NC}" >&2
value=""
while IFS= read -r -s -n1 char < /dev/tty; do
if [[ $char == $'\0' ]]; then
break
fi
if [[ $char == $'\177' ]] || [[ $char == $'\b' ]]; then
if [ ${#value} -gt 0 ]; then
value="${value%?}"
echo -ne "\b \b" >&2
fi
else
value+="$char"
echo -n "*" >&2
fi
done
echo "" >&2
else
echo -ne "${YELLOW}${prompt_text}: ${NC}" >&2
read value < /dev/tty
fi
if [ -z "$value" ] && [ -n "$default_value" ]; then
value="$default_value"
fi
eval "$varname='$value'"
}
# ============================================================================
# Dependency Checking and Installation
# ============================================================================
check_dependencies() {
log_header "Checking Dependencies"
# Check Git
if command -v git &> /dev/null; then
log_success "git installed ($(git --version | head -n1))"
else
log_warning "git is not installed (will attempt to install)"
install_git
fi
# Check bash version
if [ "${BASH_VERSINFO[0]}" -lt 4 ]; then
log_warning "Bash version ${BASH_VERSION} detected. Version 4+ recommended."
else
log_success "bash ${BASH_VERSION} is installed"
fi
# Check Docker
if command -v docker &> /dev/null; then
log_success "docker installed ($(docker --version | head -n1))"
else
log_warning "docker is not installed (will attempt to install)"
install_docker
fi
# Check Docker Compose (should be included with modern Docker installations)
if docker compose version &> /dev/null 2>&1; then
log_success "docker compose installed ($(docker compose version | head -n1))"
elif command -v docker-compose &> /dev/null; then
log_success "docker-compose installed ($(docker-compose --version | head -n1))"
else
log_warning "docker compose not found after Docker installation"
log_info "Docker Compose should be included with Docker. Verifying installation..."
# Try to verify docker is working first
if docker --version &> /dev/null; then
log_info "Docker is installed but compose plugin may not be available"
log_info "This is usually not an issue with modern Docker installations"
fi
fi
# Check Just
if command -v just &> /dev/null; then
log_success "just installed ($(just --version | head -n1))"
else
log_warning "just is not installed (will attempt to install)"
install_just
fi
# Check uv
if command -v uv &> /dev/null; then
log_success "uv installed ($(uv --version | head -n1))"
else
log_warning "uv is not installed (will attempt to install)"
install_uv
fi
log_success "All dependencies are installed!"
}
install_just() {
# Try package managers first
if [[ "$OSTYPE" == "darwin"* ]]; then
if command -v brew &> /dev/null; then
log_info "Installing just via Homebrew..."
if brew install just; then
log_success "just installed"
return 0
else
log_warning "Homebrew installation failed, trying binary download..."
fi
fi
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
if command -v cargo &> /dev/null; then
log_info "Installing just via cargo..."
if cargo install just; then
log_success "just installed"
return 0
else
log_warning "Cargo installation failed, trying binary download..."
fi
fi
fi
# Fall back to downloading pre-built binary
log_info "Downloading pre-built just binary..."
# Detect architecture
local arch=$(uname -m)
local os=$(uname -s | tr '[:upper:]' '[:lower:]')
# Map architecture names
case "$arch" in
x86_64) arch="x86_64" ;;
aarch64|arm64) arch="aarch64" ;;
*)
log_error "Unsupported architecture: $arch"
log_info "Please install just manually: https://github.com/casey/just#installation"
exit 1
;;
esac
# Map OS names
case "$os" in
darwin) os="apple-darwin" ;;
linux) os="unknown-linux-musl" ;;
*)
log_error "Unsupported OS: $os"
log_info "Please install just manually: https://github.com/casey/just#installation"
exit 1
;;
esac
# Get latest version from GitHub API
log_info "Fetching latest version..."
local latest_version=$(curl -fsSL https://api.github.com/repos/casey/just/releases/latest | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')
if [ -z "$latest_version" ]; then
log_error "Failed to fetch latest version"
log_info "Please install just manually: https://github.com/casey/just#installation"
exit 1
fi
local binary_name="just-${latest_version}-${arch}-${os}"
local download_url="https://github.com/casey/just/releases/download/${latest_version}/${binary_name}.tar.gz"
local install_dir="$HOME/.local/bin"
# Create install directory
mkdir -p "$install_dir"
# Download and extract
local tmp_dir=$(mktemp -d)
trap "rm -rf $tmp_dir" EXIT
log_info "Downloading from: $download_url"
if ! curl -fsSL "$download_url" -o "$tmp_dir/just.tar.gz"; then
log_error "Failed to download just binary"
log_info "Please install just manually: https://github.com/casey/just#installation"
exit 1
fi
log_info "Extracting to $install_dir..."
if ! tar -xzf "$tmp_dir/just.tar.gz" -C "$tmp_dir"; then
log_error "Failed to extract just binary"
exit 1
fi
# Install binary
if ! mv "$tmp_dir/just" "$install_dir/just"; then
log_error "Failed to install just to $install_dir"
exit 1
fi
chmod +x "$install_dir/just"
# Add to PATH if not already there
if [[ ":$PATH:" != *":$install_dir:"* ]]; then
log_info "Adding $install_dir to PATH..."
export PATH="$install_dir:$PATH"
# Add to shell profile
local shell_profile=""
if [ -n "$BASH_VERSION" ]; then
shell_profile="$HOME/.bashrc"
elif [ -n "$ZSH_VERSION" ]; then
shell_profile="$HOME/.zshrc"
fi
if [ -n "$shell_profile" ]; then
echo "export PATH=\"$install_dir:\$PATH\"" >> "$shell_profile"
log_info "Added to $shell_profile (restart shell or run: source $shell_profile)"
fi
fi
# Verify installation
if command -v just &> /dev/null; then
log_success "just installed successfully to $install_dir/just"
else
log_warning "just installed to $install_dir/just but not found in PATH"
log_info "You may need to restart your terminal or run:"
log_info " export PATH=\"$install_dir:\$PATH\""
fi
}
install_uv() {
log_info "Installing uv (Python package manager)..."
if curl -LsSf https://astral.sh/uv/install.sh | sh; then
# Add uv to PATH for current session
export PATH="$HOME/.local/bin:$PATH"
if command -v uv &> /dev/null; then
log_success "uv installed successfully ($(uv --version | head -n1))"
else
log_error "uv installation succeeded but not found in PATH"
log_info "You may need to restart your terminal or run:"
log_info " export PATH=\"\$HOME/.local/bin:\$PATH\""
exit 1
fi
else
log_error "Failed to install uv"
log_info "Please install manually: curl -LsSf https://astral.sh/uv/install.sh | sh"
exit 1
fi
}
detect_linux_distro() {
if [ -f /etc/os-release ]; then
. /etc/os-release
echo "$ID"
elif [ -f /etc/redhat-release ]; then
echo "rhel"
elif [ -f /etc/debian_version ]; then
echo "debian"
else
echo "unknown"
fi
}
install_git() {
log_info "Installing Git..."
if [[ "$OSTYPE" == "darwin"* ]]; then
install_git_macos
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
install_git_linux
else
log_error "Unsupported OS: $OSTYPE"
log_info "Please install Git manually: https://git-scm.com/downloads"
exit 1
fi
# Verify installation
if command -v git &> /dev/null; then
log_success "Git installed successfully ($(git --version | head -n1))"
else
log_error "Git installation failed"
exit 1
fi
}
install_git_macos() {
if command -v brew &> /dev/null; then
log_info "Installing Git via Homebrew..."
if brew install git; then
log_success "Git installed via Homebrew"
else
log_error "Failed to install Git via Homebrew"
exit 1
fi
else
# Try Xcode Command Line Tools
log_info "Installing Xcode Command Line Tools (includes Git)..."
log_info "A dialog will appear - please click 'Install'"
if xcode-select --install 2>&1 | grep -q "already installed"; then
log_info "Xcode Command Line Tools already installed"
else
log_info "Waiting for Xcode Command Line Tools installation..."
log_info "This may take a few minutes. Please complete the installation dialog."
# Wait for installation to complete
until xcode-select -p &> /dev/null; do
sleep 5
done
log_success "Xcode Command Line Tools installed"
fi
fi
}
install_git_linux() {
local distro=$(detect_linux_distro)
log_info "Installing Git on $distro..."
case "$distro" in
ubuntu|debian|pop|linuxmint)
sudo apt-get update
sudo apt-get install -y git
;;
fedora|rhel|centos|rocky|almalinux)
if command -v dnf &> /dev/null; then
sudo dnf install -y git
else
sudo yum install -y git
fi
;;
arch|manjaro)
sudo pacman -Sy --noconfirm git
;;
opensuse*|sles)
sudo zypper install -y git
;;
alpine)
sudo apk add git
;;
*)
log_error "Unsupported Linux distribution: $distro"
log_info "Please install Git manually for your distribution:"
log_info " https://git-scm.com/download/linux"
exit 1
;;
esac
}
install_docker() {
log_info "Installing Docker..."
if [[ "$OSTYPE" == "darwin"* ]]; then
install_docker_macos
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
install_docker_linux
else
log_error "Unsupported OS: $OSTYPE"
log_info "Please install Docker manually: https://docs.docker.com/get-docker/"
exit 1
fi
}
install_docker_macos() {
if command -v brew &> /dev/null; then
log_info "Installing Docker via Homebrew..."
if brew install --cask docker; then
log_success "Docker installed via Homebrew"
log_info "Starting Docker Desktop..."
open -a Docker
log_info "Waiting for Docker to start..."
# Wait for docker to be ready (up to 60 seconds)
local timeout=60
local elapsed=0
while ! docker info &> /dev/null; do
if [ $elapsed -ge $timeout ]; then
log_warning "Docker daemon did not start within ${timeout}s"
log_info "Please start Docker Desktop manually and run the installer again"
exit 1
fi
sleep 2
elapsed=$((elapsed + 2))
done
log_success "Docker is ready"
else
log_error "Failed to install Docker via Homebrew"
log_info "Please install Docker Desktop manually: https://docs.docker.com/desktop/install/mac-install/"
exit 1
fi
else
log_error "Homebrew is not installed"
log_info "Install Homebrew first: https://brew.sh"
log_info "Or install Docker Desktop manually: https://docs.docker.com/desktop/install/mac-install/"
exit 1
fi
}
install_docker_linux() {
local distro=$(detect_linux_distro)
log_info "Detected Linux distribution: $distro"
case "$distro" in
ubuntu|debian|pop|linuxmint)
install_docker_debian
;;
fedora|rhel|centos|rocky|almalinux)
install_docker_rhel
;;
arch|manjaro)
install_docker_arch
;;
*)
log_error "Unsupported Linux distribution: $distro"
log_info "Please install Docker manually: https://docs.docker.com/engine/install/"
exit 1
;;
esac
# Start and enable Docker service
start_docker_service
# Add user to docker group and activate immediately
setup_docker_permissions
}
install_docker_debian() {
log_info "Installing Docker on Debian/Ubuntu..."
# Update package index
sudo apt-get update
# Install prerequisites
sudo apt-get install -y ca-certificates curl gnupg lsb-release
# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/$(detect_linux_distro)/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Set up the repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$(detect_linux_distro) \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker Engine
sudo apt-get update
if sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin; then
log_success "Docker installed successfully"
else
log_error "Failed to install Docker"
exit 1
fi
}
install_docker_rhel() {
log_info "Installing Docker on RHEL/Fedora/CentOS..."
# Remove old versions
sudo dnf remove -y docker docker-client docker-client-latest docker-common docker-latest \
docker-latest-logrotate docker-logrotate docker-engine podman runc || true
# Install prerequisites
sudo dnf install -y dnf-plugins-core
# Add Docker repository
sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
# Install Docker Engine
if sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin; then
log_success "Docker installed successfully"
else
log_error "Failed to install Docker"
exit 1
fi
}
install_docker_arch() {
log_info "Installing Docker on Arch Linux..."
# Install Docker from official repositories
if sudo pacman -Sy --noconfirm docker docker-compose; then
log_success "Docker installed successfully"
else
log_error "Failed to install Docker"
exit 1
fi
}
start_docker_service() {
log_info "Starting Docker service..."
if command -v systemctl &> /dev/null; then
sudo systemctl start docker
sudo systemctl enable docker
log_success "Docker service started and enabled"
else
log_warning "systemctl not found, please start Docker manually"
fi
}
setup_docker_permissions() {
log_info "Setting up Docker permissions..."
# Add current user to docker group
if ! groups | grep -q docker; then
sudo usermod -aG docker "$USER"
log_success "User added to docker group"
fi
# Test docker access
if docker ps &> /dev/null 2>&1; then
log_success "Docker is accessible without sudo"
return 0
fi
# If docker requires sudo, set up for immediate use
if sudo docker ps &> /dev/null 2>&1; then
log_info "Docker group membership will be active in new terminal sessions"
log_info "For this session, using docker with sudo privileges..."
# Create a wrapper function for the current script session
# This allows the rest of the script to use docker commands
docker() {
sudo /usr/bin/docker "$@"
}
export -f docker 2>/dev/null || true
log_success "Docker is ready to use (with sudo for current session)"
log_info "Note: New terminal sessions will have docker access without sudo"
else
log_error "Docker is not accessible"
exit 1
fi
}
# ============================================================================
# Gitea Authentication
# ============================================================================
AUTH_TYPE=""
GITEA_TOKEN=""
setup_gitea_auth() {
log_header "Gitea Authentication"
log_info "The InternalAI platform repository is private and requires authentication."
echo ""
log_info "Choose authentication method:"
echo " 1) Personal Access Token (recommended)"
echo " 2) SSH Key (if already configured)"
echo ""
prompt AUTH_CHOICE "Select authentication method" "1"
case "$AUTH_CHOICE" in
1)
AUTH_TYPE="token"
echo ""
log_info "To create a personal access token:"
log_info " 1. Go to: https://gitea.app.monadical.io/user/settings/applications"
log_info " 2. Click 'Generate New Token'"
log_info " 3. Give it a name (e.g., 'InternalAI Setup')"
log_info " 4. Give it Read repository scope"
log_info " 5. Click 'Generate Token' and copy it"
echo ""
prompt GITEA_TOKEN "Enter your Gitea Personal Access Token" "" true
if [ -z "$GITEA_TOKEN" ]; then
log_error "Token is required"
exit 1
fi
;;
2)
AUTH_TYPE="ssh"
log_info "Using SSH authentication"
log_info "Ensure your SSH key is added to Gitea:"
log_info " https://gitea.app.monadical.io/user/settings/keys"
# Test SSH connection
echo ""
log_info "Testing SSH connection..."
if ssh -T git@gitea.app.monadical.io 2>&1 | grep -q "Hi there"; then
log_success "SSH connection successful"
else
log_warning "Could not verify SSH connection, but will try to continue..."
fi
;;
*)
log_error "Invalid choice"
exit 1
;;
esac
}
prepare_git_url() {
if [ "$AUTH_TYPE" = "token" ] && [ -n "$GITEA_TOKEN" ]; then
echo "$REPO_URL" | sed "s|https://gitea.app.monadical.io/|https://${GITEA_TOKEN}@gitea.app.monadical.io/|"
elif [ "$AUTH_TYPE" = "ssh" ]; then
echo "$REPO_SSH"
else
echo "$REPO_URL"
fi
}
# ============================================================================
# Git Credential Caching
# ============================================================================
configure_git_credentials() {
log_header "Configuring Git Credentials"
if [ "$AUTH_TYPE" = "ssh" ]; then
log_info "Using SSH - no credential caching needed"
return
fi
# Detect OS and configure appropriate credential helper
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS - use keychain
log_info "Configuring git to use macOS Keychain..."
git config --global credential.helper osxkeychain
log_success "Git credentials will be stored in macOS Keychain"
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
# Linux - try to use libsecret, fall back to cache
if command -v git-credential-libsecret &> /dev/null; then
log_info "Configuring git to use libsecret..."
git config --global credential.helper libsecret
log_success "Git credentials will be stored in system keyring"
else
log_info "Configuring git credential cache (1 hour)..."
git config --global credential.helper 'cache --timeout=3600'
log_success "Git credentials will be cached in memory for 1 hour"
log_info "For persistent storage, install: libsecret"
fi
else
# Unknown OS - use cache
log_info "Configuring git credential cache (1 hour)..."
git config --global credential.helper 'cache --timeout=3600'
log_success "Git credentials will be cached in memory for 1 hour"
fi
# Store credentials by triggering a git operation
if [ "$AUTH_TYPE" = "token" ] && [ -n "$INSTALL_DIR" ] && [ -d "$INSTALL_DIR/.git" ]; then
log_info "Caching credentials..."
cd "$INSTALL_DIR"
# Trigger credential storage by doing a fetch (which uses credentials)
git fetch --dry-run 2>&1 | grep -v "password\|token" > /dev/null || true
log_success "Credentials cached successfully"
fi
}
# ============================================================================
# Repository Cloning
# ============================================================================
clone_repository() {
log_header "Cloning Repository"
prompt INSTALL_DIR "Installation directory" "$DEFAULT_INSTALL_DIR"
if [ -d "$INSTALL_DIR" ]; then
if [ -d "$INSTALL_DIR/.git" ]; then
log_warning "Directory already exists and appears to be a git repository"
prompt UPDATE_CHOICE "Update existing repository? (y/n)" "y"
if [[ "$UPDATE_CHOICE" =~ ^[Yy] ]]; then
log_info "Pulling latest changes..."
cd "$INSTALL_DIR"
git pull
log_success "Repository updated"
return
else
log_info "Using existing repository"
return
fi
else
log_error "Directory exists but is not a git repository"
log_info "Please remove or rename: $INSTALL_DIR"
exit 1
fi
fi
local git_url=$(prepare_git_url)
log_info "Cloning repository to: $INSTALL_DIR"
log_info "This may take a few minutes..."
if git clone "$git_url" "$INSTALL_DIR" 2>&1 | grep -v "password\|token"; then
log_success "Repository cloned successfully"
else
log_error "Failed to clone repository"
log_info "Please check your credentials and try again"
exit 1
fi
}
# ============================================================================
# CLI Installation
# ============================================================================
install_cli() {
log_header "Installing CLI Tool"
local cli_script="$INSTALL_DIR/scripts/$CLI_NAME"
if [ ! -f "$cli_script" ]; then
log_error "CLI script not found at: $cli_script"
exit 1
fi
log_info "Installing $CLI_NAME to $CLI_INSTALL_DIR..."
if [ -w "$CLI_INSTALL_DIR" ]; then
cp "$cli_script" "$CLI_INSTALL_DIR/$CLI_NAME"
chmod +x "$CLI_INSTALL_DIR/$CLI_NAME"
else
log_warning "Need sudo permissions to write to $CLI_INSTALL_DIR"
sudo cp "$cli_script" "$CLI_INSTALL_DIR/$CLI_NAME"
sudo chmod +x "$CLI_INSTALL_DIR/$CLI_NAME"
fi
if command -v "$CLI_NAME" &> /dev/null; then
log_success "$CLI_NAME installed successfully!"
else
log_warning "$CLI_NAME installed but not found in PATH"
log_info "You may need to restart your terminal or run:"
log_info " export PATH=\"$CLI_INSTALL_DIR:\$PATH\""
fi
}
# ============================================================================
# Post-Installation
# ============================================================================
run_platform_install() {
log_header "Installation Complete!"
echo -e "${GREEN}${BOLD}The InternalAI platform has been set up successfully!${NC}"
echo ""
echo -e "${BOLD}Platform Location:${NC} ${CYAN}$INSTALL_DIR${NC}"
echo ""
log_info "Starting platform configuration and installation..."
echo ""
# Run internalai install
if command -v "$CLI_NAME" &> /dev/null; then
"$CLI_NAME" install
else
log_error "$CLI_NAME command not found in PATH"
log_info "Trying direct path: $CLI_INSTALL_DIR/$CLI_NAME"
if [ -x "$CLI_INSTALL_DIR/$CLI_NAME" ]; then
"$CLI_INSTALL_DIR/$CLI_NAME" install
else
log_error "Failed to run $CLI_NAME install"
log_info "Please run manually: $CLI_NAME install"
exit 1
fi
fi
}
# ============================================================================
# Main Installation Flow
# ============================================================================
main() {
show_welcome
check_dependencies
setup_gitea_auth
clone_repository
configure_git_credentials
install_cli
run_platform_install
echo ""
echo -e "${GREEN}${BOLD}Setup completed successfully!${NC}"
echo ""
}
main "$@"