#!/bin/bash set -euo pipefail # OpenTurtles CLI Installer # Usage: curl -fsSL https://openturtles.ai/install.sh | bash # # Environment variables: # TURTLES_VERSION — specific version to install (default: latest) # TURTLES_DIR — installation directory (default: ~/.local/bin) # ━━━ Colors ━━━ BOLD='\033[1m' GREEN='\033[38;2;0;229;176m' DIM='\033[38;2;136;146;176m' WARN='\033[38;2;255;176;32m' ERR='\033[38;2;230;57;70m' NC='\033[0m' GITHUB_REPO="openturtles/cli" BINARY_NAME="turtles" INSTALL_DIR="${TURTLES_DIR:-${HOME}/.local/bin}" # ━━━ UI Helpers ━━━ info() { echo -e "${DIM}·${NC} $*"; } success() { echo -e "${GREEN}✓${NC} $*"; } warn() { echo -e "${WARN}!${NC} $*"; } error() { echo -e "${ERR}✗${NC} $*"; } banner() { echo "" printf '\033[38;2;0;229;176m%s\033[0m\n' " ___ _____ _ _" printf '\033[38;2;0;218;180m%s\033[0m\n' " / _ \\ _ __ ___ _ |_ _| _ _ _| |_| | ___ ___" printf '\033[38;2;0;206;185m%s\033[0m\n' " | | | | '_ \\ / _ \\ '_ \\| || | | | '__| __| |/ _ \\/ __|" printf '\033[38;2;0;195;190m%s\033[0m\n' " | |_| | |_) | __/ | | | || |_| | | | |_| | __/\\__ \\" printf '\033[38;2;0;183;200m%s\033[0m\n' " \\___/| .__/ \\___|_| |_|_| \\__,_|_| \\__|_|\\___||___/" printf '\033[38;2;0;170;210m%s\033[0m\n' " |_|" echo "" echo -e "${DIM} Say one sentence. Get an AI that acts on it — forever.${NC}" echo "" } # ━━━ Detect OS & Architecture ━━━ detect_os() { case "$(uname -s 2>/dev/null)" in Darwin) echo "darwin" ;; Linux) echo "linux" ;; *) error "Unsupported operating system: $(uname -s)" echo "OpenTurtles currently supports macOS and Linux." exit 1 ;; esac } detect_arch() { case "$(uname -m 2>/dev/null)" in x86_64|amd64) echo "x86_64" ;; arm64|aarch64) echo "aarch64" ;; *) error "Unsupported architecture: $(uname -m)" echo "OpenTurtles supports x86_64 and arm64 (Apple Silicon / ARM)." exit 1 ;; esac } # ━━━ Detect Downloader ━━━ download() { local url="$1" output="$2" if command -v curl &>/dev/null; then curl -fsSL --retry 3 --retry-delay 1 -o "$output" "$url" elif command -v wget &>/dev/null; then wget -q --tries=3 -O "$output" "$url" else error "Neither curl nor wget found. Please install one and retry." exit 1 fi } # ━━━ Get Latest Version ━━━ get_latest_version() { local tmp tmp="$(mktemp)" if ! download "https://api.github.com/repos/${GITHUB_REPO}/releases/latest" "$tmp" 2>/dev/null; then error "Failed to fetch latest release info from GitHub" rm -f "$tmp" exit 1 fi local version version="$(grep '"tag_name"' "$tmp" | head -1 | sed -E 's/.*"tag_name":[[:space:]]*"([^"]+)".*/\1/')" rm -f "$tmp" if [[ -z "$version" ]]; then error "Could not determine latest version" exit 1 fi # Strip leading 'v' if present echo "${version#v}" } # ━━━ Main Install ━━━ main() { banner local os arch version asset_name download_url tmp_dir os="$(detect_os)" arch="$(detect_arch)" success "Detected: ${os}/${arch}" # Determine version if [[ -n "${TURTLES_VERSION:-}" ]]; then version="${TURTLES_VERSION#v}" info "Installing requested version: v${version}" else info "Fetching latest version..." version="$(get_latest_version)" success "Latest version: v${version}" fi # Build asset name: turtles-v0.12.0-darwin-aarch64.tar.gz asset_name="${BINARY_NAME}-v${version}-${os}-${arch}.tar.gz" download_url="https://github.com/${GITHUB_REPO}/releases/download/v${version}/${asset_name}" # Download tmp_dir="$(mktemp -d)" trap "rm -rf '$tmp_dir'" EXIT info "Downloading ${asset_name}..." if ! download "$download_url" "$tmp_dir/$asset_name"; then error "Download failed: ${download_url}" echo "" echo " Make sure the release exists at:" echo " https://github.com/${GITHUB_REPO}/releases/tag/v${version}" echo "" echo " Available platforms: darwin-aarch64, darwin-x86_64, linux-x86_64, linux-aarch64" exit 1 fi success "Downloaded successfully" # Extract info "Extracting..." tar -xzf "$tmp_dir/$asset_name" -C "$tmp_dir" 2>/dev/null local binary_path binary_path="$(find "$tmp_dir" -type f -name "$BINARY_NAME" | head -1)" if [[ -z "$binary_path" ]]; then error "Binary not found in archive" exit 1 fi chmod +x "$binary_path" # Install mkdir -p "$INSTALL_DIR" mv "$binary_path" "$INSTALL_DIR/$BINARY_NAME" success "Installed to ${INSTALL_DIR}/${BINARY_NAME}" # Check PATH if ! echo "$PATH" | tr ':' '\n' | grep -q "^${INSTALL_DIR}$"; then echo "" warn "${INSTALL_DIR} is not in your PATH" echo "" echo " Add it to your shell profile:" echo "" local shell_name shell_name="$(basename "${SHELL:-/bin/bash}")" case "$shell_name" in zsh) echo " echo 'export PATH=\"${INSTALL_DIR}:\$PATH\"' >> ~/.zshrc" echo " source ~/.zshrc" ;; fish) echo " fish_add_path ${INSTALL_DIR}" ;; *) echo " echo 'export PATH=\"${INSTALL_DIR}:\$PATH\"' >> ~/.bashrc" echo " source ~/.bashrc" ;; esac echo "" fi # Verify if command -v "$BINARY_NAME" &>/dev/null; then local installed_version installed_version="$("$BINARY_NAME" --version 2>/dev/null || echo "unknown")" success "Verified: ${installed_version}" fi # Done echo "" echo -e "${GREEN}${BOLD} ✅ OpenTurtles installed successfully!${NC}" echo "" echo -e " ${DIM}Quick start:${NC}" echo "" echo " turtles create my-turtle" echo " turtles start my-turtle" echo " turtles watch my-turtle" echo "" echo -e " ${DIM}Documentation:${NC} https://openturtles.ai/docs" echo -e " ${DIM}GitHub:${NC} https://github.com/${GITHUB_REPO}" echo "" } main "$@"