diff --git a/README.md b/README.md index d963a010..76f093ac 100644 --- a/README.md +++ b/README.md @@ -348,3 +348,67 @@ OPENROUTER_API_KEY=sk-or-v1-xxxxx \ - `OPENROUTER_API_KEY` - Skip OAuth and use this API key directly - `LINODE_TYPE` - Instance type (default: `g6-standard-1`) - `LINODE_REGION` - Datacenter region (default: `us-east`) + +--- + +## AWS Lightsail + +Spawn agents on [AWS Lightsail](https://aws.amazon.com/lightsail/) instances. Requires AWS CLI installed and configured (`aws configure`). + +### Usage + +#### Claude Code + +```bash +bash <(curl -fsSL https://openrouter.ai/lab/spawn/aws-lightsail/claude.sh) +``` + +#### OpenClaw + +```bash +bash <(curl -fsSL https://openrouter.ai/lab/spawn/aws-lightsail/openclaw.sh) +``` + +#### NanoClaw + +```bash +bash <(curl -fsSL https://openrouter.ai/lab/spawn/aws-lightsail/nanoclaw.sh) +``` + +#### Aider + +```bash +bash <(curl -fsSL https://openrouter.ai/lab/spawn/aws-lightsail/aider.sh) +``` + +#### Goose + +```bash +bash <(curl -fsSL https://openrouter.ai/lab/spawn/aws-lightsail/goose.sh) +``` + +#### Codex CLI + +```bash +bash <(curl -fsSL https://openrouter.ai/lab/spawn/aws-lightsail/codex.sh) +``` + +#### Open Interpreter + +```bash +bash <(curl -fsSL https://openrouter.ai/lab/spawn/aws-lightsail/interpreter.sh) +``` + +### Non-Interactive Mode + +```bash +LIGHTSAIL_SERVER_NAME=dev-mk1 \ +OPENROUTER_API_KEY=sk-or-v1-xxxxx \ + bash <(curl -fsSL https://openrouter.ai/lab/spawn/aws-lightsail/claude.sh) +``` + +**Environment Variables:** +- `LIGHTSAIL_SERVER_NAME` - Name for the instance (skips prompt) +- `OPENROUTER_API_KEY` - Skip OAuth and use this API key directly +- `LIGHTSAIL_BUNDLE` - Instance bundle (default: `medium_3_0`) +- `LIGHTSAIL_REGION` - AWS region (default: `us-east-1`) diff --git a/aws-lightsail/aider.sh b/aws-lightsail/aider.sh new file mode 100755 index 00000000..79223a9f --- /dev/null +++ b/aws-lightsail/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/aws-lightsail/lib/common.sh) +fi + +log_info "Aider on AWS Lightsail" +echo "" + +# 1. Ensure AWS CLI is configured +ensure_aws_cli + +# 2. Generate + register SSH key +ensure_ssh_key + +# 3. Get instance name and create server +SERVER_NAME=$(get_server_name) +create_server "$SERVER_NAME" + +# 4. Wait for SSH and cloud-init +verify_server_connectivity "$LIGHTSAIL_SERVER_IP" +wait_for_cloud_init "$LIGHTSAIL_SERVER_IP" + +# 5. Install Aider +log_warn "Installing Aider..." +run_server "$LIGHTSAIL_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 "$LIGHTSAIL_SERVER_IP" "$ENV_TEMP" "/tmp/env_config" +run_server "$LIGHTSAIL_SERVER_IP" "cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config" +rm "$ENV_TEMP" + +echo "" +log_info "Lightsail instance setup completed successfully!" +log_info "Instance: $SERVER_NAME (IP: $LIGHTSAIL_SERVER_IP)" +echo "" + +# 9. Start Aider interactively +log_warn "Starting Aider..." +sleep 1 +clear +interactive_session "$LIGHTSAIL_SERVER_IP" "source ~/.zshrc && aider --model openrouter/${MODEL_ID}" diff --git a/aws-lightsail/claude.sh b/aws-lightsail/claude.sh new file mode 100755 index 00000000..b93d3081 --- /dev/null +++ b/aws-lightsail/claude.sh @@ -0,0 +1,114 @@ +#!/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/aws-lightsail/lib/common.sh) +fi + +log_info "Claude Code on AWS Lightsail" +echo "" + +# 1. Ensure AWS CLI is configured +ensure_aws_cli + +# 2. Generate + register SSH key +ensure_ssh_key + +# 3. Get instance name and create server +SERVER_NAME=$(get_server_name) +create_server "$SERVER_NAME" + +# 4. Wait for SSH and cloud-init +verify_server_connectivity "$LIGHTSAIL_SERVER_IP" +wait_for_cloud_init "$LIGHTSAIL_SERVER_IP" + +# 5. Verify Claude Code is installed (fallback to manual install) +log_warn "Verifying Claude Code installation..." +if ! run_server "$LIGHTSAIL_SERVER_IP" "command -v claude" >/dev/null 2>&1; then + log_warn "Claude Code not found, installing manually..." + run_server "$LIGHTSAIL_SERVER_IP" "curl -fsSL https://claude.ai/install.sh | bash" +fi +log_info "Claude Code is 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. 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}" +export ANTHROPIC_BASE_URL="https://openrouter.ai/api" +export ANTHROPIC_AUTH_TOKEN="${OPENROUTER_API_KEY}" +export ANTHROPIC_API_KEY="" +export CLAUDE_CODE_SKIP_ONBOARDING="1" +export CLAUDE_CODE_ENABLE_TELEMETRY="0" +EOF + +upload_file "$LIGHTSAIL_SERVER_IP" "$ENV_TEMP" "/tmp/env_config" +run_server "$LIGHTSAIL_SERVER_IP" "cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config" +rm "$ENV_TEMP" + +# 8. Configure Claude Code settings +log_warn "Configuring Claude Code..." + +run_server "$LIGHTSAIL_SERVER_IP" "mkdir -p ~/.claude" + +# Upload settings.json +SETTINGS_TEMP=$(mktemp) +cat > "$SETTINGS_TEMP" << EOF +{ + "theme": "dark", + "editor": "vim", + "env": { + "CLAUDE_CODE_ENABLE_TELEMETRY": "0", + "ANTHROPIC_BASE_URL": "https://openrouter.ai/api", + "ANTHROPIC_AUTH_TOKEN": "${OPENROUTER_API_KEY}" + }, + "permissions": { + "defaultMode": "bypassPermissions", + "dangerouslySkipPermissions": true + } +} +EOF + +upload_file "$LIGHTSAIL_SERVER_IP" "$SETTINGS_TEMP" "/home/ubuntu/.claude/settings.json" +rm "$SETTINGS_TEMP" + +# Upload ~/.claude.json global state +GLOBAL_STATE_TEMP=$(mktemp) +cat > "$GLOBAL_STATE_TEMP" << EOF +{ + "hasCompletedOnboarding": true, + "bypassPermissionsModeAccepted": true +} +EOF + +upload_file "$LIGHTSAIL_SERVER_IP" "$GLOBAL_STATE_TEMP" "/home/ubuntu/.claude.json" +rm "$GLOBAL_STATE_TEMP" + +# Create empty CLAUDE.md +run_server "$LIGHTSAIL_SERVER_IP" "touch ~/.claude/CLAUDE.md" + +echo "" +log_info "Lightsail instance setup completed successfully!" +log_info "Instance: $SERVER_NAME (IP: $LIGHTSAIL_SERVER_IP)" +echo "" + +# 9. Start Claude Code interactively +log_warn "Starting Claude Code..." +sleep 1 +clear +interactive_session "$LIGHTSAIL_SERVER_IP" "source ~/.zshrc && claude" diff --git a/aws-lightsail/codex.sh b/aws-lightsail/codex.sh new file mode 100755 index 00000000..b89a6b21 --- /dev/null +++ b/aws-lightsail/codex.sh @@ -0,0 +1,67 @@ +#!/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/aws-lightsail/lib/common.sh) +fi + +log_info "Codex CLI on AWS Lightsail" +echo "" + +# 1. Ensure AWS CLI is configured +ensure_aws_cli + +# 2. Generate + register SSH key +ensure_ssh_key + +# 3. Get instance name and create server +SERVER_NAME=$(get_server_name) +create_server "$SERVER_NAME" + +# 4. Wait for SSH and cloud-init +verify_server_connectivity "$LIGHTSAIL_SERVER_IP" +wait_for_cloud_init "$LIGHTSAIL_SERVER_IP" + +# 5. Install Codex CLI +log_warn "Installing Codex CLI..." +run_server "$LIGHTSAIL_SERVER_IP" "npm install -g @openai/codex" +log_info "Codex CLI 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. 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}" +export OPENAI_API_KEY="${OPENROUTER_API_KEY}" +export OPENAI_BASE_URL="https://openrouter.ai/api/v1" +EOF + +upload_file "$LIGHTSAIL_SERVER_IP" "$ENV_TEMP" "/tmp/env_config" +run_server "$LIGHTSAIL_SERVER_IP" "cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config" +rm "$ENV_TEMP" + +echo "" +log_info "Lightsail instance setup completed successfully!" +log_info "Instance: $SERVER_NAME (IP: $LIGHTSAIL_SERVER_IP)" +echo "" + +# 8. Start Codex interactively +log_warn "Starting Codex..." +sleep 1 +clear +interactive_session "$LIGHTSAIL_SERVER_IP" "source ~/.zshrc && codex" diff --git a/aws-lightsail/goose.sh b/aws-lightsail/goose.sh new file mode 100755 index 00000000..3f1ce3d7 --- /dev/null +++ b/aws-lightsail/goose.sh @@ -0,0 +1,66 @@ +#!/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/aws-lightsail/lib/common.sh) +fi + +log_info "Goose on AWS Lightsail" +echo "" + +# 1. Ensure AWS CLI is configured +ensure_aws_cli + +# 2. Generate + register SSH key +ensure_ssh_key + +# 3. Get instance name and create server +SERVER_NAME=$(get_server_name) +create_server "$SERVER_NAME" + +# 4. Wait for SSH and cloud-init +verify_server_connectivity "$LIGHTSAIL_SERVER_IP" +wait_for_cloud_init "$LIGHTSAIL_SERVER_IP" + +# 5. Install Goose +log_warn "Installing Goose..." +run_server "$LIGHTSAIL_SERVER_IP" "CONFIGURE=false curl -fsSL https://github.com/block/goose/releases/latest/download/download_cli.sh | bash" +log_info "Goose 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. Inject environment variables into ~/.zshrc +log_warn "Setting up environment variables..." + +ENV_TEMP=$(mktemp) +cat > "$ENV_TEMP" << EOF + +# [spawn:env] +export GOOSE_PROVIDER=openrouter +export OPENROUTER_API_KEY="${OPENROUTER_API_KEY}" +EOF + +upload_file "$LIGHTSAIL_SERVER_IP" "$ENV_TEMP" "/tmp/env_config" +run_server "$LIGHTSAIL_SERVER_IP" "cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config" +rm "$ENV_TEMP" + +echo "" +log_info "Lightsail instance setup completed successfully!" +log_info "Instance: $SERVER_NAME (IP: $LIGHTSAIL_SERVER_IP)" +echo "" + +# 8. Start Goose interactively +log_warn "Starting Goose..." +sleep 1 +clear +interactive_session "$LIGHTSAIL_SERVER_IP" "source ~/.zshrc && goose" diff --git a/aws-lightsail/interpreter.sh b/aws-lightsail/interpreter.sh new file mode 100755 index 00000000..855d4ed1 --- /dev/null +++ b/aws-lightsail/interpreter.sh @@ -0,0 +1,67 @@ +#!/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/aws-lightsail/lib/common.sh) +fi + +log_info "Open Interpreter on AWS Lightsail" +echo "" + +# 1. Ensure AWS CLI is configured +ensure_aws_cli + +# 2. Generate + register SSH key +ensure_ssh_key + +# 3. Get instance name and create server +SERVER_NAME=$(get_server_name) +create_server "$SERVER_NAME" + +# 4. Wait for SSH and cloud-init +verify_server_connectivity "$LIGHTSAIL_SERVER_IP" +wait_for_cloud_init "$LIGHTSAIL_SERVER_IP" + +# 5. Install Open Interpreter +log_warn "Installing Open Interpreter..." +run_server "$LIGHTSAIL_SERVER_IP" "pip install open-interpreter 2>/dev/null || pip3 install open-interpreter" +log_info "Open Interpreter 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. 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}" +export OPENAI_API_KEY="${OPENROUTER_API_KEY}" +export OPENAI_BASE_URL="https://openrouter.ai/api/v1" +EOF + +upload_file "$LIGHTSAIL_SERVER_IP" "$ENV_TEMP" "/tmp/env_config" +run_server "$LIGHTSAIL_SERVER_IP" "cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config" +rm "$ENV_TEMP" + +echo "" +log_info "Lightsail instance setup completed successfully!" +log_info "Instance: $SERVER_NAME (IP: $LIGHTSAIL_SERVER_IP)" +echo "" + +# 8. Start Open Interpreter interactively +log_warn "Starting Open Interpreter..." +sleep 1 +clear +interactive_session "$LIGHTSAIL_SERVER_IP" "source ~/.zshrc && interpreter" diff --git a/aws-lightsail/lib/common.sh b/aws-lightsail/lib/common.sh new file mode 100644 index 00000000..b4d43c1f --- /dev/null +++ b/aws-lightsail/lib/common.sh @@ -0,0 +1,270 @@ +#!/bin/bash +# Common bash functions for AWS Lightsail spawn scripts +# Uses AWS CLI (aws lightsail) — requires `aws` CLI configured with credentials + +# ============================================================ +# Provider-agnostic functions +# ============================================================ + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +log_info() { echo -e "${GREEN}$1${NC}" >&2; } +log_warn() { echo -e "${YELLOW}$1${NC}" >&2; } +log_error() { echo -e "${RED}$1${NC}" >&2; } + +safe_read() { + local prompt="$1" result="" + if [[ -t 0 ]]; then read -p "$prompt" result + elif echo -n "" > /dev/tty 2>/dev/null; then read -p "$prompt" result < /dev/tty + else log_error "Cannot read input: no TTY available"; return 1; fi + echo "$result" +} + +nc_listen() { + local port=$1; shift + if nc --help 2>&1 | grep -q "BusyBox\|busybox" || nc --help 2>&1 | grep -q "\-p "; then + nc -l -p "$port" "$@" + else nc -l "$port" "$@"; fi +} + +open_browser() { + local url=$1 + if command -v termux-open-url &>/dev/null; then termux-open-url "$url" /dev/null; then open "$url" /dev/null; then xdg-open "$url" /dev/null; then log_warn "netcat (nc) not found"; return 1; fi + local callback_url="http://localhost:${callback_port}/callback" + local auth_url="https://openrouter.ai/auth?callback_url=${callback_url}" + local oauth_dir=$(mktemp -d) code_file="$oauth_dir/code" + log_warn "Starting local OAuth server on port ${callback_port}..." + ( + local success_response='HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n
You can close this tab