#!/bin/sh # finish.sh installer # Usage: curl -sSL https://git.appmodel.nl/tour/finish/raw/branch/main/docs/install.sh | bash set -e ACSH_VERSION="v0.6.0" BRANCH_OR_VERSION=${1:-main} REPO_URL="https://git.appmodel.nl/tour/finish/raw/branch" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color echo_green() { printf "${GREEN}%s${NC}\n" "$1" } echo_error() { printf "${RED}ERROR: %s${NC}\n" "$1" >&2 } echo_warning() { printf "${YELLOW}WARNING: %s${NC}\n" "$1" } # Detect the current shell detect_shell() { if [ -n "$ZSH_VERSION" ]; then echo "zsh" elif [ -n "$BASH_VERSION" ]; then echo "bash" else parent_shell=$(ps -p $PPID -o comm= 2>/dev/null || echo "") case "$parent_shell" in *zsh*) echo "zsh" ;; *bash*) echo "bash" ;; *) echo "unknown" ;; esac fi } # Check dependencies check_dependencies() { local missing="" if ! command -v curl > /dev/null 2>&1 && ! command -v wget > /dev/null 2>&1; then missing="${missing}curl or wget, " fi if ! command -v jq > /dev/null 2>&1; then missing="${missing}jq, " fi if ! command -v bc > /dev/null 2>&1; then missing="${missing}bc, " fi if [ -n "$missing" ]; then echo_error "Missing dependencies: ${missing%, }" echo "" echo "Install them with:" echo " Ubuntu/Debian: sudo apt-get install curl jq bc bash-completion" echo " CentOS/RHEL: sudo yum install curl jq bc bash-completion" echo " macOS: brew install jq bc bash-completion" return 1 fi return 0 } # Download file download_file() { local url="$1" local output="$2" if command -v curl > /dev/null 2>&1; then curl -fsSL "$url" -o "$output" elif command -v wget > /dev/null 2>&1; then wget -q -O "$output" "$url" else echo_error "Neither curl nor wget is available" return 1 fi } # Main installation main() { echo_green "==========================================" echo_green " finish.sh Installation" echo_green " Version: $ACSH_VERSION" echo_green "==========================================" echo "" # Detect shell SHELL_TYPE=$(detect_shell) case "$SHELL_TYPE" in zsh) RC_FILE="$HOME/.zshrc" ;; bash) RC_FILE="$HOME/.bashrc" ;; *) echo_error "Unsupported shell. Currently only bash and zsh are supported." exit 1 ;; esac echo "Detected shell: $SHELL_TYPE" # Check Python and venv echo "Checking Python installation..." if ! command -v python3 > /dev/null 2>&1; then echo_error "Python 3 is required but not found" echo "Install it with:" echo " Ubuntu/Debian: sudo apt-get install python3 python3-pip python3-venv" echo " macOS: brew install python3" exit 1 fi echo_green "✓ Python 3 found: $(python3 --version)" # Check if venv module is available if ! python3 -m venv --help > /dev/null 2>&1; then echo_error "python3-venv module is not installed" echo "Install it with:" echo " Ubuntu/Debian: sudo apt-get install python3-venv" echo " CentOS/RHEL: sudo yum install python3-venv" echo " macOS: (included with python3)" exit 1 fi echo_green "✓ python3-venv available" echo "" # Check dependencies echo "Checking dependencies..." if ! check_dependencies; then exit 1 fi echo_green "✓ All dependencies found" echo "" # Determine installation location # Prefer local user install at ~/.local/bin, create it if missing if [ ! -d "$HOME/.local/bin" ]; then mkdir -p "$HOME/.local/bin" fi if [ -d "$HOME/.local/bin" ]; then INSTALL_LOCATION="$HOME/.local/bin/finish" # Add to PATH if not already there if ! echo "$PATH" | grep -q "$HOME/.local/bin"; then echo_warning "$HOME/.local/bin is not in PATH" if [ ! -f "$RC_FILE" ] || ! grep -q ".local/bin" "$RC_FILE"; then echo "Adding $HOME/.local/bin to PATH in $RC_FILE" echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$RC_FILE" fi fi elif [ -w "/usr/local/bin" ]; then INSTALL_LOCATION="/usr/local/bin/finish" else echo_error "Cannot determine installation location" echo "Please ensure either $HOME/.local/bin exists and is writable, or run with sudo for /usr/local/bin" exit 1 fi # Create directories if needed mkdir -p "$(dirname "$INSTALL_LOCATION")" mkdir -p "$HOME/.venvs" # Download Python script echo "Downloading finish.py..." URL="$REPO_URL/$BRANCH_OR_VERSION/src/finish.py" if ! download_file "$URL" "$INSTALL_LOCATION"; then echo_error "Failed to download from $URL" exit 1 fi # Download requirements.txt echo "Downloading requirements.txt..." TEMP_REQ="/tmp/finish_requirements.txt" REQ_URL="$REPO_URL/$BRANCH_OR_VERSION/requirements.txt" if ! download_file "$REQ_URL" "$TEMP_REQ"; then echo_error "Failed to download requirements.txt from $REQ_URL" exit 1 fi # Create virtualenv and install dependencies echo "Creating virtual environment..." VENV_PATH="$HOME/.venvs/finish" if [ -d "$VENV_PATH" ]; then echo "Virtual environment already exists, removing old one..." rm -rf "$VENV_PATH" fi if ! python3 -m venv "$VENV_PATH"; then echo_error "Failed to create virtual environment" echo "Make sure python3-venv is installed:" echo " Ubuntu/Debian: sudo apt-get install python3-venv" exit 1 fi echo_green "✓ Virtual environment created at $VENV_PATH" echo "Installing Python dependencies..." if ! "$VENV_PATH/bin/pip" install --quiet --upgrade pip; then echo_error "Failed to upgrade pip" exit 1 fi if ! "$VENV_PATH/bin/pip" install --quiet -r "$TEMP_REQ"; then echo_error "Failed to install dependencies" cat "$TEMP_REQ" exit 1 fi echo_green "✓ Dependencies installed" rm -f "$TEMP_REQ" # Update shebang to use venv python (compatible with macOS and Linux) if sed --version >/dev/null 2>&1; then # GNU sed (Linux) sed -i "1s|.*|#!$VENV_PATH/bin/python3|" "$INSTALL_LOCATION" else # BSD sed (macOS) sed -i '' "1s|.*|#!$VENV_PATH/bin/python3|" "$INSTALL_LOCATION" fi # Verify shebang was updated correctly SHEBANG=$(head -n 1 "$INSTALL_LOCATION") if [ "$SHEBANG" != "#!$VENV_PATH/bin/python3" ]; then echo_error "Failed to update shebang. Got: $SHEBANG" exit 1 fi chmod +x "$INSTALL_LOCATION" echo_green "✓ Installed to $INSTALL_LOCATION" echo "" # Ensure current shell PATH includes the install dir for immediate use INSTALL_DIR="$(dirname "$INSTALL_LOCATION")" case ":$PATH:" in *":$INSTALL_DIR:"*) ;; *) export PATH="$INSTALL_DIR:$PATH" ;; esac # Check bash-completion if [ "$SHELL_TYPE" = "bash" ]; then if ! command -v _init_completion > /dev/null 2>&1; then if [ -f /usr/share/bash-completion/bash_completion ]; then echo_warning "bash-completion not loaded. Add to $RC_FILE:" echo " source /usr/share/bash-completion/bash_completion" elif [ -f /etc/bash_completion ]; then echo_warning "bash-completion not loaded. Add to $RC_FILE:" echo " source /etc/bash_completion" else echo_warning "bash-completion not found. Install it for best experience:" echo " sudo apt-get install bash-completion # Ubuntu/Debian" fi echo "" fi fi # Test that finish works echo "Testing installation..." if ! "$INSTALL_LOCATION" --version > /dev/null 2>&1; then echo_error "finish command failed to execute" echo "Testing with direct python call..." "$VENV_PATH/bin/python3" "$INSTALL_LOCATION" --version exit 1 fi echo_green "✓ finish command works" # Run finish install to set up keybinding echo "Setting up shell keybinding..." if "$INSTALL_LOCATION" install; then echo "" echo_green "==========================================" echo_green " Installation Complete!" echo_green "==========================================" echo "" echo "Next steps:" echo " 1. Reload your shell configuration:" echo " source $RC_FILE" echo "" echo " 2. Configure your LLM endpoint:" echo " finish config" echo "" echo " 3. Edit config if needed:" echo " nano ~/.finish/finish.json" echo "" echo " 4. Start using by pressing Alt+\\ after typing a command" echo "" echo "Example:" echo " Type: show gpu status" echo " Press: Alt+\\" echo " Select completion with ↑↓ arrows, Enter to accept" echo "" echo "Documentation: https://git.appmodel.nl/tour/finish" else echo_error "Installation failed. Please check the output above." exit 1 fi } main "$@"