#!/bin/bash set -e # ============================================================================ # Grove CLI Installer # ============================================================================ # Served at: https://grove.city/install-cli.sh # Install via: curl -fsSL https://grove.city/install-cli.sh | bash # ============================================================================ # Colors GREEN='\033[0;32m' CYAN='\033[0;36m' RED='\033[0;31m' NC='\033[0m' # No Color # Agent skills repository (public repo for distributing binaries) AGENT_SKILLS_REPO="buildwithgrove/agent-skills" GITHUB_API="https://api.github.com/repos/${AGENT_SKILLS_REPO}" # Parse arguments DRY_RUN=false VERSION="latest" for arg in "$@"; do case $arg in --dry-run) DRY_RUN=true echo "DRY RUN MODE - No changes will be made" echo "" ;; --version=*) VERSION="${arg#*=}" ;; *) echo "Unknown option: $arg" echo "Usage: $0 [--dry-run] [--version=]" exit 1 ;; esac done echo "Installing Grove CLI..." # Detect OS and architecture detect_platform() { local os="" local arch="" local bin_ext="" case "$(uname -s)" in Linux*) os="linux" ;; Darwin*) os="macos" ;; MINGW*|MSYS*|CYGWIN*) os="windows"; bin_ext=".exe" ;; *) echo -e "${RED}Error: Unsupported operating system: $(uname -s)${NC}" exit 1 ;; esac case "$(uname -m)" in x86_64|amd64) arch="x86_64" ;; arm64|aarch64) arch="arm64" ;; *) echo -e "${RED}Error: Unsupported architecture: $(uname -m)${NC}" exit 1 ;; esac # macOS: only ARM64 binaries are built (works on Intel via Rosetta 2) if [ "$os" = "macos" ]; then arch="arm64" fi # Linux: only x86_64 binaries are built if [ "$os" = "linux" ] && [ "$arch" = "arm64" ]; then echo -e "${RED}Error: ARM64 Linux is not supported yet${NC}" echo " Please install from source or use an x86_64 system" exit 1 fi echo "$os,$arch,$bin_ext" } # Get latest release tag get_latest_release() { if command -v curl &> /dev/null; then curl -fsSL "${GITHUB_API}/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' else echo -e "${RED}Error: curl is required to download Grove CLI${NC}" exit 1 fi } # Parse platform IFS=',' read -r OS ARCH BIN_EXT <<< "$(detect_platform)" echo "Detected platform: ${OS}-${ARCH}" # Determine asset name (wallet build includes all features) ASSET_NAME="grove-${OS}-${ARCH}-wallet${BIN_EXT}.tar.gz" # Get release tag if [ "$VERSION" = "latest" ]; then RELEASE_TAG=$(get_latest_release) if [ -z "$RELEASE_TAG" ]; then echo -e "${RED}Error: Failed to fetch latest release${NC}" echo " Please check your internet connection and try again" exit 1 fi echo "Latest release: $RELEASE_TAG" else RELEASE_TAG="$VERSION" echo "Using release: $RELEASE_TAG" fi # Construct download URL DOWNLOAD_URL="https://github.com/${AGENT_SKILLS_REPO}/releases/download/${RELEASE_TAG}/${ASSET_NAME}" # Create installation directory INSTALL_DIR="$HOME/.grove" echo "Installing to $INSTALL_DIR" # Clean up previous install to avoid conflicts (preserve config files) BACKUP_DIR="/tmp/grove-config-backup-$$" if [ -d "$INSTALL_DIR" ]; then if [ "$DRY_RUN" = true ]; then echo "Would remove previous installation at $INSTALL_DIR (preserving config)" else echo "Removing previous installation (preserving config)..." mkdir -p "$BACKUP_DIR" for file in .env keyfile.txt; do if [ -f "$INSTALL_DIR/$file" ]; then cp "$INSTALL_DIR/$file" "$BACKUP_DIR/" fi done rm -rf "$INSTALL_DIR" fi fi if [ "$DRY_RUN" = true ]; then echo "Would create directory $INSTALL_DIR" else mkdir -p "$INSTALL_DIR" if [ -d "$BACKUP_DIR" ]; then RESTORED_COUNT=0 for file in .env keyfile.txt; do if [ -f "$BACKUP_DIR/$file" ]; then mv "$BACKUP_DIR/$file" "$INSTALL_DIR/" RESTORED_COUNT=$((RESTORED_COUNT + 1)) fi done rm -rf "$BACKUP_DIR" if [ $RESTORED_COUNT -gt 0 ]; then echo "Preserved configuration from previous installation" fi fi fi # Download and extract archive if [ "$DRY_RUN" = true ]; then echo "Would download:" echo " URL: $DOWNLOAD_URL" echo " Destination: $INSTALL_DIR/" echo "" echo "DRY RUN COMPLETE - No changes were made" exit 0 fi echo "Downloading Grove CLI..." TMPFILE=$(mktemp) if ! curl -fsSL -o "$TMPFILE" "$DOWNLOAD_URL"; then rm -f "$TMPFILE" echo "" echo -e "${RED}Error: Failed to download Grove CLI${NC}" echo "" echo "Attempted URL: $DOWNLOAD_URL" echo "" echo "Possible causes:" echo " 1. Release not available: $RELEASE_TAG" echo " 2. Binary not available for platform: ${OS}-${ARCH}" echo " 3. Network connectivity issue" echo "" echo "Available releases: https://github.com/${AGENT_SKILLS_REPO}/releases" exit 1 fi # Extract tarball (archive contains grove/ directory with binary + _internal/) tar -xzf "$TMPFILE" -C "$INSTALL_DIR" --strip-components=1 rm -f "$TMPFILE" echo "Downloaded successfully" # Make binary executable (Unix systems only) if [ "$OS" != "windows" ]; then chmod +x "$INSTALL_DIR/grove${BIN_EXT}" fi # Create symlink BIN_DIR="$HOME/.local/bin" mkdir -p "$BIN_DIR" ln -sf "$INSTALL_DIR/grove${BIN_EXT}" "$BIN_DIR/grove" # Check if in PATH if [[ ":$PATH:" != *":$BIN_DIR:"* ]]; then echo "" echo -e "${RED}WARNING: $BIN_DIR is not in your PATH${NC}" echo "" echo "Add this to your shell config and restart your terminal:" echo " export PATH=\"\$HOME/.local/bin:\$PATH\"" echo "" fi echo "" echo -e "${GREEN}Grove CLI installed successfully!${NC}" echo "" echo -e "Run ${CYAN}grove --help${NC} to get started." echo -e "Run ${CYAN}grove setup${NC} for first-time configuration."