#!/usr/bin/env bash set -euo pipefail INSTALL_API="https://install.ace.githubnext.com" platform=$(uname -ms) # Windows detection - use MINGW64 bash if [[ ${OS:-} = Windows_NT ]]; then if [[ $platform != MINGW64* ]]; then # TODO: powershell installer echo "Please use Git Bash (MINGW64) to run this installer on Windows" >&2 exit 1 fi fi # Colors (only if terminal supports it) Color_Off='' Red='' Green='' Dim='' Bold='' if [[ -t 1 ]]; then Color_Off='\033[0m' Red='\033[0;31m' Green='\033[38;2;125;166;139m' Dim='\033[0;2m' Bold='\033[1m' fi error() { echo -e "${Red}error${Color_Off}:" "$@" >&2 exit 1 } info() { echo -e "${Dim}$@${Color_Off}" } success() { echo -e "${Green}$@${Color_Off}" } # Check for required tools command -v curl >/dev/null || error "'curl' is required but not installed" command -v unzip >/dev/null || error "'unzip' is required but not installed" # Parse arguments usage() { cat < Install a specific version (e.g., 1.0.0) --no-modify-path Do not modify shell config files Examples: curl -fsSL $INSTALL_API | bash curl -fsSL $INSTALL_API | bash -s -- --version 1.0.0 EOF } requested_version="" no_modify_path=false while [[ $# -gt 0 ]]; do case "$1" in -h|--help) usage exit 0 ;; -v|--version) [[ -n "${2:-}" ]] || error "--version requires a version argument" requested_version="$2" shift 2 ;; --no-modify-path) no_modify_path=true shift ;; *) error "Unknown option: $1" ;; esac done # Detect platform case "$platform" in 'Darwin x86_64') target=darwin-x64 ;; 'Darwin arm64') target=darwin-arm64 ;; 'Linux aarch64' | 'Linux arm64') target=linux-arm64 ;; 'Linux x86_64') target=linux-x64 ;; MINGW64*) target=windows-x64 ;; *) target=linux-x64 ;; esac # Check for musl on Linux case "$target" in 'linux'*) if [[ -f /etc/alpine-release ]]; then target="$target-musl" elif command -v ldd >/dev/null 2>&1 && ldd --version 2>&1 | grep -qi musl; then target="$target-musl" fi ;; esac # Rosetta detection on macOS if [[ $target = darwin-x64 ]]; then if [[ $(sysctl -n sysctl.proc_translated 2>/dev/null) = 1 ]]; then target=darwin-arm64 info "Running in Rosetta 2, downloading arm64 binary instead" fi fi # Set up install directory install_dir="${ACE_INSTALL:-$HOME/.ace}" bin_dir="$install_dir/bin" if [[ $target = windows-x64 ]]; then exe="$bin_dir/ace.exe" else exe="$bin_dir/ace" fi mkdir -p "$bin_dir" || error "Failed to create install directory: $bin_dir" if [[ -z "$requested_version" ]]; then # Get latest version release_info=$(curl -sf "$INSTALL_API/tui/latest") || error "Failed to fetch latest release info" version=$(echo "$release_info" | sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p') [[ -n "$version" ]] || error "Failed to parse version from release info" download_url="$INSTALL_API/tui/latest/$target" else version="${requested_version#v}" # Verify release exists http_code=$(curl -sI -o /dev/null -w "%{http_code}" "$INSTALL_API/tui/$version") [[ "$http_code" != "404" ]] || error "Release v$version not found" download_url="$INSTALL_API/tui/$version/$target" fi # Check if already installed if command -v ace >/dev/null 2>&1; then installed=$(ace --version 2>/dev/null || echo "") if [[ "$installed" = "$version" ]]; then info "ace v$version is already installed" exit 0 fi fi info "Installing ace v$version for $target" # Download curl --fail --location --progress-bar --output "$exe.zip" "$download_url" || error "Failed to download ace from $download_url" # Extract unzip -oqd "$bin_dir" "$exe.zip" || error "Failed to extract ace" # Move binary (handles nested directory from zip) if [[ -d "$bin_dir/ace-$target" ]]; then if [[ $target = windows-x64 ]]; then mv "$bin_dir/ace-$target/ace.exe" "$exe" else mv "$bin_dir/ace-$target/ace" "$exe" fi rm -rf "$bin_dir/ace-$target" fi chmod +x "$exe" rm -f "$exe.zip" success "ace v$version installed to $exe" # Add to PATH tildify() { if [[ $1 = $HOME/* ]]; then echo "~${1#$HOME}" else echo "$1" fi } if [[ "$no_modify_path" != "true" ]] && [[ ":$PATH:" != *":$bin_dir:"* ]]; then case $(basename "$SHELL") in fish) fish_config="$HOME/.config/fish/config.fish" if [[ -w "$fish_config" ]]; then echo -e '\n# ace' >> "$fish_config" echo "fish_add_path $bin_dir" >> "$fish_config" info "Added $(tildify "$bin_dir") to \$PATH in $(tildify "$fish_config")" fi ;; zsh) zsh_config="${ZDOTDIR:-$HOME}/.zshrc" if [[ -w "$zsh_config" ]]; then echo -e '\n# ace' >> "$zsh_config" echo "export PATH=\"$bin_dir:\$PATH\"" >> "$zsh_config" info "Added $(tildify "$bin_dir") to \$PATH in $(tildify "$zsh_config")" fi ;; bash) for bash_config in "$HOME/.bashrc" "$HOME/.bash_profile"; do if [[ -w "$bash_config" ]]; then echo -e '\n# ace' >> "$bash_config" echo "export PATH=\"$bin_dir:\$PATH\"" >> "$bash_config" info "Added $(tildify "$bin_dir") to \$PATH in $(tildify "$bash_config")" break fi done ;; *) echo "Add the following to your shell config:" echo " export PATH=\"$bin_dir:\$PATH\"" ;; esac fi # GitHub Actions support if [[ "${GITHUB_ACTIONS:-}" = "true" ]]; then echo "$bin_dir" >> "$GITHUB_PATH" info "Added $bin_dir to \$GITHUB_PATH" fi # Success message echo "" echo -e "${Green} █████╗ ██████╗███████╗${Color_Off}" echo -e "${Green}██╔══██╗██╔════╝██╔════╝${Color_Off}" echo -e "${Green}███████║██║ █████╗ ${Color_Off}" echo -e "${Green}██╔══██║██║ ██╔══╝ ${Color_Off}" echo -e "${Green}██║ ██║╚██████╗███████╗${Color_Off}" echo -e "${Green}╚═╝ ╚═╝ ╚═════╝╚══════╝${Color_Off}" echo "" echo -e "${Dim}To get started:${Color_Off}" echo "" echo -e " cd ${Dim}# Open a repository${Color_Off}" echo -e " ace ${Dim}# Run command${Color_Off}" echo "" echo -e "${Dim}For more information visit${Color_Off} https://ace.githubnext.com/docs" echo ""