diff --git a/README.md b/README.md index 15063ed1..9d4a808a 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,12 @@ bash <(curl -fsSL https://openrouter.ai/lab/spawn/sprite/openclaw.sh) bash <(curl -fsSL https://openrouter.ai/lab/spawn/sprite/nanoclaw.sh) ``` +#### Aider + +```bash +bash <(curl -fsSL https://openrouter.ai/lab/spawn/sprite/aider.sh) +``` + ### Non-Interactive Mode For automation or CI/CD, set environment variables: @@ -87,6 +93,12 @@ bash <(curl -fsSL https://openrouter.ai/lab/spawn/hetzner/openclaw.sh) bash <(curl -fsSL https://openrouter.ai/lab/spawn/hetzner/nanoclaw.sh) ``` +#### Aider + +```bash +bash <(curl -fsSL https://openrouter.ai/lab/spawn/hetzner/aider.sh) +``` + ### Non-Interactive Mode ```bash @@ -129,6 +141,12 @@ bash <(curl -fsSL https://openrouter.ai/lab/spawn/digitalocean/openclaw.sh) bash <(curl -fsSL https://openrouter.ai/lab/spawn/digitalocean/nanoclaw.sh) ``` +#### Aider + +```bash +bash <(curl -fsSL https://openrouter.ai/lab/spawn/digitalocean/aider.sh) +``` + ### Non-Interactive Mode ```bash diff --git a/digitalocean/aider.sh b/digitalocean/aider.sh new file mode 100755 index 00000000..1ecc6688 --- /dev/null +++ b/digitalocean/aider.sh @@ -0,0 +1,72 @@ +#!/bin/bash +set -e + +# Source common functions - try local file first, fall back to remote +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" +if [[ -f "$SCRIPT_DIR/lib/common.sh" ]]; then + source "$SCRIPT_DIR/lib/common.sh" +else + source <(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/digitalocean/lib/common.sh) +fi + +log_info "Aider on DigitalOcean" +echo "" + +# 1. Resolve DigitalOcean API token +ensure_do_token + +# 2. Generate + register SSH key +ensure_ssh_key + +# 3. Get droplet name and create droplet +DROPLET_NAME=$(get_server_name) +create_server "$DROPLET_NAME" + +# 4. Wait for SSH and cloud-init +verify_server_connectivity "$DO_SERVER_IP" +wait_for_cloud_init "$DO_SERVER_IP" + +# 5. Install Aider +log_warn "Installing Aider..." +run_server "$DO_SERVER_IP" "pip install aider-chat 2>/dev/null || pip3 install aider-chat" +log_info "Aider installed" + +# 6. Get OpenRouter API key +echo "" +if [[ -n "$OPENROUTER_API_KEY" ]]; then + log_info "Using OpenRouter API key from environment" +else + OPENROUTER_API_KEY=$(get_openrouter_api_key_oauth 5180) +fi + +# 7. Get model preference +echo "" +log_warn "Browse models at: https://openrouter.ai/models" +log_warn "Which model would you like to use with Aider?" +MODEL_ID=$(safe_read "Enter model ID [openrouter/auto]: ") || MODEL_ID="" +MODEL_ID="${MODEL_ID:-openrouter/auto}" + +# 8. Inject environment variables into ~/.zshrc +log_warn "Setting up environment variables..." + +ENV_TEMP=$(mktemp) +cat > "$ENV_TEMP" << EOF + +# [spawn:env] +export OPENROUTER_API_KEY="${OPENROUTER_API_KEY}" +EOF + +upload_file "$DO_SERVER_IP" "$ENV_TEMP" "/tmp/env_config" +run_server "$DO_SERVER_IP" "cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config" +rm "$ENV_TEMP" + +echo "" +log_info "DigitalOcean droplet setup completed successfully!" +log_info "Droplet: $DROPLET_NAME (ID: $DO_DROPLET_ID, IP: $DO_SERVER_IP)" +echo "" + +# 9. Start Aider interactively +log_warn "Starting Aider..." +sleep 1 +clear +interactive_session "$DO_SERVER_IP" "source ~/.zshrc && aider --model openrouter/${MODEL_ID}" diff --git a/hetzner/aider.sh b/hetzner/aider.sh new file mode 100755 index 00000000..d9e826fb --- /dev/null +++ b/hetzner/aider.sh @@ -0,0 +1,72 @@ +#!/bin/bash +set -e + +# Source common functions - try local file first, fall back to remote +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" +if [[ -f "$SCRIPT_DIR/lib/common.sh" ]]; then + source "$SCRIPT_DIR/lib/common.sh" +else + source <(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hetzner/lib/common.sh) +fi + +log_info "Aider on Hetzner Cloud" +echo "" + +# 1. Resolve Hetzner API token +ensure_hcloud_token + +# 2. Generate + register SSH key +ensure_ssh_key + +# 3. Get server name and create server +SERVER_NAME=$(get_server_name) +create_server "$SERVER_NAME" + +# 4. Wait for SSH and cloud-init +verify_server_connectivity "$HETZNER_SERVER_IP" +wait_for_cloud_init "$HETZNER_SERVER_IP" + +# 5. Install Aider +log_warn "Installing Aider..." +run_server "$HETZNER_SERVER_IP" "pip install aider-chat 2>/dev/null || pip3 install aider-chat" +log_info "Aider installed" + +# 6. Get OpenRouter API key +echo "" +if [[ -n "$OPENROUTER_API_KEY" ]]; then + log_info "Using OpenRouter API key from environment" +else + OPENROUTER_API_KEY=$(get_openrouter_api_key_oauth 5180) +fi + +# 7. Get model preference +echo "" +log_warn "Browse models at: https://openrouter.ai/models" +log_warn "Which model would you like to use with Aider?" +MODEL_ID=$(safe_read "Enter model ID [openrouter/auto]: ") || MODEL_ID="" +MODEL_ID="${MODEL_ID:-openrouter/auto}" + +# 8. Inject environment variables into ~/.zshrc +log_warn "Setting up environment variables..." + +ENV_TEMP=$(mktemp) +cat > "$ENV_TEMP" << EOF + +# [spawn:env] +export OPENROUTER_API_KEY="${OPENROUTER_API_KEY}" +EOF + +upload_file "$HETZNER_SERVER_IP" "$ENV_TEMP" "/tmp/env_config" +run_server "$HETZNER_SERVER_IP" "cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config" +rm "$ENV_TEMP" + +echo "" +log_info "Hetzner server setup completed successfully!" +log_info "Server: $SERVER_NAME (ID: $HETZNER_SERVER_ID, IP: $HETZNER_SERVER_IP)" +echo "" + +# 9. Start Aider interactively +log_warn "Starting Aider..." +sleep 1 +clear +interactive_session "$HETZNER_SERVER_IP" "source ~/.zshrc && aider --model openrouter/${MODEL_ID}" diff --git a/manifest.json b/manifest.json index 55bb5f2a..965b1cda 100644 --- a/manifest.json +++ b/manifest.json @@ -65,6 +65,23 @@ } }, "notes": "Requires WhatsApp QR code scan for authentication" + }, + "aider": { + "name": "Aider", + "description": "AI pair programming in the terminal", + "url": "https://github.com/paul-gauthier/aider", + "install": "pip install aider-chat", + "launch": "aider --model openrouter/${MODEL_ID}", + "env": { + "OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}" + }, + "interactive_prompts": { + "model_id": { + "prompt": "Enter model ID", + "default": "openrouter/auto" + } + }, + "notes": "Natively supports OpenRouter via OPENROUTER_API_KEY and --model openrouter/... flag" } }, "clouds": { @@ -118,6 +135,9 @@ "hetzner/nanoclaw": "implemented", "digitalocean/claude": "implemented", "digitalocean/openclaw": "implemented", - "digitalocean/nanoclaw": "implemented" + "digitalocean/nanoclaw": "implemented", + "sprite/aider": "implemented", + "hetzner/aider": "implemented", + "digitalocean/aider": "implemented" } } diff --git a/sprite/aider.sh b/sprite/aider.sh new file mode 100755 index 00000000..8aca9e42 --- /dev/null +++ b/sprite/aider.sh @@ -0,0 +1,68 @@ +#!/bin/bash +set -e + +# Source common functions - try local file first, fall back to remote +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" +if [[ -f "$SCRIPT_DIR/lib/common.sh" ]]; then + source "$SCRIPT_DIR/lib/common.sh" +else + source <(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/sprite/lib/common.sh) +fi + +log_info "Aider on Sprite" +echo "" + +# Setup sprite environment +ensure_sprite_installed +ensure_sprite_authenticated + +SPRITE_NAME=$(get_sprite_name) +ensure_sprite_exists "$SPRITE_NAME" 5 +verify_sprite_connectivity "$SPRITE_NAME" + +log_warn "Setting up sprite environment..." + +# Configure shell environment +setup_shell_environment "$SPRITE_NAME" + +# Install Aider +log_warn "Installing Aider..." +run_sprite "$SPRITE_NAME" "pip install aider-chat 2>/dev/null || pip3 install aider-chat" + +# Get OpenRouter API key via OAuth +echo "" +if [[ -n "$OPENROUTER_API_KEY" ]]; then + log_info "Using OpenRouter API key from environment" +else + OPENROUTER_API_KEY=$(get_openrouter_api_key_oauth 5180) +fi + +# Get model preference +echo "" +log_warn "Browse models at: https://openrouter.ai/models" +log_warn "Which model would you like to use with Aider?" +MODEL_ID=$(safe_read "Enter model ID [openrouter/auto]: ") || MODEL_ID="" +MODEL_ID="${MODEL_ID:-openrouter/auto}" + +# Inject environment variables +log_warn "Setting up environment variables..." + +ENV_TEMP=$(mktemp) +cat > "$ENV_TEMP" << EOF + +# [spawn:env] +export OPENROUTER_API_KEY="${OPENROUTER_API_KEY}" +EOF + +sprite exec -s "$SPRITE_NAME" -file "$ENV_TEMP:/tmp/env_config" -- bash -c "cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config" +rm "$ENV_TEMP" + +echo "" +log_info "Sprite setup completed successfully!" +echo "" + +# Start Aider interactively +log_warn "Starting Aider..." +sleep 1 +clear +sprite exec -s "$SPRITE_NAME" -tty -- zsh -c "source ~/.zshrc && aider --model openrouter/${MODEL_ID}"